Skip to content

CEP-45: Lost witness marker race#4892

Open
bdeggleston wants to merge 2 commits into
apache:cep-45-mutation-trackingfrom
bdeggleston:C21443-lost-witness-all
Open

CEP-45: Lost witness marker race#4892
bdeggleston wants to merge 2 commits into
apache:cep-45-mutation-trackingfrom
bdeggleston:C21443-lost-witness-all

Conversation

@bdeggleston

Copy link
Copy Markdown
Member

Don't truncate journal segments until witnessed offsets they contain are flushed. Also moves MutationTrackingService startup to after the commit log is replayed

Thanks for sending a pull request! Here are some tips if you're new here:

  • Ensure you have added or run the appropriate tests for your PR.
  • Be sure to keep the PR description updated to reflect all changes.
  • Write your PR title to summarize what this PR proposes.
  • If possible, provide a concise example to reproduce the issue for a faster review.
  • Read our contributor guidelines
  • If you're making a documentation change, see our guide to documentation contribution

Commit messages should follow the following format:

<One sentence description, usually Jira title or CHANGES.txt summary>

<Optional lengthier description (context on patch)>

patch by <Authors>; reviewed by <Reviewers> for CASSANDRA-#####

Co-authored-by: Name1 <email1>
Co-authored-by: Name2 <email2>

The Cassandra Jira

Don't truncate journal segments until witnessed offsets they contain are
flushed. Also moves MutationTrackingService startup to after the commit
log is replayed
@bdeggleston bdeggleston requested a review from frankgh June 17, 2026 20:17

@frankgh frankgh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a couple of comments, but the patch looks good in general.

);
pendingClearReplaySize = Metrics.register(
factory.createMetricName("PendingClearReplaySize"),
() -> MutationJournal.instance().pendingClearReplaySize()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to worry about the case where MT is disabled and maybe handle the IllegalStateException thrown when the instance is null?

// opaque / immutable list of segments that we should clear the needs-replay flag on
public static class PendingClearReplay
{
private ImmutableSet<Long> segments;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: can we make this final?

Suggested change
private ImmutableSet<Long> segments;
private final mmutableSet<Long> segments;


private void shutdownBlocking() throws InterruptedException
{
ClusterMetadataService.instance().log().removeListener(tcmListener);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we conditionally remove the listener here, only if the service was started?

Suggested change
boolean wasStarted;
synchronized (this)
{
wasStarted = started;
if (wasStarted)
ClusterMetadataService.instance().log().removeListener(tcmListener);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally, we need to synchronize for access to the started volatile variable.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it's just a noop if the tcmListener isn't registered.

executor.awaitTermination(1, TimeUnit.MINUTES);
// attempt to persist offsets and mark segments as
// not needing replay one last time before shutdown
if (started)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (started)
if (wasStarted)

ClusterMetadataService.instance().log().removeListener(tcmListener);
activeReconciler.shutdownBlocking();
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log if we fail to shutdown here?

Suggested change
executor.awaitTermination(1, TimeUnit.MINUTES);
if (!executor.awaitTermination(1, TimeUnit.MINUTES))
{
logger.warn("Mutation tracking executor did not terminate within 1 minute; forcing shutdown");
}

* To improve startup, we periodically save our view of mutation ids that we've witnessed to disk as part of this
* class. Any ids witnessed since the last time this class was run are reconstructed by replaying the journal.
*
* However, if an sstable is flushed is after the most recent LogStatePersister run, AND it marks a segment as no

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT:

Suggested change
* However, if an sstable is flushed is after the most recent LogStatePersister run, AND it marks a segment as no
* However, if an sstable is flushed after the most recent LogStatePersister run, AND it marks a segment as no

TableMetadata table = Schema.instance.getTableMetadata(keyspaceName, tableName);
DecoratedKey dk = Murmur3Partitioner.instance.decorateKey(ByteBufferUtil.bytes(key));
MutationSummary summary = MutationTrackingService.instance().createSummaryForKey(dk, table.id, false);
if (summary.size() == 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT:

Suggested change
if (summary.size() == 0)
if (summary.isEmpty())

@frankgh frankgh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 looks good to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants