diff --git a/modules/core/src/main/java/org/apache/ignite/DataStorageMetrics.java b/modules/core/src/main/java/org/apache/ignite/DataStorageMetrics.java
index e26bb1fe5b225..680caba62b8f9 100644
--- a/modules/core/src/main/java/org/apache/ignite/DataStorageMetrics.java
+++ b/modules/core/src/main/java/org/apache/ignite/DataStorageMetrics.java
@@ -26,7 +26,7 @@ public interface DataStorageMetrics {
* Gets the average number of WAL records per second written during the last time interval.
*
* The length of time interval is configured via {@link DataStorageConfiguration#setMetricsRateTimeInterval(long)}
- * configurartion property.
+ * configuration property.
* The number of subintervals is configured via {@link DataStorageConfiguration#setMetricsSubIntervalCount(int)}
* configuration property.
*/
@@ -35,7 +35,7 @@ public interface DataStorageMetrics {
/**
* Gets the average number of bytes per second written during the last time interval.
* The length of time interval is configured via {@link DataStorageConfiguration#setMetricsRateTimeInterval(long)}
- * configurartion property.
+ * configuration property.
* The number of subintervals is configured via {@link DataStorageConfiguration#setMetricsSubIntervalCount(int)}
* configuration property.
*/
@@ -50,12 +50,22 @@ public interface DataStorageMetrics {
* Gets the average WAL fsync duration in microseconds over the last time interval.
*
* The length of time interval is configured via {@link DataStorageConfiguration#setMetricsRateTimeInterval(long)}
- * configurartion property.
+ * configuration property.
* The number of subintervals is configured via {@link DataStorageConfiguration#setMetricsSubIntervalCount(int)}
* configuration property.
*/
public float getWalFsyncTimeAverage();
+ /**
+ * Returns WAL buffer poll spins number over the last time interval.
+ *
+ * The length of time interval is configured via {@link DataStorageConfiguration#setMetricsRateTimeInterval(long)}
+ * configuration property.
+ * The number of subintervals is configured via {@link DataStorageConfiguration#setMetricsSubIntervalCount(int)}
+ * configuration property.
+ */
+ public long getWalBuffPollSpinsRate();
+
/**
* Gets the duration of the last checkpoint in milliseconds.
*
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 8e2298fc67d1f..97329055d3787 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -750,6 +750,12 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_WAL_SERIALIZER_VERSION = "IGNITE_WAL_SERIALIZER_VERSION";
+ /**
+ * Property that indicates should be mapped byte buffer used or not.
+ * Possible values: {@code true} and {@code false}.
+ */
+ public static final String IGNITE_WAL_MMAP = "IGNITE_WAL_MMAP";
+
/**
* When set to {@code true}, Data store folders are generated only by consistent id, and no consistent ID will be
* set based on existing data store folders. This option also enables compatible folder generation mode as it was
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/DataStorageConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/DataStorageConfiguration.java
index 2c903984446db..381c3152287b2 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/DataStorageConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/DataStorageConfiguration.java
@@ -124,6 +124,9 @@ public class DataStorageConfiguration implements Serializable {
/** Default thread local buffer size. */
public static final int DFLT_TLB_SIZE = 128 * 1024;
+ /** Default thread local buffer size. */
+ public static final int DFLT_WAL_BUFF_SIZE = DFLT_WAL_SEGMENT_SIZE / 4;
+
/** Default Wal flush frequency. */
public static final int DFLT_WAL_FLUSH_FREQ = 2000;
@@ -205,6 +208,9 @@ public class DataStorageConfiguration implements Serializable {
/** WAl thread local buffer size. */
private int walTlbSize = DFLT_TLB_SIZE;
+ /** WAl buffer size. */
+ private int walBuffSize/* = DFLT_WAL_BUFF_SIZE*/;
+
/** Wal flush frequency in milliseconds. */
private long walFlushFreq = DFLT_WAL_FLUSH_FREQ;
@@ -230,7 +236,7 @@ public class DataStorageConfiguration implements Serializable {
* rate-based metrics when next sub-interval has to be recycled but introduces bigger
* calculation overhead.
*/
- private int metricsSubIntervalCount = DFLT_SUB_INTERVALS;
+ private int metricsSubIntervalCnt = DFLT_SUB_INTERVALS;
/** Time interval (in milliseconds) for rate-based metrics. */
private long metricsRateTimeInterval = DFLT_RATE_TIME_INTERVAL_MILLIS;
@@ -648,7 +654,7 @@ public DataStorageConfiguration setMetricsRateTimeInterval(long metricsRateTimeI
* @return The number of sub-intervals for history tracking.
*/
public int getMetricsSubIntervalCount() {
- return metricsSubIntervalCount;
+ return metricsSubIntervalCnt;
}
/**
@@ -657,7 +663,7 @@ public int getMetricsSubIntervalCount() {
* @param metricsSubIntervalCnt The number of sub-intervals for history tracking.
*/
public DataStorageConfiguration setMetricsSubIntervalCount(int metricsSubIntervalCnt) {
- this.metricsSubIntervalCount = metricsSubIntervalCnt;
+ this.metricsSubIntervalCnt = metricsSubIntervalCnt;
return this;
}
@@ -706,6 +712,25 @@ public DataStorageConfiguration setWalThreadLocalBufferSize(int walTlbSize) {
return this;
}
+ /**
+ * Property defines size of WAL buffer.
+ * Each WAL record will be serialized to this buffer before write in WAL file.
+ *
+ * @return WAL buffer size.
+ */
+ public int getWalBufferSize() {
+ return walBuffSize <= 0 ? getWalSegmentSize() / 4 : walBuffSize;
+ }
+
+ /**
+ * @param walBuffSize WAL buffer size.
+ */
+ public DataStorageConfiguration setWalBufferSize(int walBuffSize) {
+ this.walBuffSize = walBuffSize;
+
+ return this;
+ }
+
/**
* This property define how often WAL will be fsync-ed in {@code BACKGROUND} mode. Ignored for
* all other WAL modes.
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/PersistentStoreConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/PersistentStoreConfiguration.java
index c41721a5f9450..d59d19b67b2d4 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/PersistentStoreConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/PersistentStoreConfiguration.java
@@ -65,9 +65,6 @@ public class PersistentStoreConfiguration implements Serializable {
/** Default wal mode. */
public static final WALMode DFLT_WAL_MODE = WALMode.DEFAULT;
- /** Default thread local buffer size. */
- public static final int DFLT_TLB_SIZE = 128 * 1024;
-
/** Default Wal flush frequency. */
public static final int DFLT_WAL_FLUSH_FREQ = 2000;
@@ -128,8 +125,8 @@ public class PersistentStoreConfiguration implements Serializable {
/** Wal mode. */
private WALMode walMode = DFLT_WAL_MODE;
- /** WAl thread local buffer size. */
- private int tlbSize = DFLT_TLB_SIZE;
+ /** WAl buffer size. */
+ private int walBuffSize/* = DFLT_WAL_BUFF_SIZE*/;
/** Wal flush frequency in milliseconds. */
private long walFlushFreq = DFLT_WAL_FLUSH_FREQ;
@@ -492,20 +489,43 @@ public PersistentStoreConfiguration setWalMode(WALMode walMode) {
}
/**
- * Property define size thread local buffer.
- * Each thread which write to wal have thread local buffer for serialize recode before write in wal.
+ * Property defines size of WAL buffer.
+ * Each WAL record will be serialized to this buffer before write in WAL file.
*
- * @return Thread local buffer size.
+ * @return WAL buffer size.
+ * @deprecated Instead {@link #getWalBufferSize()} should be used.
*/
+ @Deprecated
public int getTlbSize() {
- return tlbSize <= 0 ? DFLT_TLB_SIZE : tlbSize;
+ return getWalBufferSize();
}
/**
- * @param tlbSize Tlb size.
+ * @param tlbSize WAL buffer size.
+ * @deprecated Instead {@link #setWalBufferSize(int walBuffSize)} should be used.
*/
+ @Deprecated
public PersistentStoreConfiguration setTlbSize(int tlbSize) {
- this.tlbSize = tlbSize;
+ return setWalBufferSize(tlbSize);
+ }
+
+ /**
+ * Property defines size of WAL buffer.
+ * Each WAL record will be serialized to this buffer before write in WAL file.
+ *
+ * @return WAL buffer size.
+ */
+ @Deprecated
+ public int getWalBufferSize() {
+ return walBuffSize <= 0 ? getWalSegmentSize() / 4 : walBuffSize;
+ }
+
+ /**
+ * @param walBuffSize WAL buffer size.
+ */
+ @Deprecated
+ public PersistentStoreConfiguration setWalBufferSize(int walBuffSize) {
+ this.walBuffSize = walBuffSize;
return this;
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
index 08bba1b174fb2..744691695314e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/pagemem/wal/record/WALRecord.java
@@ -43,7 +43,7 @@ public enum RecordType {
/** Checkpoint (begin) record */
CHECKPOINT_RECORD,
- /** */
+ /** WAL segment header record. */
HEADER_RECORD,
// Delta records.
@@ -187,9 +187,6 @@ public static RecordType fromOrdinal(int ord) {
/** */
private int size;
- /** */
- private int chainSize;
-
/** */
@GridToStringExclude
private WALRecord prev;
@@ -197,20 +194,6 @@ public static RecordType fromOrdinal(int ord) {
/** */
private WALPointer pos;
- /**
- * @param chainSize Chain size in bytes.
- */
- public void chainSize(int chainSize) {
- this.chainSize = chainSize;
- }
-
- /**
- * @return Get chain size in bytes.
- */
- public int chainSize() {
- return chainSize;
- }
-
/**
* @return Previous record in chain.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsImpl.java
index e871597c593ec..4f32c25321e6e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsImpl.java
@@ -34,7 +34,10 @@ public class DataStorageMetricsImpl implements DataStorageMetricsMXBean {
private volatile HitRateMetrics walFsyncTimeDuration;
/** */
- private volatile HitRateMetrics walFsyncTimeNumber;
+ private volatile HitRateMetrics walFsyncTimeNum;
+
+ /** */
+ private volatile HitRateMetrics walBuffPollSpinsNum;
/** */
private volatile long lastCpLockWaitDuration;
@@ -118,7 +121,7 @@ public DataStorageMetricsImpl(
if (!metricsEnabled)
return 0;
- long numRate = walFsyncTimeNumber.getRate();
+ long numRate = walFsyncTimeNum.getRate();
if (numRate == 0)
return 0;
@@ -126,6 +129,15 @@ public DataStorageMetricsImpl(
return (float)walFsyncTimeDuration.getRate() / numRate;
}
+ /** {@inheritDoc} */
+ @Override public long getWalBuffPollSpinsRate() {
+ if (!metricsEnabled)
+ return 0;
+
+ return walBuffPollSpinsNum.getRate();
+ }
+
+
/** {@inheritDoc} */
@Override public long getLastCheckpointDuration() {
if (!metricsEnabled)
@@ -281,7 +293,14 @@ public void onFsync(long nanoTime) {
long microseconds = nanoTime / 1_000;
walFsyncTimeDuration.onHits(microseconds);
- walFsyncTimeNumber.onHit();
+ walFsyncTimeNum.onHit();
+ }
+
+ /**
+ * @param num Number.
+ */
+ public void onBuffPollSpin(int num) {
+ walBuffPollSpinsNum.onHits(num);
}
/**
@@ -290,8 +309,9 @@ public void onFsync(long nanoTime) {
private void resetRates() {
walLoggingRate = new HitRateMetrics((int)rateTimeInterval, subInts);
walWritingRate = new HitRateMetrics((int)rateTimeInterval, subInts);
+ walBuffPollSpinsNum = new HitRateMetrics((int)rateTimeInterval, subInts);
walFsyncTimeDuration = new HitRateMetrics((int)rateTimeInterval, subInts);
- walFsyncTimeNumber = new HitRateMetrics((int)rateTimeInterval, subInts);
+ walFsyncTimeNum = new HitRateMetrics((int)rateTimeInterval, subInts);
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsSnapshot.java
index 5bbb0e1086c4f..c67eeeb1f2bb7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsSnapshot.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataStorageMetricsSnapshot.java
@@ -35,6 +35,9 @@ public class DataStorageMetricsSnapshot implements DataStorageMetrics {
/** */
private float walFsyncTimeAvg;
+ /** */
+ private long walBuffPollSpinsNum;
+
/** */
private long lastCpDuration;
@@ -67,6 +70,7 @@ public DataStorageMetricsSnapshot(DataStorageMetrics metrics) {
walWritingRate = metrics.getWalWritingRate();
walArchiveSegments = metrics.getWalArchiveSegments();
walFsyncTimeAvg = metrics.getWalFsyncTimeAverage();
+ walBuffPollSpinsNum = metrics.getWalBuffPollSpinsRate();
lastCpDuration = metrics.getLastCheckpointDuration();
lastCpLockWaitDuration = metrics.getLastCheckpointLockWaitDuration();
lastCpMmarkDuration = metrics.getLastCheckpointMarkDuration();
@@ -97,6 +101,11 @@ public DataStorageMetricsSnapshot(DataStorageMetrics metrics) {
return walFsyncTimeAvg;
}
+ /** {@inheritDoc} */
+ @Override public long getWalBuffPollSpinsRate() {
+ return walBuffPollSpinsNum;
+ }
+
/** {@inheritDoc} */
@Override public long getLastCheckpointDuration() {
return lastCpDuration;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/AsyncFileIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/AsyncFileIO.java
index 8fad7a5109d01..b1db79d706a2e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/AsyncFileIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/AsyncFileIO.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.OpenOption;
@@ -69,11 +70,11 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer) throws IOException {
+ @Override public int read(ByteBuffer destBuf) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
- ch.read(destinationBuffer, position, this, fut);
+ ch.read(destBuf, position, this, fut);
try {
return fut.getUninterruptibly();
@@ -84,11 +85,11 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer, long position) throws IOException {
+ @Override public int read(ByteBuffer destBuf, long position) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
- ch.read(destinationBuffer, position, null, fut);
+ ch.read(destBuf, position, null, fut);
try {
return fut.getUninterruptibly();
@@ -102,11 +103,12 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public int read(byte[] buffer, int offset, int length) throws IOException {
+ @Override public int read(byte[] buf, int off, int
+ length) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
- ch.read(ByteBuffer.wrap(buffer, offset, length), position, this, fut);
+ ch.read(ByteBuffer.wrap(buf, off, length), position, this, fut);
try {
return fut.getUninterruptibly();
@@ -117,11 +119,11 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer) throws IOException {
+ @Override public int write(ByteBuffer srcBuf) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
- ch.write(sourceBuffer, position, this, fut);
+ ch.write(srcBuf, position, this, fut);
try {
return fut.getUninterruptibly();
@@ -132,13 +134,13 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer, long position) throws IOException {
+ @Override public int write(ByteBuffer srcBuf, long position) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
asyncFuts.add(fut);
- ch.write(sourceBuffer, position, null, fut);
+ ch.write(srcBuf, position, null, fut);
try {
return fut.getUninterruptibly();
@@ -152,11 +154,11 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
/** {@inheritDoc} */
- @Override public void write(byte[] buffer, int offset, int length) throws IOException {
+ @Override public void write(byte[] buf, int off, int len) throws IOException {
ChannelOpFuture fut = holder.get();
fut.reset();
- ch.write(ByteBuffer.wrap(buffer, offset, length), position, this, fut);
+ ch.write(ByteBuffer.wrap(buf, off, len), position, this, fut);
try {
fut.getUninterruptibly();
@@ -166,6 +168,11 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
}
}
+ /** {@inheritDoc} */
+ @Override public MappedByteBuffer map(int maxWalSegmentSize) throws IOException {
+ throw new UnsupportedOperationException("AsynchronousFileChannel doesn't support mmap.");
+ }
+
/** {@inheritDoc} */
@Override public void force() throws IOException {
ch.force(false);
@@ -200,18 +207,18 @@ public AsyncFileIO(File file, ThreadLocal holder, OpenOption...
/** */
static class ChannelOpFuture extends GridFutureAdapter implements CompletionHandler {
/** {@inheritDoc} */
- @Override public void completed(Integer result, AsyncFileIO attachment) {
- if (attachment != null) {
- if (result != -1)
- attachment.position += result;
+ @Override public void completed(Integer res, AsyncFileIO attach) {
+ if (attach != null) {
+ if (res != -1)
+ attach.position += res;
}
// Release waiter and allow next operation to begin.
- super.onDone(result, null);
+ super.onDone(res, null);
}
/** {@inheritDoc} */
- @Override public void failed(Throwable exc, AsyncFileIO attachment) {
+ @Override public void failed(Throwable exc, AsyncFileIO attach) {
super.onDone(exc);
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIO.java
index 1e81150658596..849f03a51453a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIO.java
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
/**
* Interface to perform file I/O operations.
@@ -49,76 +50,78 @@ public interface FileIO extends AutoCloseable {
/**
* Reads a sequence of bytes from this file into the {@code destinationBuffer}.
*
- * @param destinationBuffer Destination byte buffer.
+ * @param destBuf Destination byte buffer.
*
* @return Number of read bytes.
*
* @throws IOException If some I/O error occurs.
*/
- public int read(ByteBuffer destinationBuffer) throws IOException;
+ public int read(ByteBuffer destBuf) throws IOException;
/**
* Reads a sequence of bytes from this file into the {@code destinationBuffer}
* starting from specified file {@code position}.
*
- * @param destinationBuffer Destination byte buffer.
+ * @param destBuf Destination byte buffer.
* @param position Starting position of file.
*
* @return Number of read bytes.
*
* @throws IOException If some I/O error occurs.
*/
- public int read(ByteBuffer destinationBuffer, long position) throws IOException;
+ public int read(ByteBuffer destBuf, long position) throws IOException;
/**
* Reads a up to {@code length} bytes from this file into the {@code buffer}.
*
- * @param buffer Destination byte array.
- * @param offset The start offset in array {@code b}
+ * @param buf Destination byte array.
+ * @param off The start offset in array {@code b}
* at which the data is written.
- * @param length Maximum number of bytes read.
+ * @param len Maximum number of bytes read.
*
* @return Number of read bytes.
*
* @throws IOException If some I/O error occurs.
*/
- public int read(byte[] buffer, int offset, int length) throws IOException;
+ public int read(byte[] buf, int off, int len) throws IOException;
/**
* Writes a sequence of bytes to this file from the {@code sourceBuffer}.
*
- * @param sourceBuffer Source buffer.
+ * @param srcBuf Source buffer.
*
* @return Number of written bytes.
*
* @throws IOException If some I/O error occurs.
*/
- public int write(ByteBuffer sourceBuffer) throws IOException;
+ public int write(ByteBuffer srcBuf) throws IOException;
/**
* Writes a sequence of bytes to this file from the {@code sourceBuffer}
* starting from specified file {@code position}
*
- * @param sourceBuffer Source buffer.
+ * @param srcBuf Source buffer.
* @param position Starting file position.
*
* @return Number of written bytes.
*
* @throws IOException If some I/O error occurs.
*/
- public int write(ByteBuffer sourceBuffer, long position) throws IOException;
+ public int write(ByteBuffer srcBuf, long position) throws IOException;
/**
* Writes {@code length} bytes from the {@code buffer}
* starting at offset {@code off} to this file.
*
- * @param buffer Source byte array.
- * @param offset Start offset in the {@code buffer}.
- * @param length Number of bytes to write.
+ * @param buf Source byte array.
+ * @param off Start offset in the {@code buffer}.
+ * @param len Number of bytes to write.
*
* @throws IOException If some I/O error occurs.
*/
- public void write(byte[] buffer, int offset, int length) throws IOException;
+ public void write(byte[] buf, int off, int len) throws IOException;
+
+ public MappedByteBuffer map(int maxWalSegmentSize) throws IOException;
/**
* Forces any updates of this file to be written to the storage
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIODecorator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIODecorator.java
index 53115908a714e..dd563f2d68197 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIODecorator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/FileIODecorator.java
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
/**
* Decorator class for File I/O
@@ -46,33 +47,38 @@ public FileIODecorator(FileIO delegate) {
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer) throws IOException {
- return delegate.read(destinationBuffer);
+ @Override public int read(ByteBuffer destBuf) throws IOException {
+ return delegate.read(destBuf);
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer, long position) throws IOException {
- return delegate.read(destinationBuffer, position);
+ @Override public int read(ByteBuffer destBuf, long position) throws IOException {
+ return delegate.read(destBuf, position);
}
/** {@inheritDoc} */
- @Override public int read(byte[] buffer, int offset, int length) throws IOException {
- return delegate.read(buffer, offset, length);
+ @Override public int read(byte[] buf, int off, int len) throws IOException {
+ return delegate.read(buf, off, len);
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer) throws IOException {
- return delegate.write(sourceBuffer);
+ @Override public int write(ByteBuffer srcBuf) throws IOException {
+ return delegate.write(srcBuf);
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer, long position) throws IOException {
- return delegate.write(sourceBuffer, position);
+ @Override public int write(ByteBuffer srcBuf, long position) throws IOException {
+ return delegate.write(srcBuf, position);
}
/** {@inheritDoc} */
- @Override public void write(byte[] buffer, int offset, int length) throws IOException {
- delegate.write(buffer, offset, length);
+ @Override public void write(byte[] buf, int off, int len) throws IOException {
+ delegate.write(buf, off, len);
+ }
+
+ /** {@inheritDoc} */
+ @Override public MappedByteBuffer map(int maxWalSegmentSize) throws IOException {
+ return delegate.map(maxWalSegmentSize);
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/RandomAccessFileIO.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/RandomAccessFileIO.java
index 55849fe0cf0b5..23d6ebfeead76 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/RandomAccessFileIO.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/file/RandomAccessFileIO.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.OpenOption;
@@ -53,33 +54,33 @@ public RandomAccessFileIO(File file, OpenOption... modes) throws IOException {
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer) throws IOException {
- return ch.read(destinationBuffer);
+ @Override public int read(ByteBuffer destBuf) throws IOException {
+ return ch.read(destBuf);
}
/** {@inheritDoc} */
- @Override public int read(ByteBuffer destinationBuffer, long position) throws IOException {
- return ch.read(destinationBuffer, position);
+ @Override public int read(ByteBuffer destBuf, long position) throws IOException {
+ return ch.read(destBuf, position);
}
/** {@inheritDoc} */
- @Override public int read(byte[] buffer, int offset, int length) throws IOException {
- return ch.read(ByteBuffer.wrap(buffer, offset, length));
+ @Override public int read(byte[] buf, int off, int len) throws IOException {
+ return ch.read(ByteBuffer.wrap(buf, off, len));
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer) throws IOException {
- return ch.write(sourceBuffer);
+ @Override public int write(ByteBuffer srcBuf) throws IOException {
+ return ch.write(srcBuf);
}
/** {@inheritDoc} */
- @Override public int write(ByteBuffer sourceBuffer, long position) throws IOException {
- return ch.write(sourceBuffer, position);
+ @Override public int write(ByteBuffer srcBuf, long position) throws IOException {
+ return ch.write(srcBuf, position);
}
/** {@inheritDoc} */
- @Override public void write(byte[] buffer, int offset, int length) throws IOException {
- ch.write(ByteBuffer.wrap(buffer, offset, length));
+ @Override public void write(byte[] buf, int off, int len) throws IOException {
+ ch.write(ByteBuffer.wrap(buf, off, len));
}
/** {@inheritDoc} */
@@ -101,4 +102,9 @@ public RandomAccessFileIO(File file, OpenOption... modes) throws IOException {
@Override public void close() throws IOException {
ch.close();
}
+
+ /** {@inheritDoc} */
+ @Override public MappedByteBuffer map(int maxWalSegmentSize) throws IOException {
+ return ch.map(FileChannel.MapMode.READ_WRITE, 0, maxWalSegmentSize);
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
index 7415db321ac7a..c2c07f6b3a6a0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/AbstractWalRecordsIterator.java
@@ -219,13 +219,10 @@ private IgniteBiTuple advanceRecord(
if (hnd == null)
return null;
- final FileWALPointer ptr = new FileWALPointer(
- hnd.idx,
- (int)hnd.in.position(),
- 0);
+ FileWALPointer ptr = new FileWALPointer(hnd.idx, (int)hnd.in.position(),0);
try {
- final WALRecord rec = hnd.ser.readRecord(hnd.in, ptr);
+ WALRecord rec = hnd.ser.readRecord(hnd.in, ptr);
ptr.length(rec.size());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWALPointer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWALPointer.java
index 4998700024a63..0e095fa24f17f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWALPointer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWALPointer.java
@@ -19,6 +19,7 @@
import org.apache.ignite.internal.pagemem.wal.WALPointer;
import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.NotNull;
/**
* File WAL pointer.
@@ -31,34 +32,20 @@ public class FileWALPointer implements WALPointer, Comparable {
private final long idx;
/** */
- private final int fileOffset;
+ private final int fileOff;
/** Written record length */
private int len;
- /** Force flush flag. Used in BACKGROUND WAL mode. */
- private boolean forceFlush;
-
- /**
- * @param idx Absolute WAL segment file index (incremental counter)
- * @param fileOffset Offset in file, from the beginning.
- * @param len Record length.
- */
- public FileWALPointer(long idx, int fileOffset, int len) {
- this(idx, fileOffset, len, false);
- }
-
/**
- * @param idx Absolute WAL segment file index .
- * @param fileOffset Offset in file, from the beginning.
+ * @param idx Absolute WAL segment file index (incremental counter).
+ * @param fileOff Offset in file, from the beginning.
* @param len Record length.
- * @param forceFlush Force flush flag.
*/
- public FileWALPointer(long idx, int fileOffset, int len, boolean forceFlush) {
+ public FileWALPointer(long idx, int fileOff, int len) {
this.idx = idx;
- this.fileOffset = fileOffset;
+ this.fileOff = fileOff;
this.len = len;
- this.forceFlush = forceFlush;
}
/**
@@ -72,7 +59,7 @@ public long index() {
* @return File offset.
*/
public int fileOffset() {
- return fileOffset;
+ return fileOff;
}
/**
@@ -96,14 +83,7 @@ public void length(int len) {
"(this pointer is a terminal): " + this);
// Return a terminal pointer.
- return new FileWALPointer(idx, fileOffset + len, 0);
- }
-
- /**
- * @return Force flush flag.
- */
- public boolean forceFlush() {
- return forceFlush;
+ return new FileWALPointer(idx, fileOff + len, 0);
}
/** {@inheritDoc} */
@@ -116,23 +96,23 @@ public boolean forceFlush() {
FileWALPointer that = (FileWALPointer)o;
- return idx == that.idx && fileOffset == that.fileOffset;
+ return idx == that.idx && fileOff == that.fileOff;
}
/** {@inheritDoc} */
@Override public int hashCode() {
- int result = (int)(idx ^ (idx >>> 32));
+ int res = (int)(idx ^ (idx >>> 32));
- result = 31 * result + fileOffset;
+ res = 31 * res + fileOff;
- return result;
+ return res;
}
/** {@inheritDoc} */
- @Override public int compareTo(FileWALPointer o) {
+ @Override public int compareTo(@NotNull FileWALPointer o) {
int res = Long.compare(idx, o.idx);
- return res == 0 ? Integer.compare(fileOffset, o.fileOffset) : res;
+ return res == 0 ? Integer.compare(fileOff, o.fileOff) : res;
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
index 5cb6b2f7f7b14..4a7a20b8ac61d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/FileWriteAheadLogManager.java
@@ -26,12 +26,17 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
import java.nio.file.Files;
import java.sql.Time;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
@@ -40,10 +45,10 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -90,7 +95,6 @@
import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.typedef.CIX1;
import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiTuple;
@@ -98,21 +102,48 @@
import org.apache.ignite.lang.IgniteUuid;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jsr166.ConcurrentHashMap8;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_SERIALIZER_VERSION;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_MMAP;
+import static org.apache.ignite.configuration.WALMode.LOG_ONLY;
+import static org.apache.ignite.internal.pagemem.wal.record.WALRecord.RecordType.SWITCH_SEGMENT_RECORD;
+import static org.apache.ignite.internal.processors.cache.persistence.wal.SegmentedRingByteBuffer.BufferMode.DIRECT;
+import static org.apache.ignite.internal.util.IgniteUtils.findField;
+import static org.apache.ignite.internal.util.IgniteUtils.findNonPublicMethod;
/**
* File WAL manager.
*/
public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter implements IgniteWriteAheadLogManager {
- /** */
- public static final FileDescriptor[] EMPTY_DESCRIPTORS = new FileDescriptor[0];
+ /** {@link MappedByteBuffer#force0(java.io.FileDescriptor, long, long)}. */
+ private static final Method force0 = findNonPublicMethod(
+ MappedByteBuffer.class, "force0",
+ java.io.FileDescriptor.class, long.class, long.class
+ );
+
+ /** {@link MappedByteBuffer#mappingOffset()}. */
+ private static final Method mappingOffset = findNonPublicMethod(MappedByteBuffer.class, "mappingOffset");
+
+ /** {@link MappedByteBuffer#mappingAddress(long)}. */
+ private static final Method mappingAddress = findNonPublicMethod(
+ MappedByteBuffer.class, "mappingAddress", long.class
+ );
+
+ /** {@link MappedByteBuffer#fd} */
+ private static final Field fd = findField(MappedByteBuffer.class, "fd");
+
+ /** Page size. */
+ private static final int PAGE_SIZE = GridUnsafe.pageSize();
/** */
- public static final String WAL_SEGMENT_FILE_EXT = ".wal";
+ private static final FileDescriptor[] EMPTY_DESCRIPTORS = new FileDescriptor[0];
+
+ /** WAL segment file extension. */
+ private static final String WAL_SEGMENT_FILE_EXT = ".wal";
/** */
private static final byte[] FILL_BUF = new byte[1024 * 1024];
@@ -168,6 +199,12 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
/** Latest serializer version to use. */
private static final int LATEST_SERIALIZER_VERSION = 2;
+ /** Buffer size. */
+ private static final int BUF_SIZE = 1024 * 1024;
+
+ /** Use mapped byte buffer. */
+ private static boolean mmap = IgniteSystemProperties.getBoolean(IGNITE_WAL_MMAP, true);
+
/** */
private final boolean alwaysWriteFullPages;
@@ -177,9 +214,6 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
/** */
private final WALMode mode;
- /** Thread local byte buffer size, see {@link #tlb} */
- private final int tlbSize;
-
/** WAL flush frequency. Makes sense only for {@link WALMode#BACKGROUND} log WALMode. */
private final long flushFreq;
@@ -208,7 +242,7 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
private RecordSerializer serializer;
/** Serializer latest version to use. */
- private final int serializerVersion =
+ private final int serializerVer =
IgniteSystemProperties.getInteger(IGNITE_WAL_SERIALIZER_VERSION, LATEST_SERIALIZER_VERSION);
/** Latest segment cleared by {@link #truncate(WALPointer)}. */
@@ -217,24 +251,9 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
/** Factory to provide I/O interfaces for read/write operations with files */
private final FileIOFactory ioFactory;
- /** Updater for {@link #currentHnd}, used for verify there are no concurrent update for current log segment handle */
- private static final AtomicReferenceFieldUpdater currentHndUpd =
- AtomicReferenceFieldUpdater.newUpdater(FileWriteAheadLogManager.class, FileWriteHandle.class, "currentHnd");
-
- /**
- * Thread local byte buffer for saving serialized WAL records chain, see {@link FileWriteHandle#head}.
- * Introduced to decrease number of buffers allocation.
- * Used only for record itself is shorter than {@link #tlbSize}.
- */
- private final ThreadLocal tlb = new ThreadLocal() {
- @Override protected ByteBuffer initialValue() {
- ByteBuffer buf = ByteBuffer.allocateDirect(tlbSize);
-
- buf.order(GridUnsafe.NATIVE_BYTE_ORDER);
-
- return buf;
- }
- };
+ /** Updater for {@link #currHnd}, used for verify there are no concurrent update for current log segment handle */
+ private static final AtomicReferenceFieldUpdater CURR_HND_UPD =
+ AtomicReferenceFieldUpdater.newUpdater(FileWriteAheadLogManager.class, FileWriteHandle.class, "currHnd");
/** */
private volatile FileArchiver archiver;
@@ -249,7 +268,7 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
private final ThreadLocal lastWALPtr = new ThreadLocal<>();
/** Current log segment handle */
- private volatile FileWriteHandle currentHnd;
+ private volatile FileWriteHandle currHnd;
/** Environment failure. */
private volatile Throwable envFailed;
@@ -261,25 +280,26 @@ public class FileWriteAheadLogManager extends GridCacheSharedManagerAdapter impl
private final long walAutoArchiveAfterInactivity;
/**
- * Container with last WAL record logged timestamp.
- * Zero value means there was no records logged to current segment, skip possible archiving for this case
- * Value is filled only for case {@link #walAutoArchiveAfterInactivity} > 0
+ * Container with last WAL record logged timestamp. Zero value means there was no records logged to current
+ * segment, skip possible archiving for this case Value is filled only for case {@link
+ * #walAutoArchiveAfterInactivity} > 0
*/
private AtomicLong lastRecordLoggedMs = new AtomicLong();
/**
- * Cancellable task for {@link WALMode#BACKGROUND}, should be cancelled at shutdown
- * Null for non background modes
+ * Cancellable task for {@link WALMode#BACKGROUND}, should be cancelled at shutdown Null for non background modes
*/
@Nullable private volatile GridTimeoutProcessor.CancelableTask backgroundFlushSchedule;
/**
- * Reference to the last added next archive timeout check object.
- * Null if mode is not enabled.
- * Should be cancelled at shutdown
+ * Reference to the last added next archive timeout check object. Null if mode is not enabled. Should be cancelled
+ * at shutdown
*/
@Nullable private volatile GridTimeoutObject nextAutoArchiveTimeoutObj;
+ /** WAL writer worker. */
+ private WALWriter walWriter;
+
/**
* @param ctx Kernal context.
*/
@@ -294,7 +314,6 @@ public FileWriteAheadLogManager(@NotNull final GridKernalContext ctx) {
maxWalSegmentSize = dsCfg.getWalSegmentSize();
mode = dsCfg.getWalMode();
- tlbSize = dsCfg.getWalThreadLocalBufferSize();
flushFreq = dsCfg.getWalFlushFrequency();
fsyncDelay = dsCfg.getWalFsyncDelayNanos();
alwaysWriteFullPages = dsCfg.isAlwaysWriteFullPages();
@@ -324,7 +343,7 @@ public FileWriteAheadLogManager(@NotNull final GridKernalContext ctx) {
"write ahead log archive directory"
);
- serializer = new RecordSerializerFactoryImpl(cctx).createSerializer(serializerVersion);
+ serializer = new RecordSerializerFactoryImpl(cctx).createSerializer(serializerVer);
GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)cctx.database();
@@ -384,12 +403,15 @@ private void checkWalConfiguration() throws IgniteCheckedException {
try {
if (mode == WALMode.BACKGROUND) {
if (currHnd != null)
- currHnd.flush((FileWALPointer)null, true);
+ currHnd.flush(null);
}
if (currHnd != null)
currHnd.close(false);
+ if (walWriter != null)
+ walWriter.shutdown();
+
if (archiver != null)
archiver.shutdown();
@@ -400,7 +422,7 @@ private void checkWalConfiguration() throws IgniteCheckedException {
decompressor.shutdown();
}
catch (Exception e) {
- U.error(log, "Failed to gracefully close WAL segment: " + currentHnd.fileIO, e);
+ U.error(log, "Failed to gracefully close WAL segment: " + this.currHnd.fileIO, e);
}
}
@@ -432,7 +454,7 @@ private void checkWalConfiguration() throws IgniteCheckedException {
stop0(true);
- currentHnd = null;
+ currHnd = null;
}
/** {@inheritDoc} */
@@ -448,22 +470,33 @@ private void checkWalConfiguration() throws IgniteCheckedException {
/** {@inheritDoc} */
@Override public void resumeLogging(WALPointer lastPtr) throws IgniteCheckedException {
try {
- assert currentHnd == null;
+ assert currHnd == null;
assert lastPtr == null || lastPtr instanceof FileWALPointer;
FileWALPointer filePtr = (FileWALPointer)lastPtr;
- currentHnd = restoreWriteHandle(filePtr);
+ walWriter = new WALWriter();
+
+ if (!mmap)
+ walWriter.start();
+
+ currHnd = restoreWriteHandle(filePtr);
+
+ // For new handle write serializer version to it.
+ if (filePtr == null)
+ currHnd.writeHeader();
- if (currentHnd.serializer.version() != serializer.version()) {
+ if (currHnd.serializer.version() != serializer.version()) {
if (log.isInfoEnabled())
log.info("Record serializer version change detected, will start logging with a new WAL record " +
- "serializer to a new WAL segment [curFile=" + currentHnd + ", newVer=" + serializer.version() +
- ", oldVer=" + currentHnd.serializer.version() + ']');
+ "serializer to a new WAL segment [curFile=" + currHnd + ", newVer=" + serializer.version() +
+ ", oldVer=" + currHnd.serializer.version() + ']');
- rollOver(currentHnd);
+ rollOver(currHnd);
}
+ currHnd.resume = false;
+
if (mode == WALMode.BACKGROUND) {
backgroundFlushSchedule = cctx.time().schedule(new Runnable() {
@Override public void run() {
@@ -481,8 +514,8 @@ private void checkWalConfiguration() throws IgniteCheckedException {
}
/**
- * Schedules next check of inactivity period expired. Based on current record update timestamp.
- * At timeout method does check of inactivity period and schedules new launch.
+ * Schedules next check of inactivity period expired. Based on current record update timestamp. At timeout method
+ * does check of inactivity period and schedules new launch.
*/
private void scheduleNextInactivityPeriodElapsedCheck() {
final long lastRecMs = lastRecordLoggedMs.get();
@@ -518,13 +551,12 @@ private void scheduleNextInactivityPeriodElapsedCheck() {
* @return Latest serializer version.
*/
public int serializerVersion() {
- return serializerVersion;
+ return serializerVer;
}
/**
- * Checks if there was elapsed significant period of inactivity.
- * If WAL auto-archive is enabled using {@link #walAutoArchiveAfterInactivity} > 0 this method will activate
- * roll over by timeout
+ * Checks if there was elapsed significant period of inactivity. If WAL auto-archive is enabled using
+ * {@link #walAutoArchiveAfterInactivity} > 0 this method will activate roll over by timeout.
*/
private void checkWalRolloverRequiredDuringInactivityPeriod() {
if (walAutoArchiveAfterInactivity <= 0)
@@ -546,6 +578,8 @@ private void checkWalRolloverRequiredDuringInactivityPeriod() {
final FileWriteHandle handle = currentHandle();
try {
+ handle.buf.close();
+
rollOver(handle);
}
catch (IgniteCheckedException e) {
@@ -556,7 +590,7 @@ private void checkWalRolloverRequiredDuringInactivityPeriod() {
/** {@inheritDoc} */
@SuppressWarnings("TooBroadScope")
- @Override public WALPointer log(WALRecord record) throws IgniteCheckedException, StorageException {
+ @Override public WALPointer log(WALRecord rec) throws IgniteCheckedException, StorageException {
if (serializer == null || mode == WALMode.NONE)
return null;
@@ -567,10 +601,10 @@ private void checkWalRolloverRequiredDuringInactivityPeriod() {
return null;
// Need to calculate record size first.
- record.size(serializer.size(record));
+ rec.size(serializer.size(rec));
for (; ; currWrHandle = rollOver(currWrHandle)) {
- WALPointer ptr = currWrHandle.addRecord(record);
+ WALPointer ptr = currWrHandle.addRecord(rec);
if (ptr != null) {
metrics.onWalRecordLogged();
@@ -603,13 +637,11 @@ private void checkWalRolloverRequiredDuringInactivityPeriod() {
FileWALPointer filePtr = (FileWALPointer)(ptr == null ? lastWALPtr.get() : ptr);
- boolean forceFlush = filePtr != null && filePtr.forceFlush();
-
- if (mode == WALMode.BACKGROUND && !forceFlush)
+ if (mode == WALMode.BACKGROUND)
return;
- if (mode == WALMode.LOG_ONLY || forceFlush) {
- cur.flushOrWait(filePtr, false);
+ if (mode == LOG_ONLY) {
+ cur.flushOrWait(filePtr);
return;
}
@@ -618,12 +650,11 @@ private void checkWalRolloverRequiredDuringInactivityPeriod() {
if (filePtr != null && !cur.needFsync(filePtr))
return;
- cur.fsync(filePtr, false);
+ cur.fsync(filePtr);
}
/** {@inheritDoc} */
- @Override public WALIterator replay(WALPointer start)
- throws IgniteCheckedException, StorageException {
+ @Override public WALIterator replay(WALPointer start) throws IgniteCheckedException, StorageException {
assert start == null || start instanceof FileWALPointer : "Invalid start pointer: " + start;
FileWriteHandle hnd = currentHandle();
@@ -704,7 +735,7 @@ private boolean hasIndex(long absIdx) {
if (absIdx <= lastArchivedIndex())
return false;
- FileWriteHandle cur = currentHnd;
+ FileWriteHandle cur = currHnd;
return cur != null && cur.idx >= absIdx;
}
@@ -869,7 +900,7 @@ private File initDirectory(String cfg, String defDir, String consId, String msg)
* @return Current log segment handle.
*/
private FileWriteHandle currentHandle() {
- return currentHnd;
+ return currHnd;
}
/**
@@ -883,9 +914,11 @@ private FileWriteHandle rollOver(FileWriteHandle cur) throws StorageException, I
return hnd;
if (hnd.close(true)) {
- FileWriteHandle next = initNextWriteHandle(cur.idx);
+ FileWriteHandle next = initNextWriteHandle(cur);
+
+ next.writeHeader();
- boolean swapped = currentHndUpd.compareAndSet(this, hnd, next);
+ boolean swapped = CURR_HND_UPD.compareAndSet(this, hnd, next);
assert swapped : "Concurrent updates on rollover are not allowed";
@@ -913,14 +946,14 @@ private FileWriteHandle restoreWriteHandle(FileWALPointer lastReadPtr) throws Ig
File curFile = new File(walWorkDir, FileDescriptor.fileName(segNo));
- int offset = lastReadPtr == null ? 0 : lastReadPtr.fileOffset();
+ int off = lastReadPtr == null ? 0 : lastReadPtr.fileOffset();
int len = lastReadPtr == null ? 0 : lastReadPtr.length();
try {
FileIO fileIO = ioFactory.create(curFile);
try {
- int serVer = serializerVersion;
+ int serVer = serializerVer;
// If we have existing segment, try to read version from it.
if (lastReadPtr != null) {
@@ -928,7 +961,7 @@ private FileWriteHandle restoreWriteHandle(FileWALPointer lastReadPtr) throws Ig
serVer = readSerializerVersionAndCompactedFlag(fileIO).get1();
}
catch (SegmentEofException | EOFException ignore) {
- serVer = serializerVersion;
+ serVer = serializerVer;
}
}
@@ -936,19 +969,34 @@ private FileWriteHandle restoreWriteHandle(FileWALPointer lastReadPtr) throws Ig
if (log.isInfoEnabled())
log.info("Resuming logging to WAL segment [file=" + curFile.getAbsolutePath() +
- ", offset=" + offset + ", ver=" + serVer + ']');
+ ", offset=" + off + ", ver=" + serVer + ']');
+
+ SegmentedRingByteBuffer rbuf;
+
+ if (mmap) {
+ try {
+ MappedByteBuffer buf = fileIO.map((int)maxWalSegmentSize);
+
+ rbuf = new SegmentedRingByteBuffer(buf, metrics);
+ }
+ catch (IOException e) {
+ throw new IgniteCheckedException(e);
+ }
+ }
+ else
+ rbuf = new SegmentedRingByteBuffer(dsCfg.getWalBufferSize(), maxWalSegmentSize, DIRECT, metrics);
+
+ if (lastReadPtr != null)
+ rbuf.init(lastReadPtr.fileOffset() + lastReadPtr.length());
FileWriteHandle hnd = new FileWriteHandle(
fileIO,
absIdx,
cctx.igniteInstanceName(),
- offset + len,
- maxWalSegmentSize,
- ser);
-
- // For new handle write serializer version to it.
- if (lastReadPtr == null)
- hnd.writeSerializerVersion();
+ off + len,
+ true,
+ ser,
+ rbuf);
archiver.currentWalIndex(absIdx);
@@ -966,33 +1014,46 @@ private FileWriteHandle restoreWriteHandle(FileWALPointer lastReadPtr) throws Ig
}
/**
- * Fills the file header for a new segment.
- * Calling this method signals we are done with the segment and it can be archived.
- * If we don't have prepared file yet and achiever is busy this method blocks
+ * Fills the file header for a new segment. Calling this method signals we are done with the segment and it can be
+ * archived. If we don't have prepared file yet and achiever is busy this method blocks
*
- * @param curIdx current absolute segment released by WAL writer
+ * @param cur Current file write handle released by WAL writer
* @return Initialized file handle.
* @throws StorageException If IO exception occurred.
* @throws IgniteCheckedException If failed.
*/
- private FileWriteHandle initNextWriteHandle(long curIdx) throws StorageException, IgniteCheckedException {
+ private FileWriteHandle initNextWriteHandle(FileWriteHandle cur) throws StorageException, IgniteCheckedException {
try {
- File nextFile = pollNextFile(curIdx);
+ File nextFile = pollNextFile(cur.idx);
if (log.isDebugEnabled())
log.debug("Switching to a new WAL segment: " + nextFile.getAbsolutePath());
FileIO fileIO = ioFactory.create(nextFile);
+ SegmentedRingByteBuffer rbuf;
+
+ if (mmap) {
+ try {
+ MappedByteBuffer buf = fileIO.map((int)maxWalSegmentSize);
+
+ rbuf = new SegmentedRingByteBuffer(buf, metrics);
+ }
+ catch (IOException e) {
+ throw new IgniteCheckedException(e);
+ }
+ }
+ else
+ rbuf = cur.buf.reset();
+
FileWriteHandle hnd = new FileWriteHandle(
fileIO,
- curIdx + 1,
+ cur.idx + 1,
cctx.igniteInstanceName(),
0,
- maxWalSegmentSize,
- serializer);
-
- hnd.writeSerializerVersion();
+ false,
+ serializer,
+ rbuf);
return hnd;
}
@@ -1094,8 +1155,7 @@ private void createFile(File file) throws IgniteCheckedException {
}
/**
- * Retrieves next available file to write WAL data, waiting
- * if necessary for a segment to become available.
+ * Retrieves next available file to write WAL data, waiting if necessary for a segment to become available.
*
* @param curIdx Current absolute WAL segment index.
* @return File ready for use as new WAL segment.
@@ -1137,32 +1197,28 @@ public static FileDescriptor[] scan(File[] allFiles) {
private void checkEnvironment() throws StorageException {
if (envFailed != null)
throw new StorageException("Failed to flush WAL buffer (environment was invalidated by a " +
- "previous error)", envFailed);
+ "previous error)", envFailed);
}
/**
- * File archiver operates on absolute segment indexes. For any given absolute segment index N we can calculate
- * the work WAL segment: S(N) = N % dsCfg.walSegments.
- * When a work segment is finished, it is given to the archiver. If the absolute index of last archived segment
- * is denoted by A and the absolute index of next segment we want to write is denoted by W, then we can allow
- * write to S(W) if W - A <= walSegments.
+ * File archiver operates on absolute segment indexes. For any given absolute segment index N we can calculate the
+ * work WAL segment: S(N) = N % dsCfg.walSegments. When a work segment is finished, it is given to the archiver. If
+ * the absolute index of last archived segment is denoted by A and the absolute index of next segment we want to
+ * write is denoted by W, then we can allow write to S(W) if W - A <= walSegments.
*
- * Monitor of current object is used for notify on:
- *
current file
+ * index changed ({@link FileArchiver#curAbsWalIdx})
last archived file index was changed ({@link
+ * FileArchiver#lastAbsArchivedIdx})
some WAL index was removed from {@link FileArchiver#locked} map
*
*/
private class FileArchiver extends Thread {
/** Exception which occurred during initial creation of files or during archiving WAL segment */
- private IgniteCheckedException cleanException;
+ private IgniteCheckedException cleanErr;
/**
- * Absolute current segment index WAL Manager writes to. Guarded by this.
- * Incremented during rollover. Also may be directly set if WAL is resuming logging after start.
+ * Absolute current segment index WAL Manager writes to. Guarded by this. Incremented during
+ * rollover. Also may be directly set if WAL is resuming logging after start.
*/
private long curAbsWalIdx = -1;
@@ -1176,8 +1232,8 @@ private class FileArchiver extends Thread {
private NavigableMap reserved = new TreeMap<>();
/**
- * Maps absolute segment index to locks counter. Lock on segment protects from archiving segment and may
- * come from {@link RecordsIterator} during WAL replay. Map itself is guarded by this.
+ * Maps absolute segment index to locks counter. Lock on segment protects from archiving segment and may come
+ * from {@link RecordsIterator} during WAL replay. Map itself is guarded by this.
*/
private Map locked = new HashMap<>();
@@ -1265,7 +1321,7 @@ private synchronized void release(long absIdx) {
catch (IgniteCheckedException e) {
synchronized (this) {
// Stop the thread and report to starter.
- cleanException = e;
+ cleanErr = e;
notifyAll();
@@ -1323,7 +1379,7 @@ private synchronized void release(long absIdx) {
}
catch (IgniteCheckedException e) {
synchronized (this) {
- cleanException = e;
+ cleanErr = e;
notifyAll();
}
@@ -1346,8 +1402,8 @@ private void changeLastArchivedIndexAndWakeupCompressor(long idx) {
}
/**
- * Gets the absolute index of the next WAL segment available to write.
- * Blocks till there are available file to write
+ * Gets the absolute index of the next WAL segment available to write. Blocks till there are available file to
+ * write
*
* @param curIdx Current absolute index that we want to increment.
* @return Next index (curWalSegmIdx+1) when it is ready to be written.
@@ -1356,8 +1412,8 @@ private void changeLastArchivedIndexAndWakeupCompressor(long idx) {
private long nextAbsoluteSegmentIndex(long curIdx) throws IgniteCheckedException {
try {
synchronized (this) {
- if (cleanException != null)
- throw cleanException;
+ if (cleanErr != null)
+ throw cleanErr;
assert curIdx == curAbsWalIdx;
@@ -1366,7 +1422,7 @@ private long nextAbsoluteSegmentIndex(long curIdx) throws IgniteCheckedException
// Notify archiver thread.
notifyAll();
- while (curAbsWalIdx - lastAbsArchivedIdx > dsCfg.getWalSegments() && cleanException == null)
+ while (curAbsWalIdx - lastAbsArchivedIdx > dsCfg.getWalSegments() && cleanErr == null)
wait();
return curAbsWalIdx;
@@ -1437,8 +1493,7 @@ private void releaseWorkSegment(long absIdx) {
}
/**
- * Moves WAL segment from work folder to archive folder.
- * Temp file is used to do movement
+ * Moves WAL segment from work folder to archive folder. Temp file is used to do movement
*
* @param absIdx Absolute index to archive.
*/
@@ -1491,8 +1546,8 @@ private boolean checkStop() {
}
/**
- * Background creation of all segments except first. First segment was created in main thread by
- * {@link FileWriteAheadLogManager#checkOrPrepareFiles()}
+ * Background creation of all segments except first. First segment was created in main thread by {@link
+ * FileWriteAheadLogManager#checkOrPrepareFiles()}
*/
private void allocateRemainingFiles() throws IgniteCheckedException {
checkFiles(1, true, new IgnitePredicate() {
@@ -1659,7 +1714,7 @@ private void compressSegmentToFile(long nextSegment, File raw, File zip)
int segmentSerializerVer;
try (FileIO fileIO = ioFactory.create(raw)) {
- IgniteBiTuple tup = FileWriteAheadLogManager.readSerializerVersionAndCompactedFlag(fileIO);
+ IgniteBiTuple tup = readSerializerVersionAndCompactedFlag(fileIO);
segmentSerializerVer = tup.get1();
}
@@ -1667,7 +1722,10 @@ private void compressSegmentToFile(long nextSegment, File raw, File zip)
try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zip)))) {
zos.putNextEntry(new ZipEntry(""));
- zos.write(prepareSerializerVersionBuffer(nextSegment, segmentSerializerVer, true).array());
+ ByteBuffer buf = ByteBuffer.allocate(RecordV1Serializer.HEADER_RECORD_SIZE);
+ buf.order(ByteOrder.nativeOrder());
+
+ zos.write(prepareSerializerVersionBuffer(nextSegment, segmentSerializerVer, true, buf).array());
final CIX1 appendToZipC = new CIX1() {
@Override public void applyx(WALRecord record) throws IgniteCheckedException {
@@ -1683,7 +1741,7 @@ private void compressSegmentToFile(long nextSegment, File raw, File zip)
};
try (SingleSegmentLogicalRecordsIterator iter = new SingleSegmentLogicalRecordsIterator(
- log, cctx, ioFactory, tlbSize, nextSegment, walArchiveDir, appendToZipC)) {
+ log, cctx, ioFactory, BUF_SIZE, nextSegment, walArchiveDir, appendToZipC)) {
while (iter.hasNextX())
iter.nextX();
@@ -1722,7 +1780,7 @@ private class FileDecompressor extends Thread {
private PriorityBlockingQueue segmentsQueue = new PriorityBlockingQueue<>();
/** Byte array for draining data. */
- private byte[] arr = new byte[tlbSize];
+ private byte[] arr = new byte[BUF_SIZE];
/**
*
@@ -1812,8 +1870,8 @@ private void shutdown() throws IgniteInterruptedCheckedException {
}
/**
- * Validate files depending on {@link DataStorageConfiguration#getWalSegments()} and create if need.
- * Check end when exit condition return false or all files are passed.
+ * Validate files depending on {@link DataStorageConfiguration#getWalSegments()} and create if need. Check end
+ * when exit condition return false or all files are passed.
*
* @param startWith Start with.
* @param create Flag create file.
@@ -1821,7 +1879,7 @@ private void shutdown() throws IgniteInterruptedCheckedException {
* @throws IgniteCheckedException if validation or create file fail.
*/
private void checkFiles(int startWith, boolean create, IgnitePredicate p) throws IgniteCheckedException {
- for (int i = startWith; i < dsCfg.getWalSegments() && (p == null || (p != null && p.apply(i))); i++) {
+ for (int i = startWith; i < dsCfg.getWalSegments() && (p == null || p.apply(i)); i++) {
File checkFile = new File(walWorkDir, FileDescriptor.fileName(i));
if (checkFile.exists()) {
@@ -1845,7 +1903,7 @@ else if (create)
* @return Serializer version stored in the file.
* @throws IgniteCheckedException If failed to read serializer version.
*/
- public static IgniteBiTuple readSerializerVersionAndCompactedFlag(FileIO io)
+ static IgniteBiTuple readSerializerVersionAndCompactedFlag(FileIO io)
throws IgniteCheckedException, IOException {
try (ByteBufferExpander buf = new ByteBufferExpander(RecordV1Serializer.HEADER_RECORD_SIZE, ByteOrder.nativeOrder())) {
FileInput in = new FileInput(io, buf);
@@ -1870,6 +1928,7 @@ public static IgniteBiTuple readSerializerVersionAndCompactedF
long hdrMagicNum = in.readLong();
boolean compacted;
+
if (hdrMagicNum == HeaderRecord.REGULAR_MAGIC)
compacted = false;
else if (hdrMagicNum == HeaderRecord.COMPACTED_MAGIC)
@@ -1890,39 +1949,13 @@ else if (hdrMagicNum == HeaderRecord.COMPACTED_MAGIC)
}
/**
- * Writes record serializer version to provided {@code io}.
- * NOTE: Method mutates position of {@code io}.
+ * Needs only for WAL compaction.
*
- * @param io I/O interface for file.
- * @param idx Segment index.
- * @param version Serializer version.
- * @return I/O position after write version.
- * @throws IOException If failed to write serializer version.
- */
- public static long writeSerializerVersion(FileIO io, long idx, int version, WALMode mode) throws IOException {
- ByteBuffer buffer = prepareSerializerVersionBuffer(idx, version, false);
-
- do {
- io.write(buffer);
- }
- while (buffer.hasRemaining());
-
- // Flush
- if (mode == WALMode.DEFAULT)
- io.force();
-
- return io.position();
- }
-
- /**
* @param idx Index.
* @param ver Version.
* @param compacted Compacted flag.
*/
- @NotNull private static ByteBuffer prepareSerializerVersionBuffer(long idx, int ver, boolean compacted) {
- ByteBuffer buf = ByteBuffer.allocate(RecordV1Serializer.HEADER_RECORD_SIZE);
- buf.order(ByteOrder.nativeOrder());
-
+ @NotNull private static ByteBuffer prepareSerializerVersionBuffer(long idx, int ver, boolean compacted, ByteBuffer buf) {
// Write record type.
buf.put((byte) (WALRecord.RecordType.HEADER_RECORD.ordinal() + 1));
@@ -1936,7 +1969,7 @@ public static long writeSerializerVersion(FileIO io, long idx, int version, WALM
buf.putInt(ver);
// Place CRC if needed.
- if (!RecordV1Serializer.SKIP_CRC) {
+ if (!RecordV1Serializer.skipCrc) {
int curPos = buf.position();
buf.position(0);
@@ -2005,25 +2038,8 @@ public static String fileName(long segment) {
return b.toString();
}
- /**
- * @param segment Segment number as integer.
- * @return Segment number as aligned string.
- */
- private static String segmentNumber(long segment) {
- SB b = new SB();
-
- String segmentStr = Long.toString(segment);
-
- for (int i = segmentStr.length(); i < 16; i++)
- b.a('0');
-
- b.a(segmentStr);
-
- return b.toString();
- }
-
/** {@inheritDoc} */
- @Override public int compareTo(FileDescriptor o) {
+ @Override public int compareTo(@NotNull FileDescriptor o) {
return Long.compare(idx, o.idx);
}
@@ -2065,7 +2081,7 @@ public String getAbsolutePath() {
*/
private abstract static class FileHandle {
/** I/O interface for read/write operations with file */
- protected FileIO fileIO;
+ FileIO fileIO;
/** Absolute WAL segment file index (incremental counter) */
protected final long idx;
@@ -2095,8 +2111,8 @@ public static class ReadFileHandle extends FileHandle {
FileInput in;
/**
- * true if this file handle came from work directory.
- * false if this file handle came from archive directory.
+ * true if this file handle came from work directory. false if this file handle came
+ * from archive directory.
*/
private boolean workDir;
@@ -2107,11 +2123,11 @@ public static class ReadFileHandle extends FileHandle {
* @param in File input.
*/
ReadFileHandle(
- FileIO fileIO,
- long idx,
- String gridName,
- RecordSerializer ser,
- FileInput in
+ FileIO fileIO,
+ long idx,
+ String gridName,
+ RecordSerializer ser,
+ FileInput in
) {
super(fileIO, idx, gridName);
@@ -2140,16 +2156,8 @@ private class FileWriteHandle extends FileHandle {
/** */
private final RecordSerializer serializer;
- /** See {@link FileWriteAheadLogManager#maxWalSegmentSize} */
- private final long maxSegmentSize;
-
- /**
- * Accumulated WAL records chain.
- * This reference points to latest WAL record.
- * When writing records chain is iterated from latest to oldest (see {@link WALRecord#previous()})
- * Records from chain are saved into buffer in reverse order
- */
- private final AtomicReference head = new AtomicReference<>();
+ /** Created on resume logging. */
+ private volatile boolean resume;
/**
* Position in current file after the end of last written record (incremented after file channel write
@@ -2160,7 +2168,7 @@ private class FileWriteHandle extends FileHandle {
/** */
private volatile long lastFsyncPos;
- /** Stop guard to provide warranty that only one thread will be successful in calling {@link #close(boolean)}*/
+ /** Stop guard to provide warranty that only one thread will be successful in calling {@link #close(boolean)} */
private final AtomicBoolean stop = new AtomicBoolean(false);
/** */
@@ -2173,17 +2181,21 @@ private class FileWriteHandle extends FileHandle {
private final Condition fsync = lock.newCondition();
/**
- * Next segment available condition.
- * Protection from "spurious wakeup" is provided by predicate {@link #fileIO}=null
+ * Next segment available condition. Protection from "spurious wakeup" is provided by predicate {@link
+ * #fileIO}=null
*/
private final Condition nextSegment = lock.newCondition();
+ /** Buffer. */
+ private final SegmentedRingByteBuffer buf;
+
/**
* @param fileIO I/O file interface to use
* @param idx Absolute WAL segment file index for easy access.
* @param pos Position.
- * @param maxSegmentSize Max segment size.
+ * @param resume Created on resume logging flag.
* @param serializer Serializer.
+ * @param buf Buffer.
* @throws IOException If failed.
*/
private FileWriteHandle(
@@ -2191,8 +2203,9 @@ private FileWriteHandle(
long idx,
String gridName,
long pos,
- long maxSegmentSize,
- RecordSerializer serializer
+ boolean resume,
+ RecordSerializer serializer,
+ SegmentedRingByteBuffer buf
) throws IOException {
super(fileIO, idx, gridName);
@@ -2200,109 +2213,90 @@ private FileWriteHandle(
fileIO.position(pos);
- this.maxSegmentSize = maxSegmentSize;
this.serializer = serializer;
- head.set(new FakeRecord(new FileWALPointer(idx, (int)pos, 0), false));
written = pos;
lastFsyncPos = pos;
+ this.resume = resume;
+ this.buf = buf;
}
+
/**
* Write serializer version to current handle.
- * NOTE: Method mutates {@code fileIO} position, written and lastFsyncPos fields.
*
* @throws IgniteCheckedException If fail to write serializer version.
*/
- public void writeSerializerVersion() throws IgniteCheckedException {
+ public void writeHeader() throws IgniteCheckedException {
try {
- assert fileIO.position() == 0 : "Serializer version can be written only at the begin of file " +
- fileIO.position();
-
- long updatedPosition = FileWriteAheadLogManager.writeSerializerVersion(fileIO, idx,
- serializer.version(), mode);
-
- written = updatedPosition;
- lastFsyncPos = updatedPosition;
- head.set(new FakeRecord(new FileWALPointer(idx, (int)updatedPosition, 0), false));
+ assert fileIO.position() == 0 : "Serializer version can be written only at the begin of file. " +
+ "Current file position: " + fileIO.position();
}
catch (IOException e) {
throw new IgniteCheckedException("Unable to write serializer version for segment " + idx, e);
}
- }
- /**
- * Checks if current head is a close fake record and returns {@code true} if so.
- *
- * @return {@code true} if current head is close record.
- */
- private boolean stopped() {
- return stopped(head.get());
- }
+ SegmentedRingByteBuffer.WriteSegment seg = buf.offer(RecordV1Serializer.HEADER_RECORD_SIZE);
- /**
- * @param record Record to check.
- * @return {@code true} if the record is fake close record.
- */
- private boolean stopped(WALRecord record) {
- return record instanceof FakeRecord && ((FakeRecord)record).stop;
+ assert seg != null && seg.position() > 0;
+
+ prepareSerializerVersionBuffer(idx, serializerVersion(), false, seg.buffer());
+
+ seg.release();
}
/**
- * @param rec Record to be added to record chain as new {@link #head}
+ * @param rec Record to be added to write queue.
* @return Pointer or null if roll over to next segment is required or already started by other thread.
* @throws StorageException If failed.
* @throws IgniteCheckedException If failed.
*/
@Nullable private WALPointer addRecord(WALRecord rec) throws StorageException, IgniteCheckedException {
- assert rec.size() > 0 || rec.getClass() == FakeRecord.class;
+ assert rec.size() > 0 : rec;
- boolean flushed = false;
+ for (;;) {
+ checkEnvironment();
- for (; ; ) {
- WALRecord h = head.get();
+ SegmentedRingByteBuffer.WriteSegment seg;
- long nextPos = nextPosition(h);
+ // Buffer can be in open state in case of resuming with different serializer version.
+ if (rec.type() == SWITCH_SEGMENT_RECORD && !currHnd.resume)
+ seg = buf.offerSafe(rec.size());
+ else
+ seg = buf.offer(rec.size());
- if (nextPos + rec.size() >= maxSegmentSize || stopped(h)) {
- // Can not write to this segment, need to switch to the next one.
- return null;
- }
+ FileWALPointer ptr = null;
- int newChainSize = h.chainSize() + rec.size();
+ if (seg != null) {
+ try {
+ int pos = (int)(seg.position() - rec.size());
- if (newChainSize > tlbSize && !flushed) {
- boolean res = h.previous() == null || flush(h, false);
+ ByteBuffer buf = seg.buffer();
- if (rec.size() > tlbSize)
- flushed = res;
+ if (buf == null || (stop.get() && rec.type() != SWITCH_SEGMENT_RECORD))
+ return null; // Can not write to this segment, need to switch to the next one.
- continue;
- }
+ ptr = new FileWALPointer(idx, pos, rec.size());
- rec.chainSize(newChainSize);
- rec.previous(h);
+ rec.position(ptr);
- FileWALPointer ptr = new FileWALPointer(
- idx,
- (int)nextPos,
- rec.size(),
- // We need to force checkpoint records into file in BACKGROUND WALMode.
- mode == WALMode.BACKGROUND && rec instanceof CheckpointRecord);
+ fillBuffer(buf, rec);
- rec.position(ptr);
+ if (mmap)
+ written = seg.position();
- if (head.compareAndSet(h, rec))
- return ptr;
- }
- }
+ return ptr;
+ }
+ finally {
+ seg.release();
- /**
- * @param rec Record.
- * @return Position for the next record.
- */
- private long nextPosition(WALRecord rec) {
- return recordOffset(rec) + rec.size();
+ if (mode == WALMode.BACKGROUND && rec instanceof CheckpointRecord)
+ flushOrWait(ptr);
+ }
+ }
+ else
+ walWriter.flushAll();
+ }
}
/**
@@ -2311,192 +2305,45 @@ private long nextPosition(WALRecord rec) {
* @param ptr Pointer.
* @throws IgniteCheckedException If failed.
*/
- private void flushOrWait(FileWALPointer ptr, boolean stop) throws IgniteCheckedException {
- long expWritten;
-
+ private void flushOrWait(FileWALPointer ptr) throws IgniteCheckedException {
if (ptr != null) {
// If requested obsolete file index, it must be already flushed by close.
if (ptr.index() != idx)
return;
-
- expWritten = ptr.fileOffset();
}
- else // We read head position before the flush because otherwise we can get wrong position.
- expWritten = recordOffset(head.get());
-
- if (flush(ptr, stop))
- return;
- else if (stop) {
- FakeRecord fr = (FakeRecord)head.get();
- assert fr.stop : "Invalid fake record on top of the queue: " + fr;
-
- expWritten = recordOffset(fr);
- }
-
- // Spin-wait for a while before acquiring the lock.
- for (int i = 0; i < 64; i++) {
- if (written >= expWritten)
- return;
- }
-
- // If we did not flush ourselves then await for concurrent flush to complete.
- lock.lock();
-
- try {
- while (written < expWritten && envFailed == null)
- U.awaitQuiet(writeComplete);
- }
- finally {
- lock.unlock();
- }
+ flush(ptr);
}
/**
* @param ptr Pointer.
- * @return {@code true} If the flush really happened.
* @throws IgniteCheckedException If failed.
* @throws StorageException If failed.
*/
- private boolean flush(FileWALPointer ptr, boolean stop) throws IgniteCheckedException, StorageException {
+ private void flush(FileWALPointer ptr) throws IgniteCheckedException, StorageException {
if (ptr == null) { // Unconditional flush.
- for (; ; ) {
- WALRecord expHead = head.get();
-
- if (expHead.previous() == null) {
- FakeRecord frHead = (FakeRecord)expHead;
+ walWriter.flushAll();
- if (frHead.stop == stop || frHead.stop ||
- head.compareAndSet(expHead, new FakeRecord(frHead.position(), stop)))
- return false;
- }
-
- if (flush(expHead, stop))
- return true;
- }
+ return;
}
assert ptr.index() == idx;
- for (; ; ) {
- WALRecord h = head.get();
-
- // If current chain begin position is greater than requested, then someone else flushed our changes.
- if (chainBeginPosition(h) > ptr.fileOffset())
- return false;
-
- if (flush(h, stop))
- return true; // We are lucky.
- }
- }
-
- /**
- * @param h Head of the chain.
- * @return Chain begin position.
- */
- private long chainBeginPosition(WALRecord h) {
- return recordOffset(h) + h.size() - h.chainSize();
+ walWriter.flushBuffer(ptr.fileOffset());
}
/**
- * @param expHead Expected head of chain. If head was changed, flush is not performed in this thread
+ * @param buf Buffer.
+ * @param rec WAL record.
* @throws IgniteCheckedException If failed.
- * @throws StorageException If failed.
*/
- private boolean flush(WALRecord expHead, boolean stop) throws StorageException, IgniteCheckedException {
- if (expHead.previous() == null) {
- FakeRecord frHead = (FakeRecord)expHead;
-
- if (!stop || frHead.stop) // Protects from CASing terminal FakeRecord(true) to FakeRecord(false)
- return false;
- }
-
- // Fail-fast before CAS.
- checkEnvironment();
-
- if (!head.compareAndSet(expHead, new FakeRecord(new FileWALPointer(idx, (int)nextPosition(expHead), 0), stop)))
- return false;
-
- if (expHead.chainSize() == 0)
- return false;
-
- // At this point we grabbed the piece of WAL chain.
- // Any failure in this code must invalidate the environment.
+ private void fillBuffer(ByteBuffer buf, WALRecord rec) throws IgniteCheckedException {
try {
- // We can safely allow other threads to start building next chains while we are doing flush here.
- ByteBuffer buf;
-
- boolean tmpBuf = false;
-
- if (expHead.chainSize() > tlbSize) {
- buf = GridUnsafe.allocateBuffer(expHead.chainSize());
-
- tmpBuf = true; // We need to manually release this temporary direct buffer.
- }
- else
- buf = tlb.get();
-
- try {
- long pos = fillBuffer(buf, expHead);
-
- writeBuffer(pos, buf);
- }
- finally {
- if (tmpBuf)
- GridUnsafe.freeBuffer(buf);
- }
-
- return true;
+ serializer.writeRecord(rec, buf);
}
- catch (Throwable e) {
- invalidateEnvironment(e);
-
- // All workers waiting for a next segment must be woken up and stopped
- signalNextAvailable();
-
- throw e;
- }
- }
-
- /**
- * Serializes WAL records chain to provided byte buffer
- *
- * @param buf Buffer, will be filled with records chain from end to beginning
- * @param head Head of the chain to write to the buffer.
- * @return Position in file for this buffer.
- * @throws IgniteCheckedException If failed.
- */
- private long fillBuffer(ByteBuffer buf, WALRecord head) throws IgniteCheckedException {
- final int limit = head.chainSize();
-
- assert limit <= buf.capacity();
-
- buf.rewind();
- buf.limit(limit);
-
- do {
- buf.position(head.chainSize() - head.size());
- buf.limit(head.chainSize()); // Just to make sure that serializer works in bounds.
-
- try {
- serializer.writeRecord(head, buf);
- }
- catch (RuntimeException e) {
- throw new IllegalStateException("Failed to write record: " + head, e);
- }
-
- assert !buf.hasRemaining() : "Reported record size is greater than actual: " + head;
-
- head = head.previous();
+ catch (RuntimeException e) {
+ throw new IllegalStateException("Failed to write record: " + rec, e);
}
- while (head.previous() != null);
-
- assert head instanceof FakeRecord : head.getClass();
-
- buf.rewind();
- buf.limit(limit);
-
- return recordOffset(head);
}
/**
@@ -2530,7 +2377,7 @@ private FileWALPointer position() {
* @param ptr Pointer to sync.
* @throws StorageException If failed.
*/
- private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, IgniteCheckedException {
+ private void fsync(FileWALPointer ptr) throws StorageException, IgniteCheckedException {
lock.lock();
try {
@@ -2538,7 +2385,7 @@ private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, Ig
if (!needFsync(ptr))
return;
- if (fsyncDelay > 0 && !stopped()) {
+ if (fsyncDelay > 0 && !this.stop.get()) {
// Delay fsync to collect as many updates as possible: trade latency for throughput.
U.await(fsync, fsyncDelay, TimeUnit.NANOSECONDS);
@@ -2547,9 +2394,9 @@ private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, Ig
}
}
- flushOrWait(ptr, stop);
+ flushOrWait(ptr);
- if (stopped())
+ if (this.stop.get())
return;
if (lastFsyncPos != written) {
@@ -2559,12 +2406,26 @@ private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, Ig
long start = metricsEnabled ? System.nanoTime() : 0;
- try {
- fileIO.force();
- }
- catch (IOException e) {
- throw new StorageException(e);
+ if (mmap) {
+ long pos = ptr == null ? -1 : ptr.fileOffset();
+
+ List segs = buf.poll(pos);
+
+ if (segs != null) {
+ assert segs.size() == 1;
+
+ SegmentedRingByteBuffer.ReadSegment seg = segs.get(0);
+
+ int off = seg.buffer().position();
+ int len = seg.buffer().limit() - off;
+
+ fsync((MappedByteBuffer)buf.buf, off, len);
+
+ seg.release();
+ }
}
+ else
+ walWriter.force();
lastFsyncPos = written;
@@ -2582,6 +2443,30 @@ private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, Ig
}
}
+ /**
+ * @param buf Mapped byte buffer..
+ * @param off Offset.
+ * @param len Length.
+ */
+ private void fsync(MappedByteBuffer buf, int off, int len) throws IgniteCheckedException {
+ try {
+ long mappedOff = (Long)mappingOffset.invoke(buf);
+
+ assert mappedOff == 0 : mappedOff;
+
+ long addr = (Long)mappingAddress.invoke(buf, mappedOff);
+
+ long delta = (addr + off) % PAGE_SIZE;
+
+ long alignedAddr = (addr + off) - delta;
+
+ force0.invoke(buf, fd.get(buf), alignedAddr, len + delta);
+ }
+ catch (IllegalAccessException | InvocationTargetException e) {
+ throw new IgniteCheckedException(e);
+ }
+ }
+
/**
* @return {@code true} If this thread actually closed the segment.
* @throws IgniteCheckedException If failed.
@@ -2589,48 +2474,62 @@ private void fsync(FileWALPointer ptr, boolean stop) throws StorageException, Ig
*/
private boolean close(boolean rollOver) throws IgniteCheckedException, StorageException {
if (stop.compareAndSet(false, true)) {
- lock.lock();
-
try {
- flushOrWait(null, true);
+ lock.lock();
- assert stopped() : "Segment is not closed after close flush: " + head.get();
+ flushOrWait(null);
try {
RecordSerializer backwardSerializer = new RecordSerializerFactoryImpl(cctx)
- .createSerializer(serializerVersion);
+ .createSerializer(serializerVer);
SwitchSegmentRecord segmentRecord = new SwitchSegmentRecord();
int switchSegmentRecSize = backwardSerializer.size(segmentRecord);
- if (rollOver && written < (maxSegmentSize - switchSegmentRecSize)) {
- final ByteBuffer buf = ByteBuffer.allocate(switchSegmentRecSize);
+ if (rollOver && written < (maxWalSegmentSize - switchSegmentRecSize)) {
+ segmentRecord.size(switchSegmentRecSize);
- segmentRecord.position(new FileWALPointer(idx, (int)written, switchSegmentRecSize));
- backwardSerializer.writeRecord(segmentRecord, buf);
+ WALPointer segRecPtr = addRecord(segmentRecord);
- buf.rewind();
-
- int rem = buf.remaining();
+ if (segRecPtr != null)
+ fsync((FileWALPointer)segRecPtr);
+ }
- while (rem > 0) {
- int written0 = fileIO.write(buf, written);
+ if (mmap) {
+ List segs = buf.poll(maxWalSegmentSize);
- written += written0;
+ if (segs != null) {
+ assert segs.size() == 1;
- rem -= written0;
+ segs.get(0).release();
}
}
// Do the final fsync.
if (mode == WALMode.DEFAULT) {
- fileIO.force();
+ if (mmap)
+ ((MappedByteBuffer)buf.buf).force();
+ else
+ fileIO.force();
lastFsyncPos = written;
}
- fileIO.close();
+ if (mmap) {
+ try {
+ fileIO.close();
+ }
+ catch (IOException e) {
+ // No-op.
+ }
+ }
+ else {
+ walWriter.close();
+
+ if (!rollOver)
+ buf.free();
+ }
}
catch (IOException e) {
throw new IgniteCheckedException(e);
@@ -2642,6 +2541,9 @@ private boolean close(boolean rollOver) throws IgniteCheckedException, StorageEx
return true;
}
finally {
+ if (mmap)
+ buf.free();
+
lock.unlock();
}
}
@@ -2656,15 +2558,8 @@ private void signalNextAvailable() {
lock.lock();
try {
- WALRecord rec = head.get();
-
- if (envFailed == null) {
- assert rec instanceof FakeRecord : "Expected head FakeRecord, actual head "
- + (rec != null ? rec.getClass().getSimpleName() : "null");
-
- assert written == lastFsyncPos || mode != WALMode.DEFAULT :
- "fsync [written=" + written + ", lastFsync=" + lastFsyncPos + ']';
- }
+ assert envFailed != null || written == lastFsyncPos || mode != WALMode.DEFAULT :
+ "fsync [written=" + written + ", lastFsync=" + lastFsyncPos + ", idx=" + idx + ']';
fileIO = null;
@@ -2690,92 +2585,6 @@ private void awaitNext() throws IgniteCheckedException {
}
}
- /**
- * @param pos Position in file to start write from. May be checked against actual position to wait previous
- * writes to complete
- * @param buf Buffer to write to file
- * @throws StorageException If failed.
- * @throws IgniteCheckedException If failed.
- */
- @SuppressWarnings("TooBroadScope")
- private void writeBuffer(long pos, ByteBuffer buf) throws StorageException, IgniteCheckedException {
- boolean interrupted = false;
-
- lock.lock();
-
- try {
- assert fileIO != null : "Writing to a closed segment.";
-
- checkEnvironment();
-
- long lastLogged = U.currentTimeMillis();
-
- long logBackoff = 2_000;
-
- // If we were too fast, need to wait previous writes to complete.
- while (written != pos) {
- assert written < pos : "written = " + written + ", pos = " + pos; // No one can write further than we are now.
-
- // Permutation occurred between blocks write operations.
- // Order of acquiring lock is not the same as order of write.
- long now = U.currentTimeMillis();
-
- if (now - lastLogged >= logBackoff) {
- if (logBackoff < 60 * 60_000)
- logBackoff *= 2;
-
- U.warn(log, "Still waiting for a concurrent write to complete [written=" + written +
- ", pos=" + pos + ", lastFsyncPos=" + lastFsyncPos + ", stop=" + stop.get() +
- ", actualPos=" + safePosition() + ']');
-
- lastLogged = now;
- }
-
- try {
- writeComplete.await(2, TimeUnit.SECONDS);
- }
- catch (InterruptedException ignore) {
- interrupted = true;
- }
-
- checkEnvironment();
- }
-
- // Do the write.
- int size = buf.remaining();
-
- assert size > 0 : size;
-
- try {
- assert written == fileIO.position();
-
- do {
- fileIO.write(buf);
- }
- while (buf.hasRemaining());
-
- written += size;
-
- metrics.onWalBytesWritten(size);
-
- assert written == fileIO.position();
- }
- catch (IOException e) {
- invalidateEnvironmentLocked(e);
-
- throw new StorageException(e);
- }
- }
- finally {
- writeComplete.signalAll();
-
- lock.unlock();
-
- if (interrupted)
- Thread.currentThread().interrupt();
- }
- }
-
/**
* @param e Exception to set as a cause for all further operations.
*/
@@ -2799,8 +2608,8 @@ private void invalidateEnvironmentLocked(Throwable e) {
if (envFailed == null) {
envFailed = e;
- U.error(log, "IO error encountered while running WAL flush. All further operations will be failed and " +
- "local node will be stopped.", e);
+ U.error(log, "IO error encountered while running WAL flush. All further operations " +
+ " will be failed and local node will be stopped.", e);
new Thread() {
@Override public void run() {
@@ -2823,59 +2632,11 @@ private String safePosition() {
return String.valueOf(io.position());
}
catch (IOException e) {
- return "{Failed to read channel position: " + e.getMessage() + "}";
+ return "{Failed to read channel position: " + e.getMessage() + '}';
}
}
}
- /**
- * Gets WAL record offset relative to the WAL segment file beginning.
- *
- * @param rec WAL record.
- * @return File offset.
- */
- private static int recordOffset(WALRecord rec) {
- FileWALPointer ptr = (FileWALPointer)rec.position();
-
- assert ptr != null;
-
- return ptr.fileOffset();
- }
-
- /**
- * Fake record is zero-sized record, which is not stored into file.
- * Fake record is used for storing position in file {@link WALRecord#position()}.
- * Fake record is allowed to have no previous record.
- */
- private static final class FakeRecord extends WALRecord {
- /** */
- private final boolean stop;
-
- /**
- * @param pos Position.
- */
- FakeRecord(FileWALPointer pos, boolean stop) {
- position(pos);
-
- this.stop = stop;
- }
-
- /** {@inheritDoc} */
- @Override public RecordType type() {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override public FileWALPointer position() {
- return (FileWALPointer) super.position();
- }
-
- /** {@inheritDoc} */
- @Override public String toString() {
- return S.toString(FakeRecord.class, this, "super", super.toString());
- }
- }
-
/**
* Iterator over WAL-log.
*/
@@ -3049,10 +2810,8 @@ private void init() throws IgniteCheckedException {
boolean readArchive = canReadArchiveOrReserveWork(curWalSegmIdx);
- if (readArchive) {
- fd = new FileDescriptor(new File(walArchiveDir,
- FileDescriptor.fileName(curWalSegmIdx)));
- }
+ if (readArchive)
+ fd = new FileDescriptor(new File(walArchiveDir, FileDescriptor.fileName(curWalSegmIdx)));
else {
long workIdx = curWalSegmIdx % psCfg.getWalSegments();
@@ -3064,9 +2823,8 @@ private void init() throws IgniteCheckedException {
if (log.isDebugEnabled())
log.debug("Reading next file [absIdx=" + curWalSegmIdx + ", file=" + fd.file.getAbsolutePath() + ']');
- assert fd != null;
-
ReadFileHandle nextHandle;
+
try {
nextHandle = initReadHandle(fd, start != null && curWalSegmIdx == start.index() ? start : null);
}
@@ -3086,6 +2844,7 @@ private void init() throws IgniteCheckedException {
curRec = null;
+
return nextHandle;
}
@@ -3109,16 +2868,279 @@ private void releaseWorkSegment(long absIdx) {
}
/**
- * Flushes current file handle for {@link WALMode#BACKGROUND} WALMode.
- * Called periodically from scheduler.
+ * Flushes current file handle for {@link WALMode#BACKGROUND} WALMode. Called periodically from scheduler.
*/
private void doFlush() {
- final FileWriteHandle hnd = currentHandle();
+ FileWriteHandle hnd = currentHandle();
+
try {
- hnd.flush(hnd.head.get(), false);
+ hnd.flush(null);
}
catch (Exception e) {
U.warn(log, "Failed to flush WAL record queue", e);
}
}
+
+ /**
+ * WAL writer worker.
+ */
+ class WALWriter extends Thread {
+ /** Unconditional flush. */
+ private static final long UNCONDITIONAL_FLUSH = -1L;
+
+ /** File close. */
+ private static final long FILE_CLOSE = -2L;
+
+ /** File force. */
+ private static final long FILE_FORCE = -3L;
+
+ /** Shutdown. */
+ private volatile boolean shutdown;
+
+ /** Err. */
+ private volatile Throwable err;
+
+ //TODO: replace with GC free data structure.
+ /** Parked threads. */
+ final Map waiters = new ConcurrentHashMap8<>();
+
+ /**
+ * Default constructor.
+ */
+ WALWriter() {
+ super("wal-write-worker%" + cctx.igniteInstanceName());
+ }
+
+ /** {@inheritDoc} */
+ @Override public void run() {
+ while (!shutdown && !Thread.currentThread().isInterrupted()) {
+ while (waiters.isEmpty()) {
+ if (!shutdown)
+ LockSupport.park();
+ else {
+ unparkWaiters(Long.MAX_VALUE);
+
+ return;
+ }
+ }
+
+ Long pos = null;
+
+ for (Long val : waiters.values()) {
+ if (val > Long.MIN_VALUE)
+ pos = val;
+ }
+
+ if (pos == null)
+ continue;
+ else if (pos < UNCONDITIONAL_FLUSH) {
+ try {
+ assert pos == FILE_CLOSE || pos == FILE_FORCE : pos;
+
+ if (pos == FILE_CLOSE)
+ currHnd.fileIO.close();
+ else if (pos == FILE_FORCE)
+ currHnd.fileIO.force();
+ }
+ catch (IOException e) {
+ log.error("Exception in WAL writer thread: ", e);
+
+ err = e;
+
+ unparkWaiters(Long.MAX_VALUE);
+
+ return;
+ }
+
+ unparkWaiters(pos);
+ }
+
+ List segs = currentHandle().buf.poll(pos);
+
+ if (segs == null) {
+ unparkWaiters(pos);
+
+ continue;
+ }
+
+ for (int i = 0; i < segs.size(); i++) {
+ SegmentedRingByteBuffer.ReadSegment seg = segs.get(i);
+
+ try {
+ writeBuffer(seg.position(), seg.buffer());
+ }
+ catch (Throwable e) {
+ log.error("Exception in WAL writer thread: ", e);
+
+ err = e;
+ }
+ finally {
+ seg.release();
+
+ long p = pos <= UNCONDITIONAL_FLUSH || err != null ? Long.MAX_VALUE : currentHandle().written;
+
+ unparkWaiters(p);
+ }
+ }
+ }
+
+ unparkWaiters(Long.MAX_VALUE);
+ }
+
+ /**
+ * Shutdowns thread.
+ */
+ public void shutdown() throws IgniteInterruptedCheckedException {
+ shutdown = true;
+
+ LockSupport.unpark(this);
+
+ U.join(this);
+ }
+
+ /**
+ * Unparks waiting threads.
+ *
+ * @param pos Pos.
+ */
+ private void unparkWaiters(long pos) {
+ assert pos > Long.MIN_VALUE : pos;
+
+ for (Map.Entry e : waiters.entrySet()) {
+ Long val = e.getValue();
+
+ if (val <= pos) {
+ if (val != Long.MIN_VALUE)
+ waiters.put(e.getKey(), Long.MIN_VALUE);
+
+ LockSupport.unpark(e.getKey());
+ }
+ }
+ }
+
+ /**
+ * Forces all made changes to the file.
+ */
+ void force() throws IgniteCheckedException {
+ flushBuffer(FILE_FORCE);
+ }
+
+ /**
+ * Closes file.
+ */
+ void close() throws IgniteCheckedException {
+ flushBuffer(FILE_CLOSE);
+ }
+
+ /**
+ * Flushes all data from the buffer.
+ */
+ void flushAll() throws IgniteCheckedException {
+ flushBuffer(UNCONDITIONAL_FLUSH);
+ }
+
+ /**
+ * @param expPos Expected position.
+ */
+ @SuppressWarnings("ForLoopReplaceableByForEach")
+ void flushBuffer(long expPos) throws StorageException, IgniteCheckedException {
+ if (mmap)
+ return;
+
+ Throwable err = walWriter.err;
+
+ if (err != null)
+ currentHandle().invalidateEnvironment(err);
+
+ if (expPos == UNCONDITIONAL_FLUSH)
+ expPos = (currentHandle().buf.tail());
+
+ Thread t = Thread.currentThread();
+
+ waiters.put(t, expPos);
+
+ LockSupport.unpark(walWriter);
+
+ while (true) {
+ Long val = waiters.get(t);
+
+ assert val != null : "Only this thread can remove thread from waiters";
+
+ if (val == Long.MIN_VALUE) {
+ waiters.remove(t);
+
+ return;
+ }
+ else
+ LockSupport.park();
+ }
+ }
+
+ /**
+ * @param pos Position in file to start write from. May be checked against actual position to wait previous
+ * writes to complete
+ * @param buf Buffer to write to file
+ * @throws StorageException If failed.
+ * @throws IgniteCheckedException If failed.
+ */
+ @SuppressWarnings("TooBroadScope")
+ private void writeBuffer(long pos, ByteBuffer buf) throws StorageException, IgniteCheckedException {
+ FileWriteHandle hdl = currentHandle();
+
+ assert hdl.fileIO != null : "Writing to a closed segment.";
+
+ checkEnvironment();
+
+ long lastLogged = U.currentTimeMillis();
+
+ long logBackoff = 2_000;
+
+ // If we were too fast, need to wait previous writes to complete.
+ while (hdl.written != pos) {
+ assert hdl.written < pos : "written = " + hdl.written + ", pos = " + pos; // No one can write further than we are now.
+
+ // Permutation occurred between blocks write operations.
+ // Order of acquiring lock is not the same as order of write.
+ long now = U.currentTimeMillis();
+
+ if (now - lastLogged >= logBackoff) {
+ if (logBackoff < 60 * 60_000)
+ logBackoff *= 2;
+
+ U.warn(log, "Still waiting for a concurrent write to complete [written=" + hdl.written +
+ ", pos=" + pos + ", lastFsyncPos=" + hdl.lastFsyncPos + ", stop=" + hdl.stop.get() +
+ ", actualPos=" + hdl.safePosition() + ']');
+
+ lastLogged = now;
+ }
+
+ checkEnvironment();
+ }
+
+ // Do the write.
+ int size = buf.remaining();
+
+ assert size > 0 : size;
+
+ try {
+ assert hdl.written == hdl.fileIO.position();
+
+ do {
+ hdl.fileIO.write(buf);
+ }
+ while (buf.hasRemaining());
+
+ hdl.written += size;
+
+ metrics.onWalBytesWritten(size);
+
+ assert hdl.written == hdl.fileIO.position();
+ }
+ catch (IOException e) {
+ hdl.invalidateEnvironmentLocked(e);
+
+ throw new StorageException(e);
+ }
+ }
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/SegmentedRingByteBuffer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/SegmentedRingByteBuffer.java
new file mode 100644
index 0000000000000..a0209f9fdc9b4
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/SegmentedRingByteBuffer.java
@@ -0,0 +1,593 @@
+/*
+ * 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.processors.cache.persistence.wal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import org.apache.ignite.internal.processors.cache.persistence.DataStorageMetricsImpl;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import sun.nio.ch.DirectBuffer;
+
+import static java.nio.ByteBuffer.allocate;
+import static java.nio.ByteBuffer.allocateDirect;
+import static org.apache.ignite.internal.processors.cache.persistence.wal.SegmentedRingByteBuffer.BufferMode.DIRECT;
+import static org.apache.ignite.internal.processors.cache.persistence.wal.SegmentedRingByteBuffer.BufferMode.MAPPED;
+
+/**
+ * Segmented ring byte buffer that represents multi producer/single consumer queue that can be used by multiple writer
+ * threads and one reader thread.
+ */
+public class SegmentedRingByteBuffer {
+ /** Open mask. */
+ private static final long OPEN_MASK = 0x7FFFFFFFFFFFFFFFL;
+
+ /** Close mask. */
+ private static final long CLOSE_MASK = 0x8000000000000000L;
+
+ /** Tail field atomic updater. */
+ private static final AtomicLongFieldUpdater TAIL_UPD =
+ AtomicLongFieldUpdater.newUpdater(SegmentedRingByteBuffer.class, "tail");
+
+ /** Producers count field atomic updater. */
+ private static final AtomicIntegerFieldUpdater PRODUCERS_CNT_UPD =
+ AtomicIntegerFieldUpdater.newUpdater(SegmentedRingByteBuffer.class, "producersCnt");
+
+ /** Capacity. */
+ private final int cap;
+
+ /** Direct. */
+ private final BufferMode mode;
+
+ /** Buffer. */
+ public final ByteBuffer buf;
+
+ /** Max segment size. */
+ private final long maxSegmentSize;
+
+ /** Head. */
+ private volatile long head;
+
+ /** Tail. */
+ private volatile long tail;
+
+ /**
+ * Producers count. Uses by consumer in order to wait for ending of data writing by all producers.
+ */
+ private volatile int producersCnt;
+
+ /**
+ * Wait for consumer flag. Prevents producers from writing data to the ring buffer while consumer waiting for finish
+ * of all already writing producers.
+ */
+ private volatile boolean waitForConsumer;
+
+ /** Metrics. */
+ private final DataStorageMetricsImpl metrics;
+
+ /**
+ * Creates ring buffer with given capacity.
+ *
+ * @param cap Buffer's capacity.
+ * @param maxSegmentSize Max segment size.
+ * @param mode Buffer mode.
+ */
+ public SegmentedRingByteBuffer(int cap, long maxSegmentSize, BufferMode mode) {
+ this(cap, maxSegmentSize, mode == DIRECT ? allocateDirect(cap) : allocate(cap), mode, null);
+ }
+
+ /**
+ * Creates ring buffer with given capacity.
+ *
+ * @param cap Buffer's capacity.
+ * @param maxSegmentSize Max segment size.
+ * @param mode Buffer mode.
+ * @param metrics Metrics.
+ */
+ public SegmentedRingByteBuffer(int cap, long maxSegmentSize, BufferMode mode, DataStorageMetricsImpl metrics) {
+ this(cap, maxSegmentSize, mode == DIRECT ? allocateDirect(cap) : allocate(cap), mode, metrics);
+ }
+
+ /**
+ * Creates ring buffer with given capacity which mapped to file.
+ *
+ * @param buf {@link MappedByteBuffer} instance.
+ * @param metrics Metrics.
+ */
+ public SegmentedRingByteBuffer(MappedByteBuffer buf, DataStorageMetricsImpl metrics) {
+ this(buf.capacity(), buf.capacity(), buf, MAPPED, metrics);
+ }
+
+ /**
+ * @param cap Capacity.
+ * @param maxSegmentSize Max segment size.
+ * @param buf Buffer.
+ * @param mode Mode.
+ * @param metrics Metrics.
+ */
+ private SegmentedRingByteBuffer(
+ int cap,
+ long maxSegmentSize,
+ ByteBuffer buf,
+ BufferMode mode,
+ DataStorageMetricsImpl metrics
+ ) {
+ this.cap = cap;
+ this.mode = mode;
+ this.buf = buf;
+ this.buf.order(ByteOrder.nativeOrder());
+ this.maxSegmentSize = maxSegmentSize;
+ this.metrics = metrics;
+ }
+
+ /**
+ * Performs initialization of ring buffer state.
+ *
+ * @param pos Position.
+ */
+ public void init(long pos) {
+ head = pos;
+ tail = pos;
+ }
+
+ /**
+ * Returns buffer mode.
+ *
+ * @return Buffer mode.
+ */
+ public BufferMode mode() {
+ return mode;
+ }
+
+ /**
+ * Returns actual buffer tail.
+ *
+ * @return Buffer tail.
+ */
+ public long tail() {
+ return tail & SegmentedRingByteBuffer.OPEN_MASK;
+ }
+
+ /**
+ * Reserves {@code size} bytes in {@code SegmentedRingByteBuffer} and returns instance of {@link WriteSegment}
+ * class that points to wrapped {@link ByteBuffer} instance with corresponding capacity. This {@link ByteBuffer}
+ * instance should be used only for data writing to {@link SegmentedRingByteBuffer}.
+ *
+ * Returned result can be {@code null} in case of requested amount of bytes greater then available space
+ * in {@code SegmentedRingByteBuffer}. Also {@link WriteSegment#buffer()} can return {@code null} in case of
+ * {@link #maxSegmentSize} value is exceeded. In this case buffer will be closed in order to prevent any
+ * concurrent threads from trying of reserve new segment.
+ *
+ * This method can be invoked by many producer threads and each producer will get own {@link ByteBuffer} instance
+ * that mapped to own {@link SegmentedRingByteBuffer} slice.
+ *
+ * Once the data has been written into the {@link ByteBuffer} client code must notify
+ * {@code SegmentedRingByteBuffer} instance using {@link WriteSegment#release()} method in order to provide
+ * possibility to consumer get data for reading.
+ *
+ * @param size Amount of bytes for reserve.
+ * @return {@link WriteSegment} instance that point to {@link ByteBuffer} instance with given {@code size}.
+ * {@code null} if buffer space is not enough.
+ */
+ public WriteSegment offer(int size) {
+ return offer0(size, false);
+ }
+
+ /**
+ * Behaves like {@link #offer(int)} but in safe manner: there are no any concurrent threads and buffer in
+ * closed state.
+ *
+ * @param size Amount of bytes for reserve.
+ * @return {@link WriteSegment} instance that point to {@link ByteBuffer} instance with given {@code size}.
+ * {@code null} if buffer space is not enough.
+ */
+ public WriteSegment offerSafe(int size) {
+ return offer0(size, true);
+ }
+
+ /**
+ * @param size Amount of bytes for reserve.
+ * @param safe Safe ьщву.
+ */
+ private WriteSegment offer0(int size, boolean safe) {
+ if (size > cap)
+ throw new IllegalArgumentException("Record is too long [capacity=" + cap + ", size=" + size + ']');
+
+ for (;;) {
+ if (!waitForConsumer) {
+ int cur = producersCnt;
+
+ if (cur >= 0 && PRODUCERS_CNT_UPD.compareAndSet(this, cur, cur + 1))
+ break;
+ }
+ }
+
+ for (;;) {
+ long currTail = tail;
+
+ assert !safe || currTail < 0 : "Unsafe usage of segment ring byte buffer currTail=" + currTail;
+
+ if (currTail < 0) {
+ if (safe)
+ currTail &= SegmentedRingByteBuffer.OPEN_MASK;
+ else
+ return new WriteSegment(null, -1);
+ }
+
+ long head0 = head;
+
+ long currTailIdx = toIndex(currTail);
+
+ boolean fitsSeg = currTail + size <= maxSegmentSize;
+
+ long newTail = fitsSeg ? currTail + size : currTail;
+
+ if (head0 < newTail - cap) { // Not enough space.
+ PRODUCERS_CNT_UPD.decrementAndGet(this);
+
+ return null;
+ }
+ else {
+ // If safe we should keep buffer closed.
+ long tail0 = fitsSeg ? (safe ? newTail | CLOSE_MASK : newTail) : newTail | CLOSE_MASK;
+
+ boolean upd = TAIL_UPD.compareAndSet(this, safe ? currTail | CLOSE_MASK : currTail, tail0);
+
+ assert !safe || upd : "Unsafe usage of segment ring byte buffer";
+
+ if (upd) {
+ if (!fitsSeg)
+ return new WriteSegment(null, -1);
+
+ boolean wrap = cap - currTailIdx < size;
+
+ if (wrap) {
+ long newTailIdx = toIndex(newTail);
+
+ return new WriteSegment(currTail, newTail, newTailIdx == 0 ? newTail : currTail);
+ }
+ else {
+ ByteBuffer slice = slice((int)toIndex(newTail - size), size, false);
+
+ return new WriteSegment(slice, newTail);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Closes the buffer.
+ */
+ public void close() {
+ for (;;) {
+ long currTail = tail;
+
+ if (currTail < 0)
+ return;
+
+ if(TAIL_UPD.compareAndSet(this, currTail, currTail | CLOSE_MASK))
+ return;
+ }
+ }
+
+ /**
+ * Retrieves list of {@link ReadSegment} instances that point to {@link ByteBuffer} that contains all data available
+ * for reading from {@link SegmentedRingByteBuffer} or {@code null} if there are no available data for reading.
+ *
+ * This method can be invoked only by one consumer thread.
+ *
+ * Once the data has been read from the returned {@link ReadSegment} client code must notify
+ * {@link SegmentedRingByteBuffer} instance using {@link ReadSegment#release()} method in order to release occupied
+ * space in the {@link SegmentedRingByteBuffer} and make it available for writing.
+ *
+ * @return List of {@code ReadSegment} instances with all available data for reading or {@code null} if
+ * there are no available data.
+ */
+ public List poll() {
+ return poll(-1);
+ }
+
+ /**
+ * Retrieves list of {@link ReadSegment} instances that point to {@link ByteBuffer} that contains data
+ * available for reading from {@link SegmentedRingByteBuffer} limited by {@code pos} parameter or {@code null}
+ * if there are no available data for reading.
+ *
+ * This method can be invoked only by one consumer thread.
+ *
+ * Once the data has been read from the returned {@link ReadSegment} client code must notify
+ * {@link SegmentedRingByteBuffer} instance using {@link ReadSegment#release()} method in order to release occupied
+ * space in the {@link SegmentedRingByteBuffer} and make it available for writing.
+ *
+ * @param pos End position in buffer.
+ * @return List of {@code ReadSegment} instances with all available data for reading or {@code null} if
+ * there are no available data.
+ */
+ public List poll(long pos) {
+ waitForConsumer = true;
+
+ int spins = 0;
+
+ for (;;) {
+ if (PRODUCERS_CNT_UPD.compareAndSet(this, 0, -1))
+ break;
+
+ spins++;
+ }
+
+ if (metrics != null && metrics.metricsEnabled())
+ metrics.onBuffPollSpin(spins);
+
+ long head = this.head;
+
+ long tail = this.tail & OPEN_MASK;
+
+ producersCnt = 0;
+
+ waitForConsumer = false;
+
+ // There are no data for reading or all data up to given position were read.
+ if (tail <= head || (pos >=0 && head > pos))
+ return null;
+
+ int headIdx = (int)toIndex(head);
+
+ int tailIdx = (int)toIndex(tail);
+
+ boolean wrapped = tailIdx <= headIdx;
+
+ if (wrapped && tailIdx != 0) {
+ List lst = new ArrayList<>(2);
+
+ int lim = cap - headIdx;
+
+ lst.add(new ReadSegment(slice(headIdx, lim, true), head, head + lim));
+
+ lst.add(new ReadSegment(slice(0, tailIdx, true), head + lim, tail));
+
+ return lst;
+ }
+ else
+ return Collections.singletonList(new ReadSegment(slice(headIdx, (int)(tail - head), true), head, tail));
+ }
+
+ /**
+ * Frees allocated memory in case of direct byte buffer.
+ */
+ public void free() {
+ if (mode == DIRECT || mode == MAPPED)
+ ((DirectBuffer)buf).cleaner().clean();
+ }
+
+ /**
+ * Resets the state of the buffer and returns new instance but with the same underlying buffer.
+ */
+ public SegmentedRingByteBuffer reset() {
+ return new SegmentedRingByteBuffer(buf.capacity(), maxSegmentSize, buf, mode, metrics);
+ }
+
+ /**
+ * @param off Offset.
+ * @param len Length.
+ * @param readOnly Read only.
+ */
+ private ByteBuffer slice(int off, int len, boolean readOnly) {
+ ByteBuffer bb = readOnly ? buf.asReadOnlyBuffer() : buf.duplicate();
+
+ bb.order(ByteOrder.nativeOrder());
+ bb.limit(off + len);
+ bb.position(off);
+
+ return bb;
+ }
+
+ /**
+ * @param globalIdx Global index of ring buffer.
+ * @return Index of byte array.
+ */
+ private long toIndex(long globalIdx) {
+ return globalIdx % cap;
+ }
+
+ /**
+ * @param src Source.
+ * @param srcPos Source pos.
+ * @param dest Destination.
+ * @param destPos Destination pos.
+ * @param len Length.
+ */
+ private void copy(ByteBuffer src, int srcPos, ByteBuffer dest, int destPos, int len) {
+ assert mode != MAPPED;
+
+ if (buf.isDirect()) {
+ ByteBuffer src0 = src.duplicate();
+ src0.limit(srcPos + len);
+ src0.position(srcPos);
+
+ ByteBuffer dest0 = dest.duplicate();
+ dest0.limit(destPos + len);
+ dest0.position(destPos);
+
+ dest0.put(src0);
+ }
+ else
+ System.arraycopy(src.array(), srcPos, buf.array(), destPos, len);
+ }
+
+ /**
+ *
+ */
+ private abstract class Segment {
+ /** Buffer. */
+ protected final ByteBuffer seg;
+
+ /** Pos. */
+ protected final long pos;
+
+ /**
+ * @param seg Seg.
+ * @param pos Pos.
+ */
+ protected Segment(ByteBuffer seg, long pos) {
+ this.seg = seg;
+ this.pos = pos;
+ }
+
+ /**
+ * Releases segment.
+ */
+ abstract public void release();
+
+ /**
+ * Returns byte buffer.
+ *
+ * @return Byte buffer.
+ */
+ abstract public ByteBuffer buffer();
+
+ /**
+ * Returns position.
+ *
+ * @return Position.
+ */
+ public long position() {
+ return pos;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Segment.class, this);
+ }
+ }
+
+ /**
+ * Segment available for data writing.
+ */
+ public class WriteSegment extends Segment {
+ /** Current tail. */
+ private final long currTail;
+
+ /** Wrap point. */
+ private final long wrapPnt;
+
+ /**
+ * @param currTail Current tail.
+ * @param newTail New tail.
+ * @param wrapPnt Wrap point.
+ */
+ private WriteSegment(long currTail, long newTail, long wrapPnt) {
+ super(allocate((int)(newTail - currTail)), newTail);
+
+ this.seg.order(ByteOrder.nativeOrder());
+ this.currTail = currTail;
+ this.wrapPnt = wrapPnt;
+ }
+
+ /**
+ * @param seg Seg.
+ * @param pos Pos.
+ */
+ private WriteSegment(ByteBuffer seg, long pos) {
+ super(seg, pos);
+
+ this.currTail = -1;
+ this.wrapPnt = -1;
+ }
+
+ /** {@inheritDoc} */
+ @Override public ByteBuffer buffer() {
+ return seg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void release() {
+ if (wrapPnt > -1) {
+ int pos = (int)toIndex(currTail);
+
+ int len = cap - pos;
+
+ copy(seg, 0, buf, pos, len);
+
+ copy(seg, len, buf, 0, seg.array().length - len);
+ }
+
+ assert producersCnt >= 0;
+
+ PRODUCERS_CNT_UPD.decrementAndGet(SegmentedRingByteBuffer.this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(WriteSegment.class, this, "super", super.toString());
+ }
+ }
+
+ /**
+ * Segment available for data reading.
+ */
+ public class ReadSegment extends Segment {
+ /** New head. */
+ private final long newHead;
+
+ /**
+ * @param seg Seg.
+ * @param pos Pos.
+ * @param newHead New head.
+ */
+ private ReadSegment(ByteBuffer seg, long pos, long newHead) {
+ super(seg, pos);
+
+ this.newHead = newHead;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void release() {
+ if (newHead >= 0)
+ head = newHead;
+ }
+
+ /** {@inheritDoc} */
+ @Override public ByteBuffer buffer() {
+ return seg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(ReadSegment.class, this, "super", super.toString());
+ }
+ }
+
+ /**
+ * Buffer mode.
+ */
+ public enum BufferMode {
+ /** Byte buffer on-heap. */
+ ONHEAP,
+
+ /** Direct byte buffer off-heap */
+ DIRECT,
+
+ /** Byte buffer mapped to file. */
+ MAPPED
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/HeaderRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/HeaderRecord.java
index 35c94a8b1a27e..c26a0c6e3e3ef 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/HeaderRecord.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/record/HeaderRecord.java
@@ -25,10 +25,10 @@
*/
public class HeaderRecord extends WALRecord {
/** Magic of regular WAL segment. */
- public static final long REGULAR_MAGIC = 0xB0D045A_CE7ED045AL;
+ public static final long REGULAR_MAGIC = 0xB0D045AC_E7ED045AL;
/** Magic of WAL segment with skipped physical records. */
- public static final long COMPACTED_MAGIC = 0x4E07AE0_E573A694EL;
+ public static final long COMPACTED_MAGIC = 0x4E07AE0E_573A694EL;
/** Serializer version */
private final int ver;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
index d478917ab09c3..12992a1b78bc1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV1Serializer.java
@@ -92,8 +92,6 @@
import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
import org.apache.ignite.internal.util.typedef.internal.U;
-import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.CRC_SIZE;
-
/**
* Record data V1 serializer.
*/
@@ -314,14 +312,14 @@ assert record instanceof PageSnapshot;
long lsb = in.readLong();
boolean hasPtr = in.readByte() != 0;
int idx = hasPtr ? in.readInt() : 0;
- int offset = hasPtr ? in.readInt() : 0;
+ int off = hasPtr ? in.readInt() : 0;
int len = hasPtr ? in.readInt() : 0;
Map states = readPartitionStates(in);
boolean end = in.readByte() != 0;
- FileWALPointer walPtr = hasPtr ? new FileWALPointer(idx, offset, len) : null;
+ FileWALPointer walPtr = hasPtr ? new FileWALPointer(idx, off, len) : null;
CheckpointRecord cpRec = new CheckpointRecord(new UUID(msb, lsb), walPtr, end);
@@ -789,9 +787,9 @@ assert record instanceof PageSnapshot;
state = in.readByte();
- long updateCounter = in.readLong();
+ long updateCntr = in.readLong();
- res = new PartitionMetaStateRecord(cacheId, partId, GridDhtPartitionState.fromOrdinal(state), updateCounter);
+ res = new PartitionMetaStateRecord(cacheId, partId, GridDhtPartitionState.fromOrdinal(state), updateCntr);
break;
@@ -818,10 +816,10 @@ assert record instanceof PageSnapshot;
}
/** {@inheritDoc} */
- @Override public void writeRecord(WALRecord record, ByteBuffer buf) throws IgniteCheckedException {
- switch (record.type()) {
+ @Override public void writeRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
+ switch (rec.type()) {
case PAGE_RECORD:
- PageSnapshot snap = (PageSnapshot)record;
+ PageSnapshot snap = (PageSnapshot)rec;
buf.putInt(snap.fullPageId().groupId());
buf.putLong(snap.fullPageId().pageId());
@@ -830,14 +828,14 @@ assert record instanceof PageSnapshot;
break;
case MEMORY_RECOVERY:
- MemoryRecoveryRecord memoryRecoveryRecord = (MemoryRecoveryRecord)record;
+ MemoryRecoveryRecord memoryRecoveryRecord = (MemoryRecoveryRecord)rec;
buf.putLong(memoryRecoveryRecord.time());
break;
case PARTITION_DESTROY:
- PartitionDestroyRecord partDestroy = (PartitionDestroyRecord)record;
+ PartitionDestroyRecord partDestroy = (PartitionDestroyRecord)rec;
buf.putInt(partDestroy.groupId());
buf.putInt(partDestroy.partitionId());
@@ -845,7 +843,7 @@ assert record instanceof PageSnapshot;
break;
case META_PAGE_INIT:
- MetaPageInitRecord updRootsRec = (MetaPageInitRecord)record;
+ MetaPageInitRecord updRootsRec = (MetaPageInitRecord)rec;
buf.putInt(updRootsRec.groupId());
buf.putLong(updRootsRec.pageId());
@@ -858,7 +856,7 @@ assert record instanceof PageSnapshot;
break;
case PARTITION_META_PAGE_UPDATE_COUNTERS:
- MetaPageUpdatePartitionDataRecord partDataRec = (MetaPageUpdatePartitionDataRecord)record;
+ MetaPageUpdatePartitionDataRecord partDataRec = (MetaPageUpdatePartitionDataRecord)rec;
buf.putInt(partDataRec.groupId());
buf.putLong(partDataRec.pageId());
@@ -873,7 +871,7 @@ assert record instanceof PageSnapshot;
break;
case CHECKPOINT_RECORD:
- CheckpointRecord cpRec = (CheckpointRecord)record;
+ CheckpointRecord cpRec = (CheckpointRecord)rec;
assert cpRec.checkpointMark() == null || cpRec.checkpointMark() instanceof FileWALPointer :
"Invalid WAL record: " + cpRec;
@@ -899,7 +897,7 @@ assert record instanceof PageSnapshot;
break;
case DATA_RECORD:
- DataRecord dataRec = (DataRecord)record;
+ DataRecord dataRec = (DataRecord)rec;
buf.putInt(dataRec.writeEntries().size());
@@ -908,15 +906,8 @@ assert record instanceof PageSnapshot;
break;
- case HEADER_RECORD:
- buf.putLong(HeaderRecord.REGULAR_MAGIC);
-
- buf.putInt(((HeaderRecord)record).version());
-
- break;
-
case DATA_PAGE_INSERT_RECORD:
- DataPageInsertRecord diRec = (DataPageInsertRecord)record;
+ DataPageInsertRecord diRec = (DataPageInsertRecord)rec;
buf.putInt(diRec.groupId());
buf.putLong(diRec.pageId());
@@ -928,7 +919,7 @@ assert record instanceof PageSnapshot;
break;
case DATA_PAGE_UPDATE_RECORD:
- DataPageUpdateRecord uRec = (DataPageUpdateRecord)record;
+ DataPageUpdateRecord uRec = (DataPageUpdateRecord)rec;
buf.putInt(uRec.groupId());
buf.putLong(uRec.pageId());
@@ -941,7 +932,7 @@ assert record instanceof PageSnapshot;
break;
case DATA_PAGE_INSERT_FRAGMENT_RECORD:
- final DataPageInsertFragmentRecord difRec = (DataPageInsertFragmentRecord)record;
+ final DataPageInsertFragmentRecord difRec = (DataPageInsertFragmentRecord)rec;
buf.putInt(difRec.groupId());
buf.putLong(difRec.pageId());
@@ -953,7 +944,7 @@ assert record instanceof PageSnapshot;
break;
case DATA_PAGE_REMOVE_RECORD:
- DataPageRemoveRecord drRec = (DataPageRemoveRecord)record;
+ DataPageRemoveRecord drRec = (DataPageRemoveRecord)rec;
buf.putInt(drRec.groupId());
buf.putLong(drRec.pageId());
@@ -963,7 +954,7 @@ assert record instanceof PageSnapshot;
break;
case DATA_PAGE_SET_FREE_LIST_PAGE:
- DataPageSetFreeListPageRecord freeListRec = (DataPageSetFreeListPageRecord)record;
+ DataPageSetFreeListPageRecord freeListRec = (DataPageSetFreeListPageRecord)rec;
buf.putInt(freeListRec.groupId());
buf.putLong(freeListRec.pageId());
@@ -973,7 +964,7 @@ assert record instanceof PageSnapshot;
break;
case INIT_NEW_PAGE_RECORD:
- InitNewPageRecord inpRec = (InitNewPageRecord)record;
+ InitNewPageRecord inpRec = (InitNewPageRecord)rec;
buf.putInt(inpRec.groupId());
buf.putLong(inpRec.pageId());
@@ -985,7 +976,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_META_PAGE_INIT_ROOT:
- MetaPageInitRootRecord imRec = (MetaPageInitRootRecord)record;
+ MetaPageInitRootRecord imRec = (MetaPageInitRootRecord)rec;
buf.putInt(imRec.groupId());
buf.putLong(imRec.pageId());
@@ -995,7 +986,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_META_PAGE_INIT_ROOT2:
- MetaPageInitRootInlineRecord imRec2 = (MetaPageInitRootInlineRecord)record;
+ MetaPageInitRootInlineRecord imRec2 = (MetaPageInitRootInlineRecord)rec;
buf.putInt(imRec2.groupId());
buf.putLong(imRec2.pageId());
@@ -1006,7 +997,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_META_PAGE_ADD_ROOT:
- MetaPageAddRootRecord arRec = (MetaPageAddRootRecord)record;
+ MetaPageAddRootRecord arRec = (MetaPageAddRootRecord)rec;
buf.putInt(arRec.groupId());
buf.putLong(arRec.pageId());
@@ -1016,7 +1007,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_META_PAGE_CUT_ROOT:
- MetaPageCutRootRecord crRec = (MetaPageCutRootRecord)record;
+ MetaPageCutRootRecord crRec = (MetaPageCutRootRecord)rec;
buf.putInt(crRec.groupId());
buf.putLong(crRec.pageId());
@@ -1024,7 +1015,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_INIT_NEW_ROOT:
- NewRootInitRecord> riRec = (NewRootInitRecord>)record;
+ NewRootInitRecord> riRec = (NewRootInitRecord>)rec;
buf.putInt(riRec.groupId());
buf.putLong(riRec.pageId());
@@ -1040,7 +1031,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_RECYCLE:
- RecycleRecord recRec = (RecycleRecord)record;
+ RecycleRecord recRec = (RecycleRecord)rec;
buf.putInt(recRec.groupId());
buf.putLong(recRec.pageId());
@@ -1050,7 +1041,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_INSERT:
- InsertRecord> inRec = (InsertRecord>)record;
+ InsertRecord> inRec = (InsertRecord>)rec;
buf.putInt(inRec.groupId());
buf.putLong(inRec.pageId());
@@ -1065,7 +1056,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_FIX_LEFTMOST_CHILD:
- FixLeftmostChildRecord flRec = (FixLeftmostChildRecord)record;
+ FixLeftmostChildRecord flRec = (FixLeftmostChildRecord)rec;
buf.putInt(flRec.groupId());
buf.putLong(flRec.pageId());
@@ -1075,7 +1066,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_FIX_COUNT:
- FixCountRecord fcRec = (FixCountRecord)record;
+ FixCountRecord fcRec = (FixCountRecord)rec;
buf.putInt(fcRec.groupId());
buf.putLong(fcRec.pageId());
@@ -1085,7 +1076,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_REPLACE:
- ReplaceRecord> rRec = (ReplaceRecord>)record;
+ ReplaceRecord> rRec = (ReplaceRecord>)rec;
buf.putInt(rRec.groupId());
buf.putLong(rRec.pageId());
@@ -1099,7 +1090,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_REMOVE:
- RemoveRecord rmRec = (RemoveRecord)record;
+ RemoveRecord rmRec = (RemoveRecord)rec;
buf.putInt(rmRec.groupId());
buf.putLong(rmRec.pageId());
@@ -1110,7 +1101,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_INNER_REPLACE:
- InnerReplaceRecord> irRec = (InnerReplaceRecord>)record;
+ InnerReplaceRecord> irRec = (InnerReplaceRecord>)rec;
buf.putInt(irRec.groupId());
buf.putLong(irRec.pageId());
@@ -1123,7 +1114,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_FORWARD_PAGE_SPLIT:
- SplitForwardPageRecord sfRec = (SplitForwardPageRecord)record;
+ SplitForwardPageRecord sfRec = (SplitForwardPageRecord)rec;
buf.putInt(sfRec.groupId());
buf.putLong(sfRec.pageId());
@@ -1138,7 +1129,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_EXISTING_PAGE_SPLIT:
- SplitExistingPageRecord seRec = (SplitExistingPageRecord)record;
+ SplitExistingPageRecord seRec = (SplitExistingPageRecord)rec;
buf.putInt(seRec.groupId());
buf.putLong(seRec.pageId());
@@ -1149,7 +1140,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_PAGE_MERGE:
- MergeRecord> mRec = (MergeRecord>)record;
+ MergeRecord> mRec = (MergeRecord>)rec;
buf.putInt(mRec.groupId());
buf.putLong(mRec.pageId());
@@ -1162,7 +1153,7 @@ assert record instanceof PageSnapshot;
break;
case PAGES_LIST_SET_NEXT:
- PagesListSetNextRecord plNextRec = (PagesListSetNextRecord)record;
+ PagesListSetNextRecord plNextRec = (PagesListSetNextRecord)rec;
buf.putInt(plNextRec.groupId());
buf.putLong(plNextRec.pageId());
@@ -1172,7 +1163,7 @@ assert record instanceof PageSnapshot;
break;
case PAGES_LIST_SET_PREVIOUS:
- PagesListSetPreviousRecord plPrevRec = (PagesListSetPreviousRecord)record;
+ PagesListSetPreviousRecord plPrevRec = (PagesListSetPreviousRecord)rec;
buf.putInt(plPrevRec.groupId());
buf.putLong(plPrevRec.pageId());
@@ -1182,7 +1173,7 @@ assert record instanceof PageSnapshot;
break;
case PAGES_LIST_INIT_NEW_PAGE:
- PagesListInitNewPageRecord plNewRec = (PagesListInitNewPageRecord)record;
+ PagesListInitNewPageRecord plNewRec = (PagesListInitNewPageRecord)rec;
buf.putInt(plNewRec.groupId());
buf.putLong(plNewRec.pageId());
@@ -1196,7 +1187,7 @@ assert record instanceof PageSnapshot;
break;
case PAGES_LIST_ADD_PAGE:
- PagesListAddPageRecord plAddRec = (PagesListAddPageRecord)record;
+ PagesListAddPageRecord plAddRec = (PagesListAddPageRecord)rec;
buf.putInt(plAddRec.groupId());
buf.putLong(plAddRec.pageId());
@@ -1206,7 +1197,7 @@ assert record instanceof PageSnapshot;
break;
case PAGES_LIST_REMOVE_PAGE:
- PagesListRemovePageRecord plRmvRec = (PagesListRemovePageRecord)record;
+ PagesListRemovePageRecord plRmvRec = (PagesListRemovePageRecord)rec;
buf.putInt(plRmvRec.groupId());
buf.putLong(plRmvRec.pageId());
@@ -1216,7 +1207,7 @@ assert record instanceof PageSnapshot;
break;
case BTREE_FIX_REMOVE_ID:
- FixRemoveId frRec = (FixRemoveId)record;
+ FixRemoveId frRec = (FixRemoveId)rec;
buf.putInt(frRec.groupId());
buf.putLong(frRec.pageId());
@@ -1226,7 +1217,7 @@ assert record instanceof PageSnapshot;
break;
case TRACKING_PAGE_DELTA:
- TrackingPageDeltaRecord tpDelta = (TrackingPageDeltaRecord)record;
+ TrackingPageDeltaRecord tpDelta = (TrackingPageDeltaRecord)rec;
buf.putInt(tpDelta.groupId());
buf.putLong(tpDelta.pageId());
@@ -1238,7 +1229,7 @@ assert record instanceof PageSnapshot;
break;
case META_PAGE_UPDATE_NEXT_SNAPSHOT_ID:
- MetaPageUpdateNextSnapshotId mpUpdateNextSnapshotId = (MetaPageUpdateNextSnapshotId)record;
+ MetaPageUpdateNextSnapshotId mpUpdateNextSnapshotId = (MetaPageUpdateNextSnapshotId)rec;
buf.putInt(mpUpdateNextSnapshotId.groupId());
buf.putLong(mpUpdateNextSnapshotId.pageId());
@@ -1249,7 +1240,7 @@ assert record instanceof PageSnapshot;
case META_PAGE_UPDATE_LAST_SUCCESSFUL_FULL_SNAPSHOT_ID:
MetaPageUpdateLastSuccessfulFullSnapshotId mpUpdateLastSuccFullSnapshotId =
- (MetaPageUpdateLastSuccessfulFullSnapshotId)record;
+ (MetaPageUpdateLastSuccessfulFullSnapshotId)rec;
buf.putInt(mpUpdateLastSuccFullSnapshotId.groupId());
buf.putLong(mpUpdateLastSuccFullSnapshotId.pageId());
@@ -1260,7 +1251,7 @@ assert record instanceof PageSnapshot;
case META_PAGE_UPDATE_LAST_SUCCESSFUL_SNAPSHOT_ID:
MetaPageUpdateLastSuccessfulSnapshotId mpUpdateLastSuccSnapshotId =
- (MetaPageUpdateLastSuccessfulSnapshotId)record;
+ (MetaPageUpdateLastSuccessfulSnapshotId)rec;
buf.putInt(mpUpdateLastSuccSnapshotId.groupId());
buf.putLong(mpUpdateLastSuccSnapshotId.pageId());
@@ -1272,7 +1263,7 @@ assert record instanceof PageSnapshot;
case META_PAGE_UPDATE_LAST_ALLOCATED_INDEX:
MetaPageUpdateLastAllocatedIndex mpUpdateLastAllocatedIdx =
- (MetaPageUpdateLastAllocatedIndex) record;
+ (MetaPageUpdateLastAllocatedIndex) rec;
buf.putInt(mpUpdateLastAllocatedIdx.groupId());
buf.putLong(mpUpdateLastAllocatedIdx.pageId());
@@ -1282,7 +1273,7 @@ assert record instanceof PageSnapshot;
break;
case PART_META_UPDATE_STATE:
- PartitionMetaStateRecord partMetaStateRecord = (PartitionMetaStateRecord) record;
+ PartitionMetaStateRecord partMetaStateRecord = (PartitionMetaStateRecord) rec;
buf.putInt(partMetaStateRecord.groupId());
@@ -1295,7 +1286,7 @@ assert record instanceof PageSnapshot;
break;
case PAGE_LIST_META_RESET_COUNT_RECORD:
- PageListMetaResetCountRecord pageListMetaResetCntRecord = (PageListMetaResetCountRecord) record;
+ PageListMetaResetCountRecord pageListMetaResetCntRecord = (PageListMetaResetCountRecord) rec;
buf.putInt(pageListMetaResetCntRecord.groupId());
buf.putLong(pageListMetaResetCntRecord.pageId());
@@ -1303,7 +1294,7 @@ assert record instanceof PageSnapshot;
break;
case TX_RECORD:
- txRecordSerializer.writeTxRecord((TxRecord)record, buf);
+ txRecordSerializer.writeTxRecord((TxRecord)rec, buf);
break;
@@ -1311,7 +1302,7 @@ assert record instanceof PageSnapshot;
break;
default:
- throw new UnsupportedOperationException("Type: " + record.type());
+ throw new UnsupportedOperationException("Type: " + rec.type());
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
index 16a81a4c5676c..0e574f8dc7a63 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordDataV2Serializer.java
@@ -33,6 +33,9 @@
* Record data V2 serializer.
*/
public class RecordDataV2Serializer implements RecordDataSerializer {
+ /** Length of HEADER record data. */
+ static final int HEADER_RECORD_DATA_SIZE = /*Magic*/8 + /*Version*/4;
+
/** V1 data serializer delegate. */
private final RecordDataV1Serializer delegateSerializer;
@@ -47,10 +50,10 @@ public RecordDataV2Serializer(RecordDataV1Serializer delegateSerializer) {
/** {@inheritDoc} */
@Override public int size(WALRecord record) throws IgniteCheckedException {
- if (record instanceof HeaderRecord)
- throw new UnsupportedOperationException("Getting size of header records is forbidden since version 2 of serializer");
-
switch (record.type()) {
+ case HEADER_RECORD:
+ return HEADER_RECORD_DATA_SIZE;
+
case DATA_RECORD:
return delegateSerializer.size(record) + 8/*timestamp*/;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
index d4607059c2b23..11bd16b8f83e1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV1Serializer.java
@@ -68,7 +68,7 @@ public class RecordV1Serializer implements RecordSerializer {
public static final int HEADER_RECORD_SIZE = REC_TYPE_SIZE + FILE_WAL_POINTER_SIZE + CRC_SIZE + RecordDataV1Serializer.HEADER_RECORD_DATA_SIZE;
/** Skip CRC calculation/check flag */
- public static boolean SKIP_CRC = IgniteSystemProperties.getBoolean(IGNITE_PDS_SKIP_CRC, false);
+ public static boolean skipCrc = IgniteSystemProperties.getBoolean(IGNITE_PDS_SKIP_CRC, false);
/** V1 data serializer. */
private final RecordDataV1Serializer dataSerializer;
@@ -152,15 +152,15 @@ else if (marshalledMode) {
}
/** {@inheritDoc} */
- @Override public void writeWithHeaders(WALRecord record, ByteBuffer buf) throws IgniteCheckedException {
+ @Override public void writeWithHeaders(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
// Write record type.
- putRecordType(buf, record);
+ putRecordType(buf, rec);
// Write record file position.
- putPositionOfRecord(buf, record);
+ putPositionOfRecord(buf, rec);
// Write record data.
- dataSerializer.writeRecord(record, buf);
+ dataSerializer.writeRecord(rec, buf);
}
};
@@ -193,8 +193,8 @@ public RecordV1Serializer(RecordDataV1Serializer dataSerializer, boolean writePo
/** {@inheritDoc} */
@SuppressWarnings("CastConflictsWithInstanceof")
- @Override public void writeRecord(WALRecord record, ByteBuffer buf) throws IgniteCheckedException {
- writeWithCrc(record, buf, recordIO);
+ @Override public void writeRecord(WALRecord rec, ByteBuffer buf) throws IgniteCheckedException {
+ writeWithCrc(rec, buf, recordIO);
}
/** {@inheritDoc} */
@@ -225,29 +225,29 @@ public static void putPosition(ByteBuffer buf, FileWALPointer ptr) {
*/
public static FileWALPointer readPosition(DataInput in) throws IOException {
long idx = in.readLong();
- int fileOffset = in.readInt();
+ int fileOff = in.readInt();
- return new FileWALPointer(idx, fileOffset, 0);
+ return new FileWALPointer(idx, fileOff, 0);
}
/**
* Writes record file position to given {@code buf}.
*
* @param buf Buffer to write record file position.
- * @param record WAL record.
+ * @param rec WAL record.
*/
- public static void putPositionOfRecord(ByteBuffer buf, WALRecord record) {
- putPosition(buf, (FileWALPointer) record.position());
+ private static void putPositionOfRecord(ByteBuffer buf, WALRecord rec) {
+ putPosition(buf, (FileWALPointer)rec.position());
}
/**
* Writes record type to given {@code buf}.
*
* @param buf Buffer to write record type.
- * @param record WAL record.
+ * @param rec WAL record.
*/
- public static void putRecordType(ByteBuffer buf, WALRecord record) {
- buf.put((byte)(record.type().ordinal() + 1));
+ static void putRecordType(ByteBuffer buf, WALRecord rec) {
+ buf.put((byte)(rec.type().ordinal() + 1));
}
/**
@@ -258,7 +258,7 @@ public static void putRecordType(ByteBuffer buf, WALRecord record) {
* @throws IgniteCheckedException If logical end of segment is reached.
* @throws IOException In case of I/O problems.
*/
- public static RecordType readRecordType(DataInput in) throws IgniteCheckedException, IOException {
+ static RecordType readRecordType(DataInput in) throws IgniteCheckedException, IOException {
int type = in.readUnsignedByte();
if (type == WALRecord.RecordType.STOP_ITERATION_RECORD_TYPE)
@@ -282,10 +282,10 @@ public static RecordType readRecordType(DataInput in) throws IgniteCheckedExcept
* @throws EOFException In case of end of file.
* @throws IgniteCheckedException If it's unable to read record.
*/
- public static WALRecord readWithCrc(FileInput in0, WALPointer expPtr, RecordIO reader) throws EOFException, IgniteCheckedException {
+ static WALRecord readWithCrc(FileInput in0, WALPointer expPtr, RecordIO reader) throws EOFException, IgniteCheckedException {
long startPos = -1;
- try (FileInput.Crc32CheckingFileInput in = in0.startRead(SKIP_CRC)) {
+ try (FileInput.Crc32CheckingFileInput in = in0.startRead(skipCrc)) {
startPos = in0.position();
WALRecord res = reader.readWithHeaders(in, expPtr);
@@ -307,19 +307,19 @@ public static WALRecord readWithCrc(FileInput in0, WALPointer expPtr, RecordIO r
/**
* Writes record with calculated CRC to buffer {@code buf}.
*
- * @param record WAL record.
+ * @param rec WAL record.
* @param buf Buffer to write.
* @param writer Record write I/O interface.
* @throws IgniteCheckedException If it's unable to write record.
*/
- public static void writeWithCrc(WALRecord record, ByteBuffer buf, RecordIO writer) throws IgniteCheckedException {
- assert record.size() >= 0 && buf.remaining() >= record.size() : record.size();
+ static void writeWithCrc(WALRecord rec, ByteBuffer buf, RecordIO writer) throws IgniteCheckedException {
+ assert rec.size() >= 0 && buf.remaining() >= rec.size() : rec.size();
int startPos = buf.position();
- writer.writeWithHeaders(record, buf);
+ writer.writeWithHeaders(rec, buf);
- if (!SKIP_CRC) {
+ if (!skipCrc) {
int curPos = buf.position();
buf.position(startPos);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
index 05f2a244e84b6..adfd70120faf5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/serializer/RecordV2Serializer.java
@@ -54,7 +54,7 @@
*/
public class RecordV2Serializer implements RecordSerializer {
/** Length of WAL Pointer: Index (8) + File offset (4) + Record length (4) */
- public static final int FILE_WAL_POINTER_SIZE = 8 + 4 + 4;
+ private static final int FILE_WAL_POINTER_SIZE = 8 + 4 + 4;
/** V2 data serializer. */
private final RecordDataV2Serializer dataSerializer;
@@ -212,37 +212,38 @@ public RecordV2Serializer(RecordDataV2Serializer dataSerializer, boolean writePo
* @return Read file WAL pointer.
* @throws IOException If failed to write.
*/
- public static FileWALPointer readPositionAndCheckPoint(
+ @SuppressWarnings("UnusedReturnValue")
+ private static FileWALPointer readPositionAndCheckPoint(
DataInput in,
WALPointer expPtr,
boolean skipPositionCheck
) throws IgniteCheckedException, IOException {
long idx = in.readLong();
- int fileOffset = in.readInt();
- int length = in.readInt();
+ int fileOff = in.readInt();
+ int len = in.readInt();
FileWALPointer p = (FileWALPointer)expPtr;
- if (!F.eq(idx, p.index()) || (!skipPositionCheck && !F.eq(fileOffset, p.fileOffset())))
+ if (!F.eq(idx, p.index()) || (!skipPositionCheck && !F.eq(fileOff, p.fileOffset())))
throw new WalSegmentTailReachedException(
"WAL segment tail is reached. [ " +
"Expected next state: {Index=" + p.index() + ",Offset=" + p.fileOffset() + "}, " +
- "Actual state : {Index=" + idx + ",Offset=" + fileOffset + "} ]", null);
+ "Actual state : {Index=" + idx + ",Offset=" + fileOff + "} ]", null);
- return new FileWALPointer(idx, fileOffset, length);
+ return new FileWALPointer(idx, fileOff, len);
}
/**
- * Writes record file position to given {@code buf}.
+ * Writes rec file position to given {@code buf}.
*
- * @param buf Buffer to write record file position.
- * @param record WAL record.
+ * @param buf Buffer to write rec file position.
+ * @param rec WAL rec.
*/
- public static void putPositionOfRecord(ByteBuffer buf, WALRecord record) {
- FileWALPointer p = (FileWALPointer)record.position();
+ private static void putPositionOfRecord(ByteBuffer buf, WALRecord rec) {
+ FileWALPointer p = (FileWALPointer)rec.position();
buf.putLong(p.index());
buf.putInt(p.fileOffset());
- buf.putInt(record.size());
+ buf.putInt(rec.size());
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
index 49d8c180333e0..6a265ebee286b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
@@ -259,9 +259,8 @@ public static CacheConfiguration readCacheConfiguration(BinaryRawReaderEx in) {
}
}
- if (ccfg.getPluginConfigurations() != null) {
+ if (ccfg.getPluginConfigurations() != null)
Collections.addAll(plugins, ccfg.getPluginConfigurations());
- }
ccfg.setPluginConfigurations(plugins.toArray(new CachePluginConfiguration[plugins.size()]));
}
@@ -420,7 +419,8 @@ private static void writeAffinityFunction(BinaryRawWriter out, AffinityFunction
out.writeBoolean(f0.isExcludeNeighbors());
out.writeByte((byte) 0); // override flags
out.writeObject(null); // user func
- } else if (f instanceof PlatformAffinityFunction) {
+ }
+ else if (f instanceof PlatformAffinityFunction) {
PlatformAffinityFunction f0 = (PlatformAffinityFunction) f;
AffinityFunction baseFunc = f0.getBaseFunc();
@@ -430,16 +430,17 @@ private static void writeAffinityFunction(BinaryRawWriter out, AffinityFunction
out.writeBoolean(((RendezvousAffinityFunction) baseFunc).isExcludeNeighbors());
out.writeByte(f0.getOverrideFlags());
out.writeObject(f0.getUserFunc());
- } else {
+ }
+ else {
out.writeByte((byte) 3);
out.writeInt(f0.partitions());
out.writeBoolean(false); // exclude neighbors
out.writeByte(f0.getOverrideFlags());
out.writeObject(f0.getUserFunc());
}
- } else {
- out.writeByte((byte) 0);
}
+ else
+ out.writeByte((byte)0);
}
/**
@@ -465,9 +466,8 @@ else if (p instanceof LruEvictionPolicy) {
out.writeInt(p0.getMaxSize());
out.writeLong(p0.getMaxMemorySize());
}
- else {
+ else
out.writeByte((byte)0);
- }
}
/**
@@ -578,9 +578,9 @@ private static QueryIndex readQueryIndex(BinaryRawReader in) {
public static void readIgniteConfiguration(BinaryRawReaderEx in, IgniteConfiguration cfg) {
if (in.readBoolean())
cfg.setClientMode(in.readBoolean());
- int[] eventTypes = in.readIntArray();
- if (eventTypes != null)
- cfg.setIncludeEventTypes(eventTypes);
+ int[] evtTypes = in.readIntArray();
+ if (evtTypes != null)
+ cfg.setIncludeEventTypes(evtTypes);
if (in.readBoolean())
cfg.setMetricsExpireTime(in.readLong());
if (in.readBoolean())
@@ -598,9 +598,9 @@ public static void readIgniteConfiguration(BinaryRawReaderEx in, IgniteConfigura
String workDir = in.readString();
if (workDir != null)
cfg.setWorkDirectory(workDir);
- String localHost = in.readString();
- if (localHost != null)
- cfg.setLocalHost(localHost);
+ String locHost = in.readString();
+ if (locHost != null)
+ cfg.setLocalHost(locHost);
if (in.readBoolean())
cfg.setDaemon(in.readBoolean());
if (in.readBoolean())
@@ -787,9 +787,9 @@ private static void readCacheConfigurations(BinaryRawReaderEx in, IgniteConfigur
* @param in Reader.
*/
private static void readDiscoveryConfiguration(BinaryRawReader in, IgniteConfiguration cfg) {
- boolean hasConfig = in.readBoolean();
+ boolean hasCfg = in.readBoolean();
- if (!hasConfig)
+ if (!hasCfg)
return;
TcpDiscoverySpi disco = new TcpDiscoverySpi();
@@ -799,21 +799,20 @@ private static void readDiscoveryConfiguration(BinaryRawReader in, IgniteConfigu
if (hasIpFinder) {
byte ipFinderType = in.readByte();
- int addrCount = in.readInt();
+ int addrCnt = in.readInt();
ArrayList addrs = null;
- if (addrCount > 0) {
- addrs = new ArrayList<>(addrCount);
+ if (addrCnt > 0) {
+ addrs = new ArrayList<>(addrCnt);
- for (int i = 0; i < addrCount; i++)
+ for (int i = 0; i < addrCnt; i++)
addrs.add(in.readString());
}
TcpDiscoveryVmIpFinder finder = null;
- if (ipFinderType == 1) {
+ if (ipFinderType == 1)
finder = new TcpDiscoveryVmIpFinder();
- }
else if (ipFinderType == 2) {
TcpDiscoveryMulticastIpFinder finder0 = new TcpDiscoveryMulticastIpFinder();
@@ -830,9 +829,8 @@ else if (ipFinderType == 2) {
finder = finder0;
}
- else {
+ else
assert false;
- }
finder.setAddresses(addrs);
@@ -981,23 +979,23 @@ public static void writeCacheConfiguration(BinaryRawWriter writer, CacheConfigur
* Write query entity.
*
* @param writer Writer.
- * @param queryEntity Query entity.
+ * @param qryEntity Query entity.
*/
- public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEntity) {
- assert queryEntity != null;
+ public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity qryEntity) {
+ assert qryEntity != null;
- writer.writeString(queryEntity.getKeyType());
- writer.writeString(queryEntity.getValueType());
- writer.writeString(queryEntity.getTableName());
- writer.writeString(queryEntity.getKeyFieldName());
- writer.writeString(queryEntity.getValueFieldName());
+ writer.writeString(qryEntity.getKeyType());
+ writer.writeString(qryEntity.getValueType());
+ writer.writeString(qryEntity.getTableName());
+ writer.writeString(qryEntity.getKeyFieldName());
+ writer.writeString(qryEntity.getValueFieldName());
// Fields
- LinkedHashMap fields = queryEntity.getFields();
+ LinkedHashMap fields = qryEntity.getFields();
if (fields != null) {
- Set keyFields = queryEntity.getKeyFields();
- Set notNullFields = queryEntity.getNotNullFields();
+ Set keyFields = qryEntity.getKeyFields();
+ Set notNullFields = qryEntity.getNotNullFields();
writer.writeInt(fields.size());
@@ -1012,7 +1010,7 @@ public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEnt
writer.writeInt(0);
// Aliases
- Map aliases = queryEntity.getAliases();
+ Map aliases = qryEntity.getAliases();
if (aliases != null) {
writer.writeInt(aliases.size());
@@ -1026,7 +1024,7 @@ public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEnt
writer.writeInt(0);
// Indexes
- Collection indexes = queryEntity.getIndexes();
+ Collection indexes = qryEntity.getIndexes();
if (indexes != null) {
writer.writeInt(indexes.size());
@@ -1042,16 +1040,16 @@ public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity queryEnt
* Writer query index.
*
* @param writer Writer.
- * @param index Index.
+ * @param idx Index.
*/
- private static void writeQueryIndex(BinaryRawWriter writer, QueryIndex index) {
- assert index != null;
+ private static void writeQueryIndex(BinaryRawWriter writer, QueryIndex idx) {
+ assert idx != null;
- writer.writeString(index.getName());
- writeEnumByte(writer, index.getIndexType());
- writer.writeInt(index.getInlineSize());
+ writer.writeString(idx.getName());
+ writeEnumByte(writer, idx.getIndexType());
+ writer.writeInt(idx.getInlineSize());
- LinkedHashMap fields = index.getFields();
+ LinkedHashMap fields = idx.getFields();
if (fields != null) {
writer.writeInt(fields.size());
@@ -1273,9 +1271,9 @@ private static void writeDiscoveryConfiguration(BinaryRawWriter w, DiscoverySpi
if (finder instanceof TcpDiscoveryVmIpFinder) {
w.writeBoolean(true);
- boolean isMulticast = finder instanceof TcpDiscoveryMulticastIpFinder;
+ boolean isMcast = finder instanceof TcpDiscoveryMulticastIpFinder;
- w.writeByte((byte)(isMulticast ? 2 : 1));
+ w.writeByte((byte)(isMcast ? 2 : 1));
Collection addrs = finder.getRegisteredAddresses();
@@ -1284,7 +1282,7 @@ private static void writeDiscoveryConfiguration(BinaryRawWriter w, DiscoverySpi
for (InetSocketAddress a : addrs)
w.writeString(a.toString());
- if (isMulticast) {
+ if (isMcast) {
TcpDiscoveryMulticastIpFinder multiFinder = (TcpDiscoveryMulticastIpFinder) finder;
w.writeString(multiFinder.getLocalAddress());
@@ -1529,9 +1527,8 @@ private static void writeMemoryConfiguration(BinaryRawWriter w, MemoryConfigurat
w.writeLong(plc.getRateTimeInterval());
}
}
- else {
+ else
w.writeInt(0);
- }
}
/**
@@ -1573,9 +1570,8 @@ private static void writeSqlConnectorConfiguration(BinaryRawWriter w, SqlConnect
w.writeBoolean(cfg.isTcpNoDelay());
w.writeInt(cfg.getMaxOpenCursorsPerConnection());
w.writeInt(cfg.getThreadPoolSize());
- } else {
+ } else
w.writeBoolean(false);
- }
}
/**
@@ -1640,7 +1636,7 @@ private static PersistentStoreConfiguration readPersistentStoreConfiguration(Bin
.setWalStorePath(in.readString())
.setWalArchivePath(in.readString())
.setWalMode(WALMode.fromOrdinal(in.readInt()))
- .setTlbSize(in.readInt())
+ .setWalBufferSize(in.readInt())
.setWalFlushFrequency((int) in.readLong())
.setWalFsyncDelayNanos(in.readLong())
.setWalRecordIteratorBufferSize(in.readInt())
@@ -1729,7 +1725,7 @@ private static void writePersistentStoreConfiguration(BinaryRawWriter w, Persist
w.writeString(cfg.getWalStorePath());
w.writeString(cfg.getWalArchivePath());
w.writeInt(cfg.getWalMode().ordinal());
- w.writeInt(cfg.getTlbSize());
+ w.writeInt(cfg.getWalBufferSize());
w.writeLong(cfg.getWalFlushFrequency());
w.writeLong(cfg.getWalFsyncDelayNanos());
w.writeInt(cfg.getWalRecordIteratorBufferSize());
@@ -1740,9 +1736,8 @@ private static void writePersistentStoreConfiguration(BinaryRawWriter w, Persist
w.writeInt(cfg.getCheckpointWriteOrder().ordinal());
w.writeBoolean(cfg.isWriteThrottlingEnabled());
- } else {
+ } else
w.writeBoolean(false);
- }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
index 15e6f2c87520b..98b5c083838d9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridUnsafe.java
@@ -1319,6 +1319,15 @@ public static void putObjectVolatile(Object obj, long off, Object val) {
UNSAFE.putObjectVolatile(obj, off, val);
}
+ /**
+ * Returns page size.
+ *
+ * @return Page size.
+ */
+ public static int pageSize() {
+ return UNSAFE.pageSize();
+ }
+
/**
* Returns unaligned flag.
*/
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 98046086dcc96..b3ca6ffb06b00 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -9449,11 +9449,9 @@ public static Comparator inetAddressesComparator(final boolea
try {
Method mtd = cls.getDeclaredMethod(name, paramTypes);
- if (mtd.getReturnType() != void.class) {
- mtd.setAccessible(true);
+ mtd.setAccessible(true);
- return mtd;
- }
+ return mtd;
}
catch (NoSuchMethodException ignored) {
// No-op.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorPersistentStoreConfiguration.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorPersistentStoreConfiguration.java
index d26ab355d21e1..986f0ee0c54c8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorPersistentStoreConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorPersistentStoreConfiguration.java
@@ -111,7 +111,7 @@ public VisorPersistentStoreConfiguration(DataStorageConfiguration cfg) {
walArchivePath = cfg.getWalArchivePath();
metricsEnabled = cfg.isMetricsEnabled();
walMode = cfg.getWalMode();
- tlbSize = cfg.getWalThreadLocalBufferSize();
+ tlbSize = cfg.getWalBufferSize();
walFlushFreq = cfg.getWalFlushFrequency();
walFsyncDelay = cfg.getWalFsyncDelayNanos();
walRecordIterBuffSize = cfg.getWalRecordIteratorBufferSize();
diff --git a/modules/core/src/main/java/org/apache/ignite/mxbean/DataStorageMetricsMXBean.java b/modules/core/src/main/java/org/apache/ignite/mxbean/DataStorageMetricsMXBean.java
index 40410cb58e492..2051da39b41e4 100644
--- a/modules/core/src/main/java/org/apache/ignite/mxbean/DataStorageMetricsMXBean.java
+++ b/modules/core/src/main/java/org/apache/ignite/mxbean/DataStorageMetricsMXBean.java
@@ -40,6 +40,10 @@ public interface DataStorageMetricsMXBean extends DataStorageMetrics {
@MXBeanDescription("Average WAL fsync duration in microseconds over the last time interval.")
@Override float getWalFsyncTimeAverage();
+ /** {@inheritDoc} */
+ @MXBeanDescription("WAL buffer poll spins number over the last time interval.")
+ @Override long getWalBuffPollSpinsRate();
+
/** {@inheritDoc} */
@MXBeanDescription("Duration of the last checkpoint in milliseconds.")
@Override long getLastCheckpointDuration();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTestWithPersistence.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTestWithPersistence.java
index 624595215ae10..15e67b29a6b0d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTestWithPersistence.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClusterActivateDeactivateTestWithPersistence.java
@@ -214,4 +214,8 @@ public void testActivateCacheRestoreConfigurationConflict() throws Exception {
checkNoCaches(SRVS);
}
+
+ @Override public void testActivateFailover3() throws Exception {
+ super.testActivateFailover3();
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsTransactionsHangTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsTransactionsHangTest.java
index f3aee08b773fc..22d16657ee9f8 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsTransactionsHangTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgnitePdsTransactionsHangTest.java
@@ -204,7 +204,7 @@ public void testTransactionsDontHang() throws Exception {
}
}
catch (Throwable e) {
- System.out.println(e.toString());
+ log.error("Unexpected exception:", e);
throw new RuntimeException(e);
}
@@ -229,14 +229,14 @@ public void testTransactionsDontHang() throws Exception {
max = Math.max(max, sum);
min = Math.min(min, sum);
- System.out.println("Operation count: " + sum + " min=" + min + " max=" + max + " avg=" + totalOperations / (periods - WARM_UP_PERIOD));
+ log.info("Operation count: " + sum + " min=" + min + " max=" + max + " avg=" + totalOperations / (periods - WARM_UP_PERIOD));
}
}
interrupt.set(true);
threadPool.shutdown();
- System.out.println("Test complete");
+ log.info("Test complete");
threadPool.awaitTermination(getTestTimeout(), TimeUnit.MILLISECONDS);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgnitePdsWalTlbTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgnitePdsWalTlbTest.java
deleted file mode 100644
index 3b76b63a33b54..0000000000000
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgnitePdsWalTlbTest.java
+++ /dev/null
@@ -1,126 +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.processors.cache.persistence.db.wal;
-
-import javax.cache.CacheException;
-import org.apache.ignite.IgniteDataStreamer;
-import org.apache.ignite.configuration.CacheConfiguration;
-import org.apache.ignite.configuration.IgniteConfiguration;
-import org.apache.ignite.configuration.DataStorageConfiguration;
-import org.apache.ignite.configuration.DataRegionConfiguration;
-import org.apache.ignite.configuration.WALMode;
-import org.apache.ignite.internal.IgniteEx;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
-import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
-
-import static org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.DFLT_MIN_CHECKPOINTING_PAGE_BUFFER_SIZE;
-import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.DFLT_STORE_DIR;
-
-/**
- *
- */
-public class IgnitePdsWalTlbTest extends GridCommonAbstractTest {
- /** Ip finder. */
- private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
-
- /** Cache name. */
- private static final String CACHE_NAME = "cache";
-
- /** {@inheritDoc} */
- @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
- IgniteConfiguration cfg = super.getConfiguration(gridName);
-
- CacheConfiguration ccfg = new CacheConfiguration<>(CACHE_NAME);
-
- cfg.setCacheConfiguration(ccfg);
-
- DataStorageConfiguration memCfg = new DataStorageConfiguration()
- .setDefaultDataRegionConfiguration(
- new DataRegionConfiguration().setMaxSize(100 * 1024 * 1024)
- .setPersistenceEnabled(true)
- .setCheckpointPageBufferSize(DFLT_MIN_CHECKPOINTING_PAGE_BUFFER_SIZE + 1))
- .setWalMode(WALMode.LOG_ONLY)
- .setWalThreadLocalBufferSize(640000000);
-
- cfg.setDataStorageConfiguration(memCfg);
-
- TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
-
- discoSpi.setIpFinder(IP_FINDER);
-
- if (gridName.endsWith("1"))
- cfg.setClientMode(true);
-
- cfg.setDiscoverySpi(discoSpi);
-
- return cfg;
- }
-
- /** {@inheritDoc} */
- @Override protected long getTestTimeout() {
- return 30_000;
- }
-
- /** {@inheritDoc} */
- @Override protected void beforeTest() throws Exception {
- deleteRecursively(U.resolveWorkDirectory(U.defaultWorkDirectory(), DFLT_STORE_DIR, false));
-
- stopAllGrids();
-
- startGrids(2);
- }
-
- /** {@inheritDoc} */
- @Override protected void afterTest() throws Exception {
- stopAllGrids();
-
- deleteRecursively(U.resolveWorkDirectory(U.defaultWorkDirectory(), DFLT_STORE_DIR, false));
- }
-
- /**
- * @throws Exception if failed.
- */
- public void testWalDirectOutOfMemory() throws Exception {
- IgniteEx ig = grid(1);
-
- ig.active(true);
-
- boolean locked = true;
-
- try (IgniteDataStreamer streamer = ig.dataStreamer(CACHE_NAME)) {
- for (int i = 0; i < 100_000; i++) {
- streamer.addData(i, 1);
-
- if (i > 0 && i % 10_000 == 0)
- info("Done put: " + i);
- }
- }
- catch (CacheException ignore) {
- // expected
- locked = false;
- }
- finally {
- assertFalse(locked);
-
- stopAllGrids();
- }
- }
-}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
index 107b4672a5bd7..2bcc22fffc1ea 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushFailoverTest.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
import java.nio.file.OpenOption;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
@@ -31,6 +32,7 @@
import org.apache.ignite.configuration.WALMode;
import org.apache.ignite.internal.GridKernalState;
import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIODecorator;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
@@ -65,6 +67,8 @@ public class IgniteWalFlushFailoverTest extends GridCommonAbstractTest {
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
+ stopAllGrids();
+
deleteWorkFiles();
}
@@ -83,12 +87,12 @@ public class IgniteWalFlushFailoverTest extends GridCommonAbstractTest {
cfg.setCacheConfiguration(cacheCfg);
DataStorageConfiguration memCfg = new DataStorageConfiguration()
- .setDefaultDataRegionConfiguration(
- new DataRegionConfiguration().setMaxSize(2048L * 1024 * 1024).setPersistenceEnabled(true))
- .setFileIOFactory(new FailingFileIOFactory())
- .setWalMode(WALMode.BACKGROUND)
- // Setting WAL Segment size to high values forces flushing by timeout.
- .setWalSegmentSize(flushByTimeout ? 500_000 : 50_000);
+ .setDefaultDataRegionConfiguration(
+ new DataRegionConfiguration().setMaxSize(2048L * 1024 * 1024).setPersistenceEnabled(true))
+ .setFileIOFactory(new FailingFileIOFactory())
+ .setWalMode(WALMode.BACKGROUND)
+ .setWalBufferSize(128 * 1024)// Setting WAL Segment size to high values forces flushing by timeout.
+ .setWalSegmentSize(flushByTimeout ? 500_000 : 50_000);
cfg.setDataStorageConfiguration(memCfg);
@@ -121,6 +125,13 @@ public void testErrorOnDirectFlush() throws Exception {
private void flushingErrorTest() throws Exception {
final IgniteEx grid = startGrid(0);
+ IgniteWriteAheadLogManager wal = grid.context().cache().context().wal();
+
+ boolean mmap = GridTestUtils.getFieldValue(wal, "mmap");
+
+ if (mmap)
+ return;
+
try {
grid.active(true);
@@ -152,7 +163,7 @@ private void flushingErrorTest() throws Exception {
}
/**
- * @throws IgniteCheckedException
+ * @throws IgniteCheckedException If failed.
*/
private void deleteWorkFiles() throws IgniteCheckedException {
deleteRecursively(U.resolveWorkDirectory(U.defaultWorkDirectory(), DFLT_STORE_DIR, false));
@@ -162,9 +173,10 @@ private void deleteWorkFiles() throws IgniteCheckedException {
* Create File I/O which fails after second attempt to write to File
*/
private static class FailingFileIOFactory implements FileIOFactory {
+ /** Serial version uid. */
private static final long serialVersionUID = 0L;
- /** */
+ /** Delegate factory. */
private final FileIOFactory delegateFactory = new RandomAccessFileIOFactory();
/** {@inheritDoc} */
@@ -174,17 +186,23 @@ private static class FailingFileIOFactory implements FileIOFactory {
/** {@inheritDoc} */
@Override public FileIO create(File file, OpenOption... modes) throws IOException {
- FileIO delegate = delegateFactory.create(file, modes);
+ final FileIO delegate = delegateFactory.create(file, modes);
return new FileIODecorator(delegate) {
int writeAttempts = 2;
- @Override public int write(ByteBuffer sourceBuffer) throws IOException {
+ @Override public int write(ByteBuffer srcBuf) throws IOException {
if (--writeAttempts == 0)
throw new RuntimeException("Test exception. Unable to write to file.");
- return super.write(sourceBuffer);
+ return super.write(srcBuf);
}
+
+ /** {@inheritDoc} */
+ @Override public MappedByteBuffer map(int maxWalSegmentSize) throws IOException {
+ return delegate.map(maxWalSegmentSize);
+ }
+
};
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
index 057e082a5717b..d6c0a9da45cf6 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/wal/IgniteWalFlushMultiNodeFailoverAbstractSelfTest.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
@@ -30,6 +31,8 @@
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIODecorator;
import org.apache.ignite.internal.processors.cache.persistence.file.FileIOFactory;
@@ -139,6 +142,13 @@ public void failWhilePut(boolean failWhileStart) throws Exception {
final Ignite grid = startGridsMultiThreaded(gridCount());
+ IgniteWriteAheadLogManager wal = ((IgniteKernal)grid).context().cache().context().wal();
+
+ boolean mmap = GridTestUtils.getFieldValue(wal, "mmap");
+
+ if (mmap)
+ return;
+
grid.active(true);
IgniteCache