Commit 02db986546d0f4c87addac63837843e4ba78504a

Authored by Yevhen Bondarenko
Committed by GitHub
1 parent 9e331a17

Feature/separate ts (#3190)

* created annotations for ts latest and created LatestDatabaseSchemaService for cassandra, hsql, psql, timescale

* created ts latest dao

* fixed tests and refactored

* refactored

* refactored

* created latest dao configs

* fix SqlTimeseriesDaoConfig

* refactoring, and deleted annotation @SqlDao

* refactoring

* created migration script for ts latest

* refactoring

Co-authored-by: Andrew Shvayka <ashvayka@thingsboard.io>
Showing 116 changed files with 1623 additions and 1039 deletions
... ... @@ -28,7 +28,9 @@ import org.thingsboard.server.service.install.DatabaseTsUpgradeService;
28 28 import org.thingsboard.server.service.install.EntityDatabaseSchemaService;
29 29 import org.thingsboard.server.service.install.SystemDataLoaderService;
30 30 import org.thingsboard.server.service.install.TsDatabaseSchemaService;
  31 +import org.thingsboard.server.service.install.TsLatestDatabaseSchemaService;
31 32 import org.thingsboard.server.service.install.migrate.EntitiesMigrateService;
  33 +import org.thingsboard.server.service.install.migrate.TsLatestMigrateService;
32 34 import org.thingsboard.server.service.install.update.DataUpdateService;
33 35
34 36 @Service
... ... @@ -51,6 +53,9 @@ public class ThingsboardInstallService {
51 53 @Autowired
52 54 private TsDatabaseSchemaService tsDatabaseSchemaService;
53 55
  56 + @Autowired(required = false)
  57 + private TsLatestDatabaseSchemaService tsLatestDatabaseSchemaService;
  58 +
54 59 @Autowired
55 60 private DatabaseEntitiesUpgradeService databaseEntitiesUpgradeService;
56 61
... ... @@ -72,6 +77,9 @@ public class ThingsboardInstallService {
72 77 @Autowired(required = false)
73 78 private EntitiesMigrateService entitiesMigrateService;
74 79
  80 + @Autowired(required = false)
  81 + private TsLatestMigrateService latestMigrateService;
  82 +
75 83 public void performInstall() {
76 84 try {
77 85 if (isUpgrade) {
... ... @@ -82,6 +90,10 @@ public class ThingsboardInstallService {
82 90 entitiesMigrateService.migrate();
83 91 log.info("Updating system data...");
84 92 systemDataLoaderService.updateSystemWidgets();
  93 + } else if ("3.0.1-cassandra".equals(upgradeFromVersion)) {
  94 + log.info("Migrating ThingsBoard latest timeseries data from cassandra to SQL database ...");
  95 + latestMigrateService.migrate();
  96 + log.info("Updating system data...");
85 97 } else {
86 98 switch (upgradeFromVersion) {
87 99 case "1.2.3": //NOSONAR, Need to execute gradual upgrade starting from upgradeFromVersion
... ... @@ -181,6 +193,10 @@ public class ThingsboardInstallService {
181 193
182 194 tsDatabaseSchemaService.createDatabaseSchema();
183 195
  196 + if (tsLatestDatabaseSchemaService != null) {
  197 + tsLatestDatabaseSchemaService.createDatabaseSchema();
  198 + }
  199 +
184 200 log.info("Loading system data...");
185 201
186 202 componentDiscoveryService.discoverComponents();
... ...
  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.install;
  17 +
  18 +import org.springframework.context.annotation.Profile;
  19 +import org.springframework.stereotype.Service;
  20 +import org.thingsboard.server.dao.util.NoSqlTsLatestDao;
  21 +
  22 +@Service
  23 +@NoSqlTsLatestDao
  24 +@Profile("install")
  25 +public class CassandraTsLatestDatabaseSchemaService extends CassandraAbstractDatabaseSchemaService
  26 + implements TsLatestDatabaseSchemaService {
  27 + public CassandraTsLatestDatabaseSchemaService() {
  28 + super("schema-ts-latest.cql");
  29 + }
  30 +}
... ...
... ... @@ -18,11 +18,9 @@ package org.thingsboard.server.service.install;
18 18 import org.springframework.context.annotation.Profile;
19 19 import org.springframework.stereotype.Service;
20 20 import org.thingsboard.server.dao.util.HsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23 22 @Service
24 23 @HsqlDao
25   -@SqlDao
26 24 @Profile("install")
27 25 public class HsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService
28 26 implements EntityDatabaseSchemaService {
... ...
... ... @@ -18,10 +18,8 @@ package org.thingsboard.server.service.install;
18 18 import org.springframework.context.annotation.Profile;
19 19 import org.springframework.stereotype.Service;
20 20 import org.thingsboard.server.dao.util.PsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23 22 @Service
24   -@SqlDao
25 23 @PsqlDao
26 24 @Profile("install")
27 25 public class PsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService
... ...
... ... @@ -21,7 +21,6 @@ import org.springframework.beans.factory.annotation.Value;
21 21 import org.springframework.context.annotation.Profile;
22 22 import org.springframework.stereotype.Service;
23 23 import org.thingsboard.server.dao.dashboard.DashboardService;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24 import org.thingsboard.server.service.install.sql.SqlDbHelper;
26 25
27 26 import java.nio.charset.Charset;
... ... @@ -58,7 +57,6 @@ import static org.thingsboard.server.service.install.DatabaseHelper.TYPE;
58 57 @Service
59 58 @Profile("install")
60 59 @Slf4j
61   -@SqlDao
62 60 public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService {
63 61
64 62 private static final String SCHEMA_UPDATE_SQL = "schema_update.sql";
... ...
  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.install;
  17 +
  18 +public interface TsLatestDatabaseSchemaService extends DatabaseSchemaService {
  19 +}
... ...
... ... @@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.EntityType;
24 24 import org.thingsboard.server.common.data.UUIDConverter;
25 25 import org.thingsboard.server.dao.cassandra.CassandraCluster;
26 26 import org.thingsboard.server.dao.util.NoSqlAnyDao;
27   -import org.thingsboard.server.dao.util.SqlDao;
28 27 import org.thingsboard.server.service.install.EntityDatabaseSchemaService;
29 28
30 29 import java.sql.Connection;
... ... @@ -42,7 +41,6 @@ import static org.thingsboard.server.service.install.migrate.CassandraToSqlColum
42 41
43 42 @Service
44 43 @Profile("install")
45   -@SqlDao
46 44 @NoSqlAnyDao
47 45 @Slf4j
48 46 public class CassandraEntitiesToSqlMigrateService implements EntitiesMigrateService {
... ...
... ... @@ -128,7 +128,7 @@ public class CassandraToSqlTable {
128 128 return this.validateColumnData(data);
129 129 }
130 130
131   - private CassandraToSqlColumnData[] validateColumnData(CassandraToSqlColumnData[] data) {
  131 + protected CassandraToSqlColumnData[] validateColumnData(CassandraToSqlColumnData[] data) {
132 132 for (int i=0;i<data.length;i++) {
133 133 CassandraToSqlColumn column = this.columns.get(i);
134 134 if (column.getType() == CassandraToSqlColumnType.STRING) {
... ... @@ -148,7 +148,7 @@ public class CassandraToSqlTable {
148 148 return data;
149 149 }
150 150
151   - private void batchInsert(List<CassandraToSqlColumnData[]> batchData, Connection conn) throws SQLException {
  151 + protected void batchInsert(List<CassandraToSqlColumnData[]> batchData, Connection conn) throws SQLException {
152 152 boolean retry = false;
153 153 for (CassandraToSqlColumnData[] data : batchData) {
154 154 for (CassandraToSqlColumn column: this.columns) {
... ... @@ -269,7 +269,7 @@ public class CassandraToSqlTable {
269 269 return Optional.empty();
270 270 }
271 271
272   - private Statement createCassandraSelectStatement() {
  272 + protected Statement createCassandraSelectStatement() {
273 273 StringBuilder selectStatementBuilder = new StringBuilder();
274 274 selectStatementBuilder.append("SELECT ");
275 275 for (CassandraToSqlColumn column : columns) {
... ...
  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.install.migrate;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.hibernate.exception.ConstraintViolationException;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.beans.factory.annotation.Value;
  23 +import org.springframework.context.annotation.Profile;
  24 +import org.springframework.stereotype.Service;
  25 +import org.thingsboard.server.common.data.UUIDConverter;
  26 +import org.thingsboard.server.dao.cassandra.CassandraCluster;
  27 +import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionary;
  28 +import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionaryCompositeKey;
  29 +import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
  30 +import org.thingsboard.server.dao.sqlts.dictionary.TsKvDictionaryRepository;
  31 +import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository;
  32 +import org.thingsboard.server.dao.util.NoSqlAnyDao;
  33 +import org.thingsboard.server.service.install.EntityDatabaseSchemaService;
  34 +
  35 +import java.sql.Connection;
  36 +import java.sql.DriverManager;
  37 +import java.util.Arrays;
  38 +import java.util.List;
  39 +import java.util.Optional;
  40 +import java.util.concurrent.ConcurrentHashMap;
  41 +import java.util.concurrent.ConcurrentMap;
  42 +import java.util.concurrent.locks.ReentrantLock;
  43 +import java.util.stream.Collectors;
  44 +
  45 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.bigintColumn;
  46 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.booleanColumn;
  47 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.doubleColumn;
  48 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.idColumn;
  49 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.jsonColumn;
  50 +import static org.thingsboard.server.service.install.migrate.CassandraToSqlColumn.stringColumn;
  51 +
  52 +@Service
  53 +@Profile("install")
  54 +@NoSqlAnyDao
  55 +@Slf4j
  56 +public class CassandraTsLatestToSqlMigrateService implements TsLatestMigrateService {
  57 +
  58 + @Autowired
  59 + private EntityDatabaseSchemaService entityDatabaseSchemaService;
  60 +
  61 + @Autowired
  62 + private InsertLatestTsRepository insertLatestTsRepository;
  63 +
  64 + @Autowired
  65 + protected CassandraCluster cluster;
  66 +
  67 + @Autowired
  68 + protected TsKvDictionaryRepository dictionaryRepository;
  69 +
  70 + @Value("${spring.datasource.url}")
  71 + protected String dbUrl;
  72 +
  73 + @Value("${spring.datasource.username}")
  74 + protected String dbUserName;
  75 +
  76 + @Value("${spring.datasource.password}")
  77 + protected String dbPassword;
  78 +
  79 + private final ConcurrentMap<String, Integer> tsKvDictionaryMap = new ConcurrentHashMap<>();
  80 +
  81 + protected static final ReentrantLock tsCreationLock = new ReentrantLock();
  82 +
  83 + @Override
  84 + public void migrate() throws Exception {
  85 + log.info("Performing migration of latest timeseries data from cassandra to SQL database ...");
  86 + entityDatabaseSchemaService.createDatabaseSchema(false);
  87 + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
  88 + conn.setAutoCommit(false);
  89 + for (CassandraToSqlTable table : tables) {
  90 + table.migrateToSql(cluster.getSession(), conn);
  91 + }
  92 + } catch (Exception e) {
  93 + log.error("Unexpected error during ThingsBoard entities data migration!", e);
  94 + throw e;
  95 + }
  96 + entityDatabaseSchemaService.createDatabaseIndexes();
  97 + }
  98 +
  99 + private List<CassandraToSqlTable> tables = Arrays.asList(
  100 + new CassandraToSqlTable("ts_kv_latest_cf",
  101 + idColumn("entity_id"),
  102 + stringColumn("key"),
  103 + bigintColumn("ts"),
  104 + booleanColumn("bool_v"),
  105 + stringColumn("str_v"),
  106 + bigintColumn("long_v"),
  107 + doubleColumn("dbl_v"),
  108 + jsonColumn("json_v")) {
  109 +
  110 + @Override
  111 + protected void batchInsert(List<CassandraToSqlColumnData[]> batchData, Connection conn) {
  112 + insertLatestTsRepository
  113 + .saveOrUpdate(batchData.stream().map(data -> getTsKvLatestEntity(data)).collect(Collectors.toList()));
  114 + }
  115 +
  116 + @Override
  117 + protected CassandraToSqlColumnData[] validateColumnData(CassandraToSqlColumnData[] data) {
  118 + return data;
  119 + }
  120 + });
  121 +
  122 + private TsKvLatestEntity getTsKvLatestEntity(CassandraToSqlColumnData[] data) {
  123 + TsKvLatestEntity latestEntity = new TsKvLatestEntity();
  124 + latestEntity.setEntityId(UUIDConverter.fromString(data[0].getValue()));
  125 + latestEntity.setKey(getOrSaveKeyId(data[1].getValue()));
  126 + latestEntity.setTs(Long.parseLong(data[2].getValue()));
  127 +
  128 + String strV = data[4].getValue();
  129 + if (strV != null) {
  130 + latestEntity.setStrValue(strV);
  131 + } else {
  132 + Long longV = null;
  133 + try {
  134 + longV = Long.parseLong(data[5].getValue());
  135 + } catch (Exception e) {
  136 + }
  137 + if (longV != null) {
  138 + latestEntity.setLongValue(longV);
  139 + } else {
  140 + Double doubleV = null;
  141 + try {
  142 + doubleV = Double.parseDouble(data[6].getValue());
  143 + } catch (Exception e) {
  144 + }
  145 + if (doubleV != null) {
  146 + latestEntity.setDoubleValue(doubleV);
  147 + } else {
  148 +
  149 + String jsonV = data[7].getValue();
  150 + if (StringUtils.isNoneEmpty(jsonV)) {
  151 + latestEntity.setJsonValue(jsonV);
  152 + } else {
  153 + Boolean boolV = null;
  154 + try {
  155 + boolV = Boolean.parseBoolean(data[3].getValue());
  156 + } catch (Exception e) {
  157 + }
  158 + if (boolV != null) {
  159 + latestEntity.setBooleanValue(boolV);
  160 + } else {
  161 + log.warn("All values in key-value row are nullable ");
  162 + }
  163 + }
  164 + }
  165 + }
  166 + }
  167 + return latestEntity;
  168 + }
  169 +
  170 + protected Integer getOrSaveKeyId(String strKey) {
  171 + Integer keyId = tsKvDictionaryMap.get(strKey);
  172 + if (keyId == null) {
  173 + Optional<TsKvDictionary> tsKvDictionaryOptional;
  174 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  175 + if (!tsKvDictionaryOptional.isPresent()) {
  176 + tsCreationLock.lock();
  177 + try {
  178 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  179 + if (!tsKvDictionaryOptional.isPresent()) {
  180 + TsKvDictionary tsKvDictionary = new TsKvDictionary();
  181 + tsKvDictionary.setKey(strKey);
  182 + try {
  183 + TsKvDictionary saved = dictionaryRepository.save(tsKvDictionary);
  184 + tsKvDictionaryMap.put(saved.getKey(), saved.getKeyId());
  185 + keyId = saved.getKeyId();
  186 + } catch (ConstraintViolationException e) {
  187 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  188 + TsKvDictionary dictionary = tsKvDictionaryOptional.orElseThrow(() -> new RuntimeException("Failed to get TsKvDictionary entity from DB!"));
  189 + tsKvDictionaryMap.put(dictionary.getKey(), dictionary.getKeyId());
  190 + keyId = dictionary.getKeyId();
  191 + }
  192 + } else {
  193 + keyId = tsKvDictionaryOptional.get().getKeyId();
  194 + }
  195 + } finally {
  196 + tsCreationLock.unlock();
  197 + }
  198 + } else {
  199 + keyId = tsKvDictionaryOptional.get().getKeyId();
  200 + tsKvDictionaryMap.put(strKey, keyId);
  201 + }
  202 + }
  203 + return keyId;
  204 + }
  205 +}
... ...
  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.install.migrate;
  17 +
  18 +public interface TsLatestMigrateService {
  19 +
  20 + void migrate() throws Exception;
  21 +}
... ...
... ... @@ -28,7 +28,6 @@ import org.thingsboard.server.common.msg.TbActorMsg;
28 28 import org.thingsboard.server.common.msg.queue.ServiceType;
29 29 import org.thingsboard.server.common.msg.queue.TbCallback;
30 30 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
31   -import org.thingsboard.server.gen.transport.TransportProtos;
32 31 import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
33 32 import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto;
34 33 import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto;
... ... @@ -61,7 +60,6 @@ import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWra
61 60
62 61 import javax.annotation.PostConstruct;
63 62 import javax.annotation.PreDestroy;
64   -import java.util.ArrayList;
65 63 import java.util.List;
66 64 import java.util.Optional;
67 65 import java.util.UUID;
... ...
... ... @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Value;
20 20 import org.springframework.scheduling.annotation.Scheduled;
21 21 import org.springframework.stereotype.Service;
22 22 import org.thingsboard.server.dao.util.PsqlDao;
23   -import org.thingsboard.server.dao.util.SqlDao;
24 23 import org.thingsboard.server.service.ttl.AbstractCleanUpService;
25 24
26 25 import java.sql.Connection;
... ... @@ -28,7 +27,6 @@ import java.sql.DriverManager;
28 27 import java.sql.SQLException;
29 28
30 29 @PsqlDao
31   -@SqlDao
32 30 @Slf4j
33 31 @Service
34 32 public class EventsCleanUpService extends AbstractCleanUpService {
... ...
... ... @@ -19,11 +19,13 @@ import lombok.extern.slf4j.Slf4j;
19 19 import org.springframework.beans.factory.annotation.Value;
20 20 import org.springframework.stereotype.Service;
21 21 import org.thingsboard.server.dao.model.ModelConstants;
22   -import org.thingsboard.server.dao.util.PsqlTsDao;
  22 +import org.thingsboard.server.dao.util.PsqlDao;
  23 +import org.thingsboard.server.dao.util.SqlTsDao;
23 24
24 25 import java.sql.Connection;
25 26
26   -@PsqlTsDao
  27 +@SqlTsDao
  28 +@PsqlDao
27 29 @Service
28 30 @Slf4j
29 31 public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService {
... ... @@ -33,9 +35,9 @@ public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpServi
33 35
34 36 @Override
35 37 protected void doCleanUp(Connection connection) {
36   - long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);");
37   - log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved);
38   - long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID + "'," + systemTtl + ", 0);");
39   - log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved);
  38 + long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);");
  39 + log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved);
  40 + long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID + "'," + systemTtl + ", 0);");
  41 + log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved);
40 42 }
41 43 }
\ No newline at end of file
... ...
... ... @@ -178,8 +178,8 @@ database:
178 178 ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records
179 179 ts:
180 180 type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale)
181   - latest_ts:
182   - type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale)
  181 + ts_latest:
  182 + type: "${DATABASE_TS_LATEST_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale)
183 183
184 184 # note: timescale works only with postgreSQL database for DATABASE_ENTITIES_TYPE.
185 185
... ...
... ... @@ -41,7 +41,9 @@ public class MqttNoSqlTestSuite {
41 41 public static CustomCassandraCQLUnit cassandraUnit =
42 42 new CustomCassandraCQLUnit(
43 43 Arrays.asList(
44   - new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false)),
  44 + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false),
  45 + new ClassPathCQLDataSet("cassandra/schema-ts-latest.cql", false, false)
  46 + ),
45 47 "cassandra-test.yaml", 30000l);
46 48
47 49 @BeforeClass
... ...
... ... @@ -21,6 +21,6 @@ import java.lang.annotation.Retention;
21 21 import java.lang.annotation.RetentionPolicy;
22 22
23 23 @Retention(RetentionPolicy.RUNTIME)
24   -@ConditionalOnExpression("'${database.ts.type}'=='cassandra' || '${database.entities.type}'=='cassandra'")
  24 +@ConditionalOnExpression("'${database.ts.type}'=='cassandra' || '${database.ts_latest.type}'=='cassandra'")
25 25 public @interface NoSqlAnyDao {
26 26 }
... ...
common/dao-api/src/main/java/org/thingsboard/server/dao/util/NoSqlTsLatestDao.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlDao.java
... ... @@ -15,9 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.dao.util;
17 17
  18 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  19 +
18 20 import java.lang.annotation.Retention;
19 21 import java.lang.annotation.RetentionPolicy;
20 22
21 23 @Retention(RetentionPolicy.RUNTIME)
22   -public @interface SqlDao {
  24 +@ConditionalOnProperty(prefix = "database.ts_latest", value = "type", havingValue = "cassandra")
  25 +public @interface NoSqlTsLatestDao {
23 26 }
... ...
common/dao-api/src/main/java/org/thingsboard/server/dao/util/PsqlTsLatestAnyDao.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/util/PsqlTsAnyDao.java
... ... @@ -21,7 +21,7 @@ import java.lang.annotation.Retention;
21 21 import java.lang.annotation.RetentionPolicy;
22 22
23 23 @Retention(RetentionPolicy.RUNTIME)
24   -@ConditionalOnExpression("('${database.ts.type}'=='sql' || '${database.ts.type}'=='timescale') " +
  24 +@ConditionalOnExpression("('${database.ts_latest.type}'=='sql' || '${database.ts_latest.type}'=='timescale') " +
25 25 "&& '${spring.jpa.database-platform}'=='org.hibernate.dialect.PostgreSQLDialect'")
26   -public @interface PsqlTsAnyDao {
  26 +public @interface PsqlTsLatestAnyDao {
27 27 }
... ...
  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.dao.util;
  17 +
  18 +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  19 +
  20 +import java.lang.annotation.Retention;
  21 +import java.lang.annotation.RetentionPolicy;
  22 +
  23 +@Retention(RetentionPolicy.RUNTIME)
  24 +@ConditionalOnExpression("'${database.ts_latest.type}'=='sql' || '${database.ts_latest.type}'=='timescale'")
  25 +public @interface SqlTsLatestAnyDao {
  26 +}
... ...
  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.dao.util;
  17 +
  18 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  19 +
  20 +import java.lang.annotation.Retention;
  21 +import java.lang.annotation.RetentionPolicy;
  22 +
  23 +@Retention(RetentionPolicy.RUNTIME)
  24 +@ConditionalOnProperty(prefix = "database.ts_latest", value = "type", havingValue = "sql")
  25 +public @interface SqlTsLatestDao {
  26 +}
... ...
common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlTsOrTsLatestAnyDao.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/util/SqlTsAnyDao.java
... ... @@ -21,6 +21,6 @@ import java.lang.annotation.Retention;
21 21 import java.lang.annotation.RetentionPolicy;
22 22
23 23 @Retention(RetentionPolicy.RUNTIME)
24   -@ConditionalOnExpression("'${database.ts.type}'=='sql' || '${database.ts.type}'=='timescale'")
25   -public @interface SqlTsAnyDao {
  24 +@ConditionalOnExpression("'${database.ts.type}'=='sql' || '${database.ts.type}'=='timescale' || '${database.ts_latest.type}'=='sql' || '${database.ts_latest.type}'=='timescale'")
  25 +public @interface SqlTsOrTsLatestAnyDao {
26 26 }
... ...
  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.dao.util;
  17 +
  18 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  19 +
  20 +import java.lang.annotation.Retention;
  21 +import java.lang.annotation.RetentionPolicy;
  22 +
  23 +@Retention(RetentionPolicy.RUNTIME)
  24 +@ConditionalOnProperty(prefix = "database.ts_latest", value = "type", havingValue = "timescale")
  25 +public @interface TimescaleDBTsLatestDao {
  26 +}
... ...
common/dao-api/src/main/java/org/thingsboard/server/dao/util/TimescaleDBTsOrTsLatestDao.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/util/PsqlTsDao.java
... ... @@ -21,5 +21,6 @@ import java.lang.annotation.Retention;
21 21 import java.lang.annotation.RetentionPolicy;
22 22
23 23 @Retention(RetentionPolicy.RUNTIME)
24   -@ConditionalOnExpression("'${database.ts.type}'=='sql' && '${spring.jpa.database-platform}'=='org.hibernate.dialect.PostgreSQLDialect'")
25   -public @interface PsqlTsDao { }
\ No newline at end of file
  24 +@ConditionalOnExpression("'${database.ts.type}'=='timescale' || '${database.ts_latest.type}'=='timescale'")
  25 +public @interface TimescaleDBTsOrTsLatestDao {
  26 +}
... ...
... ... @@ -27,8 +27,8 @@ import org.thingsboard.server.dao.util.SqlTsDao;
27 27 @Configuration
28 28 @EnableAutoConfiguration
29 29 @ComponentScan({"org.thingsboard.server.dao.sqlts.hsql"})
30   -@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.ts", "org.thingsboard.server.dao.sqlts.insert.hsql", "org.thingsboard.server.dao.sqlts.insert.latest.hsql", "org.thingsboard.server.dao.sqlts.latest", "org.thingsboard.server.dao.sqlts.dictionary"})
31   -@EntityScan({"org.thingsboard.server.dao.model.sqlts.ts", "org.thingsboard.server.dao.model.sqlts.latest", "org.thingsboard.server.dao.model.sqlts.dictionary"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.ts", "org.thingsboard.server.dao.sqlts.insert.hsql"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.ts"})
32 32 @EnableTransactionManagement
33 33 @SqlTsDao
34 34 @HsqlDao
... ...
  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.dao;
  17 +
  18 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  19 +import org.springframework.boot.autoconfigure.domain.EntityScan;
  20 +import org.springframework.context.annotation.ComponentScan;
  21 +import org.springframework.context.annotation.Configuration;
  22 +import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  23 +import org.springframework.transaction.annotation.EnableTransactionManagement;
  24 +import org.thingsboard.server.dao.util.HsqlDao;
  25 +import org.thingsboard.server.dao.util.SqlTsLatestDao;
  26 +
  27 +@Configuration
  28 +@EnableAutoConfiguration
  29 +@ComponentScan({"org.thingsboard.server.dao.sqlts.hsql"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.insert.latest.hsql", "org.thingsboard.server.dao.sqlts.latest"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.latest"})
  32 +@EnableTransactionManagement
  33 +@SqlTsLatestDao
  34 +@HsqlDao
  35 +public class HsqlTsLatestDaoConfig {
  36 +
  37 +}
... ...
... ... @@ -21,7 +21,6 @@ import org.springframework.context.annotation.ComponentScan;
21 21 import org.springframework.context.annotation.Configuration;
22 22 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
23 23 import org.springframework.transaction.annotation.EnableTransactionManagement;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 /**
27 26 * @author Valerii Sosliuk
... ... @@ -32,7 +31,6 @@ import org.thingsboard.server.dao.util.SqlDao;
32 31 @EnableJpaRepositories("org.thingsboard.server.dao.sql")
33 32 @EntityScan("org.thingsboard.server.dao.model.sql")
34 33 @EnableTransactionManagement
35   -@SqlDao
36 34 public class JpaDaoConfig {
37 35
38 36 }
... ...
... ... @@ -27,11 +27,11 @@ import org.thingsboard.server.dao.util.SqlTsDao;
27 27 @Configuration
28 28 @EnableAutoConfiguration
29 29 @ComponentScan({"org.thingsboard.server.dao.sqlts.psql"})
30   -@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.ts", "org.thingsboard.server.dao.sqlts.insert.psql", "org.thingsboard.server.dao.sqlts.insert.latest.psql", "org.thingsboard.server.dao.sqlts.latest", "org.thingsboard.server.dao.sqlts.dictionary"})
31   -@EntityScan({"org.thingsboard.server.dao.model.sqlts.ts", "org.thingsboard.server.dao.model.sqlts.latest", "org.thingsboard.server.dao.model.sqlts.dictionary"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.ts", "org.thingsboard.server.dao.sqlts.insert.psql"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.ts"})
32 32 @EnableTransactionManagement
33   -@SqlTsDao
34 33 @PsqlDao
  34 +@SqlTsDao
35 35 public class PsqlTsDaoConfig {
36 36
37 37 }
... ...
  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.dao;
  17 +
  18 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  19 +import org.springframework.boot.autoconfigure.domain.EntityScan;
  20 +import org.springframework.context.annotation.ComponentScan;
  21 +import org.springframework.context.annotation.Configuration;
  22 +import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  23 +import org.springframework.transaction.annotation.EnableTransactionManagement;
  24 +import org.thingsboard.server.dao.util.PsqlDao;
  25 +import org.thingsboard.server.dao.util.SqlTsLatestDao;
  26 +
  27 +@Configuration
  28 +@EnableAutoConfiguration
  29 +@ComponentScan({"org.thingsboard.server.dao.sqlts.psql"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.insert.latest.psql", "org.thingsboard.server.dao.sqlts.latest"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.latest"})
  32 +@EnableTransactionManagement
  33 +@SqlTsLatestDao
  34 +@PsqlDao
  35 +public class PsqlTsLatestDaoConfig {
  36 +
  37 +}
... ...
  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.dao;
  17 +
  18 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  19 +import org.springframework.boot.autoconfigure.domain.EntityScan;
  20 +import org.springframework.context.annotation.Configuration;
  21 +import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  22 +import org.springframework.transaction.annotation.EnableTransactionManagement;
  23 +import org.thingsboard.server.dao.util.PsqlDao;
  24 +import org.thingsboard.server.dao.util.SqlTsOrTsLatestAnyDao;
  25 +
  26 +@Configuration
  27 +@EnableAutoConfiguration
  28 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.dictionary"})
  29 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.dictionary"})
  30 +@EnableTransactionManagement
  31 +@SqlTsOrTsLatestAnyDao
  32 +public class SqlTimeseriesDaoConfig {
  33 +
  34 +}
... ...
... ... @@ -27,8 +27,8 @@ import org.thingsboard.server.dao.util.TimescaleDBTsDao;
27 27 @Configuration
28 28 @EnableAutoConfiguration
29 29 @ComponentScan({"org.thingsboard.server.dao.sqlts.timescale"})
30   -@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.timescale", "org.thingsboard.server.dao.sqlts.insert.latest.psql", "org.thingsboard.server.dao.sqlts.insert.timescale", "org.thingsboard.server.dao.sqlts.dictionary", "org.thingsboard.server.dao.sqlts.latest"})
31   -@EntityScan({"org.thingsboard.server.dao.model.sqlts.timescale", "org.thingsboard.server.dao.model.sqlts.dictionary", "org.thingsboard.server.dao.model.sqlts.latest"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.timescale", "org.thingsboard.server.dao.sqlts.insert.timescale"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.timescale"})
32 32 @EnableTransactionManagement
33 33 @TimescaleDBTsDao
34 34 @PsqlDao
... ...
  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.dao;
  17 +
  18 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
  19 +import org.springframework.boot.autoconfigure.domain.EntityScan;
  20 +import org.springframework.context.annotation.ComponentScan;
  21 +import org.springframework.context.annotation.Configuration;
  22 +import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  23 +import org.springframework.transaction.annotation.EnableTransactionManagement;
  24 +import org.thingsboard.server.dao.util.PsqlDao;
  25 +import org.thingsboard.server.dao.util.TimescaleDBTsLatestDao;
  26 +
  27 +@Configuration
  28 +@EnableAutoConfiguration
  29 +@ComponentScan({"org.thingsboard.server.dao.sqlts.timescale"})
  30 +@EnableJpaRepositories({"org.thingsboard.server.dao.sqlts.insert.latest.psql", "org.thingsboard.server.dao.sqlts.latest"})
  31 +@EntityScan({"org.thingsboard.server.dao.model.sqlts.latest"})
  32 +@EnableTransactionManagement
  33 +@TimescaleDBTsLatestDao
  34 +@PsqlDao
  35 +public class TimescaleTsLatestDaoConfig {
  36 +
  37 +}
... ...
... ... @@ -18,10 +18,8 @@ package org.thingsboard.server.dao.sql;
18 18 import org.springframework.beans.factory.annotation.Value;
19 19 import org.springframework.stereotype.Component;
20 20 import org.thingsboard.common.util.AbstractListeningExecutor;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23 22 @Component
24   -@SqlDao
25 23 public class JpaExecutorService extends AbstractListeningExecutor {
26 24
27 25 @Value("${spring.datasource.hikari.maximumPoolSize}")
... ...
... ... @@ -21,25 +21,15 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.CrudRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.common.data.alarm.AlarmStatus;
24   -import org.thingsboard.server.common.data.id.CustomerId;
25   -import org.thingsboard.server.common.data.id.EntityId;
26   -import org.thingsboard.server.common.data.id.TenantId;
27   -import org.thingsboard.server.common.data.page.PageData;
28   -import org.thingsboard.server.common.data.query.AlarmData;
29   -import org.thingsboard.server.common.data.query.AlarmDataQuery;
30 24 import org.thingsboard.server.dao.model.sql.AlarmEntity;
31 25 import org.thingsboard.server.dao.model.sql.AlarmInfoEntity;
32   -import org.thingsboard.server.dao.util.SqlDao;
33 26
34   -import java.util.Collection;
35 27 import java.util.List;
36   -import java.util.Set;
37 28 import java.util.UUID;
38 29
39 30 /**
40 31 * Created by Valerii Sosliuk on 5/21/2017.
41 32 */
42   -@SqlDao
43 33 public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
44 34
45 35 @Query("SELECT a FROM AlarmEntity a WHERE a.originatorId = :originatorId AND a.type = :alarmType ORDER BY a.startTs DESC")
... ...
... ... @@ -39,7 +39,6 @@ import org.thingsboard.server.dao.model.sql.AlarmEntity;
39 39 import org.thingsboard.server.dao.relation.RelationDao;
40 40 import org.thingsboard.server.dao.sql.JpaAbstractDao;
41 41 import org.thingsboard.server.dao.sql.query.AlarmQueryRepository;
42   -import org.thingsboard.server.dao.util.SqlDao;
43 42
44 43 import java.util.ArrayList;
45 44 import java.util.Collection;
... ... @@ -54,7 +53,6 @@ import java.util.UUID;
54 53 */
55 54 @Slf4j
56 55 @Component
57   -@SqlDao
58 56 public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements AlarmDao {
59 57
60 58 @Autowired
... ...
... ... @@ -22,7 +22,6 @@ import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.AssetEntity;
24 24 import org.thingsboard.server.dao.model.sql.AssetInfoEntity;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.List;
28 27 import java.util.UUID;
... ... @@ -30,7 +29,6 @@ import java.util.UUID;
30 29 /**
31 30 * Created by Valerii Sosliuk on 5/21/2017.
32 31 */
33   -@SqlDao
34 32 public interface AssetRepository extends PagingAndSortingRepository<AssetEntity, UUID> {
35 33
36 34 @Query("SELECT new org.thingsboard.server.dao.model.sql.AssetInfoEntity(a, c.title, c.additionalInfo) " +
... ...
... ... @@ -31,7 +31,6 @@ import org.thingsboard.server.dao.asset.AssetDao;
31 31 import org.thingsboard.server.dao.model.sql.AssetEntity;
32 32 import org.thingsboard.server.dao.model.sql.AssetInfoEntity;
33 33 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
34   -import org.thingsboard.server.dao.util.SqlDao;
35 34
36 35 import java.util.ArrayList;
37 36 import java.util.Collections;
... ... @@ -44,7 +43,6 @@ import java.util.UUID;
44 43 * Created by Valerii Sosliuk on 5/19/2017.
45 44 */
46 45 @Component
47   -@SqlDao
48 46 public class JpaAssetDao extends JpaAbstractSearchTextDao<AssetEntity, Asset> implements AssetDao {
49 47
50 48 @Autowired
... ...
... ... @@ -25,7 +25,6 @@ import org.springframework.transaction.TransactionStatus;
25 25 import org.springframework.transaction.support.TransactionCallbackWithoutResult;
26 26 import org.springframework.transaction.support.TransactionTemplate;
27 27 import org.thingsboard.server.dao.model.sql.AttributeKvEntity;
28   -import org.thingsboard.server.dao.util.SqlDao;
29 28
30 29 import java.sql.PreparedStatement;
31 30 import java.sql.SQLException;
... ... @@ -35,7 +34,6 @@ import java.util.ArrayList;
35 34 import java.util.List;
36 35 import java.util.regex.Pattern;
37 36
38   -@SqlDao
39 37 @Repository
40 38 @Slf4j
41 39 public abstract class AttributeKvInsertRepository {
... ...
... ... @@ -23,12 +23,10 @@ import org.springframework.transaction.annotation.Transactional;
23 23 import org.thingsboard.server.common.data.EntityType;
24 24 import org.thingsboard.server.dao.model.sql.AttributeKvCompositeKey;
25 25 import org.thingsboard.server.dao.model.sql.AttributeKvEntity;
26   -import org.thingsboard.server.dao.util.SqlDao;
27 26
28 27 import java.util.List;
29 28 import java.util.UUID;
30 29
31   -@SqlDao
32 30 public interface AttributeKvRepository extends CrudRepository<AttributeKvEntity, AttributeKvCompositeKey> {
33 31
34 32 @Query("SELECT a FROM AttributeKvEntity a WHERE a.id.entityType = :entityType " +
... ...
... ... @@ -19,12 +19,10 @@ import org.springframework.stereotype.Repository;
19 19 import org.springframework.transaction.annotation.Transactional;
20 20 import org.thingsboard.server.dao.model.sql.AttributeKvEntity;
21 21 import org.thingsboard.server.dao.util.HsqlDao;
22   -import org.thingsboard.server.dao.util.SqlDao;
23 22
24 23 import java.sql.Types;
25 24 import java.util.List;
26 25
27   -@SqlDao
28 26 @HsqlDao
29 27 @Repository
30 28 @Transactional
... ...
... ... @@ -34,7 +34,6 @@ import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService;
34 34 import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
35 35 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
36 36 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
37   -import org.thingsboard.server.dao.util.SqlDao;
38 37
39 38 import javax.annotation.PostConstruct;
40 39 import javax.annotation.PreDestroy;
... ... @@ -46,7 +45,6 @@ import java.util.stream.Collectors;
46 45
47 46 @Component
48 47 @Slf4j
49   -@SqlDao
50 48 public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService implements AttributesDao {
51 49
52 50 @Autowired
... ...
... ... @@ -18,9 +18,7 @@ package org.thingsboard.server.dao.sql.attributes;
18 18 import org.springframework.stereotype.Repository;
19 19 import org.springframework.transaction.annotation.Transactional;
20 20 import org.thingsboard.server.dao.util.PsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23   -@SqlDao
24 22 @PsqlDao
25 23 @Repository
26 24 @Transactional
... ...
... ... @@ -30,14 +30,12 @@ import org.thingsboard.server.dao.DaoUtil;
30 30 import org.thingsboard.server.dao.audit.AuditLogDao;
31 31 import org.thingsboard.server.dao.model.sql.AuditLogEntity;
32 32 import org.thingsboard.server.dao.sql.JpaAbstractDao;
33   -import org.thingsboard.server.dao.util.SqlDao;
34 33
35 34 import java.util.List;
36 35 import java.util.Objects;
37 36 import java.util.UUID;
38 37
39 38 @Component
40   -@SqlDao
41 39 public class JpaAuditLogDao extends JpaAbstractDao<AuditLogEntity, AuditLog> implements AuditLogDao {
42 40
43 41 @Autowired
... ...
... ... @@ -23,14 +23,12 @@ import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.common.data.plugin.ComponentScope;
24 24 import org.thingsboard.server.common.data.plugin.ComponentType;
25 25 import org.thingsboard.server.dao.model.sql.ComponentDescriptorEntity;
26   -import org.thingsboard.server.dao.util.SqlDao;
27 26
28 27 import java.util.UUID;
29 28
30 29 /**
31 30 * Created by Valerii Sosliuk on 5/6/2017.
32 31 */
33   -@SqlDao
34 32 public interface ComponentDescriptorRepository extends PagingAndSortingRepository<ComponentDescriptorEntity, UUID> {
35 33
36 34 ComponentDescriptorEntity findByClazz(String clazz);
... ...
... ... @@ -18,11 +18,9 @@ package org.thingsboard.server.dao.sql.component;
18 18 import org.springframework.stereotype.Repository;
19 19 import org.thingsboard.server.dao.model.sql.ComponentDescriptorEntity;
20 20 import org.thingsboard.server.dao.util.HsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23 22 import javax.persistence.Query;
24 23
25   -@SqlDao
26 24 @HsqlDao
27 25 @Repository
28 26 public class HsqlComponentDescriptorInsertRepository extends AbstractComponentDescriptorInsertRepository {
... ...
... ... @@ -31,7 +31,6 @@ import org.thingsboard.server.dao.DaoUtil;
31 31 import org.thingsboard.server.dao.component.ComponentDescriptorDao;
32 32 import org.thingsboard.server.dao.model.sql.ComponentDescriptorEntity;
33 33 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
34   -import org.thingsboard.server.dao.util.SqlDao;
35 34
36 35 import java.util.Objects;
37 36 import java.util.Optional;
... ... @@ -41,7 +40,6 @@ import java.util.UUID;
41 40 * Created by Valerii Sosliuk on 5/6/2017.
42 41 */
43 42 @Component
44   -@SqlDao
45 43 public class JpaBaseComponentDescriptorDao extends JpaAbstractSearchTextDao<ComponentDescriptorEntity, ComponentDescriptor>
46 44 implements ComponentDescriptorDao {
47 45
... ...
... ... @@ -18,9 +18,7 @@ package org.thingsboard.server.dao.sql.component;
18 18 import org.springframework.stereotype.Repository;
19 19 import org.thingsboard.server.dao.model.sql.ComponentDescriptorEntity;
20 20 import org.thingsboard.server.dao.util.PsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23   -@SqlDao
24 22 @PsqlDao
25 23 @Repository
26 24 public class PsqlComponentDescriptorInsertRepository extends AbstractComponentDescriptorInsertRepository {
... ...
... ... @@ -21,14 +21,12 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.CustomerEntity;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 import java.util.UUID;
27 26
28 27 /**
29 28 * Created by Valerii Sosliuk on 5/6/2017.
30 29 */
31   -@SqlDao
32 30 public interface CustomerRepository extends PagingAndSortingRepository<CustomerEntity, UUID> {
33 31
34 32 @Query("SELECT c FROM CustomerEntity c WHERE c.tenantId = :tenantId " +
... ...
... ... @@ -25,7 +25,6 @@ import org.thingsboard.server.dao.DaoUtil;
25 25 import org.thingsboard.server.dao.customer.CustomerDao;
26 26 import org.thingsboard.server.dao.model.sql.CustomerEntity;
27 27 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
28   -import org.thingsboard.server.dao.util.SqlDao;
29 28
30 29 import java.util.Objects;
31 30 import java.util.Optional;
... ... @@ -35,7 +34,6 @@ import java.util.UUID;
35 34 * Created by Valerii Sosliuk on 5/6/2017.
36 35 */
37 36 @Component
38   -@SqlDao
39 37 public class JpaCustomerDao extends JpaAbstractSearchTextDao<CustomerEntity, Customer> implements CustomerDao {
40 38
41 39 @Autowired
... ...
... ... @@ -21,14 +21,12 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.DashboardInfoEntity;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 import java.util.UUID;
27 26
28 27 /**
29 28 * Created by Valerii Sosliuk on 5/6/2017.
30 29 */
31   -@SqlDao
32 30 public interface DashboardInfoRepository extends PagingAndSortingRepository<DashboardInfoEntity, UUID> {
33 31
34 32 @Query("SELECT di FROM DashboardInfoEntity di WHERE di.tenantId = :tenantId " +
... ...
... ... @@ -17,13 +17,11 @@ package org.thingsboard.server.dao.sql.dashboard;
17 17
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sql.DashboardEntity;
20   -import org.thingsboard.server.dao.util.SqlDao;
21 20
22 21 import java.util.UUID;
23 22
24 23 /**
25 24 * Created by Valerii Sosliuk on 5/6/2017.
26 25 */
27   -@SqlDao
28 26 public interface DashboardRepository extends CrudRepository<DashboardEntity, UUID> {
29 27 }
... ...
... ... @@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.Dashboard;
22 22 import org.thingsboard.server.dao.dashboard.DashboardDao;
23 23 import org.thingsboard.server.dao.model.sql.DashboardEntity;
24 24 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.UUID;
28 27
... ... @@ -30,7 +29,6 @@ import java.util.UUID;
30 29 * Created by Valerii Sosliuk on 5/6/2017.
31 30 */
32 31 @Component
33   -@SqlDao
34 32 public class JpaDashboardDao extends JpaAbstractSearchTextDao<DashboardEntity, Dashboard> implements DashboardDao {
35 33
36 34 @Autowired
... ...
... ... @@ -27,7 +27,6 @@ import org.thingsboard.server.dao.dashboard.DashboardInfoDao;
27 27 import org.thingsboard.server.dao.model.sql.DashboardInfoEntity;
28 28 import org.thingsboard.server.dao.relation.RelationDao;
29 29 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
30   -import org.thingsboard.server.dao.util.SqlDao;
31 30
32 31 import java.util.Objects;
33 32 import java.util.UUID;
... ... @@ -37,7 +36,6 @@ import java.util.UUID;
37 36 */
38 37 @Slf4j
39 38 @Component
40   -@SqlDao
41 39 public class JpaDashboardInfoDao extends JpaAbstractSearchTextDao<DashboardInfoEntity, DashboardInfo> implements DashboardInfoDao {
42 40
43 41 @Autowired
... ...
... ... @@ -17,14 +17,12 @@ package org.thingsboard.server.dao.sql.device;
17 17
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sql.DeviceCredentialsEntity;
20   -import org.thingsboard.server.dao.util.SqlDao;
21 20
22 21 import java.util.UUID;
23 22
24 23 /**
25 24 * Created by Valerii Sosliuk on 5/6/2017.
26 25 */
27   -@SqlDao
28 26 public interface DeviceCredentialsRepository extends CrudRepository<DeviceCredentialsEntity, UUID> {
29 27
30 28 DeviceCredentialsEntity findByDeviceId(UUID deviceId);
... ...
... ... @@ -22,7 +22,6 @@ import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.DeviceEntity;
24 24 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.List;
28 27 import java.util.UUID;
... ... @@ -30,7 +29,6 @@ import java.util.UUID;
30 29 /**
31 30 * Created by Valerii Sosliuk on 5/6/2017.
32 31 */
33   -@SqlDao
34 32 public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntity, UUID> {
35 33
36 34 @Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo) " +
... ...
... ... @@ -24,7 +24,6 @@ import org.thingsboard.server.dao.DaoUtil;
24 24 import org.thingsboard.server.dao.device.DeviceCredentialsDao;
25 25 import org.thingsboard.server.dao.model.sql.DeviceCredentialsEntity;
26 26 import org.thingsboard.server.dao.sql.JpaAbstractDao;
27   -import org.thingsboard.server.dao.util.SqlDao;
28 27
29 28 import java.util.UUID;
30 29
... ... @@ -32,7 +31,6 @@ import java.util.UUID;
32 31 * Created by Valerii Sosliuk on 5/6/2017.
33 32 */
34 33 @Component
35   -@SqlDao
36 34 public class JpaDeviceCredentialsDao extends JpaAbstractDao<DeviceCredentialsEntity, DeviceCredentials> implements DeviceCredentialsDao {
37 35
38 36 @Autowired
... ...
... ... @@ -32,7 +32,6 @@ import org.thingsboard.server.dao.device.DeviceDao;
32 32 import org.thingsboard.server.dao.model.sql.DeviceEntity;
33 33 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity;
34 34 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
35   -import org.thingsboard.server.dao.util.SqlDao;
36 35
37 36 import java.util.ArrayList;
38 37 import java.util.Collections;
... ... @@ -45,7 +44,6 @@ import java.util.UUID;
45 44 * Created by Valerii Sosliuk on 5/6/2017.
46 45 */
47 46 @Component
48   -@SqlDao
49 47 public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> implements DeviceDao {
50 48
51 49 @Autowired
... ...
... ... @@ -22,7 +22,6 @@ import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.EntityViewEntity;
24 24 import org.thingsboard.server.dao.model.sql.EntityViewInfoEntity;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.List;
28 27 import java.util.UUID;
... ... @@ -30,7 +29,6 @@ import java.util.UUID;
30 29 /**
31 30 * Created by Victor Basanets on 8/31/2017.
32 31 */
33   -@SqlDao
34 32 public interface EntityViewRepository extends PagingAndSortingRepository<EntityViewEntity, UUID> {
35 33
36 34 @Query("SELECT new org.thingsboard.server.dao.model.sql.EntityViewInfoEntity(e, c.title, c.additionalInfo) " +
... ...
... ... @@ -31,7 +31,6 @@ import org.thingsboard.server.dao.entityview.EntityViewDao;
31 31 import org.thingsboard.server.dao.model.sql.EntityViewEntity;
32 32 import org.thingsboard.server.dao.model.sql.EntityViewInfoEntity;
33 33 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
34   -import org.thingsboard.server.dao.util.SqlDao;
35 34
36 35 import java.util.ArrayList;
37 36 import java.util.Collections;
... ... @@ -44,7 +43,6 @@ import java.util.UUID;
44 43 * Created by Victor Basanets on 8/31/2017.
45 44 */
46 45 @Component
47   -@SqlDao
48 46 public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity, EntityView>
49 47 implements EntityViewDao {
50 48
... ...
... ... @@ -22,7 +22,6 @@ import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.common.data.EntityType;
24 24 import org.thingsboard.server.dao.model.sql.EventEntity;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.List;
28 27 import java.util.UUID;
... ... @@ -30,7 +29,6 @@ import java.util.UUID;
30 29 /**
31 30 * Created by Valerii Sosliuk on 5/3/2017.
32 31 */
33   -@SqlDao
34 32 public interface EventRepository extends PagingAndSortingRepository<EventEntity, UUID> {
35 33
36 34 EventEntity findByTenantIdAndEntityTypeAndEntityIdAndEventTypeAndEventUid(UUID tenantId,
... ...
... ... @@ -18,11 +18,9 @@ package org.thingsboard.server.dao.sql.event;
18 18 import org.springframework.stereotype.Repository;
19 19 import org.thingsboard.server.dao.model.sql.EventEntity;
20 20 import org.thingsboard.server.dao.util.HsqlDao;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23 22 import javax.persistence.Query;
24 23
25   -@SqlDao
26 24 @HsqlDao
27 25 @Repository
28 26 public class HsqlEventInsertRepository extends AbstractEventInsertRepository {
... ...
... ... @@ -21,7 +21,6 @@ import lombok.extern.slf4j.Slf4j;
21 21 import org.apache.commons.lang3.StringUtils;
22 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.data.domain.PageRequest;
24   -import org.springframework.data.jpa.domain.Specification;
25 24 import org.springframework.data.repository.CrudRepository;
26 25 import org.springframework.stereotype.Component;
27 26 import org.thingsboard.server.common.data.Event;
... ... @@ -34,10 +33,7 @@ import org.thingsboard.server.dao.DaoUtil;
34 33 import org.thingsboard.server.dao.event.EventDao;
35 34 import org.thingsboard.server.dao.model.sql.EventEntity;
36 35 import org.thingsboard.server.dao.sql.JpaAbstractDao;
37   -import org.thingsboard.server.dao.util.SqlDao;
38 36
39   -import javax.persistence.criteria.Predicate;
40   -import java.util.ArrayList;
41 37 import java.util.List;
42 38 import java.util.Objects;
43 39 import java.util.Optional;
... ... @@ -50,7 +46,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
50 46 */
51 47 @Slf4j
52 48 @Component
53   -@SqlDao
54 49 public class JpaBaseEventDao extends JpaAbstractDao<EventEntity, Event> implements EventDao {
55 50
56 51 private final UUID systemTenantId = NULL_UUID;
... ...
... ... @@ -19,10 +19,8 @@ import lombok.extern.slf4j.Slf4j;
19 19 import org.springframework.stereotype.Repository;
20 20 import org.thingsboard.server.dao.model.sql.EventEntity;
21 21 import org.thingsboard.server.dao.util.PsqlDao;
22   -import org.thingsboard.server.dao.util.SqlDao;
23 22
24 23 @Slf4j
25   -@SqlDao
26 24 @PsqlDao
27 25 @Repository
28 26 public class PsqlEventInsertRepository extends AbstractEventInsertRepository {
... ...
... ... @@ -39,7 +39,6 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder;
39 39 import org.thingsboard.server.common.data.query.EntityKey;
40 40 import org.thingsboard.server.common.data.query.EntityKeyType;
41 41 import org.thingsboard.server.dao.model.ModelConstants;
42   -import org.thingsboard.server.dao.util.SqlDao;
43 42
44 43 import java.util.ArrayList;
45 44 import java.util.Arrays;
... ... @@ -52,7 +51,6 @@ import java.util.Objects;
52 51 import java.util.Set;
53 52 import java.util.stream.Collectors;
54 53
55   -@SqlDao
56 54 @Repository
57 55 @Slf4j
58 56 public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
... ...
... ... @@ -50,7 +50,6 @@ import org.thingsboard.server.common.data.query.RelationsQueryFilter;
50 50 import org.thingsboard.server.common.data.query.SingleEntityFilter;
51 51 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
52 52 import org.thingsboard.server.common.data.relation.EntityTypeFilter;
53   -import org.thingsboard.server.dao.util.SqlDao;
54 53
55 54 import java.util.Arrays;
56 55 import java.util.Collections;
... ... @@ -61,7 +60,6 @@ import java.util.Optional;
61 60 import java.util.UUID;
62 61 import java.util.stream.Collectors;
63 62
64   -@SqlDao
65 63 @Repository
66 64 @Slf4j
67 65 public class DefaultEntityQueryRepository implements EntityQueryRepository {
... ...
... ... @@ -24,10 +24,8 @@ import org.thingsboard.server.common.data.query.EntityCountQuery;
24 24 import org.thingsboard.server.common.data.query.EntityData;
25 25 import org.thingsboard.server.common.data.query.EntityDataQuery;
26 26 import org.thingsboard.server.dao.entity.EntityQueryDao;
27   -import org.thingsboard.server.dao.util.SqlDao;
28 27
29 28 @Component
30   -@SqlDao
31 29 public class JpaEntityQueryDao implements EntityQueryDao {
32 30
33 31 @Autowired
... ...
... ... @@ -20,12 +20,10 @@ import org.springframework.transaction.annotation.Transactional;
20 20 import org.thingsboard.server.dao.model.sql.RelationCompositeKey;
21 21 import org.thingsboard.server.dao.model.sql.RelationEntity;
22 22 import org.thingsboard.server.dao.util.HsqlDao;
23   -import org.thingsboard.server.dao.util.SqlDao;
24 23
25 24 import javax.persistence.Query;
26 25
27 26 @HsqlDao
28   -@SqlDao
29 27 @Repository
30 28 @Transactional
31 29 public class HsqlRelationInsertRepository extends AbstractRelationInsertRepository implements RelationInsertRepository {
... ...
... ... @@ -30,7 +30,6 @@ import org.thingsboard.server.dao.model.sql.RelationCompositeKey;
30 30 import org.thingsboard.server.dao.model.sql.RelationEntity;
31 31 import org.thingsboard.server.dao.relation.RelationDao;
32 32 import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService;
33   -import org.thingsboard.server.dao.util.SqlDao;
34 33
35 34 import javax.persistence.criteria.Predicate;
36 35 import java.util.ArrayList;
... ... @@ -41,7 +40,6 @@ import java.util.List;
41 40 */
42 41 @Slf4j
43 42 @Component
44   -@SqlDao
45 43 public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService implements RelationDao {
46 44
47 45 @Autowired
... ...
... ... @@ -19,10 +19,8 @@ import org.springframework.stereotype.Repository;
19 19 import org.springframework.transaction.annotation.Transactional;
20 20 import org.thingsboard.server.dao.model.sql.RelationEntity;
21 21 import org.thingsboard.server.dao.util.PsqlDao;
22   -import org.thingsboard.server.dao.util.SqlDao;
23 22
24 23 @PsqlDao
25   -@SqlDao
26 24 @Repository
27 25 @Transactional
28 26 public class PsqlRelationInsertRepository extends AbstractRelationInsertRepository implements RelationInsertRepository {
... ...
... ... @@ -20,12 +20,10 @@ import org.springframework.data.repository.CrudRepository;
20 20 import org.springframework.transaction.annotation.Transactional;
21 21 import org.thingsboard.server.dao.model.sql.RelationCompositeKey;
22 22 import org.thingsboard.server.dao.model.sql.RelationEntity;
23   -import org.thingsboard.server.dao.util.SqlDao;
24 23
25 24 import java.util.List;
26 25 import java.util.UUID;
27 26
28   -@SqlDao
29 27 public interface RelationRepository
30 28 extends CrudRepository<RelationEntity, RelationCompositeKey>, JpaSpecificationExecutor<RelationEntity> {
31 29
... ...
... ... @@ -26,14 +26,12 @@ import org.thingsboard.server.dao.DaoUtil;
26 26 import org.thingsboard.server.dao.model.sql.RuleChainEntity;
27 27 import org.thingsboard.server.dao.rule.RuleChainDao;
28 28 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
29   -import org.thingsboard.server.dao.util.SqlDao;
30 29
31 30 import java.util.Objects;
32 31 import java.util.UUID;
33 32
34 33 @Slf4j
35 34 @Component
36   -@SqlDao
37 35 public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, RuleChain> implements RuleChainDao {
38 36
39 37 @Autowired
... ...
... ... @@ -23,11 +23,9 @@ import org.thingsboard.server.common.data.rule.RuleNode;
23 23 import org.thingsboard.server.dao.model.sql.RuleNodeEntity;
24 24 import org.thingsboard.server.dao.rule.RuleNodeDao;
25 25 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
26   -import org.thingsboard.server.dao.util.SqlDao;
27 26
28 27 @Slf4j
29 28 @Component
30   -@SqlDao
31 29 public class JpaRuleNodeDao extends JpaAbstractSearchTextDao<RuleNodeEntity, RuleNode> implements RuleNodeDao {
32 30
33 31 @Autowired
... ...
... ... @@ -21,11 +21,9 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.RuleChainEntity;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 import java.util.UUID;
27 26
28   -@SqlDao
29 27 public interface RuleChainRepository extends PagingAndSortingRepository<RuleChainEntity, UUID> {
30 28
31 29 @Query("SELECT rc FROM RuleChainEntity rc WHERE rc.tenantId = :tenantId " +
... ...
... ... @@ -17,9 +17,7 @@ package org.thingsboard.server.dao.sql.rule;
17 17
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sql.RuleNodeEntity;
20   -import org.thingsboard.server.dao.util.SqlDao;
21 20
22   -@SqlDao
23 21 public interface RuleNodeRepository extends CrudRepository<RuleNodeEntity, String> {
24 22
25 23 }
... ...
... ... @@ -25,13 +25,11 @@ import org.thingsboard.server.dao.DaoUtil;
25 25 import org.thingsboard.server.dao.model.sql.AdminSettingsEntity;
26 26 import org.thingsboard.server.dao.settings.AdminSettingsDao;
27 27 import org.thingsboard.server.dao.sql.JpaAbstractDao;
28   -import org.thingsboard.server.dao.util.SqlDao;
29 28
30 29 import java.util.UUID;
31 30
32 31 @Component
33 32 @Slf4j
34   -@SqlDao
35 33 public class JpaAdminSettingsDao extends JpaAbstractDao<AdminSettingsEntity, AdminSettings> implements AdminSettingsDao {
36 34
37 35 @Autowired
... ...
... ... @@ -26,7 +26,6 @@ import org.thingsboard.server.dao.DaoUtil;
26 26 import org.thingsboard.server.dao.model.sql.TenantEntity;
27 27 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
28 28 import org.thingsboard.server.dao.tenant.TenantDao;
29   -import org.thingsboard.server.dao.util.SqlDao;
30 29
31 30 import java.util.Objects;
32 31 import java.util.UUID;
... ... @@ -36,7 +35,6 @@ import java.util.UUID;
36 35 * Created by Valerii Sosliuk on 4/30/2017.
37 36 */
38 37 @Component
39   -@SqlDao
40 38 public class JpaTenantDao extends JpaAbstractSearchTextDao<TenantEntity, Tenant> implements TenantDao {
41 39
42 40 @Autowired
... ...
... ... @@ -21,14 +21,12 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.TenantEntity;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 import java.util.UUID;
27 26
28 27 /**
29 28 * Created by Valerii Sosliuk on 4/30/2017.
30 29 */
31   -@SqlDao
32 30 public interface TenantRepository extends PagingAndSortingRepository<TenantEntity, UUID> {
33 31
34 32 @Query("SELECT t FROM TenantEntity t WHERE t.region = :region " +
... ...
... ... @@ -24,7 +24,6 @@ import org.thingsboard.server.dao.DaoUtil;
24 24 import org.thingsboard.server.dao.model.sql.UserCredentialsEntity;
25 25 import org.thingsboard.server.dao.sql.JpaAbstractDao;
26 26 import org.thingsboard.server.dao.user.UserCredentialsDao;
27   -import org.thingsboard.server.dao.util.SqlDao;
28 27
29 28 import java.util.UUID;
30 29
... ... @@ -32,7 +31,6 @@ import java.util.UUID;
32 31 * Created by Valerii Sosliuk on 4/22/2017.
33 32 */
34 33 @Component
35   -@SqlDao
36 34 public class JpaUserCredentialsDao extends JpaAbstractDao<UserCredentialsEntity, UserCredentials> implements UserCredentialsDao {
37 35
38 36 @Autowired
... ...
... ... @@ -27,7 +27,6 @@ import org.thingsboard.server.dao.DaoUtil;
27 27 import org.thingsboard.server.dao.model.sql.UserEntity;
28 28 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
29 29 import org.thingsboard.server.dao.user.UserDao;
30   -import org.thingsboard.server.dao.util.SqlDao;
31 30
32 31 import java.util.Objects;
33 32 import java.util.UUID;
... ... @@ -38,7 +37,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
38 37 * @author Valerii Sosliuk
39 38 */
40 39 @Component
41   -@SqlDao
42 40 public class JpaUserDao extends JpaAbstractSearchTextDao<UserEntity, User> implements UserDao {
43 41
44 42 @Autowired
... ...
... ... @@ -17,14 +17,12 @@ package org.thingsboard.server.dao.sql.user;
17 17
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sql.UserCredentialsEntity;
20   -import org.thingsboard.server.dao.util.SqlDao;
21 20
22 21 import java.util.UUID;
23 22
24 23 /**
25 24 * Created by Valerii Sosliuk on 4/22/2017.
26 25 */
27   -@SqlDao
28 26 public interface UserCredentialsRepository extends CrudRepository<UserCredentialsEntity, UUID> {
29 27
30 28 UserCredentialsEntity findByUserId(UUID userId);
... ...
... ... @@ -22,14 +22,12 @@ import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.common.data.security.Authority;
24 24 import org.thingsboard.server.dao.model.sql.UserEntity;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import java.util.UUID;
28 27
29 28 /**
30 29 * @author Valerii Sosliuk
31 30 */
32   -@SqlDao
33 31 public interface UserRepository extends PagingAndSortingRepository<UserEntity, UUID> {
34 32
35 33 UserEntity findByEmail(String email);
... ...
... ... @@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.widget.WidgetType;
22 22 import org.thingsboard.server.dao.DaoUtil;
23 23 import org.thingsboard.server.dao.model.sql.WidgetTypeEntity;
24 24 import org.thingsboard.server.dao.sql.JpaAbstractDao;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25 import org.thingsboard.server.dao.widget.WidgetTypeDao;
27 26
28 27 import java.util.List;
... ... @@ -32,7 +31,6 @@ import java.util.UUID;
32 31 * Created by Valerii Sosliuk on 4/29/2017.
33 32 */
34 33 @Component
35   -@SqlDao
36 34 public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeEntity, WidgetType> implements WidgetTypeDao {
37 35
38 36 @Autowired
... ...
... ... @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
25 25 import org.thingsboard.server.dao.DaoUtil;
26 26 import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity;
27 27 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
28   -import org.thingsboard.server.dao.util.SqlDao;
29 28 import org.thingsboard.server.dao.widget.WidgetsBundleDao;
30 29
31 30 import java.util.Objects;
... ... @@ -37,7 +36,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
37 36 * Created by Valerii Sosliuk on 4/23/2017.
38 37 */
39 38 @Component
40   -@SqlDao
41 39 public class JpaWidgetsBundleDao extends JpaAbstractSearchTextDao<WidgetsBundleEntity, WidgetsBundle> implements WidgetsBundleDao {
42 40
43 41 @Autowired
... ...
... ... @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.sql.widget;
17 17
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sql.WidgetTypeEntity;
20   -import org.thingsboard.server.dao.util.SqlDao;
21 20
22 21 import java.util.List;
23 22 import java.util.UUID;
... ... @@ -25,7 +24,6 @@ import java.util.UUID;
25 24 /**
26 25 * Created by Valerii Sosliuk on 4/29/2017.
27 26 */
28   -@SqlDao
29 27 public interface WidgetTypeRepository extends CrudRepository<WidgetTypeEntity, UUID> {
30 28
31 29 List<WidgetTypeEntity> findByTenantIdAndBundleAlias(UUID tenantId, String bundleAlias);
... ...
... ... @@ -21,14 +21,12 @@ import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 22 import org.springframework.data.repository.query.Param;
23 23 import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity;
24   -import org.thingsboard.server.dao.util.SqlDao;
25 24
26 25 import java.util.UUID;
27 26
28 27 /**
29 28 * Created by Valerii Sosliuk on 4/23/2017.
30 29 */
31   -@SqlDao
32 30 public interface WidgetsBundleRepository extends PagingAndSortingRepository<WidgetsBundleEntity, UUID> {
33 31
34 32 WidgetsBundleEntity findWidgetsBundleByTenantIdAndAlias(UUID tenantId, String alias);
... ...
... ... @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.sqlts;
17 17
18 18 import com.google.common.util.concurrent.Futures;
19 19 import com.google.common.util.concurrent.ListenableFuture;
20   -import com.google.common.util.concurrent.ListeningExecutorService;
21 20 import com.google.common.util.concurrent.MoreExecutors;
22 21 import com.google.common.util.concurrent.SettableFuture;
23 22 import lombok.extern.slf4j.Slf4j;
... ... @@ -33,7 +32,6 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
33 32 import org.thingsboard.server.common.stats.StatsFactory;
34 33 import org.thingsboard.server.dao.DaoUtil;
35 34 import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
36   -import org.thingsboard.server.dao.sql.TbSqlBlockingQueue;
37 35 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
38 36 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
39 37 import org.thingsboard.server.dao.sqlts.insert.InsertTsRepository;
... ... @@ -64,7 +62,6 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
64 62
65 63 @PostConstruct
66 64 protected void init() {
67   - super.init();
68 65 TbSqlBlockingQueueParams tsParams = TbSqlBlockingQueueParams.builder()
69 66 .logName("TS")
70 67 .batchSize(tsBatchSize)
... ... @@ -80,7 +77,6 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
80 77
81 78 @PreDestroy
82 79 protected void destroy() {
83   - super.destroy();
84 80 if (tsQueue != null) {
85 81 tsQueue.destroy();
86 82 }
... ... @@ -99,26 +95,6 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
99 95 }
100 96
101 97 @Override
102   - public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
103   - return getSaveLatestFuture(entityId, tsKvEntry);
104   - }
105   -
106   - @Override
107   - public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
108   - return getRemoveLatestFuture(entityId, query);
109   - }
110   -
111   - @Override
112   - public ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key) {
113   - return getFindLatestFuture(entityId, key);
114   - }
115   -
116   - @Override
117   - public ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId) {
118   - return getFindAllLatestFuture(entityId);
119   - }
120   -
121   - @Override
122 98 public ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) {
123 99 return Futures.immediateFuture(null);
124 100 }
... ... @@ -134,7 +110,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
134 110 }
135 111
136 112 @Override
137   - protected ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query) {
  113 + public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) {
138 114 if (query.getAggregation() == Aggregation.NONE) {
139 115 return findAllAsyncWithLimit(entityId, query);
140 116 } else {
... ... @@ -151,8 +127,7 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
151 127 }
152 128 }
153 129
154   - @Override
155   - protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) {
  130 + private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) {
156 131 Integer keyId = getOrSaveKeyId(query.getKey());
157 132 List<TsKvEntity> tsKvEntities = tsKvRepository.findAllWithLimit(
158 133 entityId.getId(),
... ...
... ... @@ -16,96 +16,28 @@
16 16 package org.thingsboard.server.dao.sqlts;
17 17
18 18 import com.google.common.base.Function;
19   -import com.google.common.collect.Lists;
20   -import com.google.common.util.concurrent.FutureCallback;
21 19 import com.google.common.util.concurrent.Futures;
22 20 import com.google.common.util.concurrent.ListenableFuture;
23   -import com.google.common.util.concurrent.MoreExecutors;
24 21 import lombok.extern.slf4j.Slf4j;
25   -import org.hibernate.exception.ConstraintViolationException;
26 22 import org.springframework.beans.factory.annotation.Autowired;
27 23 import org.springframework.beans.factory.annotation.Value;
28 24 import org.thingsboard.server.common.data.id.EntityId;
29 25 import org.thingsboard.server.common.data.id.TenantId;
30   -import org.thingsboard.server.common.data.kv.Aggregation;
31   -import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
32   -import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
33   -import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
34 26 import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
35   -import org.thingsboard.server.common.data.kv.StringDataEntry;
36 27 import org.thingsboard.server.common.data.kv.TsKvEntry;
37   -import org.thingsboard.server.common.stats.StatsFactory;
38   -import org.thingsboard.server.dao.DaoUtil;
39   -import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionary;
40   -import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionaryCompositeKey;
41   -import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey;
42   -import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
43   -import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService;
44 28 import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
45   -import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
46   -import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
47   -import org.thingsboard.server.dao.sqlts.dictionary.TsKvDictionaryRepository;
48   -import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository;
49   -import org.thingsboard.server.dao.sqlts.latest.SearchTsKvLatestRepository;
50   -import org.thingsboard.server.dao.sqlts.latest.TsKvLatestRepository;
51   -import org.thingsboard.server.dao.timeseries.SimpleListenableFuture;
52 29
53 30 import javax.annotation.Nullable;
54   -import javax.annotation.PostConstruct;
55   -import javax.annotation.PreDestroy;
56   -import java.util.ArrayList;
57   -import java.util.HashMap;
58 31 import java.util.List;
59   -import java.util.Map;
60 32 import java.util.Objects;
61   -import java.util.Optional;
62   -import java.util.concurrent.ConcurrentHashMap;
63   -import java.util.concurrent.ConcurrentMap;
64   -import java.util.concurrent.ExecutionException;
65   -import java.util.concurrent.locks.ReentrantLock;
66 33 import java.util.stream.Collectors;
67 34
68 35 @Slf4j
69   -public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningExecutorService {
70   -
71   - private static final String DESC_ORDER = "DESC";
72   -
73   - private final ConcurrentMap<String, Integer> tsKvDictionaryMap = new ConcurrentHashMap<>();
74   -
75   - private static final ReentrantLock tsCreationLock = new ReentrantLock();
76   -
77   - @Autowired
78   - private TsKvLatestRepository tsKvLatestRepository;
79   -
80   - @Autowired
81   - private SearchTsKvLatestRepository searchTsKvLatestRepository;
82   -
83   - @Autowired
84   - private InsertLatestTsRepository insertLatestTsRepository;
85   -
86   - @Autowired
87   - private TsKvDictionaryRepository dictionaryRepository;
88   -
89   - private TbSqlBlockingQueueWrapper<TsKvLatestEntity> tsLatestQueue;
90   -
91   - @Value("${sql.ts_latest.batch_size:1000}")
92   - private int tsLatestBatchSize;
93   -
94   - @Value("${sql.ts_latest.batch_max_delay:100}")
95   - private long tsLatestMaxDelay;
96   -
97   - @Value("${sql.ts_latest.stats_print_interval_ms:1000}")
98   - private long tsLatestStatsPrintIntervalMs;
99   -
100   - @Value("${sql.ts_latest.batch_threads:4}")
101   - private int tsLatestBatchThreads;
  36 +public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseriesDao implements AggregationTimeseriesDao {
102 37
103 38 @Autowired
104 39 protected ScheduledLogExecutorComponent logExecutor;
105 40
106   - @Autowired
107   - private StatsFactory statsFactory;
108   -
109 41 @Value("${sql.ts.batch_size:1000}")
110 42 protected int tsBatchSize;
111 43
... ... @@ -121,44 +53,10 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx
121 53 @Value("${sql.timescale.batch_threads:4}")
122 54 protected int timescaleBatchThreads;
123 55
124   - @PostConstruct
125   - protected void init() {
126   - TbSqlBlockingQueueParams tsLatestParams = TbSqlBlockingQueueParams.builder()
127   - .logName("TS Latest")
128   - .batchSize(tsLatestBatchSize)
129   - .maxDelay(tsLatestMaxDelay)
130   - .statsPrintIntervalMs(tsLatestStatsPrintIntervalMs)
131   - .statsNamePrefix("ts.latest")
132   - .build();
133   -
134   - java.util.function.Function<TsKvLatestEntity, Integer> hashcodeFunction = entity -> entity.getEntityId().hashCode();
135   - tsLatestQueue = new TbSqlBlockingQueueWrapper<>(tsLatestParams, hashcodeFunction, tsLatestBatchThreads, statsFactory);
136   -
137   - tsLatestQueue.init(logExecutor, v -> {
138   - Map<TsKey, TsKvLatestEntity> trueLatest = new HashMap<>();
139   - v.forEach(ts -> {
140   - TsKey key = new TsKey(ts.getEntityId(), ts.getKey());
141   - TsKvLatestEntity old = trueLatest.get(key);
142   - if (old == null || old.getTs() < ts.getTs()) {
143   - trueLatest.put(key, ts);
144   - }
145   - });
146   - List<TsKvLatestEntity> latestEntities = new ArrayList<>(trueLatest.values());
147   - insertLatestTsRepository.saveOrUpdate(latestEntities);
148   - });
149   - }
150   -
151   - @PreDestroy
152   - protected void destroy() {
153   - if (tsLatestQueue != null) {
154   - tsLatestQueue.destroy();
155   - }
156   - }
157   -
158 56 protected ListenableFuture<List<TsKvEntry>> processFindAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
159 57 List<ListenableFuture<List<TsKvEntry>>> futures = queries
160 58 .stream()
161   - .map(query -> findAllAsync(entityId, query))
  59 + .map(query -> findAllAsync(tenantId, entityId, query))
162 60 .collect(Collectors.toList());
163 61 return Futures.transform(Futures.allAsList(futures), new Function<List<List<TsKvEntry>>, List<TsKvEntry>>() {
164 62 @Nullable
... ... @@ -174,168 +72,4 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx
174 72 }
175 73 }, service);
176 74 }
177   -
178   - protected abstract ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query);
179   -
180   - protected abstract ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query);
181   -
182   - protected ListenableFuture<List<TsKvEntry>> getTskvEntriesFuture(ListenableFuture<List<Optional<TsKvEntry>>> future) {
183   - return Futures.transform(future, new Function<List<Optional<TsKvEntry>>, List<TsKvEntry>>() {
184   - @Nullable
185   - @Override
186   - public List<TsKvEntry> apply(@Nullable List<Optional<TsKvEntry>> results) {
187   - if (results == null || results.isEmpty()) {
188   - return null;
189   - }
190   - return results.stream()
191   - .filter(Optional::isPresent)
192   - .map(Optional::get)
193   - .collect(Collectors.toList());
194   - }
195   - }, service);
196   - }
197   -
198   - protected ListenableFuture<List<TsKvEntry>> findNewLatestEntryFuture(EntityId entityId, DeleteTsKvQuery query) {
199   - long startTs = 0;
200   - long endTs = query.getStartTs() - 1;
201   - ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1,
202   - Aggregation.NONE, DESC_ORDER);
203   - return findAllAsync(entityId, findNewLatestQuery);
204   - }
205   -
206   - protected ListenableFuture<TsKvEntry> getFindLatestFuture(EntityId entityId, String key) {
207   - TsKvLatestCompositeKey compositeKey =
208   - new TsKvLatestCompositeKey(
209   - entityId.getId(),
210   - getOrSaveKeyId(key));
211   - Optional<TsKvLatestEntity> entry = tsKvLatestRepository.findById(compositeKey);
212   - TsKvEntry result;
213   - if (entry.isPresent()) {
214   - TsKvLatestEntity tsKvLatestEntity = entry.get();
215   - tsKvLatestEntity.setStrKey(key);
216   - result = DaoUtil.getData(tsKvLatestEntity);
217   - } else {
218   - result = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null));
219   - }
220   - return Futures.immediateFuture(result);
221   - }
222   -
223   - protected ListenableFuture<Void> getRemoveLatestFuture(EntityId entityId, DeleteTsKvQuery query) {
224   - ListenableFuture<TsKvEntry> latestFuture = getFindLatestFuture(entityId, query.getKey());
225   -
226   - ListenableFuture<Boolean> booleanFuture = Futures.transform(latestFuture, tsKvEntry -> {
227   - long ts = tsKvEntry.getTs();
228   - return ts > query.getStartTs() && ts <= query.getEndTs();
229   - }, service);
230   -
231   - ListenableFuture<Void> removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
232   - if (isRemove) {
233   - TsKvLatestEntity latestEntity = new TsKvLatestEntity();
234   - latestEntity.setEntityId(entityId.getId());
235   - latestEntity.setKey(getOrSaveKeyId(query.getKey()));
236   - return service.submit(() -> {
237   - tsKvLatestRepository.delete(latestEntity);
238   - return null;
239   - });
240   - }
241   - return Futures.immediateFuture(null);
242   - }, service);
243   -
244   - final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
245   - Futures.addCallback(removedLatestFuture, new FutureCallback<Void>() {
246   - @Override
247   - public void onSuccess(@Nullable Void result) {
248   - if (query.getRewriteLatestIfDeleted()) {
249   - ListenableFuture<Void> savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
250   - if (isRemove) {
251   - return getNewLatestEntryFuture(entityId, query);
252   - }
253   - return Futures.immediateFuture(null);
254   - }, service);
255   -
256   - try {
257   - resultFuture.set(savedLatestFuture.get());
258   - } catch (InterruptedException | ExecutionException e) {
259   - log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e);
260   - }
261   - } else {
262   - resultFuture.set(null);
263   - }
264   - }
265   -
266   - @Override
267   - public void onFailure(Throwable t) {
268   - log.warn("[{}] Failed to process remove of the latest value", entityId, t);
269   - }
270   - }, MoreExecutors.directExecutor());
271   - return resultFuture;
272   - }
273   -
274   - protected ListenableFuture<List<TsKvEntry>> getFindAllLatestFuture(EntityId entityId) {
275   - return Futures.immediateFuture(
276   - DaoUtil.convertDataList(Lists.newArrayList(
277   - searchTsKvLatestRepository.findAllByEntityId(entityId.getId()))));
278   - }
279   -
280   - protected ListenableFuture<Void> getSaveLatestFuture(EntityId entityId, TsKvEntry tsKvEntry) {
281   - TsKvLatestEntity latestEntity = new TsKvLatestEntity();
282   - latestEntity.setEntityId(entityId.getId());
283   - latestEntity.setTs(tsKvEntry.getTs());
284   - latestEntity.setKey(getOrSaveKeyId(tsKvEntry.getKey()));
285   - latestEntity.setStrValue(tsKvEntry.getStrValue().orElse(null));
286   - latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
287   - latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
288   - latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
289   - latestEntity.setJsonValue(tsKvEntry.getJsonValue().orElse(null));
290   -
291   - return tsLatestQueue.add(latestEntity);
292   - }
293   -
294   - protected Integer getOrSaveKeyId(String strKey) {
295   - Integer keyId = tsKvDictionaryMap.get(strKey);
296   - if (keyId == null) {
297   - Optional<TsKvDictionary> tsKvDictionaryOptional;
298   - tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
299   - if (!tsKvDictionaryOptional.isPresent()) {
300   - tsCreationLock.lock();
301   - try {
302   - tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
303   - if (!tsKvDictionaryOptional.isPresent()) {
304   - TsKvDictionary tsKvDictionary = new TsKvDictionary();
305   - tsKvDictionary.setKey(strKey);
306   - try {
307   - TsKvDictionary saved = dictionaryRepository.save(tsKvDictionary);
308   - tsKvDictionaryMap.put(saved.getKey(), saved.getKeyId());
309   - keyId = saved.getKeyId();
310   - } catch (ConstraintViolationException e) {
311   - tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
312   - TsKvDictionary dictionary = tsKvDictionaryOptional.orElseThrow(() -> new RuntimeException("Failed to get TsKvDictionary entity from DB!"));
313   - tsKvDictionaryMap.put(dictionary.getKey(), dictionary.getKeyId());
314   - keyId = dictionary.getKeyId();
315   - }
316   - } else {
317   - keyId = tsKvDictionaryOptional.get().getKeyId();
318   - }
319   - } finally {
320   - tsCreationLock.unlock();
321   - }
322   - } else {
323   - keyId = tsKvDictionaryOptional.get().getKeyId();
324   - tsKvDictionaryMap.put(strKey, keyId);
325   - }
326   - }
327   - return keyId;
328   - }
329   -
330   - private ListenableFuture<Void> getNewLatestEntryFuture(EntityId entityId, DeleteTsKvQuery query) {
331   - ListenableFuture<List<TsKvEntry>> future = findNewLatestEntryFuture(entityId, query);
332   - return Futures.transformAsync(future, entryList -> {
333   - if (entryList.size() == 1) {
334   - return getSaveLatestFuture(entityId, entryList.get(0));
335   - } else {
336   - log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey());
337   - }
338   - return Futures.immediateFuture(null);
339   - }, service);
340   - }
341 75 }
... ...
  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.dao.sqlts;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
  22 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  23 +
  24 +import java.util.List;
  25 +
  26 +public interface AggregationTimeseriesDao {
  27 +
  28 + ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query);
  29 +}
... ...
  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.dao.sqlts;
  17 +
  18 +import com.google.common.base.Function;
  19 +import com.google.common.util.concurrent.Futures;
  20 +import com.google.common.util.concurrent.ListenableFuture;
  21 +import lombok.extern.slf4j.Slf4j;
  22 +import org.hibernate.exception.ConstraintViolationException;
  23 +import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  25 +import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionary;
  26 +import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionaryCompositeKey;
  27 +import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService;
  28 +import org.thingsboard.server.dao.sqlts.dictionary.TsKvDictionaryRepository;
  29 +
  30 +import javax.annotation.Nullable;
  31 +import java.util.List;
  32 +import java.util.Optional;
  33 +import java.util.concurrent.ConcurrentHashMap;
  34 +import java.util.concurrent.ConcurrentMap;
  35 +import java.util.concurrent.locks.ReentrantLock;
  36 +import java.util.stream.Collectors;
  37 +
  38 +@Slf4j
  39 +public abstract class BaseAbstractSqlTimeseriesDao extends JpaAbstractDaoListeningExecutorService {
  40 +
  41 + private final ConcurrentMap<String, Integer> tsKvDictionaryMap = new ConcurrentHashMap<>();
  42 +
  43 + protected static final ReentrantLock tsCreationLock = new ReentrantLock();
  44 +
  45 + @Autowired
  46 + protected TsKvDictionaryRepository dictionaryRepository;
  47 +
  48 + protected Integer getOrSaveKeyId(String strKey) {
  49 + Integer keyId = tsKvDictionaryMap.get(strKey);
  50 + if (keyId == null) {
  51 + Optional<TsKvDictionary> tsKvDictionaryOptional;
  52 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  53 + if (!tsKvDictionaryOptional.isPresent()) {
  54 + tsCreationLock.lock();
  55 + try {
  56 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  57 + if (!tsKvDictionaryOptional.isPresent()) {
  58 + TsKvDictionary tsKvDictionary = new TsKvDictionary();
  59 + tsKvDictionary.setKey(strKey);
  60 + try {
  61 + TsKvDictionary saved = dictionaryRepository.save(tsKvDictionary);
  62 + tsKvDictionaryMap.put(saved.getKey(), saved.getKeyId());
  63 + keyId = saved.getKeyId();
  64 + } catch (ConstraintViolationException e) {
  65 + tsKvDictionaryOptional = dictionaryRepository.findById(new TsKvDictionaryCompositeKey(strKey));
  66 + TsKvDictionary dictionary = tsKvDictionaryOptional.orElseThrow(() -> new RuntimeException("Failed to get TsKvDictionary entity from DB!"));
  67 + tsKvDictionaryMap.put(dictionary.getKey(), dictionary.getKeyId());
  68 + keyId = dictionary.getKeyId();
  69 + }
  70 + } else {
  71 + keyId = tsKvDictionaryOptional.get().getKeyId();
  72 + }
  73 + } finally {
  74 + tsCreationLock.unlock();
  75 + }
  76 + } else {
  77 + keyId = tsKvDictionaryOptional.get().getKeyId();
  78 + tsKvDictionaryMap.put(strKey, keyId);
  79 + }
  80 + }
  81 + return keyId;
  82 + }
  83 +
  84 + protected ListenableFuture<List<TsKvEntry>> getTskvEntriesFuture(ListenableFuture<List<Optional<TsKvEntry>>> future) {
  85 + return Futures.transform(future, new Function<List<Optional<TsKvEntry>>, List<TsKvEntry>>() {
  86 + @Nullable
  87 + @Override
  88 + public List<TsKvEntry> apply(@Nullable List<Optional<TsKvEntry>> results) {
  89 + if (results == null || results.isEmpty()) {
  90 + return null;
  91 + }
  92 + return results.stream()
  93 + .filter(Optional::isPresent)
  94 + .map(Optional::get)
  95 + .collect(Collectors.toList());
  96 + }
  97 + }, service);
  98 + }
  99 +}
... ...
  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.dao.sqlts;
  17 +
  18 +import com.google.common.collect.Lists;
  19 +import com.google.common.util.concurrent.FutureCallback;
  20 +import com.google.common.util.concurrent.Futures;
  21 +import com.google.common.util.concurrent.ListenableFuture;
  22 +import com.google.common.util.concurrent.MoreExecutors;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.springframework.beans.factory.annotation.Autowired;
  25 +import org.springframework.beans.factory.annotation.Value;
  26 +import org.springframework.stereotype.Component;
  27 +import org.thingsboard.server.common.data.id.EntityId;
  28 +import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.kv.Aggregation;
  30 +import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
  31 +import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  32 +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
  33 +import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
  34 +import org.thingsboard.server.common.data.kv.StringDataEntry;
  35 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  36 +import org.thingsboard.server.common.stats.StatsFactory;
  37 +import org.thingsboard.server.dao.DaoUtil;
  38 +import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey;
  39 +import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
  40 +import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
  41 +import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
  42 +import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
  43 +import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository;
  44 +import org.thingsboard.server.dao.sqlts.latest.SearchTsKvLatestRepository;
  45 +import org.thingsboard.server.dao.sqlts.latest.TsKvLatestRepository;
  46 +import org.thingsboard.server.dao.timeseries.SimpleListenableFuture;
  47 +import org.thingsboard.server.dao.timeseries.TimeseriesLatestDao;
  48 +import org.thingsboard.server.dao.util.SqlTsLatestAnyDao;
  49 +
  50 +import javax.annotation.Nullable;
  51 +import javax.annotation.PostConstruct;
  52 +import javax.annotation.PreDestroy;
  53 +import java.util.ArrayList;
  54 +import java.util.HashMap;
  55 +import java.util.List;
  56 +import java.util.Map;
  57 +import java.util.Optional;
  58 +import java.util.concurrent.ExecutionException;
  59 +
  60 +@Slf4j
  61 +@Component
  62 +@SqlTsLatestAnyDao
  63 +public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao implements TimeseriesLatestDao {
  64 +
  65 + private static final String DESC_ORDER = "DESC";
  66 +
  67 + @Autowired
  68 + private TsKvLatestRepository tsKvLatestRepository;
  69 +
  70 + @Autowired
  71 + protected AggregationTimeseriesDao aggregationTimeseriesDao;
  72 +
  73 + @Autowired
  74 + private SearchTsKvLatestRepository searchTsKvLatestRepository;
  75 +
  76 + @Autowired
  77 + private InsertLatestTsRepository insertLatestTsRepository;
  78 +
  79 + private TbSqlBlockingQueueWrapper<TsKvLatestEntity> tsLatestQueue;
  80 +
  81 + @Value("${sql.ts_latest.batch_size:1000}")
  82 + private int tsLatestBatchSize;
  83 +
  84 + @Value("${sql.ts_latest.batch_max_delay:100}")
  85 + private long tsLatestMaxDelay;
  86 +
  87 + @Value("${sql.ts_latest.stats_print_interval_ms:1000}")
  88 + private long tsLatestStatsPrintIntervalMs;
  89 +
  90 + @Value("${sql.ts_latest.batch_threads:4}")
  91 + private int tsLatestBatchThreads;
  92 +
  93 + @Autowired
  94 + protected ScheduledLogExecutorComponent logExecutor;
  95 +
  96 + @Autowired
  97 + private StatsFactory statsFactory;
  98 +
  99 + @PostConstruct
  100 + protected void init() {
  101 + TbSqlBlockingQueueParams tsLatestParams = TbSqlBlockingQueueParams.builder()
  102 + .logName("TS Latest")
  103 + .batchSize(tsLatestBatchSize)
  104 + .maxDelay(tsLatestMaxDelay)
  105 + .statsPrintIntervalMs(tsLatestStatsPrintIntervalMs)
  106 + .statsNamePrefix("ts.latest")
  107 + .build();
  108 +
  109 + java.util.function.Function<TsKvLatestEntity, Integer> hashcodeFunction = entity -> entity.getEntityId().hashCode();
  110 + tsLatestQueue = new TbSqlBlockingQueueWrapper<>(tsLatestParams, hashcodeFunction, tsLatestBatchThreads, statsFactory);
  111 +
  112 + tsLatestQueue.init(logExecutor, v -> {
  113 + Map<TsKey, TsKvLatestEntity> trueLatest = new HashMap<>();
  114 + v.forEach(ts -> {
  115 + TsKey key = new TsKey(ts.getEntityId(), ts.getKey());
  116 + TsKvLatestEntity old = trueLatest.get(key);
  117 + if (old == null || old.getTs() < ts.getTs()) {
  118 + trueLatest.put(key, ts);
  119 + }
  120 + });
  121 + List<TsKvLatestEntity> latestEntities = new ArrayList<>(trueLatest.values());
  122 + insertLatestTsRepository.saveOrUpdate(latestEntities);
  123 + });
  124 + }
  125 +
  126 + @PreDestroy
  127 + protected void destroy() {
  128 + if (tsLatestQueue != null) {
  129 + tsLatestQueue.destroy();
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
  135 + return getSaveLatestFuture(entityId, tsKvEntry);
  136 + }
  137 +
  138 + @Override
  139 + public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  140 + return getRemoveLatestFuture(tenantId, entityId, query);
  141 + }
  142 +
  143 + @Override
  144 + public ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key) {
  145 + return getFindLatestFuture(entityId, key);
  146 + }
  147 +
  148 + @Override
  149 + public ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId) {
  150 + return getFindAllLatestFuture(entityId);
  151 + }
  152 +
  153 + private ListenableFuture<Void> getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  154 + ListenableFuture<List<TsKvEntry>> future = findNewLatestEntryFuture(tenantId, entityId, query);
  155 + return Futures.transformAsync(future, entryList -> {
  156 + if (entryList.size() == 1) {
  157 + return getSaveLatestFuture(entityId, entryList.get(0));
  158 + } else {
  159 + log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey());
  160 + }
  161 + return Futures.immediateFuture(null);
  162 + }, service);
  163 + }
  164 +
  165 + private ListenableFuture<List<TsKvEntry>> findNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  166 + long startTs = 0;
  167 + long endTs = query.getStartTs() - 1;
  168 + ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1,
  169 + Aggregation.NONE, DESC_ORDER);
  170 + return aggregationTimeseriesDao.findAllAsync(tenantId, entityId, findNewLatestQuery);
  171 + }
  172 +
  173 + protected ListenableFuture<TsKvEntry> getFindLatestFuture(EntityId entityId, String key) {
  174 + TsKvLatestCompositeKey compositeKey =
  175 + new TsKvLatestCompositeKey(
  176 + entityId.getId(),
  177 + getOrSaveKeyId(key));
  178 + Optional<TsKvLatestEntity> entry = tsKvLatestRepository.findById(compositeKey);
  179 + TsKvEntry result;
  180 + if (entry.isPresent()) {
  181 + TsKvLatestEntity tsKvLatestEntity = entry.get();
  182 + tsKvLatestEntity.setStrKey(key);
  183 + result = DaoUtil.getData(tsKvLatestEntity);
  184 + } else {
  185 + result = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null));
  186 + }
  187 + return Futures.immediateFuture(result);
  188 + }
  189 +
  190 + protected ListenableFuture<Void> getRemoveLatestFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  191 + ListenableFuture<TsKvEntry> latestFuture = getFindLatestFuture(entityId, query.getKey());
  192 +
  193 + ListenableFuture<Boolean> booleanFuture = Futures.transform(latestFuture, tsKvEntry -> {
  194 + long ts = tsKvEntry.getTs();
  195 + return ts > query.getStartTs() && ts <= query.getEndTs();
  196 + }, service);
  197 +
  198 + ListenableFuture<Void> removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
  199 + if (isRemove) {
  200 + TsKvLatestEntity latestEntity = new TsKvLatestEntity();
  201 + latestEntity.setEntityId(entityId.getId());
  202 + latestEntity.setKey(getOrSaveKeyId(query.getKey()));
  203 + return service.submit(() -> {
  204 + tsKvLatestRepository.delete(latestEntity);
  205 + return null;
  206 + });
  207 + }
  208 + return Futures.immediateFuture(null);
  209 + }, service);
  210 +
  211 + final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
  212 + Futures.addCallback(removedLatestFuture, new FutureCallback<Void>() {
  213 + @Override
  214 + public void onSuccess(@Nullable Void result) {
  215 + if (query.getRewriteLatestIfDeleted()) {
  216 + ListenableFuture<Void> savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
  217 + if (isRemove) {
  218 + return getNewLatestEntryFuture(tenantId, entityId, query);
  219 + }
  220 + return Futures.immediateFuture(null);
  221 + }, service);
  222 +
  223 + try {
  224 + resultFuture.set(savedLatestFuture.get());
  225 + } catch (InterruptedException | ExecutionException e) {
  226 + log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e);
  227 + }
  228 + } else {
  229 + resultFuture.set(null);
  230 + }
  231 + }
  232 +
  233 + @Override
  234 + public void onFailure(Throwable t) {
  235 + log.warn("[{}] Failed to process remove of the latest value", entityId, t);
  236 + }
  237 + }, MoreExecutors.directExecutor());
  238 + return resultFuture;
  239 + }
  240 +
  241 + protected ListenableFuture<List<TsKvEntry>> getFindAllLatestFuture(EntityId entityId) {
  242 + return Futures.immediateFuture(
  243 + DaoUtil.convertDataList(Lists.newArrayList(
  244 + searchTsKvLatestRepository.findAllByEntityId(entityId.getId()))));
  245 + }
  246 +
  247 + protected ListenableFuture<Void> getSaveLatestFuture(EntityId entityId, TsKvEntry tsKvEntry) {
  248 + TsKvLatestEntity latestEntity = new TsKvLatestEntity();
  249 + latestEntity.setEntityId(entityId.getId());
  250 + latestEntity.setTs(tsKvEntry.getTs());
  251 + latestEntity.setKey(getOrSaveKeyId(tsKvEntry.getKey()));
  252 + latestEntity.setStrValue(tsKvEntry.getStrValue().orElse(null));
  253 + latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
  254 + latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
  255 + latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
  256 + latestEntity.setJsonValue(tsKvEntry.getJsonValue().orElse(null));
  257 +
  258 + return tsLatestQueue.add(latestEntity);
  259 + }
  260 +
  261 +}
... ...
... ... @@ -18,11 +18,11 @@ package org.thingsboard.server.dao.sqlts.dictionary;
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionary;
20 20 import org.thingsboard.server.dao.model.sqlts.dictionary.TsKvDictionaryCompositeKey;
21   -import org.thingsboard.server.dao.util.SqlTsAnyDao;
  21 +import org.thingsboard.server.dao.util.SqlTsOrTsLatestAnyDao;
22 22
23 23 import java.util.Optional;
24 24
25   -@SqlTsAnyDao
  25 +@SqlTsOrTsLatestAnyDao
26 26 public interface TsKvDictionaryRepository extends CrudRepository<TsKvDictionary, TsKvDictionaryCompositeKey> {
27 27
28 28 Optional<TsKvDictionary> findByKeyId(int keyId);
... ...
... ... @@ -22,14 +22,14 @@ import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
22 22 import org.thingsboard.server.dao.sqlts.insert.AbstractInsertRepository;
23 23 import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository;
24 24 import org.thingsboard.server.dao.util.HsqlDao;
25   -import org.thingsboard.server.dao.util.SqlTsDao;
  25 +import org.thingsboard.server.dao.util.SqlTsLatestDao;
26 26
27 27 import java.sql.PreparedStatement;
28 28 import java.sql.SQLException;
29 29 import java.sql.Types;
30 30 import java.util.List;
31 31
32   -@SqlTsDao
  32 +@SqlTsLatestDao
33 33 @HsqlDao
34 34 @Repository
35 35 @Transactional
... ...
... ... @@ -23,7 +23,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult;
23 23 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
24 24 import org.thingsboard.server.dao.sqlts.insert.AbstractInsertRepository;
25 25 import org.thingsboard.server.dao.sqlts.insert.latest.InsertLatestTsRepository;
26   -import org.thingsboard.server.dao.util.PsqlTsAnyDao;
  26 +import org.thingsboard.server.dao.util.PsqlTsLatestAnyDao;
27 27
28 28 import java.sql.PreparedStatement;
29 29 import java.sql.SQLException;
... ... @@ -32,7 +32,7 @@ import java.util.ArrayList;
32 32 import java.util.List;
33 33
34 34
35   -@PsqlTsAnyDao
  35 +@PsqlTsLatestAnyDao
36 36 @Repository
37 37 @Transactional
38 38 public class PsqlLatestInsertTsRepository extends AbstractInsertRepository implements InsertLatestTsRepository {
... ...
... ... @@ -17,14 +17,14 @@ package org.thingsboard.server.dao.sqlts.latest;
17 17
18 18 import org.springframework.stereotype.Repository;
19 19 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
20   -import org.thingsboard.server.dao.util.SqlTsAnyDao;
  20 +import org.thingsboard.server.dao.util.SqlTsLatestAnyDao;
21 21
22 22 import javax.persistence.EntityManager;
23 23 import javax.persistence.PersistenceContext;
24 24 import java.util.List;
25 25 import java.util.UUID;
26 26
27   -@SqlTsAnyDao
  27 +@SqlTsLatestAnyDao
28 28 @Repository
29 29 public class SearchTsKvLatestRepository {
30 30
... ...
... ... @@ -18,9 +18,7 @@ package org.thingsboard.server.dao.sqlts.latest;
18 18 import org.springframework.data.repository.CrudRepository;
19 19 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey;
20 20 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
21   -import org.thingsboard.server.dao.util.SqlDao;
22 21
23   -@SqlDao
24 22 public interface TsKvLatestRepository extends CrudRepository<TsKvLatestEntity, TsKvLatestCompositeKey> {
25 23
26 24 }
... ...
... ... @@ -41,11 +41,10 @@ import java.util.Optional;
41 41 import java.util.concurrent.ConcurrentHashMap;
42 42 import java.util.concurrent.locks.ReentrantLock;
43 43
44   -
45 44 @Component
46 45 @Slf4j
47   -@SqlTsDao
48 46 @PsqlDao
  47 +@SqlTsDao
49 48 public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDao {
50 49
51 50 private final Map<Long, PsqlPartition> partitions = new ConcurrentHashMap<>();
... ...
... ... @@ -18,7 +18,7 @@ package org.thingsboard.server.dao.sqlts.timescale;
18 18 import org.springframework.scheduling.annotation.Async;
19 19 import org.springframework.stereotype.Repository;
20 20 import org.thingsboard.server.dao.model.sqlts.timescale.ts.TimescaleTsKvEntity;
21   -import org.thingsboard.server.dao.util.TimescaleDBTsDao;
  21 +import org.thingsboard.server.dao.util.TimescaleDBTsOrTsLatestDao;
22 22
23 23 import javax.persistence.EntityManager;
24 24 import javax.persistence.PersistenceContext;
... ... @@ -27,7 +27,7 @@ import java.util.UUID;
27 27 import java.util.concurrent.CompletableFuture;
28 28
29 29 @Repository
30   -@TimescaleDBTsDao
  30 +@TimescaleDBTsOrTsLatestDao
31 31 public class AggregationRepository {
32 32
33 33 public static final String FIND_AVG = "findAvg";
... ...
... ... @@ -72,7 +72,6 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
72 72
73 73 @PostConstruct
74 74 protected void init() {
75   - super.init();
76 75 TbSqlBlockingQueueParams tsParams = TbSqlBlockingQueueParams.builder()
77 76 .logName("TS Timescale")
78 77 .batchSize(tsBatchSize)
... ... @@ -89,14 +88,60 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
89 88
90 89 @PreDestroy
91 90 protected void destroy() {
92   - super.destroy();
93 91 if (tsQueue != null) {
94 92 tsQueue.destroy();
95 93 }
96 94 }
97 95
98 96 @Override
99   - protected ListenableFuture<List<TsKvEntry>> findAllAsync(EntityId entityId, ReadTsKvQuery query) {
  97 + public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
  98 + return processFindAllAsync(tenantId, entityId, queries);
  99 + }
  100 +
  101 + @Override
  102 + public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
  103 + String strKey = tsKvEntry.getKey();
  104 + Integer keyId = getOrSaveKeyId(strKey);
  105 + TimescaleTsKvEntity entity = new TimescaleTsKvEntity();
  106 + entity.setEntityId(entityId.getId());
  107 + entity.setTs(tsKvEntry.getTs());
  108 + entity.setKey(keyId);
  109 + entity.setStrValue(tsKvEntry.getStrValue().orElse(null));
  110 + entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
  111 + entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
  112 + entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
  113 + entity.setJsonValue(tsKvEntry.getJsonValue().orElse(null));
  114 +
  115 + log.trace("Saving entity to timescale db: {}", entity);
  116 + return tsQueue.add(entity);
  117 + }
  118 +
  119 + @Override
  120 + public ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) {
  121 + return Futures.immediateFuture(null);
  122 + }
  123 +
  124 + @Override
  125 + public ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  126 + String strKey = query.getKey();
  127 + Integer keyId = getOrSaveKeyId(strKey);
  128 + return service.submit(() -> {
  129 + tsKvRepository.delete(
  130 + entityId.getId(),
  131 + keyId,
  132 + query.getStartTs(),
  133 + query.getEndTs());
  134 + return null;
  135 + });
  136 + }
  137 +
  138 + @Override
  139 + public ListenableFuture<Void> removePartition(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  140 + return service.submit(() -> null);
  141 + }
  142 +
  143 + @Override
  144 + public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) {
100 145 if (query.getAggregation() == Aggregation.NONE) {
101 146 return findAllAsyncWithLimit(entityId, query);
102 147 } else {
... ... @@ -108,8 +153,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
108 153 }
109 154 }
110 155
111   - @Override
112   - protected ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) {
  156 + private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, ReadTsKvQuery query) {
113 157 String strKey = query.getKey();
114 158 Integer keyId = getOrSaveKeyId(strKey);
115 159 List<TimescaleTsKvEntity> timescaleTsKvEntities = tsKvRepository.findAllWithLimit(
... ... @@ -153,73 +197,6 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
153 197 }, MoreExecutors.directExecutor());
154 198 }
155 199
156   - @Override
157   - public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
158   - return processFindAllAsync(tenantId, entityId, queries);
159   - }
160   -
161   - @Override
162   - public ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key) {
163   - return getFindLatestFuture(entityId, key);
164   - }
165   -
166   - @Override
167   - public ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId) {
168   - return getFindAllLatestFuture(entityId);
169   - }
170   -
171   - @Override
172   - public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
173   - String strKey = tsKvEntry.getKey();
174   - Integer keyId = getOrSaveKeyId(strKey);
175   - TimescaleTsKvEntity entity = new TimescaleTsKvEntity();
176   - entity.setEntityId(entityId.getId());
177   - entity.setTs(tsKvEntry.getTs());
178   - entity.setKey(keyId);
179   - entity.setStrValue(tsKvEntry.getStrValue().orElse(null));
180   - entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
181   - entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
182   - entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
183   - entity.setJsonValue(tsKvEntry.getJsonValue().orElse(null));
184   -
185   - log.trace("Saving entity to timescale db: {}", entity);
186   - return tsQueue.add(entity);
187   - }
188   -
189   - @Override
190   - public ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) {
191   - return Futures.immediateFuture(null);
192   - }
193   -
194   - @Override
195   - public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
196   - return getSaveLatestFuture(entityId, tsKvEntry);
197   - }
198   -
199   - @Override
200   - public ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
201   - String strKey = query.getKey();
202   - Integer keyId = getOrSaveKeyId(strKey);
203   - return service.submit(() -> {
204   - tsKvRepository.delete(
205   - entityId.getId(),
206   - keyId,
207   - query.getStartTs(),
208   - query.getEndTs());
209   - return null;
210   - });
211   - }
212   -
213   - @Override
214   - public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
215   - return getRemoveLatestFuture(entityId, query);
216   - }
217   -
218   - @Override
219   - public ListenableFuture<Void> removePartition(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
220   - return service.submit(() -> null);
221   - }
222   -
223 200 private CompletableFuture<List<TimescaleTsKvEntity>> switchAggregation(String key, long startTs, long endTs, long timeBucket, Aggregation aggregation, UUID entityId) {
224 201 switch (aggregation) {
225 202 case AVG:
... ...
... ... @@ -23,12 +23,12 @@ import org.springframework.data.repository.query.Param;
23 23 import org.springframework.transaction.annotation.Transactional;
24 24 import org.thingsboard.server.dao.model.sqlts.timescale.ts.TimescaleTsKvCompositeKey;
25 25 import org.thingsboard.server.dao.model.sqlts.timescale.ts.TimescaleTsKvEntity;
26   -import org.thingsboard.server.dao.util.TimescaleDBTsDao;
  26 +import org.thingsboard.server.dao.util.TimescaleDBTsOrTsLatestDao;
27 27
28 28 import java.util.List;
29 29 import java.util.UUID;
30 30
31   -@TimescaleDBTsDao
  31 +@TimescaleDBTsOrTsLatestDao
32 32 public interface TsKvTimescaleRepository extends CrudRepository<TimescaleTsKvEntity, TimescaleTsKvCompositeKey> {
33 33
34 34 @Query("SELECT tskv FROM TimescaleTsKvEntity tskv WHERE tskv.entityId = :entityId " +
... ...
... ... @@ -24,13 +24,11 @@ import org.springframework.scheduling.annotation.Async;
24 24 import org.springframework.transaction.annotation.Transactional;
25 25 import org.thingsboard.server.dao.model.sqlts.ts.TsKvCompositeKey;
26 26 import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
27   -import org.thingsboard.server.dao.util.SqlDao;
28 27
29 28 import java.util.List;
30 29 import java.util.UUID;
31 30 import java.util.concurrent.CompletableFuture;
32 31
33   -@SqlDao
34 32 public interface TsKvRepository extends CrudRepository<TsKvEntity, TsKvCompositeKey> {
35 33
36 34 @Query("SELECT tskv FROM TsKvEntity tskv WHERE tskv.entityId = :entityId " +
... ...
  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.dao.timeseries;
  17 +
  18 +import com.datastax.oss.driver.api.core.cql.Row;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.apache.commons.lang3.StringUtils;
  21 +import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  22 +import org.thingsboard.server.common.data.kv.BooleanDataEntry;
  23 +import org.thingsboard.server.common.data.kv.DoubleDataEntry;
  24 +import org.thingsboard.server.common.data.kv.JsonDataEntry;
  25 +import org.thingsboard.server.common.data.kv.KvEntry;
  26 +import org.thingsboard.server.common.data.kv.LongDataEntry;
  27 +import org.thingsboard.server.common.data.kv.StringDataEntry;
  28 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  29 +import org.thingsboard.server.dao.model.ModelConstants;
  30 +import org.thingsboard.server.dao.nosql.CassandraAbstractAsyncDao;
  31 +
  32 +import java.util.ArrayList;
  33 +import java.util.List;
  34 +
  35 +@Slf4j
  36 +public abstract class AbstractCassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao {
  37 + public static final String DESC_ORDER = "DESC";
  38 + public static final String GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID = "Generated query [{}] for entityType {} and entityId {}";
  39 + public static final String INSERT_INTO = "INSERT INTO ";
  40 + public static final String SELECT_PREFIX = "SELECT ";
  41 + public static final String EQUALS_PARAM = " = ? ";
  42 +
  43 + public static KvEntry toKvEntry(Row row, String key) {
  44 + KvEntry kvEntry = null;
  45 + String strV = row.get(ModelConstants.STRING_VALUE_COLUMN, String.class);
  46 + if (strV != null) {
  47 + kvEntry = new StringDataEntry(key, strV);
  48 + } else {
  49 + Long longV = row.get(ModelConstants.LONG_VALUE_COLUMN, Long.class);
  50 + if (longV != null) {
  51 + kvEntry = new LongDataEntry(key, longV);
  52 + } else {
  53 + Double doubleV = row.get(ModelConstants.DOUBLE_VALUE_COLUMN, Double.class);
  54 + if (doubleV != null) {
  55 + kvEntry = new DoubleDataEntry(key, doubleV);
  56 + } else {
  57 + Boolean boolV = row.get(ModelConstants.BOOLEAN_VALUE_COLUMN, Boolean.class);
  58 + if (boolV != null) {
  59 + kvEntry = new BooleanDataEntry(key, boolV);
  60 + } else {
  61 + String jsonV = row.get(ModelConstants.JSON_VALUE_COLUMN, String.class);
  62 + if (StringUtils.isNoneEmpty(jsonV)) {
  63 + kvEntry = new JsonDataEntry(key, jsonV);
  64 + } else {
  65 + log.warn("All values in key-value row are nullable ");
  66 + }
  67 + }
  68 + }
  69 + }
  70 + }
  71 + return kvEntry;
  72 + }
  73 +
  74 + protected List<TsKvEntry> convertResultToTsKvEntryList(List<Row> rows) {
  75 + List<TsKvEntry> entries = new ArrayList<>(rows.size());
  76 + if (!rows.isEmpty()) {
  77 + rows.forEach(row -> entries.add(convertResultToTsKvEntry(row)));
  78 + }
  79 + return entries;
  80 + }
  81 +
  82 + private TsKvEntry convertResultToTsKvEntry(Row row) {
  83 + String key = row.getString(ModelConstants.KEY_COLUMN);
  84 + long ts = row.getLong(ModelConstants.TS_COLUMN);
  85 + return new BasicTsKvEntry(ts, toKvEntry(row, key));
  86 + }
  87 +
  88 +}
... ...
... ... @@ -60,6 +60,9 @@ public class BaseTimeseriesService implements TimeseriesService {
60 60 private TimeseriesDao timeseriesDao;
61 61
62 62 @Autowired
  63 + private TimeseriesLatestDao timeseriesLatestDao;
  64 +
  65 + @Autowired
63 66 private EntityViewService entityViewService;
64 67
65 68 @Override
... ... @@ -103,7 +106,7 @@ public class BaseTimeseriesService implements TimeseriesService {
103 106 return Futures.immediateFuture(new ArrayList<>());
104 107 }
105 108 }
106   - keys.forEach(key -> futures.add(timeseriesDao.findLatest(tenantId, entityId, key)));
  109 + keys.forEach(key -> futures.add(timeseriesLatestDao.findLatest(tenantId, entityId, key)));
107 110 return Futures.allAsList(futures);
108 111 }
109 112
... ... @@ -119,7 +122,7 @@ public class BaseTimeseriesService implements TimeseriesService {
119 122 return Futures.immediateFuture(new ArrayList<>());
120 123 }
121 124 } else {
122   - return timeseriesDao.findAllLatest(tenantId, entityId);
  125 + return timeseriesLatestDao.findAllLatest(tenantId, entityId);
123 126 }
124 127 }
125 128
... ... @@ -151,7 +154,7 @@ public class BaseTimeseriesService implements TimeseriesService {
151 154 throw new IncorrectParameterException("Telemetry data can't be stored for entity view. Read only");
152 155 }
153 156 futures.add(timeseriesDao.savePartition(tenantId, entityId, tsKvEntry.getTs(), tsKvEntry.getKey(), ttl));
154   - futures.add(timeseriesDao.saveLatest(tenantId, entityId, tsKvEntry));
  157 + futures.add(timeseriesLatestDao.saveLatest(tenantId, entityId, tsKvEntry));
155 158 futures.add(timeseriesDao.save(tenantId, entityId, tsKvEntry, ttl));
156 159 }
157 160
... ... @@ -187,7 +190,7 @@ public class BaseTimeseriesService implements TimeseriesService {
187 190
188 191 private void deleteAndRegisterFutures(TenantId tenantId, List<ListenableFuture<Void>> futures, EntityId entityId, DeleteTsKvQuery query) {
189 192 futures.add(timeseriesDao.remove(tenantId, entityId, query));
190   - futures.add(timeseriesDao.removeLatest(tenantId, entityId, query));
  193 + futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query));
191 194 futures.add(timeseriesDao.removePartition(tenantId, entityId, query));
192 195 }
193 196
... ...
... ... @@ -20,7 +20,6 @@ import com.datastax.oss.driver.api.core.cql.BoundStatement;
20 20 import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder;
21 21 import com.datastax.oss.driver.api.core.cql.PreparedStatement;
22 22 import com.datastax.oss.driver.api.core.cql.Row;
23   -import com.datastax.oss.driver.api.core.cql.Statement;
24 23 import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
25 24 import com.datastax.oss.driver.api.querybuilder.select.Select;
26 25 import com.google.common.base.Function;
... ... @@ -30,7 +29,6 @@ import com.google.common.util.concurrent.Futures;
30 29 import com.google.common.util.concurrent.ListenableFuture;
31 30 import com.google.common.util.concurrent.MoreExecutors;
32 31 import lombok.extern.slf4j.Slf4j;
33   -import org.apache.commons.lang3.StringUtils;
34 32 import org.springframework.beans.factory.annotation.Autowired;
35 33 import org.springframework.beans.factory.annotation.Value;
36 34 import org.springframework.core.env.Environment;
... ... @@ -39,21 +37,15 @@ import org.thingsboard.server.common.data.id.EntityId;
39 37 import org.thingsboard.server.common.data.id.TenantId;
40 38 import org.thingsboard.server.common.data.kv.Aggregation;
41 39 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
42   -import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
43   -import org.thingsboard.server.common.data.kv.BooleanDataEntry;
44 40 import org.thingsboard.server.common.data.kv.DataType;
45 41 import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
46   -import org.thingsboard.server.common.data.kv.DoubleDataEntry;
47   -import org.thingsboard.server.common.data.kv.JsonDataEntry;
48 42 import org.thingsboard.server.common.data.kv.KvEntry;
49   -import org.thingsboard.server.common.data.kv.LongDataEntry;
50 43 import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
51   -import org.thingsboard.server.common.data.kv.StringDataEntry;
52 44 import org.thingsboard.server.common.data.kv.TsKvEntry;
53 45 import org.thingsboard.server.dao.model.ModelConstants;
54   -import org.thingsboard.server.dao.nosql.CassandraAbstractAsyncDao;
55 46 import org.thingsboard.server.dao.nosql.TbResultSet;
56 47 import org.thingsboard.server.dao.nosql.TbResultSetFuture;
  48 +import org.thingsboard.server.dao.sqlts.AggregationTimeseriesDao;
57 49 import org.thingsboard.server.dao.util.NoSqlTsDao;
58 50
59 51 import javax.annotation.Nullable;
... ... @@ -68,7 +60,6 @@ import java.util.Arrays;
68 60 import java.util.Collections;
69 61 import java.util.List;
70 62 import java.util.Optional;
71   -import java.util.concurrent.ExecutionException;
72 63 import java.util.stream.Collectors;
73 64
74 65 import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal;
... ... @@ -79,16 +70,11 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal;
79 70 @Component
80 71 @Slf4j
81 72 @NoSqlTsDao
82   -public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implements TimeseriesDao {
  73 +public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesDao implements TimeseriesDao, AggregationTimeseriesDao {
83 74
84   - private static final int MIN_AGGREGATION_STEP_MS = 1000;
85   - public static final String INSERT_INTO = "INSERT INTO ";
86   - public static final String GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID = "Generated query [{}] for entityType {} and entityId {}";
87   - public static final String SELECT_PREFIX = "SELECT ";
88   - public static final String EQUALS_PARAM = " = ? ";
  75 + protected static final int MIN_AGGREGATION_STEP_MS = 1000;
89 76 public static final String ASC_ORDER = "ASC";
90   - public static final String DESC_ORDER = "DESC";
91   - private static List<Long> FIXED_PARTITION = Arrays.asList(new Long[]{0L});
  77 + protected static List<Long> FIXED_PARTITION = Arrays.asList(new Long[]{0L});
92 78
93 79 @Autowired
94 80 private Environment environment;
... ... @@ -106,13 +92,10 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
106 92
107 93 private PreparedStatement partitionInsertStmt;
108 94 private PreparedStatement partitionInsertTtlStmt;
109   - private PreparedStatement latestInsertStmt;
110 95 private PreparedStatement[] saveStmts;
111 96 private PreparedStatement[] saveTtlStmts;
112 97 private PreparedStatement[] fetchStmtsAsc;
113 98 private PreparedStatement[] fetchStmtsDesc;
114   - private PreparedStatement findLatestStmt;
115   - private PreparedStatement findAllLatestStmt;
116 99 private PreparedStatement deleteStmt;
117 100 private PreparedStatement deletePartitionStmt;
118 101
... ... @@ -157,8 +140,113 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
157 140 }, readResultsProcessingExecutor);
158 141 }
159 142
  143 + @Override
  144 + public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
  145 + List<ListenableFuture<Void>> futures = new ArrayList<>();
  146 + ttl = computeTtl(ttl);
  147 + long partition = toPartitionTs(tsKvEntry.getTs());
  148 + DataType type = tsKvEntry.getDataType();
  149 + if (setNullValuesEnabled) {
  150 + processSetNullValues(tenantId, entityId, tsKvEntry, ttl, futures, partition, type);
  151 + }
  152 + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getSaveStmt(type) : getSaveTtlStmt(type)).bind());
  153 + stmtBuilder.setString(0, entityId.getEntityType().name())
  154 + .setUuid(1, entityId.getId())
  155 + .setString(2, tsKvEntry.getKey())
  156 + .setLong(3, partition)
  157 + .setLong(4, tsKvEntry.getTs());
  158 + addValue(tsKvEntry, stmtBuilder, 5);
  159 + if (ttl > 0) {
  160 + stmtBuilder.setInt(6, (int) ttl);
  161 + }
  162 + BoundStatement stmt = stmtBuilder.build();
  163 + futures.add(getFuture(executeAsyncWrite(tenantId, stmt), rs -> null));
  164 + return Futures.transform(Futures.allAsList(futures), result -> null, MoreExecutors.directExecutor());
  165 + }
  166 +
  167 + @Override
  168 + public ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) {
  169 + if (isFixedPartitioning()) {
  170 + return Futures.immediateFuture(null);
  171 + }
  172 + ttl = computeTtl(ttl);
  173 + long partition = toPartitionTs(tsKvEntryTs);
  174 + log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key);
  175 + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind());
  176 + stmtBuilder.setString(0, entityId.getEntityType().name())
  177 + .setUuid(1, entityId.getId())
  178 + .setLong(2, partition)
  179 + .setString(3, key);
  180 + if (ttl > 0) {
  181 + stmtBuilder.setInt(4, (int) ttl);
  182 + }
  183 + BoundStatement stmt = stmtBuilder.build();
  184 + return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
  185 + }
160 186
161   - private ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) {
  187 + @Override
  188 + public ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  189 + long minPartition = toPartitionTs(query.getStartTs());
  190 + long maxPartition = toPartitionTs(query.getEndTs());
  191 +
  192 + TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
  193 +
  194 + final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
  195 + final ListenableFuture<List<Long>> partitionsListFuture = Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
  196 +
  197 + Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
  198 + @Override
  199 + public void onSuccess(@Nullable List<Long> partitions) {
  200 + QueryCursor cursor = new QueryCursor(entityId.getEntityType().name(), entityId.getId(), query, partitions);
  201 + deleteAsync(tenantId, cursor, resultFuture);
  202 + }
  203 +
  204 + @Override
  205 + public void onFailure(Throwable t) {
  206 + log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
  207 + }
  208 + }, readResultsProcessingExecutor);
  209 + return resultFuture;
  210 + }
  211 +
  212 + @Override
  213 + public ListenableFuture<Void> removePartition(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  214 + long minPartition = toPartitionTs(query.getStartTs());
  215 + long maxPartition = toPartitionTs(query.getEndTs());
  216 + if (minPartition == maxPartition) {
  217 + return Futures.immediateFuture(null);
  218 + } else {
  219 + TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
  220 +
  221 + final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
  222 + final ListenableFuture<List<Long>> partitionsListFuture = Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
  223 +
  224 + Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
  225 + @Override
  226 + public void onSuccess(@Nullable List<Long> partitions) {
  227 + int index = 0;
  228 + if (minPartition != query.getStartTs()) {
  229 + index = 1;
  230 + }
  231 + List<Long> partitionsToDelete = new ArrayList<>();
  232 + for (int i = index; i < partitions.size() - 1; i++) {
  233 + partitionsToDelete.add(partitions.get(i));
  234 + }
  235 + QueryCursor cursor = new QueryCursor(entityId.getEntityType().name(), entityId.getId(), query, partitionsToDelete);
  236 + deletePartitionAsync(tenantId, cursor, resultFuture);
  237 + }
  238 +
  239 + @Override
  240 + public void onFailure(Throwable t) {
  241 + log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
  242 + }
  243 + }, readResultsProcessingExecutor);
  244 + return resultFuture;
  245 + }
  246 + }
  247 +
  248 + @Override
  249 + public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) {
162 250 if (query.getAggregation() == Aggregation.NONE) {
163 251 return findAllAsyncWithLimit(tenantId, entityId, query);
164 252 } else {
... ... @@ -183,18 +271,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
183 271 }
184 272 }
185 273
186   - public boolean isFixedPartitioning() {
187   - return tsFormat.getTruncateUnit().equals(ChronoUnit.FOREVER);
188   - }
189   -
190   - private ListenableFuture<List<Long>> getPartitionsFuture(TenantId tenantId, ReadTsKvQuery query, EntityId entityId, long minPartition, long maxPartition) {
191   - if (isFixedPartitioning()) { //no need to fetch partitions from DB
192   - return Futures.immediateFuture(FIXED_PARTITION);
193   - }
194   - TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
195   - return Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
196   - }
197   -
198 274 private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(TenantId tenantId, EntityId entityId, ReadTsKvQuery query) {
199 275 long minPartition = toPartitionTs(query.getStartTs());
200 276 long maxPartition = toPartitionTs(query.getEndTs());
... ... @@ -287,10 +363,18 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
287 363
288 364 private AsyncFunction<TbResultSet, List<Long>> getPartitionsArrayFunction() {
289 365 return rs ->
290   - Futures.transform(rs.allRows(readResultsProcessingExecutor), rows ->
291   - rows.stream()
292   - .map(row -> row.getLong(ModelConstants.PARTITION_COLUMN)).collect(Collectors.toList()),
293   - readResultsProcessingExecutor);
  366 + Futures.transform(rs.allRows(readResultsProcessingExecutor), rows ->
  367 + rows.stream()
  368 + .map(row -> row.getLong(ModelConstants.PARTITION_COLUMN)).collect(Collectors.toList()),
  369 + readResultsProcessingExecutor);
  370 + }
  371 +
  372 + private ListenableFuture<List<Long>> getPartitionsFuture(TenantId tenantId, ReadTsKvQuery query, EntityId entityId, long minPartition, long maxPartition) {
  373 + if (isFixedPartitioning()) { //no need to fetch partitions from DB
  374 + return Futures.immediateFuture(FIXED_PARTITION);
  375 + }
  376 + TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
  377 + return Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
294 378 }
295 379
296 380 private AsyncFunction<List<Long>, List<TbResultSet>> getFetchChunksAsyncFunction(TenantId tenantId, EntityId entityId, String key, Aggregation aggregation, long startTs, long endTs) {
... ... @@ -319,49 +403,8 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
319 403 };
320 404 }
321 405
322   - @Override
323   - public ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key) {
324   - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getFindLatestStmt().bind());
325   - stmtBuilder.setString(0, entityId.getEntityType().name());
326   - stmtBuilder.setUuid(1, entityId.getId());
327   - stmtBuilder.setString(2, key);
328   - BoundStatement stmt = stmtBuilder.build();
329   - log.debug(GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID, stmt, entityId.getEntityType(), entityId.getId());
330   - return getFuture(executeAsyncRead(tenantId, stmt), rs -> convertResultToTsKvEntry(key, rs.one()));
331   - }
332   -
333   - @Override
334   - public ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId) {
335   - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getFindAllLatestStmt().bind());
336   - stmtBuilder.setString(0, entityId.getEntityType().name());
337   - stmtBuilder.setUuid(1, entityId.getId());
338   - BoundStatement stmt = stmtBuilder.build();
339   - log.debug(GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID, stmt, entityId.getEntityType(), entityId.getId());
340   - return getFutureAsync(executeAsyncRead(tenantId, stmt), rs -> convertAsyncResultSetToTsKvEntryList(rs));
341   - }
342   -
343   - @Override
344   - public ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl) {
345   - List<ListenableFuture<Void>> futures = new ArrayList<>();
346   - ttl = computeTtl(ttl);
347   - long partition = toPartitionTs(tsKvEntry.getTs());
348   - DataType type = tsKvEntry.getDataType();
349   - if (setNullValuesEnabled) {
350   - processSetNullValues(tenantId, entityId, tsKvEntry, ttl, futures, partition, type);
351   - }
352   - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getSaveStmt(type) : getSaveTtlStmt(type)).bind());
353   - stmtBuilder.setString(0, entityId.getEntityType().name())
354   - .setUuid(1, entityId.getId())
355   - .setString(2, tsKvEntry.getKey())
356   - .setLong(3, partition)
357   - .setLong(4, tsKvEntry.getTs());
358   - addValue(tsKvEntry, stmtBuilder, 5);
359   - if (ttl > 0) {
360   - stmtBuilder.setInt(6, (int) ttl);
361   - }
362   - BoundStatement stmt = stmtBuilder.build();
363   - futures.add(getFuture(executeAsyncWrite(tenantId, stmt), rs -> null));
364   - return Futures.transform(Futures.allAsList(futures), result -> null, MoreExecutors.directExecutor());
  406 + private boolean isFixedPartitioning() {
  407 + return tsFormat.getTruncateUnit().equals(ChronoUnit.FOREVER);
365 408 }
366 409
367 410 private void processSetNullValues(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl, List<ListenableFuture<Void>> futures, long partition, DataType type) {
... ... @@ -414,26 +457,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
414 457 return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
415 458 }
416 459
417   - @Override
418   - public ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) {
419   - if (isFixedPartitioning()) {
420   - return Futures.immediateFuture(null);
421   - }
422   - ttl = computeTtl(ttl);
423   - long partition = toPartitionTs(tsKvEntryTs);
424   - log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key);
425   - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind());
426   - stmtBuilder.setString(0, entityId.getEntityType().name())
427   - .setUuid(1, entityId.getId())
428   - .setLong(2, partition)
429   - .setString(3, key);
430   - if (ttl > 0) {
431   - stmtBuilder.setInt(4, (int) ttl);
432   - }
433   - BoundStatement stmt = stmtBuilder.build();
434   - return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
435   - }
436   -
437 460 private long computeTtl(long ttl) {
438 461 if (systemTtl > 0) {
439 462 if (ttl == 0) {
... ... @@ -445,53 +468,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
445 468 return ttl;
446 469 }
447 470
448   - @Override
449   - public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
450   - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getLatestStmt().bind());
451   - stmtBuilder.setString(0, entityId.getEntityType().name())
452   - .setUuid(1, entityId.getId())
453   - .setString(2, tsKvEntry.getKey())
454   - .setLong(3, tsKvEntry.getTs())
455   - .set(4, tsKvEntry.getBooleanValue().orElse(null), Boolean.class)
456   - .set(5, tsKvEntry.getStrValue().orElse(null), String.class)
457   - .set(6, tsKvEntry.getLongValue().orElse(null), Long.class)
458   - .set(7, tsKvEntry.getDoubleValue().orElse(null), Double.class);
459   - Optional<String> jsonV = tsKvEntry.getJsonValue();
460   - if (jsonV.isPresent()) {
461   - stmtBuilder.setString(8, tsKvEntry.getJsonValue().get());
462   - } else {
463   - stmtBuilder.setToNull(8);
464   - }
465   - BoundStatement stmt = stmtBuilder.build();
466   -
467   - return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
468   - }
469   -
470   - @Override
471   - public ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
472   - long minPartition = toPartitionTs(query.getStartTs());
473   - long maxPartition = toPartitionTs(query.getEndTs());
474   -
475   - TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
476   -
477   - final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
478   - final ListenableFuture<List<Long>> partitionsListFuture = Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
479   -
480   - Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
481   - @Override
482   - public void onSuccess(@Nullable List<Long> partitions) {
483   - QueryCursor cursor = new QueryCursor(entityId.getEntityType().name(), entityId.getId(), query, partitions);
484   - deleteAsync(tenantId, cursor, resultFuture);
485   - }
486   -
487   - @Override
488   - public void onFailure(Throwable t) {
489   - log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
490   - }
491   - }, readResultsProcessingExecutor);
492   - return resultFuture;
493   - }
494   -
495 471 private void deleteAsync(TenantId tenantId, final QueryCursor cursor, final SimpleListenableFuture<Void> resultFuture) {
496 472 if (!cursor.hasNextPartition()) {
497 473 resultFuture.set(null);
... ... @@ -534,119 +510,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
534 510 return deleteStmt;
535 511 }
536 512
537   - @Override
538   - public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
539   - ListenableFuture<TsKvEntry> latestEntryFuture = findLatest(tenantId, entityId, query.getKey());
540   -
541   - ListenableFuture<Boolean> booleanFuture = Futures.transform(latestEntryFuture, latestEntry -> {
542   - long ts = latestEntry.getTs();
543   - if (ts > query.getStartTs() && ts <= query.getEndTs()) {
544   - return true;
545   - } else {
546   - log.trace("Won't be deleted latest value for [{}], key - {}", entityId, query.getKey());
547   - }
548   - return false;
549   - }, readResultsProcessingExecutor);
550   -
551   - ListenableFuture<Void> removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
552   - if (isRemove) {
553   - return deleteLatest(tenantId, entityId, query.getKey());
554   - }
555   - return Futures.immediateFuture(null);
556   - }, readResultsProcessingExecutor);
557   -
558   - final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
559   - Futures.addCallback(removedLatestFuture, new FutureCallback<Void>() {
560   - @Override
561   - public void onSuccess(@Nullable Void result) {
562   - if (query.getRewriteLatestIfDeleted()) {
563   - ListenableFuture<Void> savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
564   - if (isRemove) {
565   - return getNewLatestEntryFuture(tenantId, entityId, query);
566   - }
567   - return Futures.immediateFuture(null);
568   - }, readResultsProcessingExecutor);
569   -
570   - try {
571   - resultFuture.set(savedLatestFuture.get());
572   - } catch (InterruptedException | ExecutionException e) {
573   - log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e);
574   - }
575   - } else {
576   - resultFuture.set(null);
577   - }
578   - }
579   -
580   - @Override
581   - public void onFailure(Throwable t) {
582   - log.warn("[{}] Failed to process remove of the latest value", entityId, t);
583   - }
584   - }, MoreExecutors.directExecutor());
585   - return resultFuture;
586   - }
587   -
588   - private ListenableFuture<Void> getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
589   - long startTs = 0;
590   - long endTs = query.getStartTs() - 1;
591   - ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1,
592   - Aggregation.NONE, DESC_ORDER);
593   - ListenableFuture<List<TsKvEntry>> future = findAllAsync(tenantId, entityId, findNewLatestQuery);
594   -
595   - return Futures.transformAsync(future, entryList -> {
596   - if (entryList.size() == 1) {
597   - return saveLatest(tenantId, entityId, entryList.get(0));
598   - } else {
599   - log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey());
600   - }
601   - return Futures.immediateFuture(null);
602   - }, readResultsProcessingExecutor);
603   - }
604   -
605   - private ListenableFuture<Void> deleteLatest(TenantId tenantId, EntityId entityId, String key) {
606   - Statement delete = QueryBuilder.deleteFrom(ModelConstants.TS_KV_LATEST_CF)
607   - .whereColumn(ModelConstants.ENTITY_TYPE_COLUMN).isEqualTo(literal(entityId.getEntityType().name()))
608   - .whereColumn(ModelConstants.ENTITY_ID_COLUMN).isEqualTo(literal(entityId.getId()))
609   - .whereColumn(ModelConstants.KEY_COLUMN).isEqualTo(literal(key)).build();
610   - log.debug("Remove request: {}", delete.toString());
611   - return getFuture(executeAsyncWrite(tenantId, delete), rs -> null);
612   - }
613   -
614   - @Override
615   - public ListenableFuture<Void> removePartition(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
616   - long minPartition = toPartitionTs(query.getStartTs());
617   - long maxPartition = toPartitionTs(query.getEndTs());
618   - if (minPartition == maxPartition) {
619   - return Futures.immediateFuture(null);
620   - } else {
621   - TbResultSetFuture partitionsFuture = fetchPartitions(tenantId, entityId, query.getKey(), minPartition, maxPartition);
622   -
623   - final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
624   - final ListenableFuture<List<Long>> partitionsListFuture = Futures.transformAsync(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
625   -
626   - Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
627   - @Override
628   - public void onSuccess(@Nullable List<Long> partitions) {
629   - int index = 0;
630   - if (minPartition != query.getStartTs()) {
631   - index = 1;
632   - }
633   - List<Long> partitionsToDelete = new ArrayList<>();
634   - for (int i = index; i < partitions.size() - 1; i++) {
635   - partitionsToDelete.add(partitions.get(i));
636   - }
637   - QueryCursor cursor = new QueryCursor(entityId.getEntityType().name(), entityId.getId(), query, partitionsToDelete);
638   - deletePartitionAsync(tenantId, cursor, resultFuture);
639   - }
640   -
641   - @Override
642   - public void onFailure(Throwable t) {
643   - log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
644   - }
645   - }, readResultsProcessingExecutor);
646   - return resultFuture;
647   - }
648   - }
649   -
650 513 private void deletePartitionAsync(TenantId tenantId, final QueryCursor cursor, final SimpleListenableFuture<Void> resultFuture) {
651 514 if (!cursor.hasNextPartition()) {
652 515 resultFuture.set(null);
... ... @@ -685,79 +548,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
685 548 return deletePartitionStmt;
686 549 }
687 550
688   - private ListenableFuture<List<TsKvEntry>> convertAsyncResultSetToTsKvEntryList(TbResultSet rs) {
689   - return Futures.transform(rs.allRows(readResultsProcessingExecutor),
690   - rows -> this.convertResultToTsKvEntryList(rows), readResultsProcessingExecutor);
691   - }
692   -
693   - private List<TsKvEntry> convertResultToTsKvEntryList(List<Row> rows) {
694   - List<TsKvEntry> entries = new ArrayList<>(rows.size());
695   - if (!rows.isEmpty()) {
696   - rows.forEach(row -> entries.add(convertResultToTsKvEntry(row)));
697   - }
698   - return entries;
699   - }
700   -
701   - private TsKvEntry convertResultToTsKvEntry(String key, Row row) {
702   - if (row != null) {
703   - long ts = row.getLong(ModelConstants.TS_COLUMN);
704   - return new BasicTsKvEntry(ts, toKvEntry(row, key));
705   - } else {
706   - return new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null));
707   - }
708   - }
709   -
710   - private TsKvEntry convertResultToTsKvEntry(Row row) {
711   - String key = row.getString(ModelConstants.KEY_COLUMN);
712   - long ts = row.getLong(ModelConstants.TS_COLUMN);
713   - return new BasicTsKvEntry(ts, toKvEntry(row, key));
714   - }
715   -
716   - public static KvEntry toKvEntry(Row row, String key) {
717   - KvEntry kvEntry = null;
718   - String strV = row.get(ModelConstants.STRING_VALUE_COLUMN, String.class);
719   - if (strV != null) {
720   - kvEntry = new StringDataEntry(key, strV);
721   - } else {
722   - Long longV = row.get(ModelConstants.LONG_VALUE_COLUMN, Long.class);
723   - if (longV != null) {
724   - kvEntry = new LongDataEntry(key, longV);
725   - } else {
726   - Double doubleV = row.get(ModelConstants.DOUBLE_VALUE_COLUMN, Double.class);
727   - if (doubleV != null) {
728   - kvEntry = new DoubleDataEntry(key, doubleV);
729   - } else {
730   - Boolean boolV = row.get(ModelConstants.BOOLEAN_VALUE_COLUMN, Boolean.class);
731   - if (boolV != null) {
732   - kvEntry = new BooleanDataEntry(key, boolV);
733   - } else {
734   - String jsonV = row.get(ModelConstants.JSON_VALUE_COLUMN, String.class);
735   - if (StringUtils.isNoneEmpty(jsonV)) {
736   - kvEntry = new JsonDataEntry(key, jsonV);
737   - } else {
738   - log.warn("All values in key-value row are nullable ");
739   - }
740   - }
741   - }
742   - }
743   - }
744   - return kvEntry;
745   - }
746   -
747   - /**
748   - * Select existing partitions from the table
749   - * <code>{@link ModelConstants#TS_KV_PARTITIONS_CF}</code> for the given entity
750   - */
751   - private TbResultSetFuture fetchPartitions(TenantId tenantId, EntityId entityId, String key, long minPartition, long maxPartition) {
752   - Select select = QueryBuilder.selectFrom(ModelConstants.TS_KV_PARTITIONS_CF).column(ModelConstants.PARTITION_COLUMN)
753   - .whereColumn(ModelConstants.ENTITY_TYPE_COLUMN).isEqualTo(literal(entityId.getEntityType().name()))
754   - .whereColumn(ModelConstants.ENTITY_ID_COLUMN).isEqualTo(literal(entityId.getId()))
755   - .whereColumn(ModelConstants.KEY_COLUMN).isEqualTo(literal(key))
756   - .whereColumn(ModelConstants.PARTITION_COLUMN).isGreaterThanOrEqualTo(literal(minPartition))
757   - .whereColumn(ModelConstants.PARTITION_COLUMN).isLessThanOrEqualTo(literal(maxPartition));
758   - return executeAsyncRead(tenantId, select.build());
759   - }
760   -
761 551 private PreparedStatement getSaveStmt(DataType dataType) {
762 552 if (saveStmts == null) {
763 553 saveStmts = new PreparedStatement[DataType.values().length];
... ... @@ -792,63 +582,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
792 582 return saveTtlStmts[dataType.ordinal()];
793 583 }
794 584
795   - private PreparedStatement getFetchStmt(Aggregation aggType, String orderBy) {
796   - switch (orderBy) {
797   - case ASC_ORDER:
798   - if (fetchStmtsAsc == null) {
799   - fetchStmtsAsc = initFetchStmt(orderBy);
800   - }
801   - return fetchStmtsAsc[aggType.ordinal()];
802   - case DESC_ORDER:
803   - if (fetchStmtsDesc == null) {
804   - fetchStmtsDesc = initFetchStmt(orderBy);
805   - }
806   - return fetchStmtsDesc[aggType.ordinal()];
807   - default:
808   - throw new RuntimeException("Not supported" + orderBy + "order!");
809   - }
810   - }
811   -
812   - private PreparedStatement[] initFetchStmt(String orderBy) {
813   - PreparedStatement[] fetchStmts = new PreparedStatement[Aggregation.values().length];
814   - for (Aggregation type : Aggregation.values()) {
815   - if (type == Aggregation.SUM && fetchStmts[Aggregation.AVG.ordinal()] != null) {
816   - fetchStmts[type.ordinal()] = fetchStmts[Aggregation.AVG.ordinal()];
817   - } else if (type == Aggregation.AVG && fetchStmts[Aggregation.SUM.ordinal()] != null) {
818   - fetchStmts[type.ordinal()] = fetchStmts[Aggregation.SUM.ordinal()];
819   - } else {
820   - fetchStmts[type.ordinal()] = prepare(SELECT_PREFIX +
821   - String.join(", ", ModelConstants.getFetchColumnNames(type)) + " FROM " + ModelConstants.TS_KV_CF
822   - + " WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM
823   - + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM
824   - + "AND " + ModelConstants.KEY_COLUMN + EQUALS_PARAM
825   - + "AND " + ModelConstants.PARTITION_COLUMN + EQUALS_PARAM
826   - + "AND " + ModelConstants.TS_COLUMN + " > ? "
827   - + "AND " + ModelConstants.TS_COLUMN + " <= ?"
828   - + (type == Aggregation.NONE ? " ORDER BY " + ModelConstants.TS_COLUMN + " " + orderBy + " LIMIT ?" : ""));
829   - }
830   - }
831   - return fetchStmts;
832   - }
833   -
834   - private PreparedStatement getLatestStmt() {
835   - if (latestInsertStmt == null) {
836   - latestInsertStmt = prepare(INSERT_INTO + ModelConstants.TS_KV_LATEST_CF +
837   - "(" + ModelConstants.ENTITY_TYPE_COLUMN +
838   - "," + ModelConstants.ENTITY_ID_COLUMN +
839   - "," + ModelConstants.KEY_COLUMN +
840   - "," + ModelConstants.TS_COLUMN +
841   - "," + ModelConstants.BOOLEAN_VALUE_COLUMN +
842   - "," + ModelConstants.STRING_VALUE_COLUMN +
843   - "," + ModelConstants.LONG_VALUE_COLUMN +
844   - "," + ModelConstants.DOUBLE_VALUE_COLUMN +
845   - "," + ModelConstants.JSON_VALUE_COLUMN + ")" +
846   - " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)");
847   - }
848   - return latestInsertStmt;
849   - }
850   -
851   -
852 585 private PreparedStatement getPartitionInsertStmt() {
853 586 if (partitionInsertStmt == null) {
854 587 partitionInsertStmt = prepare(INSERT_INTO + ModelConstants.TS_KV_PARTITIONS_CF +
... ... @@ -873,42 +606,6 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
873 606 return partitionInsertTtlStmt;
874 607 }
875 608
876   -
877   - private PreparedStatement getFindLatestStmt() {
878   - if (findLatestStmt == null) {
879   - findLatestStmt = prepare(SELECT_PREFIX +
880   - ModelConstants.KEY_COLUMN + "," +
881   - ModelConstants.TS_COLUMN + "," +
882   - ModelConstants.STRING_VALUE_COLUMN + "," +
883   - ModelConstants.BOOLEAN_VALUE_COLUMN + "," +
884   - ModelConstants.LONG_VALUE_COLUMN + "," +
885   - ModelConstants.DOUBLE_VALUE_COLUMN + "," +
886   - ModelConstants.JSON_VALUE_COLUMN + " " +
887   - "FROM " + ModelConstants.TS_KV_LATEST_CF + " " +
888   - "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM +
889   - "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM +
890   - "AND " + ModelConstants.KEY_COLUMN + EQUALS_PARAM);
891   - }
892   - return findLatestStmt;
893   - }
894   -
895   - private PreparedStatement getFindAllLatestStmt() {
896   - if (findAllLatestStmt == null) {
897   - findAllLatestStmt = prepare(SELECT_PREFIX +
898   - ModelConstants.KEY_COLUMN + "," +
899   - ModelConstants.TS_COLUMN + "," +
900   - ModelConstants.STRING_VALUE_COLUMN + "," +
901   - ModelConstants.BOOLEAN_VALUE_COLUMN + "," +
902   - ModelConstants.LONG_VALUE_COLUMN + "," +
903   - ModelConstants.DOUBLE_VALUE_COLUMN + "," +
904   - ModelConstants.JSON_VALUE_COLUMN + " " +
905   - "FROM " + ModelConstants.TS_KV_LATEST_CF + " " +
906   - "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM +
907   - "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM);
908   - }
909   - return findAllLatestStmt;
910   - }
911   -
912 609 private static String getColumnName(DataType type) {
913 610 switch (type) {
914 611 case BOOLEAN:
... ... @@ -951,4 +648,56 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
951 648 }
952 649 }
953 650
  651 + /**
  652 + // * Select existing partitions from the table
  653 + // * <code>{@link ModelConstants#TS_KV_PARTITIONS_CF}</code> for the given entity
  654 + // */
  655 + private TbResultSetFuture fetchPartitions(TenantId tenantId, EntityId entityId, String key, long minPartition, long maxPartition) {
  656 + Select select = QueryBuilder.selectFrom(ModelConstants.TS_KV_PARTITIONS_CF).column(ModelConstants.PARTITION_COLUMN)
  657 + .whereColumn(ModelConstants.ENTITY_TYPE_COLUMN).isEqualTo(literal(entityId.getEntityType().name()))
  658 + .whereColumn(ModelConstants.ENTITY_ID_COLUMN).isEqualTo(literal(entityId.getId()))
  659 + .whereColumn(ModelConstants.KEY_COLUMN).isEqualTo(literal(key))
  660 + .whereColumn(ModelConstants.PARTITION_COLUMN).isGreaterThanOrEqualTo(literal(minPartition))
  661 + .whereColumn(ModelConstants.PARTITION_COLUMN).isLessThanOrEqualTo(literal(maxPartition));
  662 + return executeAsyncRead(tenantId, select.build());
  663 + }
  664 +
  665 + private PreparedStatement getFetchStmt(Aggregation aggType, String orderBy) {
  666 + switch (orderBy) {
  667 + case ASC_ORDER:
  668 + if (fetchStmtsAsc == null) {
  669 + fetchStmtsAsc = initFetchStmt(orderBy);
  670 + }
  671 + return fetchStmtsAsc[aggType.ordinal()];
  672 + case DESC_ORDER:
  673 + if (fetchStmtsDesc == null) {
  674 + fetchStmtsDesc = initFetchStmt(orderBy);
  675 + }
  676 + return fetchStmtsDesc[aggType.ordinal()];
  677 + default:
  678 + throw new RuntimeException("Not supported" + orderBy + "order!");
  679 + }
  680 + }
  681 +
  682 + private PreparedStatement[] initFetchStmt(String orderBy) {
  683 + PreparedStatement[] fetchStmts = new PreparedStatement[Aggregation.values().length];
  684 + for (Aggregation type : Aggregation.values()) {
  685 + if (type == Aggregation.SUM && fetchStmts[Aggregation.AVG.ordinal()] != null) {
  686 + fetchStmts[type.ordinal()] = fetchStmts[Aggregation.AVG.ordinal()];
  687 + } else if (type == Aggregation.AVG && fetchStmts[Aggregation.SUM.ordinal()] != null) {
  688 + fetchStmts[type.ordinal()] = fetchStmts[Aggregation.SUM.ordinal()];
  689 + } else {
  690 + fetchStmts[type.ordinal()] = prepare(SELECT_PREFIX +
  691 + String.join(", ", ModelConstants.getFetchColumnNames(type)) + " FROM " + ModelConstants.TS_KV_CF
  692 + + " WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM
  693 + + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM
  694 + + "AND " + ModelConstants.KEY_COLUMN + EQUALS_PARAM
  695 + + "AND " + ModelConstants.PARTITION_COLUMN + EQUALS_PARAM
  696 + + "AND " + ModelConstants.TS_COLUMN + " > ? "
  697 + + "AND " + ModelConstants.TS_COLUMN + " <= ?"
  698 + + (type == Aggregation.NONE ? " ORDER BY " + ModelConstants.TS_COLUMN + " " + orderBy + " LIMIT ?" : ""));
  699 + }
  700 + }
  701 + return fetchStmts;
  702 + }
954 703 }
... ...
  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.dao.timeseries;
  17 +
  18 +import com.datastax.oss.driver.api.core.cql.BoundStatement;
  19 +import com.datastax.oss.driver.api.core.cql.BoundStatementBuilder;
  20 +import com.datastax.oss.driver.api.core.cql.PreparedStatement;
  21 +import com.datastax.oss.driver.api.core.cql.Row;
  22 +import com.datastax.oss.driver.api.core.cql.Statement;
  23 +import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
  24 +import com.google.common.util.concurrent.FutureCallback;
  25 +import com.google.common.util.concurrent.Futures;
  26 +import com.google.common.util.concurrent.ListenableFuture;
  27 +import com.google.common.util.concurrent.MoreExecutors;
  28 +import lombok.extern.slf4j.Slf4j;
  29 +import org.springframework.beans.factory.annotation.Autowired;
  30 +import org.springframework.stereotype.Component;
  31 +import org.thingsboard.server.common.data.id.EntityId;
  32 +import org.thingsboard.server.common.data.id.TenantId;
  33 +import org.thingsboard.server.common.data.kv.Aggregation;
  34 +import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
  35 +import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  36 +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
  37 +import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
  38 +import org.thingsboard.server.common.data.kv.StringDataEntry;
  39 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  40 +import org.thingsboard.server.dao.model.ModelConstants;
  41 +import org.thingsboard.server.dao.nosql.TbResultSet;
  42 +import org.thingsboard.server.dao.sqlts.AggregationTimeseriesDao;
  43 +import org.thingsboard.server.dao.util.NoSqlTsLatestDao;
  44 +
  45 +import javax.annotation.Nullable;
  46 +import java.util.List;
  47 +import java.util.Optional;
  48 +import java.util.concurrent.ExecutionException;
  49 +
  50 +import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal;
  51 +
  52 +@Component
  53 +@Slf4j
  54 +@NoSqlTsLatestDao
  55 +public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimeseriesDao implements TimeseriesLatestDao {
  56 +
  57 + @Autowired
  58 + protected AggregationTimeseriesDao aggregationTimeseriesDao;
  59 +
  60 + private PreparedStatement latestInsertStmt;
  61 + private PreparedStatement findLatestStmt;
  62 + private PreparedStatement findAllLatestStmt;
  63 +
  64 + @Override
  65 + public ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key) {
  66 + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getFindLatestStmt().bind());
  67 + stmtBuilder.setString(0, entityId.getEntityType().name());
  68 + stmtBuilder.setUuid(1, entityId.getId());
  69 + stmtBuilder.setString(2, key);
  70 + BoundStatement stmt = stmtBuilder.build();
  71 + log.debug(GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID, stmt, entityId.getEntityType(), entityId.getId());
  72 + return getFuture(executeAsyncRead(tenantId, stmt), rs -> convertResultToTsKvEntry(key, rs.one()));
  73 + }
  74 +
  75 + @Override
  76 + public ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId) {
  77 + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getFindAllLatestStmt().bind());
  78 + stmtBuilder.setString(0, entityId.getEntityType().name());
  79 + stmtBuilder.setUuid(1, entityId.getId());
  80 + BoundStatement stmt = stmtBuilder.build();
  81 + log.debug(GENERATED_QUERY_FOR_ENTITY_TYPE_AND_ENTITY_ID, stmt, entityId.getEntityType(), entityId.getId());
  82 + return getFutureAsync(executeAsyncRead(tenantId, stmt), rs -> convertAsyncResultSetToTsKvEntryList(rs));
  83 + }
  84 +
  85 + @Override
  86 + public ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) {
  87 + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getLatestStmt().bind());
  88 + stmtBuilder.setString(0, entityId.getEntityType().name())
  89 + .setUuid(1, entityId.getId())
  90 + .setString(2, tsKvEntry.getKey())
  91 + .setLong(3, tsKvEntry.getTs())
  92 + .set(4, tsKvEntry.getBooleanValue().orElse(null), Boolean.class)
  93 + .set(5, tsKvEntry.getStrValue().orElse(null), String.class)
  94 + .set(6, tsKvEntry.getLongValue().orElse(null), Long.class)
  95 + .set(7, tsKvEntry.getDoubleValue().orElse(null), Double.class);
  96 + Optional<String> jsonV = tsKvEntry.getJsonValue();
  97 + if (jsonV.isPresent()) {
  98 + stmtBuilder.setString(8, tsKvEntry.getJsonValue().get());
  99 + } else {
  100 + stmtBuilder.setToNull(8);
  101 + }
  102 + BoundStatement stmt = stmtBuilder.build();
  103 +
  104 + return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null);
  105 + }
  106 +
  107 + @Override
  108 + public ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  109 + ListenableFuture<TsKvEntry> latestEntryFuture = findLatest(tenantId, entityId, query.getKey());
  110 +
  111 + ListenableFuture<Boolean> booleanFuture = Futures.transform(latestEntryFuture, latestEntry -> {
  112 + long ts = latestEntry.getTs();
  113 + if (ts > query.getStartTs() && ts <= query.getEndTs()) {
  114 + return true;
  115 + } else {
  116 + log.trace("Won't be deleted latest value for [{}], key - {}", entityId, query.getKey());
  117 + }
  118 + return false;
  119 + }, readResultsProcessingExecutor);
  120 +
  121 + ListenableFuture<Void> removedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
  122 + if (isRemove) {
  123 + return deleteLatest(tenantId, entityId, query.getKey());
  124 + }
  125 + return Futures.immediateFuture(null);
  126 + }, readResultsProcessingExecutor);
  127 +
  128 + final SimpleListenableFuture<Void> resultFuture = new SimpleListenableFuture<>();
  129 + Futures.addCallback(removedLatestFuture, new FutureCallback<Void>() {
  130 + @Override
  131 + public void onSuccess(@Nullable Void result) {
  132 + if (query.getRewriteLatestIfDeleted()) {
  133 + ListenableFuture<Void> savedLatestFuture = Futures.transformAsync(booleanFuture, isRemove -> {
  134 + if (isRemove) {
  135 + return getNewLatestEntryFuture(tenantId, entityId, query);
  136 + }
  137 + return Futures.immediateFuture(null);
  138 + }, readResultsProcessingExecutor);
  139 +
  140 + try {
  141 + resultFuture.set(savedLatestFuture.get());
  142 + } catch (InterruptedException | ExecutionException e) {
  143 + log.warn("Could not get latest saved value for [{}], {}", entityId, query.getKey(), e);
  144 + }
  145 + } else {
  146 + resultFuture.set(null);
  147 + }
  148 + }
  149 +
  150 + @Override
  151 + public void onFailure(Throwable t) {
  152 + log.warn("[{}] Failed to process remove of the latest value", entityId, t);
  153 + }
  154 + }, MoreExecutors.directExecutor());
  155 + return resultFuture;
  156 + }
  157 +
  158 + private ListenableFuture<Void> getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) {
  159 + long startTs = 0;
  160 + long endTs = query.getStartTs() - 1;
  161 + ReadTsKvQuery findNewLatestQuery = new BaseReadTsKvQuery(query.getKey(), startTs, endTs, endTs - startTs, 1,
  162 + Aggregation.NONE, DESC_ORDER);
  163 + ListenableFuture<List<TsKvEntry>> future = aggregationTimeseriesDao.findAllAsync(tenantId, entityId, findNewLatestQuery);
  164 +
  165 + return Futures.transformAsync(future, entryList -> {
  166 + if (entryList.size() == 1) {
  167 + return saveLatest(tenantId, entityId, entryList.get(0));
  168 + } else {
  169 + log.trace("Could not find new latest value for [{}], key - {}", entityId, query.getKey());
  170 + }
  171 + return Futures.immediateFuture(null);
  172 + }, readResultsProcessingExecutor);
  173 + }
  174 +
  175 + private ListenableFuture<Void> deleteLatest(TenantId tenantId, EntityId entityId, String key) {
  176 + Statement delete = QueryBuilder.deleteFrom(ModelConstants.TS_KV_LATEST_CF)
  177 + .whereColumn(ModelConstants.ENTITY_TYPE_COLUMN).isEqualTo(literal(entityId.getEntityType().name()))
  178 + .whereColumn(ModelConstants.ENTITY_ID_COLUMN).isEqualTo(literal(entityId.getId()))
  179 + .whereColumn(ModelConstants.KEY_COLUMN).isEqualTo(literal(key)).build();
  180 + log.debug("Remove request: {}", delete.toString());
  181 + return getFuture(executeAsyncWrite(tenantId, delete), rs -> null);
  182 + }
  183 +
  184 + private ListenableFuture<List<TsKvEntry>> convertAsyncResultSetToTsKvEntryList(TbResultSet rs) {
  185 + return Futures.transform(rs.allRows(readResultsProcessingExecutor),
  186 + rows -> this.convertResultToTsKvEntryList(rows), readResultsProcessingExecutor);
  187 + }
  188 +
  189 + private TsKvEntry convertResultToTsKvEntry(String key, Row row) {
  190 + if (row != null) {
  191 + long ts = row.getLong(ModelConstants.TS_COLUMN);
  192 + return new BasicTsKvEntry(ts, toKvEntry(row, key));
  193 + } else {
  194 + return new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null));
  195 + }
  196 + }
  197 +
  198 + private PreparedStatement getLatestStmt() {
  199 + if (latestInsertStmt == null) {
  200 + latestInsertStmt = prepare(INSERT_INTO + ModelConstants.TS_KV_LATEST_CF +
  201 + "(" + ModelConstants.ENTITY_TYPE_COLUMN +
  202 + "," + ModelConstants.ENTITY_ID_COLUMN +
  203 + "," + ModelConstants.KEY_COLUMN +
  204 + "," + ModelConstants.TS_COLUMN +
  205 + "," + ModelConstants.BOOLEAN_VALUE_COLUMN +
  206 + "," + ModelConstants.STRING_VALUE_COLUMN +
  207 + "," + ModelConstants.LONG_VALUE_COLUMN +
  208 + "," + ModelConstants.DOUBLE_VALUE_COLUMN +
  209 + "," + ModelConstants.JSON_VALUE_COLUMN + ")" +
  210 + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)");
  211 + }
  212 + return latestInsertStmt;
  213 + }
  214 +
  215 + private PreparedStatement getFindLatestStmt() {
  216 + if (findLatestStmt == null) {
  217 + findLatestStmt = prepare(SELECT_PREFIX +
  218 + ModelConstants.KEY_COLUMN + "," +
  219 + ModelConstants.TS_COLUMN + "," +
  220 + ModelConstants.STRING_VALUE_COLUMN + "," +
  221 + ModelConstants.BOOLEAN_VALUE_COLUMN + "," +
  222 + ModelConstants.LONG_VALUE_COLUMN + "," +
  223 + ModelConstants.DOUBLE_VALUE_COLUMN + "," +
  224 + ModelConstants.JSON_VALUE_COLUMN + " " +
  225 + "FROM " + ModelConstants.TS_KV_LATEST_CF + " " +
  226 + "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM +
  227 + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM +
  228 + "AND " + ModelConstants.KEY_COLUMN + EQUALS_PARAM);
  229 + }
  230 + return findLatestStmt;
  231 + }
  232 +
  233 + private PreparedStatement getFindAllLatestStmt() {
  234 + if (findAllLatestStmt == null) {
  235 + findAllLatestStmt = prepare(SELECT_PREFIX +
  236 + ModelConstants.KEY_COLUMN + "," +
  237 + ModelConstants.TS_COLUMN + "," +
  238 + ModelConstants.STRING_VALUE_COLUMN + "," +
  239 + ModelConstants.BOOLEAN_VALUE_COLUMN + "," +
  240 + ModelConstants.LONG_VALUE_COLUMN + "," +
  241 + ModelConstants.DOUBLE_VALUE_COLUMN + "," +
  242 + ModelConstants.JSON_VALUE_COLUMN + " " +
  243 + "FROM " + ModelConstants.TS_KV_LATEST_CF + " " +
  244 + "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM +
  245 + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM);
  246 + }
  247 + return findAllLatestStmt;
  248 + }
  249 +}
... ...
... ... @@ -31,19 +31,11 @@ public interface TimeseriesDao {
31 31
32 32 ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries);
33 33
34   - ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key);
35   -
36   - ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId);
37   -
38 34 ListenableFuture<Void> save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl);
39 35
40 36 ListenableFuture<Void> savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl);
41 37
42   - ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry);
43   -
44 38 ListenableFuture<Void> remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query);
45 39
46   - ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query);
47   -
48 40 ListenableFuture<Void> removePartition(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query);
49 41 }
... ...
  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.dao.timeseries;
  17 +
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
  22 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  23 +
  24 +import java.util.List;
  25 +
  26 +public interface TimeseriesLatestDao {
  27 +
  28 + ListenableFuture<TsKvEntry> findLatest(TenantId tenantId, EntityId entityId, String key);
  29 +
  30 + ListenableFuture<List<TsKvEntry>> findAllLatest(TenantId tenantId, EntityId entityId);
  31 +
  32 + ListenableFuture<Void> saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry);
  33 +
  34 + ListenableFuture<Void> removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query);
  35 +
  36 +}
... ...
  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 +
  17 +CREATE KEYSPACE IF NOT EXISTS thingsboard
  18 +WITH replication = {
  19 + 'class' : 'SimpleStrategy',
  20 + 'replication_factor' : 1
  21 +};
  22 +
  23 +CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf (
  24 + entity_type text, // (DEVICE, CUSTOMER, TENANT)
  25 + entity_id timeuuid,
  26 + key text,
  27 + ts bigint,
  28 + bool_v boolean,
  29 + str_v text,
  30 + long_v bigint,
  31 + dbl_v double,
  32 + json_v text,
  33 + PRIMARY KEY (( entity_type, entity_id ), key)
  34 +) WITH compaction = { 'class' : 'LeveledCompactionStrategy' };
... ...
... ... @@ -42,16 +42,3 @@ CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_partitions_cf (
42 42 PRIMARY KEY (( entity_type, entity_id, key ), partition)
43 43 ) WITH CLUSTERING ORDER BY ( partition ASC )
44 44 AND compaction = { 'class' : 'LeveledCompactionStrategy' };
45   -
46   -CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf (
47   - entity_type text, // (DEVICE, CUSTOMER, TENANT)
48   - entity_id timeuuid,
49   - key text,
50   - ts bigint,
51   - bool_v boolean,
52   - str_v text,
53   - long_v bigint,
54   - dbl_v double,
55   - json_v text,
56   - PRIMARY KEY (( entity_type, entity_id ), key)
57   -) WITH compaction = { 'class' : 'LeveledCompactionStrategy' };
... ...
... ... @@ -272,3 +272,20 @@ CREATE TABLE IF NOT EXISTS entity_view (
272 272 additional_info varchar
273 273 );
274 274
  275 +CREATE TABLE IF NOT EXISTS ts_kv_latest (
  276 + entity_id uuid NOT NULL,
  277 + key int NOT NULL,
  278 + ts bigint NOT NULL,
  279 + bool_v boolean,
  280 + str_v varchar(10000000),
  281 + long_v bigint,
  282 + dbl_v double precision,
  283 + json_v varchar(10000000),
  284 + CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key)
  285 +);
  286 +
  287 +CREATE TABLE IF NOT EXISTS ts_kv_dictionary (
  288 + key varchar(255) NOT NULL,
  289 + key_id int GENERATED BY DEFAULT AS IDENTITY(start with 0 increment by 1) UNIQUE,
  290 + CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
  291 +);
... ...
... ... @@ -14,6 +14,13 @@
14 14 -- limitations under the License.
15 15 --
16 16
  17 +CREATE TABLE IF NOT EXISTS tb_schema_settings
  18 +(
  19 + schema_version bigint NOT NULL,
  20 + CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version)
  21 +);
  22 +
  23 +INSERT INTO tb_schema_settings (schema_version) VALUES (3001000) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 3001000;
17 24
18 25 CREATE TABLE IF NOT EXISTS admin_settings (
19 26 id uuid NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY,
... ... @@ -331,3 +338,4 @@ BEGIN
331 338 '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12);
332 339 END;
333 340 $$ LANGUAGE plpgsql;
  341 +
... ...
... ... @@ -46,14 +46,6 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest (
46 46 CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key)
47 47 );
48 48
49   -CREATE TABLE IF NOT EXISTS tb_schema_settings
50   -(
51   - schema_version bigint NOT NULL,
52   - CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version)
53   -);
54   -
55   -INSERT INTO tb_schema_settings (schema_version) VALUES (2005001) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005001;
56   -
57 49 CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS
58 50 $$
59 51 BEGIN
... ...
... ... @@ -28,18 +28,6 @@ CREATE TABLE IF NOT EXISTS ts_kv (
28 28 CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts)
29 29 );
30 30
31   -CREATE TABLE IF NOT EXISTS ts_kv_latest (
32   - entity_id uuid NOT NULL,
33   - key int NOT NULL,
34   - ts bigint NOT NULL,
35   - bool_v boolean,
36   - str_v varchar(10000000),
37   - long_v bigint,
38   - dbl_v double precision,
39   - json_v varchar(10000000),
40   - CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key)
41   -);
42   -
43 31 CREATE TABLE IF NOT EXISTS ts_kv_dictionary (
44 32 key varchar(255) NOT NULL,
45 33 key_id int GENERATED BY DEFAULT AS IDENTITY(start with 0 increment by 1) UNIQUE,
... ...
... ... @@ -27,19 +27,6 @@ CREATE TABLE IF NOT EXISTS ts_kv
27 27 CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts)
28 28 ) PARTITION BY RANGE (ts);
29 29
30   -CREATE TABLE IF NOT EXISTS ts_kv_latest
31   -(
32   - entity_id uuid NOT NULL,
33   - key int NOT NULL,
34   - ts bigint NOT NULL,
35   - bool_v boolean,
36   - str_v varchar(10000000),
37   - long_v bigint,
38   - dbl_v double precision,
39   - json_v json,
40   - CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key)
41   -);
42   -
43 30 CREATE TABLE IF NOT EXISTS ts_kv_dictionary
44 31 (
45 32 key varchar(255) NOT NULL,
... ... @@ -47,14 +34,6 @@ CREATE TABLE IF NOT EXISTS ts_kv_dictionary
47 34 CONSTRAINT ts_key_id_pkey PRIMARY KEY (key)
48 35 );
49 36
50   -CREATE TABLE IF NOT EXISTS tb_schema_settings
51   -(
52   - schema_version bigint NOT NULL,
53   - CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version)
54   -);
55   -
56   -INSERT INTO tb_schema_settings (schema_version) VALUES (2005001) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005001;
57   -
58 37 CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint)
59 38 LANGUAGE plpgsql AS
60 39 $$
... ...
... ... @@ -22,7 +22,6 @@ import org.dbunit.ext.hsqldb.HsqldbDataTypeFactory;
22 22 import org.springframework.beans.factory.annotation.Autowired;
23 23 import org.springframework.context.annotation.Bean;
24 24 import org.springframework.context.annotation.Configuration;
25   -import org.thingsboard.server.dao.util.SqlDao;
26 25
27 26 import javax.sql.DataSource;
28 27 import java.io.IOException;
... ... @@ -32,7 +31,6 @@ import java.sql.SQLException;
32 31 * Created by Valerii Sosliuk on 5/6/2017.
33 32 */
34 33 @Configuration
35   -@SqlDao
36 34 public class JpaDbunitTestConfig {
37 35
38 36 @Autowired
... ...
... ... @@ -40,7 +40,8 @@ public class NoSqlDaoServiceTestSuite {
40 40 public static CustomCassandraCQLUnit cassandraUnit =
41 41 new CustomCassandraCQLUnit(
42 42 Arrays.asList(
43   - new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false)
  43 + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false),
  44 + new ClassPathCQLDataSet("cassandra/schema-ts-latest.cql", false, false)
44 45 ),
45 46 "cassandra-test.yaml", 30000L);
46 47
... ...
1 1 database.ts.type=cassandra
  2 +database.ts_latest.type=cassandra
2 3
3 4 sql.ts_inserts_executor_type=fixed
4 5 sql.ts_inserts_fixed_thread_pool_size=10
... ...
1 1 database.ts.type=sql
  2 +database.ts_latest.type=sql
2 3
3 4 sql.ts_inserts_executor_type=fixed
4 5 sql.ts_inserts_fixed_thread_pool_size=200
... ...