ibessonov commented on code in PR #6433:
URL: https://github.com/apache/ignite-3/pull/6433#discussion_r2282263567


##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -1555,14 +1552,14 @@ private void resetDirtyPages() {
          * consistency. The phase should not start until all dirty pages are 
written by the checkpoint writer, but for page replacement we
          * must block it ourselves.</p>
          *
-         * @param fullPageId Candidate page ID.
-         * @param absPtr Absolute pointer to the candidate page.
+         * @param fullPageId Candidate full page ID.
+         * @param absPtr Absolute memory pointer to candidate page with header.

Review Comment:
   Why do you add the word `memory`? Are there other pointers in this class?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -1112,68 +1108,69 @@ private long writeLockPage(long absPtr, FullPageId 
fullId, boolean checkTag) {
         return locked ? postWriteLockPage(absPtr, fullId) : 0;
     }
 
-    private long postWriteLockPage(long absPtr, FullPageId fullId) {
+    private long postWriteLockPage(long absPtr, FullPageId fullPageId) {
         writeTimestamp(absPtr, coarseCurrentTimeMillis());
 
         // Create a buffer copy if the page is scheduled for a checkpoint.
-        if (isInCheckpoint(fullId) && tempBufferPointer(absPtr) == 
INVALID_REL_PTR) {
-            long tmpRelPtr;
-
-            PagePool checkpointPool = this.checkpointPool;
-
-            while (true) {
-                tmpRelPtr = 
checkpointPool.borrowOrAllocateFreePage(tag(fullId.pageId()));
-
-                if (tmpRelPtr != INVALID_REL_PTR) {
-                    break;
-                }
-
-                // TODO https://issues.apache.org/jira/browse/IGNITE-23106 
Replace spin-wait with a proper wait.
-                try {
-                    Thread.sleep(1);
-                } catch (InterruptedException ignore) {
-                    // No-op.
-                }
-            }
+        if (isInCheckpoint(fullPageId) && 
!hasCheckpointTempBufferRelativePointer(absPtr)) {

Review Comment:
   Isn't this a bug? I thought we discussed this place precisely, and decided 
that `isInCheckpoint` check must include the partition generation. Does it 
include it?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.
      *
-     * @param absPtr Page pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
     public static boolean isAcquired(long absPtr) {
-        return getInt(absPtr + PAGE_PIN_CNT_OFFSET) > 0;
+        return getInt(absPtr + ACQUIRE_COUNT_OFFSET) > 0;
     }
 
     /**
-     * Acquires a page.
+     * Atomically acquires a page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int acquirePage(long absPtr) {
-        return incrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return incrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Releases the page.
+     * Atomically releases the page in page header.

Review Comment:
   Same here. Please improve the javadocs and make them make sense



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {

Review Comment:
   Can we pass a generation as a parameter?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -1076,14 +1078,8 @@ void readUnlockPage(long absPtr) {
         rwLock.readUnlock(absPtr + PAGE_LOCK_OFFSET);
     }
 
-    /**
-     * Checks if a page has temp copy buffer.
-     *
-     * @param absPtr Absolute pointer.
-     * @return {@code True} if a page has temp buffer.
-     */
-    public boolean hasTempCopy(long absPtr) {
-        return tempBufferPointer(absPtr) != INVALID_REL_PTR;
+    private static boolean hasCheckpointTempBufferRelativePointer(long absPtr) 
{

Review Comment:
   I liked an old name better. How does "having a pointer" make me understand 
the code better? There must be a balance. If you didn't like the word `Temp`, 
you could have replaced it with `CheckpointBuffer`. But why removing the word 
`Copy`? That's just strange!



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.

Review Comment:
   ```suggestion
        * @param dirty Dirty flag value.
   ```



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.

Review Comment:
   What do you mean by "pinned from page header"? This statement doesn't make 
any sense to me



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.
      *
-     * @param absPtr Page pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
     public static boolean isAcquired(long absPtr) {
-        return getInt(absPtr + PAGE_PIN_CNT_OFFSET) > 0;
+        return getInt(absPtr + ACQUIRE_COUNT_OFFSET) > 0;
     }
 
     /**
-     * Acquires a page.
+     * Atomically acquires a page in page header.

Review Comment:
   Same here, what does "a page in page header" mean?
   These additions to javadocs make them more confusing.



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.

Review Comment:
   ```suggestion
        * Writes value of dirty flag to page header.
   ```



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -1112,68 +1108,69 @@ private long writeLockPage(long absPtr, FullPageId 
fullId, boolean checkTag) {
         return locked ? postWriteLockPage(absPtr, fullId) : 0;
     }
 
-    private long postWriteLockPage(long absPtr, FullPageId fullId) {
+    private long postWriteLockPage(long absPtr, FullPageId fullPageId) {
         writeTimestamp(absPtr, coarseCurrentTimeMillis());
 
         // Create a buffer copy if the page is scheduled for a checkpoint.
-        if (isInCheckpoint(fullId) && tempBufferPointer(absPtr) == 
INVALID_REL_PTR) {
-            long tmpRelPtr;
-
-            PagePool checkpointPool = this.checkpointPool;
-
-            while (true) {
-                tmpRelPtr = 
checkpointPool.borrowOrAllocateFreePage(tag(fullId.pageId()));
-
-                if (tmpRelPtr != INVALID_REL_PTR) {
-                    break;
-                }
-
-                // TODO https://issues.apache.org/jira/browse/IGNITE-23106 
Replace spin-wait with a proper wait.
-                try {
-                    Thread.sleep(1);
-                } catch (InterruptedException ignore) {
-                    // No-op.
-                }
-            }
+        if (isInCheckpoint(fullPageId) && 
!hasCheckpointTempBufferRelativePointer(absPtr)) {
+            long checkpointTmpRelPtr = 
borrowOrAllocateCheckpointCopyBuffer(fullPageId);

Review Comment:
   "CopyBuffer" - you see, currently in the code it's mostly called a "tmp 
buffer". It almost feels like you're introducing a second name to this entity. 
Are you sure it's a good idea?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;

Review Comment:
   What was wrong with the old name?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -121,36 +128,27 @@
  *
  * <p>When page is allocated and is in use:
  * <pre>
- * 
+------------------+--------+--------+----+----+--------+--------+----------------------+
- * |     8 bytes      |8 bytes |8 bytes |4 b |4 b |8 bytes |8 bytes |       
PAGE_SIZE      |
- * 
+------------------+--------+--------+----+----+--------+--------+----------------------+
- * | Marker/Timestamp |Rel ptr |Page ID |C ID|PIN | LOCK   |TMP BUF |       
Page data      |
- * 
+------------------+--------+--------+----+----+--------+--------+----------------------+
+ * +-------------------+----------+
+ * |PAGE_OVERHEAD      |PAGE_SIZE |
+ * +-------------------+----------+
+ * |{@link PageHeader} |Page data |
+ * +-------------------+----------+

Review Comment:
   ```suggestion
    * +--------------------+-----------+
    * | PAGE_OVERHEAD      | PAGE_SIZE |
    * +--------------------+-----------+
    * | {@link PageHeader} | Page data |
    * +--------------------+-----------+
   ```



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+

Review Comment:
   ```suggestion
    * 
+------------------+----------------------+---------+---------+----------+---------------+-----------+-----------------------+
    * |      8 bytes     |        4 bytes       | 4 bytes | 8 bytes | 4 bytes  
| 4 bytes       | 8 bytes   |        8 bytes        |
    * 
+------------------+----------------------+---------+---------+----------+---------------+-----------+-----------------------+
    * | Marker/Timestamp | Partition generation | Flags   | Page ID | Group ID 
| Acquire count | Lock data | Checkpoint tmp buffer |
    * 
+------------------+----------------------+---------+---------+----------+---------------+-----------+-----------------------+
   ```



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemory.java:
##########
@@ -521,24 +519,24 @@ public void writeUnlock(int grpId, long pageId, long 
page, boolean dirtyFlag, bo
     public boolean isDirty(int grpId, long pageId, long page) {
         assert started;
 
-        return isDirty(page);
+        return readDirtyFlag(page);

Review Comment:
   Why not leaving an old code here? You don't need to maximize the number of 
changes in this PR, it's already big enough



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.
      *
-     * @param absPtr Page pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
     public static boolean isAcquired(long absPtr) {
-        return getInt(absPtr + PAGE_PIN_CNT_OFFSET) > 0;
+        return getInt(absPtr + ACQUIRE_COUNT_OFFSET) > 0;
     }
 
     /**
-     * Acquires a page.
+     * Atomically acquires a page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int acquirePage(long absPtr) {
-        return incrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return incrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Releases the page.
+     * Atomically releases the page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int releasePage(long absPtr) {
-        return decrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return decrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Returns number of acquires for the page.
+     * Volatile reads count of acquires for the page from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static int pinCount(long absPtr) {
-        return getIntVolatile(null, absPtr);
+    static int readAcquiresCount(long absPtr) {
+        return getIntVolatile(null, absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Reads relative pointer from the page at the given absolute position.
+     * Volatile writes timestamp to page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
+     * <p>It is written without the last byte, to avoid ABA problems see 
{@link PagePool#borrowOrAllocateFreePage} in
+     * {@code borrowFreePage}.</p>
+     *
+     * @param absPtr Absolute memory pointer to page header.
+     * @param timestamp Timestamp.
      */
-    public static long readRelative(long absPtr) {
-        return getLong(absPtr + RELATIVE_PTR_OFFSET) & RELATIVE_PTR_MASK;
+    static void writeTimestamp(long absPtr, long timestamp) {
+        timestamp &= 0xFFFFFFFFFFFFFF00L;
+
+        putLongVolatile(null, absPtr + MARKER_OR_TIMESTAMP_OFFSET, timestamp | 
0x01);
     }
 
     /**
-     * Writes relative pointer to the page at the given absolute position.
+     * Reads timestamp from page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
-     * @param relPtr Relative pointer to write.
+     * <p>It is read without the last byte, to avoid ABA problems see {@link 
PagePool#borrowOrAllocateFreePage} in
+     * {@code borrowFreePage}.</p>
+     *
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void relative(long absPtr, long relPtr) {
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtr & RELATIVE_PTR_MASK);
+    public static long readTimestamp(long absPtr) {
+        long markerAndTs = getLong(absPtr + MARKER_OR_TIMESTAMP_OFFSET);
+
+        // Clear last byte as it is occupied by page marker.
+        return markerAndTs & ~0xFF;
     }
 
     /**
-     * Volatile write for current timestamp to page in {@code absAddr} address.
+     * Writes relative pointer to checkpoint temporal copy buffer to page 
header.
      *
-     * @param absPtr Absolute page address.
-     * @param tstamp Timestamp.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param tmpRelPtr Temporal copy buffer relative pointer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied
+     *         to checkpoint buffer.
      */
-    public static void writeTimestamp(final long absPtr, long tstamp) {
-        tstamp &= 0xFFFFFFFFFFFFFF00L;
-
-        putLongVolatile(null, absPtr, tstamp | 0x01);
+    static void writeCheckpointTempBufferRelativePointer(long absPtr, long 
tmpRelPtr) {
+        putLong(absPtr + CHECKPOINT_TMP_BUFFER_OFFSET, tmpRelPtr);
     }
 
     /**
-     * Read for timestamp from page in {@code absAddr} address.
+     * Reads relative pointer to checkpoint temporal copy buffer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to
+     * checkpoint buffer from page header.
      *
-     * @param absPtr Absolute page address.
-     * @return Timestamp.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static long readTimestamp(final long absPtr) {
-        long markerAndTs = getLong(absPtr);
+    static long readCheckpointTempBufferRelativePointer(long absPtr) {
+        return getLong(absPtr + CHECKPOINT_TMP_BUFFER_OFFSET);
+    }
 
-        // Clear last byte as it is occupied by page marker.
-        return markerAndTs & ~0xFF;
+    /**
+     * Reads page ID from page header.
+     *
+     * @param absPtr Absolute memory pointer to page header.
+     */
+    static long readPageId(long absPtr) {
+        return getLong(absPtr + PAGE_ID_OFFSET);
     }
 
     /**
-     * Sets pointer to checkpoint buffer.
+     * Writes page ID to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param tmpRelPtr Temp buffer relative pointer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to checkpoint
-     *      buffer.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param pageId Page ID.
      */
-    public static void tempBufferPointer(long absPtr, long tmpRelPtr) {
-        putLong(absPtr + PAGE_TMP_BUF_OFFSET, tmpRelPtr);
+    private static void writePageId(long absPtr, long pageId) {
+        putLong(absPtr + PAGE_ID_OFFSET, pageId);
     }
 
     /**
-     * Gets pointer to checkpoint buffer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to checkpoint 
buffer.
+     * Reads page group ID from page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @return Temp buffer relative pointer.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Page group ID.
      */
-    public static long tempBufferPointer(long absPtr) {
-        return getLong(absPtr + PAGE_TMP_BUF_OFFSET);
+    private static int readPageGroupId(long absPtr) {

Review Comment:
   What's a `page group ID`? Usually we call it `Group ID`, is there something 
wrong with this name?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.
      *
-     * @param absPtr Page pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
     public static boolean isAcquired(long absPtr) {
-        return getInt(absPtr + PAGE_PIN_CNT_OFFSET) > 0;
+        return getInt(absPtr + ACQUIRE_COUNT_OFFSET) > 0;
     }
 
     /**
-     * Acquires a page.
+     * Atomically acquires a page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int acquirePage(long absPtr) {
-        return incrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return incrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Releases the page.
+     * Atomically releases the page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int releasePage(long absPtr) {
-        return decrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return decrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Returns number of acquires for the page.
+     * Volatile reads count of acquires for the page from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static int pinCount(long absPtr) {
-        return getIntVolatile(null, absPtr);
+    static int readAcquiresCount(long absPtr) {
+        return getIntVolatile(null, absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Reads relative pointer from the page at the given absolute position.
+     * Volatile writes timestamp to page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
+     * <p>It is written without the last byte, to avoid ABA problems see 
{@link PagePool#borrowOrAllocateFreePage} in
+     * {@code borrowFreePage}.</p>

Review Comment:
   This is a new comment, I haven't seen it before. Could you please expand on 
it, there's nothing about ABA problem in `PagePool#borrowOrAllocateFreePage`. 
How is it related to page pool?



##########
modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageHeader.java:
##########
@@ -27,273 +26,329 @@
 import static org.apache.ignite.internal.util.GridUnsafe.putInt;
 import static org.apache.ignite.internal.util.GridUnsafe.putLong;
 import static org.apache.ignite.internal.util.GridUnsafe.putLongVolatile;
+import static org.apache.ignite.internal.util.StringUtils.hexLong;
 
 import org.apache.ignite.internal.pagememory.FullPageId;
 
 /**
- * Page header.
+ * Helper class for working with the page header that is stored in memory for 
{@link PersistentPageMemory}.
+ *
+ * <p>Page header has the following structure:</p>
+ * <pre>
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |     8 bytes     |       4 bytes       |4 bytes |8 bytes |4 bytes  |4 
bytes       |8 bytes   |       8 bytes        |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * |Marker/Timestamp |Partition generation |Flags   |Page ID |Group ID 
|Acquire count |Lock data |Checkpoint tmp buffer |
+ * 
+-----------------+---------------------+--------+--------+---------+--------------+----------+----------------------+
+ * </pre>
+ *
+ * <p>Additional information:</p>
+ * <ul>
+ *     <li>Size of the page header in {@link #PAGE_OVERHEAD}.</li>
+ *     <li>Flags currently store only one value, whether the page is dirty or 
not. Only one byte is used for now, the rest can be reused
+ *     later, we do not remove them only for alignment.</li>
+ * </ul>
  */
 public class PageHeader {
     /** Page marker. */
-    public static final long PAGE_MARKER = 0x0000000000000001L;
+    private static final long PAGE_MARKER = 0x0000000000000001L;
+
+    /** Dirty flag mask. */
+    private static final int DIRTY_FLAG_MASK = 0x00000001;
+
+    /** Unknown partition generation. */
+    static final int UNKNOWN_PARTITION_GENERATION = -1;
+
+    /**
+     * Page overhead in bytes.
+     * <ol>
+     *     <li>8 bytes - Marker/Timestamp.</li>
+     *     <li>4 bytes - Partition generation.</li>
+     *     <li>4 bytes - Flags.</li>
+     *     <li>8 bytes - Page ID.</li>
+     *     <li>4 bytes - Page group ID.</li>
+     *     <li>4 bytes - Count of page acquires.</li>
+     *     <li>8 bytes - Page lack data.</li>
+     *     <li>8 bytes - Checkpoint temporal copy buffer relative pointer.</li>
+     * </ol>
+     */
+    public static final int PAGE_OVERHEAD = 48;
+
+    /** Marker or timestamp offset. */
+    private static final int MARKER_OR_TIMESTAMP_OFFSET = 0;
 
-    /** Dirty flag. */
-    private static final long DIRTY_FLAG = 0x0100000000000000L;
+    /** Partition generation offset. */
+    private static final int PARTITION_GENERATION_OFFSET = 8;
 
-    /** Page relative pointer. Does not change once a page is allocated. */
-    private static final int RELATIVE_PTR_OFFSET = 8;
+    /** Flags offset. */
+    private static final int FLAGS_OFFSET = 12;
 
     /** Page ID offset. */
     private static final int PAGE_ID_OFFSET = 16;
 
     /** Page group ID offset. */
-    private static final int PAGE_GROUP_ID_OFFSET = 24;
+    private static final int GROUP_ID_OFFSET = 24;
 
-    /** Page pin counter offset. */
-    private static final int PAGE_PIN_CNT_OFFSET = 28;
+    /** Page acquire counter offset. */
+    private static final int ACQUIRE_COUNT_OFFSET = 28;
 
-    /** Page temp copy buffer relative pointer offset. */
-    private static final int PAGE_TMP_BUF_OFFSET = 40;
+    /** Page lock data offset. */
+    public static final int PAGE_LOCK_OFFSET = 32;
+
+    /** Page temporal copy buffer relative pointer offset. */
+    private static final int CHECKPOINT_TMP_BUFFER_OFFSET = 40;
 
     /**
-     * Initializes the header of the page.
+     * Initializes the header of page.
      *
-     * @param absPtr Absolute pointer to initialize.
-     * @param relative Relative pointer to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void initNew(long absPtr, long relative) {
-        relative(absPtr, relative);
+    public static void initNew(long absPtr) {
+        writePageMarker(absPtr);
+
+        writePartitionGeneration(absPtr, UNKNOWN_PARTITION_GENERATION);
 
-        tempBufferPointer(absPtr, INVALID_REL_PTR);
+        putInt(absPtr + ACQUIRE_COUNT_OFFSET, 0);
 
-        putLong(absPtr, PAGE_MARKER);
-        putInt(absPtr + PAGE_PIN_CNT_OFFSET, 0);
+        writeCheckpointTempBufferRelativePointer(absPtr, INVALID_REL_PTR);
     }
 
     /**
-     * Returns value of dirty flag.
+     * Reads value of dirty flag from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static boolean dirty(long absPtr) {
-        return flag(absPtr, DIRTY_FLAG);
+    public static boolean readDirtyFlag(long absPtr) {
+        return readFlag(absPtr, DIRTY_FLAG_MASK);
     }
 
     /**
-     * Updates value of dirty flag.
+     * Write value of dirty flag to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param dirty Dirty flag.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param dirty Value dirty flag.
      * @return Previous value of dirty flag.
      */
-    public static boolean dirty(long absPtr, boolean dirty) {
-        return flag(absPtr, DIRTY_FLAG, dirty);
+    public static boolean writeDirtyFlag(long absPtr, boolean dirty) {
+        return writeFlag(absPtr, DIRTY_FLAG_MASK, dirty);
     }
 
     /**
-     * Returns flag value.
+     * Reads flag value from page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      */
-    private static boolean flag(long absPtr, long flag) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean readFlag(long absPtr, int flagMask) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        return (relPtrWithFlags & flag) != 0;
+        return (flags & flagMask) != 0;
     }
 
     /**
-     * Sets flag value.
+     * Writes flag value to page header.
      *
-     * @param absPtr Absolute pointer.
-     * @param flag Flag mask.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param flagMask Flag mask.
      * @param set New flag value.
      * @return Previous flag value.
      */
-    private static boolean flag(long absPtr, long flag, boolean set) {
-        assert (flag & 0xFFFFFFFFFFFFFFL) == 0;
-        assert Long.bitCount(flag) == 1;
+    private static boolean writeFlag(long absPtr, int flagMask, boolean set) {
+        assert Integer.bitCount(flagMask) == 1 : hexLong(flagMask);
 
-        long relPtrWithFlags = getLong(absPtr + RELATIVE_PTR_OFFSET);
+        int flags = getInt(absPtr + FLAGS_OFFSET);
 
-        boolean was = (relPtrWithFlags & flag) != 0;
+        boolean was = (flags & flagMask) != 0;
 
         if (set) {
-            relPtrWithFlags |= flag;
+            flags |= flagMask;
         } else {
-            relPtrWithFlags &= ~flag;
+            flags &= ~flagMask;
         }
 
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtrWithFlags);
+        putInt(absPtr + FLAGS_OFFSET, flags);
 
         return was;
     }
 
     /**
-     * Checks if page is pinned.
+     * Checks if page is pinned from page header.
      *
-     * @param absPtr Page pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
     public static boolean isAcquired(long absPtr) {
-        return getInt(absPtr + PAGE_PIN_CNT_OFFSET) > 0;
+        return getInt(absPtr + ACQUIRE_COUNT_OFFSET) > 0;
     }
 
     /**
-     * Acquires a page.
+     * Atomically acquires a page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int acquirePage(long absPtr) {
-        return incrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return incrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Releases the page.
+     * Atomically releases the page in page header.
      *
-     * @param absPtr Absolute pointer.
-     * @return Number of acquires for the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Number of acquires for page.
      */
     public static int releasePage(long absPtr) {
-        return decrementAndGetInt(absPtr + PAGE_PIN_CNT_OFFSET);
+        return decrementAndGetInt(absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Returns number of acquires for the page.
+     * Volatile reads count of acquires for the page from page header.
      *
-     * @param absPtr Absolute pointer.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static int pinCount(long absPtr) {
-        return getIntVolatile(null, absPtr);
+    static int readAcquiresCount(long absPtr) {
+        return getIntVolatile(null, absPtr + ACQUIRE_COUNT_OFFSET);
     }
 
     /**
-     * Reads relative pointer from the page at the given absolute position.
+     * Volatile writes timestamp to page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
+     * <p>It is written without the last byte, to avoid ABA problems see 
{@link PagePool#borrowOrAllocateFreePage} in
+     * {@code borrowFreePage}.</p>
+     *
+     * @param absPtr Absolute memory pointer to page header.
+     * @param timestamp Timestamp.
      */
-    public static long readRelative(long absPtr) {
-        return getLong(absPtr + RELATIVE_PTR_OFFSET) & RELATIVE_PTR_MASK;
+    static void writeTimestamp(long absPtr, long timestamp) {
+        timestamp &= 0xFFFFFFFFFFFFFF00L;
+
+        putLongVolatile(null, absPtr + MARKER_OR_TIMESTAMP_OFFSET, timestamp | 
0x01);
     }
 
     /**
-     * Writes relative pointer to the page at the given absolute position.
+     * Reads timestamp from page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
-     * @param relPtr Relative pointer to write.
+     * <p>It is read without the last byte, to avoid ABA problems see {@link 
PagePool#borrowOrAllocateFreePage} in
+     * {@code borrowFreePage}.</p>
+     *
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static void relative(long absPtr, long relPtr) {
-        putLong(absPtr + RELATIVE_PTR_OFFSET, relPtr & RELATIVE_PTR_MASK);
+    public static long readTimestamp(long absPtr) {
+        long markerAndTs = getLong(absPtr + MARKER_OR_TIMESTAMP_OFFSET);
+
+        // Clear last byte as it is occupied by page marker.
+        return markerAndTs & ~0xFF;
     }
 
     /**
-     * Volatile write for current timestamp to page in {@code absAddr} address.
+     * Writes relative pointer to checkpoint temporal copy buffer to page 
header.
      *
-     * @param absPtr Absolute page address.
-     * @param tstamp Timestamp.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param tmpRelPtr Temporal copy buffer relative pointer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied
+     *         to checkpoint buffer.
      */
-    public static void writeTimestamp(final long absPtr, long tstamp) {
-        tstamp &= 0xFFFFFFFFFFFFFF00L;
-
-        putLongVolatile(null, absPtr, tstamp | 0x01);
+    static void writeCheckpointTempBufferRelativePointer(long absPtr, long 
tmpRelPtr) {
+        putLong(absPtr + CHECKPOINT_TMP_BUFFER_OFFSET, tmpRelPtr);
     }
 
     /**
-     * Read for timestamp from page in {@code absAddr} address.
+     * Reads relative pointer to checkpoint temporal copy buffer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to
+     * checkpoint buffer from page header.
      *
-     * @param absPtr Absolute page address.
-     * @return Timestamp.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    public static long readTimestamp(final long absPtr) {
-        long markerAndTs = getLong(absPtr);
+    static long readCheckpointTempBufferRelativePointer(long absPtr) {
+        return getLong(absPtr + CHECKPOINT_TMP_BUFFER_OFFSET);
+    }
 
-        // Clear last byte as it is occupied by page marker.
-        return markerAndTs & ~0xFF;
+    /**
+     * Reads page ID from page header.
+     *
+     * @param absPtr Absolute memory pointer to page header.
+     */
+    static long readPageId(long absPtr) {
+        return getLong(absPtr + PAGE_ID_OFFSET);
     }
 
     /**
-     * Sets pointer to checkpoint buffer.
+     * Writes page ID to page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @param tmpRelPtr Temp buffer relative pointer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to checkpoint
-     *      buffer.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param pageId Page ID.
      */
-    public static void tempBufferPointer(long absPtr, long tmpRelPtr) {
-        putLong(absPtr + PAGE_TMP_BUF_OFFSET, tmpRelPtr);
+    private static void writePageId(long absPtr, long pageId) {
+        putLong(absPtr + PAGE_ID_OFFSET, pageId);
     }
 
     /**
-     * Gets pointer to checkpoint buffer or {@link 
PersistentPageMemory#INVALID_REL_PTR} if page is not copied to checkpoint 
buffer.
+     * Reads page group ID from page header.
      *
-     * @param absPtr Page absolute pointer.
-     * @return Temp buffer relative pointer.
+     * @param absPtr Absolute memory pointer to page header.
+     * @return Page group ID.
      */
-    public static long tempBufferPointer(long absPtr) {
-        return getLong(absPtr + PAGE_TMP_BUF_OFFSET);
+    private static int readPageGroupId(long absPtr) {
+        return getInt(absPtr + GROUP_ID_OFFSET);
     }
 
     /**
-     * Reads page ID from the page at the given absolute position.
+     * Writes page group ID to page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
-     * @return Page ID written to the page.
+     * @param absPtr Absolute memory pointer to page header.
+     * @param groupId Page group ID.
      */
-    public static long readPageId(long absPtr) {
-        return getLong(absPtr + PAGE_ID_OFFSET);
+    private static void writePageGroupId(long absPtr, int groupId) {
+        putInt(absPtr + GROUP_ID_OFFSET, groupId);
     }
 
     /**
-     * Writes page ID to the page at the given absolute position.
+     * Reads full page ID from page header.
      *
-     * @param absPtr Absolute memory pointer to the page header.
-     * @param pageId Page ID to write.
+     * @param absPtr Absolute memory pointer to page header.
      */
-    private static void pageId(long absPtr, long pageId) {
-        putLong(absPtr + PAGE_ID_OFFSET, pageId);
+    public static FullPageId readFullPageId(long absPtr) {
+        return new FullPageId(readPageId(absPtr), readPageGroupId(absPtr));
     }

Review Comment:
   I disagree with most renames here, but here I disagree even more. Could you 
please return an old name? It's a static constructor, not a method for reading 
something. And even if it was a method for reading something it wouldn't have 
to include the word `read` in it. That's not how naming should work, this is 
extremely excessive
   
   Why did you add all these `read` and `write` prefixes?



-- 
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: notifications-unsubscr...@ignite.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to