use of io.pravega.controller.stream.api.grpc.v1.Controller.TxnId in project pravega by pravega.
the class TimeoutServiceTest method testControllerPingFailureMaxExecutionTimeExceeded.
@Test(timeout = 10000)
public void testControllerPingFailureMaxExecutionTimeExceeded() throws InterruptedException {
int lease = 10;
TxnId txnId = controllerService.createTransaction(SCOPE, STREAM, lease, SCALE_GRACE_PERIOD).thenApply(x -> ModelHelper.decode(x.getKey())).join();
TxnState txnState = controllerService.checkTransactionStatus(SCOPE, STREAM, txnId).join();
Assert.assertEquals(TxnState.State.OPEN, txnState.getState());
PingTxnStatus pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, 1000 * lease).join();
Assert.assertEquals(PingTxnStatus.Status.MAX_EXECUTION_TIME_EXCEEDED, pingStatus.getStatus());
txnState = controllerService.checkTransactionStatus(SCOPE, STREAM, txnId).join();
Assert.assertEquals(TxnState.State.OPEN, txnState.getState());
}
use of io.pravega.controller.stream.api.grpc.v1.Controller.TxnId in project pravega by pravega.
the class TimeoutServiceTest method testControllerPingLeaseTooLarge.
@Test(timeout = 10000)
public void testControllerPingLeaseTooLarge() {
int lease = 10;
TxnId txnId = controllerService.createTransaction(SCOPE, STREAM, lease, SCALE_GRACE_PERIOD).thenApply(x -> ModelHelper.decode(x.getKey())).join();
PingTxnStatus pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, SCALE_GRACE_PERIOD + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, Config.MAX_LEASE_VALUE + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, Config.MAX_SCALE_GRACE_PERIOD + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, 1000 * lease + 1).join();
Assert.assertEquals(PingTxnStatus.Status.MAX_EXECUTION_TIME_EXCEEDED, pingStatus.getStatus());
VersionedTransactionData txData = streamStore.createTransaction(SCOPE, STREAM, UUID.randomUUID(), LEASE, 2 * LEASE, SCALE_GRACE_PERIOD, null, executor).join();
txnId = ModelHelper.decode(txData.getId());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, SCALE_GRACE_PERIOD + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, Config.MAX_LEASE_VALUE + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, Config.MAX_SCALE_GRACE_PERIOD + 1).join();
Assert.assertEquals(PingTxnStatus.Status.LEASE_TOO_LARGE, pingStatus.getStatus());
pingStatus = controllerService.pingTransaction(SCOPE, STREAM, txnId, 3 * LEASE).join();
Assert.assertEquals(PingTxnStatus.Status.MAX_EXECUTION_TIME_EXCEEDED, pingStatus.getStatus());
}
use of io.pravega.controller.stream.api.grpc.v1.Controller.TxnId in project pravega by pravega.
the class StreamTransactionMetadataTasks method createTxnBody.
/**
* Creates txn on the specified stream.
*
* Post-condition:
* 1. If txn creation succeeds, then
* (a) txn node is created in the store,
* (b) txn segments are successfully created on respective segment stores,
* (c) txn is present in the host-txn index of current host,
* (d) txn's timeout is being tracked in timeout service.
*
* 2. If process fails after creating txn node, but before responding to the client, then since txn is
* present in the host-txn index, some other controller process shall abort the txn after maxLeaseValue
*
* 3. If timeout service tracks timeout of specified txn,
* then txn is also present in the host-txn index of current process.
*
* Invariant:
* The following invariants are maintained throughout the execution of createTxn, pingTxn and sealTxn methods.
* 1. If timeout service tracks timeout of a txn, then txn is also present in the host-txn index of current process.
* 2. If txn znode is updated, then txn is also present in the host-txn index of current process.
*
* @param scope scope name.
* @param stream stream name.
* @param lease txn lease.
* @param scaleGracePeriod amount of time for which txn may remain open after scale operation is initiated.
* @param ctx context.
* @return identifier of the created txn.
*/
CompletableFuture<Pair<VersionedTransactionData, List<Segment>>> createTxnBody(final String scope, final String stream, final long lease, final long scaleGracePeriod, final OperationContext ctx) {
// Step 1. Validate parameters.
CompletableFuture<Void> validate = validate(lease, scaleGracePeriod);
long maxExecutionPeriod = Math.min(MAX_EXECUTION_TIME_MULTIPLIER * lease, Duration.ofDays(1).toMillis());
UUID txnId = UUID.randomUUID();
TxnResource resource = new TxnResource(scope, stream, txnId);
// Step 2. Add txn to host-transaction index.
CompletableFuture<Void> addIndex = validate.thenComposeAsync(ignore -> streamMetadataStore.addTxnToIndex(hostId, resource, 0), executor).whenComplete((v, e) -> {
if (e != null) {
log.debug("Txn={}, failed adding txn to host-txn index of host={}", txnId, hostId);
} else {
log.debug("Txn={}, added txn to host-txn index of host={}", txnId, hostId);
}
});
// Step 3. Create txn node in the store.
CompletableFuture<VersionedTransactionData> txnFuture = addIndex.thenComposeAsync(ignore -> streamMetadataStore.createTransaction(scope, stream, txnId, lease, maxExecutionPeriod, scaleGracePeriod, ctx, executor), executor).whenComplete((v, e) -> {
if (e != null) {
log.debug("Txn={}, failed creating txn in store", txnId);
} else {
log.debug("Txn={}, created in store", txnId);
}
});
// Step 4. Notify segment stores about new txn.
CompletableFuture<List<Segment>> segmentsFuture = txnFuture.thenComposeAsync(txnData -> streamMetadataStore.getActiveSegments(scope, stream, txnData.getEpoch(), ctx, executor), executor);
CompletableFuture<Void> notify = segmentsFuture.thenComposeAsync(activeSegments -> notifyTxnCreation(scope, stream, activeSegments, txnId), executor).whenComplete((v, e) -> log.debug("Txn={}, notified segments stores", txnId));
// Step 5. Start tracking txn in timeout service
return notify.whenCompleteAsync((result, ex) -> {
int version = 0;
long executionExpiryTime = System.currentTimeMillis() + maxExecutionPeriod;
if (!txnFuture.isCompletedExceptionally()) {
version = txnFuture.join().getVersion();
executionExpiryTime = txnFuture.join().getMaxExecutionExpiryTime();
}
timeoutService.addTxn(scope, stream, txnId, version, lease, executionExpiryTime, scaleGracePeriod);
log.debug("Txn={}, added to timeout service on host={}", txnId, hostId);
}, executor).thenApplyAsync(v -> new ImmutablePair<>(txnFuture.join(), segmentsFuture.join()), executor);
}
use of io.pravega.controller.stream.api.grpc.v1.Controller.TxnId in project pravega by pravega.
the class TimeoutServiceTest method testPingSuccess.
@Test(timeout = 10000)
public void testPingSuccess() throws InterruptedException {
UUID txnId = UUID.randomUUID();
VersionedTransactionData txData = streamStore.createTransaction(SCOPE, STREAM, txnId, LEASE, 10 * LEASE, SCALE_GRACE_PERIOD, null, executor).join();
timeoutService.addTxn(SCOPE, STREAM, txData.getId(), txData.getVersion(), LEASE, txData.getMaxExecutionExpiryTime(), txData.getScaleGracePeriod());
Optional<Throwable> result = timeoutService.getTaskCompletionQueue().poll((long) (0.75 * LEASE), TimeUnit.MILLISECONDS);
Assert.assertNull(result);
TxnStatus status = streamStore.transactionStatus(SCOPE, STREAM, txData.getId(), null, executor).join();
Assert.assertEquals(TxnStatus.OPEN, status);
PingTxnStatus pingStatus = timeoutService.pingTxn(SCOPE, STREAM, txData.getId(), txData.getVersion(), LEASE);
Assert.assertEquals(PingTxnStatus.Status.OK, pingStatus.getStatus());
result = timeoutService.getTaskCompletionQueue().poll((long) (0.5 * LEASE), TimeUnit.MILLISECONDS);
Assert.assertNull(result);
status = streamStore.transactionStatus(SCOPE, STREAM, txData.getId(), null, executor).join();
Assert.assertEquals(TxnStatus.OPEN, status);
result = timeoutService.getTaskCompletionQueue().poll((long) (0.8 * LEASE), TimeUnit.MILLISECONDS);
Assert.assertNotNull(result);
status = streamStore.transactionStatus(SCOPE, STREAM, txData.getId(), null, executor).join();
Assert.assertEquals(TxnStatus.ABORTING, status);
}
use of io.pravega.controller.stream.api.grpc.v1.Controller.TxnId in project pravega by pravega.
the class TimeoutServiceTest method testPingOwnershipTransfer.
@Test(timeout = 30000)
public void testPingOwnershipTransfer() throws Exception {
StreamMetadataStore streamStore2 = StreamStoreFactory.createZKStore(client, executor);
HostControllerStore hostStore = HostStoreFactory.createInMemoryStore(HostMonitorConfigImpl.dummyConfig());
TaskMetadataStore taskMetadataStore = TaskStoreFactory.createStore(storeClient, executor);
ConnectionFactoryImpl connectionFactory = new ConnectionFactoryImpl(ClientConfig.builder().build());
@Cleanup StreamMetadataTasks streamMetadataTasks2 = new StreamMetadataTasks(streamStore2, hostStore, taskMetadataStore, new SegmentHelper(), executor, "2", connectionFactory, false, "");
@Cleanup StreamTransactionMetadataTasks streamTransactionMetadataTasks2 = new StreamTransactionMetadataTasks(streamStore2, hostStore, SegmentHelperMock.getSegmentHelperMock(), executor, "2", TimeoutServiceConfig.defaultConfig(), new LinkedBlockingQueue<>(5), connectionFactory, false, "");
streamTransactionMetadataTasks2.initializeStreamWriters("commitStream", new EventStreamWriterMock<>(), "abortStream", new EventStreamWriterMock<>());
// Create TimeoutService
TimerWheelTimeoutService timeoutService2 = (TimerWheelTimeoutService) streamTransactionMetadataTasks2.getTimeoutService();
ControllerService controllerService2 = new ControllerService(streamStore2, hostStore, streamMetadataTasks2, streamTransactionMetadataTasks2, new SegmentHelper(), executor, null);
TxnId txnId = controllerService.createTransaction(SCOPE, STREAM, LEASE, SCALE_GRACE_PERIOD).thenApply(x -> ModelHelper.decode(x.getKey())).join();
VersionedTransactionData txnData = streamStore.getTransactionData(SCOPE, STREAM, ModelHelper.encode(txnId), null, executor).join();
Assert.assertEquals(txnData.getVersion(), 0);
Optional<Throwable> result = timeoutService.getTaskCompletionQueue().poll((long) (0.75 * LEASE), TimeUnit.MILLISECONDS);
Assert.assertNull(result);
TxnState txnState = controllerService.checkTransactionStatus(SCOPE, STREAM, txnId).join();
Assert.assertEquals(TxnState.State.OPEN, txnState.getState());
// increasing lease -> total effective lease = 3 * LEASE
PingTxnStatus pingStatus = controllerService2.pingTransaction(SCOPE, STREAM, txnId, 2 * LEASE).join();
Assert.assertEquals(PingTxnStatus.Status.OK, pingStatus.getStatus());
txnData = streamStore.getTransactionData(SCOPE, STREAM, ModelHelper.encode(txnId), null, executor).join();
Assert.assertEquals(txnData.getVersion(), 1);
// timeoutService1 should believe that LEASE has expired and should get non empty completion tasks
result = timeoutService.getTaskCompletionQueue().poll((long) (1.3 * LEASE + RETRY_DELAY), TimeUnit.MILLISECONDS);
Assert.assertNotNull(result);
// the txn may have been attempted to be aborted by timeoutService1 but would have failed. So txn to remain open
txnState = controllerService.checkTransactionStatus(SCOPE, STREAM, txnId).join();
Assert.assertEquals(TxnState.State.OPEN, txnState.getState());
// timeoutService2 should continue to wait on lease expiry and should get empty completion tasks
result = timeoutService2.getTaskCompletionQueue().poll(0L, TimeUnit.MILLISECONDS);
Assert.assertNull(result);
result = timeoutService2.getTaskCompletionQueue().poll(2 * LEASE + RETRY_DELAY, TimeUnit.MILLISECONDS);
Assert.assertNotNull(result);
// now txn should have moved to aborting because timeoutservice2 has initiated abort
txnState = controllerService.checkTransactionStatus(SCOPE, STREAM, txnId).join();
Assert.assertEquals(TxnState.State.ABORTING, txnState.getState());
}
Aggregations