Browse Source

merge with develop/3.4

pull/6757/head
YevhenBondarenko 4 years ago
parent
commit
c78017ecb2
  1. 1
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  2. 27
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  3. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
  4. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
  5. 4
      application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java
  6. 48
      application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java
  7. 14
      application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java
  8. 10
      application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java
  9. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java
  10. 8
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java
  11. 11
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java
  12. 22
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java
  13. 11
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/CustomerImportService.java
  14. 7
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java
  15. 5
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java
  16. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java
  17. 8
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/EntityViewImportService.java
  18. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java
  19. 6
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/WidgetsBundleImportService.java
  20. 21
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  21. 134
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
  22. 2
      application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java
  23. 1
      application/src/main/resources/thingsboard.yml
  24. 2
      common/cache/src/main/java/org/thingsboard/server/cache/SimpleTbCacheValueWrapper.java
  25. 27
      common/cluster-api/src/main/proto/queue.proto
  26. 6
      common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java
  27. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataDiff.java
  28. 5
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityLoadError.java
  29. 6
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityTypeLoadResult.java
  30. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java
  31. 8
      common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java
  32. 68
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java
  33. 13
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/PendingCommit.java
  34. 8
      docker/.gitignore
  35. 1
      msa/vc-executor/src/main/resources/tb-vc-executor.yml
  36. 1
      ui-ngx/src/app/shared/models/vc.models.ts

1
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -138,6 +138,7 @@ public class ControllerConstants {
protected static final String ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the entity version name."; protected static final String ENTITY_VERSION_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'substring' filter based on the entity version name.";
protected static final String VERSION_ID_PARAM_DESCRIPTION = "Version id, for example fd82625bdd7d6131cf8027b44ee967012ecaf990. Represents commit hash."; protected static final String VERSION_ID_PARAM_DESCRIPTION = "Version id, for example fd82625bdd7d6131cf8027b44ee967012ecaf990. Represents commit hash.";
protected static final String BRANCH_PARAM_DESCRIPTION = "The name of the working branch, for example 'master'";
protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n"; protected static final String MARKDOWN_CODE_BLOCK_START = "```json\n";
protected static final String MARKDOWN_CODE_BLOCK_END = "\n```"; protected static final String MARKDOWN_CODE_BLOCK_END = "\n```";

27
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -58,6 +58,9 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.BRANCH_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ENTITY_TYPE_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END;
import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START; import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_START;
import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE; import static org.thingsboard.server.controller.ControllerConstants.NEW_LINE;
@ -230,8 +233,11 @@ public class EntitiesVersionControlController extends BaseController {
MARKDOWN_CODE_BLOCK_END + MARKDOWN_CODE_BLOCK_END +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"}) @GetMapping(value = "/version/{entityType}/{externalEntityUuid}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityVersions(@PathVariable EntityType entityType, public DeferredResult<PageData<EntityVersion>> listEntityVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id. This is `externalId` property of an entity, or otherwise if not set - simply id of this entity.")
@PathVariable UUID externalEntityUuid, @PathVariable UUID externalEntityUuid,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION)
@RequestParam String branch, @RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize, @RequestParam int pageSize,
@ -256,7 +262,9 @@ public class EntitiesVersionControlController extends BaseController {
"The response structure is the same as for `listEntityVersions` API method." + "The response structure is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"}) @GetMapping(value = "/version/{entityType}", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@PathVariable EntityType entityType, public DeferredResult<PageData<EntityVersion>> listEntityTypeVersions(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch, @RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize, @RequestParam int pageSize,
@ -279,7 +287,8 @@ public class EntitiesVersionControlController extends BaseController {
"The response format is the same as for `listEntityVersions` API method." + "The response format is the same as for `listEntityVersions` API method." +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/version", params = {"branch", "pageSize", "page"}) @GetMapping(value = "/version", params = {"branch", "pageSize", "page"})
public DeferredResult<PageData<EntityVersion>> listVersions(@RequestParam String branch, public DeferredResult<PageData<EntityVersion>> listVersions(@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch,
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize, @RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@ -302,9 +311,11 @@ public class EntitiesVersionControlController extends BaseController {
"Entities order will be the same as in the repository." + "Entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{entityType}/{versionId}", params = {"branch"}) @GetMapping(value = "/entity/{entityType}/{versionId}", params = {"branch"})
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@PathVariable EntityType entityType, public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) @ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId, @PathVariable String versionId,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch) throws Exception { @RequestParam String branch) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType)); return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType));
@ -318,6 +329,7 @@ public class EntitiesVersionControlController extends BaseController {
@GetMapping(value = "/entity/{versionId}", params = {"branch"}) @GetMapping(value = "/entity/{versionId}", params = {"branch"})
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId, @PathVariable String versionId,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch) throws Exception { @RequestParam String branch) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId)); return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId));
@ -332,7 +344,9 @@ public class EntitiesVersionControlController extends BaseController {
@GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}") @GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}")
public DeferredResult<EntityDataInfo> getEntityDataInfo(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) public DeferredResult<EntityDataInfo> getEntityDataInfo(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId, @PathVariable String versionId,
@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType, @PathVariable EntityType entityType,
@ApiParam(value = "A string value representing external entity id", required = true)
@PathVariable UUID externalEntityUuid) throws Exception { @PathVariable UUID externalEntityUuid) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid); EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
@ -344,8 +358,11 @@ public class EntitiesVersionControlController extends BaseController {
"Entity data structure is the same as stored in a repository. " + "Entity data structure is the same as stored in a repository. " +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"branch", "versionId"}) @GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"branch", "versionId"})
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@PathVariable EntityType entityType, public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID internalEntityUuid, @PathVariable UUID internalEntityUuid,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION)
@RequestParam String branch, @RequestParam String branch,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) @ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@RequestParam String versionId) throws Exception { @RequestParam String versionId) throws Exception {

4
application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java

@ -256,8 +256,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS
} }
@Override @Override
public void notifyCreateOrUpdateRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, public void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
ActionType actionType, Object... additionalInfo) { ActionType actionType, Object... additionalInfo) {
logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, additionalInfo);
logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, additionalInfo); logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, additionalInfo);
try { try {

4
application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java

@ -107,6 +107,6 @@ public interface TbNotificationEntityService {
ActionType actionType, boolean sendNotifyMsgToEdge, ActionType actionType, boolean sendNotifyMsgToEdge,
Exception e, Object... additionalInfo); Exception e, Object... additionalInfo);
void notifyCreateOrUpdateRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user,
ActionType actionType, Object... additionalInfo); ActionType actionType, Object... additionalInfo);
} }

4
application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java

@ -42,7 +42,7 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl
public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException { public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException {
try { try {
relationService.saveRelation(tenantId, relation); relationService.saveRelation(tenantId, relation);
notificationEntityService.notifyCreateOrUpdateRelation(tenantId, customerId, notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation); relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId, notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,
@ -60,7 +60,7 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl
if (!found) { if (!found) {
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
} }
notificationEntityService.notifyCreateOrUpdateRelation(tenantId, customerId, notificationEntityService.notifyRelation(tenantId, customerId,
relation, user, ActionType.RELATION_DELETED, relation); relation, user, ActionType.RELATION_DELETED, relation);
} catch (Exception e) { } catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId, notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId,

48
application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java

@ -94,36 +94,32 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen
@Override @Override
public void updateEntityViewAttributes(TenantId tenantId, EntityView savedEntityView, EntityView oldEntityView, User user) throws ThingsboardException { public void updateEntityViewAttributes(TenantId tenantId, EntityView savedEntityView, EntityView oldEntityView, User user) throws ThingsboardException {
try { List<ListenableFuture<?>> futures = new ArrayList<>();
List<ListenableFuture<?>> futures = new ArrayList<>();
if (oldEntityView != null) { if (oldEntityView != null) {
if (oldEntityView.getKeys() != null && oldEntityView.getKeys().getAttributes() != null) { if (oldEntityView.getKeys() != null && oldEntityView.getKeys().getAttributes() != null) {
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.CLIENT_SCOPE, oldEntityView.getKeys().getAttributes().getCs(), user)); futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.CLIENT_SCOPE, oldEntityView.getKeys().getAttributes().getCs(), user));
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SERVER_SCOPE, oldEntityView.getKeys().getAttributes().getSs(), user)); futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SERVER_SCOPE, oldEntityView.getKeys().getAttributes().getSs(), user));
futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SHARED_SCOPE, oldEntityView.getKeys().getAttributes().getSh(), user)); futures.add(deleteAttributesFromEntityView(oldEntityView, DataConstants.SHARED_SCOPE, oldEntityView.getKeys().getAttributes().getSh(), user));
}
List<String> tsKeys = oldEntityView.getKeys() != null && oldEntityView.getKeys().getTimeseries() != null ?
oldEntityView.getKeys().getTimeseries() : Collections.emptyList();
futures.add(deleteLatestFromEntityView(oldEntityView, tsKeys, user));
} }
if (savedEntityView.getKeys() != null) { List<String> tsKeys = oldEntityView.getKeys() != null && oldEntityView.getKeys().getTimeseries() != null ?
if (savedEntityView.getKeys().getAttributes() != null) { oldEntityView.getKeys().getTimeseries() : Collections.emptyList();
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), user)); futures.add(deleteLatestFromEntityView(oldEntityView, tsKeys, user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), user)); }
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), user)); if (savedEntityView.getKeys() != null) {
} if (savedEntityView.getKeys().getAttributes() != null) {
futures.add(copyLatestFromEntityToEntityView(tenantId, savedEntityView)); futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), user));
futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), user));
} }
for (ListenableFuture<?> future : futures) { futures.add(copyLatestFromEntityToEntityView(tenantId, savedEntityView));
try { }
future.get(); for (ListenableFuture<?> future : futures) {
} catch (InterruptedException | ExecutionException e) { try {
throw new RuntimeException("Failed to copy attributes to entity view", e); future.get();
} } catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Failed to copy attributes to entity view", e);
} }
} catch (Exception e) {
throw e;
} }
} }

14
application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java

@ -67,14 +67,10 @@ public class DefaultTbTenantService extends AbstractTbEntityService implements T
@Override @Override
public void delete(Tenant tenant) throws Exception { public void delete(Tenant tenant) throws Exception {
try { TenantId tenantId = tenant.getId();
TenantId tenantId = tenant.getId(); tenantService.deleteTenant(tenantId);
tenantService.deleteTenant(tenantId); tenantProfileCache.evict(tenantId);
tenantProfileCache.evict(tenantId); notificationEntityService.notifyDeleteTenant(tenant);
notificationEntityService.notifyDeleteTenant(tenant); versionControlService.deleteVersionControlSettings(tenantId).get(1, TimeUnit.MINUTES);
versionControlService.deleteVersionControlSettings(tenantId).get(1, TimeUnit.MINUTES);
} catch (Exception e) {
throw e;
}
} }
} }

10
application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java

@ -32,8 +32,8 @@ import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.apiusage.RateLimitService; import org.thingsboard.server.service.apiusage.RateLimitService;
import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
import org.thingsboard.server.service.sync.ie.exporting.EntityExportService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService; import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService; import org.thingsboard.server.service.sync.ie.exporting.impl.DefaultEntityExportService;
@ -57,9 +57,9 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
private final Map<EntityType, EntityExportService<?, ?, ?>> exportServices = new HashMap<>(); private final Map<EntityType, EntityExportService<?, ?, ?>> exportServices = new HashMap<>();
private final Map<EntityType, EntityImportService<?, ?, ?>> importServices = new HashMap<>(); private final Map<EntityType, EntityImportService<?, ?, ?>> importServices = new HashMap<>();
private final EntityActionService entityActionService;
private final RelationService relationService; private final RelationService relationService;
private final RateLimitService rateLimitService; private final RateLimitService rateLimitService;
private final TbNotificationEntityService entityNotificationService;
protected static final List<EntityType> SUPPORTED_ENTITY_TYPES = List.of( protected static final List<EntityType> SUPPORTED_ENTITY_TYPES = List.of(
EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN, EntityType.CUSTOMER, EntityType.ASSET, EntityType.RULE_CHAIN,
@ -109,10 +109,8 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS
relationService.saveRelations(ctx.getTenantId(), new ArrayList<>(ctx.getRelations())); relationService.saveRelations(ctx.getTenantId(), new ArrayList<>(ctx.getRelations()));
for (EntityRelation relation : ctx.getRelations()) { for (EntityRelation relation : ctx.getRelations()) {
entityActionService.logEntityAction(ctx.getUser(), relation.getFrom(), null, null, entityNotificationService.notifyRelation(ctx.getTenantId(), null,
ActionType.RELATION_ADD_OR_UPDATE, null, relation); relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, relation);
entityActionService.logEntityAction(ctx.getUser(), relation.getTo(), null, null,
ActionType.RELATION_ADD_OR_UPDATE, null, relation);
} }
} }

2
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java

@ -41,8 +41,6 @@ public abstract class BaseEntityExportService<I extends EntityId, E extends Expo
return (D) new EntityExportData<E>(); return (D) new EntityExportData<E>();
} }
;
public abstract Set<EntityType> getSupportedEntityTypes(); public abstract Set<EntityType> getSupportedEntityTypes();
protected void replaceUuidsRecursively(EntitiesExportCtx<?> ctx, JsonNode node, Set<String> skipFieldsSet) { protected void replaceUuidsRecursively(EntitiesExportCtx<?> ctx, JsonNode node, Set<String> skipFieldsSet) {

8
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DefaultEntityExportService.java

@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.sync.ie.AttributeExportData; import org.thingsboard.server.common.data.sync.ie.AttributeExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.exporting.EntityExportService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService;
import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService; import org.thingsboard.server.service.sync.ie.exporting.ExportableEntitiesService;
@ -55,7 +55,7 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
@Lazy @Lazy
protected ExportableEntitiesService exportableEntitiesService; protected ExportableEntitiesService exportableEntitiesService;
@Autowired @Autowired
private RelationService relationService; private RelationDao relationDao;
@Autowired @Autowired
private AttributesService attributesService; private AttributesService attributesService;
@ -99,10 +99,10 @@ public class DefaultEntityExportService<I extends EntityId, E extends Exportable
private List<EntityRelation> exportRelations(EntitiesExportCtx<?> ctx, E entity) throws ThingsboardException { private List<EntityRelation> exportRelations(EntitiesExportCtx<?> ctx, E entity) throws ThingsboardException {
List<EntityRelation> relations = new ArrayList<>(); List<EntityRelation> relations = new ArrayList<>();
List<EntityRelation> inboundRelations = relationService.findByTo(ctx.getTenantId(), entity.getId(), RelationTypeGroup.COMMON); List<EntityRelation> inboundRelations = relationDao.findAllByTo(ctx.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
relations.addAll(inboundRelations); relations.addAll(inboundRelations);
List<EntityRelation> outboundRelations = relationService.findByFrom(ctx.getTenantId(), entity.getId(), RelationTypeGroup.COMMON); List<EntityRelation> outboundRelations = relationDao.findAllByFrom(ctx.getTenantId(), entity.getId(), RelationTypeGroup.COMMON);
relations.addAll(outboundRelations); relations.addAll(outboundRelations);
return relations; return relations;
} }

11
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetImportService.java

@ -18,10 +18,7 @@ package org.thingsboard.server.service.sync.ie.importing.impl;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@ -52,14 +49,6 @@ public class AssetImportService extends BaseEntityImportService<AssetId, Asset,
return assetService.saveAsset(asset); return assetService.saveAsset(asset);
} }
@Override
protected void onEntitySaved(User user, Asset savedAsset, Asset oldAsset) throws ThingsboardException {
super.onEntitySaved(user, savedAsset, oldAsset);
if (oldAsset != null) {
entityActionService.sendEntityNotificationMsgToEdge(user.getTenantId(), savedAsset.getId(), EdgeEventActionType.UPDATED);
}
}
@Override @Override
protected Asset deepCopy(Asset asset) { protected Asset deepCopy(Asset asset) {
return new Asset(asset); return new Asset(asset);

22
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java

@ -28,7 +28,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity; import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -49,6 +48,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.sync.ie.AttributeExportData; import org.thingsboard.server.common.data.sync.ie.AttributeExportData;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.common.data.sync.ie.EntityImportResult; import org.thingsboard.server.common.data.sync.ie.EntityImportResult;
import org.thingsboard.server.dao.relation.RelationDao;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.action.EntityActionService;
import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
@ -77,6 +77,8 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@Autowired @Autowired
private RelationService relationService; private RelationService relationService;
@Autowired @Autowired
private RelationDao relationDao;
@Autowired
private TelemetrySubscriptionService tsSubService; private TelemetrySubscriptionService tsSubService;
@Autowired @Autowired
protected EntityActionService entityActionService; protected EntityActionService entityActionService;
@ -201,19 +203,18 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
if (importResult.getOldEntity() != null) { if (importResult.getOldEntity() != null) {
List<EntityRelation> existingRelations = new ArrayList<>(); List<EntityRelation> existingRelations = new ArrayList<>();
existingRelations.addAll(relationService.findByTo(tenantId, entity.getId(), RelationTypeGroup.COMMON)); existingRelations.addAll(relationDao.findAllByTo(tenantId, entity.getId(), RelationTypeGroup.COMMON));
existingRelations.addAll(relationService.findByFrom(tenantId, entity.getId(), RelationTypeGroup.COMMON)); existingRelations.addAll(relationDao.findAllByFrom(tenantId, entity.getId(), RelationTypeGroup.COMMON));
// dao is used here instead of service to avoid getting cached values, because relationService.deleteRelation will evict value from cache only after transaction is committed
for (EntityRelation existingRelation : existingRelations) { for (EntityRelation existingRelation : existingRelations) {
EntityRelation relation = relationsMap.get(existingRelation); EntityRelation relation = relationsMap.get(existingRelation);
if (relation == null) { if (relation == null) {
importResult.setUpdatedRelatedEntities(true); importResult.setUpdatedRelatedEntities(true);
relationService.deleteRelation(tenantId, existingRelation); relationService.deleteRelation(ctx.getTenantId(), existingRelation.getFrom(), existingRelation.getTo(), existingRelation.getType(), existingRelation.getTypeGroup());
importResult.addSendEventsCallback(() -> { importResult.addSendEventsCallback(() -> {
entityActionService.logEntityAction(ctx.getUser(), existingRelation.getFrom(), null, null, entityNotificationService.notifyRelation(tenantId, null,
ActionType.RELATION_DELETED, null, existingRelation); existingRelation, ctx.getUser(), ActionType.RELATION_DELETED, existingRelation);
entityActionService.logEntityAction(ctx.getUser(), existingRelation.getTo(), null, null,
ActionType.RELATION_DELETED, null, existingRelation);
}); });
} else if (Objects.equal(relation.getAdditionalInfo(), existingRelation.getAdditionalInfo())) { } else if (Objects.equal(relation.getAdditionalInfo(), existingRelation.getAdditionalInfo())) {
relationsMap.remove(relation); relationsMap.remove(relation);
@ -267,9 +268,8 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
} }
protected void onEntitySaved(User user, E savedEntity, E oldEntity) throws ThingsboardException { protected void onEntitySaved(User user, E savedEntity, E oldEntity) throws ThingsboardException {
entityActionService.logEntityAction(user, savedEntity.getId(), savedEntity, entityNotificationService.notifyCreateOrUpdateEntity(user.getTenantId(), savedEntity.getId(), savedEntity,
savedEntity instanceof HasCustomerId ? ((HasCustomerId) savedEntity).getCustomerId() : user.getCustomerId(), null, oldEntity == null ? ActionType.ADDED : ActionType.UPDATED, user);
oldEntity == null ? ActionType.ADDED : ActionType.UPDATED, null);
} }

11
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/CustomerImportService.java

@ -19,9 +19,6 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
@ -68,14 +65,6 @@ public class CustomerImportService extends BaseEntityImportService<CustomerId, C
return new Customer(customer); return new Customer(customer);
} }
@Override
protected void onEntitySaved(User user, Customer savedCustomer, Customer oldCustomer) throws ThingsboardException {
super.onEntitySaved(user, savedCustomer, oldCustomer);
if (oldCustomer != null) {
entityActionService.sendEntityNotificationMsgToEdge(user.getTenantId(), savedCustomer.getId(), EdgeEventActionType.UPDATED);
}
}
@Override @Override
public EntityType getEntityType() { public EntityType getEntityType() {
return EntityType.CUSTOMER; return EntityType.CUSTOMER;

7
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java

@ -118,11 +118,8 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
} }
@Override @Override
protected void onEntitySaved(User user, Dashboard savedDashboard, Dashboard oldDashboard) throws ThingsboardException { protected boolean compare(EntitiesImportCtx ctx, EntityExportData<Dashboard> exportData, Dashboard prepared, Dashboard existing) {
super.onEntitySaved(user, savedDashboard, oldDashboard); return super.compare(ctx, exportData, prepared, existing) || !prepared.getConfiguration().equals(existing.getConfiguration());
if (oldDashboard != null) {
entityActionService.sendEntityNotificationMsgToEdge(user.getTenantId(), savedDashboard.getId(), EdgeEventActionType.UPDATED);
}
} }
@Override @Override

5
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceImportService.java

@ -20,6 +20,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -93,8 +94,8 @@ public class DeviceImportService extends BaseEntityImportService<DeviceId, Devic
@Override @Override
protected void onEntitySaved(User user, Device savedDevice, Device oldDevice) throws ThingsboardException { protected void onEntitySaved(User user, Device savedDevice, Device oldDevice) throws ThingsboardException {
super.onEntitySaved(user, savedDevice, oldDevice); entityNotificationService.notifyCreateOrUpdateDevice(user.getTenantId(), savedDevice.getId(), savedDevice.getCustomerId(),
clusterService.onDeviceUpdated(savedDevice, oldDevice); savedDevice, oldDevice, oldDevice == null ? ActionType.ADDED : ActionType.UPDATED, user);
} }
@Override @Override

6
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DeviceProfileImportService.java

@ -20,7 +20,6 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -52,6 +51,7 @@ public class DeviceProfileImportService extends BaseEntityImportService<DevicePr
deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId())); deviceProfile.setDefaultDashboardId(idProvider.getInternalId(deviceProfile.getDefaultDashboardId()));
deviceProfile.setFirmwareId(getOldEntityField(old, DeviceProfile::getFirmwareId)); deviceProfile.setFirmwareId(getOldEntityField(old, DeviceProfile::getFirmwareId));
deviceProfile.setSoftwareId(getOldEntityField(old, DeviceProfile::getSoftwareId)); deviceProfile.setSoftwareId(getOldEntityField(old, DeviceProfile::getSoftwareId));
deviceProfile.setDefaultQueueId(getOldEntityField(old, DeviceProfile::getDefaultQueueId));
return deviceProfile; return deviceProfile;
} }
@ -62,15 +62,13 @@ public class DeviceProfileImportService extends BaseEntityImportService<DevicePr
@Override @Override
protected void onEntitySaved(User user, DeviceProfile savedDeviceProfile, DeviceProfile oldDeviceProfile) throws ThingsboardException { protected void onEntitySaved(User user, DeviceProfile savedDeviceProfile, DeviceProfile oldDeviceProfile) throws ThingsboardException {
super.onEntitySaved(user, savedDeviceProfile, oldDeviceProfile);
clusterService.onDeviceProfileChange(savedDeviceProfile, null); clusterService.onDeviceProfileChange(savedDeviceProfile, null);
clusterService.broadcastEntityStateChangeEvent(user.getTenantId(), savedDeviceProfile.getId(), clusterService.broadcastEntityStateChangeEvent(user.getTenantId(), savedDeviceProfile.getId(),
oldDeviceProfile == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); oldDeviceProfile == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
entityActionService.sendEntityNotificationMsgToEdge(user.getTenantId(), savedDeviceProfile.getId(),
oldDeviceProfile == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
otaPackageStateService.update(savedDeviceProfile, otaPackageStateService.update(savedDeviceProfile,
oldDeviceProfile != null && !Objects.equals(oldDeviceProfile.getFirmwareId(), savedDeviceProfile.getFirmwareId()), oldDeviceProfile != null && !Objects.equals(oldDeviceProfile.getFirmwareId(), savedDeviceProfile.getFirmwareId()),
oldDeviceProfile != null && !Objects.equals(oldDeviceProfile.getSoftwareId(), savedDeviceProfile.getSoftwareId())); oldDeviceProfile != null && !Objects.equals(oldDeviceProfile.getSoftwareId(), savedDeviceProfile.getSoftwareId()));
super.onEntitySaved(user, savedDeviceProfile, oldDeviceProfile);
} }
@Override @Override

8
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/EntityViewImportService.java

@ -22,15 +22,14 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityExportData;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService; import org.thingsboard.server.service.entitiy.entityview.TbEntityViewService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx;
@Service @Service
@ -65,9 +64,8 @@ public class EntityViewImportService extends BaseEntityImportService<EntityViewI
protected void onEntitySaved(User user, EntityView savedEntityView, EntityView oldEntityView) throws ThingsboardException { protected void onEntitySaved(User user, EntityView savedEntityView, EntityView oldEntityView) throws ThingsboardException {
tbEntityViewService.updateEntityViewAttributes(user.getTenantId(), savedEntityView, oldEntityView, user); tbEntityViewService.updateEntityViewAttributes(user.getTenantId(), savedEntityView, oldEntityView, user);
super.onEntitySaved(user, savedEntityView, oldEntityView); super.onEntitySaved(user, savedEntityView, oldEntityView);
if (oldEntityView != null) { clusterService.broadcastEntityStateChangeEvent(savedEntityView.getTenantId(), savedEntityView.getId(),
entityActionService.sendEntityNotificationMsgToEdge(user.getTenantId(), savedEntityView.getId(), EdgeEventActionType.UPDATED); oldEntityView == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
}
} }
@Override @Override

6
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java

@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
@ -119,14 +120,15 @@ public class RuleChainImportService extends BaseEntityImportService<RuleChainId,
RuleChainMetaData newMD = exportData.getMetaData(); RuleChainMetaData newMD = exportData.getMetaData();
RuleChainMetaData existingMD = ruleChainService.loadRuleChainMetaData(ctx.getTenantId(), prepared.getId()); RuleChainMetaData existingMD = ruleChainService.loadRuleChainMetaData(ctx.getTenantId(), prepared.getId());
existingMD.setRuleChainId(null); existingMD.setRuleChainId(null);
different = newMD.equals(existingMD); different = !newMD.equals(existingMD);
} }
return different; return different;
} }
@Override @Override
protected void onEntitySaved(User user, RuleChain savedRuleChain, RuleChain oldRuleChain) throws ThingsboardException { protected void onEntitySaved(User user, RuleChain savedRuleChain, RuleChain oldRuleChain) throws ThingsboardException {
super.onEntitySaved(user, savedRuleChain, oldRuleChain); entityActionService.logEntityAction(user, savedRuleChain.getId(), savedRuleChain, null,
oldRuleChain == null ? ActionType.ADDED : ActionType.UPDATED, null);
if (savedRuleChain.getType() == RuleChainType.CORE) { if (savedRuleChain.getType() == RuleChainType.CORE) {
clusterService.broadcastEntityStateChangeEvent(user.getTenantId(), savedRuleChain.getId(), clusterService.broadcastEntityStateChangeEvent(user.getTenantId(), savedRuleChain.getId(),
oldRuleChain == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); oldRuleChain == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);

6
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/WidgetsBundleImportService.java

@ -86,9 +86,13 @@ public class WidgetsBundleImportService extends BaseEntityImportService<WidgetsB
return savedWidgetsBundle; return savedWidgetsBundle;
} }
@Override
protected boolean compare(EntitiesImportCtx ctx, WidgetsBundleExportData exportData, WidgetsBundle prepared, WidgetsBundle existing) {
return true;
}
@Override @Override
protected void onEntitySaved(User user, WidgetsBundle savedWidgetsBundle, WidgetsBundle oldWidgetsBundle) throws ThingsboardException { protected void onEntitySaved(User user, WidgetsBundle savedWidgetsBundle, WidgetsBundle oldWidgetsBundle) throws ThingsboardException {
super.onEntitySaved(user, savedWidgetsBundle, oldWidgetsBundle);
entityNotificationService.notifySendMsgToEdgeService(user.getTenantId(), savedWidgetsBundle.getId(), entityNotificationService.notifySendMsgToEdgeService(user.getTenantId(), savedWidgetsBundle.getId(),
oldWidgetsBundle == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); oldWidgetsBundle == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
} }

21
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -99,7 +99,6 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.Futures.transformAsync;
@Service @Service
@TbCoreComponent @TbCoreComponent
@ -174,9 +173,11 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
private <T> T getStatus(User user, UUID requestId, Function<VersionControlTaskCacheEntry, T> getter) throws ThingsboardException { private <T> T getStatus(User user, UUID requestId, Function<VersionControlTaskCacheEntry, T> getter) throws ThingsboardException {
var cacheEntry = taskCache.get(requestId); var cacheEntry = taskCache.get(requestId);
if (cacheEntry == null || cacheEntry.get() == null) { if (cacheEntry == null || cacheEntry.get() == null) {
log.debug("[{}] No cache record: {}", requestId, cacheEntry);
throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND);
} else { } else {
var entry = cacheEntry.get(); var entry = cacheEntry.get();
log.debug("[{}] Cache get: {}", requestId, entry);
var result = getter.apply(entry); var result = getter.apply(entry);
if (result == null) { if (result == null) {
throw new ThingsboardException(ThingsboardErrorCode.BAD_REQUEST_PARAMS); throw new ThingsboardException(ThingsboardErrorCode.BAD_REQUEST_PARAMS);
@ -362,6 +363,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
.build(); .build();
} }
@SneakyThrows
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private void importEntities(EntitiesImportCtx ctx, EntityType entityType) { private void importEntities(EntitiesImportCtx ctx, EntityType entityType) {
int limit = 100; int limit = 100;
@ -373,9 +375,9 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
log.debug("[{}] Loading {} entities pack ({})", ctx.getTenantId(), entityType, entityDataList.size());
for (EntityExportData entityData : entityDataList) { for (EntityExportData entityData : entityDataList) {
EntityExportData reimportBackup = JacksonUtil.clone(entityData); EntityExportData reimportBackup = JacksonUtil.clone(entityData);
log.debug("[{}] Loading {} entities", ctx.getTenantId(), entityType);
EntityImportResult<?> importResult; EntityImportResult<?> importResult;
try { try {
importResult = exportImportService.importEntity(ctx, entityData); importResult = exportImportService.importEntity(ctx, entityData);
@ -391,6 +393,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
ctx.getImportedEntities().computeIfAbsent(entityType, t -> new HashSet<>()) ctx.getImportedEntities().computeIfAbsent(entityType, t -> new HashSet<>())
.add(importResult.getSavedEntity().getId()); .add(importResult.getSavedEntity().getId());
} }
log.debug("Imported {} pack for tenant {}", entityType, ctx.getTenantId());
offset += limit; offset += limit;
} while (entityDataList.size() == limit); } while (entityDataList.size() == limit);
} }
@ -456,18 +459,20 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
EntityId externalId = ((ExportableEntity<EntityId>) entity).getExternalId(); EntityId externalId = ((ExportableEntity<EntityId>) entity).getExternalId();
if (externalId == null) externalId = entityId; if (externalId == null) externalId = entityId;
return transformAsync(gitServiceQueue.getEntity(user.getTenantId(), versionId, externalId), return transform(gitServiceQueue.getEntity(user.getTenantId(), versionId, externalId),
otherVersion -> { otherVersion -> {
SimpleEntitiesExportCtx ctx = new SimpleEntitiesExportCtx(user, null, null, EntityExportSettings.builder() SimpleEntitiesExportCtx ctx = new SimpleEntitiesExportCtx(user, null, null, EntityExportSettings.builder()
.exportRelations(otherVersion.hasRelations()) .exportRelations(otherVersion.hasRelations())
.exportAttributes(otherVersion.hasAttributes()) .exportAttributes(otherVersion.hasAttributes())
.exportCredentials(otherVersion.hasCredentials()) .exportCredentials(otherVersion.hasCredentials())
.build()); .build());
EntityExportData<?> currentVersion = exportImportService.exportEntity(ctx, entityId); EntityExportData<?> currentVersion;
return transform(gitServiceQueue.getContentsDiff(user.getTenantId(), try {
JacksonUtil.toPrettyString(currentVersion.sort()), currentVersion = exportImportService.exportEntity(ctx, entityId);
JacksonUtil.toPrettyString(otherVersion.sort())), } catch (ThingsboardException e) {
rawDiff -> new EntityDataDiff(currentVersion, otherVersion, rawDiff), MoreExecutors.directExecutor()); throw new RuntimeException(e);
}
return new EntityDataDiff(currentVersion.sort(), otherVersion.sort());
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} }

134
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java

@ -15,7 +15,10 @@
*/ */
package org.thingsboard.server.service.sync.vc; package org.thingsboard.server.service.sync.vc;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@ -23,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.CollectionsUtil;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
@ -71,12 +75,16 @@ import org.thingsboard.server.service.sync.vc.data.VersionsDiffGitRequest;
import org.thingsboard.server.service.sync.vc.data.VoidGitRequest; import org.thingsboard.server.service.sync.vc.data.VoidGitRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -93,9 +101,12 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
private final SchedulerComponent scheduler; private final SchedulerComponent scheduler;
private final Map<UUID, PendingGitRequest<?>> pendingRequestMap = new HashMap<>(); private final Map<UUID, PendingGitRequest<?>> pendingRequestMap = new HashMap<>();
private final Map<UUID, Map<String, String[]>> chunkedMsgs = new ConcurrentHashMap<>();
@Value("${queue.vc.request-timeout:60000}") @Value("${queue.vc.request-timeout:60000}")
private int requestTimeout; private int requestTimeout;
@Value("${queue.vc.msg-chunk-size:500000}")
private int msgChunkSize;
public DefaultGitVersionControlQueueService(TbServiceInfoProvider serviceInfoProvider, TbClusterService clusterService, public DefaultGitVersionControlQueueService(TbServiceInfoProvider serviceInfoProvider, TbClusterService clusterService,
DataDecodingEncodingService encodingService, DataDecodingEncodingService encodingService,
@ -119,20 +130,35 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
return future; return future;
} }
@SuppressWarnings("UnstableApiUsage")
@Override @Override
public ListenableFuture<Void> addToCommit(CommitGitRequest commit, EntityExportData<ExportableEntity<EntityId>> entityData) { public ListenableFuture<Void> addToCommit(CommitGitRequest commit, EntityExportData<ExportableEntity<EntityId>> entityData) {
SettableFuture<Void> future = SettableFuture.create();
String path = getRelativePath(entityData.getEntityType(), entityData.getExternalId()); String path = getRelativePath(entityData.getEntityType(), entityData.getExternalId());
String entityDataJson = JacksonUtil.toPrettyString(entityData.sort()); String entityDataJson = JacksonUtil.toPrettyString(entityData.sort());
registerAndSend(commit, builder -> builder.setCommitRequest( Iterable<String> entityDataChunks = StringUtils.split(entityDataJson, msgChunkSize);
buildCommitRequest(commit).setAddMsg( String chunkedMsgId = UUID.randomUUID().toString();
TransportProtos.AddMsg.newBuilder() int chunksCount = Iterables.size(entityDataChunks);
.setRelativePath(path).setEntityDataJson(entityDataJson).build()
).build() AtomicInteger chunkIndex = new AtomicInteger();
).build(), wrap(future, null)); List<ListenableFuture<Void>> futures = new ArrayList<>();
return future; entityDataChunks.forEach(chunk -> {
SettableFuture<Void> chunkFuture = SettableFuture.create();
log.trace("[{}] sending chunk {} for 'addToCommit'", chunkedMsgId, chunkIndex.get());
registerAndSend(commit, builder -> builder.setCommitRequest(
buildCommitRequest(commit).setAddMsg(
TransportProtos.AddMsg.newBuilder()
.setRelativePath(path).setEntityDataJsonChunk(chunk)
.setChunkedMsgId(chunkedMsgId).setChunkIndex(chunkIndex.getAndIncrement())
.setChunksCount(chunksCount).build()
).build()
).build(), wrap(chunkFuture, null));
futures.add(chunkFuture);
});
return Futures.transform(Futures.allAsList(futures), r -> {
log.trace("[{}] sent all chunks for 'addToCommit'", chunkedMsgId);
return null;
}, MoreExecutors.directExecutor());
} }
@Override @Override
@ -221,7 +247,6 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) {
return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder()
.setBranchName(branch)
.setVersionId(versionId) .setVersionId(versionId)
.setEntityType(entityType.name()) .setEntityType(entityType.name())
.build()); .build());
@ -230,7 +255,6 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) {
return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder()
.setBranchName(branch)
.setVersionId(versionId) .setVersionId(versionId)
.build()); .build());
} }
@ -257,18 +281,11 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
.build())); .build()));
} }
@Override
public ListenableFuture<String> getContentsDiff(TenantId tenantId, String content1, String content2) {
ContentsDiffGitRequest request = new ContentsDiffGitRequest(tenantId, content1, content2);
return sendRequest(request, builder -> builder.setContentsDiffRequest(TransportProtos.ContentsDiffRequestMsg.newBuilder()
.setContent1(content1)
.setContent2(content2)));
}
@Override @Override
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public ListenableFuture<EntityExportData> getEntity(TenantId tenantId, String versionId, EntityId entityId) { public ListenableFuture<EntityExportData> getEntity(TenantId tenantId, String versionId, EntityId entityId) {
EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId); EntityContentGitRequest request = new EntityContentGitRequest(tenantId, versionId, entityId);
chunkedMsgs.put(request.getRequestId(), new HashMap<>());
registerAndSend(request, builder -> builder.setEntityContentRequest(EntityContentRequestMsg.newBuilder() registerAndSend(request, builder -> builder.setEntityContentRequest(EntityContentRequestMsg.newBuilder()
.setVersionId(versionId) .setVersionId(versionId)
.setEntityType(entityId.getEntityType().name()) .setEntityType(entityId.getEntityType().name())
@ -290,9 +307,9 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
var requestBody = enrichFunction.apply(newRequestProto(request, settings)); var requestBody = enrichFunction.apply(newRequestProto(request, settings));
log.trace("[{}][{}] PUSHING request: {}", request.getTenantId(), request.getRequestId(), requestBody); log.trace("[{}][{}] PUSHING request: {}", request.getTenantId(), request.getRequestId(), requestBody);
clusterService.pushMsgToVersionControl(request.getTenantId(), requestBody, callback); clusterService.pushMsgToVersionControl(request.getTenantId(), requestBody, callback);
request.setTimeoutTask(scheduler.schedule(() -> { if (request.getTimeoutTask() == null) {
processTimeout(request.getRequestId()); request.setTimeoutTask(scheduler.schedule(() -> processTimeout(request.getRequestId()), requestTimeout, TimeUnit.MILLISECONDS));
}, requestTimeout, TimeUnit.MILLISECONDS)); }
} else { } else {
throw new RuntimeException("Future is already done!"); throw new RuntimeException("Future is already done!");
} }
@ -310,7 +327,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) { public ListenableFuture<List<EntityExportData>> getEntities(TenantId tenantId, String versionId, EntityType entityType, int offset, int limit) {
EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType); EntitiesContentGitRequest request = new EntitiesContentGitRequest(tenantId, versionId, entityType);
chunkedMsgs.put(request.getRequestId(), new HashMap<>());
registerAndSend(request, builder -> builder.setEntitiesContentRequest(EntitiesContentRequestMsg.newBuilder() registerAndSend(request, builder -> builder.setEntitiesContentRequest(EntitiesContentRequestMsg.newBuilder()
.setVersionId(versionId) .setVersionId(versionId)
.setEntityType(entityType.name()) .setEntityType(entityType.name())
@ -356,15 +373,15 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
@Override @Override
public void processResponse(VersionControlResponseMsg vcResponseMsg) { public void processResponse(VersionControlResponseMsg vcResponseMsg) {
UUID requestId = new UUID(vcResponseMsg.getRequestIdMSB(), vcResponseMsg.getRequestIdLSB()); UUID requestId = new UUID(vcResponseMsg.getRequestIdMSB(), vcResponseMsg.getRequestIdLSB());
PendingGitRequest<?> request = pendingRequestMap.remove(requestId); PendingGitRequest<?> request = pendingRequestMap.get(requestId);
if (request == null) { if (request == null) {
log.debug("[{}] received stale response: {}", requestId, vcResponseMsg); log.debug("[{}] received stale response: {}", requestId, vcResponseMsg);
return; return;
} else { } else {
log.debug("[{}] processing response: {}", requestId, vcResponseMsg); log.debug("[{}] processing response: {}", requestId, vcResponseMsg);
request.getTimeoutTask().cancel(true);
} }
var future = request.getFuture(); var future = request.getFuture();
boolean completed = true;
if (!StringUtils.isEmpty(vcResponseMsg.getError())) { if (!StringUtils.isEmpty(vcResponseMsg.getError())) {
future.setException(new RuntimeException(vcResponseMsg.getError())); future.setException(new RuntimeException(vcResponseMsg.getError()));
} else { } else {
@ -392,12 +409,28 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
var listVersionsResponse = vcResponseMsg.getListVersionsResponse(); var listVersionsResponse = vcResponseMsg.getListVersionsResponse();
((ListVersionsGitRequest) request).getFuture().set(toPageData(listVersionsResponse)); ((ListVersionsGitRequest) request).getFuture().set(toPageData(listVersionsResponse));
} else if (vcResponseMsg.hasEntityContentResponse()) { } else if (vcResponseMsg.hasEntityContentResponse()) {
var data = vcResponseMsg.getEntityContentResponse().getData(); TransportProtos.EntityContentResponseMsg responseMsg = vcResponseMsg.getEntityContentResponse();
((EntityContentGitRequest) request).getFuture().set(toData(data)); log.trace("[{}] received chunk {} for 'getEntity'", responseMsg.getChunkedMsgId(), responseMsg.getChunkIndex());
var joined = joinChunks(requestId, responseMsg, 1);
if (joined.isPresent()) {
log.trace("[{}] collected all chunks for 'getEntity'", responseMsg.getChunkedMsgId());
((EntityContentGitRequest) request).getFuture().set(joined.get().get(0));
} else {
completed = false;
}
} else if (vcResponseMsg.hasEntitiesContentResponse()) { } else if (vcResponseMsg.hasEntitiesContentResponse()) {
var dataList = vcResponseMsg.getEntitiesContentResponse().getDataList(); TransportProtos.EntitiesContentResponseMsg responseMsg = vcResponseMsg.getEntitiesContentResponse();
((EntitiesContentGitRequest) request).getFuture() TransportProtos.EntityContentResponseMsg item = responseMsg.getItem();
.set(dataList.stream().map(this::toData).collect(Collectors.toList())); if (responseMsg.getItemsCount() > 0) {
var joined = joinChunks(requestId, item, responseMsg.getItemsCount());
if (joined.isPresent()) {
((EntitiesContentGitRequest) request).getFuture().set(joined.get());
} else {
completed = false;
}
} else {
((EntitiesContentGitRequest) request).getFuture().set(Collections.emptyList());
}
} else if (vcResponseMsg.hasVersionsDiffResponse()) { } else if (vcResponseMsg.hasVersionsDiffResponse()) {
TransportProtos.VersionsDiffResponseMsg diffResponse = vcResponseMsg.getVersionsDiffResponse(); TransportProtos.VersionsDiffResponseMsg diffResponse = vcResponseMsg.getVersionsDiffResponse();
List<EntityVersionsDiff> entityVersionsDiffList = diffResponse.getDiffList().stream() List<EntityVersionsDiff> entityVersionsDiffList = diffResponse.getDiffList().stream()
@ -412,21 +445,50 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
.build()) .build())
.collect(Collectors.toList()); .collect(Collectors.toList());
((VersionsDiffGitRequest) request).getFuture().set(entityVersionsDiffList); ((VersionsDiffGitRequest) request).getFuture().set(entityVersionsDiffList);
} else if (vcResponseMsg.hasContentsDiffResponse()) {
String diff = vcResponseMsg.getContentsDiffResponse().getDiff();
((ContentsDiffGitRequest) request).getFuture().set(diff);
} }
} }
if (completed) {
removePendingRequest(requestId);
}
}
@SuppressWarnings("rawtypes")
private Optional<List<EntityExportData>> joinChunks(UUID requestId, TransportProtos.EntityContentResponseMsg responseMsg, int expectedMsgCount) {
var chunksMap = chunkedMsgs.get(requestId);
if (chunksMap == null) {
return Optional.empty();
}
String[] msgChunks = chunksMap.computeIfAbsent(responseMsg.getChunkedMsgId(), id -> new String[responseMsg.getChunksCount()]);
msgChunks[responseMsg.getChunkIndex()] = responseMsg.getData();
if (chunksMap.size() == expectedMsgCount && chunksMap.values().stream()
.allMatch(chunks -> CollectionsUtil.countNonNull(chunks) == chunks.length)) {
return Optional.of(chunksMap.values().stream()
.map(chunks -> String.join("", chunks))
.map(this::toData)
.collect(Collectors.toList()));
} else {
return Optional.empty();
}
} }
private void processTimeout(UUID requestId) { private void processTimeout(UUID requestId) {
PendingGitRequest<?> pendingRequest = pendingRequestMap.remove(requestId); PendingGitRequest<?> pendingRequest = removePendingRequest(requestId);
if (pendingRequest != null) { if (pendingRequest != null) {
log.debug("[{}] request timed out ({} ms}", requestId, requestTimeout); log.debug("[{}] request timed out ({} ms}", requestId, requestTimeout);
pendingRequest.getFuture().setException(new TimeoutException("Request timed out")); pendingRequest.getFuture().setException(new TimeoutException("Request timed out"));
} }
} }
private PendingGitRequest<?> removePendingRequest(UUID requestId) {
PendingGitRequest<?> pendingRequest = pendingRequestMap.remove(requestId);
if (pendingRequest != null && pendingRequest.getTimeoutTask() != null) {
pendingRequest.getTimeoutTask().cancel(true);
pendingRequest.setTimeoutTask(null);
}
chunkedMsgs.remove(requestId);
return pendingRequest;
}
private PageData<EntityVersion> toPageData(TransportProtos.ListVersionsResponseMsg listVersionsResponse) { private PageData<EntityVersion> toPageData(TransportProtos.ListVersionsResponseMsg listVersionsResponse) {
var listVersions = listVersionsResponse.getVersionsList().stream().map(this::getEntityVersion).collect(Collectors.toList()); var listVersions = listVersionsResponse.getVersionsList().stream().map(this::getEntityVersion).collect(Collectors.toList());
return new PageData<>(listVersions, listVersionsResponse.getTotalPages(), listVersionsResponse.getTotalElements(), listVersionsResponse.getHasNext()); return new PageData<>(listVersions, listVersionsResponse.getTotalPages(), listVersionsResponse.getTotalElements(), listVersionsResponse.getHasNext());
@ -450,6 +512,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
return JacksonUtil.fromString(data, EntityExportData.class); return JacksonUtil.fromString(data, EntityExportData.class);
} }
//The future will be completed when the corresponding result arrives from kafka
private static <T> TbQueueCallback wrap(SettableFuture<T> future) { private static <T> TbQueueCallback wrap(SettableFuture<T> future) {
return new TbQueueCallback() { return new TbQueueCallback() {
@Override @Override
@ -463,7 +526,8 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
}; };
} }
private static <T> TbQueueCallback wrap(SettableFuture<T> future, T value) { //The future will be completed when the request is successfully sent to kafka
private <T> TbQueueCallback wrap(SettableFuture<T> future, T value) {
return new TbQueueCallback() { return new TbQueueCallback() {
@Override @Override
public void onSuccess(TbQueueMsgMetadata metadata) { public void onSuccess(TbQueueMsgMetadata metadata) {

2
application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java

@ -64,8 +64,6 @@ public interface GitVersionControlQueueService {
ListenableFuture<List<EntityVersionsDiff>> getVersionsDiff(TenantId tenantId, EntityType entityType, EntityId externalId, String versionId1, String versionId2); ListenableFuture<List<EntityVersionsDiff>> getVersionsDiff(TenantId tenantId, EntityType entityType, EntityId externalId, String versionId1, String versionId2);
ListenableFuture<String> getContentsDiff(TenantId tenantId, String rawEntityData1, String rawEntityData2);
ListenableFuture<Void> initRepository(TenantId tenantId, RepositorySettings settings); ListenableFuture<Void> initRepository(TenantId tenantId, RepositorySettings settings);
ListenableFuture<Void> testRepository(TenantId tenantId, RepositorySettings settings); ListenableFuture<Void> testRepository(TenantId tenantId, RepositorySettings settings);

1
application/src/main/resources/thingsboard.yml

@ -1027,6 +1027,7 @@ queue:
poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}"
pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:60000}" pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:60000}"
request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:60000}" request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:60000}"
msg-chunk-size: "${TB_QUEUE_VC_MSG_CHUNK_SIZE:500000}"
js: js:
# JS Eval request topic # JS Eval request topic
request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}" request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}"

2
common/cache/src/main/java/org/thingsboard/server/cache/SimpleTbCacheValueWrapper.java

@ -17,8 +17,10 @@ package org.thingsboard.server.cache;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
@ToString
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class SimpleTbCacheValueWrapper<T> implements TbCacheValueWrapper<T> { public class SimpleTbCacheValueWrapper<T> implements TbCacheValueWrapper<T> {

27
common/cluster-api/src/main/proto/queue.proto

@ -715,7 +715,10 @@ message PrepareMsg {
message AddMsg { message AddMsg {
string relativePath = 1; string relativePath = 1;
string entityDataJson = 2; string entityDataJsonChunk = 2;
string chunkedMsgId = 3;
int32 chunkIndex = 4;
int32 chunksCount = 5;
} }
message DeleteMsg { message DeleteMsg {
@ -755,9 +758,8 @@ message ListVersionsResponseMsg {
} }
message ListEntitiesRequestMsg { message ListEntitiesRequestMsg {
string branchName = 1; string versionId = 1;
string versionId = 2; string entityType = 2;
string entityType = 3;
} }
message VersionedEntityInfoProto { message VersionedEntityInfoProto {
@ -791,6 +793,9 @@ message EntityContentRequestMsg {
message EntityContentResponseMsg { message EntityContentResponseMsg {
string data = 1; string data = 1;
string chunkedMsgId = 2;
int32 chunkIndex = 3;
int32 chunksCount = 4;
} }
message EntitiesContentRequestMsg { message EntitiesContentRequestMsg {
@ -801,7 +806,8 @@ message EntitiesContentRequestMsg {
} }
message EntitiesContentResponseMsg { message EntitiesContentResponseMsg {
repeated string data = 1; EntityContentResponseMsg item = 1;
int32 itemsCount = 2;
} }
message VersionsDiffRequestMsg { message VersionsDiffRequestMsg {
@ -823,15 +829,6 @@ message EntityVersionsDiff {
string rawDiff = 6; string rawDiff = 6;
} }
message ContentsDiffRequestMsg {
string content1 = 1;
string content2 = 2;
}
message ContentsDiffResponseMsg {
string diff = 1;
}
message GenericRepositoryRequestMsg {} message GenericRepositoryRequestMsg {}
message GenericRepositoryResponseMsg {} message GenericRepositoryResponseMsg {}
@ -853,7 +850,6 @@ message ToVersionControlServiceMsg {
EntityContentRequestMsg entityContentRequest = 14; EntityContentRequestMsg entityContentRequest = 14;
EntitiesContentRequestMsg entitiesContentRequest = 15; EntitiesContentRequestMsg entitiesContentRequest = 15;
VersionsDiffRequestMsg versionsDiffRequest = 16; VersionsDiffRequestMsg versionsDiffRequest = 16;
ContentsDiffRequestMsg contentsDiffRequest = 17;
} }
message VersionControlResponseMsg { message VersionControlResponseMsg {
@ -868,7 +864,6 @@ message VersionControlResponseMsg {
EntityContentResponseMsg entityContentResponse = 9; EntityContentResponseMsg entityContentResponse = 9;
EntitiesContentResponseMsg entitiesContentResponse = 10; EntitiesContentResponseMsg entitiesContentResponse = 10;
VersionsDiffResponseMsg versionsDiffResponse = 11; VersionsDiffResponseMsg versionsDiffResponse = 11;
ContentsDiffResponseMsg contentsDiffResponse = 12;
} }
/** /**

6
common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import com.google.common.base.Splitter;
import static org.apache.commons.lang3.StringUtils.repeat; import static org.apache.commons.lang3.StringUtils.repeat;
public class StringUtils { public class StringUtils {
@ -92,4 +94,8 @@ public class StringUtils {
return input.substring(0, startIndexInclusive) + obfuscatedPart + input.substring(endIndexExclusive); return input.substring(0, startIndexInclusive) + obfuscatedPart + input.substring(endIndexExclusive);
} }
public static Iterable<String> split(String value, int maxPartSize) {
return Splitter.fixedLength(maxPartSize).split(value);
}
} }

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataDiff.java

@ -24,5 +24,4 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportData;
public class EntityDataDiff { public class EntityDataDiff {
private EntityExportData<?> currentVersion; private EntityExportData<?> currentVersion;
private EntityExportData<?> otherVersion; private EntityExportData<?> otherVersion;
private String rawDiff;
} }

5
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityLoadError.java

@ -20,12 +20,15 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import java.io.Serializable;
import java.util.List; import java.util.List;
@Data @Data
@Builder @Builder
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class EntityLoadError { public class EntityLoadError implements Serializable {
private static final long serialVersionUID = 7538450180582109391L;
private String type; private String type;
private EntityId source; private EntityId source;

6
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityTypeLoadResult.java

@ -21,11 +21,15 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import java.io.Serializable;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Builder @Builder
public class EntityTypeLoadResult { public class EntityTypeLoadResult implements Serializable {
private static final long serialVersionUID = -8428039809651395241L;
private EntityType entityType; private EntityType entityType;
private int created; private int created;
private int updated; private int updated;

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/VersionedEntityInfo.java

@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.id.EntityId;
@NoArgsConstructor @NoArgsConstructor
public class VersionedEntityInfo { public class VersionedEntityInfo {
private EntityId externalId; private EntityId externalId;
// etc..
public VersionedEntityInfo(EntityId externalId) { public VersionedEntityInfo(EntityId externalId) {
this.externalId = externalId; this.externalId = externalId;

8
common/util/src/main/java/org/thingsboard/common/util/CollectionsUtil.java

@ -39,4 +39,12 @@ public class CollectionsUtil {
return isNotEmpty(collection) && collection.contains(element); return isNotEmpty(collection) && collection.contains(element);
} }
public static <T> int countNonNull(T[] array) {
int count = 0;
for (T t : array) {
if (t != null) count++;
}
return count;
}
} }

68
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/DefaultClusterVersionControlService.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.service.sync.vc; package org.thingsboard.server.service.sync.vc;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -28,6 +29,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.CollectionsUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
@ -89,6 +91,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function; import java.util.function.Function;
@ -123,6 +126,8 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
private long packProcessingTimeout; private long packProcessingTimeout;
@Value("${vc.git.io_pool_size:3}") @Value("${vc.git.io_pool_size:3}")
private int ioPoolSize; private int ioPoolSize;
@Value("${queue.vc.msg-chunk-size:500000}")
private int msgChunkSize;
//We need to manually manage the threads since tasks for particular tenant need to be processed sequentially. //We need to manually manage the threads since tasks for particular tenant need to be processed sequentially.
private final List<ListeningExecutorService> ioThreads = new ArrayList<>(); private final List<ListeningExecutorService> ioThreads = new ArrayList<>();
@ -252,8 +257,6 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
handleEntitiesContentRequest(ctx, msg.getEntitiesContentRequest()); handleEntitiesContentRequest(ctx, msg.getEntitiesContentRequest());
} else if (msg.hasVersionsDiffRequest()) { } else if (msg.hasVersionsDiffRequest()) {
handleVersionsDiffRequest(ctx, msg.getVersionsDiffRequest()); handleVersionsDiffRequest(ctx, msg.getVersionsDiffRequest());
} else if (msg.hasContentsDiffRequest()) {
handleContentsDiffRequest(ctx, msg.getContentsDiffRequest());
} }
} }
} }
@ -270,19 +273,49 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
String path = getRelativePath(entityType, null); String path = getRelativePath(entityType, null);
var ids = vcService.listEntitiesAtVersion(ctx.getTenantId(), request.getVersionId(), path) var ids = vcService.listEntitiesAtVersion(ctx.getTenantId(), request.getVersionId(), path)
.stream().skip(request.getOffset()).limit(request.getLimit()).collect(Collectors.toList()); .stream().skip(request.getOffset()).limit(request.getLimit()).collect(Collectors.toList());
var response = EntitiesContentResponseMsg.newBuilder(); if (!ids.isEmpty()) {
for (VersionedEntityInfo info : ids) { for (VersionedEntityInfo info : ids) {
var data = vcService.getFileContentAtCommit(ctx.getTenantId(), var data = vcService.getFileContentAtCommit(ctx.getTenantId(),
getRelativePath(info.getExternalId().getEntityType(), info.getExternalId().getId().toString()), request.getVersionId()); getRelativePath(info.getExternalId().getEntityType(), info.getExternalId().getId().toString()), request.getVersionId());
response.addData(data);
Iterable<String> dataChunks = StringUtils.split(data, msgChunkSize);
String chunkedMsgId = UUID.randomUUID().toString();
int chunksCount = Iterables.size(dataChunks);
AtomicInteger chunkIndex = new AtomicInteger();
dataChunks.forEach(chunk -> {
EntitiesContentResponseMsg.Builder response = EntitiesContentResponseMsg.newBuilder()
.setItemsCount(ids.size())
.setItem(EntityContentResponseMsg.newBuilder()
.setData(chunk)
.setChunkedMsgId(chunkedMsgId)
.setChunksCount(chunksCount)
.setChunkIndex(chunkIndex.getAndIncrement())
.build());
reply(ctx, Optional.empty(), builder -> builder.setEntitiesContentResponse(response));
});
}
} else {
reply(ctx, Optional.empty(), builder -> builder.setEntitiesContentResponse(
EntitiesContentResponseMsg.newBuilder()
.setItemsCount(0)));
} }
reply(ctx, Optional.empty(), builder -> builder.setEntitiesContentResponse(response));
} }
private void handleEntityContentRequest(VersionControlRequestCtx ctx, EntityContentRequestMsg request) throws IOException { private void handleEntityContentRequest(VersionControlRequestCtx ctx, EntityContentRequestMsg request) throws IOException {
String path = getRelativePath(EntityType.valueOf(request.getEntityType()), new UUID(request.getEntityIdMSB(), request.getEntityIdLSB()).toString()); String path = getRelativePath(EntityType.valueOf(request.getEntityType()), new UUID(request.getEntityIdMSB(), request.getEntityIdLSB()).toString());
String data = vcService.getFileContentAtCommit(ctx.getTenantId(), path, request.getVersionId()); String data = vcService.getFileContentAtCommit(ctx.getTenantId(), path, request.getVersionId());
reply(ctx, Optional.empty(), builder -> builder.setEntityContentResponse(EntityContentResponseMsg.newBuilder().setData(data)));
Iterable<String> dataChunks = StringUtils.split(data, msgChunkSize);
String chunkedMsgId = UUID.randomUUID().toString();
int chunksCount = Iterables.size(dataChunks);
AtomicInteger chunkIndex = new AtomicInteger();
dataChunks.forEach(chunk -> {
log.trace("[{}] sending chunk {} for 'getEntity'", chunkedMsgId, chunkIndex.get());
reply(ctx, Optional.empty(), builder -> builder.setEntityContentResponse(EntityContentResponseMsg.newBuilder()
.setData(chunk).setChunkedMsgId(chunkedMsgId).setChunksCount(chunksCount)
.setChunkIndex(chunkIndex.getAndIncrement())));
});
} }
private void handleListVersions(VersionControlRequestCtx ctx, ListVersionsRequestMsg request) throws Exception { private void handleListVersions(VersionControlRequestCtx ctx, ListVersionsRequestMsg request) throws Exception {
@ -359,12 +392,6 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
.addAllDiff(diffList))); .addAllDiff(diffList)));
} }
private void handleContentsDiffRequest(VersionControlRequestCtx ctx, TransportProtos.ContentsDiffRequestMsg request) throws IOException {
String diff = vcService.getContentsDiff(ctx.getTenantId(), request.getContent1(), request.getContent2());
reply(ctx, builder -> builder.setContentsDiffResponse(TransportProtos.ContentsDiffResponseMsg.newBuilder()
.setDiff(diff)));
}
private void handleCommitRequest(VersionControlRequestCtx ctx, CommitRequestMsg request) throws Exception { private void handleCommitRequest(VersionControlRequestCtx ctx, CommitRequestMsg request) throws Exception {
var tenantId = ctx.getTenantId(); var tenantId = ctx.getTenantId();
UUID txId = UUID.fromString(request.getTxId()); UUID txId = UUID.fromString(request.getTxId());
@ -416,7 +443,16 @@ public class DefaultClusterVersionControlService extends TbApplicationEventListe
} }
private void addToCommit(VersionControlRequestCtx ctx, PendingCommit commit, AddMsg addMsg) throws IOException { private void addToCommit(VersionControlRequestCtx ctx, PendingCommit commit, AddMsg addMsg) throws IOException {
vcService.add(commit, addMsg.getRelativePath(), addMsg.getEntityDataJson()); log.trace("[{}] received chunk {} for 'addToCommit'", addMsg.getChunkedMsgId(), addMsg.getChunkIndex());
Map<String, String[]> chunkedMsgs = commit.getChunkedMsgs();
String[] msgChunks = chunkedMsgs.computeIfAbsent(addMsg.getChunkedMsgId(), id -> new String[addMsg.getChunksCount()]);
msgChunks[addMsg.getChunkIndex()] = addMsg.getEntityDataJsonChunk();
if (CollectionsUtil.countNonNull(msgChunks) == msgChunks.length) {
log.trace("[{}] collected all chunks for 'addToCommit'", addMsg.getChunkedMsgId());
String entityDataJson = String.join("", msgChunks);
chunkedMsgs.remove(addMsg.getChunkedMsgId());
vcService.add(commit, addMsg.getRelativePath(), entityDataJson);
}
} }
private void doAbortCurrentCommit(TenantId tenantId, PendingCommit current) { private void doAbortCurrentCommit(TenantId tenantId, PendingCommit current) {

13
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/PendingCommit.java

@ -18,7 +18,9 @@ package org.thingsboard.server.service.sync.vc;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Data @Data
public class PendingCommit { public class PendingCommit {
@ -31,9 +33,10 @@ public class PendingCommit {
private String versionName; private String versionName;
private String authorName; private String authorName;
private String authorEmail; private String authorEmail;
private Map<String, String[]> chunkedMsgs;
public PendingCommit(TenantId tenantId, String nodeId, UUID txId, String branch, String versionName, String authorName, String authorEmail) { public PendingCommit(TenantId tenantId, String nodeId, UUID txId, String branch, String versionName, String authorName, String authorEmail) {
this.tenantId = tenantId; this.tenantId = tenantId;
this.nodeId = nodeId; this.nodeId = nodeId;
@ -44,4 +47,12 @@ public class PendingCommit {
this.authorEmail = authorEmail; this.authorEmail = authorEmail;
this.workingBranch = txId.toString(); this.workingBranch = txId.toString();
} }
public Map<String, String[]> getChunkedMsgs() {
if (chunkedMsgs == null) {
chunkedMsgs = new ConcurrentHashMap<>();
}
return chunkedMsgs;
}
} }

8
docker/.gitignore

@ -6,4 +6,12 @@ tb-node/postgres/**
tb-node/cassandra/** tb-node/cassandra/**
tb-transports/*/log tb-transports/*/log
tb-vc-executor/log/** tb-vc-executor/log/**
tb-node/redis-cluster-data-0/**
tb-node/redis-cluster-data-1/**
tb-node/redis-cluster-data-2/**
tb-node/redis-cluster-data-3/**
tb-node/redis-cluster-data-4/**
tb-node/redis-cluster-data-5/**
tb-node/redis-data/**
!.env !.env

1
msa/vc-executor/src/main/resources/tb-vc-executor.yml

@ -168,6 +168,7 @@ queue:
partitions: "${TB_QUEUE_VC_PARTITIONS:10}" partitions: "${TB_QUEUE_VC_PARTITIONS:10}"
poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}"
pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:60000}" pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:60000}"
msg-chunk-size: "${TB_QUEUE_VC_MSG_CHUNK_SIZE:500000}"
vc: vc:
# Pool size for handling export tasks # Pool size for handling export tasks

1
ui-ngx/src/app/shared/models/vc.models.ts

@ -228,7 +228,6 @@ export interface RuleChainExportData extends EntityExportData<RuleChain> {
export interface EntityDataDiff { export interface EntityDataDiff {
currentVersion: EntityExportData<any>; currentVersion: EntityExportData<any>;
otherVersion: EntityExportData<any>; otherVersion: EntityExportData<any>;
rawDiff: string;
} }
export function entityExportDataToJsonString(data: EntityExportData<any>): string { export function entityExportDataToJsonString(data: EntityExportData<any>): string {

Loading…
Cancel
Save