Commit 974bfd39a5e061b29b8ca196d433a96fe222a24a
1 parent
c13308b1
Update EntityView - copy latest timeseries, delete previous attributes, latest t…
…imeseries on entity view update
Showing
7 changed files
with
277 additions
and
9 deletions
... | ... | @@ -19,7 +19,9 @@ import com.google.common.util.concurrent.FutureCallback; |
19 | 19 | import com.google.common.util.concurrent.Futures; |
20 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | 21 | import com.google.common.util.concurrent.MoreExecutors; |
22 | +import com.google.common.util.concurrent.SettableFuture; | |
22 | 23 | import lombok.extern.slf4j.Slf4j; |
24 | +import org.springframework.beans.factory.annotation.Autowired; | |
23 | 25 | import org.springframework.http.HttpStatus; |
24 | 26 | import org.springframework.security.access.prepost.PreAuthorize; |
25 | 27 | import org.springframework.web.bind.annotation.PathVariable; |
... | ... | @@ -40,10 +42,14 @@ import org.thingsboard.server.common.data.id.EntityViewId; |
40 | 42 | import org.thingsboard.server.common.data.id.TenantId; |
41 | 43 | import org.thingsboard.server.common.data.id.UUIDBased; |
42 | 44 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
45 | +import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; | |
46 | +import org.thingsboard.server.common.data.kv.ReadTsKvQuery; | |
47 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | |
43 | 48 | import org.thingsboard.server.common.data.page.PageData; |
44 | 49 | import org.thingsboard.server.common.data.page.PageLink; |
45 | 50 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
46 | 51 | import org.thingsboard.server.dao.model.ModelConstants; |
52 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
47 | 53 | import org.thingsboard.server.queue.util.TbCoreComponent; |
48 | 54 | import org.thingsboard.server.service.security.model.SecurityUser; |
49 | 55 | import org.thingsboard.server.service.security.permission.Operation; |
... | ... | @@ -69,6 +75,9 @@ public class EntityViewController extends BaseController { |
69 | 75 | |
70 | 76 | public static final String ENTITY_VIEW_ID = "entityViewId"; |
71 | 77 | |
78 | + @Autowired | |
79 | + private TimeseriesService tsService; | |
80 | + | |
72 | 81 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
73 | 82 | @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) |
74 | 83 | @ResponseBody |
... | ... | @@ -101,16 +110,37 @@ public class EntityViewController extends BaseController { |
101 | 110 | try { |
102 | 111 | entityView.setTenantId(getCurrentUser().getTenantId()); |
103 | 112 | |
104 | - checkEntity(entityView.getId(), entityView, Resource.ENTITY_VIEW); | |
113 | + List<ListenableFuture<?>> futures = new ArrayList<>(); | |
114 | + | |
115 | + if (entityView.getId() == null) { | |
116 | + accessControlService | |
117 | + .checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.CREATE, null, entityView); | |
118 | + } else { | |
119 | + EntityView existingEntityView = checkNotNull(entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityView.getId())); | |
120 | + if (existingEntityView.getKeys() != null) { | |
121 | + if (existingEntityView.getKeys().getAttributes() != null) { | |
122 | + futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.CLIENT_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
123 | + futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.SERVER_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
124 | + futures.add(deleteAttributesFromEntityView(existingEntityView, DataConstants.SHARED_SCOPE, existingEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
125 | + } | |
126 | + if (existingEntityView.getKeys().getTimeseries() != null && !existingEntityView.getKeys().getTimeseries().isEmpty()) { | |
127 | + futures.add(deleteLatestFromEntityView(existingEntityView, existingEntityView.getKeys().getTimeseries(), getCurrentUser())); | |
128 | + } | |
129 | + } | |
130 | + } | |
105 | 131 | |
106 | 132 | EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); |
107 | - List<ListenableFuture<List<Void>>> futures = new ArrayList<>(); | |
108 | - if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) { | |
109 | - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
110 | - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser())); | |
111 | - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser())); | |
133 | + if (savedEntityView.getKeys() != null) { | |
134 | + if (savedEntityView.getKeys().getAttributes() != null) { | |
135 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
136 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser())); | |
137 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser())); | |
138 | + } | |
139 | + if (savedEntityView.getKeys().getTimeseries() != null && !savedEntityView.getKeys().getTimeseries().isEmpty()) { | |
140 | + futures.add(copyLatestFromEntityToEntityView(savedEntityView, getCurrentUser())); | |
141 | + } | |
112 | 142 | } |
113 | - for (ListenableFuture<List<Void>> future : futures) { | |
143 | + for (ListenableFuture<?> future : futures) { | |
114 | 144 | try { |
115 | 145 | future.get(); |
116 | 146 | } catch (InterruptedException | ExecutionException e) { |
... | ... | @@ -128,6 +158,98 @@ public class EntityViewController extends BaseController { |
128 | 158 | } |
129 | 159 | } |
130 | 160 | |
161 | + private ListenableFuture<Void> deleteLatestFromEntityView(EntityView entityView, List<String> keys, SecurityUser user) { | |
162 | + EntityViewId entityId = entityView.getId(); | |
163 | + SettableFuture<Void> resultFuture = SettableFuture.create(); | |
164 | + if (keys != null && !keys.isEmpty()) { | |
165 | + tsSubService.deleteLatest(entityView.getTenantId(), entityId, keys, new FutureCallback<Void>() { | |
166 | + @Override | |
167 | + public void onSuccess(@Nullable Void tmp) { | |
168 | + try { | |
169 | + logTimeseriesDeleted(user, entityId, keys, null); | |
170 | + } catch (ThingsboardException e) { | |
171 | + log.error("Failed to log timeseries delete", e); | |
172 | + } | |
173 | + resultFuture.set(tmp); | |
174 | + } | |
175 | + | |
176 | + @Override | |
177 | + public void onFailure(Throwable t) { | |
178 | + try { | |
179 | + logTimeseriesDeleted(user, entityId, keys, t); | |
180 | + } catch (ThingsboardException e) { | |
181 | + log.error("Failed to log timeseries delete", e); | |
182 | + } | |
183 | + resultFuture.setException(t); | |
184 | + } | |
185 | + }); | |
186 | + } else { | |
187 | + resultFuture.set(null); | |
188 | + } | |
189 | + return resultFuture; | |
190 | + } | |
191 | + | |
192 | + private ListenableFuture<Void> deleteAttributesFromEntityView(EntityView entityView, String scope, List<String> keys, SecurityUser user) { | |
193 | + EntityViewId entityId = entityView.getId(); | |
194 | + SettableFuture<Void> resultFuture = SettableFuture.create(); | |
195 | + if (keys != null && !keys.isEmpty()) { | |
196 | + tsSubService.deleteAndNotify(entityView.getTenantId(), entityId, scope, keys, new FutureCallback<Void>() { | |
197 | + @Override | |
198 | + public void onSuccess(@Nullable Void tmp) { | |
199 | + try { | |
200 | + logAttributesDeleted(user, entityId, scope, keys, null); | |
201 | + } catch (ThingsboardException e) { | |
202 | + log.error("Failed to log attribute delete", e); | |
203 | + } | |
204 | + resultFuture.set(tmp); | |
205 | + } | |
206 | + | |
207 | + @Override | |
208 | + public void onFailure(Throwable t) { | |
209 | + try { | |
210 | + logAttributesDeleted(user, entityId, scope, keys, t); | |
211 | + } catch (ThingsboardException e) { | |
212 | + log.error("Failed to log attribute delete", e); | |
213 | + } | |
214 | + resultFuture.setException(t); | |
215 | + } | |
216 | + }); | |
217 | + } else { | |
218 | + resultFuture.set(null); | |
219 | + } | |
220 | + return resultFuture; | |
221 | + } | |
222 | + | |
223 | + private ListenableFuture<List<Void>> copyLatestFromEntityToEntityView(EntityView entityView, SecurityUser user) { | |
224 | + EntityViewId entityId = entityView.getId(); | |
225 | + List<String> keys = entityView.getKeys().getTimeseries(); | |
226 | + long startTime = entityView.getStartTimeMs(); | |
227 | + long endTime = entityView.getEndTimeMs(); | |
228 | + ListenableFuture<List<TsKvEntry>> latestFuture; | |
229 | + if (startTime == 0 && endTime == 0) { | |
230 | + latestFuture = tsService.findLatest(user.getTenantId(), entityView.getEntityId(), keys); | |
231 | + } else { | |
232 | + long startTs = startTime; | |
233 | + long endTs = endTime == 0 ? System.currentTimeMillis() : endTime; | |
234 | + List<ReadTsKvQuery> queries = keys.stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, 1, "DESC")).collect(Collectors.toList()); | |
235 | + latestFuture = tsService.findAll(user.getTenantId(), entityView.getEntityId(), queries); | |
236 | + } | |
237 | + return Futures.transform(latestFuture, latestValues -> { | |
238 | + if (latestValues != null && !latestValues.isEmpty()) { | |
239 | + tsSubService.saveLatestAndNotify(entityView.getTenantId(), entityId, latestValues, new FutureCallback<Void>() { | |
240 | + @Override | |
241 | + public void onSuccess(@Nullable Void tmp) { | |
242 | + } | |
243 | + | |
244 | + @Override | |
245 | + public void onFailure(Throwable t) { | |
246 | + } | |
247 | + }); | |
248 | + } | |
249 | + return null; | |
250 | + }, MoreExecutors.directExecutor()); | |
251 | + } | |
252 | + | |
131 | 253 | private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException { |
132 | 254 | EntityViewId entityId = entityView.getId(); |
133 | 255 | if (keys != null && !keys.isEmpty()) { |
... | ... | @@ -174,10 +296,20 @@ public class EntityViewController extends BaseController { |
174 | 296 | } |
175 | 297 | |
176 | 298 | private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException { |
177 | - logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e), | |
299 | + logEntityAction(user, entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e), | |
178 | 300 | scope, attributes); |
179 | 301 | } |
180 | 302 | |
303 | + private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) throws ThingsboardException { | |
304 | + logEntityAction(user, entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e), | |
305 | + scope, keys); | |
306 | + } | |
307 | + | |
308 | + private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, Throwable e) throws ThingsboardException { | |
309 | + logEntityAction(user, entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e), | |
310 | + keys); | |
311 | + } | |
312 | + | |
181 | 313 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
182 | 314 | @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) |
183 | 315 | @ResponseStatus(value = HttpStatus.OK) | ... | ... |
... | ... | @@ -171,6 +171,7 @@ public class ThingsboardInstallService { |
171 | 171 | case "3.0.1": |
172 | 172 | log.info("Upgrading ThingsBoard from version 3.0.1 to 3.1.0 ..."); |
173 | 173 | databaseEntitiesUpgradeService.upgradeDatabase("3.0.1"); |
174 | + dataUpdateService.updateData("3.0.1"); | |
174 | 175 | log.info("Updating system data..."); |
175 | 176 | systemDataLoaderService.updateSystemWidgets(); |
176 | 177 | break; | ... | ... |
... | ... | @@ -15,20 +15,38 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.install.update; |
17 | 17 | |
18 | +import com.google.common.util.concurrent.FutureCallback; | |
19 | +import com.google.common.util.concurrent.Futures; | |
20 | +import com.google.common.util.concurrent.ListenableFuture; | |
21 | +import com.google.common.util.concurrent.MoreExecutors; | |
18 | 22 | import lombok.extern.slf4j.Slf4j; |
19 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 24 | import org.springframework.context.annotation.Profile; |
21 | 25 | import org.springframework.stereotype.Service; |
26 | +import org.thingsboard.server.common.data.EntityView; | |
22 | 27 | import org.thingsboard.server.common.data.SearchTextBased; |
23 | 28 | import org.thingsboard.server.common.data.Tenant; |
29 | +import org.thingsboard.server.common.data.id.EntityViewId; | |
30 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | 31 | import org.thingsboard.server.common.data.id.UUIDBased; |
32 | +import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; | |
33 | +import org.thingsboard.server.common.data.kv.ReadTsKvQuery; | |
34 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | |
25 | 35 | import org.thingsboard.server.common.data.page.PageData; |
26 | 36 | import org.thingsboard.server.common.data.page.PageLink; |
27 | 37 | import org.thingsboard.server.common.data.rule.RuleChain; |
38 | +import org.thingsboard.server.dao.entityview.EntityViewService; | |
28 | 39 | import org.thingsboard.server.dao.rule.RuleChainService; |
29 | 40 | import org.thingsboard.server.dao.tenant.TenantService; |
41 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
30 | 42 | import org.thingsboard.server.service.install.InstallScripts; |
31 | 43 | |
44 | +import javax.annotation.Nullable; | |
45 | +import java.util.ArrayList; | |
46 | +import java.util.List; | |
47 | +import java.util.concurrent.ExecutionException; | |
48 | +import java.util.stream.Collectors; | |
49 | + | |
32 | 50 | @Service |
33 | 51 | @Profile("install") |
34 | 52 | @Slf4j |
... | ... | @@ -43,6 +61,12 @@ public class DefaultDataUpdateService implements DataUpdateService { |
43 | 61 | @Autowired |
44 | 62 | private InstallScripts installScripts; |
45 | 63 | |
64 | + @Autowired | |
65 | + private EntityViewService entityViewService; | |
66 | + | |
67 | + @Autowired | |
68 | + private TimeseriesService tsService; | |
69 | + | |
46 | 70 | @Override |
47 | 71 | public void updateData(String fromVersion) throws Exception { |
48 | 72 | switch (fromVersion) { |
... | ... | @@ -50,6 +74,10 @@ public class DefaultDataUpdateService implements DataUpdateService { |
50 | 74 | log.info("Updating data from version 1.4.0 to 2.0.0 ..."); |
51 | 75 | tenantsDefaultRuleChainUpdater.updateEntities(null); |
52 | 76 | break; |
77 | + case "3.0.1": | |
78 | + log.info("Updating data from version 3.0.1 to 3.1.0 ..."); | |
79 | + tenantsEntityViewsUpdater.updateEntities(null); | |
80 | + break; | |
53 | 81 | default: |
54 | 82 | throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); |
55 | 83 | } |
... | ... | @@ -76,4 +104,66 @@ public class DefaultDataUpdateService implements DataUpdateService { |
76 | 104 | } |
77 | 105 | }; |
78 | 106 | |
79 | -} | |
\ No newline at end of file | ||
107 | + private PaginatedUpdater<String, Tenant> tenantsEntityViewsUpdater = | |
108 | + new PaginatedUpdater<String, Tenant>() { | |
109 | + | |
110 | + @Override | |
111 | + protected PageData<Tenant> findEntities(String region, PageLink pageLink) { | |
112 | + return tenantService.findTenants(pageLink); | |
113 | + } | |
114 | + | |
115 | + @Override | |
116 | + protected void updateEntity(Tenant tenant) { | |
117 | + updateTenantEntityViews(tenant.getId()); | |
118 | + } | |
119 | + }; | |
120 | + | |
121 | + private void updateTenantEntityViews(TenantId tenantId) { | |
122 | + PageLink pageLink = new PageLink(100); | |
123 | + PageData<EntityView> pageData = entityViewService.findEntityViewByTenantId(tenantId, pageLink); | |
124 | + boolean hasNext = true; | |
125 | + while (hasNext) { | |
126 | + List<ListenableFuture<List<Void>>> updateFutures = new ArrayList<>(); | |
127 | + for (EntityView entityView : pageData.getData()) { | |
128 | + updateFutures.add(updateEntityViewLatestTelemetry(entityView)); | |
129 | + } | |
130 | + | |
131 | + try { | |
132 | + Futures.allAsList(updateFutures).get(); | |
133 | + } catch (InterruptedException | ExecutionException e) { | |
134 | + log.error("Failed to copy latest telemetry to entity view", e); | |
135 | + } | |
136 | + | |
137 | + if (pageData.hasNext()) { | |
138 | + pageLink = pageLink.nextPageLink(); | |
139 | + pageData = entityViewService.findEntityViewByTenantId(tenantId, pageLink); | |
140 | + } else { | |
141 | + hasNext = false; | |
142 | + } | |
143 | + } | |
144 | + } | |
145 | + | |
146 | + private ListenableFuture<List<Void>> updateEntityViewLatestTelemetry(EntityView entityView) { | |
147 | + EntityViewId entityId = entityView.getId(); | |
148 | + List<String> keys = entityView.getKeys().getTimeseries(); | |
149 | + long startTime = entityView.getStartTimeMs(); | |
150 | + long endTime = entityView.getEndTimeMs(); | |
151 | + ListenableFuture<List<TsKvEntry>> latestFuture; | |
152 | + if (startTime == 0 && endTime == 0) { | |
153 | + latestFuture = tsService.findLatest(TenantId.SYS_TENANT_ID, entityView.getEntityId(), keys); | |
154 | + } else { | |
155 | + long startTs = startTime; | |
156 | + long endTs = endTime == 0 ? System.currentTimeMillis() : endTime; | |
157 | + List<ReadTsKvQuery> queries = keys.stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, 1, "DESC")).collect(Collectors.toList()); | |
158 | + latestFuture = tsService.findAll(TenantId.SYS_TENANT_ID, entityView.getEntityId(), queries); | |
159 | + } | |
160 | + return Futures.transformAsync(latestFuture, latestValues -> { | |
161 | + if (latestValues != null && !latestValues.isEmpty()) { | |
162 | + ListenableFuture<List<Void>> saveFuture = tsService.saveLatest(TenantId.SYS_TENANT_ID, entityId, latestValues); | |
163 | + return saveFuture; | |
164 | + } | |
165 | + return null; | |
166 | + }, MoreExecutors.directExecutor()); | |
167 | + } | |
168 | + | |
169 | +} | ... | ... |
... | ... | @@ -116,6 +116,13 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer |
116 | 116 | } |
117 | 117 | |
118 | 118 | @Override |
119 | + public void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback) { | |
120 | + ListenableFuture<List<Void>> saveFuture = tsService.saveLatest(tenantId, entityId, ts); | |
121 | + addMainCallback(saveFuture, callback); | |
122 | + addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, ts)); | |
123 | + } | |
124 | + | |
125 | + @Override | |
119 | 126 | public void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List<String> keys, FutureCallback<Void> callback) { |
120 | 127 | ListenableFuture<List<Void>> deleteFuture = attrService.removeAll(tenantId, entityId, scope, keys); |
121 | 128 | addMainCallback(deleteFuture, callback); |
... | ... | @@ -123,6 +130,12 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer |
123 | 130 | } |
124 | 131 | |
125 | 132 | @Override |
133 | + public void deleteLatest(TenantId tenantId, EntityId entityId, List<String> keys, FutureCallback<Void> callback) { | |
134 | + ListenableFuture<List<Void>> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); | |
135 | + addMainCallback(deleteFuture, callback); | |
136 | + } | |
137 | + | |
138 | + @Override | |
126 | 139 | public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback<Void> callback) { |
127 | 140 | saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value) |
128 | 141 | , System.currentTimeMillis())), callback); | ... | ... |
... | ... | @@ -40,5 +40,9 @@ public interface TimeseriesService { |
40 | 40 | |
41 | 41 | ListenableFuture<List<Void>> save(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntry, long ttl); |
42 | 42 | |
43 | + ListenableFuture<List<Void>> saveLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntry); | |
44 | + | |
43 | 45 | ListenableFuture<List<Void>> remove(TenantId tenantId, EntityId entityId, List<DeleteTsKvQuery> queries); |
46 | + | |
47 | + ListenableFuture<List<Void>> removeLatest(TenantId tenantId, EntityId entityId, Collection<String> keys); | |
44 | 48 | } | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.EntityId; |
28 | 28 | import org.thingsboard.server.common.data.id.EntityViewId; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 30 | import org.thingsboard.server.common.data.kv.Aggregation; |
31 | +import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; | |
31 | 32 | import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; |
32 | 33 | import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; |
33 | 34 | import org.thingsboard.server.common.data.kv.ReadTsKvQuery; |
... | ... | @@ -149,6 +150,18 @@ public class BaseTimeseriesService implements TimeseriesService { |
149 | 150 | return Futures.allAsList(futures); |
150 | 151 | } |
151 | 152 | |
153 | + @Override | |
154 | + public ListenableFuture<List<Void>> saveLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries) { | |
155 | + List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(tsKvEntries.size()); | |
156 | + for (TsKvEntry tsKvEntry : tsKvEntries) { | |
157 | + if (tsKvEntry == null) { | |
158 | + throw new IncorrectParameterException("Key value entry can't be null"); | |
159 | + } | |
160 | + futures.add(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry)); | |
161 | + } | |
162 | + return Futures.allAsList(futures); | |
163 | + } | |
164 | + | |
152 | 165 | private void saveAndRegisterFutures(TenantId tenantId, List<ListenableFuture<Void>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { |
153 | 166 | if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { |
154 | 167 | throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only"); |
... | ... | @@ -188,6 +201,17 @@ public class BaseTimeseriesService implements TimeseriesService { |
188 | 201 | return Futures.allAsList(futures); |
189 | 202 | } |
190 | 203 | |
204 | + @Override | |
205 | + public ListenableFuture<List<Void>> removeLatest(TenantId tenantId, EntityId entityId, Collection<String> keys) { | |
206 | + validate(entityId); | |
207 | + List<ListenableFuture<Void>> futures = Lists.newArrayListWithExpectedSize(keys.size()); | |
208 | + for (String key : keys) { | |
209 | + DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, 0, System.currentTimeMillis(), false); | |
210 | + futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); | |
211 | + } | |
212 | + return Futures.allAsList(futures); | |
213 | + } | |
214 | + | |
191 | 215 | private void deleteAndRegisterFutures(TenantId tenantId, List<ListenableFuture<Void>> futures, EntityId entityId, DeleteTsKvQuery query) { |
192 | 216 | futures.add(timeseriesDao.remove(tenantId, entityId, query)); |
193 | 217 | futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); | ... | ... |
... | ... | @@ -36,6 +36,8 @@ public interface RuleEngineTelemetryService { |
36 | 36 | |
37 | 37 | void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback); |
38 | 38 | |
39 | + void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback); | |
40 | + | |
39 | 41 | void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback<Void> callback); |
40 | 42 | |
41 | 43 | void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, String value, FutureCallback<Void> callback); |
... | ... | @@ -46,5 +48,7 @@ public interface RuleEngineTelemetryService { |
46 | 48 | |
47 | 49 | void deleteAndNotify(TenantId tenantId, EntityId entityId, String scope, List<String> keys, FutureCallback<Void> callback); |
48 | 50 | |
51 | + void deleteLatest(TenantId tenantId, EntityId entityId, List<String> keys, FutureCallback<Void> callback); | |
52 | + | |
49 | 53 | |
50 | 54 | } | ... | ... |