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

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


The following commit(s) were added to refs/heads/main by this push:
     new f3a1f9dd75 IGNITE-19737 
TestMvStorageUpdateHandlerTest.testConcurrentExecuteBatchGc is flacky (#2197)
f3a1f9dd75 is described below

commit f3a1f9dd75b05255ebb26173c22b29317047064b
Author: Kirill Tkalenko <[email protected]>
AuthorDate: Fri Jun 16 14:50:36 2023 +0300

    IGNITE-19737 TestMvStorageUpdateHandlerTest.testConcurrentExecuteBatchGc is 
flacky (#2197)
---
 .../storage/impl/TestMvPartitionStorage.java       |  15 +-
 .../table/distributed/StorageUpdateHandler.java    |   2 +-
 .../table/distributed/gc/GcUpdateHandler.java      |  75 +++++--
 .../internal/table/distributed/gc/IntHolder.java}  |  36 +++-
 .../ignite/internal/table/distributed/gc/MvGc.java |   4 +-
 .../AbstractMvStorageUpdateHandlerTest.java        | 139 -------------
 .../internal/table/distributed/IndexGcTest.java    |  22 +-
 .../gc/AbstractGcUpdateHandlerTest.java            | 225 +++++++++++++++++++++
 .../table/distributed/gc/GcUpdateHandlerTest.java  | 143 -------------
 .../internal/table/distributed/gc/MvGcTest.java    |   9 +-
 .../PersistentPageMemoryGcUpdateHandlerTest.java}  |   4 +-
 .../RocksDbGcUpdateHandlerTest.java}               |   4 +-
 .../TestGcUpdateHandlerTest.java}                  |   4 +-
 .../VolatilePageMemoryGcUpdateHandlerTest.java}    |   4 +-
 14 files changed, 346 insertions(+), 340 deletions(-)

diff --git 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/impl/TestMvPartitionStorage.java
 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/impl/TestMvPartitionStorage.java
index ba81744ea8..2f2306a3ac 100644
--- 
a/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/impl/TestMvPartitionStorage.java
+++ 
b/modules/storage-api/src/testFixtures/java/org/apache/ignite/internal/storage/impl/TestMvPartitionStorage.java
@@ -528,6 +528,8 @@ public class TestMvPartitionStorage implements 
MvPartitionStorage {
 
     @Override
     public synchronized @Nullable GcEntry peek(HybridTimestamp lowWatermark) {
+        assert THREAD_LOCAL_LOCKER.get() != null;
+
         try {
             VersionChain versionChain = gcQueue.first();
 
@@ -543,16 +545,19 @@ public class TestMvPartitionStorage implements 
MvPartitionStorage {
 
     @Override
     public synchronized @Nullable BinaryRow vacuum(GcEntry entry) {
+        assert THREAD_LOCAL_LOCKER.get() != null;
+        assert THREAD_LOCAL_LOCKER.get().isLocked(entry.getRowId());
+
         checkStorageClosedOrInProcessOfRebalance();
 
-        Iterator<VersionChain> it = gcQueue.iterator();
+        VersionChain dequeuedVersionChain;
 
-        if (!it.hasNext()) {
+        try {
+            dequeuedVersionChain = gcQueue.first();
+        } catch (NoSuchElementException e) {
             return null;
         }
 
-        VersionChain dequeuedVersionChain = it.next();
-
         if (dequeuedVersionChain != entry) {
             return null;
         }
@@ -564,7 +569,7 @@ public class TestMvPartitionStorage implements 
MvPartitionStorage {
         assert versionChainToRemove.next == null;
 
         dequeuedVersionChain.next = null;
-        it.remove();
+        gcQueue.remove(dequeuedVersionChain);
 
         // Tombstones must be deleted.
         if (dequeuedVersionChain.row == null) {
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandler.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandler.java
index 9da8aaf775..bbea32ec18 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandler.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/StorageUpdateHandler.java
@@ -202,7 +202,7 @@ public class StorageUpdateHandler {
             return;
         }
 
-        gcUpdateHandler.vacuumBatch(lwm, gcConfig.onUpdateBatchSize().value());
+        gcUpdateHandler.vacuumBatch(lwm, gcConfig.onUpdateBatchSize().value(), 
false);
     }
 
     /**
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandler.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandler.java
index b976075d75..8475849880 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandler.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandler.java
@@ -20,7 +20,6 @@ package org.apache.ignite.internal.table.distributed.gc;
 import org.apache.ignite.internal.hlc.HybridTimestamp;
 import org.apache.ignite.internal.schema.BinaryRow;
 import org.apache.ignite.internal.storage.MvPartitionStorage.Locker;
-import org.apache.ignite.internal.storage.MvPartitionStorage.WriteClosure;
 import org.apache.ignite.internal.storage.ReadResult;
 import org.apache.ignite.internal.storage.RowId;
 import org.apache.ignite.internal.storage.gc.GcEntry;
@@ -69,41 +68,75 @@ public class GcUpdateHandler {
      *
      * @param lowWatermark Low watermark for the vacuum.
      * @param count Count of entries to GC.
+     * @param strict {@code true} if needed to remove the strictly passed 
{@code count} oldest stale entries, {@code false} if a premature
+     *      exit is allowed when it is not possible to acquire a lock for the 
{@link RowId}.
      * @return {@code False} if there is no garbage left in the storage.
      */
-    public boolean vacuumBatch(HybridTimestamp lowWatermark, int count) {
+    public boolean vacuumBatch(HybridTimestamp lowWatermark, int count, 
boolean strict) {
+        if (count <= 0) {
+            return true;
+        }
+
+        IntHolder countHolder = new IntHolder(count);
+
+        while (countHolder.get() > 0) {
+            VacuumResult vacuumResult = internalVacuumBatch(lowWatermark, 
countHolder);
+
+            switch (vacuumResult) {
+                case NO_GARBAGE_LEFT:
+                    return false;
+                case SUCCESS:
+                    return true;
+                case FAILED_ACQUIRE_LOCK:
+                    if (strict) {
+                        continue;
+                    }
+
+                    return true;
+                default:
+                    throw new IllegalStateException(vacuumResult.toString());
+            }
+        }
+
+        return true;
+    }
+
+    private VacuumResult internalVacuumBatch(HybridTimestamp lowWatermark, 
IntHolder countHolder) {
         return storage.runConsistently(locker -> {
+            int count = countHolder.get();
+
             for (int i = 0; i < count; i++) {
-                if (!internalVacuum(lowWatermark, locker)) {
-                    return false;
+                // It is safe for the first iteration to use a lock instead of 
tryLock, since there will be no deadlock for the first RowId
+                // and a deadlock may happen with subsequent ones.
+                VacuumResult vacuumResult = internalVacuum(lowWatermark, 
locker, i > 0);
+
+                if (vacuumResult != VacuumResult.SUCCESS) {
+                    return vacuumResult;
                 }
+
+                countHolder.getAndDecrement();
             }
 
-            return true;
+            return VacuumResult.SUCCESS;
         });
     }
 
-    /**
-     * Attempts to collect garbage for one {@link RowId}.
-     *
-     * <p>Must be called inside a {@link 
PartitionDataStorage#runConsistently(WriteClosure)} closure.
-     *
-     * @param lowWatermark Low watermark for the vacuum.
-     * @param locker From {@link 
PartitionDataStorage#runConsistently(WriteClosure)}.
-     * @return {@code False} if there is no garbage left in the {@link 
#storage}.
-     */
-    private boolean internalVacuum(HybridTimestamp lowWatermark, Locker 
locker) {
+    private VacuumResult internalVacuum(HybridTimestamp lowWatermark, Locker 
locker, boolean useTryLock) {
         while (true) {
             GcEntry gcEntry = storage.peek(lowWatermark);
 
             if (gcEntry == null) {
-                return false;
+                return VacuumResult.NO_GARBAGE_LEFT;
             }
 
             RowId rowId = gcEntry.getRowId();
 
-            if (!locker.tryLock(rowId)) {
-                return true;
+            if (useTryLock) {
+                if (!locker.tryLock(rowId)) {
+                    return VacuumResult.FAILED_ACQUIRE_LOCK;
+                }
+            } else {
+                locker.lock(rowId);
             }
 
             BinaryRow binaryRow = storage.vacuum(gcEntry);
@@ -117,7 +150,11 @@ public class GcUpdateHandler {
                 indexUpdateHandler.tryRemoveFromIndexes(binaryRow, rowId, 
cursor);
             }
 
-            return true;
+            return VacuumResult.SUCCESS;
         }
     }
+
+    private enum VacuumResult {
+        SUCCESS, NO_GARBAGE_LEFT, FAILED_ACQUIRE_LOCK
+    }
 }
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/IntHolder.java
similarity index 58%
copy from 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
copy to 
modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/IntHolder.java
index aebcf89b52..6a759d0f0f 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/IntHolder.java
@@ -15,16 +15,36 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.table.distributed;
+package org.apache.ignite.internal.table.distributed.gc;
 
-import static 
org.apache.ignite.internal.distributionzones.DistributionZoneManager.DEFAULT_PARTITION_COUNT;
+/**
+ * Non-thread-safe {@code int} holder with the ability to update the number.
+ */
+class IntHolder {
+    private int value;
+
+    /**
+     * Constructor.
+     *
+     * @param value Value.
+     */
+    IntHolder(int value) {
+        this.value = value;
+    }
 
-import org.apache.ignite.internal.storage.impl.TestMvTableStorage;
-import org.junit.jupiter.api.BeforeEach;
+    /**
+     * Returns the current value.
+     */
+    int get() {
+        return value;
+    }
 
-class TestMvStorageUpdateHandlerTest extends 
AbstractMvStorageUpdateHandlerTest {
-    @BeforeEach
-    void setUp() {
-        initialize(new TestMvTableStorage(1, DEFAULT_PARTITION_COUNT));
+    /**
+     * Decrements the current value, equivalent to {@code value--}.
+     *
+     * @return Previous value.
+     */
+    int getAndDecrement() {
+        return value--;
     }
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/MvGc.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/MvGc.java
index 4840827a59..0d2d9defbc 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/MvGc.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/gc/MvGc.java
@@ -47,7 +47,7 @@ import org.jetbrains.annotations.TestOnly;
 /**
  * Garbage collector for multi-versioned storages and their indexes in the 
background.
  *
- * @see GcUpdateHandler#vacuumBatch(HybridTimestamp, int)
+ * @see GcUpdateHandler#vacuumBatch(HybridTimestamp, int, boolean)
  */
 public class MvGc implements ManuallyCloseable {
     private static final IgniteLogger LOG = Loggers.forClass(MvGc.class);
@@ -242,7 +242,7 @@ public class MvGc implements ManuallyCloseable {
                 // We can only start garbage collection when the partition 
safe time is reached.
                 gcUpdateHandler.getSafeTimeTracker()
                         .waitFor(lowWatermark)
-                        .thenApplyAsync(unused -> 
gcUpdateHandler.vacuumBatch(lowWatermark, GC_BATCH_SIZE), executor)
+                        .thenApplyAsync(unused -> 
gcUpdateHandler.vacuumBatch(lowWatermark, GC_BATCH_SIZE, true), executor)
                         .whenComplete((isGarbageLeft, throwable) -> {
                             if (throwable != null) {
                                 if (throwable instanceof TrackerClosedException
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/AbstractMvStorageUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/AbstractMvStorageUpdateHandlerTest.java
deleted file mode 100644
index 6e56bcbf98..0000000000
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/AbstractMvStorageUpdateHandlerTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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.table.distributed;
-
-import static org.apache.ignite.internal.testframework.IgniteTestUtils.runRace;
-import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willSucceedFast;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.Mockito.when;
-
-import java.util.Map;
-import java.util.UUID;
-import org.apache.ignite.distributed.TestPartitionDataStorage;
-import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
-import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
-import org.apache.ignite.internal.hlc.HybridTimestamp;
-import org.apache.ignite.internal.schema.BinaryRow;
-import org.apache.ignite.internal.schema.configuration.GcConfiguration;
-import org.apache.ignite.internal.storage.BaseMvStoragesTest;
-import org.apache.ignite.internal.storage.MvPartitionStorage;
-import org.apache.ignite.internal.storage.RowId;
-import org.apache.ignite.internal.storage.engine.MvTableStorage;
-import org.apache.ignite.internal.table.distributed.gc.GcUpdateHandler;
-import org.apache.ignite.internal.table.distributed.index.IndexUpdateHandler;
-import org.apache.ignite.internal.table.distributed.raft.PartitionDataStorage;
-import org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
-import org.apache.ignite.internal.util.PendingComparableValuesTracker;
-import org.jetbrains.annotations.Nullable;
-import org.junit.jupiter.api.RepeatedTest;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-/**
- * Abstract class for testing {@link StorageUpdateHandler} using different 
implementations of {@link MvPartitionStorage}.
- */
-@ExtendWith(MockitoExtension.class)
-@ExtendWith(ConfigurationExtension.class)
-abstract class AbstractMvStorageUpdateHandlerTest extends BaseMvStoragesTest {
-    /** To be used in a loop. {@link RepeatedTest} has a smaller failure rate 
due to recreating the storage every time. */
-    private static final int REPEATS = 100;
-
-    private static final int PARTITION_ID = 0;
-
-    private TestPartitionDataStorage partitionDataStorage;
-
-    private StorageUpdateHandler storageUpdateHandler;
-
-    @Mock
-    private LowWatermark lowWatermark;
-
-    @InjectConfiguration
-    private GcConfiguration gcConfig;
-
-    /**
-     * Initializes the internal structures needed for tests.
-     *
-     * <p>This method *MUST* always be called in either subclass' constructor 
or setUp method.
-     */
-    final void initialize(MvTableStorage tableStorage) {
-        MvPartitionStorage partitionStorage = 
getOrCreateMvPartition(tableStorage, PARTITION_ID);
-
-        partitionDataStorage = new TestPartitionDataStorage(partitionStorage);
-
-        IndexUpdateHandler indexUpdateHandler = new 
IndexUpdateHandler(DummyInternalTableImpl.createTableIndexStoragesSupplier(Map.of()));
-
-        storageUpdateHandler = new StorageUpdateHandler(
-                PARTITION_ID,
-                partitionDataStorage,
-                gcConfig,
-                lowWatermark,
-                indexUpdateHandler,
-                new GcUpdateHandler(
-                        partitionDataStorage,
-                        new 
PendingComparableValuesTracker<>(HybridTimestamp.MAX_VALUE),
-                        indexUpdateHandler
-                )
-        );
-    }
-
-    @Test
-    void testConcurrentExecuteBatchGc() {
-        assertThat(gcConfig.onUpdateBatchSize().update(4), willSucceedFast());
-
-        
when(lowWatermark.getLowWatermark()).thenReturn(HybridTimestamp.MAX_VALUE);
-
-        RowId rowId0 = new RowId(PARTITION_ID);
-        RowId rowId1 = new RowId(PARTITION_ID);
-
-        BinaryRow row0 = binaryRow(new TestKey(0, "key0"), new TestValue(0, 
"value0"));
-        BinaryRow row1 = binaryRow(new TestKey(0, "key0"), new TestValue(0, 
"value0"));
-
-        for (int i = 0; i < REPEATS; i++) {
-            addWriteCommitted(partitionDataStorage, rowId0, row0, clock.now());
-            addWriteCommitted(partitionDataStorage, rowId1, row1, clock.now());
-
-            addWriteCommitted(partitionDataStorage, rowId0, row0, clock.now());
-            addWriteCommitted(partitionDataStorage, rowId1, row1, clock.now());
-
-            addWriteCommitted(partitionDataStorage, rowId0, null, clock.now());
-            addWriteCommitted(partitionDataStorage, rowId1, null, clock.now());
-
-            runRace(
-                    () -> storageUpdateHandler.executeBatchGc(),
-                    () -> storageUpdateHandler.executeBatchGc()
-            );
-
-            
assertNull(partitionDataStorage.getStorage().closestRowId(RowId.lowestRowId(PARTITION_ID)));
-        }
-    }
-
-    private static void addWriteCommitted(PartitionDataStorage storage, RowId 
rowId, @Nullable BinaryRow row, HybridTimestamp timestamp) {
-        storage.runConsistently(locker -> {
-            locker.lock(rowId);
-
-            storage.addWrite(rowId, row, UUID.randomUUID(), 999, PARTITION_ID);
-
-            storage.commitWrite(rowId, timestamp);
-
-            return null;
-        });
-    }
-}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexGcTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexGcTest.java
index 498f4edefe..669b69bea8 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexGcTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/IndexGcTest.java
@@ -42,7 +42,7 @@ public class IndexGcTest extends IndexBaseTest {
         addWrite(storageUpdateHandler, rowUuid, row);
         commitWrite(rowId);
 
-        assertTrue(gcUpdateHandler.vacuumBatch(now(), 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(now(), 1, true));
 
         assertEquals(1, getRowVersions(rowId).size());
         // Newer entry has the same index value, so it should not be removed.
@@ -70,13 +70,13 @@ public class IndexGcTest extends IndexBaseTest {
 
         HybridTimestamp afterCommits = now();
 
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
 
         // row1 should still be in the index, because second write was 
identical to the first.
         assertTrue(inAllIndexes(row1));
 
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
-        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
+        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
 
         assertEquals(1, getRowVersions(rowId).size());
         // Older entries have different indexes, should be removed.
@@ -103,8 +103,8 @@ public class IndexGcTest extends IndexBaseTest {
 
         HybridTimestamp afterCommits = now();
 
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
-        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
+        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
 
         assertEquals(0, getRowVersions(rowId).size());
         // The last entry was a tombstone, so no indexes should be left.
@@ -129,8 +129,8 @@ public class IndexGcTest extends IndexBaseTest {
 
         HybridTimestamp afterCommits = now();
 
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
-        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
+        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
 
         assertEquals(1, getRowVersions(rowId).size());
         assertTrue(inAllIndexes(row));
@@ -154,9 +154,9 @@ public class IndexGcTest extends IndexBaseTest {
 
         HybridTimestamp afterCommits = now();
 
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
-        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1));
-        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
+        assertTrue(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
+        assertFalse(gcUpdateHandler.vacuumBatch(afterCommits, 1, true));
 
         assertEquals(0, getRowVersions(rowId).size());
         assertTrue(notInAnyIndex(row));
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/AbstractGcUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/AbstractGcUpdateHandlerTest.java
new file mode 100644
index 0000000000..9fddeb950a
--- /dev/null
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/AbstractGcUpdateHandlerTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.table.distributed.gc;
+
+import static org.apache.ignite.internal.testframework.IgniteTestUtils.runRace;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.distributed.TestPartitionDataStorage;
+import org.apache.ignite.internal.hlc.HybridTimestamp;
+import org.apache.ignite.internal.schema.BinaryRow;
+import org.apache.ignite.internal.storage.BaseMvStoragesTest;
+import org.apache.ignite.internal.storage.MvPartitionStorage;
+import org.apache.ignite.internal.storage.RowId;
+import org.apache.ignite.internal.storage.engine.MvTableStorage;
+import org.apache.ignite.internal.table.distributed.index.IndexUpdateHandler;
+import org.apache.ignite.internal.table.distributed.raft.PartitionDataStorage;
+import org.apache.ignite.internal.table.impl.DummyInternalTableImpl;
+import org.apache.ignite.internal.util.PendingComparableValuesTracker;
+import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.RepeatedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * Abstract class for testing {@link GcUpdateHandler} using different 
implementations of {@link MvPartitionStorage}.
+ */
+abstract class AbstractGcUpdateHandlerTest extends BaseMvStoragesTest {
+    /** To be used in a loop. {@link RepeatedTest} has a smaller failure rate 
due to recreating the storage every time. */
+    private static final int REPEATS = 1000;
+
+    private static final int PARTITION_ID = 0;
+
+    private MvTableStorage tableStorage;
+
+    /**
+     * Initializes the internal structures needed for tests.
+     *
+     * <p>This method *MUST* always be called in either subclass' constructor 
or setUp method.
+     */
+    final void initialize(MvTableStorage tableStorage) {
+        this.tableStorage = tableStorage;
+    }
+
+    @ParameterizedTest(name = "strict : {0}")
+    @ValueSource(booleans = {true, false})
+    void testVacuum(boolean strict) {
+        TestPartitionDataStorage partitionStorage = 
spy(createPartitionDataStorage());
+        IndexUpdateHandler indexUpdateHandler = 
spy(createIndexUpdateHandler());
+
+        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
+
+        HybridTimestamp lowWatermark = HybridTimestamp.MAX_VALUE;
+
+        assertFalse(gcUpdateHandler.vacuumBatch(lowWatermark, 1, strict));
+        verify(partitionStorage).peek(lowWatermark);
+
+        // Let's check that StorageUpdateHandler#vacuumBatch returns true.
+        clearInvocations(partitionStorage);
+
+        RowId rowId = new RowId(PARTITION_ID);
+        BinaryRow row = binaryRow(new TestKey(0, "key"), new TestValue(0, 
"value"));
+
+        addWriteCommitted(partitionStorage, rowId, row, clock.now());
+        addWriteCommitted(partitionStorage, rowId, row, clock.now());
+
+        assertTrue(gcUpdateHandler.vacuumBatch(lowWatermark, 1, strict));
+        verify(partitionStorage).peek(lowWatermark);
+        verify(indexUpdateHandler).tryRemoveFromIndexes(any(), eq(rowId), 
any());
+    }
+
+    @ParameterizedTest(name = "strict : {0}")
+    @ValueSource(booleans = {true, false})
+    void testVacuumBatch(boolean strict) {
+        TestPartitionDataStorage partitionStorage = 
spy(createPartitionDataStorage());
+        IndexUpdateHandler indexUpdateHandler = 
spy(createIndexUpdateHandler());
+
+        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
+
+        HybridTimestamp lowWatermark = HybridTimestamp.MAX_VALUE;
+
+        RowId rowId0 = new RowId(PARTITION_ID);
+        RowId rowId1 = new RowId(PARTITION_ID);
+
+        BinaryRow row0 = binaryRow(new TestKey(0, "key0"), new TestValue(0, 
"value0"));
+        BinaryRow row1 = binaryRow(new TestKey(0, "key1"), new TestValue(0, 
"value0"));
+
+        addWriteCommitted(partitionStorage, rowId0, row0, clock.now());
+        addWriteCommitted(partitionStorage, rowId0, row0, clock.now());
+
+        addWriteCommitted(partitionStorage, rowId1, row1, clock.now());
+        addWriteCommitted(partitionStorage, rowId1, row1, clock.now());
+
+        assertFalse(gcUpdateHandler.vacuumBatch(lowWatermark, 5, strict));
+
+        verify(partitionStorage, times(3)).peek(lowWatermark);
+        verify(indexUpdateHandler).tryRemoveFromIndexes(any(), eq(rowId0), 
any());
+        verify(indexUpdateHandler).tryRemoveFromIndexes(any(), eq(rowId1), 
any());
+    }
+
+    @Test
+    void testConcurrentVacuumBatchStrictTrue() {
+        TestPartitionDataStorage partitionStorage = 
createPartitionDataStorage();
+        IndexUpdateHandler indexUpdateHandler = createIndexUpdateHandler();
+
+        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
+
+        RowId rowId0 = new RowId(PARTITION_ID);
+        RowId rowId1 = new RowId(PARTITION_ID);
+
+        BinaryRow row0 = binaryRow(new TestKey(0, "key0"), new TestValue(0, 
"value0"));
+        BinaryRow row1 = binaryRow(new TestKey(1, "key1"), new TestValue(1, 
"value1"));
+
+        for (int i = 0; i < REPEATS; i++) {
+            addWriteCommitted(partitionStorage, rowId0, row0, clock.now());
+            addWriteCommitted(partitionStorage, rowId1, row1, clock.now());
+
+            addWriteCommitted(partitionStorage, rowId0, row0, clock.now());
+            addWriteCommitted(partitionStorage, rowId1, row1, clock.now());
+
+            addWriteCommitted(partitionStorage, rowId0, null, clock.now());
+            addWriteCommitted(partitionStorage, rowId1, null, clock.now());
+
+            runRace(
+                    () -> 
gcUpdateHandler.vacuumBatch(HybridTimestamp.MAX_VALUE, 2, true),
+                    () -> 
gcUpdateHandler.vacuumBatch(HybridTimestamp.MAX_VALUE, 2, true)
+            );
+
+            
assertNull(partitionStorage.getStorage().closestRowId(RowId.lowestRowId(PARTITION_ID)));
+        }
+    }
+
+    @Test
+    void testConcurrentVacuumBatchStrictFalse() {
+        TestPartitionDataStorage partitionStorage = 
createPartitionDataStorage();
+        IndexUpdateHandler indexUpdateHandler = createIndexUpdateHandler();
+
+        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
+
+        RowId rowId0 = new RowId(PARTITION_ID);
+        RowId rowId1 = new RowId(PARTITION_ID);
+        RowId rowId2 = new RowId(PARTITION_ID);
+        RowId rowId3 = new RowId(PARTITION_ID);
+
+        BinaryRow row0 = binaryRow(new TestKey(0, "key0"), new TestValue(0, 
"value0"));
+        BinaryRow row1 = binaryRow(new TestKey(1, "key1"), new TestValue(1, 
"value1"));
+        BinaryRow row2 = binaryRow(new TestKey(2, "key2"), new TestValue(2, 
"value2"));
+        BinaryRow row3 = binaryRow(new TestKey(3, "key3"), new TestValue(3, 
"value3"));
+
+        for (int i = 0; i < REPEATS; i++) {
+            addWriteCommitted(partitionStorage, rowId0, row0, clock.now());
+            addWriteCommitted(partitionStorage, rowId1, row1, clock.now());
+            addWriteCommitted(partitionStorage, rowId2, row2, clock.now());
+            addWriteCommitted(partitionStorage, rowId3, row3, clock.now());
+
+            addWriteCommitted(partitionStorage, rowId0, null, clock.now());
+            addWriteCommitted(partitionStorage, rowId1, null, clock.now());
+            addWriteCommitted(partitionStorage, rowId2, null, clock.now());
+            addWriteCommitted(partitionStorage, rowId3, null, clock.now());
+
+            runRace(
+                    () -> 
gcUpdateHandler.vacuumBatch(HybridTimestamp.MAX_VALUE, 4, false),
+                    () -> 
gcUpdateHandler.vacuumBatch(HybridTimestamp.MAX_VALUE, 4, false)
+            );
+
+            
assertNull(partitionStorage.getStorage().closestRowId(RowId.lowestRowId(PARTITION_ID)));
+        }
+    }
+
+    private TestPartitionDataStorage createPartitionDataStorage() {
+        return new 
TestPartitionDataStorage(getOrCreateMvPartition(tableStorage, PARTITION_ID));
+    }
+
+    private static IndexUpdateHandler createIndexUpdateHandler() {
+        return new 
IndexUpdateHandler(DummyInternalTableImpl.createTableIndexStoragesSupplier(Map.of()));
+    }
+
+    private static GcUpdateHandler createGcUpdateHandler(
+            PartitionDataStorage partitionDataStorage,
+            IndexUpdateHandler indexUpdateHandler
+    ) {
+        return new GcUpdateHandler(
+                partitionDataStorage,
+                new PendingComparableValuesTracker<>(new HybridTimestamp(1, 
0)),
+                indexUpdateHandler
+        );
+    }
+
+    private static void addWriteCommitted(PartitionDataStorage storage, RowId 
rowId, @Nullable BinaryRow row, HybridTimestamp timestamp) {
+        storage.runConsistently(locker -> {
+            locker.lock(rowId);
+
+            storage.addWrite(rowId, row, UUID.randomUUID(), 999, PARTITION_ID);
+
+            storage.commitWrite(rowId, timestamp);
+
+            return null;
+        });
+    }
+}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandlerTest.java
deleted file mode 100644
index ca75d719a5..0000000000
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/GcUpdateHandlerTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.table.distributed.gc;
-
-import static org.apache.ignite.internal.util.CursorUtils.emptyCursor;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.apache.ignite.distributed.TestPartitionDataStorage;
-import org.apache.ignite.internal.hlc.HybridTimestamp;
-import org.apache.ignite.internal.schema.BinaryRow;
-import org.apache.ignite.internal.storage.RowId;
-import org.apache.ignite.internal.storage.gc.GcEntry;
-import org.apache.ignite.internal.storage.impl.TestMvPartitionStorage;
-import org.apache.ignite.internal.table.distributed.TableIndexStoragesSupplier;
-import org.apache.ignite.internal.table.distributed.index.IndexUpdateHandler;
-import org.apache.ignite.internal.table.distributed.raft.PartitionDataStorage;
-import org.apache.ignite.internal.util.PendingComparableValuesTracker;
-import org.junit.jupiter.api.Test;
-
-/**
- * For {@link GcUpdateHandler} testing.
- */
-public class GcUpdateHandlerTest {
-    private static final int PARTITION_ID = 0;
-
-    @Test
-    void testVacuum() {
-        PartitionDataStorage partitionStorage = createPartitionDataStorage();
-
-        IndexUpdateHandler indexUpdateHandler = spy(new 
IndexUpdateHandler(mock(TableIndexStoragesSupplier.class)));
-
-        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
-
-        HybridTimestamp lowWatermark = new HybridTimestamp(100, 100);
-
-        assertFalse(gcUpdateHandler.vacuumBatch(lowWatermark, 1));
-        verify(partitionStorage).peek(lowWatermark);
-
-        // Let's check that StorageUpdateHandler#vacuumBatch returns true.
-        clearInvocations(partitionStorage);
-
-        RowId rowId = new RowId(PARTITION_ID);
-
-        GcEntry gcEntry = new GcEntryImpl(rowId, lowWatermark);
-        BinaryRow binaryRow = mock(BinaryRow.class);
-
-        
when(partitionStorage.scanVersions(any(RowId.class))).thenReturn(emptyCursor());
-        when(partitionStorage.peek(lowWatermark)).thenReturn(gcEntry);
-        when(partitionStorage.vacuum(gcEntry)).thenReturn(binaryRow);
-
-        assertTrue(gcUpdateHandler.vacuumBatch(lowWatermark, 1));
-        verify(partitionStorage).peek(lowWatermark);
-        verify(indexUpdateHandler).tryRemoveFromIndexes(binaryRow, rowId, 
emptyCursor());
-    }
-
-    @Test
-    void testVacuumBatch() {
-        PartitionDataStorage partitionStorage = createPartitionDataStorage();
-
-        IndexUpdateHandler indexUpdateHandler = spy(new 
IndexUpdateHandler(mock(TableIndexStoragesSupplier.class)));
-
-        GcUpdateHandler gcUpdateHandler = 
createGcUpdateHandler(partitionStorage, indexUpdateHandler);
-
-        HybridTimestamp lowWatermark = new HybridTimestamp(100, 100);
-
-        RowId rowId0 = new RowId(PARTITION_ID);
-        RowId rowId1 = new RowId(PARTITION_ID);
-
-        BinaryRow binaryRow0 = mock(BinaryRow.class);
-        BinaryRow binaryRow1 = mock(BinaryRow.class);
-
-        GcEntry gcEntry0 = new GcEntryImpl(rowId0, lowWatermark);
-        GcEntry gcEntry1 = new GcEntryImpl(rowId1, lowWatermark);
-
-        
when(partitionStorage.peek(lowWatermark)).thenReturn(gcEntry0).thenReturn(gcEntry1).thenReturn(null);
-        when(partitionStorage.vacuum(gcEntry0)).thenReturn(binaryRow0);
-        when(partitionStorage.vacuum(gcEntry1)).thenReturn(binaryRow1);
-
-        assertFalse(gcUpdateHandler.vacuumBatch(lowWatermark, 5));
-
-        verify(partitionStorage, times(3)).peek(lowWatermark);
-        verify(partitionStorage).vacuum(gcEntry0);
-        verify(partitionStorage).vacuum(gcEntry1);
-    }
-
-    private GcUpdateHandler createGcUpdateHandler(PartitionDataStorage 
partitionStorage, IndexUpdateHandler indexUpdateHandler) {
-        return new GcUpdateHandler(
-                partitionStorage,
-                new PendingComparableValuesTracker<>(new HybridTimestamp(1, 
0)),
-                indexUpdateHandler
-        );
-    }
-
-    private static PartitionDataStorage createPartitionDataStorage() {
-        PartitionDataStorage partitionStorage = spy(new 
TestPartitionDataStorage(new TestMvPartitionStorage(PARTITION_ID)));
-
-        return partitionStorage;
-    }
-
-    private static class GcEntryImpl implements GcEntry {
-        private final RowId rowId;
-
-        private final HybridTimestamp timestamp;
-
-        private GcEntryImpl(RowId rowId, HybridTimestamp timestamp) {
-            this.rowId = rowId;
-            this.timestamp = timestamp;
-        }
-
-        @Override
-        public RowId getRowId() {
-            return rowId;
-        }
-
-        @Override
-        public HybridTimestamp getTimestamp() {
-            return timestamp;
-        }
-    }
-}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/MvGcTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/MvGcTest.java
index febf9fb402..c4d2268229 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/MvGcTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/MvGcTest.java
@@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -380,7 +381,7 @@ public class MvGcTest {
             CompletableFuture<Void> future,
             @Nullable HybridTimestamp exp
     ) {
-        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), 
anyInt())).then(invocation -> {
+        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), anyInt(), 
eq(true))).then(invocation -> {
             if (exp != null) {
                 try {
                     assertEquals(exp, invocation.getArgument(0));
@@ -400,7 +401,7 @@ public class MvGcTest {
     private GcUpdateHandler createWithCountDownOnVacuum(CountDownLatch latch) {
         GcUpdateHandler gcUpdateHandler = createGcUpdateHandler();
 
-        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), 
anyInt())).then(invocation -> {
+        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), anyInt(), 
eq(true))).then(invocation -> {
             latch.countDown();
 
             return latch.getCount() > 0;
@@ -412,7 +413,7 @@ public class MvGcTest {
     private GcUpdateHandler createWithWaitFinishVacuum(CompletableFuture<Void> 
startFuture, CompletableFuture<Void> finishFuture) {
         GcUpdateHandler gcUpdateHandler = createGcUpdateHandler();
 
-        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), 
anyInt())).then(invocation -> {
+        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), anyInt(), 
eq(true))).then(invocation -> {
             startFuture.complete(null);
 
             finishFuture.get(1, TimeUnit.SECONDS);
@@ -432,7 +433,7 @@ public class MvGcTest {
     private GcUpdateHandler 
createWithCountDownOnVacuumWithoutNextBatch(CountDownLatch latch) {
         GcUpdateHandler gcUpdateHandler = createGcUpdateHandler();
 
-        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), 
anyInt())).then(invocation -> {
+        when(gcUpdateHandler.vacuumBatch(any(HybridTimestamp.class), anyInt(), 
eq(true))).then(invocation -> {
             latch.countDown();
 
             // So that there is no processing of the next batch.
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/PersistentPageMemoryMvStorageUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/PersistentPageMemoryGcUpdateHandlerTest.java
similarity index 95%
rename from 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/PersistentPageMemoryMvStorageUpdateHandlerTest.java
rename to 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/PersistentPageMemoryGcUpdateHandlerTest.java
index 61e27735cd..ca779e840c 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/PersistentPageMemoryMvStorageUpdateHandlerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/PersistentPageMemoryGcUpdateHandlerTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.table.distributed;
+package org.apache.ignite.internal.table.distributed.gc;
 
 import static 
org.apache.ignite.internal.distributionzones.DistributionZoneManager.DEFAULT_PARTITION_COUNT;
 import static 
org.apache.ignite.internal.storage.pagememory.configuration.schema.BasePageMemoryStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME;
@@ -40,7 +40,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(WorkDirectoryExtension.class)
 @ExtendWith(ConfigurationExtension.class)
-class PersistentPageMemoryMvStorageUpdateHandlerTest extends 
AbstractMvStorageUpdateHandlerTest {
+class PersistentPageMemoryGcUpdateHandlerTest extends 
AbstractGcUpdateHandlerTest {
     @WorkDirectory
     private Path workDir;
 
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/RocksDbMvStorageUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/RocksDbGcUpdateHandlerTest.java
similarity index 95%
rename from 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/RocksDbMvStorageUpdateHandlerTest.java
rename to 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/RocksDbGcUpdateHandlerTest.java
index 2ad90e3ffc..e47f5e141a 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/RocksDbMvStorageUpdateHandlerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/RocksDbGcUpdateHandlerTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.table.distributed;
+package org.apache.ignite.internal.table.distributed.gc;
 
 import static 
org.apache.ignite.internal.distributionzones.DistributionZoneManager.DEFAULT_PARTITION_COUNT;
 import static 
org.apache.ignite.internal.storage.pagememory.configuration.schema.BasePageMemoryStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME;
@@ -38,7 +38,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(WorkDirectoryExtension.class)
 @ExtendWith(ConfigurationExtension.class)
-class RocksDbMvStorageUpdateHandlerTest extends 
AbstractMvStorageUpdateHandlerTest {
+class RocksDbGcUpdateHandlerTest extends AbstractGcUpdateHandlerTest {
     @WorkDirectory
     private Path workDir;
 
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/TestGcUpdateHandlerTest.java
similarity index 89%
rename from 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
rename to 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/TestGcUpdateHandlerTest.java
index aebcf89b52..02ea69c9e4 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TestMvStorageUpdateHandlerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/TestGcUpdateHandlerTest.java
@@ -15,14 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.table.distributed;
+package org.apache.ignite.internal.table.distributed.gc;
 
 import static 
org.apache.ignite.internal.distributionzones.DistributionZoneManager.DEFAULT_PARTITION_COUNT;
 
 import org.apache.ignite.internal.storage.impl.TestMvTableStorage;
 import org.junit.jupiter.api.BeforeEach;
 
-class TestMvStorageUpdateHandlerTest extends 
AbstractMvStorageUpdateHandlerTest {
+class TestGcUpdateHandlerTest extends AbstractGcUpdateHandlerTest {
     @BeforeEach
     void setUp() {
         initialize(new TestMvTableStorage(1, DEFAULT_PARTITION_COUNT));
diff --git 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/VolatilePageMemoryMvStorageUpdateHandlerTest.java
 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/VolatilePageMemoryGcUpdateHandlerTest.java
similarity index 95%
rename from 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/VolatilePageMemoryMvStorageUpdateHandlerTest.java
rename to 
modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/VolatilePageMemoryGcUpdateHandlerTest.java
index c9c1ade0ea..6536bba553 100644
--- 
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/VolatilePageMemoryMvStorageUpdateHandlerTest.java
+++ 
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/gc/VolatilePageMemoryGcUpdateHandlerTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.table.distributed;
+package org.apache.ignite.internal.table.distributed.gc;
 
 import static 
org.apache.ignite.internal.distributionzones.DistributionZoneManager.DEFAULT_PARTITION_COUNT;
 import static 
org.apache.ignite.internal.storage.pagememory.configuration.schema.BasePageMemoryStorageEngineConfigurationSchema.DEFAULT_DATA_REGION_NAME;
@@ -36,7 +36,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(ConfigurationExtension.class)
-class VolatilePageMemoryMvStorageUpdateHandlerTest extends 
AbstractMvStorageUpdateHandlerTest {
+class VolatilePageMemoryGcUpdateHandlerTest extends 
AbstractGcUpdateHandlerTest {
     private VolatilePageMemoryStorageEngine engine;
 
     private VolatilePageMemoryTableStorage table;


Reply via email to