cli: add Apache Arrow IPC support to mcap convert - #1749
Conversation
Co-authored-by: Adrian Macneil <adrian@foxglove.dev>
There was a problem hiding this comment.
Solid converter, tests round-trip through a real StreamReader which is the right way to prove spec compliance. A few things to settle, mostly inline.
One risk that doesn't pin to a single line: Arrow's time handling fails hard mid-stream (null, negative, or out-of-u64 values are errors). Unlike the bag/db3 paths, a bad value deep in a large file aborts after the output .mcap has already been partially written and never finalized, leaving a truncated file at the output path. Worth confirming that's acceptable, or cleaning up the output on error.
Open question on sequencing: this rides on #1748 for the arrow encoding registration — see the docs comment. Draft is the right state until that lands.
|
|
||
| <!-- cspell: enable --> | ||
|
|
||
| Each input row becomes one MCAP message (an [Arrow IPC](https://arrow.apache.org/docs/format/Columnar.html#serialization-and-interprocess-communication-ipc) encapsulated `RecordBatch`) on a single channel using the [`arrow`](https://mcap.dev/spec/registry#arrow) message and schema encodings. Dictionary-encoded columns are hydrated to their value type, as required by the encoding. |
There was a problem hiding this comment.
Co-authored-by: Adrian Macneil <adrian@foxglove.dev>
- Derive default topic from the original input, not the materialized remote temp path - Drop the undocumented .arrows extension - Only read timestamps from each message's leader row so nulls in non-leader rows of a batched group don't fail conversion - Remove a partially written output file when conversion fails - Warn when arrow-only flags are passed for a non-arrow input Co-authored-by: Adrian Macneil <adrian@foxglove.dev>
Co-authored-by: Adrian Macneil <adrian@foxglove.dev>
Co-authored-by: Adrian Macneil <adrian@foxglove.dev>
There was a problem hiding this comment.
New commit closes last round's decoder-reuse coverage gap — arrow_json_reuses_cached_decoder_across_messages runs two messages through one JsonTranscoders and asserts the second decodes via the cached decoder. 👍
Still gated on #1748: files written with the arrow encoding (and the registry#arrow doc link) can't land until that registry entry is published. Open thread on cli.md tracks it — draft is the right state until then.
Summary
Adds Apache Arrow support to the Rust CLI for the
arrowmessage/schema encodings proposed in #1748, on both the write and read paths:mcap convertreads an Arrow IPC file or stream (.arrow,.feather,.ipc,.arrows) and writes a single channel using thearrowmessage encoding, with the Arrow IPCSchemastored once in the Schema record (arrowschema encoding). Each input row becomes one message containing a bare encapsulatedRecordBatch(matchingpyarrow.RecordBatch.serialize()) — no stream framing, no embedded schema, no Arrow body compression. Dictionary-encoded columns are hydrated to their value type so everyRecordBatchdecodes independently.mcap cat --jsonnow decodesarrowmessages: it reads eachRecordBatchagainst the channel's Schema record and emits the rows. Because a message may hold multiple rows, thedatafield is a JSON array of row objects.Timestamp handling
log_time/publish_timeare derived from Arrow columns:--log-time-field <NAME>selects the column; otherwise a column namedlog_timeis used, falling back to the first timestamp/date column in schema order (Arrow field order is well-defined and preserved through IPC).--publish-time-field <NAME>, then a column namedpublish_time, otherwise defaults tolog_time.Timestamp/Date32/Date64columns are scaled from their intrinsic unit to nanoseconds. Integer columns use--timestamp-unit {s,ms,us,ns}(defaultns).u64times are hard errors.New flags on
convert--topic(defaults to the input file stem),--schema-name,--log-time-field,--publish-time-field,--timestamp-unit,--rows-per-message(default1, for opt-in row batching).Dependency
Adds
arrow(ipc,json,chrono-tzfeatures).jsonpowerscat --jsonviaarrow-json's writer;chrono-tzis required so named timezones (e.g.timestamp[us, tz=UTC]) render correctly.Testing
convertinarrow_ipc.rs, 1 forcat --jsonincat.rs). Theconverttests generate Arrow IPC fixtures dynamically (no committed binaries / LFS), covering unit scaling, auto-detection, named/explicit/default field resolution, dictionary hydration, row batching, stream vs file framing, multi-batch files, and error paths; each round-trips the emitted bytes back through an ArrowStreamReader.timestamp[us, tz=UTC]+ dictionary Arrow file and a real third-party Arrow file (samplefile.com), verified withmcap info/list,mcap cat --json, and a pyarrow round-trip decode.Depends conceptually on #1748 (registry entry); this PR is the implementation.