This is an automated email from the ASF dual-hosted git repository.

tkalkirill pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new a51777f72c IGNITE-20958 
PersistentPageMemoryMvPartitionStorageTest#groupConfigShorteningWorksCorrectly 
threw an AssertionError (#2888)
a51777f72c is described below

commit a51777f72cd53ae1a43d72e41d14d73cdf0b971e
Author: Kirill Tkalenko <[email protected]>
AuthorDate: Tue Nov 28 15:13:56 2023 +0300

    IGNITE-20958 
PersistentPageMemoryMvPartitionStorageTest#groupConfigShorteningWorksCorrectly 
threw an AssertionError (#2888)
---
 .../persistence/PartitionMetaManager.java          |  50 ++++-----
 .../persistence/store/FilePageStoreManager.java    |  95 +++++++---------
 .../persistence/store/GroupPageStoresMap.java      |  12 ++
 .../persistence/PartitionMetaManagerTest.java      |  22 +++-
 .../PersistentPageMemoryNoLoadTest.java            |  29 +++--
 .../store/FilePageStoreManagerTest.java            | 118 ++++++++++++++-----
 .../PersistentPageMemoryTableStorage.java          | 125 +++++++++++----------
 7 files changed, 269 insertions(+), 182 deletions(-)

diff --git 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManager.java
 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManager.java
index bfda58770f..67f4833de3 100644
--- 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManager.java
+++ 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManager.java
@@ -18,9 +18,7 @@
 package org.apache.ignite.internal.pagememory.persistence;
 
 import static 
org.apache.ignite.internal.pagememory.persistence.PartitionMeta.partitionMetaPageId;
-import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
 import static org.apache.ignite.internal.util.GridUnsafe.bufferAddress;
-import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
@@ -80,55 +78,51 @@ public class PartitionMetaManager {
     /**
      * Reads the partition {@link PartitionMeta meta} from the partition file 
or creates a new one.
      *
-     * <p>If it creates a new one, it writes the meta to the file.
+     * <p>If it creates a new one, it writes the meta to the file.</p>
      *
      * @param checkpointId Checkpoint ID.
      * @param groupPartitionId Partition of the group.
      * @param filePageStore Partition file page store.
+     * @param buffer Buffer for reading and writing pages.
      */
     public PartitionMeta readOrCreateMeta(
             @Nullable UUID checkpointId,
             GroupPartitionId groupPartitionId,
-            FilePageStore filePageStore
+            FilePageStore filePageStore,
+            ByteBuffer buffer
     ) throws IgniteInternalCheckedException {
-        ByteBuffer buffer = allocateBuffer(pageSize);
-
         long bufferAddr = bufferAddress(buffer);
 
         long partitionMetaPageId = 
partitionMetaPageId(groupPartitionId.getPartitionId());
 
-        try {
-            if (containsPartitionMeta(filePageStore)) {
-                // Reads the partition meta.
-                try {
-                    filePageStore.readWithoutPageIdCheck(partitionMetaPageId, 
buffer, false);
+        if (containsPartitionMeta(filePageStore)) {
+            // Reads the partition meta.
+            try {
+                filePageStore.readWithoutPageIdCheck(partitionMetaPageId, 
buffer, false);
 
-                    return new PartitionMeta(checkpointId, 
ioRegistry.resolve(bufferAddr), bufferAddr);
-                } catch (IgniteInternalDataIntegrityViolationException e) {
-                    LOG.info(() -> "Error reading partition meta page, will be 
recreated: " + groupPartitionId, e);
-                }
+                return new PartitionMeta(checkpointId, 
ioRegistry.resolve(bufferAddr), bufferAddr);
+            } catch (IgniteInternalDataIntegrityViolationException e) {
+                LOG.info(() -> "Error reading partition meta page, will be 
recreated: " + groupPartitionId, e);
             }
+        }
 
-            // Creates and writes a partition meta.
-            PartitionMetaIo io = PartitionMetaIo.VERSIONS.latest();
+        // Creates and writes a partition meta.
+        PartitionMetaIo io = PartitionMetaIo.VERSIONS.latest();
 
-            io.initNewPage(bufferAddr, partitionMetaPageId, pageSize);
+        io.initNewPage(bufferAddr, partitionMetaPageId, pageSize);
 
-            // Because we will now write this page.
-            io.setPageCount(bufferAddr, 1);
+        // Because we will now write this page.
+        io.setPageCount(bufferAddr, 1);
 
-            int pageIdx = filePageStore.allocatePage();
+        int pageIdx = filePageStore.allocatePage();
 
-            assert pageIdx == 0 : pageIdx;
+        assert pageIdx == 0 : pageIdx;
 
-            filePageStore.write(partitionMetaPageId, buffer.rewind(), true);
+        filePageStore.write(partitionMetaPageId, buffer.rewind(), true);
 
-            filePageStore.sync();
+        filePageStore.sync();
 
-            return new PartitionMeta(checkpointId, io, bufferAddr);
-        } finally {
-            freeBuffer(buffer);
-        }
+        return new PartitionMeta(checkpointId, io, bufferAddr);
     }
 
     /**
diff --git 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManager.java
 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManager.java
index 502b139c5c..831d10ced8 100644
--- 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManager.java
+++ 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManager.java
@@ -24,8 +24,6 @@ import static java.util.stream.Collectors.toList;
 import static 
org.apache.ignite.internal.pagememory.PageIdAllocator.MAX_PARTITION_ID;
 import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageId;
 import static 
org.apache.ignite.internal.pagememory.util.PageIdUtils.partitionId;
-import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
-import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
 import static org.apache.ignite.internal.util.IgniteUtils.closeAll;
 
 import java.io.File;
@@ -50,7 +48,6 @@ import 
org.apache.ignite.internal.pagememory.persistence.GroupPartitionId;
 import org.apache.ignite.internal.pagememory.persistence.PageReadWriteManager;
 import 
org.apache.ignite.internal.pagememory.persistence.store.GroupPageStoresMap.GroupPartitionPageStore;
 import 
org.apache.ignite.internal.pagememory.persistence.store.LongOperationAsyncExecutor.RunnableX;
-import org.apache.ignite.internal.util.IgniteStripedLock;
 import org.apache.ignite.internal.util.IgniteUtils;
 import org.jetbrains.annotations.Nullable;
 
@@ -97,20 +94,12 @@ public class FilePageStoreManager implements 
PageReadWriteManager {
     /** Starting directory for all file page stores, for example: 
'db/group-123/index.bin'. */
     private final Path dbDir;
 
-    /** Page size in bytes. */
-    private final int pageSize;
-
     /** Executor to disallow running code that modifies data in {@link 
#groupPageStores} concurrently with cleanup of file page store. */
     private final LongOperationAsyncExecutor cleanupAsyncExecutor;
 
     /** Mapping: group ID -> group page stores. */
     private final GroupPageStoresMap<FilePageStore> groupPageStores;
 
-    /** Striped lock for partition initialization. */
-    private final IgniteStripedLock initPartitionStripedLock = new 
IgniteStripedLock(
-            Math.max(Runtime.getRuntime().availableProcessors(), 8)
-    );
-
     /** {@link FilePageStore} factory. */
     private final FilePageStoreFactory filePageStoreFactory;
 
@@ -131,7 +120,6 @@ public class FilePageStoreManager implements 
PageReadWriteManager {
             int pageSize
     ) throws IgniteInternalCheckedException {
         this.dbDir = storagePath.resolve("db");
-        this.pageSize = pageSize;
 
         cleanupAsyncExecutor = new 
LongOperationAsyncExecutor(igniteInstanceName, LOG);
 
@@ -271,48 +259,6 @@ public class FilePageStoreManager implements 
PageReadWriteManager {
         }
     }
 
-    /**
-     * Initialization of the page storage for the group partition.
-     *
-     * @param groupPartitionId Pair of group ID with partition ID.
-     * @throws IgniteInternalCheckedException If failed.
-     */
-    public void initialize(GroupPartitionId groupPartitionId) throws 
IgniteInternalCheckedException {
-        initPartitionStripedLock.lock(groupPartitionId.hashCode());
-
-        try {
-            if (!groupPageStores.contains(groupPartitionId)) {
-                Path tableWorkDir = 
ensureGroupWorkDir(groupPartitionId.getGroupId());
-
-                ByteBuffer buffer = allocateBuffer(pageSize);
-
-                try {
-                    Path partFilePath = 
tableWorkDir.resolve(String.format(PART_FILE_TEMPLATE, 
groupPartitionId.getPartitionId()));
-
-                    Path[] partDeltaFiles = 
findPartitionDeltaFiles(tableWorkDir, groupPartitionId.getPartitionId());
-
-                    FilePageStore filePageStore = 
filePageStoreFactory.createPageStore(buffer.rewind(), partFilePath, 
partDeltaFiles);
-
-                    FilePageStore previous = 
groupPageStores.put(groupPartitionId, filePageStore);
-
-                    assert previous == null : IgniteStringFormatter.format(
-                            "Parallel creation is not allowed: [tableId={}, 
partitionId={}]",
-                            groupPartitionId.getGroupId(),
-                            groupPartitionId.getPartitionId()
-                    );
-                } finally {
-                    freeBuffer(buffer);
-                }
-            }
-        } catch (IgniteInternalCheckedException e) {
-            // TODO: IGNITE-16899 By analogy with 2.0, fail a node
-
-            throw e;
-        } finally {
-            initPartitionStripedLock.unlock(groupPartitionId.hashCode());
-        }
-    }
-
     /**
      * Returns view for all page stores of all groups.
      */
@@ -324,7 +270,7 @@ public class FilePageStoreManager implements 
PageReadWriteManager {
      * Returns partition file page store for the corresponding parameters.
      *
      * @param groupPartitionId Pair of group ID with partition ID.
-     * @return Partition file page, {@code null} if not initialized or has 
been removed.
+     * @return Partition file page store, {@code null} if not initialized or 
has been removed.
      */
     public @Nullable FilePageStore getStore(GroupPartitionId groupPartitionId) 
{
         return groupPageStores.get(groupPartitionId);
@@ -488,4 +434,43 @@ public class FilePageStoreManager implements 
PageReadWriteManager {
             delete(partitionDeleteFilePath);
         }, "destroy-group-" + groupPartitionId.getGroupId() + "-partition-" + 
groupPartitionId.getPartitionId());
     }
+
+    /**
+     * Reads a partition file page store from the file system with its delta 
files if it exists, otherwise creates a new one but without
+     * saving it to the file system.
+     *
+     * <p>Also does not initialize the storage, i.e. does not call {@link 
FilePageStore#ensure()}.</p>
+     *
+     * @param groupPartitionId Pair of group ID with partition ID.
+     * @param readBuffer Buffer for reading file headers and other supporting 
information from files.
+     */
+    public FilePageStore readOrCreateStore(
+            GroupPartitionId groupPartitionId,
+            ByteBuffer readBuffer
+    ) throws IgniteInternalCheckedException {
+        Path tableWorkDir = ensureGroupWorkDir(groupPartitionId.getGroupId());
+
+        Path partFilePath = 
tableWorkDir.resolve(String.format(PART_FILE_TEMPLATE, 
groupPartitionId.getPartitionId()));
+
+        Path[] partDeltaFiles = findPartitionDeltaFiles(tableWorkDir, 
groupPartitionId.getPartitionId());
+
+        return filePageStoreFactory.createPageStore(readBuffer.rewind(), 
partFilePath, partDeltaFiles);
+    }
+
+    /**
+     * Adds a partition file page storage.
+     *
+     * <p>It is expected that the storage has not been added previously and is 
also ready to be used by other components such as checkpoint
+     * or delta file compactor.</p>
+     *
+     * @param groupPartitionId Pair of group ID with partition ID.
+     * @param filePageStore Partition file page store.
+     */
+    public void addStore(GroupPartitionId groupPartitionId, FilePageStore 
filePageStore) {
+        groupPageStores.compute(groupPartitionId, oldFilePageStore -> {
+            assert oldFilePageStore == null : groupPartitionId;
+
+            return filePageStore;
+        });
+    }
 }
diff --git 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java
 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java
index 17a7fa2de1..0554d47378 100644
--- 
a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java
+++ 
b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/store/GroupPageStoresMap.java
@@ -19,6 +19,7 @@ package 
org.apache.ignite.internal.pagememory.persistence.store;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
 import java.util.stream.Stream;
 import org.apache.ignite.internal.pagememory.persistence.GroupPartitionId;
 import org.jetbrains.annotations.Nullable;
@@ -99,6 +100,17 @@ public class GroupPageStoresMap<T extends PageStore> {
         groupPartitionIdPageStore.clear();
     }
 
+    /**
+     * Attempts to compute a mapping for the group partition and its current 
mapped value (or {@code null} if there is no current mapping).
+     * The entire method invocation is performed atomically.
+     *
+     * @param groupPartitionId Pair of group ID with partition ID.
+     * @param remappingFunction Function to compute a value.
+     */
+    public T compute(GroupPartitionId groupPartitionId, Function<? super T, ? 
extends T> remappingFunction) {
+        return groupPartitionIdPageStore.compute(groupPartitionId, 
(groupPartitionId1, t) -> remappingFunction.apply(t));
+    }
+
     /**
      * Group partition page storage.
      */
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
index 9ebcc03853..d511d47737 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PartitionMetaManagerTest.java
@@ -98,7 +98,7 @@ public class PartitionMetaManagerTest extends 
BaseIgniteAbstractTest {
         try {
             // Check for an empty file.
             try (FilePageStore filePageStore = 
createFilePageStore(testFilePath)) {
-                PartitionMeta meta = manager.readOrCreateMeta(null, partId, 
filePageStore);
+                PartitionMeta meta = readOrCreateMeta(manager, partId, 
filePageStore);
 
                 assertEquals(0, meta.lastAppliedIndex());
                 assertEquals(0, meta.lastAppliedTerm());
@@ -125,7 +125,7 @@ public class PartitionMetaManagerTest extends 
BaseIgniteAbstractTest {
 
             // Check not empty file.
             try (FilePageStore filePageStore = 
createFilePageStore(testFilePath)) {
-                PartitionMeta meta = manager.readOrCreateMeta(null, partId, 
filePageStore);
+                PartitionMeta meta = readOrCreateMeta(manager, partId, 
filePageStore);
 
                 assertEquals(50, meta.lastAppliedIndex());
                 assertEquals(10, meta.lastAppliedTerm());
@@ -152,7 +152,7 @@ public class PartitionMetaManagerTest extends 
BaseIgniteAbstractTest {
 
                 deltaFilePageStoreIo.sync();
 
-                PartitionMeta meta = manager.readOrCreateMeta(null, partId, 
filePageStore);
+                PartitionMeta meta = readOrCreateMeta(manager, partId, 
filePageStore);
 
                 assertEquals(100, meta.lastAppliedIndex());
                 assertEquals(10, meta.lastAppliedTerm());
@@ -174,7 +174,7 @@ public class PartitionMetaManagerTest extends 
BaseIgniteAbstractTest {
 
                 fileIo.writeFully(buffer.rewind(), filePageStore.headerSize());
 
-                PartitionMeta meta = manager.readOrCreateMeta(null, partId, 
filePageStore);
+                PartitionMeta meta = readOrCreateMeta(manager, partId, 
filePageStore);
 
                 assertEquals(0, meta.lastAppliedIndex());
                 assertEquals(0, meta.lastAppliedTerm());
@@ -216,4 +216,18 @@ public class PartitionMetaManagerTest extends 
BaseIgniteAbstractTest {
 
         return filePageStore;
     }
+
+    private static PartitionMeta readOrCreateMeta(
+            PartitionMetaManager manager,
+            GroupPartitionId partId,
+            FilePageStore filePageStore
+    ) throws Exception {
+        ByteBuffer buffer = allocateBuffer(PAGE_SIZE);
+
+        try {
+            return manager.readOrCreateMeta(null, partId, filePageStore, 
buffer);
+        } finally {
+            freeBuffer(buffer);
+        }
+    }
 }
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryNoLoadTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryNoLoadTest.java
index 29162f0fd5..0ee440c756 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryNoLoadTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PersistentPageMemoryNoLoadTest.java
@@ -22,8 +22,10 @@ import static 
org.apache.ignite.internal.pagememory.persistence.PersistentPageMe
 import static 
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointState.FINISHED;
 import static 
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointState.PAGES_SORTED;
 import static 
org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointTestUtils.mockCheckpointTimeoutLock;
-import static org.apache.ignite.internal.testframework.IgniteTestUtils.await;
+import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
 import static org.apache.ignite.internal.util.Constants.MiB;
+import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
+import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
 import static org.apache.ignite.internal.util.IgniteUtils.closeAll;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.empty;
@@ -365,7 +367,7 @@ public class PersistentPageMemoryNoLoadTest extends 
AbstractPageMemoryNoLoadSelf
         doAnswer(answer -> {
             startWriteMetaToBufferFuture.complete(null);
 
-            await(finishWaitWriteMetaToBufferFuture, 1, SECONDS);
+            assertThat(finishWaitWriteMetaToBufferFuture, 
willCompleteSuccessfully());
 
             return answer.callRealMethod();
         })
@@ -497,13 +499,15 @@ public class PersistentPageMemoryNoLoadTest extends 
AbstractPageMemoryNoLoadSelf
 
         checkpointManager.checkpointTimeoutLock().checkpointReadLock();
 
+        ByteBuffer buffer = null;
+
         try {
+            buffer = allocateBuffer(PAGE_SIZE);
+
             for (int partition = 0; partition < partitions; partition++) {
                 GroupPartitionId groupPartitionId = new 
GroupPartitionId(GRP_ID, partition);
 
-                filePageStoreManager.initialize(groupPartitionId);
-
-                FilePageStore filePageStore = 
filePageStoreManager.getStore(groupPartitionId);
+                FilePageStore filePageStore = 
filePageStoreManager.readOrCreateStore(groupPartitionId, buffer.rewind());
 
                 filePageStore.ensure();
 
@@ -512,11 +516,10 @@ public class PersistentPageMemoryNoLoadTest extends 
AbstractPageMemoryNoLoadSelf
                 PartitionMeta partitionMeta = 
partitionMetaManager.readOrCreateMeta(
                         lastCheckpointProgress == null ? null : 
lastCheckpointProgress.id(),
                         groupPartitionId,
-                        filePageStore
+                        filePageStore,
+                        buffer.rewind()
                 );
 
-                partitionMetaManager.addMeta(groupPartitionId, partitionMeta);
-
                 filePageStore.setPageAllocationListener(pageIdx -> {
                     assert 
checkpointManager.checkpointTimeoutLock().checkpointLockIsHeldByThread();
 
@@ -526,9 +529,17 @@ public class PersistentPageMemoryNoLoadTest extends 
AbstractPageMemoryNoLoadSelf
                 });
 
                 filePageStore.pages(partitionMeta.pageCount());
+
+                filePageStoreManager.addStore(groupPartitionId, filePageStore);
+                partitionMetaManager.addMeta(groupPartitionId, partitionMeta);
             }
         } finally {
-            checkpointManager.checkpointTimeoutLock().checkpointReadUnlock();
+            ByteBuffer bufferToClose = buffer;
+
+            closeAll(
+                    bufferToClose == null ? null : () -> 
freeBuffer(bufferToClose),
+                    () -> 
checkpointManager.checkpointTimeoutLock().checkpointReadUnlock()
+            );
         }
     }
 }
diff --git 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
index 0ee0eb377d..fa16fda64e 100644
--- 
a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
+++ 
b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/store/FilePageStoreManagerTest.java
@@ -28,8 +28,12 @@ import static 
org.apache.ignite.internal.pagememory.persistence.store.FilePageSt
 import static 
org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager.TMP_PART_DELTA_FILE_TEMPLATE;
 import static 
org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager.findPartitionDeltaFiles;
 import static org.apache.ignite.internal.testframework.IgniteTestUtils.runRace;
+import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
+import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
+import static org.apache.ignite.internal.util.IgniteUtils.closeAll;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
+import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.empty;
@@ -39,16 +43,22 @@ import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Iterator;
+import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 import org.apache.ignite.internal.fileio.RandomAccessFileIoFactory;
@@ -56,10 +66,12 @@ import 
org.apache.ignite.internal.lang.IgniteInternalCheckedException;
 import org.apache.ignite.internal.pagememory.persistence.GroupPartitionId;
 import 
org.apache.ignite.internal.pagememory.persistence.store.GroupPageStoresMap.GroupPartitionPageStore;
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
+import org.apache.ignite.internal.testframework.IgniteTestUtils;
 import org.apache.ignite.internal.testframework.WorkDirectory;
 import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
 import org.apache.ignite.internal.util.ArrayUtils;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.RepeatedTest;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
@@ -72,12 +84,21 @@ import org.junit.jupiter.params.provider.ValueSource;
  */
 @ExtendWith(WorkDirectoryExtension.class)
 public class FilePageStoreManagerTest extends BaseIgniteAbstractTest {
+    private static final int PAGE_SIZE = 1024;
+
     /** To be used in a loop. {@link RepeatedTest} cannot be combined with 
{@link ParameterizedTest}. */
     private static final int REPEATS = 100;
 
     @WorkDirectory
     private Path workDir;
 
+    private final Collection<FilePageStoreManager> managers = new 
ConcurrentLinkedQueue<>();
+
+    @AfterEach
+    void tearDown() throws Exception {
+        closeAll(managers.stream().filter(Objects::nonNull).map(manager -> 
manager::stop));
+    }
+
     @Test
     void testCreateManager() {
         // Checks if the manager was successfully created.
@@ -109,13 +130,14 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         IgniteInternalCheckedException exception = 
assertThrows(IgniteInternalCheckedException.class, manager::start);
 
         assertThat(exception.getMessage(), containsString("Could not create 
work directory for page stores"));
-
     }
 
     @Test
-    void testInitialize() throws Exception {
+    void testReadOrCreateStore() throws Exception {
         FilePageStoreManager manager = createManager();
 
+        ByteBuffer buffer = allocateBuffer(PAGE_SIZE);
+
         try {
             Files.createDirectories(workDir.resolve("db"));
 
@@ -125,19 +147,21 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
 
             GroupPartitionId groupPartitionId00 = new GroupPartitionId(0, 0);
 
-            IgniteInternalCheckedException exception = assertThrows(
+            IgniteTestUtils.assertThrows(
                     IgniteInternalCheckedException.class,
-                    () -> manager.initialize(groupPartitionId00)
+                    () -> manager.readOrCreateStore(groupPartitionId00, 
buffer.rewind()),
+                    "Failed to initialize group working directory"
             );
 
-            assertThat(exception.getMessage(), containsString("Failed to 
initialize group working directory"));
-
             Files.delete(testGroupDir);
 
             GroupPartitionId groupPartitionId01 = new GroupPartitionId(0, 1);
 
-            assertDoesNotThrow(() -> manager.initialize(groupPartitionId00));
-            assertDoesNotThrow(() -> manager.initialize(groupPartitionId01));
+            FilePageStore filePageStore0 = 
manager.readOrCreateStore(groupPartitionId00, buffer.rewind());
+            FilePageStore filePageStore1 = 
manager.readOrCreateStore(groupPartitionId01, buffer.rewind());
+
+            assertNull(manager.getStore(groupPartitionId00));
+            assertNull(manager.getStore(groupPartitionId01));
 
             assertTrue(Files.isDirectory(testGroupDir));
 
@@ -145,10 +169,8 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
                 assertThat(files.count(), is(0L));
             }
 
-            Iterator<GroupPartitionPageStore<FilePageStore>> iterator = 
manager.allPageStores().iterator();
-            while (iterator.hasNext()) {
-                iterator.next().pageStore().ensure();
-            }
+            filePageStore0.ensure();
+            filePageStore1.ensure();
 
             try (Stream<Path> files = Files.list(testGroupDir)) {
                 assertThat(
@@ -157,7 +179,7 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
                 );
             }
         } finally {
-            manager.stop();
+            freeBuffer(buffer);
         }
     }
 
@@ -170,7 +192,7 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         try {
             GroupPartitionId groupPartitionId00 = new GroupPartitionId(0, 0);
 
-            manager0.initialize(groupPartitionId00);
+            createAndAddFilePageStore(manager0, groupPartitionId00);
 
             manager0.getStore(groupPartitionId00).ensure();
 
@@ -194,7 +216,7 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         try {
             GroupPartitionId groupPartitionId10 = new GroupPartitionId(1, 0);
 
-            manager1.initialize(groupPartitionId10);
+            createAndAddFilePageStore(manager1, groupPartitionId10);
 
             manager1.getStore(groupPartitionId10).ensure();
 
@@ -216,8 +238,8 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         GroupPartitionId groupPartitionId10 = new GroupPartitionId(1, 0);
         GroupPartitionId groupPartitionId20 = new GroupPartitionId(2, 0);
 
-        manager.initialize(groupPartitionId10);
-        manager.initialize(groupPartitionId20);
+        createAndAddFilePageStore(manager, groupPartitionId10);
+        createAndAddFilePageStore(manager, groupPartitionId20);
 
         Path grpDir0 = workDir.resolve("db/table-1");
         Path grpDir1 = workDir.resolve("db/table-2");
@@ -247,8 +269,8 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         GroupPartitionId groupPartitionId10 = new GroupPartitionId(1, 0);
         GroupPartitionId groupPartitionId20 = new GroupPartitionId(2, 0);
 
-        manager.initialize(groupPartitionId10);
-        manager.initialize(groupPartitionId20);
+        createAndAddFilePageStore(manager, groupPartitionId10);
+        createAndAddFilePageStore(manager, groupPartitionId20);
 
         Path grpDir0 = workDir.resolve("db/table-1");
         Path grpDir1 = workDir.resolve("db/table-2");
@@ -328,8 +350,8 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
 
         manager.start();
 
-        manager.initialize(new GroupPartitionId(1, 0));
-        manager.initialize(new GroupPartitionId(2, 0));
+        createAndAddFilePageStore(manager, new GroupPartitionId(1, 0));
+        createAndAddFilePageStore(manager, new GroupPartitionId(2, 0));
 
         List<Path> allPageStoreFiles = manager.allPageStores()
                 .map(GroupPartitionPageStore::pageStore)
@@ -354,8 +376,8 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         GroupPartitionId groupPartitionId00 = new GroupPartitionId(0, 0);
         GroupPartitionId groupPartitionId10 = new GroupPartitionId(1, 0);
 
-        manager.initialize(groupPartitionId00);
-        manager.initialize(groupPartitionId10);
+        createAndAddFilePageStore(manager, groupPartitionId00);
+        createAndAddFilePageStore(manager, groupPartitionId10);
 
         FilePageStore filePageStore0 = manager.getStore(groupPartitionId00);
         FilePageStore filePageStore1 = manager.getStore(groupPartitionId10);
@@ -399,10 +421,10 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         GroupPartitionId groupPartitionId10 = new GroupPartitionId(1, 0);
         GroupPartitionId groupPartitionId11 = new GroupPartitionId(1, 1);
 
-        manager.initialize(groupPartitionId00);
-        manager.initialize(groupPartitionId01);
-        manager.initialize(groupPartitionId10);
-        manager.initialize(groupPartitionId11);
+        createAndAddFilePageStore(manager, groupPartitionId00);
+        createAndAddFilePageStore(manager, groupPartitionId01);
+        createAndAddFilePageStore(manager, groupPartitionId10);
+        createAndAddFilePageStore(manager, groupPartitionId11);
 
         FilePageStore filePageStore00 = manager.getStore(groupPartitionId00);
         FilePageStore filePageStore01 = manager.getStore(groupPartitionId01);
@@ -480,8 +502,34 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
         }
     }
 
+    @Test
+    void testAddStore() throws Exception {
+        FilePageStoreManager manager = createManager();
+
+        GroupPartitionId groupPartitionId0 = new GroupPartitionId(0, 0);
+        GroupPartitionId groupPartitionId1 = new GroupPartitionId(0, 1);
+        GroupPartitionId groupPartitionId2 = new GroupPartitionId(1, 0);
+
+        FilePageStore filePageStore = mock(FilePageStore.class);
+
+        manager.addStore(groupPartitionId0, filePageStore);
+
+        assertSame(filePageStore, manager.getStore(groupPartitionId0));
+        assertNull(manager.getStore(groupPartitionId1));
+        assertNull(manager.getStore(groupPartitionId2));
+
+        assertThat(
+                
manager.allPageStores().map(GroupPartitionPageStore::pageStore).collect(toList()),
+                contains(filePageStore)
+        );
+    }
+
     private FilePageStoreManager createManager() throws Exception {
-        return new FilePageStoreManager("test", workDir, new 
RandomAccessFileIoFactory(), 1024);
+        FilePageStoreManager manager = new FilePageStoreManager("test", 
workDir, new RandomAccessFileIoFactory(), PAGE_SIZE);
+
+        managers.add(manager);
+
+        return manager;
     }
 
     private static List<Path> collectFilesOnly(Path start) throws Exception {
@@ -519,4 +567,16 @@ public class FilePageStoreManagerTest extends 
BaseIgniteAbstractTest {
             assertTrue(IgniteUtils.deleteIfExists(tmpDeltaFile), 
tmpDeltaFile.toString());
         }
     }
+
+    private static void createAndAddFilePageStore(FilePageStoreManager 
manager, GroupPartitionId groupPartitionId) throws Exception {
+        ByteBuffer buffer = allocateBuffer(PAGE_SIZE);
+
+        try {
+            FilePageStore filePageStore = 
manager.readOrCreateStore(groupPartitionId, buffer);
+
+            manager.addStore(groupPartitionId, filePageStore);
+        } finally {
+            freeBuffer(buffer);
+        }
+    }
 }
diff --git 
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
 
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
index c39a114062..9114c245ea 100644
--- 
a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
+++ 
b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
@@ -18,7 +18,10 @@
 package org.apache.ignite.internal.storage.pagememory;
 
 import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX;
+import static org.apache.ignite.internal.util.GridUnsafe.allocateBuffer;
+import static org.apache.ignite.internal.util.GridUnsafe.freeBuffer;
 
+import java.nio.ByteBuffer;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicLong;
@@ -132,41 +135,6 @@ public class PersistentPageMemoryTableStorage extends 
AbstractPageMemoryTableSto
         });
     }
 
-    /**
-     * Initializes the partition file page store if it hasn't already.
-     *
-     * @param groupPartitionId Pair of group ID with partition ID.
-     * @return Partition file page store.
-     * @throws StorageException If failed.
-     */
-    private FilePageStore ensurePartitionFilePageStoreExists(GroupPartitionId 
groupPartitionId) throws StorageException {
-        try {
-            dataRegion.filePageStoreManager().initialize(groupPartitionId);
-
-            FilePageStore filePageStore = 
dataRegion.filePageStoreManager().getStore(groupPartitionId);
-
-            assert !filePageStore.isMarkedToDestroy() : 
IgniteStringFormatter.format(
-                    "Should not be marked for deletion: [tableId={}, 
partitionId={}]",
-                    groupPartitionId.getGroupId(),
-                    groupPartitionId.getPartitionId()
-            );
-
-            filePageStore.ensure();
-
-            if (filePageStore.deltaFileCount() > 0) {
-                dataRegion.checkpointManager().triggerCompaction();
-            }
-
-            return filePageStore;
-        } catch (IgniteInternalCheckedException e) {
-            throw new StorageException(
-                    "Error initializing file page store: [tableId={}, 
partitionId={}]",
-                    e,
-                    groupPartitionId.getGroupId(), 
groupPartitionId.getPartitionId()
-            );
-        }
-    }
-
     /**
      * Returns id of the last started checkpoint, or {@code null} if no 
checkpoints were started yet.
      */
@@ -458,47 +426,90 @@ public class PersistentPageMemoryTableStorage extends 
AbstractPageMemoryTableSto
     }
 
     /**
-     * Creates or gets partition meta from a file.
+     * Creates or receives partition meta from a file.
      *
-     * <p>Safe to use without a checkpointReadLock as we read the meta 
directly without using {@link PageMemory}.
+     * <p>Safe to use without a checkpointReadLock as we read the meta 
directly without using {@link PageMemory}.</p>
      *
      * @param groupPartitionId Partition of the group.
-     * @param filePageStore Partition file page store.
      */
-    private PartitionMeta getOrCreatePartitionMeta(GroupPartitionId 
groupPartitionId, FilePageStore filePageStore) {
+    private PartitionMeta 
getOrCreatePartitionMetaOnCreatePartition(GroupPartitionId groupPartitionId) {
+        ByteBuffer buffer = allocateBuffer(dataRegion.pageMemory().pageSize());
+
         try {
-            PartitionMeta meta = 
dataRegion.partitionMetaManager().readOrCreateMeta(lastCheckpointId(), 
groupPartitionId, filePageStore);
+            FilePageStore filePageStore = 
dataRegion.filePageStoreManager().getStore(groupPartitionId);
+
+            // TODO: IGNITE-20983 This shouldn't happen, we should read the 
page store and its meta again
+            if (filePageStore != null) {
+                PartitionMeta partitionMeta = 
dataRegion.partitionMetaManager().getMeta(groupPartitionId);
+
+                assert partitionMeta != null : groupPartitionId;
 
-            dataRegion.partitionMetaManager().addMeta(groupPartitionId, meta);
+                return partitionMeta;
+            }
+
+            filePageStore = readOrCreateAndInitFilePageStore(groupPartitionId, 
buffer);
+
+            PartitionMeta partitionMeta = 
readOrCreatePartitionMeta(groupPartitionId, filePageStore, buffer.rewind());
 
-            filePageStore.pages(meta.pageCount());
+            filePageStore.pages(partitionMeta.pageCount());
 
             filePageStore.setPageAllocationListener(pageIdx -> {
                 assert 
dataRegion.checkpointManager().checkpointTimeoutLock().checkpointLockIsHeldByThread();
 
-                meta.incrementPageCount(lastCheckpointId());
+                partitionMeta.incrementPageCount(lastCheckpointId());
             });
 
-            return meta;
+            dataRegion.filePageStoreManager().addStore(groupPartitionId, 
filePageStore);
+            dataRegion.partitionMetaManager().addMeta(groupPartitionId, 
partitionMeta);
+
+            if (filePageStore.deltaFileCount() > 0) {
+                dataRegion.checkpointManager().triggerCompaction();
+            }
+
+            return partitionMeta;
+        } finally {
+            freeBuffer(buffer);
+        }
+    }
+
+    private FilePageStore readOrCreateAndInitFilePageStore(
+            GroupPartitionId groupPartitionId,
+            ByteBuffer buffer
+    ) throws StorageException {
+        try {
+            FilePageStore filePageStore = 
dataRegion.filePageStoreManager().readOrCreateStore(groupPartitionId, buffer);
+
+            assert !filePageStore.isMarkedToDestroy() : 
IgniteStringFormatter.format(
+                    "Should not be marked for deletion: [tableId={}, 
partitionId={}]",
+                    groupPartitionId.getGroupId(),
+                    groupPartitionId.getPartitionId()
+            );
+
+            filePageStore.ensure();
+
+            return filePageStore;
         } catch (IgniteInternalCheckedException e) {
             throw new StorageException(
-                    "Error reading or creating partition meta information: 
[tableId={}, partitionId={}]",
+                    "Error read and initializing file page store: [tableId={}, 
partitionId={}]",
                     e,
-                    getTableId(), groupPartitionId.getPartitionId()
+                    groupPartitionId.getGroupId(), 
groupPartitionId.getPartitionId()
             );
         }
     }
 
-    /**
-     * Creates or receives partition meta from a file.
-     *
-     * <p>Safe to use without a checkpointReadLock as we read the meta 
directly without using {@link PageMemory}.
-     *
-     * @param groupPartitionId Partition of the group.
-     */
-    private PartitionMeta 
getOrCreatePartitionMetaOnCreatePartition(GroupPartitionId groupPartitionId) {
-        FilePageStore filePageStore = 
ensurePartitionFilePageStoreExists(groupPartitionId);
-
-        return getOrCreatePartitionMeta(groupPartitionId, filePageStore);
+    private PartitionMeta readOrCreatePartitionMeta(
+            GroupPartitionId groupPartitionId,
+            FilePageStore filePageStore,
+            ByteBuffer buffer
+    ) throws StorageException {
+        try {
+            return 
dataRegion.partitionMetaManager().readOrCreateMeta(lastCheckpointId(), 
groupPartitionId, filePageStore, buffer);
+        } catch (IgniteInternalCheckedException e) {
+            throw new StorageException(
+                    "Error reading or creating partition meta information: 
[tableId={}, partitionId={}]",
+                    e,
+                    getTableId(), groupPartitionId.getPartitionId()
+            );
+        }
     }
 }


Reply via email to