Skip to content

Commit 566c2b8

Browse files
committed
add memory control when caching last values
1 parent 85fdf8c commit 566c2b8

4 files changed

Lines changed: 95 additions & 25 deletions

File tree

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,8 @@ public class IoTDBConfig {
11581158
*/
11591159
private boolean cacheLastValuesForLoad = true;
11601160

1161+
private long cacheLastValuesMemoryBudgetInByte = 4 * 1024 * 1024;
1162+
11611163
IoTDBConfig() {}
11621164

11631165
public int getMaxLogEntriesNumPerBatch() {
@@ -4096,4 +4098,12 @@ public boolean isCacheLastValuesForLoad() {
40964098
public void setCacheLastValuesForLoad(boolean cacheLastValuesForLoad) {
40974099
this.cacheLastValuesForLoad = cacheLastValuesForLoad;
40984100
}
4101+
4102+
public long getCacheLastValuesMemoryBudgetInByte() {
4103+
return cacheLastValuesMemoryBudgetInByte;
4104+
}
4105+
4106+
public void setCacheLastValuesMemoryBudgetInByte(long cacheLastValuesMemoryBudgetInByte) {
4107+
this.cacheLastValuesMemoryBudgetInByte = cacheLastValuesMemoryBudgetInByte;
4108+
}
40994109
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,12 @@ private void loadLoadTsFileProps(TrimProperties properties) throws IOException {
22722272
Boolean.parseBoolean(
22732273
properties.getProperty(
22742274
"cache_last_values_for_load", String.valueOf(conf.isCacheLastValuesForLoad()))));
2275+
2276+
conf.setCacheLastValuesMemoryBudgetInByte(
2277+
Long.parseLong(
2278+
properties.getProperty(
2279+
"cache_last_values_memory_budget_in_byte",
2280+
String.valueOf(conf.getCacheLastValuesMemoryBudgetInByte()))));
22752281
}
22762282

22772283
private void loadLoadTsFileHotModifiedProp(TrimProperties properties) throws IOException {

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/TsFileResourceUtils.java

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.apache.tsfile.read.reader.page.TimePageReader;
5050
import org.apache.tsfile.read.reader.page.ValuePageReader;
5151
import org.apache.tsfile.utils.Pair;
52+
import org.apache.tsfile.utils.RamUsageEstimator;
5253
import org.apache.tsfile.utils.TsPrimitiveType;
5354
import org.apache.tsfile.write.writer.TsFileIOWriter;
5455
import org.slf4j.Logger;
@@ -430,20 +431,21 @@ public static void updateTsFileResource(
430431
: tsFileResource.getTimeIndex();
431432
Map<IDeviceID, List<Pair<String, TimeValuePair>>> deviceLastValues =
432433
tsFileResource.getLastValues();
434+
long lastValueMemCost = 0;
433435
if (cacheLastValue && deviceLastValues == null) {
434436
deviceLastValues = new HashMap<>(device2Metadata.size());
435437
}
436438
for (Map.Entry<IDeviceID, List<TimeseriesMetadata>> entry : device2Metadata.entrySet()) {
437439
List<Pair<String, TimeValuePair>> seriesLastValues = null;
438-
if (cacheLastValue) {
440+
if (deviceLastValues != null) {
439441
seriesLastValues = new ArrayList<>(entry.getValue().size());
440442
}
441443

442444
for (TimeseriesMetadata timeseriesMetaData : entry.getValue()) {
443445
newTimeIndex.updateStartTime(
444446
entry.getKey(), timeseriesMetaData.getStatistics().getStartTime());
445447
newTimeIndex.updateEndTime(entry.getKey(), timeseriesMetaData.getStatistics().getEndTime());
446-
if (cacheLastValue) {
448+
if (deviceLastValues != null) {
447449
if (timeseriesMetaData.getTsDataType() != TSDataType.BLOB) {
448450
TsPrimitiveType value;
449451
value =
@@ -461,10 +463,33 @@ public static void updateTsFileResource(
461463
}
462464
}
463465
}
464-
if (cacheLastValue) {
465-
deviceLastValues
466-
.computeIfAbsent(entry.getKey(), deviceID -> new ArrayList<>())
467-
.addAll(seriesLastValues);
466+
if (deviceLastValues != null) {
467+
lastValueMemCost += entry.getKey().ramBytesUsed();
468+
for (Pair<String, TimeValuePair> lastValue : seriesLastValues) {
469+
if (lastValue == null) {
470+
continue;
471+
}
472+
// pair
473+
lastValueMemCost += RamUsageEstimator.shallowSizeOf(lastValue);
474+
// measurement name
475+
lastValueMemCost += RamUsageEstimator.sizeOf(lastValue.left);
476+
TimeValuePair right = lastValue.getRight();
477+
lastValueMemCost +=
478+
right != null ? right.getSize() : RamUsageEstimator.NUM_BYTES_OBJECT_REF;
479+
}
480+
// ArrayList
481+
lastValueMemCost +=
482+
(long) seriesLastValues.size() * RamUsageEstimator.NUM_BYTES_OBJECT_REF
483+
+ RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
484+
+ RamUsageEstimator.NUM_BYTES_ARRAY_HEADER;
485+
lastValueMemCost += RamUsageEstimator.HASHTABLE_RAM_BYTES_PER_ENTRY;
486+
if (lastValueMemCost <= config.getCacheLastValuesMemoryBudgetInByte()) {
487+
deviceLastValues
488+
.computeIfAbsent(entry.getKey(), deviceID -> new ArrayList<>())
489+
.addAll(seriesLastValues);
490+
} else {
491+
deviceLastValues = null;
492+
}
468493
}
469494
}
470495
tsFileResource.setTimeIndex(newTimeIndex);

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/load/LoadTsFileManager.java

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import org.apache.tsfile.file.metadata.IDeviceID;
6161
import org.apache.tsfile.read.TimeValuePair;
6262
import org.apache.tsfile.utils.Pair;
63+
import org.apache.tsfile.utils.RamUsageEstimator;
6364
import org.apache.tsfile.utils.TsPrimitiveType;
6465
import org.apache.tsfile.write.writer.TsFileIOWriter;
6566
import org.slf4j.Logger;
@@ -78,6 +79,7 @@
7879
import java.util.Optional;
7980
import java.util.concurrent.ConcurrentHashMap;
8081
import java.util.concurrent.PriorityBlockingQueue;
82+
import java.util.concurrent.atomic.AtomicLong;
8183
import java.util.concurrent.atomic.AtomicReference;
8284
import java.util.stream.Collectors;
8385
import java.util.stream.Stream;
@@ -543,33 +545,60 @@ private void endTsFileResource(
543545
if (IoTDBDescriptor.getInstance().getConfig().isCacheLastValuesForLoad()) {
544546
deviceLastValues = new HashMap<>();
545547
}
548+
AtomicLong lastValuesMemCost = new AtomicLong(0);
549+
546550
for (final ChunkGroupMetadata chunkGroupMetadata : writer.getChunkGroupMetadataList()) {
547551
final IDeviceID device = chunkGroupMetadata.getDevice();
548552
for (final ChunkMetadata chunkMetadata : chunkGroupMetadata.getChunkMetadataList()) {
549553
tsFileResource.updateStartTime(device, chunkMetadata.getStartTime());
550554
tsFileResource.updateEndTime(device, chunkMetadata.getEndTime());
551555
if (deviceLastValues != null) {
552-
deviceLastValues
553-
.computeIfAbsent(device, d -> new HashMap<>())
554-
.compute(
555-
chunkMetadata.getMeasurementUid(),
556-
(m, oldPair) -> {
557-
if (oldPair != null && oldPair.getTimestamp() > chunkMetadata.getEndTime()) {
558-
return oldPair;
559-
}
560-
TsPrimitiveType lastValue =
561-
chunkMetadata.getStatistics() != null
562-
&& chunkMetadata.getDataType() != TSDataType.BLOB
563-
? TsPrimitiveType.getByType(
564-
chunkMetadata.getDataType() == TSDataType.VECTOR
565-
? TSDataType.INT64
566-
: chunkMetadata.getDataType(),
567-
chunkMetadata.getStatistics().getLastValue())
568-
: null;
569-
return lastValue != null
556+
Map<String, TimeValuePair> deviceMap =
557+
deviceLastValues.computeIfAbsent(
558+
device,
559+
d -> {
560+
Map<String, TimeValuePair> map = new HashMap<>();
561+
lastValuesMemCost.addAndGet(RamUsageEstimator.shallowSizeOf(map));
562+
lastValuesMemCost.addAndGet(device.ramBytesUsed());
563+
return map;
564+
});
565+
int prevSize = deviceMap.size();
566+
deviceMap.compute(
567+
chunkMetadata.getMeasurementUid(),
568+
(m, oldPair) -> {
569+
if (oldPair != null && oldPair.getTimestamp() > chunkMetadata.getEndTime()) {
570+
return oldPair;
571+
}
572+
TsPrimitiveType lastValue =
573+
chunkMetadata.getStatistics() != null
574+
&& chunkMetadata.getDataType() != TSDataType.BLOB
575+
? TsPrimitiveType.getByType(
576+
chunkMetadata.getDataType() == TSDataType.VECTOR
577+
? TSDataType.INT64
578+
: chunkMetadata.getDataType(),
579+
chunkMetadata.getStatistics().getLastValue())
580+
: null;
581+
TimeValuePair timeValuePair =
582+
lastValue != null
570583
? new TimeValuePair(chunkMetadata.getEndTime(), lastValue)
571584
: null;
572-
});
585+
if (oldPair != null) {
586+
lastValuesMemCost.addAndGet(-oldPair.getSize());
587+
}
588+
if (timeValuePair != null) {
589+
lastValuesMemCost.addAndGet(timeValuePair.getSize());
590+
}
591+
return timeValuePair;
592+
});
593+
int afterSize = deviceMap.size();
594+
lastValuesMemCost.addAndGet(
595+
(afterSize - prevSize) * RamUsageEstimator.HASHTABLE_RAM_BYTES_PER_ENTRY);
596+
if (lastValuesMemCost.get()
597+
> IoTDBDescriptor.getInstance()
598+
.getConfig()
599+
.getCacheLastValuesMemoryBudgetInByte()) {
600+
deviceLastValues = null;
601+
}
573602
}
574603
}
575604
}

0 commit comments

Comments
 (0)