This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new e1066549218 fix delete dead lock.
e1066549218 is described below

commit e106654921879d88c264500021bc9ac165a2726f
Author: Colin Li <[email protected]>
AuthorDate: Tue Apr 9 18:25:26 2024 +0800

    fix delete dead lock.
---
 .../analyze/cache/schema/DataNodeSchemaCache.java  |  25 +++++
 .../analyze/cache/schema/SchemaCacheEntry.java     |   8 ++
 .../cache/schema/TimeSeriesSchemaCache.java        |  32 ++++++
 .../cache/schema/dualkeycache/IDualKeyCache.java   |   9 ++
 .../schema/dualkeycache/impl/DualKeyCacheImpl.java |  59 +++++++++++
 .../schema/lastcache/DataNodeLastCacheManager.java |   7 ++
 .../schema/lastcache/ILastCacheContainer.java      |   5 +-
 .../cache/schema/lastcache/LastCacheContainer.java |   7 ++
 .../db/storageengine/dataregion/DataRegion.java    |  44 +-------
 .../cache/dualkeycache/DualKeyCacheTest.java       | 114 +++++++++++++++++++++
 10 files changed, 269 insertions(+), 41 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeSchemaCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeSchemaCache.java
index 5559f7b5483..cc5dd91fea2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeSchemaCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeSchemaCache.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.queryengine.plan.analyze.cache.schema;
 
+import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.service.metric.MetricService;
@@ -218,6 +219,30 @@ public class DataNodeSchemaCache {
     return timeSeriesSchemaCache.getLastCache(seriesPath);
   }
 
+  public void invalidateLastCache(PartialPath path) {
+    if (!CommonDescriptor.getInstance().getConfig().isLastCacheEnable()) {
+      return;
+    }
+    takeReadLock();
+    try {
+      timeSeriesSchemaCache.invalidateLastCache(path);
+    } finally {
+      releaseReadLock();
+    }
+  }
+
+  public void invalidateLastCacheInDataRegion(String database) {
+    if (!CommonDescriptor.getInstance().getConfig().isLastCacheEnable()) {
+      return;
+    }
+    takeReadLock();
+    try {
+      timeSeriesSchemaCache.invalidateDataRegionLastCache(database);
+    } finally {
+      releaseReadLock();
+    }
+  }
+
   /** get SchemaCacheEntry and update last cache */
   @TestOnly
   public void updateLastCache(
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java
index 55a8bb21a27..181f0eeccba 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java
@@ -163,4 +163,12 @@ public class SchemaCacheEntry implements 
IMeasurementSchemaInfo {
   public boolean isLogicalView() {
     return this.iMeasurementSchema.isLogicalView();
   }
+
+  public int invalidateLastCache() {
+    if (this.lastCacheContainer == null || 
this.lastCacheContainer.getCachedLast() == null) {
+      return 0;
+    }
+
+    return this.lastCacheContainer.invalidateLastCache();
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java
index 5613a7c8cdc..0f3df8aa745 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java
@@ -393,6 +393,38 @@ public class TimeSeriesSchemaCache {
     dualKeyCache.invalidate(database);
   }
 
+  public void invalidateLastCache(PartialPath path) {
+    if (!path.hasWildcard()) {
+      SchemaCacheEntry entry = dualKeyCache.get(path.getDevicePath(), 
path.getMeasurement());
+      if (null == entry) {
+        return;
+      }
+      dualKeyCache.update(
+          new IDualKeyCacheUpdating<PartialPath, String, SchemaCacheEntry>() {
+            @Override
+            public PartialPath getFirstKey() {
+              return path.getDevicePath();
+            }
+
+            @Override
+            public String[] getSecondKeyList() {
+              return new String[] {path.getMeasurement()};
+            }
+
+            @Override
+            public int updateValue(int index, SchemaCacheEntry value) {
+              return DataNodeLastCacheManager.invalidateLastCache(value);
+            }
+          });
+    } else {
+      dualKeyCache.invalidateLastCache(path);
+    }
+  }
+
+  public void invalidateDataRegionLastCache(String database) {
+    dualKeyCache.invalidateDataRegionLastCache(database);
+  }
+
   public void invalidate(List<PartialPath> partialPathList) {
     dualKeyCache.invalidate(partialPathList);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/IDualKeyCache.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/IDualKeyCache.java
index 0fcf11b37fa..95f0b0e8f00 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/IDualKeyCache.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/IDualKeyCache.java
@@ -54,6 +54,15 @@ public interface IDualKeyCache<FK, SK, V> {
   /** put the cache value into cache */
   void put(FK firstKey, SK secondKey, V value);
 
+  /**
+   * Invalidate last cache in datanode schema cache. Do not invalidate time 
series cache.
+   *
+   * @param partialPathList
+   */
+  void invalidateLastCache(PartialPath partialPath);
+
+  void invalidateDataRegionLastCache(String database);
+
   /**
    * Invalidate all cache values in the cache and clear related cache keys. 
The cache status and
    * statistics won't be clear and they can still be accessed via 
cache.stats().
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/impl/DualKeyCacheImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/impl/DualKeyCacheImpl.java
index 96bc7fd7408..d3a385467f8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/impl/DualKeyCacheImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/dualkeycache/impl/DualKeyCacheImpl.java
@@ -22,10 +22,12 @@ package 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.dualkeycache.i
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternUtil;
 import org.apache.iotdb.commons.utils.TestOnly;
+import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.SchemaCacheEntry;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.dualkeycache.IDualKeyCache;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.dualkeycache.IDualKeyCacheComputation;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.dualkeycache.IDualKeyCacheStats;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.dualkeycache.IDualKeyCacheUpdating;
+import 
org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.lastcache.DataNodeLastCacheManager;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -240,6 +242,63 @@ class DualKeyCacheImpl<FK, SK, V, T extends 
ICacheEntry<SK, V>>
     }
   }
 
+  @Override
+  public void invalidateLastCache(PartialPath path) {
+    String measurement = path.getMeasurement();
+    PartialPath devicePath = path.getDevicePath();
+    Function<FK, Boolean> deviceFilter = null;
+    Function<SK, Boolean> measurementFilter = null;
+
+    if (PathPatternUtil.hasWildcard(devicePath.getFullPath())) {
+      deviceFilter = d -> devicePath.matchFullPath((PartialPath) d);
+    }
+    if (PathPatternUtil.isMultiLevelMatchWildcard(measurement)) {
+      measurementFilter = m -> true;
+    }
+    if (deviceFilter == null) {
+      deviceFilter = d -> ((PartialPath) d).equals(devicePath);
+    }
+
+    if (measurementFilter == null) {
+      measurementFilter = m -> PathPatternUtil.isNodeMatch(measurement, 
m.toString());
+    }
+
+    for (FK device : firstKeyMap.getAllKeys()) {
+      if (Boolean.TRUE.equals(deviceFilter.apply(device))) {
+        ICacheEntryGroup<FK, SK, V, T> entryGroup = firstKeyMap.get(device);
+        for (Iterator<Map.Entry<SK, T>> it = entryGroup.getAllCacheEntries(); 
it.hasNext(); ) {
+          Map.Entry<SK, T> entry = it.next();
+          if (Boolean.TRUE.equals(measurementFilter.apply(entry.getKey()))) {
+            T cacheEntry = entry.getValue();
+            synchronized (cacheEntry) {
+              SchemaCacheEntry schemaCacheEntry = (SchemaCacheEntry) 
cacheEntry.getValue();
+              cacheStats.decreaseMemoryUsage(
+                  
DataNodeLastCacheManager.invalidateLastCache(schemaCacheEntry));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  @Override
+  public void invalidateDataRegionLastCache(String database) {
+    for (FK device : firstKeyMap.getAllKeys()) {
+      if (device.toString().startsWith(database)) {
+        ICacheEntryGroup<FK, SK, V, T> entryGroup = firstKeyMap.get(device);
+        for (Iterator<Map.Entry<SK, T>> it = entryGroup.getAllCacheEntries(); 
it.hasNext(); ) {
+          Map.Entry<SK, T> entry = it.next();
+          T cacheEntry = entry.getValue();
+          synchronized (cacheEntry) {
+            SchemaCacheEntry schemaCacheEntry = (SchemaCacheEntry) 
cacheEntry.getValue();
+            cacheStats.decreaseMemoryUsage(
+                
DataNodeLastCacheManager.invalidateLastCache(schemaCacheEntry));
+          }
+        }
+      }
+    }
+  }
+
   @Override
   public void invalidateAll() {
     executeInvalidateAll();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/DataNodeLastCacheManager.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/DataNodeLastCacheManager.java
index 6790f2cb645..88fee643e9c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/DataNodeLastCacheManager.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/DataNodeLastCacheManager.java
@@ -65,4 +65,11 @@ public class DataNodeLastCacheManager {
     }
     return entry.updateLastCache(timeValuePair, highPriorityUpdate, 
latestFlushedTime);
   }
+
+  public static int invalidateLastCache(SchemaCacheEntry entry) {
+    if (!CACHE_ENABLED || null == entry) {
+      return 0;
+    }
+    return entry.invalidateLastCache();
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/ILastCacheContainer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/ILastCacheContainer.java
index 3ada99d8ebf..de5ffdc2fd1 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/ILastCacheContainer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/ILastCacheContainer.java
@@ -28,7 +28,7 @@ public interface ILastCacheContainer {
   TimeValuePair getCachedLast();
 
   /**
-   * update last point cache
+   * update last point cache and enable last cache.
    *
    * @param timeValuePair last point
    * @param highPriorityUpdate whether it's a high priority update
@@ -38,5 +38,8 @@ public interface ILastCacheContainer {
   int updateCachedLast(
       TimeValuePair timeValuePair, boolean highPriorityUpdate, Long 
latestFlushedTime);
 
+  /** Invalidate Last cache. */
+  int invalidateLastCache();
+
   int estimateSize();
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/LastCacheContainer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/LastCacheContainer.java
index 0f9d34cc06b..e02809652cd 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/LastCacheContainer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/lastcache/LastCacheContainer.java
@@ -70,6 +70,13 @@ public class LastCacheContainer implements 
ILastCacheContainer {
     return 0;
   }
 
+  @Override
+  public int invalidateLastCache() {
+    int size = lastCacheValue.estimateSize();
+    lastCacheValue = null;
+    return size;
+  }
+
   private int getDiffSize(TsPrimitiveType oldValue, TsPrimitiveType newValue) {
     if (oldValue == null) {
       return newValue == null ? 0 : newValue.getSize();
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 8500b735ebc..9555eb0b7f2 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
@@ -23,7 +23,6 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.cluster.NodeStatus;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
 import org.apache.iotdb.commons.consensus.DataRegionId;
-import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.MetadataException;
 import org.apache.iotdb.commons.file.SystemFileFactory;
 import org.apache.iotdb.commons.path.PartialPath;
@@ -1945,17 +1944,8 @@ public class DataRegion implements IDataRegionForQuery {
     boolean hasReleasedLock = false;
 
     try {
-
+      DataNodeSchemaCache.getInstance().invalidateLastCache(pattern);
       Set<PartialPath> devicePaths = new 
HashSet<>(pattern.getDevicePathPattern());
-
-      // delete Last cache record if necessary
-      DataNodeSchemaCache.getInstance().takeWriteLock();
-      try {
-        
DataNodeSchemaCache.getInstance().invalidate(Collections.singletonList(pattern));
-      } finally {
-        DataNodeSchemaCache.getInstance().releaseWriteLock();
-      }
-
       // write log to impacted working TsFileProcessors
       List<WALFlushListener> walListeners =
           logDeletionInWAL(startTime, endTime, searchIndex, pattern);
@@ -1980,7 +1970,6 @@ public class DataRegion implements IDataRegionForQuery {
       hasReleasedLock = true;
 
       deleteDataInFiles(sealedTsFileResource, deletion, devicePaths, 
deviceMatchInfo);
-
     } catch (Exception e) {
       throw new IOException(e);
     } finally {
@@ -2000,15 +1989,9 @@ public class DataRegion implements IDataRegionForQuery {
 
     writeLock("deleteDataDirect");
     boolean releasedLock = false;
-    try {
-      // delete last cache record if necessary
-      DataNodeSchemaCache.getInstance().takeWriteLock();
-      try {
-        DataNodeSchemaCache.getInstance().invalidate(databaseName);
-      } finally {
-        DataNodeSchemaCache.getInstance().releaseWriteLock();
-      }
 
+    try {
+      
DataNodeSchemaCache.getInstance().invalidateLastCacheInDataRegion(getDatabaseName());
       // write log to impacted working TsFileProcessors
       List<WALFlushListener> walListeners =
           logDeletionInWAL(startTime, endTime, searchIndex, pathToDelete);
@@ -2539,18 +2522,6 @@ public class DataRegion implements IDataRegionForQuery {
     }
   }
 
-  private void resetLastCacheWhenLoadingTsFile() throws IllegalPathException {
-    if (!CommonDescriptor.getInstance().getConfig().isLastCacheEnable()) {
-      return;
-    }
-    DataNodeSchemaCache.getInstance().takeWriteLock();
-    try {
-      DataNodeSchemaCache.getInstance().invalidateAll();
-    } finally {
-      DataNodeSchemaCache.getInstance().releaseWriteLock();
-    }
-  }
-
   /**
    * Load a new tsfile to unsequence dir.
    *
@@ -2603,10 +2574,6 @@ public class DataRegion implements IDataRegionForQuery {
               false,
               newTsFileResource.getTsFile().getName());
 
-      // Update last cache
-      resetLastCacheWhenLoadingTsFile();
-
-      // Update last flush time & help last flush time map degrade
       if (config.isEnableSeparateData()) {
         final DataRegionId dataRegionId = new 
DataRegionId(Integer.parseInt(this.dataRegionId));
         final long timePartitionId = newTsFileResource.getTimePartition();
@@ -2637,12 +2604,9 @@ public class DataRegion implements IDataRegionForQuery {
           tsfileToBeInserted.getAbsolutePath(),
           tsfileToBeInserted.getParentFile().getName());
       throw new LoadFileException(e);
-    } catch (IllegalPathException e) {
-      logger.error(
-          "Failed to reset last cache when loading file {}", 
newTsFileResource.getTsFilePath());
-      throw new LoadFileException(e);
     } finally {
       writeUnlock();
+      
DataNodeSchemaCache.getInstance().invalidateLastCacheInDataRegion(databaseName);
     }
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/dualkeycache/DualKeyCacheTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/dualkeycache/DualKeyCacheTest.java
index 65a88591d7b..4f2a8840278 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/dualkeycache/DualKeyCacheTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/dualkeycache/DualKeyCacheTest.java
@@ -374,4 +374,118 @@ public class DualKeyCacheTest {
     Assert.assertEquals(expectSize, dualKeyCache.stats().memoryUsage());
     return dualKeyCache;
   }
+
+  private IDualKeyCache<PartialPath, String, SchemaCacheEntry> 
generateLastCache()
+      throws IllegalPathException {
+    DualKeyCacheBuilder<PartialPath, String, SchemaCacheEntry> 
dualKeyCacheBuilder =
+        new DualKeyCacheBuilder<>();
+    IDualKeyCache<PartialPath, String, SchemaCacheEntry> dualKeyCache =
+        dualKeyCacheBuilder
+            .cacheEvictionPolicy(DualKeyCachePolicy.valueOf(policy))
+            .memoryCapacity(2000) // actual threshold is 1600
+            .firstKeySizeComputer(PartialPath::estimateSize)
+            .secondKeySizeComputer(this::computeStringSize)
+            .valueSizeComputer(SchemaCacheEntry::estimateSize)
+            .build();
+    SchemaCacheEntry cacheEntry1 =
+        new SchemaCacheEntry(
+            "root.db1",
+            new MeasurementSchema("s1", TSDataType.INT32),
+            Collections.emptyMap(),
+            false);
+    cacheEntry1.updateLastCache(new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1)), true, 0L);
+    dualKeyCache.put(new PartialPath("root.db1.d1"), "s1", cacheEntry1);
+
+    SchemaCacheEntry cacheEntry2 =
+        new SchemaCacheEntry(
+            "root.db1",
+            new MeasurementSchema("s2", TSDataType.INT32),
+            Collections.emptyMap(),
+            false);
+    cacheEntry2.updateLastCache(new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1)), true, 0L);
+    dualKeyCache.put(new PartialPath("root.db1.d1"), "s2", cacheEntry2);
+
+    SchemaCacheEntry cacheEntry3 =
+        new SchemaCacheEntry(
+            "root.db2",
+            new MeasurementSchema("s2", TSDataType.INT32),
+            Collections.emptyMap(),
+            false);
+    cacheEntry3.updateLastCache(new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1)), true, 0L);
+    dualKeyCache.put(new PartialPath("root.db2.d1"), "s2", cacheEntry3);
+
+    SchemaCacheEntry cacheEntry4 =
+        new SchemaCacheEntry(
+            "root.db2",
+            new MeasurementSchema("s2", TSDataType.INT32),
+            Collections.emptyMap(),
+            false);
+    cacheEntry4.updateLastCache(new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1)), true, 0L);
+    dualKeyCache.put(new PartialPath("root.db2.d1"), "s1", cacheEntry4);
+
+    SchemaCacheEntry cacheEntry5 =
+        new SchemaCacheEntry(
+            "root.db1",
+            new MeasurementSchema("s2", TSDataType.INT32),
+            Collections.emptyMap(),
+            false);
+    cacheEntry5.updateLastCache(new TimeValuePair(1L, new 
TsPrimitiveType.TsInt(1)), true, 0L);
+    dualKeyCache.put(new PartialPath("root.db1"), "s2", cacheEntry5);
+
+    Assert.assertNotNull(dualKeyCache.get(new PartialPath("root.db1.d1"), 
"s1"));
+    Assert.assertNotNull(dualKeyCache.get(new PartialPath("root.db1.d1"), 
"s2"));
+    Assert.assertNotNull(dualKeyCache.get(new PartialPath("root.db1"), "s2"));
+    Assert.assertNotNull(dualKeyCache.get(new PartialPath("root.db2.d1"), 
"s1"));
+    Assert.assertNotNull(dualKeyCache.get(new PartialPath("root.db2.d1"), 
"s2"));
+
+    int expectSize =
+        PartialPath.estimateSize(new PartialPath("root.db1.d1")) * 2
+            + PartialPath.estimateSize(new PartialPath("root.db1"))
+            + computeStringSize("s1") * 5
+            + SchemaCacheEntry.estimateSize(cacheEntry1) * 5;
+    Assert.assertEquals(expectSize, dualKeyCache.stats().memoryUsage());
+    return dualKeyCache;
+  }
+
+  @Test
+  public void testInvalidateSimpleTimeseriesAndDataRegion() throws 
IllegalPathException {
+    IDualKeyCache<PartialPath, String, SchemaCacheEntry> dualKeyCache = 
generateLastCache();
+    long memUse = dualKeyCache.stats().memoryUsage();
+
+    dualKeyCache.invalidateLastCache(new PartialPath("root.db1.d1.s1"));
+    SchemaCacheEntry cacheEntry = dualKeyCache.get(new 
PartialPath("root.db1.d1"), "s1");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+
+    dualKeyCache.invalidateLastCache(new PartialPath("root.db1.d1.*"));
+    cacheEntry = dualKeyCache.get(new PartialPath("root.db1.d1"), "s2");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+
+    dualKeyCache.invalidateLastCache(new PartialPath("root.db2.d1.**"));
+    cacheEntry = dualKeyCache.get(new PartialPath("root.db2.d1"), "s2");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+
+    dualKeyCache.invalidateDataRegionLastCache("root.db2");
+    cacheEntry = dualKeyCache.get(new PartialPath("root.db2.d1"), "s1");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+
+    cacheEntry = dualKeyCache.get(new PartialPath("root.db1"), "s2");
+    // last cache container' estimateSize(): header 8b + Ilastcachevalueref 8b 
+  lastcache's size
+    // invalidate operation: make Ilastcachevalueref = null.
+    // So the amount of change in size is estimateSize() - 8b - 8b
+    int size = cacheEntry.getLastCacheContainer().estimateSize() - 16;
+    Assert.assertEquals(memUse - size * 4, dualKeyCache.stats().memoryUsage());
+  }
+
+  @Test
+  public void testComplexInvalidate() throws IllegalPathException {
+    IDualKeyCache<PartialPath, String, SchemaCacheEntry> dualKeyCache = 
generateLastCache();
+
+    dualKeyCache.invalidateLastCache(new PartialPath("root.db1.*.s1"));
+    SchemaCacheEntry cacheEntry = dualKeyCache.get(new 
PartialPath("root.db1.d1"), "s1");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+
+    dualKeyCache.invalidateLastCache(new PartialPath("root.db1.**.s2"));
+    cacheEntry = dualKeyCache.get(new PartialPath("root.db1.d1"), "s2");
+    Assert.assertNull(cacheEntry.getLastCacheContainer().getCachedLast());
+  }
 }

Reply via email to