You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2022/06/08 13:07:56 UTC

[ignite-3] branch main updated: IGNITE-17128 Fix PersistentPageMemoryStorageExample cannot be run twice

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 7e2a1e460 IGNITE-17128 Fix PersistentPageMemoryStorageExample cannot be run twice
7e2a1e460 is described below

commit 7e2a1e460692b79ee824b7864c326f5d1be3bfb7
Author: Kirill Tkalenko <tk...@yandex.ru>
AuthorDate: Wed Jun 8 08:20:17 2022 +0300

    IGNITE-17128 Fix PersistentPageMemoryStorageExample cannot be run twice
---
 .../PersistentPageMemoryStorageExample.java        |  4 +-
 .../storage/VolatilePageMemoryStorageExample.java  |  2 +-
 .../ignite/internal/util/CollectionUtils.java      | 99 ++++++++++++++++++++++
 .../ignite/internal/util/CollectionUtilsTest.java  | 61 +++++++++++++
 .../persistence/PageMemoryImplNoLoadTest.java      |  5 +-
 .../internal/runner/app/ItNoThreadsLeftTest.java   |  5 +-
 .../pagememory/AbstractPageMemoryTableStorage.java | 62 +++++++-------
 .../pagememory/PageMemoryStorageEngine.java        |  3 +-
 .../PersistentPageMemoryPartitionStorage.java      | 16 +++-
 .../PersistentPageMemoryTableStorage.java          |  6 ++
 .../VolatilePageMemoryPartitionStorage.java        |  6 +-
 .../pagememory/VolatilePageMemoryTableStorage.java |  6 ++
 12 files changed, 232 insertions(+), 43 deletions(-)

diff --git a/examples/src/main/java/org/apache/ignite/example/storage/PersistentPageMemoryStorageExample.java b/examples/src/main/java/org/apache/ignite/example/storage/PersistentPageMemoryStorageExample.java
index 5c1cbd6dc..649397512 100644
--- a/examples/src/main/java/org/apache/ignite/example/storage/PersistentPageMemoryStorageExample.java
+++ b/examples/src/main/java/org/apache/ignite/example/storage/PersistentPageMemoryStorageExample.java
@@ -31,7 +31,7 @@ import java.sql.Statement;
  *     <li>Import the examples project into you IDE.</li>
  *     <li>
  *         Download and prepare artifacts for running an Ignite node using the CLI tool (if not done yet):<br>
- *         {@code ignite init}
+ *         {@code ignite bootstrap}
  *     </li>
  *     <li>
  *         Start an Ignite node using the CLI tool:<br>
@@ -43,7 +43,7 @@ import java.sql.Statement;
  *     </li>
  *     <li>
  *         Add configuration for persistent data region of of the PageMemory storage engine using the CLI tool (if not done yet):<br>
- *         {@code ignite config set --type=cluster "pageMemory.regions.persistent:{persistent=true}"}
+ *         {@code ignite cluster config update "pageMemory.regions.persistent:{persistent=true}"}
  *     </li>
  *     <li>Run the example in the IDE.</li>
  *     <li>
diff --git a/examples/src/main/java/org/apache/ignite/example/storage/VolatilePageMemoryStorageExample.java b/examples/src/main/java/org/apache/ignite/example/storage/VolatilePageMemoryStorageExample.java
index f8ee293bd..329864061 100644
--- a/examples/src/main/java/org/apache/ignite/example/storage/VolatilePageMemoryStorageExample.java
+++ b/examples/src/main/java/org/apache/ignite/example/storage/VolatilePageMemoryStorageExample.java
@@ -43,7 +43,7 @@ import java.sql.Statement;
  *     </li>
  *     <li>
  *         Add configuration for in-memory data region of of the PageMemory storage engine using the CLI tool (if not done yet):<br>
- *         {@code ignite config set --type=cluster "pageMemory.regions.in-memory:{persistent=false}"}
+ *         {@code ignite cluster config update "pageMemory.regions.in-memory:{persistent=false}"}
  *     </li>
  *     <li>Run the example in the IDE.</li>
  *     <li>
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/CollectionUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/CollectionUtils.java
index a20b82393..5002ac5e3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/CollectionUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/CollectionUtils.java
@@ -36,12 +36,16 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Utility class provides various method to work with collections.
  */
 public final class CollectionUtils {
+    /** Special object for determining that there is no next element. */
+    private static final Object NO_NEXT_ELEMENT = new Object();
+
     /** Stub. */
     private CollectionUtils() {
         // No op.
@@ -387,6 +391,101 @@ public final class CollectionUtils {
         };
     }
 
+    /**
+     * Create a collection view that can only be read.
+     *
+     * @param collection Basic collection.
+     * @param mapper Conversion function.
+     * @param predicate Predicate to apply to each element of basic collection.
+     * @param <T1> Base type of the collection.
+     * @param <T2> Type for view.
+     * @return Read-only collection view.
+     */
+    public static <T1, T2> Collection<T2> viewReadOnly(
+            @Nullable Collection<? extends T1> collection,
+            @Nullable Function<? super T1, ? extends T2> mapper,
+            @Nullable Predicate<? super T1> predicate
+    ) {
+        if (collection == null) {
+            return emptyList();
+        }
+
+        if (mapper == null && predicate == null) {
+            return unmodifiableCollection((Collection<T2>) collection);
+        }
+
+        return new AbstractCollection<>() {
+            /** {@inheritDoc} */
+            @Override
+            public Iterator<T2> iterator() {
+                Iterator<? extends T1> iterator = collection.iterator();
+
+                return new Iterator<>() {
+                    @Nullable
+                    T1 current = advance();
+
+                    /** {@inheritDoc} */
+                    @Override
+                    public boolean hasNext() {
+                        return current != NO_NEXT_ELEMENT;
+                    }
+
+                    /** {@inheritDoc} */
+                    @Override
+                    public T2 next() {
+                        T1 current = this.current;
+
+                        if (current == NO_NEXT_ELEMENT) {
+                            throw new NoSuchElementException();
+                        }
+
+                        this.current = advance();
+
+                        return mapper == null ? (T2) current : mapper.apply(current);
+                    }
+
+                    private @Nullable T1 advance() {
+                        while (iterator.hasNext()) {
+                            T1 next = iterator.next();
+
+                            if (predicate == null || predicate.test(next)) {
+                                return next;
+                            }
+                        }
+
+                        return (T1) NO_NEXT_ELEMENT;
+                    }
+                };
+            }
+
+            /** {@inheritDoc} */
+            @Override
+            public int size() {
+                if (predicate == null) {
+                    return collection.size();
+                }
+
+                int count = 0;
+
+                for (Iterator<T2> iterator = iterator(); iterator.hasNext(); iterator.next()) {
+                    count++;
+                }
+
+                return count;
+            }
+
+            /** {@inheritDoc} */
+            @Override
+            public boolean isEmpty() {
+                if (predicate == null) {
+                    return collection.isEmpty();
+                }
+
+                return size() == 0;
+            }
+        };
+    }
+
     /**
      * Difference of two sets.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/CollectionUtilsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/CollectionUtilsTest.java
index 39878bf72..41c1835db 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/util/CollectionUtilsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/util/CollectionUtilsTest.java
@@ -25,6 +25,7 @@ import static org.apache.ignite.internal.util.CollectionUtils.difference;
 import static org.apache.ignite.internal.util.CollectionUtils.setOf;
 import static org.apache.ignite.internal.util.CollectionUtils.union;
 import static org.apache.ignite.internal.util.CollectionUtils.viewReadOnly;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -38,6 +39,8 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterators;
 import java.util.stream.StreamSupport;
@@ -97,6 +100,64 @@ public class CollectionUtilsTest {
         assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null).iterator().remove());
     }
 
+    @Test
+    void testViewReadOnlyWithPredicate() {
+        assertTrue(viewReadOnly(null, null, null).isEmpty());
+        assertTrue(viewReadOnly(List.of(), null, null).isEmpty());
+
+        assertEquals(List.of(1), collect(viewReadOnly(List.of(1), null, null)));
+        assertEquals(List.of(1), collect(viewReadOnly(List.of(1), identity(), null)));
+        assertEquals(List.of(1), collect(viewReadOnly(List.of(1), null, integer -> true)));
+        assertEquals(List.of(1), collect(viewReadOnly(List.of(1), identity(), integer -> true)));
+        assertEquals(List.of(), collect(viewReadOnly(List.of(1), null, integer -> false)));
+        assertEquals(List.of(), collect(viewReadOnly(List.of(1), identity(), integer -> false)));
+
+        assertEquals(List.of("1", "2", "3"), collect(viewReadOnly(List.of(1, 2, 3), String::valueOf, null)));
+        assertEquals(List.of("3"), collect(viewReadOnly(List.of(1, 2, 3), String::valueOf, integer -> integer > 2)));
+
+        assertEquals(4, viewReadOnly(List.of(1, 2, 3, 4), String::valueOf, integer -> true).size());
+        assertEquals(4, viewReadOnly(List.of(1, 2, 3, 4), String::valueOf, null).size());
+        assertEquals(2, viewReadOnly(List.of(1, 2, 3, 4), identity(), integer -> integer < 3).size());
+        assertEquals(0, viewReadOnly(List.of(1, 2, 3, 4), identity(), integer -> false).size());
+
+        assertFalse(viewReadOnly(List.of(1, 2, 3, 4), String::valueOf, integer -> true).isEmpty());
+        assertFalse(viewReadOnly(List.of(1, 2, 3, 4), String::valueOf, null).isEmpty());
+        assertFalse(viewReadOnly(List.of(1, 2, 3, 4), identity(), integer -> integer > 3).isEmpty());
+        assertTrue(viewReadOnly(List.of(1, 2, 3, 4), identity(), integer -> integer > 4).isEmpty());
+        assertTrue(viewReadOnly(List.of(1, 2, 3, 4), identity(), integer -> false).isEmpty());
+
+        assertDoesNotThrow(() -> viewReadOnly(Arrays.asList(new Integer[]{null}), null, null).iterator().next());
+        assertDoesNotThrow(() -> viewReadOnly(Arrays.asList(new Integer[]{null}), null, integer -> true).iterator().next());
+        assertDoesNotThrow(() -> viewReadOnly(Arrays.asList(null, 1), null, null).iterator().next());
+        assertDoesNotThrow(() -> viewReadOnly(Arrays.asList(null, 1), null, integer -> true).iterator().next());
+
+        assertThrows(
+                NoSuchElementException.class,
+                () -> viewReadOnly(Arrays.asList(new Integer[]{null}), null, integer -> false).iterator().next()
+        );
+
+        assertThrows(
+                NoSuchElementException.class,
+                () -> {
+                    Iterator<Object> iterator = viewReadOnly(Arrays.asList(null, 1), null, Objects::nonNull).iterator();
+                    iterator.next();
+                    iterator.next();
+                }
+        );
+
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).add(1));
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).addAll(List.of()));
+
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).remove(1));
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).removeAll(List.of()));
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).removeIf(o -> true));
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).clear());
+
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).retainAll(List.of()));
+
+        assertThrows(UnsupportedOperationException.class, () -> viewReadOnly(List.of(1), null, null).iterator().remove());
+    }
+
     @Test
     void testSetDifference() {
         assertTrue(difference(null, Set.of(1, 2, 3, 4)).isEmpty());
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 09fba505f..67cf58768 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
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.pagememory.persistence;
 
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.ignite.internal.pagememory.PageMemoryTestUtils.newDataRegion;
 import static org.apache.ignite.internal.pagememory.persistence.PageMemoryImpl.PAGE_OVERHEAD;
@@ -121,7 +120,7 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest {
             checkpointManager
                     .forceCheckpoint("for_test_flash_dirty_pages")
                     .futureFor(FINISHED)
-                    .get(100, MILLISECONDS);
+                    .get(1, SECONDS);
 
             assertThat(pageMemoryImpl.dirtyPages(), empty());
         } finally {
@@ -193,7 +192,7 @@ public class PageMemoryImplNoLoadTest extends PageMemoryNoLoadSelfTest {
             checkpointManager
                     .forceCheckpoint("for_test_safe_to_update")
                     .futureFor(FINISHED)
-                    .get(100, MILLISECONDS);
+                    .get(1, SECONDS);
 
             assertTrue(pageMemoryImpl.safeToUpdate());
         } finally {
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItNoThreadsLeftTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItNoThreadsLeftTest.java
index 0274546a9..c53877fc4 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItNoThreadsLeftTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/ItNoThreadsLeftTest.java
@@ -55,7 +55,8 @@ public class ItNoThreadsLeftTest extends IgniteAbstractTest {
             "ForkJoinPool",
             "process reaper",
             "CompletableFutureDelayScheduler",
-            "parallel"
+            "parallel",
+            "FastTimestamps updater"
     );
 
     /** One node cluster configuration. */
@@ -85,7 +86,7 @@ public class ItNoThreadsLeftTest extends IgniteAbstractTest {
             stopNode(testInfo);
         }
 
-        boolean threadsKilled = waitForCondition(() -> getCurrentThreads().size() <= threadsBefore.size(), 3_000);
+        boolean threadsKilled = waitForCondition(() -> getCurrentThreads().size() <= threadsBefore.size(), 10, 3_000);
 
         if (!threadsKilled) {
             String leakedThreadNames = getCurrentThreads().stream()
diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
index 62d688126..b6e43215e 100644
--- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
+++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/AbstractPageMemoryTableStorage.java
@@ -81,36 +81,7 @@ public abstract class AbstractPageMemoryTableStorage implements TableStorage {
     /** {@inheritDoc} */
     @Override
     public void stop() throws StorageException {
-        started = false;
-
-        List<AutoCloseable> autoCloseables = new ArrayList<>(this.autoCloseables);
-
-        for (int i = 0; i < partitions.length(); i++) {
-            PartitionStorage partition = partitions.getAndUpdate(i, p -> null);
-
-            if (partition != null) {
-                autoCloseables.add(partition);
-            }
-
-            autoCloseables.add(partition);
-        }
-
-        Collections.reverse(autoCloseables);
-
-        try {
-            IgniteUtils.closeAll(autoCloseables);
-        } catch (Exception e) {
-            throw new StorageException("Failed to stop PageMemory table storage.", e);
-        }
-
-        this.autoCloseables.clear();
-        partitions = null;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void destroy() throws StorageException {
-        stop();
+        close(false);
     }
 
     /** {@inheritDoc} */
@@ -192,4 +163,35 @@ public abstract class AbstractPageMemoryTableStorage implements TableStorage {
                 ((VolatilePageMemoryDataRegion) dataRegion).rowVersionFreeList()
         );
     }
+
+    /**
+     * Closes all {@link #partitions} and {@link #autoCloseables}.
+     *
+     * @param destroy Destroy partitions.
+     * @throws StorageException If failed.
+     */
+    protected void close(boolean destroy) throws StorageException {
+        started = false;
+
+        List<AutoCloseable> autoCloseables = new ArrayList<>(this.autoCloseables);
+
+        for (int i = 0; i < partitions.length(); i++) {
+            PartitionStorage partition = partitions.getAndUpdate(i, p -> null);
+
+            if (partition != null) {
+                autoCloseables.add(destroy ? partition::destroy : partition);
+            }
+        }
+
+        Collections.reverse(autoCloseables);
+
+        try {
+            IgniteUtils.closeAll(autoCloseables);
+        } catch (Exception e) {
+            throw new StorageException("Failed to stop PageMemory table storage.", e);
+        }
+
+        this.autoCloseables.clear();
+        partitions = null;
+    }
 }
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 91e4e912b..a31e4bf1b 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,6 +18,7 @@
 package org.apache.ignite.internal.storage.pagememory;
 
 import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.apache.ignite.internal.util.CollectionUtils.viewReadOnly;
 import static org.apache.ignite.internal.util.IgniteUtils.closeAll;
 
 import java.nio.file.Path;
@@ -127,7 +128,7 @@ public class PageMemoryStorageEngine implements StorageEngine {
                     longJvmPauseDetector,
                     engineConfig.checkpoint(),
                     filePageStoreManager,
-                    regions.values(),
+                    viewReadOnly(regions.values(), null, AbstractPageMemoryDataRegion::persistent),
                     storagePath,
                     pageSize
             );
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
index dfbb71a66..0a83869c2 100644
--- 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
@@ -26,6 +26,8 @@ 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.apache.ignite.internal.util.IgniteCursor;
+import org.apache.ignite.lang.IgniteInternalCheckedException;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -144,7 +146,19 @@ public class PersistentPageMemoryPartitionStorage extends VolatilePageMemoryPart
         checkpointTimeoutLock.checkpointReadLock();
 
         try {
-            super.destroy();
+            // TODO: IGNITE-17132 Fix partition destruction
+
+            IgniteCursor<TableDataRow> cursor = tree.find(null, null);
+
+            while (cursor.next()) {
+                TableDataRow row = cursor.get();
+
+                if (tree.removex(row)) {
+                    freeList.removeDataRowByLink(row.link());
+                }
+            }
+        } catch (IgniteInternalCheckedException e) {
+            throw new StorageException("Error destroy partition: " + partId, e);
         } 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
index 930ea4717..d448e16e5 100644
--- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
+++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/PersistentPageMemoryTableStorage.java
@@ -96,6 +96,12 @@ class PersistentPageMemoryTableStorage extends AbstractPageMemoryTableStorage {
         }
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public void destroy() throws StorageException {
+        close(true);
+    }
+
     /**
      * Initializes the partition file page store if it hasn't already.
      *
diff --git a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java
index 483b1a276..5451bc810 100644
--- a/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java
+++ b/modules/storage-page-memory/src/main/java/org/apache/ignite/internal/storage/pagememory/VolatilePageMemoryPartitionStorage.java
@@ -48,11 +48,11 @@ import org.jetbrains.annotations.Nullable;
  */
 // TODO: IGNITE-16644 Support snapshots.
 class VolatilePageMemoryPartitionStorage implements PartitionStorage {
-    private final int partId;
+    protected final int partId;
 
-    private final TableTree tree;
+    protected final TableTree tree;
 
-    private final TableFreeList freeList;
+    protected final TableFreeList freeList;
 
     /**
      * Constructor.
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 b6c9acda3..ec0f087f9 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
@@ -55,6 +55,12 @@ class VolatilePageMemoryTableStorage extends AbstractPageMemoryTableStorage {
         );
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public void destroy() throws StorageException {
+        stop();
+    }
+
     /**
      * Returns new {@link TableTree} instance for partition.
      *