|
|
|
@ -29,8 +29,6 @@ import org.thingsboard.server.common.data.TenantProfile; |
|
|
|
import org.thingsboard.server.common.data.cf.CalculatedField; |
|
|
|
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; |
|
|
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
|
|
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|
|
|
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
|
|
|
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration; |
|
|
|
import org.thingsboard.server.common.data.id.AssetId; |
|
|
|
import org.thingsboard.server.common.data.id.CalculatedFieldId; |
|
|
|
@ -40,6 +38,8 @@ import org.thingsboard.server.common.data.id.HasId; |
|
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
|
import org.thingsboard.server.common.data.id.TenantProfileId; |
|
|
|
import org.thingsboard.server.common.data.page.PageDataIterable; |
|
|
|
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|
|
|
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
|
|
|
import org.thingsboard.server.dao.cf.CalculatedFieldService; |
|
|
|
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|
|
|
import org.thingsboard.server.queue.util.AfterStartUp; |
|
|
|
@ -50,8 +50,8 @@ import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
|
import java.util.concurrent.ConcurrentMap; |
|
|
|
import java.util.concurrent.CopyOnWriteArrayList; |
|
|
|
@ -273,12 +273,12 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache { |
|
|
|
|
|
|
|
@Override |
|
|
|
public void updateOwnerEntity(TenantId tenantId, EntityId entityId) { |
|
|
|
evictEntity(entityId); |
|
|
|
evictOwnerEntity(entityId); |
|
|
|
addOwnerEntity(tenantId, entityId); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void evictEntity(EntityId entityId) { |
|
|
|
public void evictOwnerEntity(EntityId entityId) { |
|
|
|
ownerEntities.values().forEach(entities -> entities.remove(entityId)); |
|
|
|
} |
|
|
|
|
|
|
|
@ -297,71 +297,105 @@ public class DefaultCalculatedFieldCache implements CalculatedFieldCache { |
|
|
|
|
|
|
|
@EventListener(ComponentLifecycleMsg.class) |
|
|
|
public void onComponentLifecycleEvent(ComponentLifecycleMsg event) { |
|
|
|
if (event.getEvent() != ComponentLifecycleEvent.DELETED) { |
|
|
|
return; |
|
|
|
} |
|
|
|
switch (event.getEntityId().getEntityType()) { |
|
|
|
case TENANT_PROFILE: |
|
|
|
if (event.getEvent() == ComponentLifecycleEvent.UPDATED) { |
|
|
|
TenantProfileId tenantProfileId = new TenantProfileId(event.getEntityId().getId()); |
|
|
|
handleTenantProfileUpdate(tenantProfileId); |
|
|
|
} |
|
|
|
break; |
|
|
|
case TENANT: |
|
|
|
TenantId tenantId = event.getTenantId(); |
|
|
|
var removedCfIds = new HashSet<CalculatedFieldId>(); |
|
|
|
var removedCfEntityIds = new HashSet<EntityId>(); |
|
|
|
var removedLinkEntityIds = new HashSet<EntityId>(); |
|
|
|
for (Map.Entry<CalculatedFieldId, CalculatedField> entry : calculatedFields.entrySet()) { |
|
|
|
CalculatedFieldId cfId = entry.getKey(); |
|
|
|
CalculatedField cf = entry.getValue(); |
|
|
|
if (cf.getTenantId().equals(tenantId)) { |
|
|
|
calculatedFields.remove(cfId); |
|
|
|
List<CalculatedFieldLink> links = calculatedFieldLinks.remove(cfId); |
|
|
|
if (links != null) { |
|
|
|
links.forEach(link -> removedLinkEntityIds.add(link.entityId())); |
|
|
|
if (event.getEvent() == ComponentLifecycleEvent.DELETED) { |
|
|
|
TenantId tenantId = event.getTenantId(); |
|
|
|
var removedCfIds = new HashSet<CalculatedFieldId>(); |
|
|
|
var removedCfEntityIds = new HashSet<EntityId>(); |
|
|
|
var removedLinkEntityIds = new HashSet<EntityId>(); |
|
|
|
for (Map.Entry<CalculatedFieldId, CalculatedField> entry : calculatedFields.entrySet()) { |
|
|
|
CalculatedFieldId cfId = entry.getKey(); |
|
|
|
CalculatedField cf = entry.getValue(); |
|
|
|
if (cf.getTenantId().equals(tenantId)) { |
|
|
|
calculatedFields.remove(cfId); |
|
|
|
List<CalculatedFieldLink> links = calculatedFieldLinks.remove(cfId); |
|
|
|
if (links != null) { |
|
|
|
links.forEach(link -> removedLinkEntityIds.add(link.entityId())); |
|
|
|
} |
|
|
|
calculatedFieldsCtx.remove(cfId); |
|
|
|
removedCfIds.add(cfId); |
|
|
|
removedCfEntityIds.add(cf.getEntityId()); |
|
|
|
log.debug("[{}] evict calculated field from cache on tenant deletion: {}", cfId, cf); |
|
|
|
} |
|
|
|
calculatedFieldsCtx.remove(cfId); |
|
|
|
removedCfIds.add(cfId); |
|
|
|
removedCfEntityIds.add(cf.getEntityId()); |
|
|
|
log.debug("[{}] evict calculated field from cache on tenant deletion: {}", cfId, cf); |
|
|
|
} |
|
|
|
} |
|
|
|
removedCfEntityIds.forEach(entityId -> { |
|
|
|
List<CalculatedField> cfs = entityIdCalculatedFields.get(entityId); |
|
|
|
if (cfs != null) { |
|
|
|
cfs.removeIf(cf -> removedCfIds.contains(cf.getId())); |
|
|
|
if (cfs.isEmpty()) { |
|
|
|
entityIdCalculatedFields.remove(entityId); |
|
|
|
removedCfEntityIds.forEach(entityId -> { |
|
|
|
List<CalculatedField> cfs = entityIdCalculatedFields.get(entityId); |
|
|
|
if (cfs != null) { |
|
|
|
cfs.removeIf(cf -> removedCfIds.contains(cf.getId())); |
|
|
|
if (cfs.isEmpty()) { |
|
|
|
entityIdCalculatedFields.remove(entityId); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
removedLinkEntityIds.forEach(entityId -> { |
|
|
|
List<CalculatedFieldLink> entityLinks = entityIdCalculatedFieldLinks.get(entityId); |
|
|
|
if (entityLinks != null) { |
|
|
|
entityLinks.removeIf(link -> removedCfIds.contains(link.calculatedFieldId())); |
|
|
|
if (entityLinks.isEmpty()) { |
|
|
|
entityIdCalculatedFieldLinks.remove(entityId); |
|
|
|
}); |
|
|
|
removedLinkEntityIds.forEach(entityId -> { |
|
|
|
List<CalculatedFieldLink> entityLinks = entityIdCalculatedFieldLinks.get(entityId); |
|
|
|
if (entityLinks != null) { |
|
|
|
entityLinks.removeIf(link -> removedCfIds.contains(link.calculatedFieldId())); |
|
|
|
if (entityLinks.isEmpty()) { |
|
|
|
entityIdCalculatedFieldLinks.remove(entityId); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
removedCfIds.forEach(calculatedFieldFetchLocks::remove); |
|
|
|
break; |
|
|
|
case DEVICE: |
|
|
|
case ASSET: |
|
|
|
case DEVICE_PROFILE: |
|
|
|
case ASSET_PROFILE: |
|
|
|
EntityId entityId = event.getEntityId(); |
|
|
|
List<CalculatedField> cfs = entityIdCalculatedFields.remove(entityId); |
|
|
|
if (cfs != null) { |
|
|
|
var cfIds = new HashSet<CalculatedFieldId>(); |
|
|
|
cfs.forEach(cf -> { |
|
|
|
calculatedFields.remove(cf.getId()); |
|
|
|
calculatedFieldLinks.remove(cf.getId()); |
|
|
|
calculatedFieldsCtx.remove(cf.getId()); |
|
|
|
cfIds.add(cf.getId()); |
|
|
|
log.debug("[{}] evict calculated field from cache on entity deletion: {}", cf.getId(), cf); |
|
|
|
}); |
|
|
|
entityIdCalculatedFieldLinks.values().forEach(list -> list.removeIf(link -> cfIds.contains(link.calculatedFieldId()))); |
|
|
|
cfIds.forEach(calculatedFieldFetchLocks::remove); |
|
|
|
removedCfIds.forEach(calculatedFieldFetchLocks::remove); |
|
|
|
evictOwner(tenantId); |
|
|
|
} |
|
|
|
break; |
|
|
|
case CUSTOMER: |
|
|
|
if (event.getEvent().equals(ComponentLifecycleEvent.CREATED)) { |
|
|
|
addOwnerEntity(event.getTenantId(), event.getEntityId()); |
|
|
|
} else if (event.getEvent().equals(ComponentLifecycleEvent.UPDATED) && event.isOwnerChanged()) { |
|
|
|
updateOwnerEntity(event.getTenantId(), event.getEntityId()); |
|
|
|
} else if (event.getEvent() == ComponentLifecycleEvent.DELETED) { |
|
|
|
evictOwner(event.getEntityId()); |
|
|
|
evictOwnerEntity(event.getEntityId()); |
|
|
|
} |
|
|
|
break; |
|
|
|
case DEVICE, ASSET: |
|
|
|
if (event.getEvent().equals(ComponentLifecycleEvent.CREATED)) { |
|
|
|
addOwnerEntity(event.getTenantId(), event.getEntityId()); |
|
|
|
} else if (event.getEvent().equals(ComponentLifecycleEvent.UPDATED) && event.isOwnerChanged()) { |
|
|
|
updateOwnerEntity(event.getTenantId(), event.getEntityId()); |
|
|
|
} else if (event.getEvent().equals(ComponentLifecycleEvent.DELETED)) { |
|
|
|
evictOwnerEntity(event.getEntityId()); |
|
|
|
evictEntity(event.getEntityId()); |
|
|
|
} |
|
|
|
entityIdCalculatedFieldLinks.remove(entityId); |
|
|
|
break; |
|
|
|
case DEVICE_PROFILE, ASSET_PROFILE: |
|
|
|
evictEntity(event.getEntityId()); |
|
|
|
break; |
|
|
|
case CALCULATED_FIELD: |
|
|
|
if (event.getEvent() == ComponentLifecycleEvent.CREATED) { |
|
|
|
addCalculatedField(event.getTenantId(), (CalculatedFieldId) event.getEntityId()); |
|
|
|
} else if (event.getEvent() == ComponentLifecycleEvent.UPDATED) { |
|
|
|
updateCalculatedField(event.getTenantId(), (CalculatedFieldId) event.getEntityId()); |
|
|
|
} else { |
|
|
|
evict((CalculatedFieldId) event.getEntityId()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void evictEntity(EntityId entityId) { |
|
|
|
List<CalculatedField> cfs = entityIdCalculatedFields.remove(entityId); |
|
|
|
if (cfs != null) { |
|
|
|
var cfIds = new HashSet<CalculatedFieldId>(); |
|
|
|
cfs.forEach(cf -> { |
|
|
|
calculatedFields.remove(cf.getId()); |
|
|
|
calculatedFieldLinks.remove(cf.getId()); |
|
|
|
calculatedFieldsCtx.remove(cf.getId()); |
|
|
|
cfIds.add(cf.getId()); |
|
|
|
log.debug("[{}] evict calculated field from cache on entity deletion: {}", cf.getId(), cf); |
|
|
|
}); |
|
|
|
entityIdCalculatedFieldLinks.values().forEach(list -> list.removeIf(link -> cfIds.contains(link.calculatedFieldId()))); |
|
|
|
cfIds.forEach(calculatedFieldFetchLocks::remove); |
|
|
|
} |
|
|
|
entityIdCalculatedFieldLinks.remove(entityId); |
|
|
|
} |
|
|
|
|
|
|
|
private Lock getFetchLock(CalculatedFieldId id) { |
|
|
|
|