Improve Relation Service

This commit is contained in:
Igor Kulikov 2018-05-17 13:45:06 +03:00
parent 084907dfc4
commit 9175aba24f
3 changed files with 58 additions and 89 deletions

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.relation; package org.thingsboard.server.dao.relation;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
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;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -176,97 +177,64 @@ public class BaseRelationService implements RelationService {
} }
@Override @Override
public boolean deleteEntityRelations(EntityId entity) { public void deleteEntityRelations(EntityId entityId) throws ExecutionException, InterruptedException {
Cache cache = cacheManager.getCache(RELATIONS_CACHE); deleteEntityRelationsAsync(entityId).get();
log.trace("Executing deleteEntityRelations [{}]", entity);
validate(entity);
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup));
}
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, relations ->
getBooleans(relations, cache, true));
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction());
boolean inboundDeleteResult = false;
try {
inboundDeleteResult = inboundFuture.get();
} catch (InterruptedException | ExecutionException e) {
log.error("Error deleting entity inbound relations", e);
}
List<ListenableFuture<List<EntityRelation>>> outboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
outboundRelationsList.add(relationDao.findAllByFrom(entity, typeGroup));
}
ListenableFuture<List<List<EntityRelation>>> outboundRelations = Futures.allAsList(outboundRelationsList);
Futures.transform(outboundRelations, relations -> getBooleans(relations, cache, false));
boolean outboundDeleteResult = relationDao.deleteOutboundRelations(entity);
return inboundDeleteResult && outboundDeleteResult;
}
private List<Boolean> getBooleans(List<List<EntityRelation>> relations, Cache cache, boolean isRemove) {
List<Boolean> results = new ArrayList<>();
for (List<EntityRelation> relationList : relations) {
relationList.forEach(relation -> checkFromDeleteSync(cache, results, relation, isRemove));
}
return results;
}
private void checkFromDeleteSync(Cache cache, List<Boolean> results, EntityRelation relation, boolean isRemove) {
if (isRemove) {
results.add(relationDao.deleteRelation(relation));
}
cacheEviction(relation, cache);
} }
@Override @Override
public ListenableFuture<Boolean> deleteEntityRelationsAsync(EntityId entity) { public ListenableFuture<Void> deleteEntityRelationsAsync(EntityId entityId) {
Cache cache = cacheManager.getCache(RELATIONS_CACHE); Cache cache = cacheManager.getCache(RELATIONS_CACHE);
log.trace("Executing deleteEntityRelationsAsync [{}]", entity); log.trace("Executing deleteEntityRelationsAsync [{}]", entityId);
validate(entity); validate(entityId);
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>(); List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) { for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup)); inboundRelationsList.add(relationDao.findAllByTo(entityId, typeGroup));
} }
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transformAsync(inboundRelations,
relations -> {
List<ListenableFuture<Boolean>> results = getListenableFutures(relations, cache, true);
return Futures.allAsList(results);
});
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction()); ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
List<ListenableFuture<List<EntityRelation>>> outboundRelationsList = new ArrayList<>(); List<ListenableFuture<List<EntityRelation>>> outboundRelationsList = new ArrayList<>();
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) { for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
outboundRelationsList.add(relationDao.findAllByFrom(entity, typeGroup)); outboundRelationsList.add(relationDao.findAllByFrom(entityId, typeGroup));
} }
ListenableFuture<List<List<EntityRelation>>> outboundRelations = Futures.allAsList(outboundRelationsList);
Futures.transformAsync(outboundRelations, relations -> {
List<ListenableFuture<Boolean>> results = getListenableFutures(relations, cache, false);
return Futures.allAsList(results);
});
ListenableFuture<Boolean> outboundFuture = relationDao.deleteOutboundRelationsAsync(entity); ListenableFuture<List<List<EntityRelation>>> outboundRelations = Futures.allAsList(outboundRelationsList);
return Futures.transform(Futures.allAsList(Arrays.asList(inboundFuture, outboundFuture)), getListToBooleanFunction());
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transformAsync(inboundRelations,
relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(relations, cache, true);
return Futures.allAsList(results);
});
ListenableFuture<List<Boolean>> outboundDeletions = Futures.transformAsync(outboundRelations,
relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(relations, cache, false);
return Futures.allAsList(results);
});
ListenableFuture<List<List<Boolean>>> deletionsFuture = Futures.allAsList(inboundDeletions, outboundDeletions);
return Futures.transformAsync(deletionsFuture, (deletions) -> {
relationDao.deleteOutboundRelationsAsync(entityId);
return null;
});
} }
private List<ListenableFuture<Boolean>> getListenableFutures(List<List<EntityRelation>> relations, Cache cache, boolean isRemove) { private List<ListenableFuture<Boolean>> deleteRelationGroupsAsync(List<List<EntityRelation>> relations, Cache cache, boolean deleteFromDb) {
List<ListenableFuture<Boolean>> results = new ArrayList<>(); List<ListenableFuture<Boolean>> results = new ArrayList<>();
for (List<EntityRelation> relationList : relations) { for (List<EntityRelation> relationList : relations) {
relationList.forEach(relation -> checkFromDeleteAsync(cache, results, relation, isRemove)); relationList.forEach(relation -> results.add(deleteAsync(cache, relation, deleteFromDb)));
} }
return results; return results;
} }
private void checkFromDeleteAsync(Cache cache, List<ListenableFuture<Boolean>> results, EntityRelation relation, boolean isRemove) { private ListenableFuture<Boolean> deleteAsync(Cache cache, EntityRelation relation, boolean deleteFromDb) {
if (isRemove) {
results.add(relationDao.deleteRelationAsync(relation));
}
cacheEviction(relation, cache); cacheEviction(relation, cache);
if (deleteFromDb) {
return relationDao.deleteRelationAsync(relation);
} else {
return Futures.immediateFuture(false);
}
} }
private void cacheEviction(EntityRelation relation, Cache cache) { private void cacheEviction(EntityRelation relation, Cache cache) {

View File

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
/** /**
* Created by ashvayka on 27.04.17. * Created by ashvayka on 27.04.17.
@ -47,9 +48,9 @@ public interface RelationService {
ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
boolean deleteEntityRelations(EntityId entity); void deleteEntityRelations(EntityId entity) throws ExecutionException, InterruptedException;
ListenableFuture<Boolean> deleteEntityRelationsAsync(EntityId entity); ListenableFuture<Void> deleteEntityRelationsAsync(EntityId entity);
List<EntityRelation> findByFrom(EntityId from, RelationTypeGroup typeGroup); List<EntityRelation> findByFrom(EntityId from, RelationTypeGroup typeGroup);

View File

@ -132,39 +132,35 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
@Override @Override
public boolean deleteRelation(EntityRelation relation) { public boolean deleteRelation(EntityRelation relation) {
RelationCompositeKey key = new RelationCompositeKey(relation); RelationCompositeKey key = new RelationCompositeKey(relation);
boolean relationExistsBeforeDelete = relationRepository.exists(key); return deleteRelationIfExists(key);
relationRepository.delete(key);
return relationExistsBeforeDelete;
} }
@Override @Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) { public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
RelationCompositeKey key = new RelationCompositeKey(relation); RelationCompositeKey key = new RelationCompositeKey(relation);
return service.submit( return service.submit(
() -> { () -> deleteRelationIfExists(key));
boolean relationExistsBeforeDelete = relationRepository.exists(key);
relationRepository.delete(key);
return relationExistsBeforeDelete;
});
} }
@Override @Override
public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup);
boolean relationExistsBeforeDelete = relationRepository.exists(key); return deleteRelationIfExists(key);
relationRepository.delete(key);
return relationExistsBeforeDelete;
} }
@Override @Override
public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup);
return service.submit( return service.submit(
() -> { () -> deleteRelationIfExists(key));
boolean relationExistsBeforeDelete = relationRepository.exists(key); }
relationRepository.delete(key);
return relationExistsBeforeDelete; private boolean deleteRelationIfExists(RelationCompositeKey key) {
}); boolean relationExistsBeforeDelete = relationRepository.exists(key);
if (relationExistsBeforeDelete) {
relationRepository.delete(key);
}
return relationExistsBeforeDelete;
} }
@Override @Override
@ -172,7 +168,9 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
boolean relationExistsBeforeDelete = relationRepository boolean relationExistsBeforeDelete = relationRepository
.findAllByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name()) .findAllByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name())
.size() > 0; .size() > 0;
relationRepository.deleteByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name()); if (relationExistsBeforeDelete) {
relationRepository.deleteByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name());
}
return relationExistsBeforeDelete; return relationExistsBeforeDelete;
} }
@ -183,7 +181,9 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
boolean relationExistsBeforeDelete = relationRepository boolean relationExistsBeforeDelete = relationRepository
.findAllByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name()) .findAllByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name())
.size() > 0; .size() > 0;
relationRepository.deleteByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name()); if (relationExistsBeforeDelete) {
relationRepository.deleteByFromIdAndFromType(UUIDConverter.fromTimeUUID(entity.getId()), entity.getEntityType().name());
}
return relationExistsBeforeDelete; return relationExistsBeforeDelete;
}); });
} }