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): prefetch CloudFetch links while earlier files download by vuanhphung · Pull Request #1038 · 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

Stacked on #1030. The base is perf/thrift-cf-batch, so the diff shows only this change. I'll retarget to main once #1030 merges.

What type of PR is this?

  • Other (performance)

Description

With #1030, every FetchResults batch holds about one CloudFetch link per download thread, but each batch still has to finish before the next one starts. The next FetchResults goes out only after the last file of the current batch is consumed, so the slowest file holds everything up, and a new download manager and thread pool are built for each batch. Download timelines on a 4.9 GB result show an average of 5.3 of 10 downloads in flight.

The download manager can now pull links itself. Once CloudFetch starts, ThriftResultSet hands the rest of the result to the queue's download manager. Whenever a download slot is free and no links are pending, the manager asks for more links: one per free slot plus half a pool queued ahead ((free + max_download_threads // 2) × largest link, clamped to 1–4× buffer_size_bytes as in #1030). The request runs on the consumer thread, as FetchResults does today, so there's no new concurrency on the Thrift client. One thread pool now serves the whole result, and files are still returned in row order (same offset check as before). A variant that refilled only when half the slots were free kept the average at 5.3 in flight and gave no consistent gain, so slots are refilled one at a time.

Bounds and trade-offs:

  • Memory: downloaded but unconsumed files are still capped at max_download_threads, the existing bound. The pool now stays at that bound more of the time, so a slow consumer's peak RSS is higher: +5% to +16% across three runs on 1.6 GB (latest pair 831 → 918 MB).
  • Link expiry: up to max_download_threads // 2 links (5 by default) wait for a free slot. They start once that many more files are consumed. A link expires 900 s after it is issued, so a consumer has to spend more than about 180 s per ~20 MB file before a queued link expires. With a slow consumer (0.3 s per 100k rows) the oldest link still had 898 s left when its download started (perf(thrift): request about one CloudFetch file per download thread #1030: 899.5 s). Thrift still has no link refresh.
  • Close and cancel: closing a result set sets a per-manager cancel event and calls shutdown(wait=False, cancel_futures=True). Downloads now read the body in 1 MiB chunks (preload_content=False) and check the event before the GET and between chunks, so a download in flight stops within about 1 MiB and its connection is closed rather than returned to the pool. A fully read body releases its connection for reuse. urllib3 retried a failed body read only while it read the body itself, so a GET interrupted mid-body is now retried here (3 attempts). Cursor.cancel() also cancels the active result set's downloads. Later reads then raise OperationalError instead of returning a result that ends early; main raised RequestError, a subclass, at the next FetchResults. The cancellation is raised outside the HTTP client so it isn't logged as an HTTP error. downloader.py stays clear of the lines perf(cloudfetch): cut peak memory of large CloudFetch results #1032 edits, and perf(cloudfetch): cut peak memory of large CloudFetch results #1032 applies cleanly on top. The one adjustment needed after both merge is that perf(cloudfetch): cut peak memory of large CloudFetch results #1032's test_run_returns_arrow_buffer_for_lz4_file mock needs a stream(), a one-line change.
  • Kill switch: the internal connection kwarg _cloudfetch_prefetch=False restores perf(thrift): request about one CloudFetch file per download thread #1030's per-batch fetching exactly (verified live: same batches and maxBytes). String values from a URL query also work ("false"/"0"/"no"/"off"), and an unrecognized string falls back to off with a warning. Cancel-on-close stays on either way. It isn't documented publicly.
  • Errors: if a mid-stream link fetch fails, files already downloading are still returned. The read that needs rows past them raises the original error, and later reads raise, so a retry can't skip rows.

Live A/B against a PRO warehouse (Thrift; fresh processes, #1030 and this PR interleaved, warm-up discarded; fetch = time after execute() returns):

Workload FetchResults fetch p50 fetch p95 peak RSS
lineitem, 4.9 GB, fetchall_arrow, n=5 26 → 41 13.27 → 10.66 s 14.59 → 15.28 s 5648 → 5663 MB
⅓ of lineitem, 1.6 GB, fetchall_arrow, n=5 8 → 13 4.40 → 3.29 s 7.87 → 3.77 s 2399 → 2379 MB
⅓ of lineitem, 1.6 GB, fetchmany_arrow(1M), n=3 8 → 13 4.55 → 3.59 s 4.66 → 3.68 s 1244 → 1304 MB

The 4.9 GB p95 comes from one 16.4 s run; the other four were 9.4–10.8 s. An earlier run of the same A/B, before the chunked reads, measured 13.96 → 9.63 s p50 and 18.06 → 10.63 s p95. Chunked reads keep connections in reuse: draining 1.6 GB (85 files) opened 6 new HTTPS connections on both #1030 and this PR.

Early close after 500k rows of the 1.6 GB result (n=3 medians):

main #1030 this PR
downloads in flight at close 0 6 8
MB read in the 5 s after close 0 45 6
RSS 5 s after close 312 MB 514 MB 292 MB
close() 0.14 s 0.13 s 0.12 s
exit lag when the process exits right after close 0.20 s 0.47 s 0.09 s

cancel() 1.5 s into fetchall_arrow made the fetch fail 0.29 / 0.44 / 0.19 s later on main / #1030 / this PR. This PR raises OperationalError, or RequestError when the next FetchResults fails first.

With #1032 applied on top (locally, n=3, 1.6 GB): peak RSS 1312 → 642 MB for fetchmany_arrow(1M) and 2376 → 1860 MB for fetchall_arrow. Fetch time stayed within noise: 4.69 → 3.34 s and 3.56 → 5.71 s, the latter with one 10 s outlier; an earlier run measured 3.96 → 3.13 s.

How is this tested?

  • Unit tests
  • E2E Tests
  • Manually

New unit tests in test_cloudfetch_prefetch.py cover the refill rule: links are requested only when a slot is free and nothing is pending, there are never more than max_download_threads tasks, and row order is kept across refills. They also check that an empty reply doesn't cause a busy loop, the link budget and its clamp, the offset check, the handoff, and the kill switch. On the cancel side they cover:

  • chunked reads that release the connection;
  • a cancel mid-body that stops reading and skips decompression;
  • an interrupted body that is retried, and one that gives up after 3 attempts;
  • cancel() during a link fetch, and a scheduled download cancelled before it starts;
  • reads after a cancel that raise instead of ending the result;
  • Cursor.cancel() cancelling the active result set's downloads. perf(thrift): request about one CloudFetch file per download thread #1030's per-batch tests now run with the kill switch. The full unit suite passes, and perf(cloudfetch): cut peak memory of large CloudFetch results #1032's tests pass with both PRs applied. Against a live warehouse, the test_driver.py e2e tests for large wide/narrow results, async large results, fetchone/fetchall/fetchmany/iteration, Arrow fetches, row limits and cancel pass (31 passed, Thrift and SEA).

Manual live checks on a 30M-row, 32-link result verified exact row counts and order across batches for fetchall_arrow, fetchmany_arrow, mixed fetchmany/fetchone, and fetchall. They also covered close() and cancel() mid-stream, and use_cloud_fetch=False, with prefetch on and with the kill switch.

Related Tickets & Documents

Stacked on #1030. Related: #1032 (CloudFetch decompression into private mmaps).

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): prefetch CloudFetch links while earlier files download
9c6cb9e
Each FetchResults batch waited for its slowest file before the next batch was
requested, so on average only about half of the download threads were busy.
The download manager now asks the result set for more links whenever a slot
frees up and no links are pending (one per free slot plus half a pool), using
one thread pool for the whole result. _cloudfetch_prefetch=False restores
per-batch fetching.

Closing a result set now sets a cancel event that downloads check before the
GET and before decompression, and cancels queued downloads.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:10 — with GitHub Actions Error
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 11:10 — with GitHub Actions 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 · 2 Low

Looks good overall, with one medium concern: the prefetch path discards any part of a FetchResults reply that isn't a CloudFetch link. Ordering, the memory bound and cancel-on-close look right. The kill switch is wired through every result-set constructor and has tests.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

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

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/download_manager.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 11:14 Inactive
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 11:14 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 11:14 Inactive
@vuanhphung Isaac
Guard prefetched link fetches and a shut-down queue
117a095
fetch_result_links raises DataError if a reply carries rows that are not
CloudFetch links, instead of dropping them. set_link_source refuses a
manager that is already shut down, so such a result keeps per-batch
fetching. Pin that a failed link fetch reaches the caller and that fetching
can resume.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 11:18 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 11:18 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:18 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:18 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:18 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:18 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 11:20 Error
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 11:20 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 11:20 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, with two low-severity notes: a re-poll edge case in _schedule_downloads, and no end-to-end unit test of the result set handing link fetching to the queue. Ordering, the memory bound, cancel-on-close and the kill switch all behave as the PR describes. Nit: the link source is attached only after ThriftCloudFetchQueue.__init__ waits for the first file, so the first prefetch can't start until that download finishes.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

Comment thread tests/unit/test_cloudfetch_prefetch.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 11:21 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 11:21 Inactive
@vuanhphung Isaac
Don't re-poll for links when a reply only had empty links
0dede5d
Base the early exit on whether a download was scheduled, so a reply whose
links all have zero rows waits for the next call like an empty reply. Add
end-to-end tests that run ThriftResultSet over a real CloudFetch queue and
download manager across several link fetches.

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

vuanhphung commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

On the review-body nit (the first prefetch waits until ThriftCloudFetchQueue.__init__ has the first file): true. The cost is one file's download time (~250 ms here), once per result, and the initial batch keeps downloading in the meantime. The live numbers in the description include it. Removing it would mean passing the link source through ThriftResultSetQueueFactory.build_queue into the queue constructor, which is more change than it is worth, so I left it.

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 11:25 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:25 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 11:25 — with GitHub Actions 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: 1 Low

Looks good overall, with one low concern: the manager does not check whether it was cancelled after the link-fetch call returns. Prefetch is wired correctly through _start_prefetch and the has_more_rows hand-off. The kill switch keeps the old per-batch path, and the tests cover ordering, empty replies, errors, budget clamping and cancel-on-close.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/download_manager.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 11:27 Error
@peco-review-bot
peco-review-bot Bot had a problem deploying to azure-prod November 12, 2026 11:27 Error
@vuanhphung Isaac
After cancel, still return files that finished downloading
e1ce857
A read after cancel() now fails only when the cancel left the result
incomplete (links pending, more on the server, or a download it stopped).
Cancelling a statement whose result had already arrived no longer turns the
end of the result into an error. A link whose submit races with cancel()
is kept, so it still counts as missing.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 13:18 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 13:18 — with GitHub Actions Inactive
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 13:18 — with GitHub Actions Error
@vuanhphung
vuanhphung had a problem deploying to azure-prod November 12, 2026 13:18 — with GitHub Actions Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 13:19 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, with two low-severity notes on the downloader's new chunked read and retry loop. The download manager's prefetch, cancel-race handling (keeping links whose submit failed, keeping the link source attached after a cancel) and row-order logic hold up when traced through, and the new unit tests cover the race paths.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/downloader.py Resolved

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/downloader.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 13:20 Error
@peco-review-bot
peco-review-bot Bot temporarily deployed to azure-prod November 12, 2026 13:20 Inactive
@vuanhphung Isaac
Re-check cancellation and link expiry before a retried GET
30aaac3
Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 13:28 — with GitHub Actions Inactive
@vuanhphung
vuanhphung temporarily deployed to azure-prod November 12, 2026 13:28 — with GitHub Actions 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 · 1 Low

The prefetch design looks solid, with one medium concern: an error from the mid-stream link fetch can silently drop rows when the caller retries. Cancel/close handling, the retry of interrupted body reads, and the kill switch all check out. Unit coverage is generally thorough, apart from the kill-switch forwarding noted in the second finding.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

@vuanhphung Isaac
Make a failed mid-stream link fetch fail every later read
a2643e8
A link fetch that raises part-way through a read loses the rows that read
had collected, so a retry would continue past them. The download manager
now raises the same error on every later read. Test the kill switch at all
six ThriftResultSet entry points.

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: 4 Low

Looks good overall. The prefetch, cancel and retry logic is careful and well tested, including the cancel and shutdown races. I found only low-severity issues: the meaning of has_more_rows has changed, the stored link error is re-raised as the same object, a secondary error in Cursor.cancel() can hide the original one, and body-read retries have no backoff.

Sorry, something went wrong.

Uh oh!

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

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

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

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

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/downloader.py Resolved

Uh oh!

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

@vuanhphung Isaac
Back off between body-read retries; chain the stored link error
181cb82
Interrupted body reads wait 0.5 s, then 1 s, before retrying; a cancel ends
the wait. After a failed mid-stream link fetch, later reads raise a fresh
OperationalError chained to it that says to re-execute. A failure while
cancelling downloads no longer hides the cancel RPC's own error.

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: one low-severity issue with how the kill switch reads _cloudfetch_prefetch=None. I checked the prefetch scheduling loop, what happens on cancel or shutdown (including the submit() racing cancel()), chunked body reads and retries in UnifiedHttpClient.request_context, and the has_more_rows handoff in ThriftResultSet. All of them hold up, and tests/unit covers them well.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

@vuanhphung Isaac
Treat _cloudfetch_prefetch=None as unset
8d86434
Document what has_more_rows means after the handoff to the download manager.

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 · 2 Nit

Looks good overall, with 3 low findings: lenient kill-switch parsing, retry backoff counted in the download-speed metrics, and a new result-set/download-manager reference cycle. The prefetch, cancel and retry logic hangs together well and has thorough unit tests, including the cancel races and the case where a failed link fetch must not let a retry skip rows.

Other findings

  • ⚪ Nit — start_time is taken before the retry loop. When a body read is retried, download_duration therefore also covers the failed attempt(s) and the 0.5 s / 1 s backoff waits. _log_download_metrics then reports a lower MB/s and can log the CloudFetch download slower than threshold warning for a file whose successful attempt was fast. To fix it, reset start_time at the start of each attempt, or log the retry separately.
  • ⚪ Nit — set_link_source(self._fetch_more_links) creates a reference cycle: result set → results queue → download_manager._link_source (a bound method) → result set. Before this change, a ThriftResultSet dropped without close() was freed by refcounting, and its ThreadPoolExecutor (up to max_download_threads idle workers) was torn down right away. Now the whole graph, including the executor and its threads, stays alive until the cyclic GC runs. A weakref.WeakMethod (or clearing _link_source once has_more is False, which already happens, plus on close) would avoid holding the result set strongly while a stream is still in progress.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

@vuanhphung Isaac
Warn on unrecognized _cloudfetch_prefetch strings; time only the last…
779182a
… attempt

Unrecognized string values keep prefetch on but log a warning that names
the value. Download speed metrics now cover only the attempt that succeeded,
not earlier failed attempts or the backoff.

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

On the two review-body nits:

  • start_time across retries: fixed in 779182a. start_time is reset after the backoff and checks, so the speed metrics (and the slow-download warning) cover only the attempt that succeeded.
  • Reference cycle through the bound _fetch_more_links: I'm leaving this as is. The cycle is broken explicitly in both normal endings. At end of stream the manager sets _link_source = None when the last reply has hasMoreRows=False, and on close _shutdown_manager() clears it. Cursor.close() and the next execute() both close the active result set. The cycle only lasts for a result set that is dropped mid-stream without being closed, and the cyclic GC then collects it, after which the idle executor threads exit as they do on main. A WeakMethod would change the LinkSource contract for that leak-only case.
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: after a failed link fetch, downloads already in flight keep running until close(). The hand-off, cancel/close, retry and kill-switch paths look correct to me. Tests cover them well, including the races with cancel and the sticky error after a failed link fetch.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

@vuanhphung Isaac
Stop downloads when a mid-stream link fetch fails
66eeda5
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 concern: what the internal kill switch does with an unrecognized value. I checked the cancel and close races, the order of link fetches against the shutdown and cancel events, the body-read retry and connection release in downloader.py, the handoff of has_more_rows, and how SEA and the per-batch path share the download manager. I found no correctness problems, and the tests cover the new states well.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

@vuanhphung Isaac
Turn prefetch off for unrecognized _cloudfetch_prefetch strings
677f4bc
A kill switch should fail safe: an unparsable value falls back to per-batch
fetching and logs a warning. None still means unset (prefetch on).

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>
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 · 2 Low

Solid change overall: prefetching, ordering, the cancel/close paths and the kill switch are carefully done and well tested. One medium concern: a failed link fetch now aborts reads of files that are already downloaded. There are also two minor robustness gaps.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

Comment thread src/databricks/sql/backend/thrift_backend.py Resolved

Uh oh!

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

@vuanhphung Isaac
Reject row-based replies in fetch_result_links too
6e14f55
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: 2 Low

Looks good overall: the prefetch hand-off, the cancel and close semantics, and the chunked body read with retries are carefully designed and well tested. Two low findings: the first link prefetch waits until the first file has downloaded and the caller reads again, and the hot-loop case (no downloads in flight, server keeps returning no links) has no test.

Sorry, something went wrong.

Uh oh!

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

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

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/download_manager.py Resolved

Uh oh!

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

@vuanhphung Isaac
Keep returning downloaded files after a failed link fetch
a83f50f
A failed mid-stream link fetch now stops scheduling and is raised only once
the files already downloading run out, so a reader that never needs the
missing rows still succeeds, as on main. The first read that needs them gets
the original error and later reads fail too.

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: 2 Low

Looks solid overall. The cancel and close paths, the link-error latching and the ordering guarantees are well thought through and well tested. I found two low-severity issues: the meaning of the public has_more_rows attribute has changed, and the chunked body read briefly doubles memory per download.

Sorry, something went wrong.

Uh oh!

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

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

Uh oh!

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

Comment thread src/databricks/sql/cloudfetch/downloader.py Resolved

Uh oh!

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

This branch was previously deployed

1 inactive deployment
azure-prod — a83f50f7 Deployed Nov 12, 2026 by peco-review-bot[bot] via followup #2099
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.