Commit c2b4d9c8ae2653a8a94907791eb059215a495bac

Authored by Igor Kulikov
2 parents 745648a5 6a4c2791

Merge with master

Showing 61 changed files with 161 additions and 96 deletions
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>application</artifactId>
... ...
... ... @@ -166,7 +166,7 @@
166 166 "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
167 167 "settingsSchema": "{}",
168 168 "dataKeySettingsSchema": "{}",
169   - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}"
  169 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}"
170 170 }
171 171 }
172 172 ]
... ...
... ... @@ -247,4 +247,4 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
247 247 log.info("Failed to load PostgreSQL upgrade functions due to: {}", e.getMessage());
248 248 }
249 249 }
250   -}
\ No newline at end of file
  250 +}
... ...
... ... @@ -209,4 +209,4 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
209 209 log.info("Failed to load PostgreSQL upgrade functions due to: {}", e.getMessage());
210 210 }
211 211 }
212   -}
\ No newline at end of file
  212 +}
... ...
... ... @@ -39,8 +39,7 @@ public abstract class AbstractCleanUpService {
39 39 protected String dbPassword;
40 40
41 41 protected long executeQuery(Connection conn, String query) throws SQLException {
42   - try (Statement statement = conn.createStatement()) {
43   - ResultSet resultSet = statement.executeQuery(query);
  42 + try (Statement statement = conn.createStatement(); ResultSet resultSet = statement.executeQuery(query)) {
44 43 if (log.isDebugEnabled()) {
45 44 getWarnings(statement);
46 45 }
... ...
... ... @@ -33,4 +33,4 @@ public class TimescaleTimeseriesCleanUpService extends AbstractTimeseriesCleanUp
33 33 long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID + "'," + systemTtl + ", 0);");
34 34 log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved);
35 35 }
36   -}
\ No newline at end of file
  36 +}
... ...
... ... @@ -284,6 +284,8 @@ sql:
284 284 batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}"
285 285 stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}"
286 286 batch_threads: "${SQL_TS_LATEST_BATCH_THREADS:4}"
  287 + # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
  288 + batch_sort: "${SQL_BATCH_SORT:false}"
287 289 # Specify whether to remove null characters from strValue of attributes and timeseries before insert
288 290 remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}"
289 291 # Specify whether to log database queries and their parameters generated by entity query repository
... ... @@ -651,11 +653,11 @@ queue:
651 653 security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
652 654 other:
653 655 topic-properties:
654   - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
655   - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
656   - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
657   - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
658   - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}"
  656 + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  657 + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  658 + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  659 + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  660 + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}"
659 661 aws_sqs:
660 662 use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}"
661 663 access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>common</artifactId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -37,6 +37,7 @@ public class TbKafkaAdmin implements TbQueueAdmin {
37 37 private final AdminClient client;
38 38 private final Map<String, String> topicConfigs;
39 39 private final Set<String> topics = ConcurrentHashMap.newKeySet();
  40 + private final int numPartitions;
40 41
41 42 private final short replicationFactor;
42 43
... ... @@ -50,6 +51,13 @@ public class TbKafkaAdmin implements TbQueueAdmin {
50 51 log.error("Failed to get all topics.", e);
51 52 }
52 53
  54 + String numPartitionsStr = topicConfigs.get("partitions");
  55 + if (numPartitionsStr != null) {
  56 + numPartitions = Integer.parseInt(numPartitionsStr);
  57 + topicConfigs.remove("partitions");
  58 + } else {
  59 + numPartitions = 1;
  60 + }
53 61 replicationFactor = settings.getReplicationFactor();
54 62 }
55 63
... ... @@ -59,7 +67,7 @@ public class TbKafkaAdmin implements TbQueueAdmin {
59 67 return;
60 68 }
61 69 try {
62   - NewTopic newTopic = new NewTopic(topic, 1, replicationFactor).configs(topicConfigs);
  70 + NewTopic newTopic = new NewTopic(topic, numPartitions, replicationFactor).configs(topicConfigs);
63 71 createTopic(newTopic).values().get(topic).get();
64 72 topics.add(topic);
65 73 } catch (ExecutionException ee) {
... ...
... ... @@ -22,7 +22,7 @@
22 22 <modelVersion>4.0.0</modelVersion>
23 23 <parent>
24 24 <groupId>org.thingsboard</groupId>
25   - <version>3.1.2-SNAPSHOT</version>
  25 + <version>3.2.0-SNAPSHOT</version>
26 26 <artifactId>common</artifactId>
27 27 </parent>
28 28 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.common</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.common</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.common</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.common</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>common</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.common</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>dao</artifactId>
... ...
... ... @@ -22,6 +22,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory;
22 22 import org.thingsboard.server.common.stats.MessagesStats;
23 23
24 24 import java.util.ArrayList;
  25 +import java.util.Comparator;
25 26 import java.util.List;
26 27 import java.util.concurrent.BlockingQueue;
27 28 import java.util.concurrent.ExecutorService;
... ... @@ -30,6 +31,7 @@ import java.util.concurrent.LinkedBlockingQueue;
30 31 import java.util.concurrent.TimeUnit;
31 32 import java.util.function.Consumer;
32 33 import java.util.stream.Collectors;
  34 +import java.util.stream.Stream;
33 35
34 36 @Slf4j
35 37 public class TbSqlBlockingQueue<E> implements TbSqlQueue<E> {
... ... @@ -46,7 +48,7 @@ public class TbSqlBlockingQueue<E> implements TbSqlQueue<E> {
46 48 }
47 49
48 50 @Override
49   - public void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction, int index) {
  51 + public void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction, Comparator<E> batchUpdateComparator, int index) {
50 52 executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("sql-queue-" + index + "-" + params.getLogName().toLowerCase()));
51 53 executor.submit(() -> {
52 54 String logName = params.getLogName();
... ... @@ -65,7 +67,11 @@ public class TbSqlBlockingQueue<E> implements TbSqlQueue<E> {
65 67 queue.drainTo(entities, batchSize - 1);
66 68 boolean fullPack = entities.size() == batchSize;
67 69 log.debug("[{}] Going to save {} entities", logName, entities.size());
68   - saveFunction.accept(entities.stream().map(TbSqlQueueElement::getEntity).collect(Collectors.toList()));
  70 + Stream<E> entitiesStream = entities.stream().map(TbSqlQueueElement::getEntity);
  71 + saveFunction.accept(
  72 + (params.isBatchSortEnabled() ? entitiesStream.sorted(batchUpdateComparator) : entitiesStream)
  73 + .collect(Collectors.toList())
  74 + );
69 75 entities.forEach(v -> v.getFuture().set(null));
70 76 stats.incrementSuccessful(entities.size());
71 77 if (!fullPack) {
... ...
... ... @@ -31,4 +31,5 @@ public class TbSqlBlockingQueueParams {
31 31 private final long maxDelay;
32 32 private final long statsPrintIntervalMs;
33 33 private final String statsNamePrefix;
  34 + private final boolean batchSortEnabled;
34 35 }
... ...
... ... @@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
21 21 import org.thingsboard.server.common.stats.MessagesStats;
22 22 import org.thingsboard.server.common.stats.StatsFactory;
23 23
  24 +import java.util.Comparator;
24 25 import java.util.List;
25 26 import java.util.concurrent.CopyOnWriteArrayList;
26 27 import java.util.function.Consumer;
... ... @@ -36,12 +37,20 @@ public class TbSqlBlockingQueueWrapper<E> {
36 37 private final int maxThreads;
37 38 private final StatsFactory statsFactory;
38 39
39   - public void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction) {
  40 + /**
  41 + * Starts TbSqlBlockingQueues.
  42 + *
  43 + * @param logExecutor executor that will be printing logs and statistics
  44 + * @param saveFunction function to save entities in database
  45 + * @param batchUpdateComparator comparator to sort entities by primary key to avoid deadlocks in cluster mode
  46 + * NOTE: you must use all of primary key parts in your comparator
  47 + */
  48 + public void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction, Comparator<E> batchUpdateComparator) {
40 49 for (int i = 0; i < maxThreads; i++) {
41 50 MessagesStats stats = statsFactory.createMessagesStats(params.getStatsNamePrefix() + ".queue." + i);
42 51 TbSqlBlockingQueue<E> queue = new TbSqlBlockingQueue<>(params, stats);
43 52 queues.add(queue);
44   - queue.init(logExecutor, saveFunction, i);
  53 + queue.init(logExecutor, saveFunction, batchUpdateComparator, i);
45 54 }
46 55 }
47 56
... ...
... ... @@ -17,12 +17,13 @@ package org.thingsboard.server.dao.sql;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19
  20 +import java.util.Comparator;
20 21 import java.util.List;
21 22 import java.util.function.Consumer;
22 23
23 24 public interface TbSqlQueue<E> {
24 25
25   - void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction, int queueIndex);
  26 + void init(ScheduledLogExecutorComponent logExecutor, Consumer<List<E>> saveFunction, Comparator<E> batchUpdateComparator, int queueIndex);
26 27
27 28 void destroy();
28 29
... ...
... ... @@ -38,6 +38,7 @@ import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
38 38 import javax.annotation.PostConstruct;
39 39 import javax.annotation.PreDestroy;
40 40 import java.util.Collection;
  41 +import java.util.Comparator;
41 42 import java.util.List;
42 43 import java.util.Optional;
43 44 import java.util.function.Function;
... ... @@ -71,6 +72,9 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl
71 72 @Value("${sql.attributes.batch_threads:4}")
72 73 private int batchThreads;
73 74
  75 + @Value("${sql.batch_sort:false}")
  76 + private boolean batchSortEnabled;
  77 +
74 78 private TbSqlBlockingQueueWrapper<AttributeKvEntity> queue;
75 79
76 80 @PostConstruct
... ... @@ -81,11 +85,17 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl
81 85 .maxDelay(maxDelay)
82 86 .statsPrintIntervalMs(statsPrintIntervalMs)
83 87 .statsNamePrefix("attributes")
  88 + .batchSortEnabled(batchSortEnabled)
84 89 .build();
85 90
86 91 Function<AttributeKvEntity, Integer> hashcodeFunction = entity -> entity.getId().getEntityId().hashCode();
87 92 queue = new TbSqlBlockingQueueWrapper<>(params, hashcodeFunction, batchThreads, statsFactory);
88   - queue.init(logExecutor, v -> attributeKvInsertRepository.saveOrUpdate(v));
  93 + queue.init(logExecutor, v -> attributeKvInsertRepository.saveOrUpdate(v),
  94 + Comparator.comparing((AttributeKvEntity attributeKvEntity) -> attributeKvEntity.getId().getEntityId())
  95 + .thenComparing(attributeKvEntity -> attributeKvEntity.getId().getEntityType().name())
  96 + .thenComparing(attributeKvEntity -> attributeKvEntity.getId().getAttributeType())
  97 + .thenComparing(attributeKvEntity -> attributeKvEntity.getId().getAttributeKey())
  98 + );
89 99 }
90 100
91 101 @PreDestroy
... ...
... ... @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.MoreExecutors;
21 21 import com.google.common.util.concurrent.SettableFuture;
22 22 import lombok.extern.slf4j.Slf4j;
23 23 import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.beans.factory.annotation.Value;
24 25 import org.springframework.data.domain.PageRequest;
25 26 import org.springframework.data.domain.Sort;
26 27 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
31 32 import org.thingsboard.server.common.data.kv.TsKvEntry;
32 33 import org.thingsboard.server.common.stats.StatsFactory;
33 34 import org.thingsboard.server.dao.DaoUtil;
  35 +import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
34 36 import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
35 37 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
36 38 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
... ... @@ -40,9 +42,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesDao;
40 42
41 43 import javax.annotation.PostConstruct;
42 44 import javax.annotation.PreDestroy;
43   -import java.util.ArrayList;
44   -import java.util.List;
45   -import java.util.Optional;
  45 +import java.util.*;
46 46 import java.util.concurrent.CompletableFuture;
47 47 import java.util.function.Function;
48 48 import java.util.stream.Collectors;
... ... @@ -68,11 +68,16 @@ public abstract class AbstractChunkedAggregationTimeseriesDao extends AbstractSq
68 68 .maxDelay(tsMaxDelay)
69 69 .statsPrintIntervalMs(tsStatsPrintIntervalMs)
70 70 .statsNamePrefix("ts")
  71 + .batchSortEnabled(batchSortEnabled)
71 72 .build();
72 73
73 74 Function<TsKvEntity, Integer> hashcodeFunction = entity -> entity.getEntityId().hashCode();
74 75 tsQueue = new TbSqlBlockingQueueWrapper<>(tsParams, hashcodeFunction, tsBatchThreads, statsFactory);
75   - tsQueue.init(logExecutor, v -> insertRepository.saveOrUpdate(v));
  76 + tsQueue.init(logExecutor, v -> insertRepository.saveOrUpdate(v),
  77 + Comparator.comparing((Function<TsKvEntity, UUID>) AbstractTsKvEntity::getEntityId)
  78 + .thenComparing(AbstractTsKvEntity::getKey)
  79 + .thenComparing(AbstractTsKvEntity::getTs)
  80 + );
76 81 }
77 82
78 83 @PreDestroy
... ...
... ... @@ -53,6 +53,9 @@ public abstract class AbstractSqlTimeseriesDao extends BaseAbstractSqlTimeseries
53 53 @Value("${sql.timescale.batch_threads:4}")
54 54 protected int timescaleBatchThreads;
55 55
  56 + @Value("${sql.batch_sort:false}")
  57 + protected boolean batchSortEnabled;
  58 +
56 59 protected ListenableFuture<List<TsKvEntry>> processFindAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
57 60 List<ListenableFuture<List<TsKvEntry>>> futures = queries
58 61 .stream()
... ...
... ... @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.kv.StringDataEntry;
35 35 import org.thingsboard.server.common.data.kv.TsKvEntry;
36 36 import org.thingsboard.server.common.stats.StatsFactory;
37 37 import org.thingsboard.server.dao.DaoUtil;
  38 +import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
38 39 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey;
39 40 import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity;
40 41 import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
... ... @@ -50,12 +51,10 @@ import org.thingsboard.server.dao.util.SqlTsLatestAnyDao;
50 51 import javax.annotation.Nullable;
51 52 import javax.annotation.PostConstruct;
52 53 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;
  54 +import java.util.*;
58 55 import java.util.concurrent.ExecutionException;
  56 +import java.util.function.Function;
  57 +import java.util.stream.Collectors;
59 58
60 59 @Slf4j
61 60 @Component
... ... @@ -90,6 +89,9 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme
90 89 @Value("${sql.ts_latest.batch_threads:4}")
91 90 private int tsLatestBatchThreads;
92 91
  92 + @Value("${sql.batch_sort:false}")
  93 + protected boolean batchSortEnabled;
  94 +
93 95 @Autowired
94 96 protected ScheduledLogExecutorComponent logExecutor;
95 97
... ... @@ -104,6 +106,7 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme
104 106 .maxDelay(tsLatestMaxDelay)
105 107 .statsPrintIntervalMs(tsLatestStatsPrintIntervalMs)
106 108 .statsNamePrefix("ts.latest")
  109 + .batchSortEnabled(false)
107 110 .build();
108 111
109 112 java.util.function.Function<TsKvLatestEntity, Integer> hashcodeFunction = entity -> entity.getEntityId().hashCode();
... ... @@ -113,14 +116,15 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme
113 116 Map<TsKey, TsKvLatestEntity> trueLatest = new HashMap<>();
114 117 v.forEach(ts -> {
115 118 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   - }
  119 + trueLatest.merge(key, ts, (oldTs, newTs) -> oldTs.getTs() < newTs.getTs() ? newTs : oldTs);
120 120 });
121 121 List<TsKvLatestEntity> latestEntities = new ArrayList<>(trueLatest.values());
  122 + if (batchSortEnabled) {
  123 + latestEntities.sort(Comparator.comparing((Function<TsKvLatestEntity, UUID>) AbstractTsKvEntity::getEntityId)
  124 + .thenComparingInt(AbstractTsKvEntity::getKey));
  125 + }
122 126 insertLatestTsRepository.saveOrUpdate(latestEntities);
123   - });
  127 + }, (l, r) -> 0);
124 128 }
125 129
126 130 @PreDestroy
... ...
... ... @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
33 33 import org.thingsboard.server.common.data.kv.TsKvEntry;
34 34 import org.thingsboard.server.common.stats.StatsFactory;
35 35 import org.thingsboard.server.dao.DaoUtil;
  36 +import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
36 37 import org.thingsboard.server.dao.model.sqlts.timescale.ts.TimescaleTsKvEntity;
37 38 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
38 39 import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
... ... @@ -43,11 +44,7 @@ import org.thingsboard.server.dao.util.TimescaleDBTsDao;
43 44
44 45 import javax.annotation.PostConstruct;
45 46 import javax.annotation.PreDestroy;
46   -import java.util.ArrayList;
47   -import java.util.Collections;
48   -import java.util.List;
49   -import java.util.Optional;
50   -import java.util.UUID;
  47 +import java.util.*;
51 48 import java.util.concurrent.CompletableFuture;
52 49 import java.util.function.Function;
53 50
... ... @@ -78,12 +75,17 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
78 75 .maxDelay(tsMaxDelay)
79 76 .statsPrintIntervalMs(tsStatsPrintIntervalMs)
80 77 .statsNamePrefix("ts.timescale")
  78 + .batchSortEnabled(batchSortEnabled)
81 79 .build();
82 80
83 81 Function<TimescaleTsKvEntity, Integer> hashcodeFunction = entity -> entity.getEntityId().hashCode();
84 82 tsQueue = new TbSqlBlockingQueueWrapper<>(tsParams, hashcodeFunction, timescaleBatchThreads, statsFactory);
85 83
86   - tsQueue.init(logExecutor, v -> insertRepository.saveOrUpdate(v));
  84 + tsQueue.init(logExecutor, v -> insertRepository.saveOrUpdate(v),
  85 + Comparator.comparing((Function<TimescaleTsKvEntity, UUID>) AbstractTsKvEntity::getEntityId)
  86 + .thenComparing(AbstractTsKvEntity::getKey)
  87 + .thenComparing(AbstractTsKvEntity::getTs)
  88 + );
87 89 }
88 90
89 91 @PreDestroy
... ...
1 1 TB_QUEUE_TYPE=kafka
2 2 TB_KAFKA_SERVERS=kafka:9092
  3 +TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100
... ...
... ... @@ -21,7 +21,7 @@
21 21
22 22 <parent>
23 23 <groupId>org.thingsboard</groupId>
24   - <version>3.1.2-SNAPSHOT</version>
  24 + <version>3.2.0-SNAPSHOT</version>
25 25 <artifactId>msa</artifactId>
26 26 </parent>
27 27 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -25,7 +25,7 @@ kafka:
25 25 # Kafka Bootstrap Servers
26 26 servers: "localhost:9092"
27 27 replication_factor: "1"
28   - topic_properties: "retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600"
  28 + topic_properties: "retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100"
29 29 use_confluent_cloud: false
30 30 confluent:
31 31 sasl:
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>msa</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -34,7 +34,7 @@ function KafkaProducer() {
34 34 this.send = async (responseTopic, scriptId, rawResponse, headers) => {
35 35
36 36 if (!topics.includes(responseTopic)) {
37   - let createResponseTopicResult = await createTopic(responseTopic);
  37 + let createResponseTopicResult = await createTopic(responseTopic, 1);
38 38 topics.push(responseTopic);
39 39 if (createResponseTopicResult) {
40 40 logger.info('Created new topic: %s', requestTopic);
... ... @@ -88,7 +88,18 @@ function KafkaProducer() {
88 88 kafkaAdmin = kafkaClient.admin();
89 89 await kafkaAdmin.connect();
90 90
91   - let createRequestTopicResult = await createTopic(requestTopic);
  91 + let partitions = 1;
  92 +
  93 + for (let i = 0; i < configEntries.length; i++) {
  94 + let param = configEntries[i];
  95 + if (param.name === 'partitions') {
  96 + partitions = param.value;
  97 + configEntries.splice(i, 1);
  98 + break;
  99 + }
  100 + }
  101 +
  102 + let createRequestTopicResult = await createTopic(requestTopic, partitions);
92 103
93 104 if (createRequestTopicResult) {
94 105 logger.info('Created new topic: %s', requestTopic);
... ... @@ -121,10 +132,11 @@ function KafkaProducer() {
121 132 }
122 133 })();
123 134
124   -function createTopic(topic) {
  135 +function createTopic(topic, partitions) {
125 136 return kafkaAdmin.createTopics({
126 137 topics: [{
127 138 topic: topic,
  139 + numPartitions: partitions,
128 140 replicationFactor: replicationFactor,
129 141 configEntries: configEntries
130 142 }]
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>msa</artifactId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>msa</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>msa</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.msa</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.msa</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard.msa</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa.transport</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>msa</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>msa</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.msa</groupId>
... ...
... ... @@ -19,11 +19,11 @@
19 19 <modelVersion>4.0.0</modelVersion>
20 20 <parent>
21 21 <groupId>org.thingsboard</groupId>
22   - <version>3.1.2-SNAPSHOT</version>
  22 + <version>3.2.0-SNAPSHOT</version>
23 23 <artifactId>thingsboard</artifactId>
24 24 </parent>
25 25 <artifactId>netty-mqtt</artifactId>
26   - <version>3.1.2-SNAPSHOT</version>
  26 + <version>3.2.0-SNAPSHOT</version>
27 27 <packaging>jar</packaging>
28 28
29 29 <name>Netty MQTT Client</name>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <groupId>org.thingsboard</groupId>
22 22 <artifactId>thingsboard</artifactId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <packaging>pom</packaging>
25 25
26 26 <name>Thingsboard</name>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>rest-client</artifactId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>rule-engine</artifactId>
... ...
... ... @@ -22,7 +22,7 @@
22 22 <modelVersion>4.0.0</modelVersion>
23 23 <parent>
24 24 <groupId>org.thingsboard</groupId>
25   - <version>3.1.2-SNAPSHOT</version>
  25 + <version>3.2.0-SNAPSHOT</version>
26 26 <artifactId>rule-engine</artifactId>
27 27 </parent>
28 28 <groupId>org.thingsboard.rule-engine</groupId>
... ...
... ... @@ -22,7 +22,7 @@
22 22 <modelVersion>4.0.0</modelVersion>
23 23 <parent>
24 24 <groupId>org.thingsboard</groupId>
25   - <version>3.1.2-SNAPSHOT</version>
  25 + <version>3.2.0-SNAPSHOT</version>
26 26 <artifactId>rule-engine</artifactId>
27 27 </parent>
28 28 <groupId>org.thingsboard.rule-engine</groupId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>tools</artifactId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -77,11 +77,11 @@ queue:
77 77 security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
78 78 other:
79 79 topic-properties:
80   - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
81   - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
82   - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
83   - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
84   - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}"
  80 + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  81 + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  82 + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  83 + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  84 + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}"
85 85 aws_sqs:
86 86 use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}"
87 87 access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -70,11 +70,11 @@ queue:
70 70 security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
71 71 other:
72 72 topic-properties:
73   - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
74   - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
75   - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
76   - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
77   - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}"
  73 + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  74 + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  75 + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  76 + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  77 + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}"
78 78 aws_sqs:
79 79 use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}"
80 80 access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>transport</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard.transport</groupId>
... ...
... ... @@ -98,11 +98,11 @@ queue:
98 98 security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
99 99 other:
100 100 topic-properties:
101   - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
102   - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
103   - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
104   - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}"
105   - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}"
  101 + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  102 + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  103 + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  104 + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}"
  105 + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}"
106 106 aws_sqs:
107 107 use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}"
108 108 access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <artifactId>transport</artifactId>
... ...
... ... @@ -20,7 +20,7 @@
20 20 <modelVersion>4.0.0</modelVersion>
21 21 <parent>
22 22 <groupId>org.thingsboard</groupId>
23   - <version>3.1.2-SNAPSHOT</version>
  23 + <version>3.2.0-SNAPSHOT</version>
24 24 <artifactId>thingsboard</artifactId>
25 25 </parent>
26 26 <groupId>org.thingsboard</groupId>
... ...
... ... @@ -123,7 +123,7 @@ export abstract class EntityComponent<T extends BaseData<HasId>,
123 123 if (isString(obj[curr])) {
124 124 acc[curr] = obj[curr].trim();
125 125 } else if (isObject(obj[curr])) {
126   - acc[curr] = this.deepTrim(obj[curr])
  126 + acc[curr] = this.deepTrim(obj[curr]);
127 127 } else {
128 128 acc[curr] = obj[curr];
129 129 }
... ...
... ... @@ -37,6 +37,7 @@ import { getCurrentAuthUser } from '@app/core/auth/auth.selectors';
37 37 import { Authority } from '@shared/models/authority.enum';
38 38 import { DialogService } from '@core/services/dialog.service';
39 39 import { ImportExportService } from '@home/components/import-export/import-export.service';
  40 +import { Direction } from "@shared/models/page/sort-order";
40 41
41 42 @Injectable()
42 43 export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableConfig<WidgetsBundle>> {
... ... @@ -55,6 +56,7 @@ export class WidgetsBundlesTableConfigResolver implements Resolve<EntityTableCon
55 56 this.config.entityComponent = WidgetsBundleComponent;
56 57 this.config.entityTranslations = entityTypeTranslations.get(EntityType.WIDGETS_BUNDLE);
57 58 this.config.entityResources = entityTypeResources.get(EntityType.WIDGETS_BUNDLE);
  59 + this.config.defaultSortOrder = {property: 'title', direction: Direction.ASC};
58 60
59 61 this.config.entityTitle = (widgetsBundle) => widgetsBundle ?
60 62 widgetsBundle.title : '';
... ...