Merge branch 'master' of github.com:thingsboard/thingsboard

This commit is contained in:
Igor Kulikov 2021-12-09 18:46:48 +02:00
commit 8663eb56bd
17 changed files with 156 additions and 101 deletions

View File

@ -22,9 +22,49 @@ CREATE TABLE IF NOT EXISTS entity_alarm (
alarm_type varchar(255) NOT NULL,
customer_id uuid,
alarm_id uuid,
CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id),
CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id),
CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC);
CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC);
INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id)
SELECT tenant_id,
CASE
WHEN originator_type = 0 THEN 'TENANT'
WHEN originator_type = 1 THEN 'CUSTOMER'
WHEN originator_type = 2 THEN 'USER'
WHEN originator_type = 3 THEN 'DASHBOARD'
WHEN originator_type = 4 THEN 'ASSET'
WHEN originator_type = 5 THEN 'DEVICE'
WHEN originator_type = 6 THEN 'ALARM'
WHEN originator_type = 7 THEN 'RULE_CHAIN'
WHEN originator_type = 8 THEN 'RULE_NODE'
WHEN originator_type = 9 THEN 'ENTITY_VIEW'
WHEN originator_type = 10 THEN 'WIDGETS_BUNDLE'
WHEN originator_type = 11 THEN 'WIDGET_TYPE'
WHEN originator_type = 12 THEN 'TENANT_PROFILE'
WHEN originator_type = 13 THEN 'DEVICE_PROFILE'
WHEN originator_type = 14 THEN 'API_USAGE_STATE'
WHEN originator_type = 15 THEN 'TB_RESOURCE'
WHEN originator_type = 16 THEN 'OTA_PACKAGE'
WHEN originator_type = 17 THEN 'EDGE'
WHEN originator_type = 18 THEN 'RPC'
else 'UNKNOWN'
END,
originator_id,
created_time,
type,
customer_id,
id
FROM alarm
ON CONFLICT DO NOTHING;
INSERT INTO entity_alarm(tenant_id, entity_type, entity_id, created_time, alarm_type, customer_id, alarm_id)
SELECT a.tenant_id, r.from_type, r.from_id, created_time, type, customer_id, id
FROM alarm a
INNER JOIN relation r ON r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id
ON CONFLICT DO NOTHING;
DELETE FROM relation r WHERE r.relation_type_group = 'ALARM';

View File

@ -43,6 +43,7 @@ import java.sql.SQLSyntaxErrorException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO;
import static org.thingsboard.server.service.install.DatabaseHelper.ASSIGNED_CUSTOMERS;
@ -474,16 +475,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL);
loadSql(schemaUpdateFile, conn);
try {
conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" +
" select tenant_id, originator_id, created_time, type, customer_id, id from alarm;");
conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id)" +
" select a.tenant_id, r.from_id, created_time, type, customer_id, id" +
" from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;");
conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';");
} catch (Exception e) {
log.error("Failed to update alarm relations!!!", e);
}
log.info("Updating schema settings...");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;");
log.info("Schema updated.");
@ -498,10 +489,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
private void loadSql(Path sqlFile, Connection conn) throws Exception {
String sql = new String(Files.readAllBytes(sqlFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
Statement st = conn.createStatement();
st.setQueryTimeout((int) TimeUnit.HOURS.toSeconds(3));
st.execute(sql);//NOSONAR, ignoring because method used to execute thingsboard database upgrade script
printWarnings(st);
Thread.sleep(5000);
}
protected void printWarnings(Statement statement) throws SQLException {
SQLWarning warnings = statement.getWarnings();
if (warnings != null) {
log.info("{}", warnings.getMessage());
SQLWarning nextWarning = warnings.getNextWarning();
while (nextWarning != null) {
log.info("{}", nextWarning.getMessage());
nextWarning = nextWarning.getNextWarning();
}
}
}
protected boolean isOldSchema(Connection conn, long fromVersion) {
boolean isOldSchema = true;
try {

View File

@ -139,7 +139,7 @@ public class DefaultDataUpdateService implements DataUpdateService {
break;
case "3.3.2":
log.info("Updating data from version 3.3.2 to 3.3.3 ...");
nestedRuleNodeUpdater.updateEntities(null);
updateNestedRuleChains();
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
@ -225,73 +225,73 @@ public class DefaultDataUpdateService implements DataUpdateService {
}
};
private final PaginatedUpdater<String, Tenant> nestedRuleNodeUpdater =
new PaginatedUpdater<>() {
@Override
protected String getName() {
return "Tenants nested rule chain updater";
}
@Override
protected boolean forceReportTotal() {
return true;
}
@Override
protected PageData<Tenant> findEntities(String region, PageLink pageLink) {
return tenantService.findTenants(pageLink);
}
@Override
protected void updateEntity(Tenant tenant) {
private void updateNestedRuleChains() {
try {
var packSize = 1024;
var updated = 0;
boolean hasNext = true;
while (hasNext) {
List<EntityRelation> relations = relationService.findRuleNodeToRuleChainRelations(TenantId.SYS_TENANT_ID, RuleChainType.CORE, packSize);
hasNext = relations.size() == packSize;
for (EntityRelation relation : relations) {
try {
var tenantId = tenant.getId();
var packSize = 1024;
boolean hasNext = true;
while (hasNext) {
List<EntityRelation> relations = relationService.findRuleNodeToRuleChainRelations(tenantId, RuleChainType.CORE, packSize);
hasNext = relations.size() == packSize;
for (EntityRelation relation : relations) {
RuleNode sourceNode = ruleChainService.findRuleNodeById(tenantId, new RuleNodeId(relation.getFrom().getId()));
RuleChainId sourceRuleChainId = sourceNode.getRuleChainId();
RuleChain targetRuleChain = ruleChainService.findRuleChainById(tenantId, new RuleChainId(relation.getTo().getId()));
RuleNode targetNode = new RuleNode();
targetNode.setName(targetRuleChain.getName());
targetNode.setRuleChainId(sourceRuleChainId);
targetNode.setType(TbRuleChainInputNode.class.getName());
TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration();
configuration.setRuleChainId(targetRuleChain.getId().toString());
targetNode.setConfiguration(JacksonUtil.valueToTree(configuration));
targetNode.setAdditionalInfo(relation.getAdditionalInfo());
targetNode.setDebugMode(false);
targetNode = ruleChainService.saveRuleNode(tenantId, targetNode);
EntityRelation sourceRuleChainToRuleNode = new EntityRelation();
sourceRuleChainToRuleNode.setFrom(sourceRuleChainId);
sourceRuleChainToRuleNode.setTo(targetNode.getId());
sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE);
sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN);
relationService.saveRelation(tenantId, sourceRuleChainToRuleNode);
EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation();
sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId());
sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId());
sourceRuleNodeToTargetRuleNode.setType(relation.getType());
sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE);
sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo());
relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode);
//Delete old relation
relationService.deleteRelation(tenantId, relation);
}
RuleNodeId sourceNodeId = new RuleNodeId(relation.getFrom().getId());
RuleNode sourceNode = ruleChainService.findRuleNodeById(TenantId.SYS_TENANT_ID, sourceNodeId);
if (sourceNode == null) {
log.info("Skip processing of relation for non existing source rule node: [{}]", sourceNodeId);
relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation);
continue;
}
RuleChainId sourceRuleChainId = sourceNode.getRuleChainId();
RuleChainId targetRuleChainId = new RuleChainId(relation.getTo().getId());
RuleChain targetRuleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, targetRuleChainId);
if (targetRuleChain == null) {
log.info("Skip processing of relation for non existing target rule chain: [{}]", targetRuleChainId);
relationService.deleteRelation(TenantId.SYS_TENANT_ID, relation);
continue;
}
TenantId tenantId = targetRuleChain.getTenantId();
RuleNode targetNode = new RuleNode();
targetNode.setName(targetRuleChain.getName());
targetNode.setRuleChainId(sourceRuleChainId);
targetNode.setType(TbRuleChainInputNode.class.getName());
TbRuleChainInputNodeConfiguration configuration = new TbRuleChainInputNodeConfiguration();
configuration.setRuleChainId(targetRuleChain.getId().toString());
targetNode.setConfiguration(JacksonUtil.valueToTree(configuration));
targetNode.setAdditionalInfo(relation.getAdditionalInfo());
targetNode.setDebugMode(false);
targetNode = ruleChainService.saveRuleNode(tenantId, targetNode);
EntityRelation sourceRuleChainToRuleNode = new EntityRelation();
sourceRuleChainToRuleNode.setFrom(sourceRuleChainId);
sourceRuleChainToRuleNode.setTo(targetNode.getId());
sourceRuleChainToRuleNode.setType(EntityRelation.CONTAINS_TYPE);
sourceRuleChainToRuleNode.setTypeGroup(RelationTypeGroup.RULE_CHAIN);
relationService.saveRelation(tenantId, sourceRuleChainToRuleNode);
EntityRelation sourceRuleNodeToTargetRuleNode = new EntityRelation();
sourceRuleNodeToTargetRuleNode.setFrom(sourceNode.getId());
sourceRuleNodeToTargetRuleNode.setTo(targetNode.getId());
sourceRuleNodeToTargetRuleNode.setType(relation.getType());
sourceRuleNodeToTargetRuleNode.setTypeGroup(RelationTypeGroup.RULE_NODE);
sourceRuleNodeToTargetRuleNode.setAdditionalInfo(relation.getAdditionalInfo());
relationService.saveRelation(tenantId, sourceRuleNodeToTargetRuleNode);
//Delete old relation
relationService.deleteRelation(tenantId, relation);
updated++;
} catch (Exception e) {
log.error("Unable to update Tenant", e);
log.info("Failed to update RuleNodeToRuleChainRelation: {}", relation, e);
}
}
};
if (updated > 0) {
log.info("RuleNodeToRuleChainRelations: {} entities updated so far...", updated);
}
}
} catch (Exception e) {
log.error("Unable to update Tenant", e);
}
}
private final PaginatedUpdater<String, Tenant> tenantsDefaultEdgeRuleChainUpdater =
new PaginatedUpdater<>() {

View File

@ -63,4 +63,6 @@ public interface AlarmService {
PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId,
AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId);
}

View File

@ -30,8 +30,6 @@ public interface EntityService {
CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId);
void deleteEntityRelations(TenantId tenantId, EntityId entityId);
long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query);

View File

@ -64,4 +64,6 @@ public interface AlarmDao extends Dao<Alarm> {
void createEntityAlarmRecord(EntityAlarm entityAlarm);
List<EntityAlarm> findEntityAlarmRecords(TenantId tenantId, AlarmId id);
void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId);
}

View File

@ -46,7 +46,6 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.EntityService;
@ -350,6 +349,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
return alarmSeverities.stream().min(AlarmSeverity::compareTo).orElse(null);
}
@Override
public void deleteEntityAlarmRelations(TenantId tenantId, EntityId entityId) {
alarmDao.deleteEntityAlarmRecords(tenantId, entityId);
}
private Alarm merge(Alarm existing, Alarm alarm) {
if (alarm.getStartTs() > existing.getEndTs()) {
existing.setEndTs(alarm.getStartTs());

View File

@ -18,12 +18,14 @@ package org.thingsboard.server.dao.entity;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -41,6 +43,10 @@ public abstract class AbstractEntityService {
@Autowired
protected RelationService relationService;
@Lazy
@Autowired
protected AlarmService alarmService;
@Autowired
protected EntityViewService entityViewService;
@ -60,6 +66,8 @@ public abstract class AbstractEntityService {
protected void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
log.trace("Executing deleteEntityRelations [{}]", entityId);
relationService.deleteEntityRelations(tenantId, entityId);
log.trace("Executing deleteEntityAlarms [{}]", entityId);
alarmService.deleteEntityAlarmRelations(tenantId, entityId);
}
protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {

View File

@ -104,11 +104,6 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
@Autowired
private OtaPackageService otaPackageService;
@Override
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
super.deleteEntityRelations(tenantId, entityId);
}
@Override
public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query);

View File

@ -563,10 +563,9 @@ public class BaseRelationService implements RelationService {
@Override
public List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) {
log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}] and limit {}",
tenantId, limit);
log.trace("Executing findRuleNodeToRuleChainRelations, tenantId [{}], ruleChainType {} and limit {}", tenantId, ruleChainType, limit);
validateId(tenantId, "Invalid tenant id: " + tenantId);
return relationDao.findRuleNodeToRuleChainRelations(tenantId, ruleChainType, limit);
return relationDao.findRuleNodeToRuleChainRelations(ruleChainType, limit);
}
protected void validate(EntityRelation relation) {

View File

@ -61,5 +61,5 @@ public interface RelationDao {
ListenableFuture<Boolean> deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity);
List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit);
List<EntityRelation> findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit);
}

View File

@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
@ -48,7 +47,6 @@ import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainData;
import org.thingsboard.server.common.data.rule.RuleChainImportResult;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleChainUpdateResult;
import org.thingsboard.server.common.data.rule.RuleNode;

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.sql.alarm;
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey;
import org.thingsboard.server.dao.model.sql.EntityAlarmEntity;
@ -26,4 +27,6 @@ public interface EntityAlarmRepository extends CrudRepository<EntityAlarmEntity,
List<EntityAlarmEntity> findAllByAlarmId(UUID alarmId);
@Transactional
void deleteByEntityId(UUID id);
}

View File

@ -183,4 +183,10 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id);
return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId()));
}
@Override
public void deleteEntityAlarmRecords(TenantId tenantId, EntityId entityId) {
log.trace("[{}] Try to delete entity alarm records using [{}]", tenantId, entityId);
entityAlarmRepository.deleteByEntityId(entityId.getId());
}
}

View File

@ -199,8 +199,8 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
}
@Override
public List<EntityRelation> findRuleNodeToRuleChainRelations(TenantId tenantId, RuleChainType ruleChainType, int limit) {
return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(tenantId.getId(), ruleChainType, PageRequest.of(0, limit)));
public List<EntityRelation> findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit) {
return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(ruleChainType, PageRequest.of(0, limit)));
}
private Specification<RelationEntity> getEntityFieldsSpec(EntityId from, String relationType, RelationTypeGroup typeGroup, EntityType childType) {

View File

@ -58,15 +58,9 @@ public interface RelationRepository
String fromType);
@Query("SELECT r FROM RelationEntity r WHERE " +
"r.fromId in (SELECT id from RuleNodeEntity where ruleChainId in " +
"(SELECT id from RuleChainEntity where tenantId = :tenantId and type = :ruleChainType ))" +
"AND r.fromType = 'RULE_NODE' " +
"AND r.toType = 'RULE_CHAIN' " +
"AND r.relationTypeGroup = 'RULE_NODE'")
List<RelationEntity> findRuleNodeToRuleChainRelations(
@Param("tenantId") UUID tenantId,
@Param("ruleChainType") RuleChainType ruleChainType,
Pageable page);
"r.relationTypeGroup = 'RULE_NODE' AND r.toType = 'RULE_CHAIN' " +
"AND r.toId in (SELECT id from RuleChainEntity where type = :ruleChainType )")
List<RelationEntity> findRuleNodeToRuleChainRelations(@Param("ruleChainType") RuleChainType ruleChainType, Pageable page);
@Transactional
<S extends RelationEntity> S save(S entity);

View File

@ -66,7 +66,7 @@ CREATE TABLE IF NOT EXISTS entity_alarm (
alarm_type varchar(255) NOT NULL,
customer_id uuid,
alarm_id uuid,
CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id),
CONSTRAINT entity_alarm_pkey PRIMARY KEY (entity_id, alarm_id),
CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE
);