This is an automated email from the ASF dual-hosted git repository.
jiangtian pushed a commit to branch preallocate_array_list
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/preallocate_array_list by this
push:
new e702afe02d1 add memtable cache
e702afe02d1 is described below
commit e702afe02d17af7ca64d153390e6aecdaf503957
Author: Tian Jiang <[email protected]>
AuthorDate: Wed Apr 23 09:32:23 2025 +0800
add memtable cache
---
.../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 19 ++++++++++++++++
.../org/apache/iotdb/db/conf/IoTDBDescriptor.java | 25 ++++++++++++----------
.../protocol/thrift/impl/ClientRPCServiceImpl.java | 17 ++++++++-------
.../db/storageengine/dataregion/DataRegion.java | 21 ++++++++++++++++++
.../dataregion/memtable/AbstractMemTable.java | 8 +++++++
.../memtable/AbstractWritableMemChunk.java | 16 ++++++++------
.../memtable/AlignedWritableMemChunk.java | 15 ++++++++++++-
.../memtable/AlignedWritableMemChunkGroup.java | 5 +++++
.../dataregion/memtable/IMemTable.java | 3 +++
.../dataregion/memtable/IWritableMemChunk.java | 3 +++
.../memtable/IWritableMemChunkGroup.java | 3 +++
.../dataregion/memtable/TsFileProcessor.java | 15 ++++++++-----
.../dataregion/memtable/WritableMemChunk.java | 15 ++++++++++++-
.../dataregion/memtable/WritableMemChunkGroup.java | 7 ++++++
14 files changed, 140 insertions(+), 32 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index b5d5d186953..d3594d03a37 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -1154,6 +1154,9 @@ public class IoTDBConfig {
private boolean enableGCThrottle = false;
private int gcThrottleTimeMs = 1000;
+ private boolean enableMemTableCache = true;
+ private int maxCachedMemTablePerRegion = 1;
+
IoTDBConfig() {}
public int getMaxLogEntriesNumPerBatch() {
@@ -4098,4 +4101,20 @@ public class IoTDBConfig {
public void setEnableGCThrottle(boolean enableGCThrottle) {
this.enableGCThrottle = enableGCThrottle;
}
+
+ public boolean isEnableMemTableCache() {
+ return enableMemTableCache;
+ }
+
+ public void setEnableMemTableCache(boolean enableMemTableCache) {
+ this.enableMemTableCache = enableMemTableCache;
+ }
+
+ public int getMaxCachedMemTablePerRegion() {
+ return maxCachedMemTablePerRegion;
+ }
+
+ public void setMaxCachedMemTablePerRegion(int maxCachedMemTablePerRegion) {
+ this.maxCachedMemTablePerRegion = maxCachedMemTablePerRegion;
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index e6e5377009d..702807607d9 100755
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -1074,20 +1074,23 @@ public class IoTDBDescriptor {
"detail_container_min_degrade_memory_in_bytes",
String.valueOf(conf.getDetailContainerMinDegradeMemoryInBytes()))));
- conf.setEnableGCThrottle(Boolean.parseBoolean(
- properties.getProperty(
- "enable_gc_throttle",
- String.valueOf(conf.isEnableGCThrottle())
- )
- ));
+ conf.setEnableGCThrottle(
+ Boolean.parseBoolean(
+ properties.getProperty(
+ "enable_gc_throttle",
String.valueOf(conf.isEnableGCThrottle()))));
conf.setGcThrottleTimeMs(
Integer.parseInt(
properties.getProperty(
- "gc_throttle_time_ms",
- String.valueOf(conf.getGcThrottleTimeMs())
- )
- )
- );
+ "gc_throttle_time_ms",
String.valueOf(conf.getGcThrottleTimeMs()))));
+
+ conf.setEnableMemTableCache(
+ Boolean.parseBoolean(
+ properties.getProperty(
+ "enable_memtable_cache",
String.valueOf(conf.isEnableGCThrottle()))));
+ conf.setMaxCachedMemTablePerRegion(
+ Integer.parseInt(
+ properties.getProperty(
+ "max_cached_memtable_per_region",
String.valueOf(conf.getGcThrottleTimeMs()))));
loadIoTConsensusProps(properties);
loadIoTConsensusV2Props(properties);
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
index e4b9f4514dc..6f72f46ae08 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java
@@ -19,7 +19,6 @@
package org.apache.iotdb.db.protocol.thrift.impl;
-import java.util.Random;
import org.apache.iotdb.common.rpc.thrift.TAggregationType;
import org.apache.iotdb.common.rpc.thrift.TEndPoint;
import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
@@ -215,6 +214,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import java.util.Random;
import java.util.concurrent.TimeUnit;
import static org.apache.iotdb.commons.partition.DataPartition.NOT_ASSIGNED;
@@ -3065,6 +3065,7 @@ public class ClientRPCServiceImpl implements
IClientRPCServiceWithHandler {
}
private static final Random throttleRandom = new Random();
+
public static void gcThrottle() {
if (!IoTDBDescriptor.getInstance().getConfig().isEnableGCThrottle()) {
return;
@@ -3072,13 +3073,13 @@ public class ClientRPCServiceImpl implements
IClientRPCServiceWithHandler {
int minimumGcTimePercentToThrottle = 20;
long gcTimePercentage =
JvmGcMonitorMetrics.getInstance().getGcData().getGcTimePercentage();
// if gc time is above 20%, pause the request with the probability equals
to gc time percent
- if (gcTimePercentage > minimumGcTimePercentToThrottle &&
throttleRandom.nextInt(100) < gcTimePercentage) {
- try {
-
Thread.sleep(IoTDBDescriptor.getInstance().getConfig().getGcThrottleTimeMs());
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
+ if (gcTimePercentage > minimumGcTimePercentToThrottle
+ && throttleRandom.nextInt(100) < gcTimePercentage) {
+ try {
+
Thread.sleep(IoTDBDescriptor.getInstance().getConfig().getGcThrottleTimeMs());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
}
-
+ }
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
index 8880f4f1723..90a03098501 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java
@@ -176,6 +176,8 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@@ -333,6 +335,10 @@ public class DataRegion implements IDataRegionForQuery {
private ILoadDiskSelector ordinaryLoadDiskSelector;
private ILoadDiskSelector pipeAndIoTV2LoadDiskSelector;
+ private BlockingQueue<IMemTable> memTableCache =
+ new ArrayBlockingQueue<>(
+
IoTDBDescriptor.getInstance().getConfig().getMaxCachedMemTablePerRegion());
+
/**
* Construct a database processor.
*
@@ -3942,4 +3948,19 @@ public class DataRegion implements IDataRegionForQuery {
return DataNodeTTLCache.getInstance().getTTLForTable(databaseName,
insertNode.getTableName());
}
}
+
+ public IMemTable getCachedMemTable() {
+ if (IoTDBDescriptor.getInstance().getConfig().isEnableMemTableCache()) {
+ return memTableCache.poll();
+ } else {
+ return null;
+ }
+ }
+
+ @SuppressWarnings({"ResultOfMethodCallIgnored", "java:S899"})
+ public void cacheMemTable(IMemTable memTable) {
+ if (IoTDBDescriptor.getInstance().getConfig().isEnableMemTableCache()) {
+ memTableCache.offer(memTable);
+ }
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
index d550781858f..a664dba57cd 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractMemTable.java
@@ -411,6 +411,14 @@ public abstract class AbstractMemTable implements
IMemTable {
@Override
public void clear() {
memTableMap.clear();
+ reset();
+ }
+
+ @Override
+ public void reset() {
+ for (IWritableMemChunkGroup value : memTableMap.values()) {
+ value.reset();
+ }
memSize = 0;
seriesNumber = 0;
totalPointsNum = 0;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
index ac71e3da6bb..cdcc24978d7 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AbstractWritableMemChunk.java
@@ -50,14 +50,13 @@ public abstract class AbstractWritableMemChunk implements
IWritableMemChunk {
* method must ensure success because it's part of flushing.
*
* @param tvList
+ * @return whether the TvList is cleared (exclusively held by the MemTable)
*/
- protected void maybeReleaseTvList(TVList tvList) {
+ protected boolean maybeReleaseTvList(TVList tvList) {
long startTimeInMs = System.currentTimeMillis();
- boolean succeed = false;
- while (!succeed) {
+ while (true) {
try {
- tryReleaseTvList(tvList);
- succeed = true;
+ return tryReleaseTvList(tvList);
} catch (MemoryNotEnoughException ex) {
long waitQueryInMs = System.currentTimeMillis() - startTimeInMs;
if (waitQueryInMs > MAX_WAIT_QUERY_MS) {
@@ -88,11 +87,15 @@ public abstract class AbstractWritableMemChunk implements
IWritableMemChunk {
}
}
- private void tryReleaseTvList(TVList tvList) {
+ /**
+ * @return whether the list is cleared.
+ */
+ private boolean tryReleaseTvList(TVList tvList) {
tvList.lockQueryList();
try {
if (tvList.getQueryContextSet().isEmpty()) {
tvList.clear();
+ return true;
} else {
QueryContext firstQuery =
tvList.getQueryContextSet().iterator().next();
// transfer memory from write process to read process. Here it
reserves read memory and
@@ -104,6 +107,7 @@ public abstract class AbstractWritableMemChunk implements
IWritableMemChunk {
}
// update current TVList owner to first query in the list
tvList.setOwnerQuery(firstQuery);
+ return false;
}
} finally {
tvList.unlockQueryList();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
index d20866d0c79..5c63b317215 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java
@@ -697,12 +697,25 @@ public class AlignedWritableMemChunk extends
AbstractWritableMemChunk {
@Override
public void release() {
- maybeReleaseTvList(list);
+ boolean listCleared = maybeReleaseTvList(list);
+ if (!listCleared) {
+ // if the list is not cleared, we cannot reuse it
+ list = null;
+ }
for (AlignedTVList alignedTvList : sortedList) {
maybeReleaseTvList(alignedTvList);
}
}
+ @Override
+ public void reset() {
+ sortedList.clear();
+ if (list == null) {
+ list = AlignedTVList.newAlignedList(dataTypes);
+ }
+ sortedRowCount = 0;
+ }
+
@Override
public long getFirstPoint() {
if (rowCount() == 0) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
index 36acdedf9bc..f15fffa62e2 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunkGroup.java
@@ -72,6 +72,11 @@ public class AlignedWritableMemChunkGroup implements
IWritableMemChunkGroup {
memChunk.release();
}
+ @Override
+ public void reset() {
+ memChunk.reset();
+ }
+
@Override
public long count() {
return memChunk.count();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
index 44098b69a56..91fb831d955 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IMemTable.java
@@ -140,6 +140,9 @@ public interface IMemTable extends WALEntryValue {
/** putBack all the memory resources. */
void clear();
+ /** Prepare the memtable for new insertions, keeping the inner structures
for reuse. */
+ void reset();
+
boolean isEmpty();
/**
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
index 13f09a05d8a..2f2e819c9e8 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunk.java
@@ -116,6 +116,9 @@ public interface IWritableMemChunk extends WALEntryValue {
void release();
+ /** Prepare the chunk for the next round of insertion. */
+ void reset();
+
long getFirstPoint();
long getLastPoint();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
index 62bf7700218..f46c7ebd8b9 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/IWritableMemChunkGroup.java
@@ -44,6 +44,9 @@ public interface IWritableMemChunkGroup extends WALEntryValue
{
void release();
+ /** Prepare the chunk group for the next round of insertion. */
+ void reset();
+
long count();
boolean contains(String measurement);
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
index 861b72c923a..ce9cdf5bd23 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java
@@ -453,11 +453,14 @@ public class TsFileProcessor {
}
private void createNewWorkingMemTable() {
- workMemTable =
- MemTableManager.getInstance()
- .getAvailableMemTable(
- dataRegionInfo.getDataRegion().getDatabaseName(),
- dataRegionInfo.getDataRegion().getDataRegionId());
+ workMemTable = dataRegionInfo.getDataRegion().getCachedMemTable();
+ if (workMemTable == null) {
+ workMemTable =
+ MemTableManager.getInstance()
+ .getAvailableMemTable(
+ dataRegionInfo.getDataRegion().getDatabaseName(),
+ dataRegionInfo.getDataRegion().getDataRegionId());
+ }
walNode.onMemTableCreated(workMemTable, tsFileResource.getTsFilePath());
}
@@ -1632,6 +1635,8 @@ public class TsFileProcessor {
for (FlushListener flushListener : flushListeners) {
flushListener.onMemTableFlushed(memTableToFlush);
}
+ memTableToFlush.reset();
+ dataRegionInfo.getDataRegion().cacheMemTable(memTableToFlush);
// Retry to avoid unnecessary read-only mode
int retryCnt = 0;
while (shouldClose && flushingMemTables.isEmpty() && writer != null) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
index 1f4078dfc7d..89ee4445dbd 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java
@@ -504,12 +504,25 @@ public class WritableMemChunk extends
AbstractWritableMemChunk {
@Override
public void release() {
- maybeReleaseTvList(list);
+ boolean listCleared = maybeReleaseTvList(list);
+ if (!listCleared) {
+ // the list cannot be reused if not cleared
+ list = null;
+ }
for (TVList tvList : sortedList) {
maybeReleaseTvList(tvList);
}
}
+ @Override
+ public void reset() {
+ sortedRowCount = 0;
+ sortedList.clear();
+ if (list == null) {
+ list = TVList.newList(schema.getType());
+ }
+ }
+
@Override
public int serializedSize() {
int serializedSize = schema.serializedSize() + list.serializedSize();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
index 854ca9c8d2c..762ca3ed13c 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunkGroup.java
@@ -80,6 +80,13 @@ public class WritableMemChunkGroup implements
IWritableMemChunkGroup {
}
}
+ @Override
+ public void reset() {
+ for (IWritableMemChunk memChunk : memChunkMap.values()) {
+ memChunk.reset();
+ }
+ }
+
@Override
public long count() {
long count = 0;