From 20e10999dd82eb5b1d2a12daeac4bdd38f4799b8 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Mon, 28 Sep 2026 13:43:38 -0400 Subject: [PATCH] Lazy semantic region summaries - claims cache the next region shard without rebuilding its key summary - summaries are computed when a query or compaction reads them --- .../history/GenerationSemanticIndex.java | 6 +++++- .../history/GenerationSemanticIndexTest.java | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticIndex.java b/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticIndex.java index b99888127..016ba9054 100644 --- a/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticIndex.java +++ b/core/src/main/java/art/arcane/iris/world/history/GenerationSemanticIndex.java @@ -1075,7 +1075,11 @@ public final class GenerationSemanticIndex { private void cacheRegion(long regionKey, RegionShard region) { regions.put(regionKey, region); - cacheSummary(regionKey, region.summary()); + if (region.summary == null) { + summaries.remove(regionKey); + } else { + cacheSummary(regionKey, region.summary); + } while (regions.size() > MAXIMUM_CACHED_REGIONS) { Iterator> entries = regions.entrySet().iterator(); entries.next(); diff --git a/core/src/test/java/art/arcane/iris/world/history/GenerationSemanticIndexTest.java b/core/src/test/java/art/arcane/iris/world/history/GenerationSemanticIndexTest.java index 08770aa91..27f92bd5e 100644 --- a/core/src/test/java/art/arcane/iris/world/history/GenerationSemanticIndexTest.java +++ b/core/src/test/java/art/arcane/iris/world/history/GenerationSemanticIndexTest.java @@ -206,6 +206,27 @@ public final class GenerationSemanticIndexTest { new ChunkGenerationSemantics.BlockPosition(-520, 80, -8), 4)).isEmpty()); } + @Test + public void claimsDeferRegionSummariesUntilAQueryReadsThem() throws Exception { + Path root = temporaryFolder.newFolder("lazy-summaries").toPath(); + GenerationSemanticIndex index = GenerationSemanticIndex.initialize(root); + + index.claimAndPersist(ChunkGenerationSemantics.builder(-33, -1, 1L).addObject("iris:first").seal().build()); + assertEquals(0, index.cachedSummaryCount()); + assertEquals("iris:first", requiredMatch(index, GenerationSemanticIndex.SemanticKind.OBJECT, "iris:first").key()); + assertEquals(1, index.cachedSummaryCount()); + + index.claimAndPersist(ChunkGenerationSemantics.builder(-34, -1, 1L).addObject("iris:second").seal().build()); + assertEquals(0, index.cachedSummaryCount()); + assertEquals("iris:second", requiredMatch(index, GenerationSemanticIndex.SemanticKind.OBJECT, "iris:second").key()); + assertEquals("iris:first", requiredMatch(index, GenerationSemanticIndex.SemanticKind.OBJECT, "iris:first").key()); + assertEquals(2, sealedClaims(index, 1L).size()); + + GenerationSemanticIndex reopened = GenerationSemanticIndex.load(root); + assertEquals("iris:second", requiredMatch(reopened, GenerationSemanticIndex.SemanticKind.OBJECT, "iris:second").key()); + assertEquals(index.recordsSnapshot(), reopened.recordsSnapshot()); + } + @Test public void conflictingActivationsAndFactsAfterSealAreRejectedWithoutDiskChanges() throws Exception { Path dimensionRoot = temporaryFolder.newFolder("sealed").toPath();