From eab633632a7cc0904ec4ae2002bef8a88c308050 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 28 Jun 2023 11:35:54 +0300 Subject: [PATCH 1/3] added cache for TBResourceInfo --- .../src/main/resources/thingsboard.yml | 3 ++ .../resourceinfo/ResourceInfoCacheKey.java | 45 +++++++++++++++++++ .../ResourceInfoCaffeineCache.java | 34 ++++++++++++++ .../resourceinfo/ResourceInfoEvictEvent.java | 23 ++++++++++ .../resourceinfo/ResourceInfoRedisCache.java | 35 +++++++++++++++ .../server/common/data/CacheConstants.java | 1 + .../dao/resource/BaseResourceService.java | 28 +++++++----- 7 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 81654e3033..ba49ae5b23 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -497,6 +497,9 @@ cache: entityCount: timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}" maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" + resourceInfo: + timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" + maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" # deliberately placed outside 'specs' group above notificationRules: diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java new file mode 100644 index 0000000000..670866e54b --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 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.cache.resourceinfo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.io.Serializable; +import java.util.UUID; + +@Getter +@EqualsAndHashCode +@RequiredArgsConstructor +@Builder +public class ResourceInfoCacheKey implements Serializable { + + private final TenantId tenantId; + private final TbResourceId tbResourceId; + + @Override + public String toString() { + return tenantId + "_" + tbResourceId; + } +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java new file mode 100644 index 0000000000..371f2012cc --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2023 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.cache.resourceinfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("ResourceInfoCache") +public class ResourceInfoCaffeineCache extends CaffeineTbTransactionalCache { + + public ResourceInfoCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.RESOURCE_INFO_CACHE); + } + +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java new file mode 100644 index 0000000000..002510b314 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2023 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.cache.resourceinfo; + +import lombok.Data; + +@Data +public class ResourceInfoEvictEvent { + private final ResourceInfoCacheKey key; +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java new file mode 100644 index 0000000000..617367fb80 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2023 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.cache.resourceinfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CacheSpecsMap; +import org.thingsboard.server.cache.RedisTbTransactionalCache; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.cache.TbFSTRedisSerializer; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("ResourceInfoCache") +public class ResourceInfoRedisCache extends RedisTbTransactionalCache { + + public ResourceInfoRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.RESOURCE_INFO_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index ff0032f435..f21b13a674 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -44,4 +44,5 @@ public class CacheConstants { public static final String USER_SETTINGS_CACHE = "userSettings"; public static final String DASHBOARD_TITLES_CACHE = "dashboardTitles"; public static final String ENTITY_COUNT_CACHE = "entityCount"; + public static final String RESOURCE_INFO_CACHE = "resourceInfo"; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 974e3665f1..016b9c9d9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -20,7 +20,10 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; +import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.server.cache.resourceinfo.ResourceInfoEvictEvent; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.cache.resourceinfo.ResourceInfoCacheKey; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; @@ -31,6 +34,7 @@ import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -45,7 +49,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service("TbResourceDaoService") @Slf4j @AllArgsConstructor -public class BaseResourceService implements ResourceService { +public class BaseResourceService extends AbstractCachedEntityService implements ResourceService { public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; private final TbResourceDao resourceDao; @@ -55,10 +59,12 @@ public class BaseResourceService implements ResourceService { @Override public TbResource saveResource(TbResource resource) { resourceValidator.validate(resource, TbResourceInfo::getTenantId); - try { - return resourceDao.save(resource.getTenantId(), resource); + TbResource saved = resourceDao.save(resource.getTenantId(), resource); + publishEvictEvent(new ResourceInfoEvictEvent(new ResourceInfoCacheKey(resource.getTenantId(), resource.getId()))); + return saved; } catch (Exception t) { + publishEvictEvent(new ResourceInfoEvictEvent(new ResourceInfoCacheKey(resource.getTenantId(), resource.getId()))); ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) { String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName"; @@ -86,7 +92,9 @@ public class BaseResourceService implements ResourceService { public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) { log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId); Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId); - return resourceInfoDao.findById(tenantId, resourceId.getId()); + + return cache.getAndPutInTransaction(new ResourceInfoCacheKey(tenantId, resourceId), + () -> resourceInfoDao.findById(tenantId, resourceId.getId()), true); } @Override @@ -169,13 +177,9 @@ public class BaseResourceService implements ResourceService { } }; - protected Optional extractConstraintViolationException(Exception t) { - if (t instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) t); - } else if (t.getCause() instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) (t.getCause())); - } else { - return Optional.empty(); - } + @TransactionalEventListener(classes = ResourceInfoCacheKey.class) + @Override + public void handleEvictEvent(ResourceInfoEvictEvent event) { + cache.evict(event.getKey()); } } From e2ba34bbf33a70d6b3307a7284e9c5890da711f3 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 28 Jun 2023 13:48:46 +0300 Subject: [PATCH 2/3] refactoring --- application/src/main/resources/thingsboard.yml | 2 +- .../ResourceInfoCacheKey.java | 7 +------ .../ResourceInfoCaffeineCache.java | 2 +- .../ResourceInfoEvictEvent.java | 7 +++++-- .../ResourceInfoRedisCache.java | 2 +- .../server/dao/resource/BaseResourceService.java | 15 +++++++++------ 6 files changed, 18 insertions(+), 17 deletions(-) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoCacheKey.java (84%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoCaffeineCache.java (96%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoEvictEvent.java (73%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoRedisCache.java (97%) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index ba49ae5b23..c8dfd1b029 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -499,7 +499,7 @@ cache: maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" resourceInfo: timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" - maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" + maxSize: "${CACHE_SPECS_RESOURCE_INFO_MAX_SIZE:100000}" # deliberately placed outside 'specs' group above notificationRules: diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java similarity index 84% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java index 670866e54b..9db53f86c6 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java @@ -13,21 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; -import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serializable; -import java.util.UUID; @Getter @EqualsAndHashCode diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java similarity index 96% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java index 371f2012cc..95754d891a 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java similarity index 73% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java index 002510b314..11272a5e24 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import lombok.Data; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; @Data public class ResourceInfoEvictEvent { - private final ResourceInfoCacheKey key; + private final TenantId tenantId; + private final TbResourceId resourceId; } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java similarity index 97% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java index 617367fb80..fee14e1ca1 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.redis.connection.RedisConnectionFactory; diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 016b9c9d9a..bc4f47040b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -21,9 +21,10 @@ import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; -import org.thingsboard.server.cache.resourceinfo.ResourceInfoEvictEvent; +import org.thingsboard.server.cache.device.DeviceCacheKey; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoEvictEvent; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.cache.resourceinfo.ResourceInfoCacheKey; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoCacheKey; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; @@ -61,10 +62,10 @@ public class BaseResourceService extends AbstractCachedEntityService Date: Wed, 28 Jun 2023 14:50:17 +0300 Subject: [PATCH 3/3] added cache config properties --- dao/src/test/resources/application-test.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index d89211cb2f..98f9091318 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -74,6 +74,9 @@ cache.specs.dashboardTitles.maxSize=10000 cache.specs.entityCount.timeToLiveInMinutes=1440 cache.specs.entityCount.maxSize=10000 +cache.specs.resourceInfo.timeToLiveInMinutes=1440 +cache.specs.resourceInfo.maxSize=10000 + redis.connection.host=localhost redis.connection.port=6379 redis.connection.db=0