From 7d1e12d4b18a46350585971d9006932514f5b1c7 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 9 Nov 2023 15:15:12 +0200 Subject: [PATCH 1/3] fixed save method to not put into cache --- .../dao/asset/AssetProfileServiceImpl.java | 9 +++-- .../dao/device/DeviceProfileServiceImpl.java | 8 ++-- .../server/dao/device/DeviceServiceImpl.java | 6 ++- .../dao/entityview/EntityViewServiceImpl.java | 4 +- .../server/dao/service/AssetServiceTest.java | 39 +++++++++++++++++++ .../server/dao/service/DeviceServiceTest.java | 29 ++++++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 9240bbc223..fd17c484d7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -126,8 +126,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService idComparator = new IdComparator<>(); @@ -75,6 +91,29 @@ public class AssetServiceTest extends AbstractServiceTest { assetService.deleteAsset(tenantId, savedAsset.getId()); } + @Test + public void testShouldNotPutInCacheRolledbackAssetProfile() { + AssetProfile assetProfile = new AssetProfile(); + assetProfile.setName(StringUtils.randomAlphabetic(10)); + assetProfile.setTenantId(tenantId); + + Asset asset = new Asset(); + asset.setName("My asset" + StringUtils.randomAlphabetic(15)); + asset.setType(assetProfile.getName()); + asset.setTenantId(tenantId); + + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + TransactionStatus status = platformTransactionManager.getTransaction(def); + try { + assetProfileService.saveAssetProfile(assetProfile); + assetService.saveAsset(asset); + } finally { + platformTransactionManager.rollback(status); + } + AssetProfile assetProfileByName = assetProfileService.findAssetProfileByName(tenantId, assetProfile.getName()); + Assert.assertNull(assetProfileByName); + } + @Test public void testSaveAssetWithEmptyName() { Asset asset = new Asset(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceServiceTest.java index 1073f20be4..3e404f8d1d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceServiceTest.java @@ -22,6 +22,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.DefaultTransactionDefinition; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceInfo; @@ -32,6 +35,8 @@ import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; @@ -72,6 +77,8 @@ public class DeviceServiceTest extends AbstractServiceTest { OtaPackageService otaPackageService; @Autowired TenantProfileService tenantProfileService; + @Autowired + private PlatformTransactionManager platformTransactionManager; private IdComparator idComparator = new IdComparator<>(); private TenantId anotherTenantId; @@ -305,6 +312,28 @@ public class DeviceServiceTest extends AbstractServiceTest { }); } + @Test + public void testShouldNotPutInCacheRolledbackDeviceProfile() { + DeviceProfile deviceProfile = createDeviceProfile(tenantId, "New device Profile" + StringUtils.randomAlphabetic(5)); + + + Device device = new Device(); + device.setType(deviceProfile.getName()); + device.setTenantId(tenantId); + device.setName("My device"+ StringUtils.randomAlphabetic(5)); + + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + TransactionStatus status = platformTransactionManager.getTransaction(def); + try { + deviceProfileService.saveDeviceProfile(deviceProfile); + deviceService.saveDevice(device); + } finally { + platformTransactionManager.rollback(status); + } + DeviceProfile deviceProfileByName = deviceProfileService.findDeviceProfileByName(tenantId, deviceProfile.getName()); + Assert.assertNull(deviceProfileByName); + } + @Test public void testAssignDeviceToNonExistentCustomer() { Device device = new Device(); From 6551658bfc5a07074badaa3dc91348918b315e7f Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 10 Nov 2023 13:17:23 +0200 Subject: [PATCH 2/3] updated TbTransactionalCache with method that retrieve but doesn`t put value in cache --- .../server/cache/TbTransactionalCache.java | 25 ++++++++++++++++++ .../server/dao/asset/AssetProfileService.java | 4 +++ .../dao/device/DeviceProfileService.java | 4 +++ .../dao/entityview/EntityViewService.java | 2 ++ .../dao/asset/AssetProfileServiceImpl.java | 23 +++++++++++----- .../dao/device/DeviceProfileServiceImpl.java | 26 +++++++++++++------ .../server/dao/device/DeviceServiceImpl.java | 6 ++--- .../dao/entityview/EntityViewServiceImpl.java | 13 +++++++--- 8 files changed, 80 insertions(+), 23 deletions(-) diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java index fc104ef7f1..219e89299f 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java @@ -47,6 +47,18 @@ public interface TbTransactionalCache newTransactionForKeys(List keys); + default V getOrFetchFromDB(K key, Supplier dbCall, boolean cacheNullValue, boolean putToCache) { + if (putToCache) { + return getAndPutInTransaction(key, dbCall, cacheNullValue); + } else { + TbCacheValueWrapper cacheValueWrapper = get(key); + if (cacheValueWrapper != null) { + return cacheValueWrapper.get(); + } + return dbCall.get(); + } + } + default V getAndPutInTransaction(K key, Supplier dbCall, boolean cacheNullValue) { TbCacheValueWrapper cacheValueWrapper = get(key); if (cacheValueWrapper != null) { @@ -69,6 +81,19 @@ public interface TbTransactionalCache R getOrFetchFromDB(K key, Supplier dbCall, Function cacheValueToResult, Function dbValueToCacheValue, boolean cacheNullValue, boolean putToCache) { + if (putToCache) { + return getAndPutInTransaction(key, dbCall, cacheValueToResult, dbValueToCacheValue, cacheNullValue); + } else { + TbCacheValueWrapper cacheValueWrapper = get(key); + if (cacheValueWrapper != null) { + var cacheValue = cacheValueWrapper.get(); + return cacheValue == null ? null : cacheValueToResult.apply(cacheValue); + } + return dbCall.get(); + } + } + default R getAndPutInTransaction(K key, Supplier dbCall, Function cacheValueToResult, Function dbValueToCacheValue, boolean cacheNullValue) { TbCacheValueWrapper cacheValueWrapper = get(key); if (cacheValueWrapper != null) { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java index 1ec6fb3fb5..477c352b54 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java @@ -27,8 +27,12 @@ public interface AssetProfileService extends EntityDaoService { AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId); + AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId, boolean putInCache); + AssetProfile findAssetProfileByName(TenantId tenantId, String profileName); + AssetProfile findAssetProfileByName(TenantId tenantId, String profileName, boolean putInCache); + AssetProfileInfo findAssetProfileInfoById(TenantId tenantId, AssetProfileId assetProfileId); AssetProfile saveAssetProfile(AssetProfile assetProfile, boolean doValidate); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java index f94b709c97..5d325aa1a6 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java @@ -27,8 +27,12 @@ public interface DeviceProfileService extends EntityDaoService { DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId); + DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId, boolean putInCache); + DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName); + DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName, boolean putInCache); + DeviceProfileInfo findDeviceProfileInfoById(TenantId tenantId, DeviceProfileId deviceProfileId); DeviceProfile saveDeviceProfile(DeviceProfile deviceProfile, boolean doValidate); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 09bad2b48d..7a020767f5 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -50,6 +50,8 @@ public interface EntityViewService extends EntityDaoService { EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId); + EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId, boolean putInCache); + EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); PageData findEntityViewByTenantId(TenantId tenantId, PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index fd17c484d7..075975cd96 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -90,14 +90,24 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService assetProfileDao.findById(tenantId, assetProfileId.getId()), true); + return cache.getOrFetchFromDB(AssetProfileCacheKey.fromId(assetProfileId), + () -> assetProfileDao.findById(tenantId, assetProfileId.getId()), true, putInCache); } @Override public AssetProfile findAssetProfileByName(TenantId tenantId, String profileName) { + return findAssetProfileByName(tenantId, profileName, true); + } + + @Override + public AssetProfile findAssetProfileByName(TenantId tenantId, String profileName, boolean putInCache) { log.trace("Executing findAssetProfileByName [{}][{}]", tenantId, profileName); Validator.validateString(profileName, INCORRECT_ASSET_PROFILE_NAME + profileName); return cache.getAndPutInTransaction(AssetProfileCacheKey.fromName(tenantId, profileName), @@ -126,8 +136,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService deviceProfileDao.findById(tenantId, deviceProfileId.getId()), true); + return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromId(deviceProfileId), + () -> deviceProfileDao.findById(tenantId, deviceProfileId.getId()), true, putInCache); } @Override public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName) { + return findDeviceProfileByName(tenantId, profileName, true); + } + + @Override + public DeviceProfile findDeviceProfileByName(TenantId tenantId, String profileName, boolean putInCache) { log.trace("Executing findDeviceProfileByName [{}][{}]", tenantId, profileName); validateString(profileName, INCORRECT_DEVICE_PROFILE_NAME + profileName); - return cache.getAndPutInTransaction(DeviceProfileCacheKey.fromName(tenantId, profileName), - () -> deviceProfileDao.findByName(tenantId, profileName), true); + return cache.getOrFetchFromDB(DeviceProfileCacheKey.fromName(tenantId, profileName), + () -> deviceProfileDao.findByName(tenantId, profileName), true, putInCache); } @Override @@ -163,8 +173,8 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService entityViewDao.findById(tenantId, entityViewId.getId()) - , EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true); + , EntityViewCacheValue::getEntityView, v -> new EntityViewCacheValue(v, null), true, putInCache); } @Override From e6473c9c171255b17d9ef57cf6e85950e9892077 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 10 Nov 2023 15:40:56 +0200 Subject: [PATCH 3/3] fixed AssetProfileServiceImpl --- .../thingsboard/server/dao/asset/AssetProfileServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 075975cd96..7cc251f9ec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -110,8 +110,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService assetProfileDao.findByName(tenantId, profileName), false); + return cache.getOrFetchFromDB(AssetProfileCacheKey.fromName(tenantId, profileName), + () -> assetProfileDao.findByName(tenantId, profileName), false, putInCache); } @Override