|
|
|
@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; |
|
|
|
import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; |
|
|
|
import org.thingsboard.server.common.data.kv.ReadTsKvQuery; |
|
|
|
import org.thingsboard.server.common.data.kv.ReadTsKvQueryResult; |
|
|
|
import org.thingsboard.server.common.data.kv.TimeseriesSaveResult; |
|
|
|
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|
|
|
import org.thingsboard.server.common.data.kv.TsKvLatestRemovingResult; |
|
|
|
import org.thingsboard.server.dao.entityview.EntityViewService; |
|
|
|
@ -156,60 +157,48 @@ public class BaseTimeseriesService implements TimeseriesService { |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { |
|
|
|
public ListenableFuture<TimeseriesSaveResult> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { |
|
|
|
validate(entityId); |
|
|
|
List<ListenableFuture<Integer>> futures = new ArrayList<>(INSERTS_PER_ENTRY); |
|
|
|
saveAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, 0L); |
|
|
|
return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); |
|
|
|
return doSave(tenantId, entityId, List.of(tsKvEntry), 0L, true, true); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public ListenableFuture<Integer> save(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) { |
|
|
|
return doSave(tenantId, entityId, tsKvEntries, ttl, true); |
|
|
|
public ListenableFuture<TimeseriesSaveResult> save(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) { |
|
|
|
return doSave(tenantId, entityId, tsKvEntries, ttl, true, true); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public ListenableFuture<Integer> saveWithoutLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) { |
|
|
|
return doSave(tenantId, entityId, tsKvEntries, ttl, false); |
|
|
|
} |
|
|
|
|
|
|
|
private ListenableFuture<Integer> doSave(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl, boolean saveLatest) { |
|
|
|
int inserts = saveLatest ? INSERTS_PER_ENTRY : INSERTS_PER_ENTRY_WITHOUT_LATEST; |
|
|
|
List<ListenableFuture<Integer>> futures = new ArrayList<>(tsKvEntries.size() * inserts); |
|
|
|
for (TsKvEntry tsKvEntry : tsKvEntries) { |
|
|
|
if (saveLatest) { |
|
|
|
saveAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); |
|
|
|
} else { |
|
|
|
saveWithoutLatestAndRegisterFutures(tenantId, futures, entityId, tsKvEntry, ttl); |
|
|
|
} |
|
|
|
} |
|
|
|
return Futures.transform(Futures.allAsList(futures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()); |
|
|
|
public ListenableFuture<TimeseriesSaveResult> saveWithoutLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl) { |
|
|
|
return doSave(tenantId, entityId, tsKvEntries, ttl, false, true); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public ListenableFuture<List<Long>> saveLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries) { |
|
|
|
List<ListenableFuture<Long>> futures = new ArrayList<>(tsKvEntries.size()); |
|
|
|
for (TsKvEntry tsKvEntry : tsKvEntries) { |
|
|
|
futures.add(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry)); |
|
|
|
} |
|
|
|
return Futures.allAsList(futures); |
|
|
|
public ListenableFuture<TimeseriesSaveResult> saveLatest(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries) { |
|
|
|
return doSave(tenantId, entityId, tsKvEntries, 0L, true, false); |
|
|
|
} |
|
|
|
|
|
|
|
private void saveAndRegisterFutures(TenantId tenantId, List<ListenableFuture<Integer>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { |
|
|
|
doSaveAndRegisterFuturesFor(tenantId, futures, entityId, tsKvEntry, ttl); |
|
|
|
futures.add(Futures.transform(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry), v -> 0, MoreExecutors.directExecutor())); |
|
|
|
} |
|
|
|
|
|
|
|
private void saveWithoutLatestAndRegisterFutures(TenantId tenantId, List<ListenableFuture<Integer>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { |
|
|
|
doSaveAndRegisterFuturesFor(tenantId, futures, entityId, tsKvEntry, ttl); |
|
|
|
} |
|
|
|
|
|
|
|
private void doSaveAndRegisterFuturesFor(TenantId tenantId, List<ListenableFuture<Integer>> futures, EntityId entityId, TsKvEntry tsKvEntry, long ttl) { |
|
|
|
if (entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { |
|
|
|
private ListenableFuture<TimeseriesSaveResult> doSave(TenantId tenantId, EntityId entityId, List<TsKvEntry> tsKvEntries, long ttl, boolean saveLatest, boolean saveTs) { |
|
|
|
if (saveTs && entityId.getEntityType().equals(EntityType.ENTITY_VIEW)) { |
|
|
|
throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only"); |
|
|
|
} |
|
|
|
futures.add(timeseriesDao.savePartition(tenantId, entityId, tsKvEntry.getTs(), tsKvEntry.getKey())); |
|
|
|
futures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl)); |
|
|
|
List<ListenableFuture<Integer>> tsFutures = saveTs ? new ArrayList<>(tsKvEntries.size() * INSERTS_PER_ENTRY_WITHOUT_LATEST) : null; |
|
|
|
List<ListenableFuture<Long>> latestFutures = saveLatest ? new ArrayList<>(tsKvEntries.size()) : null; |
|
|
|
for (TsKvEntry tsKvEntry : tsKvEntries) { |
|
|
|
if (saveTs) { |
|
|
|
tsFutures.add(timeseriesDao.savePartition(tenantId, entityId, tsKvEntry.getTs(), tsKvEntry.getKey())); |
|
|
|
tsFutures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl)); |
|
|
|
} |
|
|
|
if (saveLatest) { |
|
|
|
latestFutures.add(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry)); |
|
|
|
} |
|
|
|
} |
|
|
|
ListenableFuture<Integer> dpsFuture = saveTs ? Futures.transform(Futures.allAsList(tsFutures), SUM_ALL_INTEGERS, MoreExecutors.directExecutor()) : Futures.immediateFuture(0); |
|
|
|
ListenableFuture<List<Long>> versionsFuture = saveLatest ? Futures.allAsList(latestFutures) : Futures.immediateFuture(null); |
|
|
|
return Futures.whenAllComplete(dpsFuture, versionsFuture).call(() -> { |
|
|
|
Integer dataPoints = Futures.getUnchecked(dpsFuture); |
|
|
|
List<Long> versions = Futures.getUnchecked(versionsFuture); |
|
|
|
return TimeseriesSaveResult.of(dataPoints, versions); |
|
|
|
}, MoreExecutors.directExecutor()); |
|
|
|
} |
|
|
|
|
|
|
|
private List<ReadTsKvQuery> updateQueriesForEntityView(EntityView entityView, List<ReadTsKvQuery> queries) { |
|
|
|
|