GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — perf(thrift): decode inline Arrow results in one call, into memory returned on free by vuanhphung · Pull Request #1037 · databricks/databricks-sql-python

Conversation

@vuanhphung

@vuanhphung vuanhphung commented Nov 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

What type of PR is this?

  • Other (performance)

Description

This PR changes how convert_arrow_based_set_to_arrow_table handles inline Arrow results on Thrift, with two effects: more statements per second for many-batch results under many threads, and large inline results that release their memory when freed. It supersedes #1036. Decoding through pyarrow alone made large-result memory worse than main, so both changes have to land together.

Throughput. The warehouse returns small inline results as dozens of LZ4-compressed Arrow batches: range(100) and range(1000) both arrive as 72 batches. Each batch was decompressed with lz4.frame.decompress, which releases and reacquires the GIL on every call. When many threads run statements, each reacquire waits behind the other runnable threads. Against a mock that replays the captured reply with 50 ms RTT, a 1,000-row statement at 64 threads made ~600 voluntary context switches and used 5.3 ms of CPU, half of it sys time (1.4 ms with one thread), and throughput stalled at ~390 statements/s. Replaying the decompressed bytes from a dict, with no C call, removed the effect, which confirmed the cause. For three or more compressed batches, the frames are now concatenated and decoded with one pyarrow.CompressedInputStream read. Arrow decodes concatenated LZ4 frames natively; python-lz4's one-shot decompress silently returns only the first frame. One- and two-batch results such as SELECT 1, uncompressed results, and pyarrow builds without the lz4 codec keep the per-batch path.

Memory. Each FetchResults row set (~3.7 MB for a large result) used to be concatenated into a bytearray on the glibc heap. The Arrow table reads it zero-copy, so these buffers live as long as the result. glibc couldn't give the space back afterwards: a 1.7 GB inline fetchall_arrow() left ~1.6 GB resident on main. Decoding through pyarrow alone made this worse, because its large read temporaries pushed the result buffers onto the brk heap (peak 2909 MB, 2859 MB left after free). Each row set's stream is now built in its own private anonymous mmap. The map is reserved at 4x the compressed size (untouched pages cost no memory), filled by readinto() straight from the decode stream (or batch by batch on the per-batch path), grown via mremap if needed, and shrunk to size before the zero-copy export. It returns to the OS when the table is released. A stream moves to a map only once it holds at least 1 MiB, because each held map is one VMA (vm.max_map_count); reaching the default limit would take over 64 GB of inline results held at once. Smaller results, mmap failures and non-Linux platforms keep the bytearray, and whenever no map was created (other platforms, or a failed mmap), results whose compressed size reaches 1 MiB keep the per-batch decode, as on main.

CloudFetch, SEA and the kernel backend are unchanged.

Trade-off: Arrow takes the stream's decode buffers from pyarrow's memory pool, which keeps a heap per thread. In a 64-thread mock run, peak RSS was 198 MB on main, 228 MB with the decode change alone and 231 MB with both, about 0.5 MB per busy thread. The memory map itself adds nothing measurable. An earlier mock measured +50 MB at 200 threads.

How is this tested?

  • Unit tests
  • E2E Tests
  • Manually

Unit tests decode real LZ4-compressed Arrow batches: 1, 2, 3 and 72 batches; compressed and not; a highly compressible result that needs several reads; and the no-codec fallback. They check that 72 batches no longer call lz4.frame.decompress. Corrupt and truncated frames raise RuntimeError on both paths, and MemoryError passes through unchanged. The memory-map tests cover:

  • 72 batches decoding as one stream into one map, and two large batches taking the per-batch path into the map;
  • growth when the estimate is too small, including the retry at the exact size;
  • the final shrink, and slicing when the shrink fails;
  • heap fallbacks when mmap or growth fails;
  • a compressible stream moving to a map once it crosses 1 MiB, while smaller streams stay on the heap;
  • non-Linux platforms;
  • the table keeping its map alive and releasing it with the table.

They pass on pyarrow 14.0.2, 23.0.1 and 26.0.1, and the full unit suite passes. Live e2e: the TestPySQLCoreSuite fetch/Arrow tests, TestPySQLLargeNarrowResultSet and test_complex_types.py pass (52). Earlier on the decode commits, the test_driver.py core, large wide/narrow and async suites passed (132); the 6 test_staging_ingestion_* failures there were a missing ingestion user in that environment and failed the same way on main. Inline results (lz4 on and off) matched CloudFetch results for 2M rows of mixed types, and 40 captured live row sets decode identically.

Memory, live Thrift warehouse with use_cloud_fetch=False: inline fetchall_arrow, 3 fresh processes per cell in rotating order, median RSS increase over the pre-query baseline. "Decode only" is this PR without the memory-map commit.

Result Peak: main / decode only / this PR After free: main / decode only / this PR Fetch time: main / this PR
110 MB 122 / 135 / 122 MB 82 / 108 / 5 MB 3.03 / 2.80 s
562 MB 601 / 602 / 585 MB 516 / 583 / 14 MB 14.23 / 14.34 s
1.7 GB 1810 / 2909 / 1758 MB 1637 / 2859 / 26 MB 42.53 / 42.84 s

Throughput, 64 threads, a connection and a cursor per statement per thread, 1,000-row / 72-batch inline result, mock with 50 ms RTT, 3 interleaved runs: 528 → 1109 statements/s and p50 120 → 56 ms on main → this PR (decode only: 1113 statements/s; the memory map doesn't affect small results).

Results from the decode commits, measured with the original harness (median of 5 interleaved runs, 1,000-row result). The small-result path they exercise is unchanged by the memory-map commit.

Setup Threads Fetch Statements/s p50 (ms) p99 (ms) CPU/statement (ms)
mock 16 fetchall_arrow 283 → 294 53 → 53 86 → 69 2.2 → 1.5
mock 64 fetchall_arrow 393 → 748 161 → 85 194 → 129 5.3 → 1.8
mock 200 fetchall_arrow 386 → 696 503 → 277 625 → 482 5.5 → 2.1
mock 64 fetchall 175 → 215 360 → 289 450 → 415 9.1 → 5.7
live 200 fetchall_arrow 380 → 499 487 → 359 877 → 1073 5.4 → 2.1
live 64 fetchall 175 → 204 355 → 302 548 → 500 8.9 → 6.0

On the live warehouse, 64-thread fetchall_arrow and all 1- and 16-thread runs were capped by the shared warehouse, and the higher live p99 at 200 threads coincides with ~30% more load on it. SELECT 1 (one batch, unchanged path) and the kernel backend measured the same on both sides.

Related Tickets & Documents

Supersedes #1036.

This pull request and its description were written by Isaac.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vuanhphung Isaac
perf(thrift): decompress many-batch inline Arrow results in one call
bf8752c
The warehouse returns small inline results as dozens of LZ4 frames (72 for
both 100 and 1,000 rows of range()). Decompressing each frame with
lz4.frame.decompress releases and reacquires the GIL per frame, so with
many busy threads a 1,000-row statement made ~600 context switches and
spent most of its time waiting for the GIL.

For three or more compressed batches, decode the concatenated frames with
one pyarrow CompressedInputStream read. One- and two-batch results keep the
python-lz4 path, as does any pyarrow build without the lz4 codec.

Co-authored-by: Isaac <[email protected]>
Signed-off-by: Vu Anh Phung <[email protected]>
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:39 — with GitHub Actions Error
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:39 — with GitHub Actions Inactive
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 1 Low · 1 Nit

Looks good: the change is well-scoped and well-tested, with two low-severity points. One is that the exception type for corrupt payloads now depends on how many batches the result has; the other is a test that assumes the environment's pyarrow has the lz4 codec.

Other findings

  • ⚪ Nit — test_convert_arrow_based_set_decodes_many_lz4_batches_in_one_call expects (72, 0) decompress calls without checking utils._PYARROW_HAS_LZ4. On a pyarrow build without the lz4 codec (exactly the case the fallback handles), this test fails instead of skipping. Pin the flag with patch.object(utils, "_PYARROW_HAS_LZ4", True) plus a skip when pyarrow.Codec.is_available("lz4") is False, or just skip when the codec is missing.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 10:42 Inactive
@vuanhphung Isaac
Raise RuntimeError for corrupt LZ4 input on the multi-batch path
2140f9d
pyarrow raises OSError where python-lz4 raises RuntimeError, so the error
type depended on how many batches a result had. Also skip the one-call
test on pyarrow builds without the lz4 codec.

Co-authored-by: Isaac <[email protected]>
Signed-off-by: Vu Anh Phung <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:43 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:43 — with GitHub Actions Inactive
@vuanhphung

vuanhphung commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

Nit from the review body (one-call test assumes the lz4 codec): fixed in 2140f9d. test_convert_arrow_based_set_decodes_many_lz4_batches_in_one_call is now skipped when utils._PYARROW_HAS_LZ4 is False. The fallback path on such builds is still covered by test_convert_arrow_based_set_without_pyarrow_lz4_codec.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:43 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:44 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 10:46 Inactive
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 2 Low

Looks good overall. The batched LZ4 path is correct and tested with real compressed data, and the fallback paths are unchanged. I have two low concerns: real out-of-memory errors get reported as decompression failures, and corruption in a middle frame isn't tested.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread tests/unit/test_thrift_backend.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 10:46 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 10:46 Inactive
@vuanhphung Isaac
Let MemoryError through; test corruption in middle frames
38cbb9a
ArrowMemoryError subclasses both MemoryError and ArrowException, so an
allocation failure was reported as an LZ4 decompression error. Also cover
truncated and corrupted middle frames, with checksums as the warehouse
sets them.

Co-authored-by: Isaac <[email protected]>
Signed-off-by: Vu Anh Phung <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:48 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:48 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:48 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:48 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:48 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 10:49 Error
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 3 Low

No blocking issues: the single-call decode is correctly limited to 3+ LZ4 batches and falls back to the old path when pyarrow lacks the lz4 codec. The error types match the old path (MemoryError is re-raised unwrapped; other decode errors become RuntimeError). I found 3 low-severity items: a test that will fail on pyarrow builds without lz4, a decode stream that is never closed, and a difference from main on malformed frames.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread tests/unit/test_thrift_backend.py
)

def test_convert_arrow_based_set_lz4_memory_error_is_not_wrapped(self):
_, arrow_batches, schema = self._arrow_set(72, 14, True)

@peco-review-bot peco-review-bot Bot Nov 12, 2026

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Low — test_convert_arrow_based_set_lz4_memory_error_is_not_wrapped patches pyarrow.CompressedInputStream, but that call only happens when _PYARROW_HAS_LZ4 is true. On a pyarrow build without the lz4 codec, the function uses the lz4.frame.decompress fallback and returns normally, so assertRaises(MemoryError) fails. Your PR description lists this setup as supported. test_convert_arrow_based_set_decodes_many_lz4_batches_in_one_call is already guarded; this test needs the same @unittest.skipUnless(utils._PYARROW_HAS_LZ4, ...) decorator.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vuanhphung vuanhphung Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c6891ff: test_convert_arrow_based_set_lz4_memory_error_is_not_wrapped now has the same @unittest.skipUnless(utils._PYARROW_HAS_LZ4, ...) guard.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@peco-review-bot peco-review-bot Bot Nov 12, 2026

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the current head and the fix isn't there yet. The only @unittest.skipUnless(utils._PYARROW_HAS_LZ4, ...) in tests/unit/test_thrift_backend.py is at line 2238, which guards test_convert_arrow_based_set_decodes_many_lz4_batches_in_one_call. Line 2291, just above test_convert_arrow_based_set_lz4_memory_error_is_not_wrapped at line 2292, has no guard. Maybe c6891ff hasn't been pushed to this branch, or the decorator ended up on a different test. Once the guard is directly above that test on the PR head, this thread is resolved.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 10:49 Inactive
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 10:49 Error
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 10:49 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 10:49 Inactive
@vuanhphung Isaac
Close the LZ4 stream; cover unchecksummed truncation
c6891ff
Close the CompressedInputStream with a with block so its buffers are freed
even when an exception traceback keeps the frame alive. Skip the memory
error test without the lz4 codec, test truncated frames without checksums,
and note that each batch is one LZ4 frame.

Co-authored-by: Isaac <[email protected]>
Signed-off-by: Vu Anh Phung <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 10:53 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 10:53 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 15:50 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 15:51 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 15:53 Inactive
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 2 Low

Looks good: I found two low-severity notes and no correctness issues. The mmap buffer's grow, shrink and fallback paths stay consistent in every error branch I traced, errors are converted the same way on both decode paths, and the tests cover these paths thoroughly.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 15:54 Inactive
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 15:54 Inactive
@vuanhphung Isaac
fix(thrift): keep large inline results on the per-batch path without …
74f5cca
…the map

On platforms without the memory map (non-Linux), decoding a large result
through Arrow into a heap bytearray is the combination that used more
memory than main with glibc, and other allocators are unmeasured. Use
the one-call decode there only for results whose compressed size is
under the map floor, where the throughput gain comes from; large
results decode per batch as on main. Note the temporary copy of the
compressed row set in the one-call path.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 15:57 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 15:57 — with GitHub Actions Error
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 15:57 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 15:57 — with GitHub Actions Error
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 15:57 — with GitHub Actions Inactive
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 15:59 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 15:59 Inactive
peco-review-bot[bot]
peco-review-bot Bot reviewed Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 1 Medium

Looks good overall, with one medium concern: on Linux the decode path is chosen from the platform flag, not from whether the memory map was actually created. If mmap or mremap fails, a large result is decoded through Arrow into the heap, which is the high-memory case this PR is meant to avoid. The buffer management, error wrapping and tests otherwise look correct and thorough.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 16:00 Inactive
@vuanhphung Isaac
fix(thrift): pick the inline decode path from whether the map exists
6d3787f
The one-call Arrow decode for large results was gated on the platform
flag, so on Linux a failed mmap (for example under strict overcommit,
where the reservation is charged up front) still decoded a large result
through Arrow into the heap, the case that used more memory than main.
Gate it on the buffer actually being mapped instead: large results
without a map use the per-batch decode, as on main.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 16:50 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 16:50 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 16:50 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 16:50 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 16:53 Inactive
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 2 Low

Looks good. The decode and mmap logic holds up, including growth, shrink and heap fallbacks, error mapping and map lifetime, and the tests cover it well. Two low findings: a missing codec-availability skip in two new tests, and a gate comment that doesn't match the compressed-size check it describes.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread tests/unit/test_util.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 16:54 Inactive
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 16:54 Inactive
@vuanhphung Isaac
test(thrift): skip one-call decode assertions without the lz4 codec
2dfe0ac
Two tests assert that lz4.frame.decompress isn't called, which only
holds when pyarrow has the lz4 codec; skip them otherwise, like the
sibling tests. Reword the gate comment: without a map it limits the
one-call decode by compressed size, so a highly compressible result can
still decode into the heap.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 1 Low

Looks good, with one low edge case. The mmap-backed stream buffer, the concatenated-frame Arrow decode (Arrow resets its decompressor between frames, and the pyarrow>=14 floor covers Codec.is_available and readinto), the error wrapping and the fallbacks all check out, and the unit tests are thorough. Nit: _decompress_lz4_frames_into hardcodes 4 * for the first read size instead of reusing _LZ4_RATIO_ESTIMATE, so the two estimates can drift apart.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@vuanhphung Isaac
fix(thrift): don't grow an exactly filled inline Arrow map
ccdbbf4
When the decoded stream filled the reservation exactly, append_stream
grew the map before seeing EOF: a wasted mremap that, under memory
pressure, could push a finished result onto the heap. Probe with a
one-byte read and grow only if more data follows. Reuse
_LZ4_RATIO_ESTIMATE for the first read size.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung

vuanhphung commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

Review-body nit, done in ccdbbf4: _decompress_lz4_frames_into now uses _LZ4_RATIO_ESTIMATE for its first read size instead of a hard-coded 4, so the two estimates can't drift apart. Same value, no behaviour change.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

peco-review-bot[bot]
peco-review-bot Bot approved these changes Nov 12, 2026
View reviewed changes

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: 1 Low

Looks good, with one low concern. The mmap-backed stream buffer, the single-call LZ4 decode and the fallbacks are careful and well tested. The error types (RuntimeError, MemoryError) and lifetime handling (the table holding the map) keep matching the old behaviour.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/databricks/sql/utils.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

This branch was previously deployed

1 inactive deployment
azure-prod — ccdbbf4c Deployed Nov 12, 2026 by vuanhphung via followup #2127
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@peco-review-bot peco-review-bot[bot] peco-review-bot[bot] approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@vuanhphung
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.