- Decision Index
- CB-FN-101 Bytes and BytesStore API Split
- CB-FN-102 Elastic Buffer Growth within Real Capacity
- CB-FN-103 Atomic Operations on Off-Heap BytesStore
- CB-FN-104 Zero-Copy Slicing and View Semantics
- CB-NF-P-201 Encoding, Alignment and Pooling Strategy
- CB-DOC-101 Documentation Structure and Diagrams
This file captures component-specific architectural and design decisions for Chronicle Bytes.
Identifiers follow the Nine-Box pattern <Scope>-<Tag>-NNN described in AGENTS.md.
Numbers are unique within the CB scope, and decisions cross-reference the formal requirements in
project-requirements.adoc and the wider architecture documentation.
- Context
-
-
Chronicle Bytes must support a range of storage backends (on-heap arrays, off-heap native memory, memory-mapped files) without duplicating logic for cursor handling and API behaviour.
-
Higher level libraries (Wire, Queue, Map, Values) expect a consistent, low-level byte-access surface that hides storage details but exposes precise control over read and write positions.
-
Requirements
CB-FN-001andCB-FN-002inproject-requirements.adocdefine the need for separate cursors and a backing store abstraction.
-
- Decision Statement
-
-
Chronicle Bytes defines
BytesStore<B, U>as the primary representation of the underlying memory region, andBytes<U>as a mutable view over aBytesStorewith independent read and write cursors. -
Implementations of
BytesStorecover on-heap, direct off-heap and memory-mapped storage, while allBytesimplementations present the same cursor-based API.
-
- Alternatives Considered
- * Single class combining storage and cursors
-
-
Pros: fewer types for new users to learn.
-
Cons: couples storage and view concerns; makes sharing storage between multiple views and backends harder; reduces flexibility for off-heap specific behaviour.
-
- * Java NIO
ByteBufferas the canonical API -
-
Pros: standard JDK type, familiar to many developers.
-
Cons: single cursor model with
flipsemantics; less suitable for separate read and write positions; less control over off-heap and mapped memory specifics.
-
- Rationale for Decision
-
-
The split between
BytesStoreandBytesprovides a stable API that can evolve storage strategies without changing callers. -
Separate read and write cursors match Chronicle usage patterns (for example, queue appenders and tailers) and simplify the implementation of zero-copy views.
-
Higher-level components can work with
Bytesinterfaces without needing to understand whether memory is on- or off-heap.
-
- Impact & Consequences
-
-
Callers must acquire a
Bytesview from aBytesStorerather than manipulating storage directly. -
Sharing the same
BytesStorebetween multipleBytesviews becomes a first-class pattern and underpins many memory-saving features. -
Tests and documentation use the
CB-FN-001andCB-FN-002identifiers when referring to these guarantees.
-
- Notes/Links
- Context
-
-
Many Chronicle workloads write variable-length records and cannot know the final buffer size in advance.
-
Unbounded growth risks exhausting memory or breaking latency guarantees when large reallocations occur.
-
Requirement
CB-FN-003inproject-requirements.adocdefines transparent growth up to a documented real capacity.
-
- Decision Statement
-
-
Chronicle Bytes provides elastic
Bytesvariants (for example created viaBytes.allocateElasticDirect()) that grow transparently up to the maximum real capacity advertised by theirBytesStore. -
When growth is required, the implementation allocates a larger underlying
BytesStore, copies existing data and updates the view, but never exceeds the configured real capacity.
-
- Alternatives Considered
- * Fully fixed-size buffers only
-
-
Pros: predictable memory usage, no growth stalls.
-
Cons: requires callers to over-estimate sizes or implement their own growth strategies; harder to use in exploratory or heterogeneous workloads.
-
- * Unbounded growth by default
-
-
Pros: simplest behaviour from an API perspective.
-
Cons: can lead to unpredictable memory usage and significant, unbounded copy costs; difficult to enforce operational limits.
-
- Rationale for Decision
-
-
Elastic growth up to a known real capacity balances ergonomics with predictable resource usage.
-
A documented capacity limit makes it possible to reason about worst-case allocation costs and to test growth behaviour in micro-benchmarks.
-
- Impact & Consequences
-
-
Callers should still pre-size buffers for predictable latency on critical paths, but can rely on elastic behaviour in less critical code.
-
Operational documentation and benchmarks (for example those referenced by
CB-NF-P-003andCB-NF-P-008) exercise and validate growth behaviour.
-
- Notes/Links
- Context
-
-
Low-latency components require atomic operations (compare-and-swap, get-and-add) directly on off-heap memory for lock-free algorithms and shared state.
-
Requirement
CB-FN-004inproject-requirements.adocmandates such operations on 32-bit and 64-bit primitives stored off-heap. -
Relying solely on heap-based
AtomicLongand similar classes introduces additional indirection and garbage collection overhead.
-
- Decision Statement
-
-
Chronicle Bytes exposes atomic operations on
BytesStoreinstances that map directly onto the underlying off-heap addresses, using the minimum necessary JVM and CPU primitives. -
These operations are documented as safe to call concurrently from multiple threads when used on properly aligned locations.
-
- Alternatives Considered
- * Only support atomic operations via heap-based
Atomic*wrappers -
-
Pros: simpler implementation, uses built-in JDK types.
-
Cons: additional indirection and allocation; does not work directly on off-heap or mapped memory; weaker fit for Chronicle workloads.
-
- * Provide no atomic operations at the Bytes layer
-
-
Pros: keeps the API smaller and delegates concurrency to higher layers.
-
Cons: forces each higher layer to reinvent low-level CAS logic; increases the risk of inconsistent or unsafe implementations.
-
- Rationale for Decision
-
-
Centralising atomic operations in Chronicle Bytes ensures consistent, well-tested behaviour across the stack.
-
Direct off-heap atomics align with the performance expectations of Chronicle Queue, Map, and Wire.
-
- Impact & Consequences
-
-
Callers must respect documentation around alignment and memory ordering when using atomic operations.
-
Benchmarks and tests referenced by
CB-NF-P-005verify performance characteristics under contention.
-
- Notes/Links
- Context
-
-
Applications often need to work with subranges of a larger byte region (for example individual messages in a file or buffer) without copying data.
-
Requirement
CB-FN-006inproject-requirements.adoccalls for slice views that share underlying storage while maintaining independent cursors. -
Incorrect handling of slices can easily lead to use-after-free errors or confusing lifetime semantics.
-
- Decision Statement
-
-
Chronicle Bytes supports creation of lightweight slice views (for example via
bytesForRead,bytesForWriteandslice) that do not copy underlying data. -
Slice views hold a reference to the original
BytesStoreand maintain their own read and write cursors constrained to the slice bounds. -
Lifetime and ownership rules are documented so that releasing the backing store invalidates all dependent slices.
-
- Alternatives Considered
- * Always copy data when creating sub-buffers
-
-
Pros: simplest ownership model, eliminates shared-storage lifetime concerns.
-
Cons: increases allocation and copy costs; unsuitable for high-throughput, low-latency use cases.
-
- * Expose raw offsets only and require callers to manage their own views
-
-
Pros: minimal API surface.
-
Cons: high risk of off-by-one and bounds errors; increases complexity in every caller.
-
- Rationale for Decision
-
-
Zero-copy slices provide the performance characteristics required by downstream libraries while keeping the ownership rules enforceable and documentable in one place.
-
Centralising slice semantics in Chronicle Bytes reduces repeated, ad-hoc slice logic in dependent projects.
-
- Impact & Consequences
-
-
Callers must treat slices as views rather than independent buffers and avoid releasing the underlying
BytesStorewhile slices are in use. -
Tests in the Chronicle Bytes module cover slice behaviour, bounds enforcement and sharing of underlying addresses.
-
- Notes/Links
- Context
-
-
Chronicle Bytes is responsible for efficient text encoding, numeric alignment and buffer pooling, which together have a large impact on throughput and latency.
-
Requirements
CB-FN-009..CB-FN-014and theCB-NF-P-*entries inproject-requirements.adocdefine expectations around encoding performance, alignment and pooling overheads. -
Changes in these areas can subtly affect higher-level protocols and applications relying on predictable performance envelopes.
-
- Decision Statement
-
-
Chronicle Bytes standardises on a small set of encodings (including UTF-8, ISO-8859-1 and US-ASCII) with dedicated, low-allocation paths that are validated by benchmarks and tests.
-
Alignment-sensitive operations are implemented to respect platform requirements, especially for off-heap and memory-mapped stores, and are reflected in dedicated aligned access methods.
-
A configurable pooling mechanism is provided for
Bytesinstances, allowing frequent allocate-and-release cycles to be served from pools rather than fresh allocations, within the limits described in the requirements.
-
- Alternatives Considered
- * Treat encoding, alignment and pooling as purely caller concerns
-
-
Pros: smaller core library surface.
-
Cons: leads to inconsistent patterns across projects; duplicates work; higher risk of performance regressions and subtle bugs.
-
- * Support many encodings and pooling strategies without clear defaults
-
-
Pros: flexibility for niche use cases.
-
Cons: harder to reason about performance; more complex configuration and testing matrix.
-
- Rationale for Decision
-
-
A focused, well-tested core of supported encodings and pooling behaviours offers predictable performance while still allowing specialised callers to plug in alternatives where needed.
-
Capturing these decisions in one place keeps project requirements, benchmarks and implementation aligned.
-
- Impact & Consequences
-
-
Performance-sensitive code should use the documented encodings and pooling mechanisms rather than bespoke conversions.
-
Benchmark targets in
project-requirements.adoc(for exampleCB-NF-P-006..CB-NF-P-009) are treated as gating checks for significant changes in these areas.
-
- Notes/Links
- Context
-
-
Chronicle Bytes documentation must support both high-level architecture work (for example ARCH_TODO) and day-to-day development.
-
Requirements, decisions and usage guides were historically scattered, with few diagrams or explicit mapping between files.
-
Documentation obligations
CB-DOC-001..CB-DOC-007require British English, traceability to requirements, and clear explanations of lifecycle and threading semantics.
-
- Decision Statement
-
-
Chronicle Bytes standardises on a three-layer documentation structure:
-
project-requirements.adocas the canonical catalogue of Nine-Box requirements (CB-FN-,CB-NF-,CB-DOC-,CB-TEST-,CB-RISK-*); -
architecture-overview.adoc,memory-management.adoc,wire-integration.adoc, and related guides as narrative explanations and diagrams that reference those requirements via anchors; -
functional-requirements.adoc,testing-strategy.adoc,security-review.adocand similar files as thematic views (for example functional behaviour, tests, security) built on top of the canonical catalogue.
-
-
Diagrams are provided in ASCII art and
mermaidblocks where helpful to illustrate component relationships and lifecycles, while remaining optional for text-only environments.
-
- Alternatives Considered
- * Single monolithic architecture document containing requirements, decisions, diagrams and usage examples
-
-
Pros: one file to read.
-
Cons: becomes large and hard to navigate; difficult to reuse across cross-module initiatives like ARCH_TODO.
-
- * Minimal documentation limited to Javadoc and README only
-
-
Pros: low maintenance overhead.
-
Cons: insufficient for external architecture work, compliance objectives, and cross-module reasoning.
-
- Rationale for Decision
-
-
Separating canonical requirements from narrative guides allows requirements to be audited and evolved independently of tutorial material.
-
Thematic documents (functional requirements, testing strategy, security review, memory management) make it easier for specialists to find relevant information without reading everything.
-
Lightweight diagrams help convey relationships (for example between
BytesandBytesStore, or reference-counting states) without imposing a specific diagramming tool on all users.
-
- Impact & Consequences
-
-
All new documentation should reference requirement IDs where applicable and follow the layering above.
-
Future diagrams should prefer text-friendly formats (ASCII art or
mermaidin code blocks) and remain in-sync with the code and requirements they represent. -
Cross-module documentation (for example links to Chronicle Wire or Chronicle Queue) should use relative paths so that navigation works within the repository.
-
- Notes/Links