yuqi1129 commented on code in PR #13152:
URL: https://github.com/apache/gravitino/pull/13152#discussion_r4060621836


##########
core/src/test/java/org/apache/gravitino/cache/TestCaffeineEntityCacheInvalidation.java:
##########
@@ -346,6 +348,50 @@ void 
testInvalidateLeafDoesNotEvictSameNameEntityOfAnotherType() {
     Assertions.assertTrue(cache.contains(topic.nameIdentifier(), 
Entity.EntityType.TOPIC));
   }
 
+  @Test
+  void testExpiredRemovalCallbackAfterReinsertKeepsIndexEntry() throws 
Exception {
+    // Deterministic regression for the removal-listener race: the 
asynchronous callback of an
+    // expired/evicted entry must not delete the index entry of a reinserted 
entry with the same
+    // key, otherwise later parent-level invalidation can no longer discover 
the child.
+    Config config = new Config(false) {};
+    // 50 ms TTL so the first entry expires quickly while the test stays 
deterministic.
+    config.set(Configs.CACHE_EXPIRATION_TIME, 50L);
+    cache = new CaffeineEntityCache(config);
+
+    CatalogEntity catalog =
+        TestUtil.getTestCatalogEntity(1L, "catalog1", 
Namespace.of("metalake"), "hive", "cmt");
+    SchemaEntity schema =
+        TestUtil.getTestSchemaEntity(2L, "schema1", Namespace.of("metalake", 
"catalog1"), "cmt");
+    TableEntity table =
+        TestUtil.getTestTableEntity(3L, "table1", Namespace.of("metalake", 
"catalog1", "schema1"));
+    cache.put(catalog);
+    cache.put(schema);
+    cache.put(table);
+
+    // Wait past the TTL so the table entry expires. Caffeine's removal 
listener runs
+    // asynchronously on the cache's executor (CLEANUP_EXECUTOR), reinsert the 
entity first and
+    // give the delayed callback a chance to run. Use Awaitility for a 
deterministic wait.
+    Awaitility.await()
+        .atMost(Duration.ofSeconds(5))
+        .untilAsserted(
+            () ->
+                Assertions.assertNull(
+                    cache.getCacheData().getIfPresent(
+                        EntityCacheKey.of(table.nameIdentifier(), 
Entity.EntityType.TABLE))));
+
+    // Reinsert the table: cacheData now holds a fresh entry and cacheIndex 
holds its key again.
+    cache.put(table);

Review Comment:
   The `Awaitility` check only proves the old entry expired; the cleanup 
callback may already have run before this `put`, so the pre-fix implementation 
can pass this test. Since this test is in the same package, a simple 
deterministic regression is to reinsert the table and then call 
`cache.invalidateExpiredItem(tableKey)` to model the delayed old callback, 
before invalidating the catalog. That exact ordering makes the old 
unconditional `cacheIndex.remove` fail while the new implementation passes. 
Alternatively, inject a controllable cleanup executor and release its callback 
after this `put`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to