This is an automated email from the ASF dual-hosted git repository.
shuwenwei pushed a commit to branch table_disk_usage_statistics_with_cache
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to
refs/heads/table_disk_usage_statistics_with_cache by this push:
new 79d39aac851 refactor
79d39aac851 is described below
commit 79d39aac851eaa624d92c9e70fa02328049e0d22
Author: shuwenwei <[email protected]>
AuthorDate: Thu Jan 22 09:53:29 2026 +0800
refactor
---
.../InformationSchemaContentSupplierFactory.java | 4 +
.../db/storageengine/dataregion/DataRegion.java | 3 +
.../AbstractTableSizeCacheWriter.java | 25 ---
.../tableDiskUsageCache/TableDiskUsageCache.java | 180 ++++++++++++++++-----
.../TableDiskUsageCacheReader.java | 64 +++-----
.../TsFileTableDiskUsageCacheWriter.java | 3 -
6 files changed, 167 insertions(+), 112 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
index 67b1aa8c1f9..a5519bfda33 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/relational/InformationSchemaContentSupplierFactory.java
@@ -1320,6 +1320,10 @@ public class InformationSchemaContentSupplierFactory {
long start = System.nanoTime();
try {
+ if (!currentDataRegionCacheReader.prepareCacheReader(start,
maxRuntime)) {
+ return null;
+ }
+
if (!currentDataRegionCacheReader.loadObjectFileTableSizeCache(start,
maxRuntime)) {
return null;
}
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 45faf95e501..305f1a044a6 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
@@ -417,6 +417,9 @@ public class DataRegion implements IDataRegionForQuery {
IoTDBThreadPoolFactory.newSingleThreadExecutor(
databaseName + "-" + dataRegionIdString + "-UpgradeMod");
+ TableDiskUsageCache.getInstance()
+ .registerRegion(databaseName, Integer.parseInt(dataRegionIdString));
+
// recover tsfiles unless consensus protocol is ratis and storage engine
is not ready
if
(config.getDataRegionConsensusProtocolClass().equals(ConsensusFactory.RATIS_CONSENSUS)
&& !StorageEngine.getInstance().isReadyForReadAndWrite()) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/AbstractTableSizeCacheWriter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/AbstractTableSizeCacheWriter.java
index 99d1439419d..a2495cbec62 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/AbstractTableSizeCacheWriter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/AbstractTableSizeCacheWriter.java
@@ -25,17 +25,14 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public abstract class AbstractTableSizeCacheWriter {
protected final int regionId;
- protected int activeReaderNum = 0;
protected long previousCompactionTimestamp = System.currentTimeMillis();
protected long lastWriteTimestamp = System.currentTimeMillis();
protected int currentIndexFileVersion = 0;
protected final File dir;
- protected CompletableFuture<Void> removedFuture;
public AbstractTableSizeCacheWriter(String database, int regionId) {
this.regionId = regionId;
@@ -68,27 +65,5 @@ public abstract class AbstractTableSizeCacheWriter {
public abstract void sync() throws IOException;
- public void increaseActiveReaderNum() {
- activeReaderNum++;
- }
-
- public void decreaseActiveReaderNum() {
- if (activeReaderNum > 0) {
- activeReaderNum--;
- }
- }
-
- public int getActiveReaderNum() {
- return activeReaderNum;
- }
-
- public void setRemovedFuture(CompletableFuture<Void> removedFuture) {
- this.removedFuture = removedFuture;
- }
-
- public CompletableFuture<Void> getRemovedFuture() {
- return removedFuture;
- }
-
public abstract void close();
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCache.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCache.java
index 9c6af6b3bc2..e586e35ca35 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCache.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCache.java
@@ -25,6 +25,7 @@ import
org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileID;
import
org.apache.iotdb.db.storageengine.dataregion.utils.tableDiskUsageCache.object.EmptyObjectTableSizeCacheReader;
import
org.apache.iotdb.db.storageengine.dataregion.utils.tableDiskUsageCache.object.IObjectTableSizeCacheReader;
+import org.apache.tsfile.utils.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,7 +42,7 @@ import java.util.concurrent.TimeUnit;
public class TableDiskUsageCache {
protected static final Logger LOGGER =
LoggerFactory.getLogger(TableDiskUsageCache.class);
protected final BlockingQueue<Operation> queue = new LinkedBlockingQueue<>();
- protected final Map<Integer, TsFileTableDiskUsageCacheWriter> writerMap =
new HashMap<>();
+ protected final Map<Integer, DataRegionTableSizeCacheWriter> writerMap = new
HashMap<>();
protected final ScheduledExecutorService scheduledExecutorService;
protected TableDiskUsageCache() {
@@ -69,24 +70,27 @@ public class TableDiskUsageCache {
}
}
} finally {
- writerMap.values().forEach(TsFileTableDiskUsageCacheWriter::close);
+ writerMap.values().forEach(DataRegionTableSizeCacheWriter::close);
}
}
protected void checkAndMayCompact(long maxRunTime) {
long startTime = System.currentTimeMillis();
- for (TsFileTableDiskUsageCacheWriter writer : writerMap.values()) {
+ for (DataRegionTableSizeCacheWriter writer : writerMap.values()) {
if (System.currentTimeMillis() - startTime > maxRunTime) {
break;
}
- if (writer.needCompact()) {
- writer.compact();
+ if (writer.getActiveReaderNum() > 0) {
+ continue;
+ }
+ if (writer.tsFileCacheWriter.needCompact()) {
+ writer.tsFileCacheWriter.compact();
}
}
}
protected void checkAndMayCloseIdleWriter() {
- for (TsFileTableDiskUsageCacheWriter writer : writerMap.values()) {
+ for (DataRegionTableSizeCacheWriter writer : writerMap.values()) {
writer.closeIfIdle();
}
}
@@ -107,9 +111,10 @@ public class TableDiskUsageCache {
throw new UnsupportedOperationException();
}
- public CompletableFuture<TsFileTableSizeCacheReader> startRead(
- String database, int regionId, boolean loadTsFileCache, boolean
loadObjectFileCache) {
- StartReadOperation operation = new StartReadOperation(database, regionId);
+ public CompletableFuture<Pair<TsFileTableSizeCacheReader,
IObjectTableSizeCacheReader>> startRead(
+ String database, int regionId, boolean readTsFileCache, boolean
readObjectFileCache) {
+ StartReadOperation operation =
+ new StartReadOperation(database, regionId, readTsFileCache,
readObjectFileCache);
queue.add(operation);
return operation.future;
}
@@ -119,13 +124,11 @@ public class TableDiskUsageCache {
queue.add(operation);
}
- public CompletableFuture<IObjectTableSizeCacheReader> startReadObject(
- String database, int regionId) {
- return CompletableFuture.completedFuture(new
EmptyObjectTableSizeCacheReader());
+ public void registerRegion(String database, int regionId) {
+ RegisterRegionOperation operation = new RegisterRegionOperation(database,
regionId);
+ queue.add(operation);
}
- public void endReadObject(String database, int regionId) {}
-
public void remove(String database, int regionId) {
RemoveRegionOperation operation = new RemoveRegionOperation(database,
regionId);
queue.add(operation);
@@ -141,7 +144,11 @@ public class TableDiskUsageCache {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdownNow();
}
- writerMap.values().forEach(TsFileTableDiskUsageCacheWriter::close);
+ writerMap.values().forEach(DataRegionTableSizeCacheWriter::close);
+ }
+
+ protected DataRegionTableSizeCacheWriter createWriter(String database, int
regionId) {
+ return new DataRegionTableSizeCacheWriter(database, regionId);
}
protected abstract static class Operation {
@@ -157,38 +164,68 @@ public class TableDiskUsageCache {
}
protected static class StartReadOperation extends Operation {
- public CompletableFuture<TsFileTableSizeCacheReader> future = new
CompletableFuture<>();
+ protected final boolean readTsFileCache;
+ protected final boolean readObjectFileCache;
+ public CompletableFuture<Pair<TsFileTableSizeCacheReader,
IObjectTableSizeCacheReader>> future =
+ new CompletableFuture<>();
- public StartReadOperation(String database, int regionId) {
+ public StartReadOperation(
+ String database, int regionId, boolean readTsFileCache, boolean
readObjectFileCache) {
super(database, regionId);
+ this.readTsFileCache = readTsFileCache;
+ this.readObjectFileCache = readObjectFileCache;
}
@Override
public void apply(TableDiskUsageCache tableDiskUsageCache) throws
IOException {
try {
- TsFileTableDiskUsageCacheWriter writer =
+ DataRegionTableSizeCacheWriter writer =
tableDiskUsageCache.writerMap.computeIfAbsent(
- regionId, k -> new TsFileTableDiskUsageCacheWriter(database,
regionId));
+ regionId, k -> tableDiskUsageCache.createWriter(database,
regionId));
if (writer.getRemovedFuture() != null) {
// region is removed
future.complete(
- new TsFileTableSizeCacheReader(
- 0, writer.getKeyFile(), 0, writer.getValueFile(), regionId));
+ new Pair<>(
+ new TsFileTableSizeCacheReader(
+ 0,
+ writer.tsFileCacheWriter.getKeyFile(),
+ 0,
+ writer.tsFileCacheWriter.getValueFile(),
+ regionId),
+ new EmptyObjectTableSizeCacheReader()));
return;
}
writer.flush();
writer.increaseActiveReaderNum();
- future.complete(
- new TsFileTableSizeCacheReader(
- writer.keyFileLength(),
- writer.getKeyFile(),
- writer.valueFileLength(),
- writer.getValueFile(),
- regionId));
+ TsFileTableSizeCacheReader tsFileTableSizeCacheReader =
+ readTsFileCache ? createTsFileCacheReader(writer) : null;
+ IObjectTableSizeCacheReader objectTableSizeCacheReader =
+ readObjectFileCache ? createObjectFileCacheReader(writer) : null;
+ future.complete(new Pair<>(tsFileTableSizeCacheReader,
objectTableSizeCacheReader));
} catch (Throwable t) {
future.completeExceptionally(t);
}
}
+
+ protected TsFileTableSizeCacheReader createTsFileCacheReader(
+ DataRegionTableSizeCacheWriter dataRegionWriter) {
+ TsFileTableDiskUsageCacheWriter tsFileCacheWriter =
dataRegionWriter.tsFileCacheWriter;
+ if (readTsFileCache) {
+ return new TsFileTableSizeCacheReader(
+ tsFileCacheWriter.keyFileLength(),
+ tsFileCacheWriter.getKeyFile(),
+ tsFileCacheWriter.valueFileLength(),
+ tsFileCacheWriter.getValueFile(),
+ regionId);
+ }
+ return new TsFileTableSizeCacheReader(
+ 0, tsFileCacheWriter.getKeyFile(), 0,
tsFileCacheWriter.getValueFile(), regionId);
+ }
+
+ protected IObjectTableSizeCacheReader createObjectFileCacheReader(
+ DataRegionTableSizeCacheWriter dataRegionWriter) {
+ return new EmptyObjectTableSizeCacheReader();
+ }
}
private static class EndReadOperation extends Operation {
@@ -198,16 +235,17 @@ public class TableDiskUsageCache {
@Override
public void apply(TableDiskUsageCache tableDiskUsageCache) throws
IOException {
- TsFileTableDiskUsageCacheWriter writer =
tableDiskUsageCache.writerMap.get(regionId);
- if (writer == null) {
- return;
- }
- writer.decreaseActiveReaderNum();
- if (writer.getRemovedFuture() != null) {
- tableDiskUsageCache.writerMap.remove(regionId);
- writer.setRemovedFuture(null);
- writer.getRemovedFuture().complete(null);
- }
+ tableDiskUsageCache.writerMap.computeIfPresent(
+ regionId,
+ (k, writer) -> {
+ writer.decreaseActiveReaderNum();
+ if (writer.getRemovedFuture() != null) {
+ writer.setRemovedFuture(null);
+ writer.getRemovedFuture().complete(null);
+ return null;
+ }
+ return writer;
+ });
}
}
@@ -226,7 +264,8 @@ public class TableDiskUsageCache {
public void apply(TableDiskUsageCache tableDiskUsageCache) throws
IOException {
tableDiskUsageCache
.writerMap
- .computeIfAbsent(regionId, k -> new
TsFileTableDiskUsageCacheWriter(database, regionId))
+ .computeIfAbsent(regionId, k -> new
DataRegionTableSizeCacheWriter(database, regionId))
+ .tsFileCacheWriter
.write(tsFileID, tableSizeMap);
}
}
@@ -243,13 +282,26 @@ public class TableDiskUsageCache {
@Override
public void apply(TableDiskUsageCache tableDiskUsageCache) throws
IOException {
- TsFileTableDiskUsageCacheWriter writer =
tableDiskUsageCache.writerMap.get(regionId);
+ DataRegionTableSizeCacheWriter writer =
tableDiskUsageCache.writerMap.get(regionId);
if (writer != null) {
- writer.write(originTsFileID, newTsFileID);
+ writer.tsFileCacheWriter.write(originTsFileID, newTsFileID);
}
}
}
+ private static class RegisterRegionOperation extends Operation {
+
+ private RegisterRegionOperation(String database, int regionId) {
+ super(database, regionId);
+ }
+
+ @Override
+ public void apply(TableDiskUsageCache tableDiskUsageCache) {
+ tableDiskUsageCache.writerMap.computeIfAbsent(
+ regionId, regionId -> tableDiskUsageCache.createWriter(database,
regionId));
+ }
+ }
+
private static class RemoveRegionOperation extends Operation {
private final CompletableFuture<Void> future = new CompletableFuture<>();
@@ -259,7 +311,7 @@ public class TableDiskUsageCache {
}
@Override
- public void apply(TableDiskUsageCache tableDiskUsageCache) throws
IOException {
+ public void apply(TableDiskUsageCache tableDiskUsageCache) {
tableDiskUsageCache.writerMap.computeIfPresent(
regionId,
(k, writer) -> {
@@ -291,4 +343,48 @@ public class TableDiskUsageCache {
return new DefaultTableDiskUsageCacheProvider().create();
}
}
+
+ protected static class DataRegionTableSizeCacheWriter {
+ protected final TsFileTableDiskUsageCacheWriter tsFileCacheWriter;
+ protected int activeReaderNum = 0;
+ protected CompletableFuture<Void> removedFuture;
+
+ protected DataRegionTableSizeCacheWriter(String database, int regionId) {
+ tsFileCacheWriter = new TsFileTableDiskUsageCacheWriter(database,
regionId);
+ }
+
+ public void increaseActiveReaderNum() {
+ activeReaderNum++;
+ }
+
+ public void decreaseActiveReaderNum() {
+ if (activeReaderNum > 0) {
+ activeReaderNum--;
+ }
+ }
+
+ public int getActiveReaderNum() {
+ return activeReaderNum;
+ }
+
+ public void closeIfIdle() {
+ tsFileCacheWriter.closeIfIdle();
+ }
+
+ public void flush() throws IOException {
+ tsFileCacheWriter.flush();
+ }
+
+ public void setRemovedFuture(CompletableFuture<Void> removedFuture) {
+ this.removedFuture = removedFuture;
+ }
+
+ public CompletableFuture<Void> getRemovedFuture() {
+ return removedFuture;
+ }
+
+ public void close() {
+ tsFileCacheWriter.close();
+ }
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCacheReader.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCacheReader.java
index b2a61c7bf0c..1bc054d0dcc 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCacheReader.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TableDiskUsageCacheReader.java
@@ -44,10 +44,12 @@ public class TableDiskUsageCacheReader implements Closeable
{
private final DataRegion dataRegion;
private final int regionId;
private final Map<Long, TimePartitionTableSizeQueryContext>
timePartitionQueryContexts;
- private CompletableFuture<TsFileTableSizeCacheReader>
tsFileTableSizeCacheReaderFuture;
+
+ private CompletableFuture<Pair<TsFileTableSizeCacheReader,
IObjectTableSizeCacheReader>>
+ prepareReaderFuture;
private TsFileTableSizeCacheReader tsFileTableSizeCacheReader;
- private CompletableFuture<IObjectTableSizeCacheReader>
objectTableSizeCacheReaderFuture;
private IObjectTableSizeCacheReader objectTableSizeCacheReader;
+
private long acquiredMemory;
private boolean tsFileIdKeysPrepared = false;
@@ -78,17 +80,21 @@ public class TableDiskUsageCacheReader implements Closeable
{
RamUsageEstimator.SHALLOW_SIZE_OF_HASHMAP_ENTRY));
}
- public boolean loadObjectFileTableSizeCache(long startTime, long maxRunTime)
throws Exception {
- if (this.objectTableSizeCacheReader == null) {
- this.objectTableSizeCacheReaderFuture =
- this.objectTableSizeCacheReaderFuture == null
+ public boolean prepareCacheReader(long startTime, long maxRunTime) throws
Exception {
+ if (this.tsFileTableSizeCacheReader == null) {
+ this.prepareReaderFuture =
+ this.prepareReaderFuture == null
? TableDiskUsageCache.getInstance()
- .startReadObject(dataRegion.getDatabaseName(), regionId)
- : objectTableSizeCacheReaderFuture;
+ .startRead(dataRegion.getDatabaseName(), regionId, true,
true)
+ : this.prepareReaderFuture;
do {
try {
- if (objectTableSizeCacheReaderFuture.isDone()) {
- this.objectTableSizeCacheReader =
objectTableSizeCacheReaderFuture.get();
+ if (prepareReaderFuture.isDone()) {
+ Pair<TsFileTableSizeCacheReader, IObjectTableSizeCacheReader>
readerPair =
+ prepareReaderFuture.get();
+ this.tsFileTableSizeCacheReader = readerPair.left;
+ this.tsFileTableSizeCacheReader.openKeyFile();
+ this.objectTableSizeCacheReader = readerPair.right;
break;
} else {
Thread.sleep(1);
@@ -99,9 +105,10 @@ public class TableDiskUsageCacheReader implements Closeable
{
}
} while (System.nanoTime() - startTime < maxRunTime);
}
- if (this.objectTableSizeCacheReader == null) {
- return false;
- }
+ return this.tsFileTableSizeCacheReader != null;
+ }
+
+ public boolean loadObjectFileTableSizeCache(long startTime, long maxRunTime)
{
if (objectTableSizeCacheReader.loadObjectFileTableSize(
timePartitionQueryContexts, startTime, maxRunTime)) {
objectTableSizeCacheReader.close();
@@ -114,29 +121,6 @@ public class TableDiskUsageCacheReader implements
Closeable {
if (tsFileIdKeysPrepared) {
return true;
}
- if (this.tsFileTableSizeCacheReader == null) {
- this.tsFileTableSizeCacheReaderFuture =
- this.tsFileTableSizeCacheReaderFuture == null
- ?
TableDiskUsageCache.getInstance().startRead(dataRegion.getDatabaseName(),
regionId)
- : tsFileTableSizeCacheReaderFuture;
- do {
- try {
- if (tsFileTableSizeCacheReaderFuture.isDone()) {
- this.tsFileTableSizeCacheReader =
tsFileTableSizeCacheReaderFuture.get();
- this.tsFileTableSizeCacheReader.openKeyFile();
- break;
- } else {
- Thread.sleep(1);
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return false;
- }
- } while (System.nanoTime() - startTime < maxRunTime);
- }
- if (this.tsFileTableSizeCacheReader == null) {
- return false;
- }
if (tsFileTableSizeCacheReader.readFromKeyFile(
timePartitionQueryContexts, startTime, maxRunTime)) {
reserveMemory(
@@ -208,13 +192,9 @@ public class TableDiskUsageCacheReader implements
Closeable {
objectTableSizeCacheReader.close();
objectTableSizeCacheReader = null;
}
- if (objectTableSizeCacheReaderFuture != null) {
-
TableDiskUsageCache.getInstance().endReadObject(dataRegion.getDatabaseName(),
regionId);
- objectTableSizeCacheReaderFuture = null;
- }
- if (tsFileTableSizeCacheReaderFuture != null) {
+ if (prepareReaderFuture != null) {
TableDiskUsageCache.getInstance().endRead(dataRegion.getDatabaseName(),
regionId);
- tsFileTableSizeCacheReaderFuture = null;
+ prepareReaderFuture = null;
}
releaseMemory();
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TsFileTableDiskUsageCacheWriter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TsFileTableDiskUsageCacheWriter.java
index 1dc81056b21..a8124726486 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TsFileTableDiskUsageCacheWriter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageCache/TsFileTableDiskUsageCacheWriter.java
@@ -138,9 +138,6 @@ public class TsFileTableDiskUsageCacheWriter extends
AbstractTableSizeCacheWrite
@Override
public boolean needCompact() {
- if (activeReaderNum > 0) {
- return false;
- }
if (System.currentTimeMillis() - previousCompactionTimestamp <=
TimeUnit.MINUTES.toMillis(2)) {
return false;
}