use of io.pravega.controller.store.stream.tables.Data in project pravega by pravega.
the class InMemoryStream method sealActiveTx.
@Override
CompletableFuture<Void> sealActiveTx(int epoch, UUID txId, boolean commit, ActiveTxnRecord txnRecord, int version) {
Preconditions.checkNotNull(txId);
CompletableFuture<Void> result = new CompletableFuture<>();
synchronized (txnsLock) {
if (!activeTxns.containsKey(txId.toString())) {
result.completeExceptionally(StoreException.create(StoreException.Type.DATA_NOT_FOUND, "Stream: " + getName() + " Transaction: " + txId.toString()));
} else {
activeTxns.compute(txId.toString(), (x, y) -> {
if (version != y.getVersion()) {
result.completeExceptionally(StoreException.create(StoreException.Type.WRITE_CONFLICT, "Stream: " + getName() + " Transaction: " + txId.toString()));
return y;
} else {
ActiveTxnRecord previous = ActiveTxnRecord.parse(y.getData());
ActiveTxnRecord updated = new ActiveTxnRecord(previous.getTxCreationTimestamp(), previous.getLeaseExpiryTime(), previous.getMaxExecutionExpiryTime(), previous.getScaleGracePeriod(), commit ? TxnStatus.COMMITTING : TxnStatus.ABORTING);
result.complete(null);
return new Data<>(updated.toByteArray(), y.getVersion() + 1);
}
});
}
}
return result;
}
use of io.pravega.controller.store.stream.tables.Data in project pravega by pravega.
the class PersistentStreamBase method addPartialHistoryRecord.
/**
* update history table if not already updated:
* fetch last record from history table.
* if eventTime is >= scale.scaleTimeStamp do nothing, else create record
*
* @return : future of history table offset for last entry
*/
private CompletableFuture<Void> addPartialHistoryRecord(final List<Integer> sealedSegments, final List<Integer> createdSegments, final int epoch) {
return getHistoryTable().thenCompose(historyTable -> {
final Optional<HistoryRecord> lastRecordOpt = HistoryRecord.readLatestRecord(historyTable.getData(), false);
// record in history table.
assert lastRecordOpt.isPresent();
final HistoryRecord lastRecord = lastRecordOpt.get();
// idempotent check
if (lastRecord.getEpoch() > epoch) {
boolean idempotent = lastRecord.isPartial() && lastRecord.getSegments().containsAll(createdSegments);
if (idempotent) {
HistoryRecord previous = HistoryRecord.fetchPrevious(lastRecord, historyTable.getData()).get();
idempotent = previous.getSegments().stream().noneMatch(createdSegments::contains);
}
if (idempotent) {
log.debug("{}/{} scale op for epoch {} - history record already added", scope, name, epoch);
return CompletableFuture.completedFuture(null);
} else {
log.warn("{}/{} scale op for epoch {}. Scale already completed.", scope, name, epoch);
throw new ScaleOperationExceptions.ScaleConditionInvalidException();
}
}
final List<Integer> newActiveSegments = getNewActiveSegments(createdSegments, sealedSegments, lastRecord);
byte[] updatedTable = TableHelper.addPartialRecordToHistoryTable(historyTable.getData(), newActiveSegments);
final Data<T> updated = new Data<>(updatedTable, historyTable.getVersion());
int latestEpoch = TableHelper.getLatestEpoch(updatedTable).getKey();
return createNewEpoch(latestEpoch).thenCompose(v -> updateHistoryTable(updated)).whenComplete((r, e) -> {
if (e == null) {
log.debug("{}/{} scale op for epoch {}. Creating new epoch and updating history table.", scope, name, epoch);
} else {
log.warn("{}/{} scale op for epoch {}. Failed to update history table. {}", scope, name, epoch, e.getClass().getName());
}
});
});
}
use of io.pravega.controller.store.stream.tables.Data in project pravega by pravega.
the class PersistentStreamBase method completeScale.
private CompletableFuture<Void> completeScale(final long scaleTimestamp, final Map<Integer, Long> sealedSegments, final int activeEpoch, final List<Integer> newSegments) {
return getHistoryTable().thenCompose(historyTable -> {
final Optional<HistoryRecord> lastRecordOpt = HistoryRecord.readLatestRecord(historyTable.getData(), false);
assert lastRecordOpt.isPresent();
final HistoryRecord lastRecord = lastRecordOpt.get();
// idempotent check
if (!lastRecord.isPartial()) {
if (lastRecord.getSegments().stream().noneMatch(sealedSegments::containsKey) && newSegments.stream().allMatch(x -> lastRecord.getSegments().contains(x))) {
log.debug("{}/{} scale already completed for epoch {}.", scope, name, activeEpoch);
return CompletableFuture.completedFuture(null);
} else {
log.debug("{}/{} scale complete attempt invalid for epoch {}.", scope, name, activeEpoch);
throw new ScaleOperationExceptions.ScaleConditionInvalidException();
}
}
long scaleEventTime = Math.max(System.currentTimeMillis(), scaleTimestamp);
final Optional<HistoryRecord> previousOpt = HistoryRecord.fetchPrevious(lastRecord, historyTable.getData());
if (previousOpt.isPresent()) {
// To ensure that we always have ascending time in history records irrespective of controller clock mismatches.
scaleEventTime = Math.max(scaleEventTime, previousOpt.get().getScaleTime() + 1);
if (previousOpt.get().getEpoch() > activeEpoch) {
throw new ScaleOperationExceptions.ScaleConditionInvalidException();
}
}
byte[] updatedTable = TableHelper.completePartialRecordInHistoryTable(historyTable.getData(), lastRecord, scaleEventTime);
final Data<T> updated = new Data<>(updatedTable, historyTable.getVersion());
final HistoryRecord newRecord = HistoryRecord.readLatestRecord(updatedTable, false).get();
return addSealedSegmentsToRecord(sealedSegments).thenCompose(x -> addIndexRecord(newRecord)).thenCompose(x -> updateHistoryTable(updated)).thenCompose(x -> Futures.toVoid(updateState(State.ACTIVE))).whenComplete((r, e) -> {
if (e != null) {
log.warn("{}/{} attempt to complete scale for epoch {}. {}", scope, name, activeEpoch, e.getClass().getName());
} else {
log.debug("{}/{} scale complete, index and history tables updated for epoch {}.", scope, name, activeEpoch);
}
});
});
}
use of io.pravega.controller.store.stream.tables.Data in project pravega by pravega.
the class PersistentStreamBase method pingTransaction.
@Override
public CompletableFuture<VersionedTransactionData> pingTransaction(final VersionedTransactionData txnData, final long lease) {
// Update txn record with new lease value and return versioned tx data.
final int epoch = txnData.getEpoch();
final UUID txnId = txnData.getId();
final int version = txnData.getVersion();
final long creationTime = txnData.getCreationTime();
final long maxExecutionExpiryTime = txnData.getMaxExecutionExpiryTime();
final long scaleGracePeriod = txnData.getScaleGracePeriod();
final TxnStatus status = txnData.getStatus();
final ActiveTxnRecord newData = new ActiveTxnRecord(creationTime, System.currentTimeMillis() + lease, maxExecutionExpiryTime, scaleGracePeriod, status);
final Data<Integer> data = new Data<>(newData.toByteArray(), version);
return updateActiveTx(epoch, txnId, data).thenApply(x -> new VersionedTransactionData(epoch, txnId, version + 1, status, creationTime, maxExecutionExpiryTime, scaleGracePeriod));
}
use of io.pravega.controller.store.stream.tables.Data in project pravega by pravega.
the class ZKStream method sealActiveTx.
@Override
CompletableFuture<Void> sealActiveTx(final int epoch, final UUID txId, final boolean commit, final ActiveTxnRecord previous, final int version) {
final String activePath = getActiveTxPath(epoch, txId.toString());
final ActiveTxnRecord updated = new ActiveTxnRecord(previous.getTxCreationTimestamp(), previous.getLeaseExpiryTime(), previous.getMaxExecutionExpiryTime(), previous.getScaleGracePeriod(), commit ? TxnStatus.COMMITTING : TxnStatus.ABORTING);
final Data<Integer> data = new Data<>(updated.toByteArray(), version);
return store.setData(activePath, data).thenApply(x -> cache.invalidateCache(activePath)).whenComplete((r, e) -> cache.invalidateCache(activePath));
}
Aggregations