Commit c7df356fb7cc4780b6ca72a22722798bf6028410

Authored by vzikratyi
Committed by Andrew Shvayka
1 parent ab76d81c

Wrapped attr cache requests, fixed bug

  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.attributes;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  20 +import org.springframework.cache.Cache;
  21 +import org.springframework.cache.CacheManager;
  22 +import org.springframework.context.annotation.Primary;
  23 +import org.springframework.stereotype.Service;
  24 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  25 +
  26 +import static org.thingsboard.server.common.data.CacheConstants.ATTRIBUTES_CACHE;
  27 +
  28 +@Service
  29 +@ConditionalOnProperty(prefix = "cache.attributes", value = "enabled", havingValue = "true")
  30 +@Primary
  31 +@Slf4j
  32 +public class AttributesCacheWrapper {
  33 + private final Cache attributesCache;
  34 +
  35 + public AttributesCacheWrapper(CacheManager cacheManager) {
  36 + this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE);
  37 + }
  38 +
  39 + public Cache.ValueWrapper get(AttributeCacheKey attributeCacheKey) {
  40 + try {
  41 + return attributesCache.get(attributeCacheKey);
  42 + } catch (Exception e) {
  43 + log.debug("Failed to retrieve element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage());
  44 + return null;
  45 + }
  46 + }
  47 +
  48 + public void put(AttributeCacheKey attributeCacheKey, AttributeKvEntry attributeKvEntry) {
  49 + try {
  50 + attributesCache.put(attributeCacheKey, attributeKvEntry);
  51 + } catch (Exception e) {
  52 + log.debug("Failed to put element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage());
  53 + }
  54 + }
  55 +
  56 + public void evict(AttributeCacheKey attributeCacheKey) {
  57 + try {
  58 + attributesCache.evict(attributeCacheKey);
  59 + } catch (Exception e) {
  60 + log.debug("Failed to evict element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage());
  61 + }
  62 + }
  63 +}
... ...
... ... @@ -56,16 +56,15 @@ public class CachedAttributesService implements AttributesService {
56 56 private static final String STATS_NAME = "attributes.cache";
57 57
58 58 private final AttributesDao attributesDao;
59   - private final Cache attributesCache;
60   -
  59 + private final AttributesCacheWrapper cacheWrapper;
61 60 private final DefaultCounter hitCounter;
62 61 private final DefaultCounter missCounter;
63 62
64 63 public CachedAttributesService(AttributesDao attributesDao,
65   - CacheManager cacheManager,
  64 + AttributesCacheWrapper cacheWrapper,
66 65 StatsFactory statsFactory) {
67 66 this.attributesDao = attributesDao;
68   - this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE);
  67 + this.cacheWrapper = cacheWrapper;
69 68
70 69 this.hitCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "hit");
71 70 this.missCounter = statsFactory.createDefaultCounter(STATS_NAME, "result", "miss");
... ... @@ -77,7 +76,7 @@ public class CachedAttributesService implements AttributesService {
77 76 Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey);
78 77
79 78 AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, attributeKey);
80   - Cache.ValueWrapper cachedAttributeValue = attributesCache.get(attributeCacheKey);
  79 + Cache.ValueWrapper cachedAttributeValue = cacheWrapper.get(attributeCacheKey);
81 80 if (cachedAttributeValue != null) {
82 81 hitCounter.increment();
83 82 AttributeKvEntry cachedAttributeKvEntry = (AttributeKvEntry) cachedAttributeValue.get();
... ... @@ -87,7 +86,7 @@ public class CachedAttributesService implements AttributesService {
87 86 ListenableFuture<Optional<AttributeKvEntry>> result = attributesDao.find(tenantId, entityId, scope, attributeKey);
88 87 return Futures.transform(result, foundAttrKvEntry -> {
89 88 // TODO: think if it's a good idea to store 'empty' attributes
90   - attributesCache.put(attributeKey, foundAttrKvEntry.orElse(null));
  89 + cacheWrapper.put(attributeCacheKey, foundAttrKvEntry.orElse(null));
91 90 return foundAttrKvEntry;
92 91 }, MoreExecutors.directExecutor());
93 92 }
... ... @@ -119,7 +118,7 @@ public class CachedAttributesService implements AttributesService {
119 118 private Map<String, Cache.ValueWrapper> findCachedAttributes(EntityId entityId, String scope, Collection<String> attributeKeys) {
120 119 Map<String, Cache.ValueWrapper> cachedAttributes = new HashMap<>();
121 120 for (String attributeKey : attributeKeys) {
122   - Cache.ValueWrapper cachedAttributeValue = attributesCache.get(new AttributeCacheKey(scope, entityId, attributeKey));
  121 + Cache.ValueWrapper cachedAttributeValue = cacheWrapper.get(new AttributeCacheKey(scope, entityId, attributeKey));
123 122 if (cachedAttributeValue != null) {
124 123 hitCounter.increment();
125 124 cachedAttributes.put(attributeKey, cachedAttributeValue);
... ... @@ -133,11 +132,11 @@ public class CachedAttributesService implements AttributesService {
133 132 private List<AttributeKvEntry> mergeDbAndCacheAttributes(EntityId entityId, String scope, List<AttributeKvEntry> cachedAttributes, Set<String> notFoundAttributeKeys, List<AttributeKvEntry> foundInDbAttributes) {
134 133 for (AttributeKvEntry foundInDbAttribute : foundInDbAttributes) {
135 134 AttributeCacheKey attributeCacheKey = new AttributeCacheKey(scope, entityId, foundInDbAttribute.getKey());
136   - attributesCache.put(attributeCacheKey, foundInDbAttribute);
  135 + cacheWrapper.put(attributeCacheKey, foundInDbAttribute);
137 136 notFoundAttributeKeys.remove(foundInDbAttribute.getKey());
138 137 }
139 138 for (String key : notFoundAttributeKeys){
140   - attributesCache.put(new AttributeCacheKey(scope, entityId, key), null);
  139 + cacheWrapper.put(new AttributeCacheKey(scope, entityId, key), null);
141 140 }
142 141 List<AttributeKvEntry> mergedAttributes = new ArrayList<>(cachedAttributes);
143 142 mergedAttributes.addAll(foundInDbAttributes);
... ... @@ -185,7 +184,7 @@ public class CachedAttributesService implements AttributesService {
185 184 private void evictAttributesFromCache(TenantId tenantId, EntityId entityId, String scope, List<String> attributeKeys) {
186 185 try {
187 186 for (String attributeKey : attributeKeys) {
188   - attributesCache.evict(new AttributeCacheKey(scope, entityId, attributeKey));
  187 + cacheWrapper.evict(new AttributeCacheKey(scope, entityId, attributeKey));
189 188 }
190 189 } catch (Exception e) {
191 190 log.error("[{}][{}] Failed to remove values from cache.", tenantId, entityId, e);
... ...