/** * Creates a new instance of the MetadataCleaner class. * * @param config Container Configuration to use. * @param metadata An EvictableMetadata to operate on. * @param metadataStore SegmentStateStore to serialize SegmentState in. * @param cleanupCallback A callback to invoke every time cleanup happened. * @param traceObjectId An identifier to use for logging purposes. This will be included at the beginning of all * log calls initiated by this Service. * @param executor The Executor to use for async callbacks and operations. */ MetadataCleaner(@NonNull ContainerConfig config, @NonNull EvictableMetadata metadata, @NonNull MetadataStore metadataStore, @NonNull Consumer<Collection<SegmentMetadata>> cleanupCallback, @NonNull ScheduledExecutorService executor, String traceObjectId) { super(traceObjectId, executor); this.config = config; this.metadata = metadata; this.metadataStore = metadataStore; this.cleanupCallback = cleanupCallback; this.lastIterationSequenceNumber = new AtomicLong(metadata.getOperationSequenceNumber()); this.stopToken = new CancellationToken(); }
/** * Creates a new instance of the Consumer class. * * @param streamName The name of the Stream to monitor. * @param config Test Configuration. * @param dataSource Data Source. * @param testState A TestState representing the current state of the test. This will be used for reporting purposes. * @param store A StoreAdapter to execute operations on. * @param executorService The Executor Service to use for async tasks. */ Consumer(String streamName, TestConfig config, ProducerDataSource dataSource, TestState testState, StoreAdapter store, ScheduledExecutorService executorService) { super(config, dataSource, store, executorService); Preconditions.checkArgument(canUseStoreAdapter(store), "StoreAdapter does not support all required features; cannot create a consumer for it."); this.logId = String.format("Consumer[%s]", streamName); this.streamName = Preconditions.checkNotNull(streamName, "streamName"); this.testState = Preconditions.checkNotNull(testState, "testState"); this.reader = store.createReader(); this.catchupReadsSupported = store.isFeatureSupported(StoreAdapter.Feature.RandomRead); this.storageReadsSupported = store.isFeatureSupported(StoreAdapter.Feature.StorageDirect); this.cancellationToken = new CancellationToken(); this.lastSequenceNumbers = new ConcurrentHashMap<>(); this.catchupQueue = new BlockingDrainingQueue<>(); this.storageQueue = new ArrayDeque<>(); this.storageReadQueue = new ArrayDeque<>(); }
/** * Tests that RequestCancellation cancels futures. */ @Test public void testRequestCancellation() { final int futureCount = 10; CancellationToken token = new CancellationToken(); ArrayList<CompletableFuture<Void>> futures = new ArrayList<>(); Predicate<Integer> isAlreadyCompleted = i -> i % 2 == 0; // Every other future is already completed. for (int i = 0; i < futureCount; i++) { val f = new CompletableFuture<Void>(); if (isAlreadyCompleted.test(i)) { f.complete(null); } futures.add(f); token.register(f); } token.requestCancellation(); for (int i = 0; i < futures.size(); i++) { if (isAlreadyCompleted.test(i)) { Assert.assertTrue("Already completed future was cancelled.", Futures.isSuccessful(futures.get(i))); } else { AssertExtensions.assertThrows( "Future was not cancelled.", futures.get(i)::join, ex -> ex instanceof CancellationException); } } }