You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by tk...@apache.org on 2022/12/12 11:01:01 UTC
[ignite] branch master updated: IGNITE-18364 Forcibly released the reservation of the WAL segments required by the checkpoint (#10429)
This is an automated email from the ASF dual-hosted git repository.
tkalkirill pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 234916967ee IGNITE-18364 Forcibly released the reservation of the WAL segments required by the checkpoint (#10429)
234916967ee is described below
commit 234916967ee6cdd4866f1800664ce675593ad627
Author: Kirill Tkalenko <tk...@yandex.ru>
AuthorDate: Mon Dec 12 14:00:51 2022 +0300
IGNITE-18364 Forcibly released the reservation of the WAL segments required by the checkpoint (#10429)
---
.../wal/aware/SegmentArchiveSizeStorage.java | 20 +++-
.../cache/persistence/wal/aware/SegmentAware.java | 1 +
.../db/wal/WalDeletionArchiveAbstractTest.java | 106 +++++++++++++++++++++
.../persistence/wal/aware/SegmentAwareTest.java | 25 +++++
4 files changed, 150 insertions(+), 2 deletions(-)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentArchiveSizeStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentArchiveSizeStorage.java
index cee0451cc54..eb1138dad58 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentArchiveSizeStorage.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentArchiveSizeStorage.java
@@ -54,11 +54,14 @@ class SegmentArchiveSizeStorage {
/** Automatically release segments. Guarded by {@code this}. */
private boolean autoRelease;
+ /** Segment of last completed checkpoint. Guarded by {@code this}. */
+ private long lastCpIdx = -1;
+
/**
* Segment sizes. Mapping: segment idx -> size in bytes. Guarded by {@code this}.
* {@code null} if {@link #walArchiveUnlimited} == {@code true}.
*/
- @Nullable private final Map<Long, Long> segmentSizes;
+ @Nullable private final TreeMap<Long, Long> segmentSizes;
/**
* Segment reservations storage.
@@ -206,7 +209,7 @@ class SegmentArchiveSizeStorage {
*/
void startAutoReleaseSegments() {
if (!walArchiveUnlimited) {
- T2<Long, Integer> forceReleaseSegments = null;
+ T2<Long, Integer> forceReleaseSegments;
synchronized (this) {
autoRelease = true;
@@ -232,6 +235,9 @@ class SegmentArchiveSizeStorage {
long size = 0;
for (Map.Entry<Long, Long> e : segmentSizes.entrySet()) {
+ if (e.getKey() > lastCpIdx)
+ break;
+
releaseIdx = e.getKey();
releaseCnt++;
@@ -260,4 +266,14 @@ class SegmentArchiveSizeStorage {
reservationStorage.forceRelease(absIdx);
}
+
+ /**
+ * Update segment of last completed checkpoint.
+ * Required for binary recovery.
+ *
+ * @param absIdx Absolut segment index.
+ */
+ synchronized void lastCheckpointIdx(long absIdx) {
+ lastCpIdx = absIdx;
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAware.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAware.java
index 728bd7411e5..cb1e7ed9422 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAware.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAware.java
@@ -370,6 +370,7 @@ public class SegmentAware {
*/
public void lastCheckpointIdx(long absIdx) {
truncateStorage.lastCheckpointIdx(absIdx);
+ archiveSizeStorage.lastCheckpointIdx(absIdx);
}
/**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalDeletionArchiveAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalDeletionArchiveAbstractTest.java
index 61911f83c55..f64435e0934 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalDeletionArchiveAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/WalDeletionArchiveAbstractTest.java
@@ -38,6 +38,8 @@ import org.apache.ignite.internal.processors.cache.persistence.checkpoint.Checkp
import org.apache.ignite.internal.processors.cache.persistence.checkpoint.Checkpointer;
import org.apache.ignite.internal.processors.cache.persistence.wal.FileDescriptor;
import org.apache.ignite.internal.processors.cache.persistence.wal.FileWriteAheadLogManager;
+import org.apache.ignite.internal.processors.cache.persistence.wal.WALPointer;
+import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.testframework.ListeningTestLogger;
import org.apache.ignite.testframework.junits.WithSystemProperty;
@@ -51,6 +53,10 @@ import static org.apache.ignite.internal.util.IgniteUtils.KB;
import static org.apache.ignite.internal.util.IgniteUtils.MB;
import static org.apache.ignite.testframework.GridTestUtils.getFieldValueHierarchy;
import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThan;
/**
*
@@ -309,6 +315,96 @@ public abstract class WalDeletionArchiveAbstractTest extends GridCommonAbstractT
assertEquals(logStrs.toString(), 1, logStrs.size());
}
+ /**
+ * Check that if the maximum archive size is equal to one WAL segment size, then when the archive is overflowing,
+ * segments that are needed for binary recovery will not be deleted from the archive until the checkpoint occurs
+ * and finishes.
+ *
+ * @throws Exception If failed.
+ */
+ @Test
+ public void testMaxWalArchiveSizeEqualsOneWalSegmentSize() throws Exception {
+ int walSegmentSize = (int)MB;
+
+ IgniteConfiguration cfg = getConfiguration(getTestIgniteInstanceName(0))
+ .setCacheConfiguration(cacheConfiguration())
+ .setDataStorageConfiguration(
+ new DataStorageConfiguration()
+ .setCheckpointFrequency(Long.MAX_VALUE)
+ .setMaxWalArchiveSize(walSegmentSize)
+ .setWalSegmentSize(walSegmentSize)
+ .setWalSegments(2)
+ .setDefaultDataRegionConfiguration(
+ new DataRegionConfiguration()
+ .setPersistenceEnabled(true)
+ .setMaxSize(GB)
+ .setCheckpointPageBufferSize(GB)
+ )
+ );
+
+ IgniteEx n = startGrid(cfg);
+
+ n.cluster().state(ClusterState.ACTIVE);
+
+ // Let's not let a checkpoint happen.
+ gridDatabase(n).checkpointReadLock();
+
+ FileWriteAheadLogManager wal = wal(n);
+
+ try {
+ long idxLastCp = lastCheckpointPtr(n).index();
+
+ // Let's reserve the very first segment that will definitely be needed for the checkpoint.
+ assertTrue(wal.reserve(new WALPointer(idxLastCp, 0, 0)));
+
+ for (int i = 0; wal.lastArchivedSegment() < 20L; i++)
+ n.cache(DEFAULT_CACHE_NAME).put(i, new byte[(int)(512 * KB)]);
+
+ // Make sure nothing has been deleted from the archive.
+ assertThat(walArchiveSize(n), greaterThanOrEqualTo(20L * walSegmentSize));
+ assertThat(wal.lastTruncatedSegment(), equalTo(-1L));
+
+ // Let's try to reserve all the segments and then immediately release them.
+ long lastWalSegmentIndex = wal.lastWritePointer().index();
+
+ for (int i = (int)(idxLastCp + 1); i < lastWalSegmentIndex; i++) {
+ WALPointer pointer = new WALPointer(i, 0, 0);
+
+ // Should be able to reserve segments because the checkpoint has not happened yet.
+ assertTrue(String.valueOf(i), wal.reserve(pointer));
+
+ wal.release(pointer);
+ }
+
+ assertTrue(
+ String.valueOf(lastWalSegmentIndex),
+ wal.reserve(new WALPointer(lastWalSegmentIndex, 0, 0))
+ );
+
+ wal.release(new WALPointer(lastWalSegmentIndex, 0, 0));
+
+ // Let's wait a bit, suddenly there will be a deletion from the archive?
+ assertFalse(waitForCondition(() -> wal.lastTruncatedSegment() >= 0, 1_000, 100));
+
+ // Make sure nothing has been deleted from the archive.
+ assertThat(walArchiveSize(n), greaterThanOrEqualTo(20L * walSegmentSize));
+ assertThat(wal.lastTruncatedSegment(), equalTo(-1L));
+ }
+ finally {
+ gridDatabase(n).checkpointReadUnlock();
+ }
+
+ // Now let's run a checkpoint and make sure that only one segment remains in the archive.
+ forceCheckpoint(n);
+
+ assertTrue(
+ IgniteUtils.humanReadableByteCount(walArchiveSize(n)),
+ waitForCondition(() -> walArchiveSize(n) <= walSegmentSize, 1_000, 100)
+ );
+
+ assertThat(wal.lastTruncatedSegment(), lessThan(lastCheckpointPtr(n).index()));
+ }
+
/**
* Extract GridCacheDatabaseSharedManager.
*/
@@ -332,4 +428,14 @@ public abstract class WalDeletionArchiveAbstractTest extends GridCommonAbstractT
private long walArchiveSize(Ignite n) {
return Arrays.stream(wal(n).walArchiveFiles()).mapToLong(fd -> fd.file().length()).sum();
}
+
+ /**
+ * Returns the value of field {@code FileWriteAheadLogManager#lastCheckpointPtr}.
+ *
+ * @param n Node.
+ * @return Field value {@code FileWriteAheadLogManager#lastCheckpointPtr}.
+ */
+ private WALPointer lastCheckpointPtr(Ignite n) {
+ return getFieldValueHierarchy(wal(n), "lastCheckpointPtr");
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAwareTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAwareTest.java
index d95fd88a0e0..e81b8a4a233 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAwareTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/wal/aware/SegmentAwareTest.java
@@ -887,12 +887,21 @@ public class SegmentAwareTest {
assertTrue(aware.reserve(1));
assertTrue(aware.reserve(8));
+ aware.lastCheckpointIdx(1);
aware.addSize(9, 10);
assertFalse(aware.reserved(0));
assertFalse(aware.reserved(1));
assertTrue(aware.reserved(8));
+ assertEquals(1, reservationStorage.minReserveIdx());
+
+ aware.lastCheckpointIdx(5);
+ aware.startAutoReleaseSegments();
+
+ assertFalse(aware.reserved(0));
+ assertFalse(aware.reserved(1));
+ assertTrue(aware.reserved(8));
assertEquals(5, reservationStorage.minReserveIdx());
for (int i = 0; i <= 5; i++) {
@@ -958,6 +967,22 @@ public class SegmentAwareTest {
aware.startAutoReleaseSegments();
+ assertTrue(aware.reserved(0));
+ assertTrue(aware.reserved(1));
+ assertTrue(aware.reserved(8));
+ assertEquals(-1, reservationStorage.minReserveIdx());
+
+ aware.lastCheckpointIdx(0);
+ aware.startAutoReleaseSegments();
+
+ assertFalse(aware.reserved(0));
+ assertTrue(aware.reserved(1));
+ assertTrue(aware.reserved(8));
+ assertEquals(0, reservationStorage.minReserveIdx());
+
+ aware.lastCheckpointIdx(100);
+ aware.startAutoReleaseSegments();
+
assertFalse(aware.reserved(0));
assertFalse(aware.reserved(1));
assertTrue(aware.reserved(8));