Design a Compact Columnar File Format
Jump TradingSoftware Engineer · Technical ScreenLast updated
Design an append-friendly, compact columnar file format optimized for fast analytical scans over tabular financial market data (e.g., tick feeds or order book snapshots). Define the on-disk binary layout, reader/writer abstractions, serialization rules, and operational trade-offs.
Scenario
High-frequency trading research and backtesting engines ingest terabytes of tick-level order book events daily. Row-oriented storage (like CSV or line-delimited JSON) causes excessive I/O when strategies query only a subset of fields (e.g., just timestamp and mid_price across billions of records).
Design a compact, self-contained, read-heavy columnar file format (a simplified Parquet-like format) along with the class interfaces for writing and reading data.
Requirements
Functional
- Data Model: Support strongly-typed tabular data with fixed-width primitive types (
INT32,INT64,FLOAT64) and nullability. - Chunking / Page Layout: Support dividing rows into horizontal "Row Groups" (e.g., 64K to 1M rows per group), with each row group storing columnar data chunks contiguously.
- Projection & Predicate Pushdown: The read API must allow reading only a subset of columns without decoding unused columns, and allow skipping row groups using column-level chunk metadata (min/max bounds).
- Self-Describing: The file must contain a schema and metadata footer so it can be parsed without external catalogs.
Non-Functional & Layout Constraints
- Fixed-size header and a tail-end metadata footer (with a fixed-size footer length and magic bytes at the very end of the file).
- Minimize random I/O: Contiguous sequential reads within a requested column chunk.
- Compression: Support pluggable block compression (e.g., Raw, Snappy/LZ4, or Bit-packing/Delta encoding for timestamps).
Expected Deliverables
- Binary Layout Specification: Define the exact byte-level layout (magic bytes, headers, row groups, column chunks, data pages, dictionary pages, and footer metadata).
- Class Interfaces: Define explicit interfaces in Python or C++ pseudo-code for
ColumnarFileWriterandColumnarFileReader, demonstrating how chunks are buffered, flushed, and projected. - Invariants & Edge Cases: Detail file corruption handling, partial writes, all-null columns, and variable row group sizes.
- Testing Strategy: Describe how you would validate correctness, zero-copy read paths, and encoding regressions.
Hints
Hint 1
Placing the metadata footer and its size at the end of the file allows single-pass streaming writes without needing to seek back to update a header.
Hint 2
For columnar projection, store the byte offset and compressed/uncompressed byte length of each column chunk in the footer index.
Hint 3
Consider dictionary encoding and run-length encoding (RLE) for repeated values or null-indicator bitmasks to maximize compression efficiency.
Follow-up questions
- How would you support variable-length strings or binary payloads (e.g., order IDs or execution reports) without losing predictable chunk offsets?
- If your trading strategies run on NVMe drives with direct I/O (`O_DIRECT`), what alignment requirements does that impose on your page boundaries and row group layouts?
- How would you evolve the file schema over time (e.g., adding an optional column) while maintaining backward and forward compatibility?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.