use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class StreamSegmentContainerTests method waitForOperationsInReadIndex.
/**
* Blocks until all operations processed so far have been added to the ReadIndex and InMemoryOperationLog.
* This is needed to simplify test verification due to the fact that the the OperationProcessor commits operations to
* the ReadIndex and InMemoryOperationLog asynchronously, after those operations were ack-ed. This method makes use
* of the fact that the OperationProcessor/MemoryStateUpdater will still commit such operations in sequence; it
* creates a new segment, writes 1 byte to it and issues a read (actual/future) and waits until it's completed - when
* it is, it is guaranteed that everything prior to that has been committed.
*/
private static void waitForOperationsInReadIndex(SegmentContainer container) throws Exception {
TimeoutTimer timer = new TimeoutTimer(TIMEOUT);
String segmentName = "test" + System.nanoTime();
container.createStreamSegment(segmentName, BASIC_TYPE, null, timer.getRemaining()).thenCompose(v -> container.append(segmentName, new ByteArraySegment(new byte[1]), null, timer.getRemaining())).thenCompose(v -> container.read(segmentName, 0, 1, timer.getRemaining())).thenCompose(rr -> {
ReadResultEntry rre = rr.next();
rre.requestContent(TIMEOUT);
return rre.getContent().thenRun(rr::close);
}).thenCompose(v -> container.deleteStreamSegment(segmentName, timer.getRemaining())).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class StreamSegmentContainerTests method waitForSegmentInStorage.
private CompletableFuture<Void> waitForSegmentInStorage(SegmentProperties metadataProps, TestContext context) {
if (metadataProps.getLength() == 0) {
// Empty segments may or may not exist in Storage, so don't bother complicating ourselves with this.
return CompletableFuture.completedFuture(null);
}
// Check if the Storage Segment is caught up. If sealed, we want to make sure that both the Segment and its
// Attribute Segment are sealed (or the latter has been deleted - for transactions). For all other, we want to
// ensure that the length and truncation offsets have caught up.
BiFunction<SegmentProperties, SegmentProperties, Boolean> meetsConditions = (segmentProps, attrProps) -> metadataProps.isSealed() == (segmentProps.isSealed() && (attrProps.isSealed() || attrProps.isDeleted())) && segmentProps.getLength() >= metadataProps.getLength() && context.storageFactory.truncationOffsets.getOrDefault(metadataProps.getName(), 0L) >= metadataProps.getStartOffset();
String attributeSegmentName = NameUtils.getAttributeSegmentName(metadataProps.getName());
AtomicBoolean canContinue = new AtomicBoolean(true);
TimeoutTimer timer = new TimeoutTimer(TIMEOUT);
return Futures.loop(canContinue::get, () -> {
val segInfo = getStorageSegmentInfo(metadataProps.getName(), timer, context);
val attrInfo = getStorageSegmentInfo(attributeSegmentName, timer, context);
return CompletableFuture.allOf(segInfo, attrInfo).thenCompose(v -> {
if (meetsConditions.apply(segInfo.join(), attrInfo.join())) {
canContinue.set(false);
return CompletableFuture.completedFuture(null);
} else if (!timer.hasRemaining()) {
return Futures.failedFuture(new TimeoutException());
} else {
return Futures.delayedFuture(Duration.ofMillis(10), executorService());
}
}).thenRun(Runnables.doNothing());
}, executorService());
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class ContainerKeyIndex method validateConditionalUpdateFailures.
private CompletableFuture<Void> validateConditionalUpdateFailures(DirectSegmentAccess segment, Map<TableKey, Long> expectedVersions, TimeoutTimer timer) {
assert !expectedVersions.isEmpty();
val bucketReader = TableBucketReader.key(segment, this::getBackpointerOffset, this.executor);
val searches = expectedVersions.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> findBucketEntry(segment, bucketReader, e.getKey().getKey(), e.getValue(), timer)));
return Futures.allOf(searches.values()).thenRun(() -> {
val failed = new HashMap<TableKey, Long>();
for (val e : searches.entrySet()) {
val actual = e.getValue().join();
boolean isValid = actual == null ? e.getKey().getVersion() == TableKey.NOT_EXISTS : e.getKey().getVersion() == actual.getVersion();
if (!isValid) {
failed.put(e.getKey(), actual == null ? TableKey.NOT_EXISTS : actual.getVersion());
}
}
if (!failed.isEmpty()) {
throw new CompletionException(new BadKeyVersionException(segment.getInfo().getName(), failed));
}
});
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class HashTableSegmentLayout method newIterator.
private <T> CompletableFuture<AsyncIterator<IteratorItem<T>>> newIterator(@NonNull DirectSegmentAccess segment, @NonNull IteratorArgs args, @NonNull GetBucketReader<T> createBucketReader) {
Preconditions.checkArgument(args.getFrom() == null && args.getTo() == null, "Range Iterators not supported for HashTableSegments.");
UUID fromHash;
BufferView serializedState = args.getContinuationToken();
try {
fromHash = KeyHasher.getNextHash(serializedState == null ? null : IteratorStateImpl.deserialize(serializedState).getKeyHash());
} catch (IOException ex) {
// Bad IteratorState serialization.
throw new IllegalDataFormatException("Unable to deserialize `serializedState`.", ex);
}
if (fromHash == null) {
// Nothing to iterate on.
return CompletableFuture.completedFuture(TableIterator.empty());
}
// Create a converter that will use a TableBucketReader to fetch all requested items in the iterated Buckets.
val bucketReader = createBucketReader.apply(segment, this.keyIndex::getBackpointerOffset, this.executor);
TableIterator.ConvertResult<IteratorItem<T>> converter = bucket -> bucketReader.findAllExisting(bucket.getSegmentOffset(), new TimeoutTimer(args.getFetchTimeout())).thenApply(result -> new IteratorItemImpl<>(new IteratorStateImpl(bucket.getHash()).serialize(), result));
// Fetch the Tail (Unindexed) Hashes, then create the TableIterator.
return this.keyIndex.getUnindexedKeyHashes(segment).thenComposeAsync(cacheHashes -> TableIterator.<IteratorItem<T>>builder().segment(segment).cacheHashes(cacheHashes).firstHash(fromHash).executor(executor).resultConverter(converter).fetchTimeout(args.getFetchTimeout()).build(), this.executor);
}
use of io.pravega.common.TimeoutTimer in project pravega by pravega.
the class IndexWriter method groupByBucket.
// endregion
// region Updating Table Buckets
/**
* Groups the given {@link BucketUpdate.KeyUpdate} instances by their associated buckets.
*
* @param segment The Segment to read from.
* @param keyUpdates A Collection of {@link BucketUpdate.KeyUpdate} instances to index.
* @param timer Timer for the operation.
* @return A CompletableFuture that, when completed, will contain the a collection of {@link BucketUpdate.Builder}s.
*/
CompletableFuture<Collection<BucketUpdate.Builder>> groupByBucket(DirectSegmentAccess segment, Collection<BucketUpdate.KeyUpdate> keyUpdates, TimeoutTimer timer) {
val updatesByHash = keyUpdates.stream().collect(Collectors.groupingBy(k -> this.hasher.hash(k.getKey())));
return locateBuckets(segment, updatesByHash.keySet(), timer).thenApplyAsync(buckets -> {
val result = new HashMap<TableBucket, BucketUpdate.Builder>();
buckets.forEach((keyHash, bucket) -> {
// Add the bucket to the result and record this Key as a "new" key in it.
BucketUpdate.Builder bu = result.computeIfAbsent(bucket, BucketUpdate::forBucket);
updatesByHash.get(keyHash).forEach(bu::withKeyUpdate);
});
return result.values();
}, this.executor);
}
Aggregations