use of org.opensearch.index.engine.Engine in project OpenSearch by opensearch-project.
the class IndexLevelReplicationTests method testAppendWhileRecovering.
public void testAppendWhileRecovering() throws Exception {
try (ReplicationGroup shards = createGroup(0)) {
shards.startAll();
CountDownLatch latch = new CountDownLatch(2);
int numDocs = randomIntBetween(100, 200);
// just append one to the translog so we can assert below
shards.appendDocs(1);
Thread thread = new Thread() {
@Override
public void run() {
try {
latch.countDown();
latch.await();
shards.appendDocs(numDocs - 1);
} catch (Exception e) {
throw new AssertionError(e);
}
}
};
thread.start();
IndexShard replica = shards.addReplica();
Future<Void> future = shards.asyncRecoverReplica(replica, (indexShard, node) -> new RecoveryTarget(indexShard, node, recoveryListener) {
@Override
public void cleanFiles(int totalTranslogOps, long globalCheckpoint, Store.MetadataSnapshot sourceMetadata, ActionListener<Void> listener) {
super.cleanFiles(totalTranslogOps, globalCheckpoint, sourceMetadata, ActionListener.runAfter(listener, () -> {
latch.countDown();
try {
latch.await();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}));
}
});
future.get();
thread.join();
shards.assertAllEqual(numDocs);
Engine engine = IndexShardTests.getEngineFromShard(shards.getPrimary());
assertEquals(0, InternalEngineTests.getNumIndexVersionsLookups((InternalEngine) engine));
assertEquals(0, InternalEngineTests.getNumVersionLookups((InternalEngine) engine));
}
}
use of org.opensearch.index.engine.Engine in project OpenSearch by opensearch-project.
the class RecoveryDuringReplicationTests method testRollbackOnPromotion.
public void testRollbackOnPromotion() throws Exception {
try (ReplicationGroup shards = createGroup(between(2, 3))) {
shards.startAll();
IndexShard newPrimary = randomFrom(shards.getReplicas());
int initDocs = shards.indexDocs(randomInt(100));
int inFlightOpsOnNewPrimary = 0;
int inFlightOps = scaledRandomIntBetween(10, 200);
for (int i = 0; i < inFlightOps; i++) {
String id = "extra-" + i;
IndexRequest primaryRequest = new IndexRequest(index.getName()).id(id).source("{}", XContentType.JSON);
BulkShardRequest replicationRequest = indexOnPrimary(primaryRequest, shards.getPrimary());
for (IndexShard replica : shards.getReplicas()) {
if (randomBoolean()) {
indexOnReplica(replicationRequest, shards, replica);
if (replica == newPrimary) {
inFlightOpsOnNewPrimary++;
}
}
}
if (randomBoolean()) {
shards.syncGlobalCheckpoint();
}
if (rarely()) {
shards.flush();
}
}
shards.refresh("test");
List<DocIdSeqNoAndSource> docsBelowGlobalCheckpoint = EngineTestCase.getDocIds(getEngine(newPrimary), randomBoolean()).stream().filter(doc -> doc.getSeqNo() <= newPrimary.getLastKnownGlobalCheckpoint()).collect(Collectors.toList());
CountDownLatch latch = new CountDownLatch(1);
final AtomicBoolean done = new AtomicBoolean();
Thread thread = new Thread(() -> {
List<IndexShard> replicas = new ArrayList<>(shards.getReplicas());
replicas.remove(newPrimary);
latch.countDown();
while (done.get() == false) {
try {
List<DocIdSeqNoAndSource> exposedDocs = EngineTestCase.getDocIds(getEngine(randomFrom(replicas)), randomBoolean());
assertThat(docsBelowGlobalCheckpoint, everyItem(is(in(exposedDocs))));
assertThat(randomFrom(replicas).getLocalCheckpoint(), greaterThanOrEqualTo(initDocs - 1L));
} catch (AlreadyClosedException ignored) {
// replica swaps engine during rollback
} catch (Exception e) {
throw new AssertionError(e);
}
}
});
thread.start();
latch.await();
shards.promoteReplicaToPrimary(newPrimary).get();
shards.assertAllEqual(initDocs + inFlightOpsOnNewPrimary);
int moreDocsAfterRollback = shards.indexDocs(scaledRandomIntBetween(1, 20));
shards.assertAllEqual(initDocs + inFlightOpsOnNewPrimary + moreDocsAfterRollback);
done.set(true);
thread.join();
shards.syncGlobalCheckpoint();
for (IndexShard shard : shards) {
shard.flush(new FlushRequest().force(true).waitIfOngoing(true));
assertThat(shard.translogStats().getUncommittedOperations(), equalTo(0));
}
}
}
use of org.opensearch.index.engine.Engine in project OpenSearch by opensearch-project.
the class IndexShardTests method testResetEngine.
public void testResetEngine() throws Exception {
IndexShard shard = newStartedShard(false);
indexOnReplicaWithGaps(shard, between(0, 1000), Math.toIntExact(shard.getLocalCheckpoint()));
long maxSeqNoBeforeRollback = shard.seqNoStats().getMaxSeqNo();
final long globalCheckpoint = randomLongBetween(shard.getLastKnownGlobalCheckpoint(), shard.getLocalCheckpoint());
shard.updateGlobalCheckpointOnReplica(globalCheckpoint, "test");
Set<String> docBelowGlobalCheckpoint = getShardDocUIDs(shard).stream().filter(id -> Long.parseLong(id) <= globalCheckpoint).collect(Collectors.toSet());
TranslogStats translogStats = shard.translogStats();
AtomicBoolean done = new AtomicBoolean();
CountDownLatch latch = new CountDownLatch(1);
Thread thread = new Thread(() -> {
latch.countDown();
int hitClosedExceptions = 0;
while (done.get() == false) {
try {
List<String> exposedDocIds = EngineTestCase.getDocIds(getEngine(shard), rarely()).stream().map(DocIdSeqNoAndSource::getId).collect(Collectors.toList());
assertThat("every operations before the global checkpoint must be reserved", docBelowGlobalCheckpoint, everyItem(is(in(exposedDocIds))));
} catch (AlreadyClosedException ignored) {
hitClosedExceptions++;
} catch (IOException e) {
throw new AssertionError(e);
}
}
// engine reference was switched twice: current read/write engine -> ready-only engine -> new read/write engine
assertThat(hitClosedExceptions, lessThanOrEqualTo(2));
});
thread.start();
latch.await();
final CountDownLatch engineResetLatch = new CountDownLatch(1);
shard.acquireAllReplicaOperationsPermits(shard.getOperationPrimaryTerm(), globalCheckpoint, 0L, ActionListener.wrap(r -> {
try {
shard.resetEngineToGlobalCheckpoint();
} finally {
r.close();
engineResetLatch.countDown();
}
}, Assert::assertNotNull), TimeValue.timeValueMinutes(1L));
engineResetLatch.await();
assertThat(getShardDocUIDs(shard), equalTo(docBelowGlobalCheckpoint));
assertThat(shard.seqNoStats().getMaxSeqNo(), equalTo(globalCheckpoint));
if (shard.indexSettings.isSoftDeleteEnabled()) {
// we might have trimmed some operations if the translog retention policy is ignored (when soft-deletes enabled).
assertThat(shard.translogStats().estimatedNumberOfOperations(), lessThanOrEqualTo(translogStats.estimatedNumberOfOperations()));
} else {
assertThat(shard.translogStats().estimatedNumberOfOperations(), equalTo(translogStats.estimatedNumberOfOperations()));
}
assertThat(shard.getMaxSeqNoOfUpdatesOrDeletes(), equalTo(maxSeqNoBeforeRollback));
done.set(true);
thread.join();
closeShard(shard, false);
}
use of org.opensearch.index.engine.Engine in project OpenSearch by opensearch-project.
the class RefreshListenersTests method testLotsOfThreads.
/**
* Uses a bunch of threads to index, wait for refresh, and non-realtime get documents to validate that they are visible after waiting
* regardless of what crazy sequence of events causes the refresh listener to fire.
*/
public void testLotsOfThreads() throws Exception {
int threadCount = between(3, 10);
maxListeners = between(1, threadCount * 2);
// This thread just refreshes every once in a while to cause trouble.
Cancellable refresher = threadPool.scheduleWithFixedDelay(() -> engine.refresh("because test"), timeValueMillis(100), Names.SAME);
// These threads add and block until the refresh makes the change visible and then do a non-realtime get.
Thread[] indexers = new Thread[threadCount];
for (int thread = 0; thread < threadCount; thread++) {
final String threadId = String.format(Locale.ROOT, "%04d", thread);
indexers[thread] = new Thread(() -> {
for (int iteration = 1; iteration <= 50; iteration++) {
try {
String testFieldValue = String.format(Locale.ROOT, "%s%04d", threadId, iteration);
Engine.IndexResult index = index(threadId, testFieldValue);
assertEquals(iteration, index.getVersion());
DummyRefreshListener listener = new DummyRefreshListener();
listeners.addOrNotify(index.getTranslogLocation(), listener);
assertBusy(() -> assertNotNull("listener never called", listener.forcedRefresh.get()), 1, TimeUnit.MINUTES);
if (threadCount < maxListeners) {
assertFalse(listener.forcedRefresh.get());
}
listener.assertNoError();
Engine.Get get = new Engine.Get(false, false, threadId, new Term(IdFieldMapper.NAME, threadId));
try (Engine.GetResult getResult = engine.get(get, engine::acquireSearcher)) {
assertTrue("document not found", getResult.exists());
assertEquals(iteration, getResult.version());
org.apache.lucene.document.Document document = getResult.docIdAndVersion().reader.document(getResult.docIdAndVersion().docId);
assertThat(document.getValues("test"), arrayContaining(testFieldValue));
}
} catch (Exception t) {
throw new RuntimeException("failure on the [" + iteration + "] iteration of thread [" + threadId + "]", t);
}
}
});
indexers[thread].start();
}
for (Thread indexer : indexers) {
indexer.join();
}
refresher.cancel();
}
use of org.opensearch.index.engine.Engine in project OpenSearch by opensearch-project.
the class RefreshListenersTests method setupListeners.
@Before
public void setupListeners() throws Exception {
// Setup dependencies of the listeners
maxListeners = randomIntBetween(1, 1000);
// Now setup the InternalEngine which is much more complicated because we aren't mocking anything
threadPool = new TestThreadPool(getTestName());
refreshMetric = new MeanMetric();
listeners = new RefreshListeners(() -> maxListeners, () -> engine.refresh("too-many-listeners"), logger, threadPool.getThreadContext(), refreshMetric);
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("index", Settings.EMPTY);
ShardId shardId = new ShardId(new Index("index", "_na_"), 1);
String allocationId = UUIDs.randomBase64UUID(random());
Directory directory = newDirectory();
store = new Store(shardId, indexSettings, directory, new DummyShardLock(shardId));
IndexWriterConfig iwc = newIndexWriterConfig();
TranslogConfig translogConfig = new TranslogConfig(shardId, createTempDir("translog"), indexSettings, BigArrays.NON_RECYCLING_INSTANCE);
Engine.EventListener eventListener = new Engine.EventListener() {
@Override
public void onFailedEngine(String reason, @Nullable Exception e) {
// we don't need to notify anybody in this test
}
};
store.createEmpty(Version.CURRENT.luceneVersion);
final long primaryTerm = randomNonNegativeLong();
final String translogUUID = Translog.createEmptyTranslog(translogConfig.getTranslogPath(), SequenceNumbers.NO_OPS_PERFORMED, shardId, primaryTerm);
store.associateIndexWithNewTranslog(translogUUID);
EngineConfig config = new EngineConfig(shardId, threadPool, indexSettings, null, store, newMergePolicy(), iwc.getAnalyzer(), iwc.getSimilarity(), new CodecService(null, logger), eventListener, IndexSearcher.getDefaultQueryCache(), IndexSearcher.getDefaultQueryCachingPolicy(), translogConfig, TimeValue.timeValueMinutes(5), Collections.singletonList(listeners), Collections.emptyList(), null, new NoneCircuitBreakerService(), () -> SequenceNumbers.NO_OPS_PERFORMED, () -> RetentionLeases.EMPTY, () -> primaryTerm, EngineTestCase.tombstoneDocSupplier());
engine = new InternalEngine(config);
engine.recoverFromTranslog((e, s) -> 0, Long.MAX_VALUE);
listeners.setCurrentRefreshLocationSupplier(engine::getTranslogLastWriteLocation);
}
Aggregations