|
@@ -79,6 +79,7 @@ import org.elasticsearch.common.bytes.BytesArray;
|
|
|
import org.elasticsearch.common.bytes.BytesReference;
|
|
|
import org.elasticsearch.common.collect.Tuple;
|
|
|
import org.elasticsearch.common.logging.Loggers;
|
|
|
+import org.elasticsearch.common.lucene.Lucene;
|
|
|
import org.elasticsearch.common.lucene.index.ElasticsearchDirectoryReader;
|
|
|
import org.elasticsearch.common.lucene.uid.Versions;
|
|
|
import org.elasticsearch.common.lucene.uid.VersionsAndSeqNoResolver;
|
|
@@ -113,6 +114,7 @@ import org.elasticsearch.index.shard.ShardId;
|
|
|
import org.elasticsearch.index.shard.ShardUtils;
|
|
|
import org.elasticsearch.index.store.DirectoryUtils;
|
|
|
import org.elasticsearch.index.store.Store;
|
|
|
+import org.elasticsearch.index.translog.SnapshotMatchers;
|
|
|
import org.elasticsearch.index.translog.Translog;
|
|
|
import org.elasticsearch.index.translog.TranslogConfig;
|
|
|
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
|
@@ -165,6 +167,7 @@ import static org.hamcrest.Matchers.everyItem;
|
|
|
import static org.hamcrest.Matchers.greaterThan;
|
|
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|
|
import static org.hamcrest.Matchers.hasKey;
|
|
|
+import static org.hamcrest.Matchers.hasSize;
|
|
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
|
|
import static org.hamcrest.Matchers.not;
|
|
|
import static org.hamcrest.Matchers.notNullValue;
|
|
@@ -945,17 +948,47 @@ public class InternalEngineTests extends EngineTestCase {
|
|
|
}
|
|
|
|
|
|
public void testCommitAdvancesMinTranslogForRecovery() throws IOException {
|
|
|
+ IOUtils.close(engine, store);
|
|
|
+ final Path translogPath = createTempDir();
|
|
|
+ store = createStore();
|
|
|
+ final AtomicBoolean inSync = new AtomicBoolean(randomBoolean());
|
|
|
+ final BiFunction<EngineConfig, SeqNoStats, SequenceNumbersService> seqNoServiceSupplier = (config, seqNoStats) ->
|
|
|
+ new SequenceNumbersService(
|
|
|
+ config.getShardId(),
|
|
|
+ config.getAllocationId(),
|
|
|
+ config.getIndexSettings(),
|
|
|
+ seqNoStats.getMaxSeqNo(),
|
|
|
+ seqNoStats.getLocalCheckpoint(),
|
|
|
+ seqNoStats.getGlobalCheckpoint()) {
|
|
|
+ @Override
|
|
|
+ public long getGlobalCheckpoint() {
|
|
|
+ return inSync.get() ? getLocalCheckpoint() : SequenceNumbers.UNASSIGNED_SEQ_NO;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ engine = new InternalEngine(config(defaultSettings, store, translogPath, newMergePolicy(), null, null), seqNoServiceSupplier);
|
|
|
ParsedDocument doc = testParsedDocument("1", null, testDocumentWithTextField(), B_1, null);
|
|
|
engine.index(indexForDoc(doc));
|
|
|
+
|
|
|
engine.flush();
|
|
|
assertThat(engine.getTranslog().currentFileGeneration(), equalTo(2L));
|
|
|
- assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(2L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(inSync.get() ? 2L : 1L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getTranslogGenerationOfLastCommit(), equalTo(2L));
|
|
|
+
|
|
|
engine.flush();
|
|
|
assertThat(engine.getTranslog().currentFileGeneration(), equalTo(2L));
|
|
|
- assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(2L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(inSync.get() ? 2L : 1L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getTranslogGenerationOfLastCommit(), equalTo(2L));
|
|
|
+
|
|
|
engine.flush(true, true);
|
|
|
assertThat(engine.getTranslog().currentFileGeneration(), equalTo(3L));
|
|
|
- assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(3L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(inSync.get() ? 3L : 1L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getTranslogGenerationOfLastCommit(), equalTo(3L));
|
|
|
+
|
|
|
+ inSync.set(true);
|
|
|
+ engine.flush(true, true);
|
|
|
+ assertThat(engine.getTranslog().currentFileGeneration(), equalTo(4L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getMinTranslogGenerationForRecovery(), equalTo(4L));
|
|
|
+ assertThat(engine.getTranslog().getDeletionPolicy().getTranslogGenerationOfLastCommit(), equalTo(4L));
|
|
|
}
|
|
|
|
|
|
public void testSyncedFlush() throws IOException {
|
|
@@ -2359,10 +2392,26 @@ public class InternalEngineTests extends EngineTestCase {
|
|
|
);
|
|
|
indexSettings.updateIndexMetaData(builder.build());
|
|
|
|
|
|
+ final BiFunction<EngineConfig, SeqNoStats, SequenceNumbersService> seqNoServiceSupplier = (config, seqNoStats) ->
|
|
|
+ new SequenceNumbersService(
|
|
|
+ config.getShardId(),
|
|
|
+ config.getAllocationId(),
|
|
|
+ config.getIndexSettings(),
|
|
|
+ seqNoStats.getMaxSeqNo(),
|
|
|
+ seqNoStats.getLocalCheckpoint(),
|
|
|
+ seqNoStats.getGlobalCheckpoint()) {
|
|
|
+ @Override
|
|
|
+ public long getGlobalCheckpoint() {
|
|
|
+ return getLocalCheckpoint();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
try (Store store = createStore()) {
|
|
|
AtomicBoolean throwErrorOnCommit = new AtomicBoolean();
|
|
|
final Path translogPath = createTempDir();
|
|
|
- try (InternalEngine engine = new InternalEngine(config(indexSettings, store, translogPath, newMergePolicy(), null, null)) {
|
|
|
+ try (InternalEngine engine =
|
|
|
+ new InternalEngine(config(indexSettings, store, translogPath, newMergePolicy(), null, null), seqNoServiceSupplier) {
|
|
|
+
|
|
|
@Override
|
|
|
protected void commitIndexWriter(IndexWriter writer, Translog translog, String syncId) throws IOException {
|
|
|
super.commitIndexWriter(writer, translog, syncId);
|
|
@@ -2377,7 +2426,8 @@ public class InternalEngineTests extends EngineTestCase {
|
|
|
FlushFailedEngineException e = expectThrows(FlushFailedEngineException.class, engine::flush);
|
|
|
assertThat(e.getCause().getMessage(), equalTo("power's out"));
|
|
|
}
|
|
|
- try (InternalEngine engine = new InternalEngine(config(indexSettings, store, translogPath, newMergePolicy(), null, null))) {
|
|
|
+ try (InternalEngine engine =
|
|
|
+ new InternalEngine(config(indexSettings, store, translogPath, newMergePolicy(), null, null), seqNoServiceSupplier)) {
|
|
|
engine.recoverFromTranslog();
|
|
|
assertVisibleCount(engine, 1);
|
|
|
final long committedGen = Long.valueOf(
|
|
@@ -2608,13 +2658,16 @@ public class InternalEngineTests extends EngineTestCase {
|
|
|
EngineConfig config = engine.config();
|
|
|
|
|
|
EngineConfig newConfig = new EngineConfig(
|
|
|
- randomBoolean() ? EngineConfig.OpenMode.OPEN_INDEX_AND_TRANSLOG : EngineConfig.OpenMode.OPEN_INDEX_CREATE_TRANSLOG,
|
|
|
+ randomBoolean() ? EngineConfig.OpenMode.CREATE_INDEX_AND_TRANSLOG : EngineConfig.OpenMode.OPEN_INDEX_CREATE_TRANSLOG,
|
|
|
shardId, allocationId.getId(),
|
|
|
threadPool, config.getIndexSettings(), null, store, newMergePolicy(), config.getAnalyzer(), config.getSimilarity(),
|
|
|
new CodecService(null, logger), config.getEventListener(), IndexSearcher.getDefaultQueryCache(),
|
|
|
IndexSearcher.getDefaultQueryCachingPolicy(), true, config.getTranslogConfig(), TimeValue.timeValueMinutes(5),
|
|
|
config.getExternalRefreshListener(), config.getInternalRefreshListener(), null, config.getTranslogRecoveryRunner(),
|
|
|
new NoneCircuitBreakerService());
|
|
|
+ if (newConfig.getOpenMode() == EngineConfig.OpenMode.CREATE_INDEX_AND_TRANSLOG) {
|
|
|
+ Lucene.cleanLuceneIndex(store.directory());
|
|
|
+ }
|
|
|
engine = new InternalEngine(newConfig);
|
|
|
if (newConfig.getOpenMode() == EngineConfig.OpenMode.OPEN_INDEX_AND_TRANSLOG) {
|
|
|
engine.recoverFromTranslog();
|
|
@@ -4116,4 +4169,62 @@ public class InternalEngineTests extends EngineTestCase {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void testKeepTranslogAfterGlobalCheckpoint() throws Exception {
|
|
|
+ IOUtils.close(engine, store);
|
|
|
+ final AtomicLong globalCheckpoint = new AtomicLong(0);
|
|
|
+ final BiFunction<EngineConfig, SeqNoStats, SequenceNumbersService> seqNoServiceSupplier = (config, seqNoStats) ->
|
|
|
+ new SequenceNumbersService(
|
|
|
+ config.getShardId(),
|
|
|
+ config.getAllocationId(),
|
|
|
+ config.getIndexSettings(),
|
|
|
+ seqNoStats.getMaxSeqNo(),
|
|
|
+ seqNoStats.getLocalCheckpoint(),
|
|
|
+ seqNoStats.getGlobalCheckpoint()) {
|
|
|
+ @Override
|
|
|
+ public long getGlobalCheckpoint() {
|
|
|
+ return globalCheckpoint.get();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ final IndexSettings indexSettings = new IndexSettings(defaultSettings.getIndexMetaData(), defaultSettings.getNodeSettings(),
|
|
|
+ defaultSettings.getScopedSettings());
|
|
|
+ IndexMetaData.Builder builder = IndexMetaData.builder(indexSettings.getIndexMetaData())
|
|
|
+ .settings(Settings.builder().put(indexSettings.getSettings())
|
|
|
+ .put(IndexSettings.INDEX_TRANSLOG_RETENTION_AGE_SETTING.getKey(), randomFrom("-1", "100micros", "30m"))
|
|
|
+ .put(IndexSettings.INDEX_TRANSLOG_RETENTION_SIZE_SETTING.getKey(), randomFrom("-1", "512b", "1gb")));
|
|
|
+ indexSettings.updateIndexMetaData(builder.build());
|
|
|
+
|
|
|
+ store = createStore();
|
|
|
+ try (InternalEngine engine
|
|
|
+ = createEngine(indexSettings, store, createTempDir(), NoMergePolicy.INSTANCE, null, seqNoServiceSupplier)) {
|
|
|
+ int numDocs = scaledRandomIntBetween(10, 100);
|
|
|
+ for (int docId = 0; docId < numDocs; docId++) {
|
|
|
+ ParseContext.Document document = testDocumentWithTextField();
|
|
|
+ document.add(new Field(SourceFieldMapper.NAME, BytesReference.toBytes(B_1), SourceFieldMapper.Defaults.FIELD_TYPE));
|
|
|
+ engine.index(indexForDoc(testParsedDocument(Integer.toString(docId), null, document, B_1, null)));
|
|
|
+ if (frequently()) {
|
|
|
+ globalCheckpoint.set(randomIntBetween(
|
|
|
+ Math.toIntExact(engine.seqNoService().getGlobalCheckpoint()),
|
|
|
+ Math.toIntExact(engine.seqNoService().getLocalCheckpoint())));
|
|
|
+ }
|
|
|
+ if (frequently()) {
|
|
|
+ engine.flush(randomBoolean(), true);
|
|
|
+ final List<IndexCommit> commits = DirectoryReader.listCommits(store.directory());
|
|
|
+ // Keep only one safe commit as the oldest commit.
|
|
|
+ final IndexCommit safeCommit = commits.get(0);
|
|
|
+ assertThat(Long.parseLong(safeCommit.getUserData().get(SequenceNumbers.MAX_SEQ_NO)),
|
|
|
+ lessThanOrEqualTo(globalCheckpoint.get()));
|
|
|
+ for (int i = 1; i < commits.size(); i++) {
|
|
|
+ assertThat(Long.parseLong(commits.get(i).getUserData().get(SequenceNumbers.MAX_SEQ_NO)),
|
|
|
+ greaterThan(globalCheckpoint.get()));
|
|
|
+ }
|
|
|
+ // Make sure we keep all translog operations after the local checkpoint of the safe commit.
|
|
|
+ long localCheckpointFromSafeCommit = Long.parseLong(safeCommit.getUserData().get(SequenceNumbers.LOCAL_CHECKPOINT_KEY));
|
|
|
+ try (Translog.Snapshot snapshot = engine.getTranslog().newSnapshot()) {
|
|
|
+ assertThat(snapshot, SnapshotMatchers.containsSeqNoRange(localCheckpointFromSafeCommit + 1, docId));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|