Cache of the dashboard titles
This commit is contained in:
parent
95e9f5b715
commit
b0d177ee51
@ -185,9 +185,9 @@ public class DefaultTbUserSettingsService implements TbUserSettingsService {
|
||||
|
||||
Map<UUID, String> dashboardTitles = new HashMap<>();
|
||||
uniqueIds.forEach(id -> {
|
||||
var dashboardInfo = dashboardService.findDashboardInfoById(tenantId, new DashboardId(id));
|
||||
if (dashboardInfo != null && StringUtils.isNotEmpty(dashboardInfo.getTitle())) {
|
||||
dashboardTitles.put(id, dashboardInfo.getTitle());
|
||||
var title = dashboardService.findDashboardTitleById(tenantId, new DashboardId(id));
|
||||
if (StringUtils.isNotEmpty(title)) {
|
||||
dashboardTitles.put(id, title);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@ -474,6 +474,10 @@ cache:
|
||||
userSettings:
|
||||
timeToLiveInMinutes: "${CACHE_SPECS_USER_SETTINGS_TTL:1440}"
|
||||
maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}"
|
||||
dashboardTitles:
|
||||
timeToLiveInMinutes: "${CACHE_SPECS_DASHBOARD_TITLES_TTL:1440}"
|
||||
maxSize: "${CACHE_SPECS_DASHBOARD_TITLES_MAX_SIZE:100000}"
|
||||
|
||||
|
||||
#Disable this because it is not required.
|
||||
spring.data.redis.repositories.enabled: false
|
||||
|
||||
@ -18,6 +18,7 @@ package org.thingsboard.server.controller;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
@ -1104,6 +1105,30 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
|
||||
Assert.assertEquals(savedDashboard2.getId().getId(), starred.getId());
|
||||
Assert.assertEquals(savedDashboard2.getTitle(), starred.getTitle());
|
||||
|
||||
//TEST renaming in the cache.
|
||||
savedDashboard1.setTitle(RandomStringUtils.randomAlphanumeric(10));
|
||||
savedDashboard1 = doPost("/api/dashboard", savedDashboard1, Dashboard.class);
|
||||
savedDashboard2.setTitle(RandomStringUtils.randomAlphanumeric(10));
|
||||
savedDashboard2 = doPost("/api/dashboard", savedDashboard2, Dashboard.class);
|
||||
|
||||
newSettings = doGet("/api/user/dashboards/" + savedDashboard1.getId().getId() + "/unstar", UserDashboardsInfo.class);
|
||||
Assert.assertNotNull(newSettings);
|
||||
Assert.assertNotNull(newSettings.getLast());
|
||||
Assert.assertEquals(2, newSettings.getLast().size());
|
||||
lastVisited = newSettings.getLast().get(0);
|
||||
Assert.assertEquals(savedDashboard2.getId().getId(), lastVisited.getId());
|
||||
Assert.assertEquals(savedDashboard2.getTitle(), lastVisited.getTitle());
|
||||
Assert.assertTrue(lastVisited.isStarred());
|
||||
lastVisited = newSettings.getLast().get(1);
|
||||
Assert.assertEquals(savedDashboard1.getId().getId(), lastVisited.getId());
|
||||
Assert.assertEquals(savedDashboard1.getTitle(), lastVisited.getTitle());
|
||||
Assert.assertFalse(lastVisited.isStarred());
|
||||
Assert.assertNotNull(retrievedSettings.getStarred());
|
||||
Assert.assertEquals(1, newSettings.getStarred().size());
|
||||
starred = newSettings.getStarred().get(0);
|
||||
Assert.assertEquals(savedDashboard2.getId().getId(), starred.getId());
|
||||
Assert.assertEquals(savedDashboard2.getTitle(), starred.getTitle());
|
||||
|
||||
doDelete("/api/dashboard/" + savedDashboard1.getId().getId().toString()).andExpect(status().isOk());
|
||||
|
||||
newSettings = doGet("/api/user/dashboards", UserDashboardsInfo.class);
|
||||
|
||||
@ -36,7 +36,7 @@ public interface DashboardService extends EntityDaoService {
|
||||
|
||||
DashboardInfo findDashboardInfoById(TenantId tenantId, DashboardId dashboardId);
|
||||
|
||||
// String findDashboardTitleById(TenantId tenantId, DashboardId dashboardId);
|
||||
String findDashboardTitleById(TenantId tenantId, DashboardId dashboardId);
|
||||
|
||||
ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId);
|
||||
|
||||
|
||||
@ -42,4 +42,5 @@ public class CacheConstants {
|
||||
public static final String TWO_FA_VERIFICATION_CODES_CACHE = "twoFaVerificationCodes";
|
||||
public static final String VERSION_CONTROL_TASK_CACHE = "versionControlTask";
|
||||
public static final String USER_SETTINGS_CACHE = "userSettings";
|
||||
public static final String DASHBOARD_TITLES_CACHE = "dashboardTitles";
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
package org.thingsboard.server.dao.dashboard;
|
||||
|
||||
import org.thingsboard.server.common.data.DashboardInfo;
|
||||
import org.thingsboard.server.common.data.id.DashboardId;
|
||||
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.Dao;
|
||||
@ -77,4 +79,5 @@ public interface DashboardInfoDao extends Dao<DashboardInfo> {
|
||||
|
||||
DashboardInfo findFirstByTenantIdAndName(UUID tenantId, String name);
|
||||
|
||||
String findTitleById(UUID tenantId, UUID dashboardId);
|
||||
}
|
||||
|
||||
@ -19,8 +19,12 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.thingsboard.server.cache.TbTransactionalCache;
|
||||
import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.Dashboard;
|
||||
import org.thingsboard.server.common.data.DashboardInfo;
|
||||
@ -36,6 +40,7 @@ import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||
import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey;
|
||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||
import org.thingsboard.server.dao.edge.EdgeDao;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
@ -43,6 +48,7 @@ import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
import org.thingsboard.server.dao.service.DataValidator;
|
||||
import org.thingsboard.server.dao.service.PaginatedRemover;
|
||||
import org.thingsboard.server.dao.service.Validator;
|
||||
import org.thingsboard.server.dao.user.UserSettingsEvictEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -70,6 +76,25 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
|
||||
@Autowired
|
||||
private DataValidator<Dashboard> dashboardValidator;
|
||||
|
||||
@Autowired
|
||||
protected TbTransactionalCache<DashboardId, String> cache;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
protected void publishEvictEvent(DashboardTitleEvictEvent event) {
|
||||
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
||||
eventPublisher.publishEvent(event);
|
||||
} else {
|
||||
handleEvictEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@TransactionalEventListener(classes = DashboardTitleEvictEvent.class)
|
||||
public void handleEvictEvent(DashboardTitleEvictEvent event) {
|
||||
cache.evict(event.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId) {
|
||||
log.trace("Executing findDashboardById [{}]", dashboardId);
|
||||
@ -91,6 +116,12 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
|
||||
return dashboardInfoDao.findById(tenantId, dashboardId.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findDashboardTitleById(TenantId tenantId, DashboardId dashboardId) {
|
||||
return cache.getAndPutInTransaction(dashboardId,
|
||||
() -> dashboardInfoDao.findTitleById(tenantId.getId(), dashboardId.getId()), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<DashboardInfo> findDashboardInfoByIdAsync(TenantId tenantId, DashboardId dashboardId) {
|
||||
log.trace("Executing findDashboardInfoByIdAsync [{}]", dashboardId);
|
||||
@ -103,8 +134,13 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
|
||||
log.trace("Executing saveDashboard [{}]", dashboard);
|
||||
dashboardValidator.validate(dashboard, DashboardInfo::getTenantId);
|
||||
try {
|
||||
return dashboardDao.save(dashboard.getTenantId(), dashboard);
|
||||
var saved = dashboardDao.save(dashboard.getTenantId(), dashboard);
|
||||
publishEvictEvent(new DashboardTitleEvictEvent(saved.getId()));
|
||||
return saved;
|
||||
} catch (Exception e) {
|
||||
if (dashboard.getId() != null) {
|
||||
publishEvictEvent(new DashboardTitleEvictEvent(dashboard.getId()));
|
||||
}
|
||||
checkConstraintViolation(e, "dashboard_external_id_unq_key", "Dashboard with such external id already exists!");
|
||||
throw e;
|
||||
}
|
||||
@ -170,6 +206,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
|
||||
deleteEntityRelations(tenantId, dashboardId);
|
||||
try {
|
||||
dashboardDao.removeById(tenantId, dashboardId.getId());
|
||||
publishEvictEvent(new DashboardTitleEvictEvent(dashboardId));
|
||||
} catch (Exception t) {
|
||||
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
|
||||
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_dashboard_device_profile")) {
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.dao.dashboard;
|
||||
|
||||
import lombok.Data;
|
||||
import org.thingsboard.server.common.data.id.DashboardId;
|
||||
import org.thingsboard.server.common.data.settings.UserSettingsCompositeKey;
|
||||
|
||||
@Data
|
||||
public class DashboardTitleEvictEvent {
|
||||
private final DashboardId key;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.dao.dashboard;
|
||||
|
||||
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.id.DashboardId;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
|
||||
@Service("DashboardTitlesCache")
|
||||
public class DashboardTitlesCaffeineCache extends CaffeineTbTransactionalCache<DashboardId, String> {
|
||||
|
||||
public DashboardTitlesCaffeineCache(CacheManager cacheManager) {
|
||||
super(cacheManager, CacheConstants.DASHBOARD_TITLES_CACHE);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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.dao.dashboard;
|
||||
|
||||
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.id.DashboardId;
|
||||
|
||||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
|
||||
@Service("DashboardTitlesCache")
|
||||
public class DashboardTitlesRedisCache extends RedisTbTransactionalCache<DashboardId, String> {
|
||||
|
||||
public DashboardTitlesRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
|
||||
super(CacheConstants.DASHBOARD_TITLES_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>());
|
||||
}
|
||||
}
|
||||
@ -72,4 +72,6 @@ public interface DashboardInfoRepository extends JpaRepository<DashboardInfoEnti
|
||||
@Param("searchText") String searchText,
|
||||
Pageable pageable);
|
||||
|
||||
@Query("SELECT di.title FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId AND di.id = :dashboardId")
|
||||
String findTitleByTenantIdAndId(@Param("tenantId") UUID tenantId, @Param("dashboardId") UUID dashboardId);
|
||||
}
|
||||
|
||||
@ -118,4 +118,9 @@ public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoE
|
||||
public DashboardInfo findFirstByTenantIdAndName(UUID tenantId, String name) {
|
||||
return DaoUtil.getData(dashboardInfoRepository.findFirstByTenantIdAndTitle(tenantId, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findTitleById(UUID tenantId, UUID dashboardId) {
|
||||
return dashboardInfoRepository.findTitleByTenantIdAndId(tenantId, dashboardId);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user