use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class IndexingScrubDangling method scrubIndexRangeOnly.
@Nonnull
private CompletableFuture<Boolean> scrubIndexRangeOnly(@Nonnull FDBRecordStore store, byte[] startBytes, byte[] endBytes, @Nonnull AtomicLong recordsScanned) {
// return false when done
Index index = common.getIndex();
final RecordMetaData metaData = store.getRecordMetaData();
final RecordMetaDataProvider recordMetaDataProvider = common.getRecordStoreBuilder().getMetaDataProvider();
if (recordMetaDataProvider == null || !metaData.equals(recordMetaDataProvider.getRecordMetaData())) {
throw new MetaDataException("Store does not have the same metadata");
}
final IndexMaintainer maintainer = store.getIndexMaintainer(index);
// scrubbing only readable, VALUE, idempotence indexes (at least for now)
validateOrThrowEx(maintainer.isIdempotent(), "scrubbed index is not idempotent");
validateOrThrowEx(index.getType().equals(IndexTypes.VALUE) || scrubbingPolicy.ignoreIndexTypeCheck(), "scrubbed index is not a VALUE index");
validateOrThrowEx(store.getIndexState(index) == IndexState.READABLE, "scrubbed index is not readable");
RangeSet rangeSet = new RangeSet(indexScrubIndexRangeSubspace(store, index));
AsyncIterator<Range> ranges = rangeSet.missingRanges(store.ensureContextActive(), startBytes, endBytes).iterator();
final ExecuteProperties.Builder executeProperties = ExecuteProperties.newBuilder().setIsolationLevel(IsolationLevel.SNAPSHOT).setReturnedRowLimit(// always respectLimit in this path; +1 allows a continuation item
getLimit() + 1);
final ScanProperties scanProperties = new ScanProperties(executeProperties.build());
return ranges.onHasNext().thenCompose(hasNext -> {
if (Boolean.FALSE.equals(hasNext)) {
// Here: no more missing ranges - all done
// To avoid stale metadata, we'll keep the scrubbed-ranges indicator empty until the next scrub call.
Transaction tr = store.getContext().ensureActive();
tr.clear(indexScrubIndexRangeSubspace(store, index).range());
return AsyncUtil.READY_FALSE;
}
final Range range = ranges.next();
final Tuple rangeStart = RangeSet.isFirstKey(range.begin) ? null : Tuple.fromBytes(range.begin);
final Tuple rangeEnd = RangeSet.isFinalKey(range.end) ? null : Tuple.fromBytes(range.end);
final TupleRange tupleRange = TupleRange.between(rangeStart, rangeEnd);
RecordCursor<FDBIndexedRecord<Message>> cursor = store.scanIndexRecords(index.getName(), IndexScanType.BY_VALUE, tupleRange, null, IndexOrphanBehavior.RETURN, scanProperties);
final AtomicBoolean hasMore = new AtomicBoolean(true);
final AtomicReference<RecordCursorResult<FDBIndexedRecord<Message>>> lastResult = new AtomicReference<>(RecordCursorResult.exhausted());
final long scanLimit = scrubbingPolicy.getEntriesScanLimit();
return iterateRangeOnly(store, cursor, this::deleteIndexIfDangling, lastResult, hasMore, recordsScanned, true).thenApply(vignore -> hasMore.get() ? lastResult.get().get().getIndexEntry().getKey() : rangeEnd).thenCompose(cont -> rangeSet.insertRange(store.ensureContextActive(), packOrNull(rangeStart), packOrNull(cont), true).thenApply(ignore -> {
if (scanLimit > 0) {
scanCounter += recordsScanned.get();
if (scanLimit <= scanCounter) {
return false;
}
}
return !Objects.equals(cont, rangeEnd);
}));
});
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBStoreBase method addConflictForSubspace.
public void addConflictForSubspace(boolean write) {
final Range range = getSubspace().range();
final Transaction tr = context.ensureActive();
if (write) {
tr.addWriteConflictRange(range.begin, range.end);
} else {
tr.addReadConflictRange(range.begin, range.end);
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBDatabase method createTransaction.
/**
* Creates a new transaction against the database.
*
* @param executor the executor to be used for asynchronous operations
* @return newly created transaction
*/
private Transaction createTransaction(@Nonnull FDBRecordContextConfig config, @Nonnull Executor executor) {
final TransactionListener listener = config.getTransactionListener() == null ? factory.getTransactionListener() : config.getTransactionListener();
final StoreTimer timer = listener != null ? new StoreSubTimer(config.getTimer()) : config.getTimer();
boolean enableAssertions = config.areAssertionsEnabled();
// noinspection ConstantConditions
Transaction transaction = database.createTransaction(executor, new EventKeeperTranslator(timer));
if (timer != null || enableAssertions) {
transaction = new InstrumentedTransaction(timer, this, listener, transaction, enableAssertions);
}
return transaction;
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBDatabase method performNoOpAsync.
/**
* Perform a no-op against FDB to check network thread liveness. This operation will not change the underlying data
* in any way, nor will it perform any I/O against the FDB cluster. However, it will schedule some amount of work
* onto the FDB client and wait for it to complete. The FoundationDB client operates by scheduling onto an event
* queue that is then processed by a single thread (the "network thread"). This method can be used to determine if
* the network thread has entered a state where it is no longer processing requests or if its time to process
* requests has increased. If the network thread is busy, this operation may take some amount of time to complete,
* which is why this operation returns a future.
*
* <p>
* If the provided {@link FDBStoreTimer} is not {@code null}, then this will update the {@link FDBStoreTimer.Events#PERFORM_NO_OP}
* operation with related timing information. This can then be monitored to detect instances of client saturation
* where the performance bottleneck lies in scheduling work to run on the FDB event queue.
* </p>
*
* @param mdcContext logger context to set in running threads
* @param timer the timer to use for instrumentation
* @return a future that will complete after being run by the FDB network thread
*/
@Nonnull
public CompletableFuture<Void> performNoOpAsync(@Nullable Map<String, String> mdcContext, @Nullable FDBStoreTimer timer) {
final FDBRecordContext context = openContext(mdcContext, timer);
boolean futureStarted = false;
try {
// Set the read version of the transaction, then read it back. This requires no I/O, but it does
// require the network thread be running. The exact value used for the read version is unimportant.
// Note that this calls setReadVersion and getReadVersion on the Transaction object, *not* on the
// FDBRecordContext. This is because the FDBRecordContext will cache the value of setReadVersion to
// avoid having to go back to the FDB network thread, but we do not want that for instrumentation.
final Transaction tr = context.ensureActive();
final long startTime = System.nanoTime();
tr.setReadVersion(1066L);
CompletableFuture<Long> future = tr.getReadVersion();
if (timer != null) {
future = context.instrument(FDBStoreTimer.Events.PERFORM_NO_OP, future, startTime);
}
futureStarted = true;
return future.thenAccept(ignore -> {
}).whenComplete((vignore, err) -> {
context.close();
if (err != null) {
logNoOpFailure(err);
}
});
} catch (RuntimeException e) {
logNoOpFailure(e);
CompletableFuture<Void> errFuture = new CompletableFuture<>();
errFuture.completeExceptionally(e);
return errFuture;
} finally {
if (!futureStarted) {
context.close();
}
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method rebuildAllIndexes.
/**
* Rebuild all of this store's indexes. All indexes will then be marked as {@linkplain IndexState#READABLE readable}
* when this function completes. Note that this will attempt to read all of the records within
* this store in a single transaction, so for large record stores, this can run up against transaction
* time and size limits. For larger stores, one should use the {@link OnlineIndexer} to build
* each index instead.
*
* @return a future that will complete when all of the indexes are built
*/
@Nonnull
public CompletableFuture<Void> rebuildAllIndexes() {
Transaction tr = ensureContextActive();
// Note that index states are *not* cleared, as rebuilding the indexes resets each state
tr.clear(getSubspace().range(Tuple.from(INDEX_KEY)));
tr.clear(getSubspace().range(Tuple.from(INDEX_SECONDARY_SPACE_KEY)));
tr.clear(getSubspace().range(Tuple.from(INDEX_RANGE_SPACE_KEY)));
tr.clear(getSubspace().range(Tuple.from(INDEX_UNIQUENESS_VIOLATIONS_KEY)));
List<CompletableFuture<Void>> work = new LinkedList<>();
addRebuildRecordCountsJob(work);
return rebuildIndexes(getRecordMetaData().getIndexesToBuildSince(-1), Collections.emptyMap(), work, RebuildIndexReason.REBUILD_ALL, null);
}
Aggregations