-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Introduce sequence-number-aware translog #22822
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
281f2e8
13a8030
5b60b52
5a55802
835c75e
76ee8fb
bed78d3
d8a846e
772a513
36a2c85
ed3973c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ | |
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.elasticsearch.index.translog; | ||
|
|
||
| import org.apache.lucene.codecs.CodecUtil; | ||
|
|
@@ -35,11 +36,13 @@ | |
| import java.nio.file.OpenOption; | ||
| import java.nio.file.Path; | ||
|
|
||
| class Checkpoint { | ||
| final class Checkpoint { | ||
|
|
||
| final long offset; | ||
| final int numOps; | ||
| final long generation; | ||
| final long minSeqNo; | ||
| final long maxSeqNo; | ||
| final long globalCheckpoint; | ||
|
|
||
| private static final int INITIAL_VERSION = 1; // start with 1, just to recognize there was some magic serialization logic before | ||
|
|
@@ -52,6 +55,8 @@ class Checkpoint { | |
| + Integer.BYTES // ops | ||
| + Long.BYTES // offset | ||
| + Long.BYTES // generation | ||
| + Long.BYTES // minimum sequence number, introduced in 6.0.0 | ||
| + Long.BYTES // maximum sequence number, introduced in 6.0.0 | ||
| + Long.BYTES // global checkpoint, introduced in 6.0.0 | ||
| + CodecUtil.footerLength(); | ||
|
|
||
|
|
@@ -62,66 +67,78 @@ class Checkpoint { | |
| + Long.BYTES // generation | ||
| + CodecUtil.footerLength(); | ||
|
|
||
| static final int LEGACY_NON_CHECKSUMMED_FILE_LENGTH = Integer.BYTES // ops | ||
| + Long.BYTES // offset | ||
| + Long.BYTES; // generation | ||
|
|
||
| Checkpoint(long offset, int numOps, long generation, long globalCheckpoint) { | ||
| /** | ||
| * Create a new translog checkpoint. | ||
| * | ||
| * @param offset the current offset in the translog | ||
| * @param numOps the current number of operations in the translog | ||
| * @param generation the current translog generation | ||
| * @param minSeqNo the current minimum sequence number of all operations in the translog | ||
| * @param maxSeqNo the current maximum sequence number of all operations in the translog | ||
| * @param globalCheckpoint the last-known global checkpoint | ||
| */ | ||
| Checkpoint(long offset, int numOps, long generation, long minSeqNo, long maxSeqNo, long globalCheckpoint) { | ||
| assert minSeqNo <= maxSeqNo; | ||
| this.offset = offset; | ||
| this.numOps = numOps; | ||
| this.generation = generation; | ||
| this.minSeqNo = minSeqNo; | ||
| this.maxSeqNo = maxSeqNo; | ||
|
||
| this.globalCheckpoint = globalCheckpoint; | ||
| } | ||
|
|
||
| private void write(DataOutput out) throws IOException { | ||
| out.writeLong(offset); | ||
| out.writeInt(numOps); | ||
| out.writeLong(generation); | ||
| out.writeLong(minSeqNo); | ||
| out.writeLong(maxSeqNo); | ||
| out.writeLong(globalCheckpoint); | ||
| } | ||
|
|
||
| static Checkpoint readChecksummedV2(DataInput in) throws IOException { | ||
| return new Checkpoint(in.readLong(), in.readInt(), in.readLong(), in.readLong()); | ||
| static Checkpoint emptyTranslogCheckpoint(final long offset, final long generation, final long globalCheckpoint) { | ||
| final long minSeqNo = SequenceNumbersService.NO_OPS_PERFORMED; | ||
| final long maxSeqNo = SequenceNumbersService.NO_OPS_PERFORMED; | ||
| return new Checkpoint(offset, 0, generation, minSeqNo, maxSeqNo, globalCheckpoint); | ||
| } | ||
|
|
||
| // reads a checksummed checkpoint introduced in ES 5.0.0 | ||
| static Checkpoint readChecksummedV1(DataInput in) throws IOException { | ||
| return new Checkpoint(in.readLong(), in.readInt(), in.readLong(), SequenceNumbersService.UNASSIGNED_SEQ_NO); | ||
| static Checkpoint readCheckpointV6_0_0(final DataInput in) throws IOException { | ||
| return new Checkpoint(in.readLong(), in.readInt(), in.readLong(), in.readLong(), in.readLong(), in.readLong()); | ||
| } | ||
|
|
||
| // reads checkpoint from ES < 5.0.0 | ||
| static Checkpoint readNonChecksummed(DataInput in) throws IOException { | ||
| return new Checkpoint(in.readLong(), in.readInt(), in.readLong(), SequenceNumbersService.UNASSIGNED_SEQ_NO); | ||
| // reads a checksummed checkpoint introduced in ES 5.0.0 | ||
| static Checkpoint readCheckpointV5_0_0(final DataInput in) throws IOException { | ||
| final long minSeqNo = SequenceNumbersService.NO_OPS_PERFORMED; | ||
| final long maxSeqNo = SequenceNumbersService.NO_OPS_PERFORMED; | ||
| final long globalCheckpoint = SequenceNumbersService.UNASSIGNED_SEQ_NO; | ||
| return new Checkpoint(in.readLong(), in.readInt(), in.readLong(), minSeqNo, maxSeqNo, globalCheckpoint); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Checkpoint{" + | ||
| "offset=" + offset + | ||
| ", numOps=" + numOps + | ||
| ", translogFileGeneration=" + generation + | ||
| ", generation=" + generation + | ||
| ", minSeqNo=" + minSeqNo + | ||
| ", maxSeqNo=" + maxSeqNo + | ||
| ", globalCheckpoint=" + globalCheckpoint + | ||
| '}'; | ||
| } | ||
|
|
||
| public static Checkpoint read(Path path) throws IOException { | ||
| try (Directory dir = new SimpleFSDirectory(path.getParent())) { | ||
| try (IndexInput indexInput = dir.openInput(path.getFileName().toString(), IOContext.DEFAULT)) { | ||
| if (indexInput.length() == LEGACY_NON_CHECKSUMMED_FILE_LENGTH) { | ||
| // OLD unchecksummed file that was written < ES 5.0.0 | ||
| return Checkpoint.readNonChecksummed(indexInput); | ||
| // We checksum the entire file before we even go and parse it. If it's corrupted we barf right here. | ||
| CodecUtil.checksumEntireFile(indexInput); | ||
| final int fileVersion = CodecUtil.checkHeader(indexInput, CHECKPOINT_CODEC, INITIAL_VERSION, CURRENT_VERSION); | ||
| if (fileVersion == INITIAL_VERSION) { | ||
| assert indexInput.length() == V1_FILE_SIZE : indexInput.length(); | ||
| return Checkpoint.readCheckpointV5_0_0(indexInput); | ||
| } else { | ||
| // We checksum the entire file before we even go and parse it. If it's corrupted we barf right here. | ||
| CodecUtil.checksumEntireFile(indexInput); | ||
| final int fileVersion = CodecUtil.checkHeader(indexInput, CHECKPOINT_CODEC, INITIAL_VERSION, CURRENT_VERSION); | ||
| if (fileVersion == INITIAL_VERSION) { | ||
| assert indexInput.length() == V1_FILE_SIZE; | ||
| return Checkpoint.readChecksummedV1(indexInput); | ||
| } else { | ||
| assert fileVersion == CURRENT_VERSION; | ||
| assert indexInput.length() == FILE_SIZE; | ||
| return Checkpoint.readChecksummedV2(indexInput); | ||
| } | ||
| assert fileVersion == CURRENT_VERSION : fileVersion; | ||
| assert indexInput.length() == FILE_SIZE : indexInput.length(); | ||
| return Checkpoint.readCheckpointV6_0_0(indexInput); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -159,30 +176,28 @@ public synchronized byte[] toByteArray() { | |
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
|
|
||
| Checkpoint that = (Checkpoint) o; | ||
|
|
||
| if (offset != that.offset) { | ||
| return false; | ||
| } | ||
| if (numOps != that.numOps) { | ||
| return false; | ||
| } | ||
| return generation == that.generation; | ||
|
|
||
| if (offset != that.offset) return false; | ||
| if (numOps != that.numOps) return false; | ||
| if (generation != that.generation) return false; | ||
| if (minSeqNo != that.minSeqNo) return false; | ||
| if (maxSeqNo != that.maxSeqNo) return false; | ||
| return globalCheckpoint == that.globalCheckpoint; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int result = Long.hashCode(offset); | ||
| result = 31 * result + numOps; | ||
| result = 31 * result + Long.hashCode(generation); | ||
| result = 31 * result + Long.hashCode(minSeqNo); | ||
| result = 31 * result + Long.hashCode(maxSeqNo); | ||
| result = 31 * result + Long.hashCode(globalCheckpoint); | ||
| return result; | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
++