- /**
- * Transform frontend metadata for a particular client into its {@link LeaderFrontendState} counterpart.
- *
- * @param shard parent shard
- * @return Leader frontend state
- */
- @Nonnull LeaderFrontendState toLeaderState(@Nonnull final Shard shard) {
- // Note: we have to make sure to *copy* all current state and not leak any views, otherwise leader/follower
- // interactions would get intertwined leading to inconsistencies.
- final Map<LocalHistoryIdentifier, LocalFrontendHistory> histories = new HashMap<>();
- for (FrontendHistoryMetadataBuilder e : currentHistories.values()) {
- if (e.getIdentifier().getHistoryId() != 0) {
- final AbstractFrontendHistory state = e.toLeaderState(shard);
- Verify.verify(state instanceof LocalFrontendHistory);
- histories.put(e.getIdentifier(), (LocalFrontendHistory) state);
+ @Override
+ void onTransactionCommitted(final TransactionIdentifier txId) {
+ final FrontendHistoryMetadataBuilder history = getHistory(txId);
+ if (history != null) {
+ history.onTransactionCommitted(txId);
+ LOG.debug("{}: Committed transaction {}", shardName(), txId);
+ } else {
+ LOG.warn("{}: Unknown history for commited transaction {}, ignoring", shardName(), txId);
+ }
+ }
+
+ @Override
+ void onTransactionPurged(final TransactionIdentifier txId) {
+ final FrontendHistoryMetadataBuilder history = getHistory(txId);
+ if (history != null) {
+ history.onTransactionPurged(txId);
+ LOG.debug("{}: Purged transaction {}", shardName(), txId);
+ } else {
+ LOG.warn("{}: Unknown history for purged transaction {}, ignoring", shardName(), txId);
+ }
+ }
+
+ @Override
+ LeaderFrontendState toLeaderState(final Shard shard) {
+ // Note: we have to make sure to *copy* all current state and not leak any views, otherwise leader/follower
+ // interactions would get intertwined leading to inconsistencies.
+ final Map<LocalHistoryIdentifier, LocalFrontendHistory> histories = new HashMap<>();
+ for (FrontendHistoryMetadataBuilder e : currentHistories.values()) {
+ if (e.getIdentifier().getHistoryId() != 0) {
+ final AbstractFrontendHistory state = e.toLeaderState(shard);
+ verify(state instanceof LocalFrontendHistory, "Unexpected state %s", state);
+ histories.put(e.getIdentifier(), (LocalFrontendHistory) state);
+ }
+ }
+
+ final AbstractFrontendHistory singleHistory;
+ final FrontendHistoryMetadataBuilder singleHistoryMeta = currentHistories.get(
+ new LocalHistoryIdentifier(getIdentifier(), 0));
+ if (singleHistoryMeta == null) {
+ final ShardDataTree tree = shard.getDataStore();
+ singleHistory = StandaloneFrontendHistory.create(shard.persistenceId(), getIdentifier(), tree);
+ } else {
+ singleHistory = singleHistoryMeta.toLeaderState(shard);
+ }
+
+ return new LeaderFrontendState.Enabled(shard.persistenceId(), getIdentifier(), shard.getDataStore(),
+ purgedHistories.copy(), singleHistory, histories);
+ }
+
+ @Override
+ ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return super.addToStringAttributes(helper).add("current", currentHistories).add("purged", purgedHistories);
+ }
+
+ private FrontendHistoryMetadataBuilder getHistory(final TransactionIdentifier txId) {
+ LocalHistoryIdentifier historyId = txId.getHistoryId();
+ if (historyId.getHistoryId() == 0 && historyId.getCookie() != 0) {
+ // We are pre-creating the history for free-standing transactions with a zero cookie, hence our lookup
+ // needs to account for that.
+ LOG.debug("{}: looking up {} instead of {}", shardName(), standaloneId, historyId);
+ historyId = standaloneId;