This is an automated email from the ASF dual-hosted git repository. tkalkirill pushed a commit to branch ignite-26216-second in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 69bd42c77799c4349036b86b61db6b10202b89d4 Author: Kirill Tkalenko <[email protected]> AuthorDate: Mon Aug 18 15:42:55 2025 +0300 IGNITE-26216 wip --- .../pagememory/persistence/PageHeader.java | 55 +++++++++++++---- .../persistence/PersistentPageMemory.java | 4 ++ .../checkpoint/CheckpointProgressImpl.java | 4 +- .../pagememory/PersistentPageMemoryNoLoadTest.java | 70 ++++++++++++++++++++++ 4 files changed, 118 insertions(+), 15 deletions(-) diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java index 52f6db69602..bddd4a2dcc4 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java @@ -33,12 +33,13 @@ import org.apache.ignite.internal.pagememory.FullPageId; /** * Page header. */ +// TODO: IGNITE-16350 Improve documentation and refactoring public class PageHeader { /** Page marker. */ public static final long PAGE_MARKER = 0x0000000000000001L; /** Dirty flag. */ - private static final long DIRTY_FLAG = 0x0100000000000000L; + private static final int DIRTY_FLAG = 0x01000000; /** Page relative pointer. Does not change once a page is allocated. */ private static final int RELATIVE_PTR_OFFSET = 8; @@ -55,6 +56,13 @@ public class PageHeader { /** Page temp copy buffer relative pointer offset. */ private static final int PAGE_TMP_BUF_OFFSET = 40; + private static final int PARTITION_GENERATION_OFFSET = 8; + + private static final int FLAGS_OFFSET = 12; + + /** Unknown partition generation. */ + static final int UNKNOWN_PARTITION_GENERATION = -1; + /** * Initializes the header of the page. * @@ -62,7 +70,7 @@ public class PageHeader { * @param relative Relative pointer to write. */ public static void initNew(long absPtr, long relative) { - relative(absPtr, relative); + writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION); tempBufferPointer(absPtr, INVALID_REL_PTR); @@ -96,13 +104,13 @@ public class PageHeader { * @param absPtr Absolute pointer. * @param flag Flag mask. */ - private static boolean flag(long absPtr, long flag) { - assert (flag & 0xFFFFFFFFFFFFFFL) == 0; + private static boolean flag(long absPtr, int flag) { + assert (flag & 0xFFFFFF) == 0; assert Long.bitCount(flag) == 1; - long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET); + int flags = getInt(absPtr + FLAGS_OFFSET); - return (relPtrWithFlags & flag) != 0; + return (flags & flag) != 0; } /** @@ -113,21 +121,21 @@ public class PageHeader { * @param set New flag value. * @return Previous flag value. */ - private static boolean flag(long absPtr, long flag, boolean set) { - assert (flag & 0xFFFFFFFFFFFFFFL) == 0; + private static boolean flag(long absPtr, int flag, boolean set) { + assert (flag & 0xFFFFFF) == 0; assert Long.bitCount(flag) == 1; - long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET); + int flags = getInt(absPtr + FLAGS_OFFSET); - boolean was = (relPtrWithFlags & flag) != 0; + boolean was = (flags & flag) != 0; if (set) { - relPtrWithFlags |= flag; + flags |= flag; } else { - relPtrWithFlags &= ~flag; + flags &= ~flag; } - putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags); + putInt(absPtr + FLAGS_OFFSET, flags); return was; } @@ -296,4 +304,25 @@ public class PageHeader { pageGroupId(absPtr, fullPageId.groupId()); } + + /** + * Reads partition generation from page header, {@link #UNKNOWN_PARTITION_GENERATION} if the partition generation was not set. + * + * @param absPtr Absolute memory pointer to the page header. + */ + public static int readPartitionGeneration(long absPtr) { + return getInt(absPtr + PARTITION_GENERATION_OFFSET); + } + + /** + * Writes partition generation to page header. + * + * @param absPtr Absolute memory pointer to page header. + * @param partitionGeneration Partition generation, strictly positive or {@link #UNKNOWN_PARTITION_GENERATION} if reset is required. + */ + static void writePartitionGeneration(long absPtr, int partitionGeneration) { + assert partitionGeneration > 0 || partitionGeneration == UNKNOWN_PARTITION_GENERATION : partitionGeneration; + + putInt(absPtr + PARTITION_GENERATION_OFFSET, partitionGeneration); + } } diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java index 653565cc7e0..5990f1b9166 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java @@ -32,6 +32,7 @@ import static org.apache.ignite.internal.pagememory.persistence.PageHeader.fullP import static org.apache.ignite.internal.pagememory.persistence.PageHeader.isAcquired; import static org.apache.ignite.internal.pagememory.persistence.PageHeader.readPageId; import static org.apache.ignite.internal.pagememory.persistence.PageHeader.tempBufferPointer; +import static org.apache.ignite.internal.pagememory.persistence.PageHeader.writePartitionGeneration; import static org.apache.ignite.internal.pagememory.persistence.PageHeader.writeTimestamp; import static org.apache.ignite.internal.pagememory.persistence.PagePool.SEGMENT_INDEX_MASK; import static org.apache.ignite.internal.pagememory.persistence.throttling.PagesWriteThrottlePolicy.CP_BUF_FILL_THRESHOLD; @@ -585,6 +586,7 @@ public class PersistentPageMemory implements PageMemory { fullPageId(absPtr, fullId); writeTimestamp(absPtr, coarseCurrentTimeMillis()); + writePartitionGeneration(absPtr, seg.partGeneration(grpId, partId)); rwLock.init(absPtr + PAGE_LOCK_OFFSET, tag(pageId)); @@ -741,6 +743,7 @@ public class PersistentPageMemory implements PageMemory { fullPageId(absPtr, fullId); writeTimestamp(absPtr, coarseCurrentTimeMillis()); + writePartitionGeneration(absPtr, seg.partGeneration(grpId, partId)); assert !isAcquired(absPtr) : "Pin counter must be 0 for a new page [relPtr=" + hexLong(relPtr) + ", absPtr=" + hexLong(absPtr) + ']'; @@ -792,6 +795,7 @@ public class PersistentPageMemory implements PageMemory { fullPageId(absPtr, fullId); writeTimestamp(absPtr, coarseCurrentTimeMillis()); + writePartitionGeneration(absPtr, seg.partGeneration(grpId, partId)); setPageId(pageAddr, pageId); assert !isAcquired(absPtr) : diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointProgressImpl.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointProgressImpl.java index 9d1ece6e634..a4e5ec20341 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointProgressImpl.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointProgressImpl.java @@ -39,7 +39,7 @@ import org.jetbrains.annotations.Nullable; /** * Data class representing the state of running/scheduled checkpoint. */ -class CheckpointProgressImpl implements CheckpointProgress { +public class CheckpointProgressImpl implements CheckpointProgress { /** Checkpoint id. */ private final UUID id = UUID.randomUUID(); @@ -92,7 +92,7 @@ class CheckpointProgressImpl implements CheckpointProgress { * * @param delay Delay in nanos before next checkpoint is to be executed. Value is from {@code 0} to {@code 365} days. */ - CheckpointProgressImpl(long delay) { + public CheckpointProgressImpl(long delay) { nextCheckpointNanos(delay); } diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryNoLoadTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryNoLoadTest.java index 2a980a19a42..4c1263cc91b 100644 --- a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryNoLoadTest.java +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryNoLoadTest.java @@ -65,6 +65,7 @@ import org.apache.ignite.internal.pagememory.configuration.CheckpointConfigurati import org.apache.ignite.internal.pagememory.configuration.PersistentDataRegionConfiguration; import org.apache.ignite.internal.pagememory.io.PageIoRegistry; import org.apache.ignite.internal.pagememory.persistence.GroupPartitionId; +import org.apache.ignite.internal.pagememory.persistence.PageHeader; import org.apache.ignite.internal.pagememory.persistence.PartitionMeta.PartitionMetaSnapshot; import org.apache.ignite.internal.pagememory.persistence.PartitionMetaManager; import org.apache.ignite.internal.pagememory.persistence.PersistentPageMemory; @@ -72,7 +73,9 @@ import org.apache.ignite.internal.pagememory.persistence.PersistentPageMemoryMet import org.apache.ignite.internal.pagememory.persistence.TestPageReadWriteManager; import org.apache.ignite.internal.pagememory.persistence.WriteDirtyPage; import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointManager; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointMetricsTracker; import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointProgress; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointProgressImpl; import org.apache.ignite.internal.pagememory.persistence.store.FilePageStore; import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; import org.apache.ignite.internal.testframework.ExecutorServiceExtension; @@ -584,4 +587,71 @@ public class PersistentPageMemoryNoLoadTest extends AbstractPageMemoryNoLoadSelf mem.stop(true); } } + + @Test + void testPartitionGenerationAfterAllocatePage() throws Exception { + runWithStartedPersistentPageMemory(mem -> { + FullPageId fullPageId = allocatePage(mem); + + // Absolute memory pointer to page with header. + long absPtr = mem.acquirePage(fullPageId.groupId(), fullPageId.pageId()); + + assertEquals(1, PageHeader.readPartitionGeneration(absPtr)); + }); + } + + @Test + void testPartitionGenerationAfterAllocatePageAndInvalidatePartition() throws Exception { + runWithStartedPersistentPageMemory(mem -> { + assertEquals(2, mem.invalidate(GRP_ID, PARTITION_ID)); + + FullPageId fullPageId = allocatePage(mem); + + // Absolute memory pointer to page with header. + long absPtr = mem.acquirePage(fullPageId.groupId(), fullPageId.pageId()); + + assertEquals(2, PageHeader.readPartitionGeneration(absPtr)); + }); + } + + @Test + void testPartitionGenerationAfterCheckpointWritePageAndInvalidatePartition() throws Exception { + runWithStartedPersistentPageMemory(mem -> { + FullPageId fullPageId = allocatePage(mem); + + mem.beginCheckpoint(new CheckpointProgressImpl(42)); + + assertEquals(2, mem.invalidate(GRP_ID, PARTITION_ID)); + + mem.checkpointWritePage( + fullPageId, + ByteBuffer.allocate(mem.pageSize()), + (fullPageId1, buf, tag) -> {}, + new CheckpointMetricsTracker(), + true + ); + + // Absolute memory pointer to page with header. + long absPtr = mem.acquirePage(fullPageId.groupId(), fullPageId.pageId()); + + assertEquals(2, PageHeader.readPartitionGeneration(absPtr)); + }); + } + + private void runWithStartedPersistentPageMemory(ConsumerX<PersistentPageMemory> c) throws Exception { + PersistentPageMemory mem = (PersistentPageMemory) memory(); + + mem.start(); + + try { + c.accept(mem); + } finally { + mem.stop(true); + } + } + + @FunctionalInterface + private interface ConsumerX<T> { + void accept(T t) throws Exception; + } }
