Atlassian uses cookies to improve your browsing experience, perform analytics and research, and conduct advertising. Accept all cookies to indicate that you agree to our use of cookies on your device. Atlassian cookies and tracking notice, (opens new window)
Navigating through the implementation details is rather daunting, as there are four implementations of JournalWriter:
SegmentedJournalWriter, given out via SegmentedJournalWriter.openWriter()
MappableJournalSegmentWriter, used by JournalSegment, which forwards requests to one of
FileChannelJournalSegmentWriter, used for buffered access
MappedJournalSegmentWriter, used for memory-mapped access
The same holds true for JournalReader and makes navigating the codebase rather strange, as it would seem those four are equivalent, but they are not.
First, SegmentedJournalWriter is the only real implementation, hence it should be hosting the interface definition and be a final class.
Second, we should have an abstract class named JournalSegmentWriter, which holds the API contract and code shared between FileChannelJournalSegmentWriter and MappedJournalSegmentWriter.
Third, MappableJournalSegmentWriter seems to only be a lifecycle helper to deal with closing the channel, indexing and switching (potentially) mapping the file into memory. I think that class should just get integrated into JournalSegment.
We'll retain the interfaces and hide the implementations.
Robert Varga March 10, 2024 at 9:44 PM
So MappedJournalSegment{Reader,Writer} are really just delegators, forwarding to the current implementation and used by SegmentedJournal{Reader,Writer}. Access to these is protected through reference counting – i.e. we always acquire/release the underlying segment before getting the writer or creating a reader.
The lifecycle is not really what we want, as reader's implementation seems to be subservient to the reference count and hence we need to track readers only to be able to switch their implementation – essentially to cater to a non-existing edge case where the refcount drops to zero while there is a reader open.
This is not what we want to do: we really want the mapping to remain intact for as long as there are references to it. As such, we really need to expand the internal interface to have an acquireWriter() and acquireNewReader() – which will internalize refcounting and just give out the requested object, which will then remain alive until it is relinquished.
Navigating through the implementation details is rather daunting, as there are four implementations of JournalWriter:
SegmentedJournalWriter, given out via SegmentedJournalWriter.openWriter()
MappableJournalSegmentWriter, used by JournalSegment, which forwards requests to one of
FileChannelJournalSegmentWriter, used for buffered access
MappedJournalSegmentWriter, used for memory-mapped access
The same holds true for JournalReader and makes navigating the codebase rather strange, as it would seem those four are equivalent, but they are not.
First, SegmentedJournalWriter is the only real implementation, hence it should be hosting the interface definition and be a final class.
Second, we should have an abstract class named JournalSegmentWriter, which holds the API contract and code shared between FileChannelJournalSegmentWriter and MappedJournalSegmentWriter.
Third, MappableJournalSegmentWriter seems to only be a lifecycle helper to deal with closing the channel, indexing and switching (potentially) mapping the file into memory. I think that class should just get integrated into JournalSegment.