Wrapped attr cache requests, fixed bug

This commit is contained in:
vzikratyi 2021-02-25 12:02:26 +02:00 committed by Andrew Shvayka
parent ab76d81c6f
commit c7df356fb7
2 changed files with 72 additions and 10 deletions

View File

@ -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());
}
}
}

View File

@ -56,16 +56,15 @@ public class CachedAttributesService implements AttributesService {
private static final String STATS_NAME = "attributes.cache"; private static final String STATS_NAME = "attributes.cache";
private final AttributesDao attributesDao; private final AttributesDao attributesDao;
private final Cache attributesCache; private final AttributesCacheWrapper cacheWrapper;
private final DefaultCounter hitCounter; private final DefaultCounter hitCounter;
private final DefaultCounter missCounter; private final DefaultCounter missCounter;
public CachedAttributesService(AttributesDao attributesDao, public CachedAttributesService(AttributesDao attributesDao,
CacheManager cacheManager, AttributesCacheWrapper cacheWrapper,
StatsFactory statsFactory) { StatsFactory statsFactory) {
this.attributesDao = attributesDao; this.attributesDao = attributesDao;
this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE); this.cacheWrapper = cacheWrapper;
this.hitCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "hit"); this.hitCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "hit");
this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss"); this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss");
@ -77,7 +76,7 @@ public class CachedAttributesService implements AttributesService {
Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey); Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey);
AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey); AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey);
Cache.ValueWrapper cachedAttributeValue = attributesCache.get(attributeCacheKey); Cache.ValueWrapper cachedAttributeValue = cacheWrapper.get(attributeCacheKey);
if (cachedAttributeValue != null) { if (cachedAttributeValue != null) {
hitCounter.increment(); hitCounter.increment();
AttributeKvEntry cachedAttributeKvEntry = (AttributeKvEntry) cachedAttributeValue.get(); AttributeKvEntry cachedAttributeKvEntry = (AttributeKvEntry) cachedAttributeValue.get();
@ -87,7 +86,7 @@ public class CachedAttributesService implements AttributesService {
ListenableFuture<Optional<AttributeKvEntry>> result = attributesDao.find(tenantId, entityId, scope, attributeKey); ListenableFuture<Optional<AttributeKvEntry>> result = attributesDao.find(tenantId, entityId, scope, attributeKey);
return Futures.transform(result, foundAttrKvEntry -> { return Futures.transform(result, foundAttrKvEntry -> {
// TODO: think if it's a good idea to store 'empty' attributes // 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; return foundAttrKvEntry;
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} }
@ -119,7 +118,7 @@ public class CachedAttributesService implements AttributesService {
private Map<String, Cache.ValueWrapper> findCachedAttributes(EntityId entityId, String scope, Collection<String> attributeKeys) { private Map<String, Cache.ValueWrapper> findCachedAttributes(EntityId entityId, String scope, Collection<String> attributeKeys) {
Map<String, Cache.ValueWrapper> cachedAttributes = new HashMap<>(); Map<String, Cache.ValueWrapper> cachedAttributes = new HashMap<>();
for (String attributeKey : attributeKeys) { 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) { if (cachedAttributeValue != null) {
hitCounter.increment(); hitCounter.increment();
cachedAttributes.put(attributeKey, cachedAttributeValue); cachedAttributes.put(attributeKey, cachedAttributeValue);
@ -133,11 +132,11 @@ public class CachedAttributesService implements AttributesService {
private List<AttributeKvEntry> mergeDbAndCacheAttributes(EntityId entityId, String scope, List<AttributeKvEntry> cachedAttributes, Set<String> notFoundAttributeKeys, List<AttributeKvEntry> foundInDbAttributes) { private List<AttributeKvEntry> mergeDbAndCacheAttributes(EntityId entityId, String scope, List<AttributeKvEntry> cachedAttributes, Set<String> notFoundAttributeKeys, List<AttributeKvEntry> foundInDbAttributes) {
for (AttributeKvEntry foundInDbAttribute : foundInDbAttributes) { for (AttributeKvEntry foundInDbAttribute : foundInDbAttributes) {
AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, foundInDbAttribute.getKey()); AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, foundInDbAttribute.getKey());
attributesCache.put(attributeCacheKey, foundInDbAttribute); cacheWrapper.put(attributeCacheKey, foundInDbAttribute);
notFoundAttributeKeys.remove(foundInDbAttribute.getKey()); notFoundAttributeKeys.remove(foundInDbAttribute.getKey());
} }
for (String key : notFoundAttributeKeys){ for (String key : notFoundAttributeKeys){
attributesCache.put(new AttributeCacheKey(scope, entityId, key), null); cacheWrapper.put(new AttributeCacheKey(scope, entityId, key), null);
} }
List<AttributeKvEntry> mergedAttributes = new ArrayList<>(cachedAttributes); List<AttributeKvEntry> mergedAttributes = new ArrayList<>(cachedAttributes);
mergedAttributes.addAll(foundInDbAttributes); mergedAttributes.addAll(foundInDbAttributes);
@ -185,7 +184,7 @@ public class CachedAttributesService implements AttributesService {
private void evictAttributesFromCache(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys) { private void evictAttributesFromCache(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys) {
try { try {
for (String attributeKey : attributeKeys) { for (String attributeKey : attributeKeys) {
attributesCache.evict(new AttributeCacheKey(scope, entityId, attributeKey)); cacheWrapper.evict(new AttributeCacheKey(scope, entityId, attributeKey));
} }
} catch (Exception e) { } catch (Exception e) {
log.error("[{}][{}] Failed to remove values from cache.", tenantId, entityId, e); log.error("[{}][{}] Failed to remove values from cache.", tenantId, entityId, e);