A result goes to Arrow without a copy - #9
Merged
Merged
Conversation
The C ABI has a zu_result_arrow that hands a whole result to an Arrow consumer over the C Data Interface, and the JVM client had no way to call it. This is that way: zudb-arrow, one class and three static methods, giving back the ArrowReader every Arrow consumer on the JVM already takes. It is an artifact of its own because arrow-java is the largest dependency anything in this repository would have and the one most likely to clash with a version an application already pins. The rest of the client has no dependencies at all, and a program that reads rows or columns should keep it that way. Nothing on the path is proportional to the answer. The arrays that cross are the buffers the executor filled, at the addresses it filled them at, so an export is a schema, a stream and the pointers in it, and batches are slices of arrays that are already in memory. Summing a hundred thousand rows through the reader costs about 2 ns a row over the statement itself, against 0.5 for the borrowed column and 76 for a row at a time. That is also why an export spends its result: once the buffers have left there is nothing on this side to read again. Result.exportArrow clears the handle before the call rather than after it, because the engine nulls the result on every path it takes, refusals included, and a result this side still thought it owned would be one a later close would free twice. The two arguments it checks itself are checked before the engine sees them, so a call refused for a stream that is nowhere spent nothing and the result is still there to read. A node column names its table out of the catalog the connection holds, so a Result now knows which connection produced it and lends the handle back for this one call. A connection that has already closed is not a failure, and the export then names a table after its id. Twelve tests over a real engine, covering a stored column crossing as the buffers it already was, an ORDER BY crossing through the row-built fallback, nulls, UTF-8, the batch size a consumer asked for, an empty result arriving as one empty batch, the spending, and the zoned time column Arrow has no type for. The allocator is closed after every one, so a leaked stream or reader fails the test that leaked it.
zu_result_arrow is what the engine added the revision for, so a client that calls it is a client written against 0.12 and should say so. CI reads the macro out of the engine's own header and compares, which is the step that has been red on main since the engine bumped.
22 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The C ABI has a
zu_result_arrowthat hands a whole result to an Arrow consumer over the C Data Interface, and the JVM client had no way to call it. This is that way:zudb-arrow, one class and three static methods, giving back theArrowReaderevery Arrow consumer on the JVM already takes.It is an artifact of its own because arrow-java is the largest dependency anything in this repository would have and the one most likely to clash with a version an application already pins. The rest of the client has no dependencies at all, and a program that reads rows or columns should keep it that way.
Nothing on the path is proportional to the answer. The arrays that cross are the buffers the executor filled, at the addresses it filled them at, so an export is a schema, a stream and the pointers in it, and batches are slices of arrays that are already in memory.
The same hundred thousand rows, statement included on every line because an export cannot be run twice against one result:
r.longs(0)and a sum over the bufferArrow.query(...)and a sum over every batchfor (Row row : r) row.getLong(0)Read those against the first line rather than against zero. Summing through Arrow costs about 2 ns a row over the statement, against 0.5 for the borrowed column and 76 for a row at a time.
That is also why an export spends its result: once the buffers have left there is nothing on this side to read again.
Result.exportArrowclears the handle before the call rather than after it, because the engine nulls the result on every path it takes, refusals included, and a result this side still thought it owned would be one a later close would free twice. The two arguments it checks itself are checked before the engine sees them, so a call refused for a stream that is nowhere spent nothing and the result is still there to read.A node column names its table out of the catalog the connection holds, so a
Resultnow knows which connection produced it and lends the handle back for this one call. A connection that has already closed is not a failure, and the export then names a table after its id.Twelve tests over a real engine, covering a stored column crossing as the buffers it already was, an
ORDER BYcrossing through the row-built fallback, nulls, UTF-8, the batch size a consumer asked for, an empty result arriving as one empty batch, the spending, and the zoned time column Arrow has no type for. The allocator is closed after every one, so a leaked stream or reader fails the test that leaked it.Local: 200 tests green across the four modules, javadoc clean under the release profile, and the benchmark jar builds and runs.