This is an automated email from the ASF dual-hosted git repository. sdanilov 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 706968b82 IGNITE-16641 [Native Persistence 3.0] Support persistent B+Tree-based storage (#845) 706968b82 is described below commit 706968b8271968b69cfdbd360c1cea9bca906170 Author: Kirill Tkalenko <tkalkir...@yandex.ru> AuthorDate: Mon Jun 6 12:19:12 2022 +0300 IGNITE-16641 [Native Persistence 3.0] Support persistent B+Tree-based storage (#845) --- .../apache/ignite/internal/util/ArrayUtils.java | 19 ++ .../ignite/internal/util/ArrayUtilsSelfTest.java | 15 ++ .../persistence/ItBplusTreePageMemoryImplTest.java | 7 +- .../ItBplusTreeReuseListPageMemoryImplTest.java | 7 +- .../ignite/internal/pagememory/io/PageIo.java | 1 + .../pagememory/mem/DirectMemoryProvider.java | 2 + .../pagememory/mem/DirectMemoryRegion.java | 6 +- .../mem/unsafe/UnsafeMemoryProvider.java | 3 +- .../pagememory/persistence/PageMemoryImpl.java | 21 +- .../persistence/checkpoint/CheckpointManager.java | 4 +- .../persistence/checkpoint/CheckpointWorkflow.java | 8 +- .../persistence/PageMemoryImplNoLoadTest.java | 24 +- .../runner/app/ItIgniteNodeRestartTest.java | 4 +- .../org/apache/ignite/internal/app/IgniteImpl.java | 8 +- .../sql/engine/exec/MockedStructuresTest.java | 2 +- .../ignite/internal/storage/DataStorageModule.java | 11 +- .../internal/storage/DataStorageModules.java | 10 +- .../storage/AbstractPartitionStorageTest.java | 6 +- .../internal/storage/DataStorageManagerTest.java | 12 +- .../internal/storage/DataStorageModulesTest.java | 9 +- .../TestConcurrentHashMapDataStorageModule.java | 9 +- .../pagememory/AbstractPageMemoryDataRegion.java | 1 - ...ge.java => AbstractPageMemoryTableStorage.java} | 9 +- .../pagememory/PageMemoryDataStorageModule.java | 11 +- .../pagememory/PageMemoryStorageEngine.java | 119 +++++++++- .../pagememory/PageMemoryStorageIoModule.java | 4 +- ...eMemoryTableStorage.java => PartitionMeta.java} | 37 +-- .../pagememory/PersistentPageMemoryDataRegion.java | 142 +++++++++++ .../PersistentPageMemoryPartitionStorage.java | 152 ++++++++++++ .../PersistentPageMemoryTableStorage.java | 262 +++++++++++++++++++++ .../pagememory/VolatilePageMemoryDataRegion.java | 2 +- ...ava => VolatilePageMemoryPartitionStorage.java} | 48 +--- .../pagememory/VolatilePageMemoryTableStorage.java | 58 ++++- ...PageMemoryStorageEngineConfigurationSchema.java | 5 + .../storage/pagememory/io/PartitionMetaIo.java | 110 +++++++++ .../storage/pagememory/mv/io/RowVersionDataIo.java | 2 +- .../pagememory/mv/io/VersionChainDataIo.java | 2 +- .../pagememory/mv/io/VersionChainInnerIo.java | 2 +- .../pagememory/mv/io/VersionChainLeafIo.java | 2 +- .../pagememory/mv/io/VersionChainMetaIo.java | 2 +- .../PersistentPageMemoryDataRegionTest.java | 88 +++++++ ... PersistentPageMemoryPartitionStorageTest.java} | 68 +++--- ...=> VolatilePageMemoryPartitionStorageTest.java} | 19 +- .../mv/PageMemoryMvPartitionStorageTest.java | 11 +- .../storage/rocksdb/RocksDbDataStorageModule.java | 9 +- .../ignite/internal/table/TableManagerTest.java | 2 +- 46 files changed, 1176 insertions(+), 179 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/ArrayUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/ArrayUtils.java index b9a1f2fda..60b5067d2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/ArrayUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/ArrayUtils.java @@ -315,6 +315,25 @@ public final class ArrayUtils { return newArr; } + /** + * Concatenates an elements to an array. + * + * @param arr Array. + * @param longs One or more elements. + * @return Concatenated array. + */ + public static long[] concat(@Nullable long[] arr, long... longs) { + if (nullOrEmpty(arr)) { + return longs; + } + + long[] newArr = Arrays.copyOf(arr, arr.length + longs.length); + + System.arraycopy(longs, 0, newArr, arr.length, longs.length); + + return newArr; + } + /** * Removes an element from an array with decrementing the array itself. * diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/ArrayUtilsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/ArrayUtilsSelfTest.java index ac8bb26ba..a81d84cd1 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/util/ArrayUtilsSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/util/ArrayUtilsSelfTest.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.util; import static org.apache.ignite.internal.util.ArrayUtils.clearTail; +import static org.apache.ignite.internal.util.ArrayUtils.concat; import static org.apache.ignite.internal.util.ArrayUtils.remove; import static org.apache.ignite.internal.util.ArrayUtils.set; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -134,4 +135,18 @@ public class ArrayUtilsSelfTest { assertEquals("zz", arr[i]); } } + + @Test + void testConcatLong() { + long[] arr = {}; + + assertSame(arr, concat(null, arr)); + assertSame(arr, concat(new long[0], arr)); + + assertArrayEquals(new long[]{0}, concat(arr, 0)); + assertArrayEquals(new long[]{0, 1}, concat(arr, 0, 1)); + assertArrayEquals(new long[]{1, 2}, concat(new long[]{1}, 2)); + assertArrayEquals(new long[]{1, 2, 3}, concat(new long[]{1, 2}, 3)); + assertArrayEquals(new long[]{1, 2, 3, 4}, concat(new long[]{1, 2}, 3, 4)); + } } diff --git a/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreePageMemoryImplTest.java b/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreePageMemoryImplTest.java index 88163cd51..d04703330 100644 --- a/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreePageMemoryImplTest.java +++ b/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreePageMemoryImplTest.java @@ -36,10 +36,6 @@ public class ItBplusTreePageMemoryImplTest extends ItBplusTreeSelfTest { protected PageMemory createPageMemory() throws Exception { dataRegionCfg.change(c -> c.changeInitSize(MAX_MEMORY_SIZE).changeMaxSize(MAX_MEMORY_SIZE)).get(1, TimeUnit.SECONDS); - long[] sizes = LongStream.range(0, CPUS + 1).map(i -> MAX_MEMORY_SIZE / CPUS).toArray(); - - sizes[CPUS] = 10 * MiB; - TestPageIoRegistry ioRegistry = new TestPageIoRegistry(); ioRegistry.loadFromServiceLoader(); @@ -47,7 +43,8 @@ public class ItBplusTreePageMemoryImplTest extends ItBplusTreeSelfTest { return new PageMemoryImpl( dataRegionCfg, ioRegistry, - sizes, + LongStream.range(0, CPUS).map(i -> MAX_MEMORY_SIZE / CPUS).toArray(), + 10 * MiB, new TestPageReadWriteManager(), (page, fullPageId, pageMemoryImpl) -> { }, diff --git a/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreeReuseListPageMemoryImplTest.java b/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreeReuseListPageMemoryImplTest.java index bb428a90d..0951b875c 100644 --- a/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreeReuseListPageMemoryImplTest.java +++ b/modules/page-memory/src/integrationTest/java/org/apache/ignite/internal/pagememory/persistence/ItBplusTreeReuseListPageMemoryImplTest.java @@ -35,10 +35,6 @@ public class ItBplusTreeReuseListPageMemoryImplTest extends ItBplusTreeReuseSelf protected PageMemory createPageMemory() throws Exception { dataRegionCfg.change(c -> c.changeInitSize(MAX_MEMORY_SIZE).changeMaxSize(MAX_MEMORY_SIZE)).get(1, TimeUnit.SECONDS); - long[] sizes = LongStream.range(0, CPUS + 1).map(i -> MAX_MEMORY_SIZE / CPUS).toArray(); - - sizes[CPUS] = 10 * MiB; - TestPageIoRegistry ioRegistry = new TestPageIoRegistry(); ioRegistry.loadFromServiceLoader(); @@ -46,7 +42,8 @@ public class ItBplusTreeReuseListPageMemoryImplTest extends ItBplusTreeReuseSelf return new PageMemoryImpl( dataRegionCfg, ioRegistry, - sizes, + LongStream.range(0, CPUS).map(i -> MAX_MEMORY_SIZE / CPUS).toArray(), + 10 * MiB, new TestPageReadWriteManager(), (page, fullPageId, pageMemoryImpl) -> { }, diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/PageIo.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/PageIo.java index 631c2d2d3..0e7879039 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/PageIo.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/io/PageIo.java @@ -104,6 +104,7 @@ public abstract class PageIo { private final int ver; /** IO type. */ + // TODO: IGNITE-17104 Consider the mechanism for avoiding type intersection for different structures private final int type; /** IO flag: either {@link PageIdAllocator#FLAG_DATA} or {@link PageIdAllocator#FLAG_AUX}. */ diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryProvider.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryProvider.java index b7534981e..2926b1c50 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryProvider.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryProvider.java @@ -28,6 +28,7 @@ public interface DirectMemoryProvider { * * @param chunkSizes Chunk sizes. */ + // TODO: IGNITE-16350 Consider deleting a method void initialize(long[] chunkSizes); /** @@ -43,5 +44,6 @@ public interface DirectMemoryProvider { * @return Next memory region. */ @Nullable + // TODO: IGNITE-16350 Consider adding a region size argument DirectMemoryRegion nextRegion(); } diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryRegion.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryRegion.java index 1070c9645..f5678589b 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryRegion.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/DirectMemoryRegion.java @@ -24,12 +24,12 @@ public interface DirectMemoryRegion { /** * Returns a region start address. */ - public long address(); + long address(); /** * Returns a region size. */ - public long size(); + long size(); /** * Creates a sub-region of this region starting from the given offset. @@ -37,5 +37,5 @@ public interface DirectMemoryRegion { * @param offset Offset within this region. * @return Sub-region. */ - public DirectMemoryRegion slice(long offset); + DirectMemoryRegion slice(long offset); } diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/unsafe/UnsafeMemoryProvider.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/unsafe/UnsafeMemoryProvider.java index 1b231857b..31c7a30d5 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/unsafe/UnsafeMemoryProvider.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/mem/unsafe/UnsafeMemoryProvider.java @@ -95,7 +95,8 @@ public class UnsafeMemoryProvider implements DirectMemoryProvider { } /** {@inheritDoc} */ - @Override public DirectMemoryRegion nextRegion() { + @Override + public @Nullable DirectMemoryRegion nextRegion() { if (used == sizes.length) { return null; } diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImpl.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImpl.java index 7569db9f0..c40706af2 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImpl.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImpl.java @@ -39,6 +39,7 @@ import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageId; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.pageIndex; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.partitionId; import static org.apache.ignite.internal.pagememory.util.PageIdUtils.tag; +import static org.apache.ignite.internal.util.ArrayUtils.concat; import static org.apache.ignite.internal.util.FastTimestamps.coarseCurrentTimeMillis; import static org.apache.ignite.internal.util.GridUnsafe.BYTE_ARR_OFF; import static org.apache.ignite.internal.util.GridUnsafe.bufferAddress; @@ -191,6 +192,7 @@ public class PageMemoryImpl implements PageMemory { private volatile int pageReplacementWarned; /** Segments sizes, the last one being the {@link #checkpointPool checkpoint buffer} size. */ + // TODO: IGNITE-16350 Consider splitting into segments and the checkpoint buffer private final long[] sizes; /** {@code False} if memory was not started or already stopped and is not supposed for any usage. */ @@ -221,7 +223,8 @@ public class PageMemoryImpl implements PageMemory { * * @param dataRegionConfig Data region configuration. * @param ioRegistry IO registry. - * @param sizes Segments sizes, the last one being the checkpoint buffer size. + * @param segmentSizes Segments sizes in bytes. + * @param checkpointBufferSize Checkpoint buffer size in bytes. * @param pageStoreManager Page store manager. * @param changeTracker Callback invoked to track changes in pages. * @param flushDirtyPage Write callback invoked when a dirty page is removed for replacement. @@ -231,7 +234,8 @@ public class PageMemoryImpl implements PageMemory { public PageMemoryImpl( PageMemoryDataRegionConfiguration dataRegionConfig, PageIoRegistry ioRegistry, - long[] sizes, + long[] segmentSizes, + long checkpointBufferSize, PageReadWriteManager pageStoreManager, @Nullable PageChangeTracker changeTracker, PageStoreWriter flushDirtyPage, @@ -241,7 +245,7 @@ public class PageMemoryImpl implements PageMemory { ) { this.dataRegionConfigView = dataRegionConfig.value(); this.ioRegistry = ioRegistry; - this.sizes = sizes; + this.sizes = concat(segmentSizes, checkpointBufferSize); this.pageStoreManager = pageStoreManager; this.changeTracker = changeTracker; this.flushDirtyPage = flushDirtyPage; @@ -308,11 +312,11 @@ public class PageMemoryImpl implements PageMemory { Segment[] segments = new Segment[regs - 1]; - DirectMemoryRegion cpReg = regions.get(regs - 1); + DirectMemoryRegion checkpointRegion = regions.get(regs - 1); - checkpointPool = new PagePool(regs - 1, cpReg, sysPageSize, rwLock); + checkpointPool = new PagePool(regs - 1, checkpointRegion, sysPageSize, rwLock); - long checkpointBuf = cpReg.size(); + long checkpointBufferSize = checkpointRegion.size(); long totalAllocated = 0; int pages = 0; @@ -340,7 +344,7 @@ public class PageMemoryImpl implements PageMemory { + ", pages=" + pages + ", tableSize=" + readableSize(totalTblSize, false) + ", replacementSize=" + readableSize(totalReplSize, false) - + ", checkpointBuffer=" + readableSize(checkpointBuf, false) + + ", checkpointBuffer=" + readableSize(checkpointBufferSize, false) + ']'); } } @@ -611,8 +615,7 @@ public class PageMemoryImpl implements PageMemory { public long partitionMetaPageId(int grpId, int partId) { assert started; - //TODO IGNITE-16350 Consider reworking in FLAG_AUX. - return pageId(partId, FLAG_DATA, 0); + return pageId(partId, FLAG_AUX, 0); } /** {@inheritDoc} */ diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointManager.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointManager.java index 2a8dd9ece..7e4a4896f 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointManager.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointManager.java @@ -85,7 +85,7 @@ public class CheckpointManager implements IgniteComponent { @Nullable LongJvmPauseDetector longJvmPauseDetector, PageMemoryCheckpointConfiguration checkpointConfig, FilePageStoreManager filePageStoreManager, - Collection<PageMemoryDataRegion> dataRegions, + Collection<? extends PageMemoryDataRegion> dataRegions, Path storagePath, // TODO: IGNITE-17017 Move to common config int pageSize @@ -196,7 +196,7 @@ public class CheckpointManager implements IgniteComponent { * @param dataRegions Data regions. * @see PageMemoryImpl#safeToUpdate() */ - static boolean safeToUpdateAllPageMemories(Collection<PageMemoryDataRegion> dataRegions) { + static boolean safeToUpdateAllPageMemories(Collection<? extends PageMemoryDataRegion> dataRegions) { for (PageMemoryDataRegion dataRegion : dataRegions) { if (dataRegion.persistent() && !((PageMemoryImpl) dataRegion.pageMemory()).safeToUpdate()) { return false; diff --git a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointWorkflow.java b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointWorkflow.java index 88d788e59..8b064a774 100644 --- a/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointWorkflow.java +++ b/modules/page-memory/src/main/java/org/apache/ignite/internal/pagememory/persistence/checkpoint/CheckpointWorkflow.java @@ -80,7 +80,7 @@ class CheckpointWorkflow implements IgniteComponent { private final CheckpointReadWriteLock checkpointReadWriteLock; /** Persistent data regions for the checkpointing. */ - private final Collection<PageMemoryDataRegion> dataRegions; + private final Collection<? extends PageMemoryDataRegion> dataRegions; /** Checkpoint write order configuration. */ private final CheckpointWriteOrder checkpointWriteOrder; @@ -100,7 +100,7 @@ class CheckpointWorkflow implements IgniteComponent { PageMemoryCheckpointConfiguration checkpointConfig, CheckpointMarkersStorage checkpointMarkersStorage, CheckpointReadWriteLock checkpointReadWriteLock, - Collection<PageMemoryDataRegion> dataRegions + Collection<? extends PageMemoryDataRegion> dataRegions ) { PageMemoryCheckpointView checkpointConfigView = checkpointConfig.value(); @@ -260,7 +260,7 @@ class CheckpointWorkflow implements IgniteComponent { * * @param dataRegions Data regions. */ - public List<CheckpointListener> collectCheckpointListeners(Collection<PageMemoryDataRegion> dataRegions) { + public List<CheckpointListener> collectCheckpointListeners(Collection<? extends PageMemoryDataRegion> dataRegions) { return listeners.stream() .filter(tuple -> tuple.getValue() == null || dataRegions.contains(tuple.getValue())) .map(IgniteBiTuple::getKey) @@ -268,7 +268,7 @@ class CheckpointWorkflow implements IgniteComponent { } private CheckpointDirtyPagesInfoHolder beginCheckpoint( - Collection<PageMemoryDataRegion> dataRegions, + Collection<? extends PageMemoryDataRegion> dataRegions, CompletableFuture<?> allowToReplace ) { Collection<IgniteBiTuple<PageMemoryImpl, Collection<FullPageId>>> pages = new ArrayList<>(dataRegions.size()); diff --git a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImplNoLoadTest.java b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImplNoLoadTest.java index a244f14e1..09fba505f 100644 --- a/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImplNoLoadTest.java +++ b/modules/page-memory/src/test/java/org/apache/ignite/internal/pagememory/persistence/PageMemoryImplNoLoadTest.java @@ -69,7 +69,7 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { /** {@inheritDoc} */ @Override protected PageMemory memory() { - return createPageMemoryImpl(defaultSegmentSizes(), null, null); + return createPageMemoryImpl(defaultSegmentSizes(), defaultCheckpointBufferSize(), null, null); } /** {@inheritDoc} */ @@ -90,7 +90,12 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { CheckpointManager checkpointManager = createCheckpointManager(checkpointConfig, workDir, filePageStoreManager, dataRegions); - PageMemoryImpl pageMemoryImpl = createPageMemoryImpl(defaultSegmentSizes(), filePageStoreManager, checkpointManager); + PageMemoryImpl pageMemoryImpl = createPageMemoryImpl( + defaultSegmentSizes(), + defaultCheckpointBufferSize(), + filePageStoreManager, + checkpointManager + ); dataRegions.add(newDataRegion(true, pageMemoryImpl)); @@ -144,7 +149,8 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { dataRegionCfg.change(c -> c.changeInitSize(128 * systemPageSize).changeMaxSize(128 * systemPageSize)).get(1, SECONDS); PageMemoryImpl pageMemoryImpl = createPageMemoryImpl( - new long[]{100 * systemPageSize, 28 * systemPageSize}, + new long[]{100 * systemPageSize}, + 28 * systemPageSize, filePageStoreManager, checkpointManager ); @@ -200,7 +206,8 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { } protected PageMemoryImpl createPageMemoryImpl( - long[] sizes, + long[] segmentSizes, + long checkpointBufferSize, @Nullable FilePageStoreManager filePageStoreManager, @Nullable CheckpointManager checkpointManager ) { @@ -211,7 +218,8 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { return new PageMemoryImpl( dataRegionCfg, ioRegistry, - sizes, + segmentSizes, + checkpointBufferSize, filePageStoreManager == null ? new TestPageReadWriteManager() : filePageStoreManager, null, (fullPageId, buf, tag) -> fail("Should not happen"), @@ -235,7 +243,11 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest { } private static long[] defaultSegmentSizes() { - return LongStream.range(0, 10).map(i -> 5 * MiB).toArray(); + return LongStream.range(0, 9).map(i -> 5 * MiB).toArray(); + } + + private static long defaultCheckpointBufferSize() { + return 5 * MiB; } private static CheckpointManager createCheckpointManager( diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java index 3e90e4979..8f15f4fd0 100644 --- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java +++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItIgniteNodeRestartTest.java @@ -259,8 +259,10 @@ public class ItIgniteNodeRestartTest extends IgniteAbstractTest { DataStorageManager dataStorageManager = new DataStorageManager( clusterCfgMgr.configurationRegistry().getConfiguration(TablesConfiguration.KEY), dataStorageModules.createStorageEngines( + name, clusterCfgMgr.configurationRegistry(), - getPartitionsStorePath(dir) + getPartitionsStorePath(dir), + null ) ); diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java index 354f22191..04b33842f 100644 --- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java +++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java @@ -205,6 +205,8 @@ public class IgniteImpl implements Ignite { IgniteImpl(String name, Path workDir, @Nullable ClassLoader serviceProviderClassLoader) { this.name = name; + longJvmPauseDetector = new LongJvmPauseDetector(name); + lifecycleManager = new LifecycleManager(name); vaultMgr = createVault(workDir); @@ -295,8 +297,10 @@ public class IgniteImpl implements Ignite { dataStorageMgr = new DataStorageManager( clusterCfgMgr.configurationRegistry().getConfiguration(TablesConfiguration.KEY), dataStorageModules.createStorageEngines( + name, clusterCfgMgr.configurationRegistry(), - getPartitionsStorePath(workDir) + getPartitionsStorePath(workDir), + longJvmPauseDetector ) ); @@ -338,8 +342,6 @@ public class IgniteImpl implements Ignite { nettyBootstrapFactory, sql ); - - longJvmPauseDetector = new LongJvmPauseDetector(name); } private static ConfigurationModules loadConfigurationModules(ClassLoader classLoader) { diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java index 765c39cc5..79195cf84 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java @@ -226,7 +226,7 @@ public class MockedStructuresTest extends IgniteAbstractTest { dataStorageManager = new DataStorageManager( tblsCfg, - dataStorageModules.createStorageEngines(configRegistry, workDir) + dataStorageModules.createStorageEngines(NODE_NAME, configRegistry, workDir, null) ); dataStorageManager.start(); diff --git a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModule.java b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModule.java index a323f8e0a..0025b8e21 100644 --- a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModule.java +++ b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModule.java @@ -19,8 +19,10 @@ package org.apache.ignite.internal.storage; import java.nio.file.Path; import org.apache.ignite.configuration.schemas.store.DataStorageConfigurationSchema; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.ConfigurationRegistry; import org.apache.ignite.internal.storage.engine.StorageEngine; +import org.jetbrains.annotations.Nullable; /** * Data storage module. @@ -36,9 +38,16 @@ public interface DataStorageModule { /** * Creates a new storage engine. * + * @param igniteInstanceName String igniteInstanceName * @param configRegistry Configuration register. * @param storagePath Storage path. + * @param longJvmPauseDetector Long JVM pause detector. * @throws StorageException If there is an error when creating the storage engine. */ - StorageEngine createEngine(ConfigurationRegistry configRegistry, Path storagePath) throws StorageException; + StorageEngine createEngine( + String igniteInstanceName, + ConfigurationRegistry configRegistry, + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector + ) throws StorageException; } diff --git a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModules.java b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModules.java index da6238199..00db64e3a 100644 --- a/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModules.java +++ b/modules/storage-api/src/main/java/org/apache/ignite/internal/storage/DataStorageModules.java @@ -34,8 +34,10 @@ import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance; import org.apache.ignite.configuration.annotation.Value; import org.apache.ignite.configuration.schemas.store.DataStorageConfigurationSchema; import org.apache.ignite.configuration.schemas.store.UnknownDataStorageConfigurationSchema; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.ConfigurationRegistry; import org.apache.ignite.internal.storage.engine.StorageEngine; +import org.jetbrains.annotations.Nullable; /** * Auxiliary class for working with {@link DataStorageModule}. @@ -86,17 +88,21 @@ public class DataStorageModules { /** * Creates new storage engines unique by {@link DataStorageModule#name name}. * + * @param igniteInstanceName String igniteInstanceName * @param configRegistry Configuration register. * @param storagePath Storage path. + * @param longJvmPauseDetector Long JVM pause detector. * @throws StorageException If there is an error when creating the storage engines. */ public Map<String, StorageEngine> createStorageEngines( + String igniteInstanceName, ConfigurationRegistry configRegistry, - Path storagePath + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector ) { return modules.entrySet().stream().collect(toUnmodifiableMap( Entry::getKey, - e -> e.getValue().createEngine(configRegistry, storagePath) + e -> e.getValue().createEngine(igniteInstanceName, configRegistry, storagePath, longJvmPauseDetector) )); } diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractPartitionStorageTest.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractPartitionStorageTest.java index be90ef4a2..990832cfa 100644 --- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractPartitionStorageTest.java +++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/AbstractPartitionStorageTest.java @@ -63,10 +63,10 @@ import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(WorkDirectoryExtension.class) public abstract class AbstractPartitionStorageTest { /** Test key. */ - private static final String KEY = "key"; + protected static final String KEY = "key"; /** Test value. */ - private static final String VALUE = "value"; + protected static final String VALUE = "value"; /** Storage instance. */ protected PartitionStorage storage; @@ -644,7 +644,7 @@ public abstract class AbstractPartitionStorageTest { * * @param row Expected data row. */ - private void checkHasSameEntry(DataRow row) { + protected void checkHasSameEntry(DataRow row) { DataRow read = storage.read(row); assertNotNull(read); diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageManagerTest.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageManagerTest.java index 873059e96..d21981f5c 100644 --- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageManagerTest.java +++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageManagerTest.java @@ -84,7 +84,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); // Checks that the current default is "pagememory" even if we have one engine and it's not "pagememory". @@ -100,7 +100,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); assertThat("pagememory", equalTo(dataStorageManager.defaultDataStorage())); @@ -124,7 +124,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); // Check random polymorphicTypeId. @@ -167,7 +167,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); DataStorageView dataStorageView = dataStorageConfig.value(); @@ -203,7 +203,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); dataStorageConfig.change(dataStorageManager.defaultTableDataStorageConsumer(FIRST)).get(1, TimeUnit.SECONDS); @@ -224,7 +224,7 @@ public class DataStorageManagerTest { DataStorageManager dataStorageManager = new DataStorageManager( tablesConfig, - dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir) + dataStorageModules.createStorageEngines("test", mock(ConfigurationRegistry.class), workDir, null) ); dataStorageConfig.change(dataStorageManager.defaultTableDataStorageConsumer(FIRST)).get(1, TimeUnit.SECONDS); diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageModulesTest.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageModulesTest.java index 234cf857f..a1f45941b 100644 --- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageModulesTest.java +++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/DataStorageModulesTest.java @@ -114,7 +114,12 @@ public class DataStorageModulesTest { createMockedDataStorageModule(SECOND) )); - Map<String, StorageEngine> engines = dataStorageModules.createStorageEngines(mock(ConfigurationRegistry.class), workDir); + Map<String, StorageEngine> engines = dataStorageModules.createStorageEngines( + "test", + mock(ConfigurationRegistry.class), + workDir, + null + ); assertThat(engines, aMapWithSize(2)); @@ -208,7 +213,7 @@ public class DataStorageModulesTest { when(mock.name()).thenReturn(name); - when(mock.createEngine(any(), any())).thenReturn(mock(StorageEngine.class)); + when(mock.createEngine(any(), any(), any(), any())).thenReturn(mock(StorageEngine.class)); return mock; } diff --git a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapDataStorageModule.java b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapDataStorageModule.java index abe6b01fd..ef52bd654 100644 --- a/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapDataStorageModule.java +++ b/modules/storage-api/src/test/java/org/apache/ignite/internal/storage/chm/TestConcurrentHashMapDataStorageModule.java @@ -20,10 +20,12 @@ package org.apache.ignite.internal.storage.chm; import static org.apache.ignite.internal.storage.chm.TestConcurrentHashMapStorageEngine.ENGINE_NAME; import java.nio.file.Path; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.ConfigurationRegistry; import org.apache.ignite.internal.storage.DataStorageModule; import org.apache.ignite.internal.storage.StorageException; import org.apache.ignite.internal.storage.engine.StorageEngine; +import org.jetbrains.annotations.Nullable; /** * Implementation for creating {@link TestConcurrentHashMapStorageEngine}s. @@ -37,7 +39,12 @@ public class TestConcurrentHashMapDataStorageModule implements DataStorageModule /** {@inheritDoc} */ @Override - public StorageEngine createEngine(ConfigurationRegistry configRegistry, Path storagePath) throws StorageException { + public StorageEngine createEngine( + String igniteInstanceName, + ConfigurationRegistry configRegistry, + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector + ) throws StorageException { return new TestConcurrentHashMapStorageEngine(); } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryDataRegion.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryDataRegion.java index 4e5863076..5d62ec794 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryDataRegion.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryDataRegion.java @@ -27,7 +27,6 @@ import org.apache.ignite.internal.pagememory.io.PageIoRegistry; /** * Abstract data region for {@link PageMemoryStorageEngine}. Based on a {@link PageMemory}. */ -// TODO: IGNITE-16641 Add support for persistent case. abstract class AbstractPageMemoryDataRegion implements PageMemoryDataRegion, IgniteComponent { protected final PageMemoryDataRegionConfiguration cfg; diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryTableStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java similarity index 93% rename from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryTableStorage.java rename to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java index 80d1489da..62d688126 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryTableStorage.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java @@ -38,9 +38,8 @@ import org.jetbrains.annotations.TestOnly; /** * Abstract table storage implementation based on {@link PageMemory}. */ -// TODO: IGNITE-16641 Add support for persistent case. // TODO: IGNITE-16642 Support indexes. -public abstract class PageMemoryTableStorage implements TableStorage { +public abstract class AbstractPageMemoryTableStorage implements TableStorage { protected final AbstractPageMemoryDataRegion dataRegion; protected final TableConfiguration tableCfg; @@ -58,7 +57,7 @@ public abstract class PageMemoryTableStorage implements TableStorage { * @param tableCfg – Table configuration. * @param dataRegion – Data region for the table. */ - public PageMemoryTableStorage(TableConfiguration tableCfg, AbstractPageMemoryDataRegion dataRegion) { + public AbstractPageMemoryTableStorage(TableConfiguration tableCfg, AbstractPageMemoryDataRegion dataRegion) { this.dataRegion = dataRegion; this.tableCfg = tableCfg; } @@ -174,12 +173,12 @@ public abstract class PageMemoryTableStorage implements TableStorage { } /** - * Returns a new instance of {@link PageMemoryPartitionStorage}. + * Returns a new instance of {@link VolatilePageMemoryPartitionStorage}. * * @param partId Partition id. * @throws StorageException If there is an error while creating the partition storage. */ - protected abstract PageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException; + protected abstract VolatilePageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException; /** * This API is not yet ready. But we need to test mv storages anyways. diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryDataStorageModule.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryDataStorageModule.java index b6699dbaa..f5ff3afe8 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryDataStorageModule.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryDataStorageModule.java @@ -20,12 +20,14 @@ package org.apache.ignite.internal.storage.pagememory; import static org.apache.ignite.internal.storage.pagememory.PageMemoryStorageEngine.ENGINE_NAME; import java.nio.file.Path; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.ConfigurationRegistry; import org.apache.ignite.internal.pagememory.io.PageIoRegistry; import org.apache.ignite.internal.storage.DataStorageModule; import org.apache.ignite.internal.storage.StorageException; import org.apache.ignite.internal.storage.engine.StorageEngine; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryStorageEngineConfiguration; +import org.jetbrains.annotations.Nullable; /** * Implementation for creating {@link PageMemoryStorageEngine}s. @@ -39,7 +41,12 @@ public class PageMemoryDataStorageModule implements DataStorageModule { /** {@inheritDoc} */ @Override - public StorageEngine createEngine(ConfigurationRegistry configRegistry, Path storagePath) throws StorageException { + public StorageEngine createEngine( + String igniteInstanceName, + ConfigurationRegistry configRegistry, + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector + ) throws StorageException { PageMemoryStorageEngineConfiguration engineConfig = configRegistry.getConfiguration(PageMemoryStorageEngineConfiguration.KEY); assert engineConfig != null; @@ -48,6 +55,6 @@ public class PageMemoryDataStorageModule implements DataStorageModule { ioRegistry.loadFromServiceLoader(); - return new PageMemoryStorageEngine(engineConfig, ioRegistry); + return new PageMemoryStorageEngine(igniteInstanceName, engineConfig, ioRegistry, storagePath, longJvmPauseDetector); } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageEngine.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageEngine.java index d95436511..91e4e912b 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageEngine.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageEngine.java @@ -18,23 +18,35 @@ package org.apache.ignite.internal.storage.pagememory; import static java.util.concurrent.CompletableFuture.completedFuture; +import static org.apache.ignite.internal.util.IgniteUtils.closeAll; +import java.nio.file.Path; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; import org.apache.ignite.configuration.notifications.ConfigurationNamedListListener; import org.apache.ignite.configuration.notifications.ConfigurationNotificationEvent; import org.apache.ignite.configuration.schemas.table.TableConfiguration; import org.apache.ignite.configuration.schemas.table.TableView; +import org.apache.ignite.internal.components.LongJvmPauseDetector; +import org.apache.ignite.internal.fileio.AsyncFileIoFactory; +import org.apache.ignite.internal.fileio.FileIoFactory; +import org.apache.ignite.internal.fileio.RandomAccessFileIoFactory; import org.apache.ignite.internal.pagememory.PageMemory; +import org.apache.ignite.internal.pagememory.PageMemoryDataRegion; import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionConfiguration; import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionView; import org.apache.ignite.internal.pagememory.io.PageIoRegistry; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointManager; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; import org.apache.ignite.internal.storage.StorageException; import org.apache.ignite.internal.storage.engine.StorageEngine; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageView; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryStorageEngineConfiguration; -import org.apache.ignite.internal.util.IgniteUtils; +import org.apache.ignite.lang.IgniteInternalCheckedException; +import org.apache.ignite.lang.IgniteLogger; +import org.jetbrains.annotations.Nullable; /** * Storage engine implementation based on {@link PageMemory}. @@ -43,29 +55,88 @@ public class PageMemoryStorageEngine implements StorageEngine { /** Engine name. */ public static final String ENGINE_NAME = "pagememory"; + private final String igniteInstanceName; + private final PageMemoryStorageEngineConfiguration engineConfig; private final PageIoRegistry ioRegistry; - private final Map<String, VolatilePageMemoryDataRegion> regions = new ConcurrentHashMap<>(); + private final Path storagePath; + + @Nullable + private final LongJvmPauseDetector longJvmPauseDetector; + + private final Map<String, AbstractPageMemoryDataRegion> regions = new ConcurrentHashMap<>(); + + @Nullable + private volatile FilePageStoreManager filePageStoreManager; + + @Nullable + private volatile CheckpointManager checkpointManager; /** * Constructor. * + * @param igniteInstanceName String igniteInstanceName * @param engineConfig PageMemory storage engine configuration. * @param ioRegistry IO registry. + * @param storagePath Storage path. + * @param longJvmPauseDetector Long JVM pause detector. */ public PageMemoryStorageEngine( + String igniteInstanceName, PageMemoryStorageEngineConfiguration engineConfig, - PageIoRegistry ioRegistry + PageIoRegistry ioRegistry, + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector ) { + this.igniteInstanceName = igniteInstanceName; this.engineConfig = engineConfig; this.ioRegistry = ioRegistry; + this.storagePath = storagePath; + this.longJvmPauseDetector = longJvmPauseDetector; } /** {@inheritDoc} */ @Override public void start() { + int pageSize = engineConfig.pageSize().value(); + + try { + FileIoFactory fileIoFactory = engineConfig.checkpoint().useAsyncFileIoFactory().value() + ? new AsyncFileIoFactory() + : new RandomAccessFileIoFactory(); + + filePageStoreManager = new FilePageStoreManager( + IgniteLogger.forClass(FilePageStoreManager.class), + igniteInstanceName, + storagePath, + fileIoFactory, + pageSize + ); + + filePageStoreManager.start(); + } catch (IgniteInternalCheckedException e) { + throw new StorageException("Error starting file page store manager", e); + } + + try { + checkpointManager = new CheckpointManager( + igniteInstanceName, + null, + longJvmPauseDetector, + engineConfig.checkpoint(), + filePageStoreManager, + regions.values(), + storagePath, + pageSize + ); + + checkpointManager.start(); + } catch (IgniteInternalCheckedException e) { + throw new StorageException("Error starting checkpoint manager", e); + } + addDataRegion(engineConfig.defaultRegion()); // TODO: IGNITE-17066 Add handling deleting/updating data regions configuration @@ -84,24 +155,42 @@ public class PageMemoryStorageEngine implements StorageEngine { @Override public void stop() throws StorageException { try { - IgniteUtils.closeAll(regions.values().stream().map(region -> region::stop)); + Stream<AutoCloseable> closeRegions = regions.values().stream().map(region -> region::stop); + + Stream<AutoCloseable> closeManagers = Stream.of( + checkpointManager == null ? null : (AutoCloseable) checkpointManager::stop, + filePageStoreManager == null ? null : (AutoCloseable) filePageStoreManager::stop + ); + + closeAll(Stream.concat(closeRegions, closeManagers)); } catch (Exception e) { - throw new StorageException("Error when stopping regions", e); + throw new StorageException("Error when stopping components", e); } } /** {@inheritDoc} */ @Override - public PageMemoryTableStorage createTable(TableConfiguration tableCfg) { + public AbstractPageMemoryTableStorage createTable(TableConfiguration tableCfg) { TableView tableView = tableCfg.value(); assert tableView.dataStorage().name().equals(ENGINE_NAME) : tableView.dataStorage().name(); PageMemoryDataStorageView dataStorageView = (PageMemoryDataStorageView) tableView.dataStorage(); - VolatilePageMemoryDataRegion dataRegion = regions.get(dataStorageView.dataRegion()); + PageMemoryDataRegion dataRegion = regions.get(dataStorageView.dataRegion()); + + if (dataRegion.persistent()) { + return new PersistentPageMemoryTableStorage(tableCfg, (PersistentPageMemoryDataRegion) dataRegion); + } - return new VolatilePageMemoryTableStorage(tableCfg, dataRegion); + return new VolatilePageMemoryTableStorage(tableCfg, (VolatilePageMemoryDataRegion) dataRegion); + } + + /** + * Returns checkpoint manager, {@code null} if engine not started. + */ + public @Nullable CheckpointManager checkpointManager() { + return checkpointManager; } /** @@ -114,7 +203,19 @@ public class PageMemoryStorageEngine implements StorageEngine { String name = dataRegionConfig.name().value(); - VolatilePageMemoryDataRegion dataRegion = new VolatilePageMemoryDataRegion(dataRegionConfig, ioRegistry, pageSize); + AbstractPageMemoryDataRegion dataRegion; + + if (dataRegionConfig.persistent().value()) { + dataRegion = new PersistentPageMemoryDataRegion( + dataRegionConfig, + ioRegistry, + filePageStoreManager, + checkpointManager, + pageSize + ); + } else { + dataRegion = new VolatilePageMemoryDataRegion(dataRegionConfig, ioRegistry, pageSize); + } dataRegion.start(); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageIoModule.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageIoModule.java index bc6ddd8b4..c1e1268cc 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageIoModule.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryStorageIoModule.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.List; import org.apache.ignite.internal.pagememory.io.IoVersions; import org.apache.ignite.internal.pagememory.io.PageIoModule; +import org.apache.ignite.internal.storage.pagememory.io.PartitionMetaIo; import org.apache.ignite.internal.storage.pagememory.io.TableDataIo; import org.apache.ignite.internal.storage.pagememory.io.TableInnerIo; import org.apache.ignite.internal.storage.pagememory.io.TableLeafIo; @@ -37,7 +38,8 @@ public class PageMemoryStorageIoModule implements PageIoModule { TableMetaIo.VERSIONS, TableInnerIo.VERSIONS, TableLeafIo.VERSIONS, - TableDataIo.VERSIONS + TableDataIo.VERSIONS, + PartitionMetaIo.VERSIONS ); } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PartitionMeta.java similarity index 53% copy from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java copy to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PartitionMeta.java index fab23050a..f53b4554f 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PartitionMeta.java @@ -17,26 +17,35 @@ package org.apache.ignite.internal.storage.pagememory; -import org.apache.ignite.configuration.schemas.table.TableConfiguration; -import org.apache.ignite.internal.storage.StorageException; +import org.apache.ignite.internal.pagememory.FullPageId; /** - * Implementation of {@link PageMemoryTableStorage} for in-memory case. + * Class for storing {@link TableTree} partition metadata. */ -class VolatilePageMemoryTableStorage extends PageMemoryTableStorage { +class PartitionMeta { + /** {@link TableTree} root. */ + final FullPageId treeRoot; + + /** {@link TableFreeList} root. */ + final FullPageId reuseListRoot; + + /** Have been allocated (created) or read. */ + final boolean allocated; + /** * Constructor. * - * @param tableCfg – Table configuration. - * @param dataRegion – Data region for the table. + * @param reuseListRoot {@link TableFreeList} root. + * @param treeRoot {@link TableTree} root. + * @param allocated Have been allocated (created) or read. */ - public VolatilePageMemoryTableStorage(TableConfiguration tableCfg, VolatilePageMemoryDataRegion dataRegion) { - super(tableCfg, dataRegion); - } - - /** {@inheritDoc} */ - @Override - protected PageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException { - return new PageMemoryPartitionStorage(partId, tableCfg, dataRegion, ((VolatilePageMemoryDataRegion) dataRegion).tableFreeList()); + public PartitionMeta( + FullPageId treeRoot, + FullPageId reuseListRoot, + boolean allocated + ) { + this.treeRoot = treeRoot; + this.reuseListRoot = reuseListRoot; + this.allocated = allocated; } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegion.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegion.java new file mode 100644 index 000000000..ba76279b1 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegion.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.storage.pagememory; + +import static org.apache.ignite.internal.util.Constants.GiB; +import static org.apache.ignite.internal.util.Constants.MiB; + +import java.util.Arrays; +import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionConfiguration; +import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionView; +import org.apache.ignite.internal.pagememory.io.PageIoRegistry; +import org.apache.ignite.internal.pagememory.persistence.PageMemoryImpl; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointManager; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStoreManager; + +/** + * Implementation of {@link AbstractPageMemoryDataRegion} for persistent case. + */ +class PersistentPageMemoryDataRegion extends AbstractPageMemoryDataRegion { + private final FilePageStoreManager filePageStoreManager; + + private final CheckpointManager checkpointManager; + + /** + * Constructor. + * + * @param cfg Data region configuration. + * @param ioRegistry IO registry. + * @param filePageStoreManager File page store manager. + * @param checkpointManager Checkpoint manager. + * @param pageSize Page size in bytes. + */ + public PersistentPageMemoryDataRegion( + PageMemoryDataRegionConfiguration cfg, + PageIoRegistry ioRegistry, + FilePageStoreManager filePageStoreManager, + CheckpointManager checkpointManager, + int pageSize + ) { + super(cfg, ioRegistry, pageSize); + + this.filePageStoreManager = filePageStoreManager; + this.checkpointManager = checkpointManager; + } + + /** {@inheritDoc} */ + @Override + public void start() { + PageMemoryDataRegionView dataRegionConfigView = cfg.value(); + + assert persistent() : dataRegionConfigView.name(); + + PageMemoryImpl pageMemoryImpl = new PageMemoryImpl( + cfg, + ioRegistry, + calculateSegmentSizes(dataRegionConfigView, Runtime.getRuntime().availableProcessors()), + calculateCheckpointBufferSize(dataRegionConfigView), + filePageStoreManager, + null, + (fullPageId, buf, tag) -> { + // Write page to disk. + filePageStoreManager.write(fullPageId.groupId(), fullPageId.pageId(), buf, tag, true); + }, + checkpointManager.checkpointTimeoutLock(), + pageSize + ); + + pageMemoryImpl.start(); + + pageMemory = pageMemoryImpl; + } + + /** + * Returns file page store manager. + */ + public FilePageStoreManager filePageStoreManager() { + return filePageStoreManager; + } + + /** + * Returns checkpoint manager. + */ + public CheckpointManager checkpointManager() { + return checkpointManager; + } + + /** + * Calculates the size of segments in bytes. + * + * @param dataRegionConfigView Data region configuration. + * @param concurrencyLevel Number of concurrent segments in Ignite internal page mapping tables, must be greater than 0. + */ + // TODO: IGNITE-16350 Add more and more detailed description + static long[] calculateSegmentSizes(PageMemoryDataRegionView dataRegionConfigView, int concurrencyLevel) { + assert concurrencyLevel > 0 : concurrencyLevel; + + long maxSize = dataRegionConfigView.maxSize(); + + long fragmentSize = Math.max(maxSize / concurrencyLevel, MiB); + + long[] sizes = new long[concurrencyLevel]; + + Arrays.fill(sizes, fragmentSize); + + return sizes; + } + + /** + * Calculates the size of the checkpoint buffer in bytes. + * + * @param dataRegionConfigView Data region configuration. + */ + // TODO: IGNITE-16350 Add more and more detailed description + static long calculateCheckpointBufferSize(PageMemoryDataRegionView dataRegionConfigView) { + long maxSize = dataRegionConfigView.maxSize(); + + if (maxSize < GiB) { + return Math.min(GiB / 4L, maxSize); + } + + if (maxSize < 8L * GiB) { + return maxSize / 4L; + } + + return 2L * GiB; + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorage.java new file mode 100644 index 000000000..dfbb71a66 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorage.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.storage.pagememory; + +import java.util.Collection; +import java.util.List; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointTimeoutLock; +import org.apache.ignite.internal.pagememory.tree.BplusTree; +import org.apache.ignite.internal.storage.DataRow; +import org.apache.ignite.internal.storage.InvokeClosure; +import org.apache.ignite.internal.storage.PartitionStorage; +import org.apache.ignite.internal.storage.SearchRow; +import org.apache.ignite.internal.storage.StorageException; +import org.jetbrains.annotations.Nullable; + +/** + * Implementation of {@link PartitionStorage} based on a {@link BplusTree} for persistent case. + */ +public class PersistentPageMemoryPartitionStorage extends VolatilePageMemoryPartitionStorage { + private final CheckpointTimeoutLock checkpointTimeoutLock; + + /** + * Constructor. + * + * @param partId Partition id. + * @param freeList Table free list. + * @param tree Table tree. + * @param checkpointTimeoutLock Checkpoint timeout lock. + * @throws StorageException If there is an error while creating the partition storage. + */ + public PersistentPageMemoryPartitionStorage( + int partId, + TableFreeList freeList, + TableTree tree, + CheckpointTimeoutLock checkpointTimeoutLock + ) throws StorageException { + super(partId, freeList, tree); + + this.checkpointTimeoutLock = checkpointTimeoutLock; + } + + /** {@inheritDoc} */ + @Override + public void write(DataRow row) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + super.write(row); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public void writeAll(List<? extends DataRow> rows) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + super.writeAll(rows); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public Collection<DataRow> insertAll(List<? extends DataRow> rows) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + return super.insertAll(rows); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public void remove(SearchRow key) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + super.remove(key); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public Collection<SearchRow> removeAll(List<? extends SearchRow> keys) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + return super.removeAll(keys); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public Collection<DataRow> removeAllExact(List<? extends DataRow> keyValues) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + return super.removeAllExact(keyValues); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public <T> @Nullable T invoke(SearchRow key, InvokeClosure<T> clo) throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + return super.invoke(key, clo); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** {@inheritDoc} */ + @Override + public void destroy() throws StorageException { + checkpointTimeoutLock.checkpointReadLock(); + + try { + super.destroy(); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } +} 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 new file mode 100644 index 000000000..930ea4717 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.storage.pagememory; + +import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX; +import static org.apache.ignite.internal.storage.StorageUtils.groupId; + +import java.util.concurrent.atomic.AtomicLong; +import org.apache.ignite.configuration.schemas.table.TableConfiguration; +import org.apache.ignite.configuration.schemas.table.TableView; +import org.apache.ignite.internal.pagememory.FullPageId; +import org.apache.ignite.internal.pagememory.evict.PageEvictionTrackerNoOp; +import org.apache.ignite.internal.pagememory.metric.IoStatisticsHolderNoOp; +import org.apache.ignite.internal.pagememory.persistence.PageMemoryImpl; +import org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointTimeoutLock; +import org.apache.ignite.internal.pagememory.persistence.store.FilePageStore; +import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp; +import org.apache.ignite.internal.storage.StorageException; +import org.apache.ignite.internal.storage.pagememory.io.PartitionMetaIo; +import org.apache.ignite.lang.IgniteInternalCheckedException; + +/** + * Implementation of {@link AbstractPageMemoryTableStorage} for persistent case. + */ +class PersistentPageMemoryTableStorage extends AbstractPageMemoryTableStorage { + /** + * Constructor. + * + * @param tableCfg Table configuration. + * @param dataRegion Data region for the table. + */ + public PersistentPageMemoryTableStorage( + TableConfiguration tableCfg, + PersistentPageMemoryDataRegion dataRegion + ) { + super(tableCfg, dataRegion); + } + + /** {@inheritDoc} */ + @Override + public void start() throws StorageException { + super.start(); + + TableView tableView = tableCfg.value(); + + try { + // TODO: IGNITE-16665 Directory name needs to be corrected to support table renaming + ((PersistentPageMemoryDataRegion) dataRegion) + .filePageStoreManager() + .initialize(tableView.name(), groupId(tableView), tableView.partitions()); + } catch (IgniteInternalCheckedException e) { + throw new StorageException("Error initializing file page stores for table: " + tableView.name(), e); + } + } + + /** {@inheritDoc} */ + @Override + protected PersistentPageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException { + TableView tableView = tableCfg.value(); + + FilePageStore partitionFilePageStore = ensurePartitionFilePageStore(tableView, partId); + + CheckpointTimeoutLock checkpointTimeoutLock = ((PersistentPageMemoryDataRegion) dataRegion) + .checkpointManager() + .checkpointTimeoutLock(); + + checkpointTimeoutLock.checkpointReadLock(); + + try { + PartitionMeta partitionMeta = getOrCreatePartitionMeta(tableView, partId, partitionFilePageStore); + + TableFreeList tableFreeList = createTableFreeList(tableView, partId, partitionMeta); + + autoCloseables.add(tableFreeList::close); + + TableTree tableTree = createTableTree(tableView, partId, tableFreeList, partitionMeta); + + return new PersistentPageMemoryPartitionStorage(partId, tableFreeList, tableTree, checkpointTimeoutLock); + } finally { + checkpointTimeoutLock.checkpointReadUnlock(); + } + } + + /** + * Initializes the partition file page store if it hasn't already. + * + * @param tableView Table configuration. + * @param partId Partition ID. + * @return Partition file page store. + * @throws StorageException If failed. + */ + FilePageStore ensurePartitionFilePageStore(TableView tableView, int partId) throws StorageException { + try { + FilePageStore filePageStore = ((PersistentPageMemoryDataRegion) dataRegion) + .filePageStoreManager() + .getStore(groupId(tableView), partId); + + filePageStore.ensure(); + + return filePageStore; + } catch (IgniteInternalCheckedException e) { + throw new StorageException( + String.format("Error initializing file page store [tableName=%s, partitionId=%s]", tableView.name(), partId), + e + ); + } + } + + /** + * Creates new or reads existing partition meta. + * + * @param tableView Table configuration. + * @param partId Partition ID. + * @param filePageStore Partition file page store. + * @return Partition meta. + * @throws StorageException If failed. + */ + PartitionMeta getOrCreatePartitionMeta( + TableView tableView, + int partId, + FilePageStore filePageStore + ) throws StorageException { + PageMemoryImpl pageMemoryImpl = (PageMemoryImpl) dataRegion.pageMemory(); + + int grpId = groupId(tableView); + + boolean allocatePartMetaPage = filePageStore.pages() == 0; + + try { + long partMetaPageId = allocatePartMetaPage + ? pageMemoryImpl.allocatePage(grpId, partId, FLAG_AUX) + : pageMemoryImpl.partitionMetaPageId(grpId, partId); + + long partMetaPage = pageMemoryImpl.acquirePage(grpId, partMetaPageId); + + try { + long partMetaPageAddr = pageMemoryImpl.writeLock(grpId, partMetaPageId, partMetaPage); + + try { + long treeRootPageId; + long reuseListRootPageId; + + if (allocatePartMetaPage) { + PartitionMetaIo partMetaIo = PartitionMetaIo.VERSIONS.latest(); + + partMetaIo.initNewPage(partMetaPageAddr, partMetaPageId, pageMemoryImpl.realPageSize(grpId)); + + treeRootPageId = pageMemoryImpl.allocatePage(grpId, partId, FLAG_AUX); + reuseListRootPageId = pageMemoryImpl.allocatePage(grpId, partId, FLAG_AUX); + + partMetaIo.setTreeRootPageId(partMetaPageAddr, treeRootPageId); + partMetaIo.setReuseListRootPageId(partMetaPageAddr, reuseListRootPageId); + } else { + PartitionMetaIo partMetaIo = pageMemoryImpl.ioRegistry().resolve(partMetaPageAddr); + + treeRootPageId = partMetaIo.getTreeRootPageId(partMetaPageAddr); + reuseListRootPageId = partMetaIo.getReuseListRootPageId(partMetaPageAddr); + } + + return new PartitionMeta( + new FullPageId(treeRootPageId, grpId), + new FullPageId(reuseListRootPageId, grpId), + allocatePartMetaPage + ); + } finally { + pageMemoryImpl.writeUnlock(grpId, partMetaPageId, partMetaPage, allocatePartMetaPage); + } + } finally { + pageMemoryImpl.releasePage(grpId, partMetaPageId, partMetaPage); + } + } catch (IgniteInternalCheckedException e) { + throw new StorageException( + String.format("Error getting or creating partition metadata [tableName=%s, partitionId=%s]", tableView.name(), partId), + e + ); + } + } + + /** + * Returns new {@link TableFreeList} instance for partition. + * + * @param tableView Table configuration. + * @param partId Partition ID. + * @param partitionMeta Table partition metadata. + * @throws StorageException If failed. + */ + TableFreeList createTableFreeList( + TableView tableView, + int partId, + PartitionMeta partitionMeta + ) throws StorageException { + try { + return new TableFreeList( + groupId(tableView), + dataRegion.pageMemory(), + PageLockListenerNoOp.INSTANCE, + partitionMeta.reuseListRoot.pageId(), + partitionMeta.allocated, + null, + PageEvictionTrackerNoOp.INSTANCE, + IoStatisticsHolderNoOp.INSTANCE + ); + } catch (IgniteInternalCheckedException e) { + throw new StorageException( + String.format("Error creating TableFreeList [tableName=%s, partitionId=%s]", tableView.name(), partId), + e + ); + } + } + + /** + * Returns new {@link TableTree} instance for partition. + * + * @param tableView Table configuration. + * @param partId Partition ID. + * @param freeList Table free list. + * @param partitionMeta Table partition metadata. + * @throws StorageException If failed. + */ + TableTree createTableTree( + TableView tableView, + int partId, + TableFreeList freeList, + PartitionMeta partitionMeta + ) throws StorageException { + int grpId = groupId(tableView); + + try { + return new TableTree( + grpId, + tableView.name(), + dataRegion.pageMemory(), + PageLockListenerNoOp.INSTANCE, + new AtomicLong(), + partitionMeta.treeRoot.pageId(), + freeList, + partId, + partitionMeta.allocated + ); + } catch (IgniteInternalCheckedException e) { + throw new StorageException( + String.format("Error creating TableTree [tableName=%s, partitionId=%s]", tableView.name(), partId), + e + ); + } + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java index cf4ee0823..dc43778cc 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryDataRegion.java @@ -36,7 +36,7 @@ import org.apache.ignite.lang.IgniteInternalCheckedException; /** * Implementation of {@link AbstractPageMemoryDataRegion} for in-memory case. */ -public class VolatilePageMemoryDataRegion extends AbstractPageMemoryDataRegion { +class VolatilePageMemoryDataRegion extends AbstractPageMemoryDataRegion { private static final int FREE_LIST_GROUP_ID = 0; private TableFreeList tableFreeList; diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java similarity index 89% rename from modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorage.java rename to modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java index 3ec2da275..483b1a276 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorage.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java @@ -17,9 +17,7 @@ package org.apache.ignite.internal.storage.pagememory; -import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX; import static org.apache.ignite.internal.pagememory.PageIdAllocator.MAX_PARTITION_ID; -import static org.apache.ignite.internal.storage.StorageUtils.groupId; import java.nio.ByteBuffer; import java.nio.file.Path; @@ -29,13 +27,9 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; -import org.apache.ignite.configuration.schemas.table.TableConfiguration; -import org.apache.ignite.configuration.schemas.table.TableView; import org.apache.ignite.internal.pagememory.tree.BplusTree; import org.apache.ignite.internal.pagememory.tree.IgniteTree; -import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp; import org.apache.ignite.internal.storage.DataRow; import org.apache.ignite.internal.storage.InvokeClosure; import org.apache.ignite.internal.storage.OperationType; @@ -50,10 +44,10 @@ import org.apache.ignite.lang.IgniteInternalException; import org.jetbrains.annotations.Nullable; /** - * Storage implementation based on a {@link BplusTree}. + * Implementation of {@link PartitionStorage} based on a {@link BplusTree} for in-memory case. */ // TODO: IGNITE-16644 Support snapshots. -class PageMemoryPartitionStorage implements PartitionStorage { +class VolatilePageMemoryPartitionStorage implements PartitionStorage { private final int partId; private final TableTree tree; @@ -64,48 +58,20 @@ class PageMemoryPartitionStorage implements PartitionStorage { * Constructor. * * @param partId Partition id. - * @param tableCfg – Table configuration. - * @param dataRegion – Data region for the table. * @param freeList Table free list. + * @param tree Table tree. * @throws StorageException If there is an error while creating the partition storage. */ - public PageMemoryPartitionStorage( + public VolatilePageMemoryPartitionStorage( int partId, - TableConfiguration tableCfg, - AbstractPageMemoryDataRegion dataRegion, - TableFreeList freeList + TableFreeList freeList, + TableTree tree ) throws StorageException { assert partId >= 0 && partId < MAX_PARTITION_ID : partId; this.partId = partId; - this.freeList = freeList; - - TableView tableView = tableCfg.value(); - - int grpId = groupId(tableView); - - try { - // TODO: IGNITE-16641 It is necessary to do getting the tree root for the persistent case. - long metaPageId = dataRegion.pageMemory().allocatePage(grpId, partId, FLAG_AUX); - - // TODO: IGNITE-16641 It is necessary to take into account the persistent case. - boolean initNew = true; - - tree = new TableTree( - grpId, - tableView.name(), - dataRegion.pageMemory(), - PageLockListenerNoOp.INSTANCE, - new AtomicLong(), - metaPageId, - freeList, - partId, - initNew - ); - } catch (IgniteInternalCheckedException e) { - throw new StorageException("Error occurred while creating the partition storage", e); - } + this.tree = tree; } /** {@inheritDoc} */ diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java index fab23050a..b6c9acda3 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryTableStorage.java @@ -17,13 +17,20 @@ package org.apache.ignite.internal.storage.pagememory; +import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX; +import static org.apache.ignite.internal.storage.StorageUtils.groupId; + +import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.configuration.schemas.table.TableConfiguration; +import org.apache.ignite.configuration.schemas.table.TableView; +import org.apache.ignite.internal.pagememory.util.PageLockListenerNoOp; import org.apache.ignite.internal.storage.StorageException; +import org.apache.ignite.lang.IgniteInternalCheckedException; /** - * Implementation of {@link PageMemoryTableStorage} for in-memory case. + * Implementation of {@link AbstractPageMemoryTableStorage} for in-memory case. */ -class VolatilePageMemoryTableStorage extends PageMemoryTableStorage { +class VolatilePageMemoryTableStorage extends AbstractPageMemoryTableStorage { /** * Constructor. * @@ -36,7 +43,50 @@ class VolatilePageMemoryTableStorage extends PageMemoryTableStorage { /** {@inheritDoc} */ @Override - protected PageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException { - return new PageMemoryPartitionStorage(partId, tableCfg, dataRegion, ((VolatilePageMemoryDataRegion) dataRegion).tableFreeList()); + protected VolatilePageMemoryPartitionStorage createPartitionStorage(int partId) throws StorageException { + TableFreeList tableFreeList = ((VolatilePageMemoryDataRegion) dataRegion).tableFreeList(); + + TableTree tableTree = createTableTree(tableCfg.value(), partId, tableFreeList); + + return new VolatilePageMemoryPartitionStorage( + partId, + tableFreeList, + tableTree + ); + } + + /** + * Returns new {@link TableTree} instance for partition. + * + * @param tableView Table configuration. + * @param partId Partition ID. + * @param freeList Table free list. + * @throws StorageException If failed. + */ + TableTree createTableTree( + TableView tableView, + int partId, + TableFreeList freeList + ) throws StorageException { + int grpId = groupId(tableView); + + try { + return new TableTree( + grpId, + tableView.name(), + dataRegion.pageMemory(), + PageLockListenerNoOp.INSTANCE, + new AtomicLong(), + dataRegion.pageMemory().allocatePage(grpId, partId, FLAG_AUX), + freeList, + partId, + true + ); + } catch (IgniteInternalCheckedException e) { + throw new StorageException( + String.format("Error creating TableTree [tableName=%s, partitionId=%s]", tableView.name(), partId), + e + ); + } } } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/configuration/schema/PageMemoryStorageEngineConfigurationSchema.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/configuration/schema/PageMemoryStorageEngineConfigurationSchema.java index aad7896d5..1836b8d4e 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/configuration/schema/PageMemoryStorageEngineConfigurationSchema.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/configuration/schema/PageMemoryStorageEngineConfigurationSchema.java @@ -28,6 +28,7 @@ import org.apache.ignite.configuration.validation.ExceptKeys; import org.apache.ignite.configuration.validation.Immutable; import org.apache.ignite.configuration.validation.PowerOfTwo; import org.apache.ignite.configuration.validation.Range; +import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryCheckpointConfigurationSchema; import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionConfigurationSchema; import org.apache.ignite.internal.storage.pagememory.PageMemoryStorageEngine; @@ -55,4 +56,8 @@ public class PageMemoryStorageEngineConfigurationSchema { @ExceptKeys(DEFAULT_DATA_REGION_NAME) @NamedConfigValue public PageMemoryDataRegionConfigurationSchema regions; + + /* Checkpoint configuration for persistent data regions. */ + @ConfigValue + public PageMemoryCheckpointConfigurationSchema checkpoint; } diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/io/PartitionMetaIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/io/PartitionMetaIo.java new file mode 100644 index 000000000..610995e70 --- /dev/null +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/io/PartitionMetaIo.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.storage.pagememory.io; + +import static org.apache.ignite.internal.pagememory.PageIdAllocator.FLAG_AUX; +import static org.apache.ignite.internal.pagememory.util.PageUtils.getLong; +import static org.apache.ignite.internal.pagememory.util.PageUtils.putLong; + +import org.apache.ignite.internal.pagememory.io.IoVersions; +import org.apache.ignite.internal.pagememory.io.PageIo; +import org.apache.ignite.lang.IgniteStringBuilder; + +/** + * Io for partition metadata pages. + */ +public class PartitionMetaIo extends PageIo { + private static final int TREE_ROOT_PAGE_ID_OFF = COMMON_HEADER_END; + + private static final int REUSE_LIST_ROOT_PAGE_ID_OFF = TREE_ROOT_PAGE_ID_OFF + Long.BYTES; + + /** Page IO type. */ + public static final short T_TABLE_PARTITION_META_IO = 7; + + /** I/O versions. */ + public static final IoVersions<PartitionMetaIo> VERSIONS = new IoVersions<>(new PartitionMetaIo(1)); + + /** + * Constructor. + * + * @param ver Page format version. + */ + protected PartitionMetaIo(int ver) { + super(T_TABLE_PARTITION_META_IO, ver, FLAG_AUX); + } + + /** {@inheritDoc} */ + @Override + public void initNewPage(long pageAddr, long pageId, int pageSize) { + super.initNewPage(pageAddr, pageId, pageSize); + + setTreeRootPageId(pageAddr, 0); + setReuseListRootPageId(pageAddr, 0); + } + + /** + * Sets tree root page ID. + * + * @param pageAddr Page address. + * @param pageId Tree root page ID. + */ + public void setTreeRootPageId(long pageAddr, long pageId) { + assertPageType(pageAddr); + + putLong(pageAddr, TREE_ROOT_PAGE_ID_OFF, pageId); + } + + /** + * Returns tree root page ID. + * + * @param pageAddr Page address. + */ + public long getTreeRootPageId(long pageAddr) { + return getLong(pageAddr, TREE_ROOT_PAGE_ID_OFF); + } + + /** + * Sets reuse list root page ID. + * + * @param pageAddr Page address. + * @param pageId Reuse list root page ID. + */ + public void setReuseListRootPageId(long pageAddr, long pageId) { + assertPageType(pageAddr); + + putLong(pageAddr, REUSE_LIST_ROOT_PAGE_ID_OFF, pageId); + } + + /** + * Returns reuse list root page ID. + * + * @param pageAddr Page address. + */ + public long getReuseListRootPageId(long pageAddr) { + return getLong(pageAddr, REUSE_LIST_ROOT_PAGE_ID_OFF); + } + + /** {@inheritDoc} */ + @Override + protected void printPage(long addr, int pageSize, IgniteStringBuilder sb) { + sb.app("TablePartitionMeta [").nl() + .app("treeRootPageId=").appendHex(getTreeRootPageId(addr)).nl() + .app(", reuseListRootPageId=").appendHex(getReuseListRootPageId(addr)).nl() + .app(']'); + } +} diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java index c7e9bdccc..11214b612 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/RowVersionDataIo.java @@ -36,7 +36,7 @@ import org.jetbrains.annotations.Nullable; */ public class RowVersionDataIo extends AbstractDataPageIo<RowVersion> { /** Page IO type. */ - public static final short T_VALUE_VERSION_DATA_IO = 11; + public static final short T_VALUE_VERSION_DATA_IO = 12; /** I/O versions. */ public static final IoVersions<RowVersionDataIo> VERSIONS = new IoVersions<>(new RowVersionDataIo(1)); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainDataIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainDataIo.java index eb18573a5..7d7618792 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainDataIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainDataIo.java @@ -34,7 +34,7 @@ import org.jetbrains.annotations.Nullable; */ public class VersionChainDataIo extends AbstractDataPageIo<VersionChain> { /** Page IO type. */ - public static final short T_VERSION_CHAIN_IO = 7; + public static final short T_VERSION_CHAIN_IO = 8; /** I/O versions. */ public static final IoVersions<VersionChainDataIo> VERSIONS = new IoVersions<>(new VersionChainDataIo(1)); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainInnerIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainInnerIo.java index d24e83ea4..89b036623 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainInnerIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainInnerIo.java @@ -34,7 +34,7 @@ import org.apache.ignite.internal.storage.pagememory.mv.VersionChainTree; */ public class VersionChainInnerIo extends BplusInnerIo<VersionChainLink> implements VersionChainIo { /** Page IO type. */ - public static final short T_VERSION_CHAIN_INNER_IO = 9; + public static final short T_VERSION_CHAIN_INNER_IO = 10; /** I/O versions. */ public static final IoVersions<VersionChainInnerIo> VERSIONS = new IoVersions<>(new VersionChainInnerIo(1)); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainLeafIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainLeafIo.java index 15bbce063..a375a7004 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainLeafIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainLeafIo.java @@ -34,7 +34,7 @@ import org.apache.ignite.internal.storage.pagememory.mv.VersionChainTree; */ public class VersionChainLeafIo extends BplusLeafIo<VersionChainLink> implements VersionChainIo { /** Page IO type. */ - public static final short T_VERSION_CHAIN_LEAF_IO = 10; + public static final short T_VERSION_CHAIN_LEAF_IO = 11; /** I/O versions. */ public static final IoVersions<VersionChainLeafIo> VERSIONS = new IoVersions<>(new VersionChainLeafIo(1)); diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainMetaIo.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainMetaIo.java index ae66188a4..ca63625bd 100644 --- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainMetaIo.java +++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/mv/io/VersionChainMetaIo.java @@ -26,7 +26,7 @@ import org.apache.ignite.internal.storage.pagememory.mv.VersionChainTree; */ public class VersionChainMetaIo extends BplusMetaIo { /** Page IO type. */ - public static final short T_VERSION_CHAIN_META_IO = 8; + public static final short T_VERSION_CHAIN_META_IO = 9; /** I/O versions. */ public static final IoVersions<VersionChainMetaIo> VERSIONS = new IoVersions<>(new VersionChainMetaIo(1)); diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegionTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegionTest.java new file mode 100644 index 000000000..a3f1b2839 --- /dev/null +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryDataRegionTest.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.storage.pagememory; + +import static org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryDataRegion.calculateCheckpointBufferSize; +import static org.apache.ignite.internal.storage.pagememory.PersistentPageMemoryDataRegion.calculateSegmentSizes; +import static org.apache.ignite.internal.util.Constants.GiB; +import static org.apache.ignite.internal.util.Constants.MiB; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.internal.configuration.testframework.ConfigurationExtension; +import org.apache.ignite.internal.configuration.testframework.InjectConfiguration; +import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionConfiguration; +import org.apache.ignite.internal.pagememory.configuration.schema.PageMemoryDataRegionView; +import org.apache.ignite.internal.pagememory.configuration.schema.UnsafeMemoryAllocatorConfigurationSchema; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * For {@link PersistentPageMemoryDataRegion} testing. + */ +@ExtendWith(ConfigurationExtension.class) +public class PersistentPageMemoryDataRegionTest { + @InjectConfiguration(polymorphicExtensions = UnsafeMemoryAllocatorConfigurationSchema.class) + private PageMemoryDataRegionConfiguration dataRegionConfig; + + @Test + void testCalculateSegmentSizes() throws Exception { + int concurrencyLevel = 2; + + PageMemoryDataRegionView dataRegionConfigView = dataRegionConfig.value(); + + assertArrayEquals( + fill(new long[concurrencyLevel], dataRegionConfigView.maxSize() / concurrencyLevel), + calculateSegmentSizes(dataRegionConfigView, concurrencyLevel) + ); + + dataRegionConfig.maxSize().update(1024L).get(1, TimeUnit.SECONDS); + + assertArrayEquals( + fill(new long[concurrencyLevel], MiB), + calculateSegmentSizes(dataRegionConfig.value(), concurrencyLevel) + ); + } + + @Test + void testCalculateCheckpointBufferSize() throws Exception { + PageMemoryDataRegionView dataRegionConfigView = dataRegionConfig.value(); + + assertEquals(dataRegionConfigView.maxSize(), calculateCheckpointBufferSize(dataRegionConfigView)); + + dataRegionConfig.maxSize().update(GiB / 2L).get(1, TimeUnit.SECONDS); + + assertEquals(GiB / 4L, calculateCheckpointBufferSize(dataRegionConfig.value())); + + dataRegionConfig.maxSize().update(6L * GiB).get(1, TimeUnit.SECONDS); + + assertEquals((6L * GiB) / 4L, calculateCheckpointBufferSize(dataRegionConfig.value())); + + dataRegionConfig.maxSize().update(8L * GiB).get(1, TimeUnit.SECONDS); + + assertEquals(2L * GiB, calculateCheckpointBufferSize(dataRegionConfig.value())); + } + + private long[] fill(long[] arr, long v) { + Arrays.fill(arr, v); + + return arr; + } +} diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorageTest.java similarity index 72% copy from modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java copy to modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorageTest.java index 227357120..a081ab131 100644 --- a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryPartitionStorageTest.java @@ -17,26 +17,27 @@ package org.apache.ignite.internal.storage.pagememory; -import static java.util.stream.Collectors.joining; +import static org.apache.ignite.internal.pagememory.persistence.checkpoint.CheckpointState.FINISHED; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import java.nio.file.Path; -import java.util.concurrent.ThreadLocalRandom; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.apache.ignite.configuration.schemas.store.UnknownDataStorageConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TableConfiguration; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.testframework.ConfigurationExtension; import org.apache.ignite.internal.configuration.testframework.InjectConfiguration; import org.apache.ignite.internal.pagememory.configuration.schema.UnsafeMemoryAllocatorConfigurationSchema; import org.apache.ignite.internal.pagememory.io.PageIoRegistry; import org.apache.ignite.internal.storage.AbstractPartitionStorageTest; import org.apache.ignite.internal.storage.DataRow; -import org.apache.ignite.internal.storage.engine.StorageEngine; import org.apache.ignite.internal.storage.engine.TableStorage; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageChange; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageConfigurationSchema; @@ -55,12 +56,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; /** - * Storage test implementation for {@link PageMemoryPartitionStorage}. + * Storage test implementation for {@link PersistentPageMemoryPartitionStorage}. */ -// TODO: IGNITE-16641 Add test for persistent case. @ExtendWith(ConfigurationExtension.class) @ExtendWith(WorkDirectoryExtension.class) -public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest { +public class PersistentPageMemoryPartitionStorageTest extends AbstractPartitionStorageTest { private static PageIoRegistry ioRegistry; @InjectConfiguration(polymorphicExtensions = UnsafeMemoryAllocatorConfigurationSchema.class) @@ -76,10 +76,15 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest ) private TableConfiguration tableCfg; - private StorageEngine engine; + private LongJvmPauseDetector longJvmPauseDetector; + + private PageMemoryStorageEngine engine; private TableStorage table; + @WorkDirectory + private Path workDir; + @BeforeAll static void beforeAll() { ioRegistry = new PageIoRegistry(); @@ -89,12 +94,19 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest @BeforeEach void setUp() throws Exception { - engine = new PageMemoryStorageEngine(engineConfig, ioRegistry); + String nodeName = "test-node"; + + longJvmPauseDetector = new LongJvmPauseDetector(nodeName); + + longJvmPauseDetector.start(); + + engineConfig.defaultRegion().persistent().update(true).get(1, TimeUnit.SECONDS); + + engine = new PageMemoryStorageEngine(nodeName, engineConfig, ioRegistry, workDir, longJvmPauseDetector); engine.start(); - tableCfg.change(c -> c.changeDataStorage(dsc -> dsc.convert(PageMemoryDataStorageChange.class))) - .get(1, TimeUnit.SECONDS); + tableCfg.change(c -> c.changeDataStorage(dsc -> dsc.convert(PageMemoryDataStorageChange.class))).get(1, TimeUnit.SECONDS); assertEquals( PageMemoryStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME, @@ -103,13 +115,13 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest table = engine.createTable(tableCfg); - assertThat(table, is(instanceOf(PageMemoryTableStorage.class))); + assertThat(table, is(instanceOf(PersistentPageMemoryTableStorage.class))); table.start(); storage = table.getOrCreatePartition(0); - assertThat(storage, is(instanceOf(PageMemoryPartitionStorage.class))); + assertThat(storage, is(instanceOf(PersistentPageMemoryPartitionStorage.class))); } @AfterEach @@ -117,7 +129,8 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest IgniteUtils.closeAll( storage, table == null ? null : table::stop, - engine == null ? null : engine::stop + engine == null ? null : engine::stop, + longJvmPauseDetector == null ? null : longJvmPauseDetector::stop ); } @@ -134,25 +147,24 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest super.testSnapshot(workDir); } - /** - * Checks that fragments are written and read correctly. - * - * @throws Exception If failed. - */ @Test - void testFragments() { - int pageSize = engineConfig.pageSize().value(); + void testReadAfterRestart() throws Exception { + List<DataRow> rows = IntStream.range(0, 100) + .mapToObj(i -> dataRow(KEY + i, VALUE + i)) + .collect(Collectors.toList()); - DataRow dataRow = dataRow(createRandomString(pageSize), createRandomString(pageSize)); + storage.writeAll(rows); - storage.write(dataRow); + engine + .checkpointManager() + .forceCheckpoint("before_stop_engine") + .futureFor(FINISHED) + .get(1, TimeUnit.SECONDS); - DataRow read = storage.read(dataRow); + tearDown(); - assertArrayEquals(dataRow.valueBytes(), read.valueBytes()); - } + setUp(); - private String createRandomString(int len) { - return ThreadLocalRandom.current().ints(len).mapToObj(i -> String.valueOf(Math.abs(i % 10))).collect(joining("")); + rows.forEach(this::checkHasSameEntry); } } diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorageTest.java similarity index 89% rename from modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java rename to modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorageTest.java index 227357120..7aa58c9a3 100644 --- a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/PageMemoryPartitionStorageTest.java +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorageTest.java @@ -55,12 +55,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; /** - * Storage test implementation for {@link PageMemoryPartitionStorage}. + * Storage test implementation for {@link VolatilePageMemoryPartitionStorage}. */ -// TODO: IGNITE-16641 Add test for persistent case. @ExtendWith(ConfigurationExtension.class) @ExtendWith(WorkDirectoryExtension.class) -public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest { +public class VolatilePageMemoryPartitionStorageTest extends AbstractPartitionStorageTest { private static PageIoRegistry ioRegistry; @InjectConfiguration(polymorphicExtensions = UnsafeMemoryAllocatorConfigurationSchema.class) @@ -80,6 +79,9 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest private TableStorage table; + @WorkDirectory + private Path workDir; + @BeforeAll static void beforeAll() { ioRegistry = new PageIoRegistry(); @@ -89,12 +91,13 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest @BeforeEach void setUp() throws Exception { - engine = new PageMemoryStorageEngine(engineConfig, ioRegistry); + engineConfig.defaultRegion().persistent().update(false).get(1, TimeUnit.SECONDS); + + engine = new PageMemoryStorageEngine("test", engineConfig, ioRegistry, workDir, null); engine.start(); - tableCfg.change(c -> c.changeDataStorage(dsc -> dsc.convert(PageMemoryDataStorageChange.class))) - .get(1, TimeUnit.SECONDS); + tableCfg.change(c -> c.changeDataStorage(dsc -> dsc.convert(PageMemoryDataStorageChange.class))).get(1, TimeUnit.SECONDS); assertEquals( PageMemoryStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME, @@ -103,13 +106,13 @@ public class PageMemoryPartitionStorageTest extends AbstractPartitionStorageTest table = engine.createTable(tableCfg); - assertThat(table, is(instanceOf(PageMemoryTableStorage.class))); + assertThat(table, is(instanceOf(VolatilePageMemoryTableStorage.class))); table.start(); storage = table.getOrCreatePartition(0); - assertThat(storage, is(instanceOf(PageMemoryPartitionStorage.class))); + assertThat(storage, is(instanceOf(VolatilePageMemoryPartitionStorage.class))); } @AfterEach diff --git a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/PageMemoryMvPartitionStorageTest.java b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/PageMemoryMvPartitionStorageTest.java index f013eade0..1d5ae5e1c 100644 --- a/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/PageMemoryMvPartitionStorageTest.java +++ b/modules/storage-page-memory/src/test/java/org/apache/ignite/internal/storage/pagememory/mv/PageMemoryMvPartitionStorageTest.java @@ -21,6 +21,7 @@ import static java.util.stream.Collectors.joining; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.nio.file.Path; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; import org.apache.ignite.configuration.schemas.store.UnknownDataStorageConfigurationSchema; @@ -33,13 +34,14 @@ import org.apache.ignite.internal.pagememory.io.PageIoRegistry; import org.apache.ignite.internal.schema.BinaryRow; import org.apache.ignite.internal.storage.AbstractMvPartitionStorageTest; import org.apache.ignite.internal.storage.RowId; +import org.apache.ignite.internal.storage.pagememory.AbstractPageMemoryTableStorage; import org.apache.ignite.internal.storage.pagememory.PageMemoryStorageEngine; -import org.apache.ignite.internal.storage.pagememory.PageMemoryTableStorage; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageChange; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageConfigurationSchema; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryDataStorageView; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryStorageEngineConfiguration; import org.apache.ignite.internal.storage.pagememory.configuration.schema.PageMemoryStorageEngineConfigurationSchema; +import org.apache.ignite.internal.testframework.WorkDirectory; import org.apache.ignite.internal.testframework.WorkDirectoryExtension; import org.apache.ignite.internal.tx.Timestamp; import org.apache.ignite.internal.util.Cursor; @@ -73,13 +75,16 @@ class PageMemoryMvPartitionStorageTest extends AbstractMvPartitionStorageTest<Pa private PageMemoryStorageEngine engine; - private PageMemoryTableStorage table; + private AbstractPageMemoryTableStorage table; private int nextPageIndex = 100; + @WorkDirectory + private Path workDir; + @BeforeEach void setUp() throws Exception { - engine = new PageMemoryStorageEngine(engineConfig, ioRegistry); + engine = new PageMemoryStorageEngine("test", engineConfig, ioRegistry, workDir, null); engine.start(); diff --git a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbDataStorageModule.java b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbDataStorageModule.java index b6ab0ddfc..598881e73 100644 --- a/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbDataStorageModule.java +++ b/modules/storage-rocksdb/src/main/java/org/apache/ignite/internal/storage/rocksdb/RocksDbDataStorageModule.java @@ -20,11 +20,13 @@ package org.apache.ignite.internal.storage.rocksdb; import static org.apache.ignite.internal.storage.rocksdb.RocksDbStorageEngine.ENGINE_NAME; import java.nio.file.Path; +import org.apache.ignite.internal.components.LongJvmPauseDetector; import org.apache.ignite.internal.configuration.ConfigurationRegistry; import org.apache.ignite.internal.storage.DataStorageModule; import org.apache.ignite.internal.storage.StorageException; import org.apache.ignite.internal.storage.engine.StorageEngine; import org.apache.ignite.internal.storage.rocksdb.configuration.schema.RocksDbStorageEngineConfiguration; +import org.jetbrains.annotations.Nullable; /** * Implementation for creating {@link RocksDbStorageEngine}s. @@ -38,7 +40,12 @@ public class RocksDbDataStorageModule implements DataStorageModule { /** {@inheritDoc} */ @Override - public StorageEngine createEngine(ConfigurationRegistry configRegistry, Path storagePath) throws StorageException { + public StorageEngine createEngine( + String igniteInstanceName, + ConfigurationRegistry configRegistry, + Path storagePath, + @Nullable LongJvmPauseDetector longJvmPauseDetector + ) throws StorageException { RocksDbStorageEngineConfiguration engineConfig = configRegistry.getConfiguration(RocksDbStorageEngineConfiguration.KEY); assert engineConfig != null; diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java index 2d24d0511..60cc92552 100644 --- a/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java +++ b/modules/table/src/test/java/org/apache/ignite/internal/table/TableManagerTest.java @@ -656,7 +656,7 @@ public class TableManagerTest extends IgniteAbstractTest { DataStorageManager manager = new DataStorageManager( tblsCfg, - dataStorageModules.createStorageEngines(mockedRegistry, storagePath) + dataStorageModules.createStorageEngines(NODE_NAME, mockedRegistry, storagePath, null) ); manager.start();