use of com.apple.foundationdb.FDBException in project fdb-record-layer by FoundationDB.
the class IndexingThrottle method throttledRunAsync.
@Nonnull
<R> CompletableFuture<R> throttledRunAsync(@Nonnull final Function<FDBRecordStore, CompletableFuture<R>> function, @Nonnull final BiFunction<R, Throwable, Pair<R, Throwable>> handlePostTransaction, @Nullable final BiConsumer<FDBException, List<Object>> handleLessenWork, @Nullable final List<Object> additionalLogMessageKeyValues) {
List<Object> onlineIndexerLogMessageKeyValues = new ArrayList<>(Arrays.asList(LogMessageKeys.INDEX_NAME, common.getTargetIndexesNames(), LogMessageKeys.INDEXER_ID, common.getUuid()));
if (additionalLogMessageKeyValues != null) {
onlineIndexerLogMessageKeyValues.addAll(additionalLogMessageKeyValues);
}
AtomicInteger tries = new AtomicInteger(0);
CompletableFuture<R> ret = new CompletableFuture<>();
AtomicLong toWait = new AtomicLong(common.getRunner().getDatabase().getFactory().getInitialDelayMillis());
AsyncUtil.whileTrue(() -> {
loadConfig();
return common.getRunner().runAsync(context -> common.getRecordStoreBuilder().copyBuilder().setContext(context).openAsync().thenCompose(store -> {
for (Index index : common.getTargetIndexes()) {
IndexState indexState = store.getIndexState(index);
if (indexState != expectedIndexState) {
throw new RecordCoreStorageException("Unexpected index state", LogMessageKeys.INDEX_NAME, index.getName(), common.getRecordStoreBuilder().getSubspaceProvider().logKey(), common.getRecordStoreBuilder().getSubspaceProvider().toString(context), LogMessageKeys.INDEX_STATE, indexState, LogMessageKeys.INDEX_STATE_PRECONDITION, expectedIndexState);
}
}
return function.apply(store);
}), handlePostTransaction, onlineIndexerLogMessageKeyValues).handle((value, e) -> {
if (e == null) {
ret.complete(value);
return AsyncUtil.READY_FALSE;
} else {
int currTries = tries.getAndIncrement();
FDBException fdbE = getFDBException(e);
if (currTries < common.config.getMaxRetries() && fdbE != null && lessenWorkCodes.contains(fdbE.getCode())) {
if (handleLessenWork != null) {
handleLessenWork.accept(fdbE, onlineIndexerLogMessageKeyValues);
}
long delay = (long) (Math.random() * toWait.get());
toWait.set(Math.min(toWait.get() * 2, common.getRunner().getDatabase().getFactory().getMaxDelayMillis()));
if (LOGGER.isWarnEnabled()) {
final KeyValueLogMessage message = KeyValueLogMessage.build("Retrying Runner Exception", LogMessageKeys.INDEXER_CURR_RETRY, currTries, LogMessageKeys.INDEXER_MAX_RETRIES, common.config.getMaxRetries(), LogMessageKeys.DELAY, delay, LogMessageKeys.LIMIT, limit);
message.addKeysAndValues(onlineIndexerLogMessageKeyValues);
LOGGER.warn(message.toString(), e);
}
return MoreAsyncUtil.delayedFuture(delay, TimeUnit.MILLISECONDS).thenApply(vignore3 -> true);
} else {
return completeExceptionally(ret, e, onlineIndexerLogMessageKeyValues);
}
}
}).thenCompose(Function.identity());
}, common.getRunner().getExecutor()).whenComplete((vignore, e) -> {
if (e != null) {
// Just update ret and ignore the returned future.
completeExceptionally(ret, e, onlineIndexerLogMessageKeyValues);
}
});
return ret;
}
use of com.apple.foundationdb.FDBException in project fdb-record-layer by FoundationDB.
the class BunchedMapScanTest method scanWithConflict.
@Test
public void scanWithConflict() throws InterruptedException, ExecutionException {
clearAndPopulate();
try (Transaction tr1 = db.createTransaction();
Transaction tr2 = db.createTransaction()) {
CompletableFuture.allOf(tr1.getReadVersion(), tr2.getReadVersion()).get();
BunchedMapIterator<Tuple, Tuple> iterator = map.scan(tr1, bmSubspace);
int count = MoreAsyncUtil.reduce(iterator, 0, (oldCount, item) -> oldCount + 1).get();
assertEquals(keys.size(), count);
tr1.addWriteConflictKey(Tuple.from(count).pack());
assertFalse(map.put(tr2, bmSubspace, Tuple.from(keys.get(keys.size() - 1).getLong(0) + 1), value).get().isPresent());
tr2.commit().get();
CompletionException e = assertThrows(CompletionException.class, () -> tr1.commit().join());
assertNotNull(e.getCause());
assertTrue(e.getCause() instanceof FDBException);
FDBException fdbE = (FDBException) e.getCause();
assertEquals(FDBError.NOT_COMMITTED.code(), fdbE.getCode());
}
byte[] continuation = null;
for (int i = 0; i < keys.size(); i++) {
}
try (Transaction tr1 = db.createTransaction();
Transaction tr2 = db.createTransaction()) {
CompletableFuture.allOf(tr1.getReadVersion(), tr2.getReadVersion()).get();
BunchedMapIterator<Tuple, Tuple> iterator = map.scan(tr1, bmSubspace);
}
}
use of com.apple.foundationdb.FDBException in project fdb-record-layer by FoundationDB.
the class BunchedMapTest method inconsistentScan.
private static List<KeyValue> inconsistentScan(@Nonnull Database db, @Nonnull Subspace subspace) {
// Note that tr is mutated in the block, hence not using try-with-resources
Transaction tr = db.createTransaction();
try {
KeySelector begin = KeySelector.firstGreaterOrEqual(subspace.range().begin);
KeySelector end = KeySelector.firstGreaterOrEqual(subspace.range().end);
KeyValue lastSeen = null;
AsyncIterator<KeyValue> rangeIterator = tr.getRange(begin, end).iterator();
List<KeyValue> rangeKVs = new ArrayList<>();
boolean done = false;
while (!done) {
// Might loop if there are timeouts encountered within loop.
try {
while (rangeIterator.hasNext()) {
KeyValue next = rangeIterator.next();
rangeKVs.add(next);
lastSeen = next;
}
done = true;
} catch (RuntimeException e) {
FDBException fdbE = unwrapException(e);
if (fdbE == null || fdbE.getCode() != FDBError.TRANSACTION_TOO_OLD.code()) {
throw e;
} else {
// Timed out. Restart transaction and keep going.
tr.close();
tr = db.createTransaction();
if (lastSeen != null) {
// Update begin if we have any results.
begin = KeySelector.firstGreaterThan(lastSeen.getKey());
lastSeen = null;
}
rangeIterator = tr.getRange(begin, end).iterator();
}
}
}
return rangeKVs;
} finally {
tr.close();
}
}
use of com.apple.foundationdb.FDBException in project fdb-record-layer by FoundationDB.
the class BunchedMapTest method runWithTwoTrs.
private void runWithTwoTrs(@Nonnull BiConsumer<? super Transaction, ? super Transaction> operation, boolean legal, @Nonnull List<Tuple> boundaryKeys) throws ExecutionException, InterruptedException {
final String id = "two-trs-" + UUID.randomUUID().toString();
try (Transaction tr1 = db.createTransaction();
Transaction tr2 = db.createTransaction()) {
tr1.options().setDebugTransactionIdentifier(id + "-1");
tr1.options().setLogTransaction();
tr2.options().setDebugTransactionIdentifier(id + "-2");
tr2.options().setLogTransaction();
CompletableFuture.allOf(tr1.getReadVersion(), tr2.getReadVersion()).get();
tr1.addWriteConflictKey(new byte[] { 0x01 });
tr2.addWriteConflictKey(new byte[] { 0x02 });
operation.accept(tr1, tr2);
tr1.commit().get();
if (legal) {
tr2.commit().get();
} else {
ExecutionException e = assertThrows(ExecutionException.class, () -> tr2.commit().get());
assertNotNull(e.getCause());
assertTrue(e.getCause() instanceof FDBException);
FDBException fdbE = (FDBException) e.getCause();
assertEquals(FDBError.NOT_COMMITTED.code(), fdbE.getCode());
}
}
verifyBoundaryKeys(boundaryKeys);
}
use of com.apple.foundationdb.FDBException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method testRestoreMdc.
@Test
void testRestoreMdc() {
Executor oldExecutor = FDBDatabaseFactory.instance().getExecutor();
try {
ThreadContext.clearAll();
ThreadContext.put("outer", "Echidna");
final Map<String, String> outer = ThreadContext.getContext();
final ImmutableMap<String, String> restored = ImmutableMap.of("restored", "Platypus");
FDBDatabaseFactory.instance().setExecutor(new ContextRestoringExecutor(new ForkJoinPool(2), ImmutableMap.of("executor", "Water Bear")));
AtomicInteger attempts = new AtomicInteger(0);
final FDBDatabaseRunner runner = database.newRunner(FDBRecordContextConfig.newBuilder().setMdcContext(restored));
List<Map<String, String>> threadContexts = new Vector<>();
Consumer<String> saveThreadContext = name -> threadContexts.add(threadContextPlus(name, attempts.get(), ThreadContext.getContext()));
final String runnerRunAsyncName = "runner runAsync";
final String supplyAsyncName = "supplyAsync";
final String handleName = "handle";
// Delay starting the future until all callbacks have been set up so that the handle lambda
// runs in the context-restoring executor.
CompletableFuture<Void> signal = new CompletableFuture<>();
CompletableFuture<?> task = runner.runAsync(recordContext -> {
saveThreadContext.accept(runnerRunAsyncName);
return signal.thenCompose(vignore -> CompletableFuture.supplyAsync(() -> {
saveThreadContext.accept(supplyAsyncName);
if (attempts.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Retriable and lessener", new FDBException("not_committed", 1020));
} else {
return null;
}
}, recordContext.getExecutor()));
}).handle((result, exception) -> {
saveThreadContext.accept(handleName);
return exception;
});
signal.complete(null);
assertNull(task.join());
List<Map<String, String>> expected = ImmutableList.of(// it is known behavior that the first will be run in the current context
threadContextPlus(runnerRunAsyncName, 0, outer), threadContextPlus(supplyAsyncName, 0, restored), // the code that creates the future, should now have the correct MDC
threadContextPlus(runnerRunAsyncName, 1, restored), threadContextPlus(supplyAsyncName, 1, restored), // this should also have the correct MDC
threadContextPlus(handleName, 2, restored));
assertEquals(expected, threadContexts);
assertEquals(outer, ThreadContext.getContext());
} finally {
FDBDatabaseFactory.instance().setExecutor(oldExecutor);
}
}
Aggregations