Josh McKenzie created CASSANDRA-15362:
-----------------------------------------

             Summary: Add a resumable commit log reader for CDC consumption
                 Key: CASSANDRA-15362
                 URL: https://issues.apache.org/jira/browse/CASSANDRA-15362
             Project: Cassandra
          Issue Type: New Feature
          Components: Feature/Change Data Capture
            Reporter: Josh McKenzie
            Assignee: Josh McKenzie


[Link to wip 
branch|https://github.com/apache/cassandra/compare/trunk...josh-mckenzie:resumable_clreader]

This ticket builds upon and supersedes CASSANDRA-15196.

One of the initial shortcomings of CDC after its initial implementation is 
that, upon update of the related CDC index file if parsing an active segment, a 
user needs to re-scan files (specifically compressed or encrypted) as they're 
written and discard duplicate mutations. The primary push of this patch is to 
introduce a new class, the 
[ResumableCommitLogReader|https://github.com/josh-mckenzie/cassandra/blob/resumable_clreader/src/java/org/apache/cassandra/db/commitlog/ResumableCommitLogReader.java#L35-L53]
 that greatly simplifies and optimizes repeated reads from a commitlog file 
being actively written underneath you.

The primary API consists of:
{noformat}
public void readPartial(int readLimit) throws IOException;
public void readToCompletion() throws IOException
public void close(); // is AutoCloseable
{noformat}
An example of the usage of this can be seen in the changed standard read 
implementation within the 
[CommitLogReader|https://github.com/josh-mckenzie/cassandra/blob/resumable_clreader/src/java/org/apache/cassandra/db/commitlog/CommitLogReader.java#L129-L134]

 The simple "read straight through" case:
{noformat}
try(ResumableCommitLogReader resumableReader = new 
ResumableCommitLogReader(file, handler, minPosition, mutationLimit, 
tolerateTruncation))
{
    resumableReader.readToCompletion();
}
{noformat}
The more complex "resume reading" case:
{noformat}
try(ResumableCommitLogReader resumableReader = new 
ResumableCommitLogReader(file, handler, minPosition, mutationLimit, 
tolerateTruncation))
{
    while(!parseCDCCompletionStatus(cdcIndexFile))
    {
        Thread.sleep(10000);
        rr.readPartial(parseCDCOffset(cdcIndexFile));
    }
}
{noformat}
A brief enumeration of some of the most obvious pros and cons of this current 
design and implementation:

Pros:
 * Very simple external user interface
 * All the complexity of resuming, RAR seeking, RAR re-creation hidden from 
end-users
 * Minimal risk to existing CL reading code (isPartial() path very separate 
from default in computeNext())

Cons:
 * Creation of a resumable reader object required on each new segment file read 
(trivially fixable if a concern)
 * Added complexity burden on computeNext of snapshotting Segmenter state and 
reverting: 
[reference|https://github.com/josh-mckenzie/cassandra/blob/resumable_clreader/src/java/org/apache/cassandra/db/commitlog/CommitLogSegmentReader.java#L92]
 * Added complexity burden on computeNext of Sentinel state and resumability of 
iterator
 * Generally breaking the "one way street" paradigm of iterators (biggest 
concern to me atm)
 * Philosophical "add complexity to C* code-base to ease 'external tool' users" 
debate

One other meta trade-off: this design puts the ResumableCommitLogReader at the 
center of the Commit log reading design; most other related classes now take 
that as an argument and it serves as both our parent logic coordinator + data 
holder. The obvious benefit of this design is it's a lot easier to pass things 
around and you have to grok really one thing to know what data and context you 
have to work with. The obvious downside is risk of calcification and lack of 
modularity plus the need to construct on any read. It's trivial to unwind that 
and keep CommitLogReader et al totally unaware of the resumable reader if we're 
so inclined.

Anyway - figured I'd toss this ticket up here so it's visible to people that 
some of this is in flight. I've spoken with several engineers from different 
companies that are using CDC at scale and have backported things to 3.0 or 3.11 
(CASSANDRA-12148 for instance), so having this code here visible may be of use 
to someone even in it's not quite yet polished or tested state.

There are some obvious counter-designs (add a skipToNextSyncMarker call to 
Segmenter for example, or break out of iterator paradigm entirely and have an 
API for {{computeNextSegment}} or {{revertToLastKnownSegment}} and just walk 
across SyncSegments internal to a non-iterator based class), etc. I prefer not 
to rewrite things _too_ much when working on them (and we already have some 
complexity in {{SegmentReader.computeNext}} coming into this), and I'm getting 
more partial to the "keep things as stupidly simple for external users as 
possible" approach to APIs as I age so that's why my initial cut at this takes 
on the burden of this complexity internally to keep the consumption braindead 
easy.

Currently passes CommitLogReader + new ResumableCommitLogReader tests; haven't 
run it through the entire gamut yet. Figured it'd be worth kicking it out here 
to see if anyone has feedback that significantly alters the design before going 
into the full gauntlet of tests.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to