use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class BTreeIndex method get.
/**
* Looks up the value of a single key.
*
* @param key A ByteArraySegment representing the key to look up.
* @param timeout Timeout for the operation.
* @return A CompletableFuture that, when completed normally, will contain the value associated with the given key.
* If no value is associated with this key, the Future will complete with null. If the operation failed, the Future
* will be completed with the appropriate exception.
*/
public CompletableFuture<ByteArraySegment> get(@NonNull ByteArraySegment key, @NonNull Duration timeout) {
ensureInitialized();
TimeoutTimer timer = new TimeoutTimer(timeout);
// Lookup the page where the Key should exist (if at all).
PageCollection pageCollection = new PageCollection(this.state.length);
return locatePage(key, pageCollection, timer).thenApplyAsync(page -> page.getPage().searchExact(key), this.executor);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class BTreeIndex method update.
/**
* Inserts, updates or removes the given Page Entries into the index. If {@link PageEntry#getValue()} is null, then
* the page entry is removed, otherwise it is added.
*
* @param entries A Collection of Page Entries to insert. The collection need not be sorted.
* @param timeout Timeout for the operation.
* @return A CompletableFuture that, when completed normally, will indicate that the index updates have been applied
* successfully and will contain the current version of the index (any modifications to the index will result in a
* larger version value). If the operation failed, the Future will be completed with the appropriate exception.
*/
public CompletableFuture<Long> update(@NonNull Collection<PageEntry> entries, @NonNull Duration timeout) {
ensureInitialized();
TimeoutTimer timer = new TimeoutTimer(timeout);
// Process the Entries in sorted order (by key); this makes the operation more efficient as we can batch-update
// entries belonging to the same page.
val toUpdate = entries.stream().sorted((e1, e2) -> KEY_COMPARATOR.compare(e1.getKey(), e2.getKey())).iterator();
return applyUpdates(toUpdate, timer).thenComposeAsync(pageCollection -> loadSmallestOffsetPage(pageCollection, timer).thenRun(() -> processModifiedPages(pageCollection)).thenComposeAsync(v -> writePages(pageCollection, timer.getRemaining()), this.executor), this.executor);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class BTreeIndex method get.
/**
* Looks up the value of multiple keys.
*
* @param keys A list of ByteArraySegments representing the keys to look up.
* @param timeout Timeout for the operation.
* @return A CompletableFuture that, when completed normally, will contain a List with ByteArraySegments representing
* the values associated with the given keys. The values in this list will be in the same order as the given Keys, so
* they can be matched to their sought keys by their index. If the operation failed, the Future
* will be completed with the appropriate exception.
*/
public CompletableFuture<List<ByteArraySegment>> get(@NonNull List<ByteArraySegment> keys, @NonNull Duration timeout) {
if (keys.size() == 1) {
// Shortcut for single key.
return get(keys.get(0), timeout).thenApply(Collections::singletonList);
}
// Lookup all the keys in parallel, and make sure to apply their resulting values in the same order that their keys
// where provided to us.
ensureInitialized();
TimeoutTimer timer = new TimeoutTimer(timeout);
PageCollection pageCollection = new PageCollection(this.state.length);
val gets = keys.stream().map(key -> locatePage(key, pageCollection, timer).thenApplyAsync(page -> page.getPage().searchExact(key), this.executor)).collect(Collectors.toList());
return Futures.allOfWithResults(gets);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class BTreeIndex method applyUpdates.
// endregion
// region Helpers
/**
* Executes the given updates on the index. Loads up any necessary BTreePage instances in memory but does not persist
* the changes to the external data source, nor does it reassign offsets to the modified pages, perform splits, etc.
*
* @param updates An Iterator of the PageEntry instances to insert, update or remove. The Iterator must return the
* updates in sorted order (by key).
* @param timer Timer for the operation.
* @return A CompletableFuture that will contain a PageCollection with all touched pages.
*/
private CompletableFuture<UpdateablePageCollection> applyUpdates(Iterator<PageEntry> updates, TimeoutTimer timer) {
UpdateablePageCollection pageCollection = new UpdateablePageCollection(this.state.length);
AtomicReference<PageWrapper> lastPage = new AtomicReference<>(null);
val lastPageUpdates = new ArrayList<PageEntry>();
return Futures.loop(updates::hasNext, () -> {
// Locate the page where the update is to be executed. Do not apply it yet as it is more efficient
// to bulk-apply multiple at once. Collect all updates for each Page, and only apply them once we have
// "moved on" to another page.
PageEntry next = updates.next();
return locatePage(next.getKey(), pageCollection, timer).thenAccept(page -> {
PageWrapper last = lastPage.get();
if (page != last) {
// This key goes to a different page than the one we were looking at.
if (last != null) {
// Commit the outstanding updates.
last.setEntryCountDelta(last.getPage().update(lastPageUpdates));
}
// Update the pointers.
lastPage.set(page);
lastPageUpdates.clear();
}
// Record the current update.
lastPageUpdates.add(next);
});
}, this.executor).thenApplyAsync(v -> {
// We need not forget to apply the last batch of updates from the last page.
PageWrapper last = lastPage.get();
if (last != null) {
last.setEntryCountDelta(last.getPage().update(lastPageUpdates));
}
return pageCollection;
}, this.executor);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class StreamSegmentContainerTests method tryActivate.
/**
* Attempts to activate the targetSegment in the given Container. Since we do not have access to the internals of the
* Container, we need to trigger this somehow, hence the need for this complex code. We need to trigger a truncation,
* so we need an 'appendSegment' to which we continuously append so that the DurableDataLog is truncated. After truncation,
* the Metadata should have enough leeway in making room for new activation.
*
* @return A Future that will complete either with an exception (failure) or SegmentProperties for the targetSegment.
*/
private CompletableFuture<SegmentProperties> tryActivate(MetadataCleanupContainer localContainer, String targetSegment, String appendSegment) {
CompletableFuture<SegmentProperties> successfulMap = new CompletableFuture<>();
// Append continuously to an existing segment in order to trigger truncations (these are necessary for forced evictions).
val appendFuture = localContainer.appendRandomly(appendSegment, false, () -> !successfulMap.isDone());
Futures.exceptionListener(appendFuture, successfulMap::completeExceptionally);
// Repeatedly try to get info on 'segment1' (activate it), until we succeed or time out.
TimeoutTimer remaining = new TimeoutTimer(TIMEOUT);
Futures.loop(() -> !successfulMap.isDone(), () -> Futures.delayedFuture(Duration.ofMillis(EVICTION_SEGMENT_EXPIRATION_MILLIS_SHORT), executorService()).thenCompose(v -> localContainer.getStreamSegmentInfo(targetSegment, TIMEOUT)).thenAccept(successfulMap::complete).exceptionally(ex -> {
if (!(Exceptions.unwrap(ex) instanceof TooManyActiveSegmentsException)) {
// Some other error.
successfulMap.completeExceptionally(ex);
} else if (!remaining.hasRemaining()) {
// Waited too long.
successfulMap.completeExceptionally(new TimeoutException("No successful activation could be done in the allotted time."));
}
// Try again.
return null;
}), executorService());
return successfulMap;
}
Aggregations