diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesCacheWrapper.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesCacheWrapper.java new file mode 100644 index 0000000000..196204cda1 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesCacheWrapper.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.attributes; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; + +import static org.thingsboard.server.common.data.CacheConstants.ATTRIBUTES_CACHE; + +@Service +@ConditionalOnProperty(prefix = "cache.attributes", value = "enabled", havingValue = "true") +@Primary +@Slf4j +public class AttributesCacheWrapper { + private final Cache attributesCache; + + public AttributesCacheWrapper(CacheManager cacheManager) { + this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE); + } + + public Cache.ValueWrapper get(AttributeCacheKey attributeCacheKey) { + try { + return attributesCache.get(attributeCacheKey); + } catch (Exception e) { + log.debug("Failed to retrieve element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); + return null; + } + } + + public void put(AttributeCacheKey attributeCacheKey, AttributeKvEntry attributeKvEntry) { + try { + attributesCache.put(attributeCacheKey, attributeKvEntry); + } catch (Exception e) { + log.debug("Failed to put element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); + } + } + + public void evict(AttributeCacheKey attributeCacheKey) { + try { + attributesCache.evict(attributeCacheKey); + } catch (Exception e) { + log.debug("Failed to evict element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java index 6ebebdbcaa..87ddfeee9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java @@ -56,16 +56,15 @@ public class CachedAttributesService implements AttributesService { private static final String STATS_NAME = "attributes.cache"; private final AttributesDao attributesDao; - private final Cache attributesCache; - + private final AttributesCacheWrapper cacheWrapper; private final DefaultCounter hitCounter; private final DefaultCounter missCounter; public CachedAttributesService(AttributesDao attributesDao, - CacheManager cacheManager, + AttributesCacheWrapper cacheWrapper, StatsFactory statsFactory) { this.attributesDao = attributesDao; - this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE); + this.cacheWrapper = cacheWrapper; this.hitCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "hit"); this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss"); @@ -77,7 +76,7 @@ public class CachedAttributesService implements AttributesService { Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey); AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey); - Cache.ValueWrapper cachedAttributeValue = attributesCache.get(attributeCacheKey); + Cache.ValueWrapper cachedAttributeValue = cacheWrapper.get(attributeCacheKey); if (cachedAttributeValue != null) { hitCounter.increment(); AttributeKvEntry cachedAttributeKvEntry = (AttributeKvEntry) cachedAttributeValue.get(); @@ -87,7 +86,7 @@ public class CachedAttributesService implements AttributesService { ListenableFuture> result = attributesDao.find(tenantId, entityId, scope, attributeKey); return Futures.transform(result, foundAttrKvEntry -> { // TODO: think if it's a good idea to store 'empty' attributes - attributesCache.put(attributeKey, foundAttrKvEntry.orElse(null)); + cacheWrapper.put(attributeCacheKey, foundAttrKvEntry.orElse(null)); return foundAttrKvEntry; }, MoreExecutors.directExecutor()); } @@ -119,7 +118,7 @@ public class CachedAttributesService implements AttributesService { private Map findCachedAttributes(EntityId entityId, String scope, Collection attributeKeys) { Map cachedAttributes = new HashMap<>(); for (String attributeKey : attributeKeys) { - Cache.ValueWrapper cachedAttributeValue = attributesCache.get(new AttributeCacheKey(scope, entityId, attributeKey)); + Cache.ValueWrapper cachedAttributeValue = cacheWrapper.get(new AttributeCacheKey(scope, entityId, attributeKey)); if (cachedAttributeValue != null) { hitCounter.increment(); cachedAttributes.put(attributeKey, cachedAttributeValue); @@ -133,11 +132,11 @@ public class CachedAttributesService implements AttributesService { private List mergeDbAndCacheAttributes(EntityId entityId, String scope, List cachedAttributes, Set notFoundAttributeKeys, List foundInDbAttributes) { for (AttributeKvEntry foundInDbAttribute : foundInDbAttributes) { AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, foundInDbAttribute.getKey()); - attributesCache.put(attributeCacheKey, foundInDbAttribute); + cacheWrapper.put(attributeCacheKey, foundInDbAttribute); notFoundAttributeKeys.remove(foundInDbAttribute.getKey()); } for (String key : notFoundAttributeKeys){ - attributesCache.put(new AttributeCacheKey(scope, entityId, key), null); + cacheWrapper.put(new AttributeCacheKey(scope, entityId, key), null); } List mergedAttributes = new ArrayList<>(cachedAttributes); mergedAttributes.addAll(foundInDbAttributes); @@ -185,7 +184,7 @@ public class CachedAttributesService implements AttributesService { private void evictAttributesFromCache(TenantId tenantId, EntityId entityId, String scope, List attributeKeys) { try { for (String attributeKey : attributeKeys) { - attributesCache.evict(new AttributeCacheKey(scope, entityId, attributeKey)); + cacheWrapper.evict(new AttributeCacheKey(scope, entityId, attributeKey)); } } catch (Exception e) { log.error("[{}][{}] Failed to remove values from cache.", tenantId, entityId, e);