Commit 6f80cf95e2699c0d36bc8e378158c6ac7f8ce622

Authored by Andrii Shvaika
1 parent ff4ca5a7

Tenant Profile Cache

... ... @@ -72,6 +72,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService;
72 72 import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
73 73 import org.thingsboard.server.service.mail.MailExecutorService;
74 74 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
  75 +import org.thingsboard.server.service.profile.TbTenantProfileCache;
75 76 import org.thingsboard.server.service.queue.TbClusterService;
76 77 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
77 78 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
... ... @@ -129,6 +130,10 @@ public class ActorSystemContext {
129 130
130 131 @Autowired
131 132 @Getter
  133 + private TbTenantProfileCache tenantProfileCache;
  134 +
  135 + @Autowired
  136 + @Getter
132 137 private TbDeviceProfileCache deviceProfileCache;
133 138
134 139 @Autowired
... ...
... ... @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.Tenant;
30 30 import org.thingsboard.server.common.data.TenantProfile;
31 31 import org.thingsboard.server.common.data.id.EntityId;
32 32 import org.thingsboard.server.common.data.id.TenantId;
  33 +import org.thingsboard.server.common.data.id.TenantProfileId;
33 34 import org.thingsboard.server.common.data.page.PageDataIterable;
34 35 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
35 36 import org.thingsboard.server.common.msg.MsgType;
... ... @@ -40,7 +41,9 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
40 41 import org.thingsboard.server.common.msg.queue.RuleEngineException;
41 42 import org.thingsboard.server.common.msg.queue.ServiceType;
42 43 import org.thingsboard.server.dao.model.ModelConstants;
  44 +import org.thingsboard.server.dao.tenant.TenantProfileService;
43 45 import org.thingsboard.server.dao.tenant.TenantService;
  46 +import org.thingsboard.server.service.profile.TbTenantProfileCache;
44 47 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
45 48
46 49 import java.util.HashSet;
... ... @@ -50,13 +53,14 @@ import java.util.Set;
50 53 @Slf4j
51 54 public class AppActor extends ContextAwareActor {
52 55
53   - private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
  56 + private final TbTenantProfileCache tenantProfileCache;
54 57 private final TenantService tenantService;
55 58 private final Set<TenantId> deletedTenants;
56 59 private boolean ruleChainsInitialized;
57 60
58 61 private AppActor(ActorSystemContext systemContext) {
59 62 super(systemContext);
  63 + this.tenantProfileCache = systemContext.getTenantProfileCache();
60 64 this.tenantService = systemContext.getTenantService();
61 65 this.deletedTenants = new HashSet<>();
62 66 }
... ... @@ -117,8 +121,7 @@ public class AppActor extends ContextAwareActor {
117 121 boolean isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
118 122 boolean isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
119 123 for (Tenant tenant : tenantIterator) {
120   - // TODO: Tenant Profile from cache
121   - TenantProfile tenantProfile = systemContext.getTenantProfileService().findTenantProfileById(TenantId.SYS_TENANT_ID, tenant.getTenantProfileId());
  124 + TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId());
122 125 if (isCore || (isRuleEngine && !tenantProfile.isIsolatedTbRuleEngine())) {
123 126 log.debug("[{}] Creating tenant actor", tenant.getId());
124 127 getOrCreateTenantActor(tenant.getId());
... ... @@ -133,7 +136,7 @@ public class AppActor extends ContextAwareActor {
133 136 }
134 137
135 138 private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
136   - if (SYSTEM_TENANT.equals(msg.getTenantId())) {
  139 + if (TenantId.SYS_TENANT_ID.equals(msg.getTenantId())) {
137 140 msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!"));
138 141 } else {
139 142 if (!deletedTenants.contains(msg.getTenantId())) {
... ... @@ -146,15 +149,23 @@ public class AppActor extends ContextAwareActor {
146 149
147 150 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
148 151 TbActorRef target = null;
149   - if (SYSTEM_TENANT.equals(msg.getTenantId())) {
150   - log.warn("Message has system tenant id: {}", msg);
  152 + if (TenantId.SYS_TENANT_ID.equals(msg.getTenantId())) {
  153 + if (msg.getEntityId().getEntityType() == EntityType.TENANT_PROFILE) {
  154 + tenantProfileCache.evict(new TenantProfileId(msg.getEntityId().getId()));
  155 + } else {
  156 + log.warn("Message has system tenant id: {}", msg);
  157 + }
151 158 } else {
152   - if (msg.getEntityId().getEntityType() == EntityType.TENANT
153   - && msg.getEvent() == ComponentLifecycleEvent.DELETED) {
154   - log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
  159 + if (msg.getEntityId().getEntityType() == EntityType.TENANT) {
155 160 TenantId tenantId = new TenantId(msg.getEntityId().getId());
156   - deletedTenants.add(tenantId);
157   - ctx.stop(new TbEntityActorId(tenantId));
  161 + tenantProfileCache.evict(tenantId);
  162 + if (msg.getEvent() == ComponentLifecycleEvent.DELETED) {
  163 + log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
  164 + deletedTenants.add(tenantId);
  165 + ctx.stop(new TbEntityActorId(tenantId));
  166 + } else {
  167 + target = getOrCreateTenantActor(msg.getTenantId());
  168 + }
158 169 } else {
159 170 target = getOrCreateTenantActor(msg.getTenantId());
160 171 }
... ...
... ... @@ -77,9 +77,7 @@ public class TenantActor extends RuleChainManagerActor {
77 77 // This Service may be started for specific tenant only.
78 78 Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant();
79 79
80   - // TODO: Tenant Profile from cache
81   -
82   - TenantProfile tenantProfile = systemContext.getTenantProfileService().findTenantProfileById(tenantId, tenant.getTenantProfileId());
  80 + TenantProfile tenantProfile = systemContext.getTenantProfileCache().get(tenant.getTenantProfileId());
83 81
84 82 isRuleEngineForCurrentTenant = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
85 83 isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
... ...
... ... @@ -94,6 +94,7 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
94 94 import org.thingsboard.server.queue.util.TbCoreComponent;
95 95 import org.thingsboard.server.service.component.ComponentDiscoveryService;
96 96 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
  97 +import org.thingsboard.server.service.profile.TbTenantProfileCache;
97 98 import org.thingsboard.server.service.queue.TbClusterService;
98 99 import org.thingsboard.server.service.security.model.SecurityUser;
99 100 import org.thingsboard.server.service.security.permission.AccessControlService;
... ... @@ -206,6 +207,9 @@ public abstract class BaseController {
206 207 protected TbQueueProducerProvider producerProvider;
207 208
208 209 @Autowired
  210 + protected TbTenantProfileCache tenantProfileCache;
  211 +
  212 + @Autowired
209 213 protected TbDeviceProfileCache deviceProfileCache;
210 214
211 215 @Value("${server.log_controller_error_stack_trace}")
... ...
... ... @@ -91,6 +91,7 @@ public class TenantController extends BaseController {
91 91 if (newTenant) {
92 92 installScripts.createDefaultRuleChains(tenant.getId());
93 93 }
  94 + tenantProfileCache.evict(tenant.getId());
94 95 return tenant;
95 96 } catch (Exception e) {
96 97 throw handleException(e);
... ... @@ -106,6 +107,7 @@ public class TenantController extends BaseController {
106 107 TenantId tenantId = new TenantId(toUUID(strTenantId));
107 108 checkTenantId(tenantId, Operation.DELETE);
108 109 tenantService.deleteTenant(tenantId);
  110 + tenantProfileCache.evict(tenantId);
109 111 tbClusterService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
110 112 } catch (Exception e) {
111 113 throw handleException(e);
... ...
... ... @@ -29,9 +29,11 @@ import org.springframework.web.bind.annotation.RestController;
29 29 import org.thingsboard.server.common.data.EntityInfo;
30 30 import org.thingsboard.server.common.data.TenantProfile;
31 31 import org.thingsboard.server.common.data.exception.ThingsboardException;
  32 +import org.thingsboard.server.common.data.id.TenantId;
32 33 import org.thingsboard.server.common.data.id.TenantProfileId;
33 34 import org.thingsboard.server.common.data.page.PageData;
34 35 import org.thingsboard.server.common.data.page.PageLink;
  36 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
35 37 import org.thingsboard.server.queue.util.TbCoreComponent;
36 38 import org.thingsboard.server.service.security.permission.Operation;
37 39 import org.thingsboard.server.service.security.permission.Resource;
... ... @@ -93,8 +95,11 @@ public class TenantProfileController extends BaseController {
93 95 }
94 96
95 97 tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile));
  98 + tenantProfileCache.put(tenantProfile);
  99 + tbClusterService.onEntityStateChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(),
  100 + newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
96 101 return tenantProfile;
97   - } catch (Exception e) {
  102 + } catch (Exception e) {
98 103 throw handleException(e);
99 104 }
100 105 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 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.service.profile;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Service;
  20 +import org.thingsboard.server.common.data.Device;
  21 +import org.thingsboard.server.common.data.DeviceProfile;
  22 +import org.thingsboard.server.common.data.Tenant;
  23 +import org.thingsboard.server.common.data.TenantProfile;
  24 +import org.thingsboard.server.common.data.id.DeviceId;
  25 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  26 +import org.thingsboard.server.common.data.id.TenantId;
  27 +import org.thingsboard.server.common.data.id.TenantProfileId;
  28 +import org.thingsboard.server.dao.device.DeviceProfileService;
  29 +import org.thingsboard.server.dao.device.DeviceService;
  30 +import org.thingsboard.server.dao.tenant.TenantProfileService;
  31 +import org.thingsboard.server.dao.tenant.TenantService;
  32 +
  33 +import java.util.concurrent.ConcurrentHashMap;
  34 +import java.util.concurrent.ConcurrentMap;
  35 +import java.util.concurrent.locks.Lock;
  36 +import java.util.concurrent.locks.ReentrantLock;
  37 +
  38 +@Service
  39 +@Slf4j
  40 +public class DefaultTbTenantProfileCache implements TbTenantProfileCache {
  41 +
  42 + private final Lock tenantProfileFetchLock = new ReentrantLock();
  43 + private final TenantProfileService tenantProfileService;
  44 + private final TenantService tenantService;
  45 +
  46 + private final ConcurrentMap<TenantProfileId, TenantProfile> tenantProfilesMap = new ConcurrentHashMap<>();
  47 + private final ConcurrentMap<TenantId, TenantProfileId> tenantsMap = new ConcurrentHashMap<>();
  48 +
  49 + public DefaultTbTenantProfileCache(TenantProfileService tenantProfileService, TenantService tenantService) {
  50 + this.tenantProfileService = tenantProfileService;
  51 + this.tenantService = tenantService;
  52 + }
  53 +
  54 + @Override
  55 + public TenantProfile get(TenantProfileId tenantProfileId) {
  56 + TenantProfile profile = tenantProfilesMap.get(tenantProfileId);
  57 + if (profile == null) {
  58 + profile = tenantProfilesMap.get(tenantProfileId);
  59 + if (profile == null) {
  60 + tenantProfileFetchLock.lock();
  61 + try {
  62 + profile = tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, tenantProfileId);
  63 + if (profile != null) {
  64 + tenantProfilesMap.put(tenantProfileId, profile);
  65 + }
  66 + } finally {
  67 + tenantProfileFetchLock.unlock();
  68 + }
  69 + }
  70 + }
  71 + return profile;
  72 + }
  73 +
  74 + @Override
  75 + public TenantProfile get(TenantId tenantId) {
  76 + TenantProfileId profileId = tenantsMap.get(tenantId);
  77 + if (profileId == null) {
  78 + Tenant tenant = tenantService.findTenantById(tenantId);
  79 + if (tenant != null) {
  80 + profileId = tenant.getTenantProfileId();
  81 + tenantsMap.put(tenantId, profileId);
  82 + } else {
  83 + return null;
  84 + }
  85 + }
  86 + return get(profileId);
  87 + }
  88 +
  89 + @Override
  90 + public void put(TenantProfile profile) {
  91 + if (profile.getId() != null) {
  92 + tenantProfilesMap.put(profile.getId(), profile);
  93 + }
  94 + }
  95 +
  96 + @Override
  97 + public void evict(TenantProfileId profileId) {
  98 + tenantProfilesMap.remove(profileId);
  99 + }
  100 +
  101 + @Override
  102 + public void evict(TenantId tenantId) {
  103 + tenantsMap.remove(tenantId);
  104 + }
  105 +
  106 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2020 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.service.profile;
  17 +
  18 +import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
  19 +import org.thingsboard.server.common.data.DeviceProfile;
  20 +import org.thingsboard.server.common.data.TenantProfile;
  21 +import org.thingsboard.server.common.data.id.DeviceId;
  22 +import org.thingsboard.server.common.data.id.DeviceProfileId;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.id.TenantProfileId;
  25 +
  26 +public interface TbTenantProfileCache {
  27 +
  28 + TenantProfile get(TenantId tenantId);
  29 +
  30 + TenantProfile get(TenantProfileId tenantProfileId);
  31 +
  32 + void put(TenantProfile profile);
  33 +
  34 + void evict(TenantProfileId id);
  35 +
  36 + void evict(TenantId id);
  37 +
  38 +}
... ...
... ... @@ -25,6 +25,7 @@ import org.thingsboard.server.dao.tenant.TenantProfileService;
25 25 import org.thingsboard.server.dao.tenant.TenantService;
26 26 import org.thingsboard.server.queue.discovery.TenantRoutingInfo;
27 27 import org.thingsboard.server.queue.discovery.TenantRoutingInfoService;
  28 +import org.thingsboard.server.service.profile.TbTenantProfileCache;
28 29
29 30 @Slf4j
30 31 @Service
... ... @@ -33,19 +34,18 @@ public class DefaultTenantRoutingInfoService implements TenantRoutingInfoService
33 34
34 35 private final TenantService tenantService;
35 36
36   - private final TenantProfileService tenantProfileService;
  37 + private final TbTenantProfileCache tenantProfileCache;
37 38
38   - public DefaultTenantRoutingInfoService(TenantService tenantService, TenantProfileService tenantProfileService) {
  39 + public DefaultTenantRoutingInfoService(TenantService tenantService, TbTenantProfileCache tenantProfileCache) {
39 40 this.tenantService = tenantService;
40   - this.tenantProfileService = tenantProfileService;
  41 + this.tenantProfileCache = tenantProfileCache;
41 42 }
42 43
43 44 @Override
44 45 public TenantRoutingInfo getRoutingInfo(TenantId tenantId) {
45 46 Tenant tenant = tenantService.findTenantById(tenantId);
46 47 if (tenant != null) {
47   - // TODO: Tenant Profile from cache
48   - TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(tenantId, tenant.getTenantProfileId());
  48 + TenantProfile tenantProfile = tenantProfileCache.get(tenant.getTenantProfileId());
49 49 return new TenantRoutingInfo(tenantId, tenantProfile.isIsolatedTbCore(), tenantProfile.isIsolatedTbRuleEngine());
50 50 } else {
51 51 throw new RuntimeException("Tenant not found!");
... ...
... ... @@ -70,6 +70,7 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg;
70 70 import org.thingsboard.server.queue.util.TbCoreComponent;
71 71 import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
72 72 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
  73 +import org.thingsboard.server.service.profile.TbTenantProfileCache;
73 74 import org.thingsboard.server.service.queue.TbClusterService;
74 75 import org.thingsboard.server.service.state.DeviceStateService;
75 76
... ... @@ -92,7 +93,7 @@ public class DefaultTransportApiService implements TransportApiService {
92 93 //TODO: Constructor dependencies;
93 94 private final DeviceProfileService deviceProfileService;
94 95 private final TenantService tenantService;
95   - private final TenantProfileService tenantProfileService;
  96 + private final TbTenantProfileCache tenantProfileCache;
96 97 private final DeviceService deviceService;
97 98 private final RelationService relationService;
98 99 private final DeviceCredentialsService deviceCredentialsService;
... ... @@ -106,14 +107,14 @@ public class DefaultTransportApiService implements TransportApiService {
106 107 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
107 108
108 109 public DefaultTransportApiService(DeviceProfileService deviceProfileService, TenantService tenantService,
109   - TenantProfileService tenantProfileService, DeviceService deviceService,
  110 + TbTenantProfileCache tenantProfileCache, DeviceService deviceService,
110 111 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
111 112 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
112 113 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
113 114 DeviceProvisionService deviceProvisionService) {
114 115 this.deviceProfileService = deviceProfileService;
115 116 this.tenantService = tenantService;
116   - this.tenantProfileService = tenantProfileService;
  117 + this.tenantProfileCache = tenantProfileCache;
117 118 this.deviceService = deviceService;
118 119 this.relationService = relationService;
119 120 this.deviceCredentialsService = deviceCredentialsService;
... ... @@ -321,10 +322,8 @@ public class DefaultTransportApiService implements TransportApiService {
321 322
322 323 private ListenableFuture<TransportApiResponseMsg> handle(GetTenantRoutingInfoRequestMsg requestMsg) {
323 324 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
324   - // TODO: Tenant Profile from cache
325   - ListenableFuture<TenantProfile> tenantProfileFuture =
326   - Futures.transform(tenantService.findTenantByIdAsync(TenantId.SYS_TENANT_ID, tenantId), tenant ->
327   - tenantProfileService.findTenantProfileById(TenantId.SYS_TENANT_ID, tenant.getTenantProfileId()), dbCallbackExecutorService);
  325 +
  326 + ListenableFuture<TenantProfile> tenantProfileFuture = Futures.immediateFuture(tenantProfileCache.get(tenantId));
328 327 return Futures.transform(tenantProfileFuture, tenantProfile -> TransportApiResponseMsg.newBuilder()
329 328 .setGetTenantRoutingInfoResponseMsg(GetTenantRoutingInfoResponseMsg.newBuilder().setIsolatedTbCore(tenantProfile.isIsolatedTbCore())
330 329 .setIsolatedTbRuleEngine(tenantProfile.isIsolatedTbRuleEngine()).build()).build(), dbCallbackExecutorService);
... ...