Commit 75b77f09f8e4e2535988adc1309da24bfbb5c1ef

Authored by Andrew Shvayka
Committed by GitHub
2 parents 68c7f8a9 7f01a980

Merge pull request #1014 from davidgin/fixedPartitions

address issue  Add partition granularity to time series data #1006  h…
... ... @@ -205,7 +205,7 @@ cassandra:
205 205 read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}"
206 206 write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}"
207 207 default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}"
208   - # Specify partitioning size for timestamp key-value storage. Example MINUTES, HOURS, DAYS, MONTHS
  208 + # Specify partitioning size for timestamp key-value storage. Example MINUTES, HOURS, DAYS, MONTHS,INDEFINITE
209 209 ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}"
210 210 ts_key_value_ttl: "${TS_KV_TTL:0}"
211 211 buffer_size: "${CASSANDRA_QUERY_BUFFER_SIZE:200000}"
... ...
... ... @@ -54,10 +54,11 @@ import javax.annotation.PreDestroy;
54 54 import java.time.Instant;
55 55 import java.time.LocalDateTime;
56 56 import java.time.ZoneOffset;
57   -import java.util.ArrayList;
58   -import java.util.Collections;
  57 +import java.util.Arrays;
59 58 import java.util.List;
  59 +import java.util.ArrayList;
60 60 import java.util.Optional;
  61 +import java.util.Collections;
61 62 import java.util.stream.Collectors;
62 63
63 64 import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
... ... @@ -76,6 +77,9 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
76 77 public static final String SELECT_PREFIX = "SELECT ";
77 78 public static final String EQUALS_PARAM = " = ? ";
78 79
  80 +
  81 + private static List<Long> FIXED_PARTITION = Arrays.asList(new Long[]{0L});
  82 +
79 83 @Autowired
80 84 private Environment environment;
81 85
... ... @@ -163,14 +167,25 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
163 167 }
164 168 }
165 169
  170 + public boolean isFixedPartitioning() {
  171 + return tsFormat.getTruncateUnit().equals(TsPartitionDate.EPOCH_START);
  172 + }
  173 +
  174 + private ListenableFuture<List<Long>> getPartitionsFuture(TsKvQuery query, EntityId entityId, long minPartition, long maxPartition) {
  175 + if (isFixedPartitioning()) { //no need to fetch partitions from DB
  176 + return Futures.immediateFuture(FIXED_PARTITION);
  177 + }
  178 + ResultSetFuture partitionsFuture = fetchPartitions(entityId, query.getKey(), minPartition, maxPartition);
  179 + return Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
  180 + }
  181 +
166 182 private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, TsKvQuery query) {
  183 +
167 184 long minPartition = toPartitionTs(query.getStartTs());
168 185 long maxPartition = toPartitionTs(query.getEndTs());
169 186
170   - ResultSetFuture partitionsFuture = fetchPartitions(entityId, query.getKey(), minPartition, maxPartition);
171   -
  187 + final ListenableFuture<List<Long>> partitionsListFuture = getPartitionsFuture(query, entityId, minPartition, maxPartition);
172 188 final SimpleListenableFuture<List<TsKvEntry>> resultFuture = new SimpleListenableFuture<>();
173   - final ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
174 189
175 190 Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
176 191 @Override
... ... @@ -181,7 +196,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
181 196
182 197 @Override
183 198 public void onFailure(Throwable t) {
184   - log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
  199 + log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), toPartitionTs(query.getStartTs()), toPartitionTs(query.getEndTs()), t);
185 200 }
186 201 }, readResultsProcessingExecutor);
187 202
... ... @@ -229,10 +244,8 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
229 244 final long endTs = query.getEndTs();
230 245 final long ts = startTs + (endTs - startTs) / 2;
231 246
232   - ResultSetFuture partitionsFuture = fetchPartitions(entityId, key, minPartition, maxPartition);
233   -
234   - ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
235 247
  248 + ListenableFuture<List<Long>> partitionsListFuture = getPartitionsFuture(query, entityId, minPartition, maxPartition);
236 249 ListenableFuture<List<ResultSet>> aggregationChunks = Futures.transformAsync(partitionsListFuture,
237 250 getFetchChunksAsyncFunction(entityId, key, aggregation, startTs, endTs), readResultsProcessingExecutor);
238 251
... ... @@ -308,6 +321,9 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
308 321
309 322 @Override
310 323 public ListenableFuture<Void> savePartition(EntityId entityId, long tsKvEntryTs, String key, long ttl) {
  324 + if (isFixedPartitioning()) {
  325 + return Futures.immediateFuture(null);
  326 + }
311 327 ttl = computeTtl(ttl);
312 328 long partition = toPartitionTs(tsKvEntryTs);
313 329 log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key);
... ...
... ... @@ -16,22 +16,25 @@
16 16 package org.thingsboard.server.dao.timeseries;
17 17
18 18 import java.time.LocalDateTime;
  19 +import java.time.ZoneOffset;
19 20 import java.time.temporal.ChronoUnit;
20 21 import java.time.temporal.TemporalUnit;
21 22 import java.util.Optional;
22 23
23 24 public enum TsPartitionDate {
24 25
25   - MINUTES("yyyy-MM-dd-HH-mm", ChronoUnit.MINUTES), HOURS("yyyy-MM-dd-HH", ChronoUnit.HOURS), DAYS("yyyy-MM-dd", ChronoUnit.DAYS), MONTHS("yyyy-MM", ChronoUnit.MONTHS), YEARS("yyyy", ChronoUnit.YEARS);
  26 + MINUTES("yyyy-MM-dd-HH-mm", ChronoUnit.MINUTES), HOURS("yyyy-MM-dd-HH", ChronoUnit.HOURS), DAYS("yyyy-MM-dd", ChronoUnit.DAYS), MONTHS("yyyy-MM", ChronoUnit.MONTHS), YEARS("yyyy", ChronoUnit.YEARS),INDEFINITE("",ChronoUnit.FOREVER);
26 27
27 28 private final String pattern;
28 29 private final transient TemporalUnit truncateUnit;
  30 + public final static LocalDateTime EPOCH_START = LocalDateTime.ofEpochSecond(0,0, ZoneOffset.UTC);
29 31
30 32 TsPartitionDate(String pattern, TemporalUnit truncateUnit) {
31 33 this.pattern = pattern;
32 34 this.truncateUnit = truncateUnit;
33 35 }
34 36
  37 +
35 38 public String getPattern() {
36 39 return pattern;
37 40 }
... ... @@ -46,6 +49,8 @@ public enum TsPartitionDate {
46 49 return time.truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
47 50 case YEARS:
48 51 return time.truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
  52 + case INDEFINITE:
  53 + return EPOCH_START;
49 54 default:
50 55 return time.truncatedTo(truncateUnit);
51 56 }
... ...