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;
+    }
 }

Reply via email to