adriangb opened a new pull request, #808:
URL: https://github.com/apache/arrow-rs-object-store/pull/808

   # Which issue does this PR close?
   
   No separate issue is filed; the bug and repro are described in full below.
   
   # Rationale for this change
   
   `ThrottledStore` is the crate's built-in wrapper for performance testing (it 
injects `wait_get_per_call` first-byte latency, `wait_get_per_byte` throughput 
throttling, and so on). But it panics with `not implemented` on the first 
`get`/`get_opts`/`head` when it wraps a store that returns a file-backed 
payload, which is exactly what `LocalFileSystem` does when the `fs` feature is 
enabled, and `LocalFileSystem` is the obvious inner store you would want to 
throttle for perf testing.
   
   Every `get_opts` result is funnelled through the free function 
`throttle_get` in `src/throttle.rs`, whose payload match was:
   
   ```rust
   GetResultPayload::File(_, _) => unimplemented!(),
   ```
   
   `LocalFileSystem::get_opts` returns `GetResultPayload::File(..)`, so the 
first read hits `unimplemented!()`.
   
   Note that the fixed per-call latency already worked for File payloads 
(`sleep(wait_get_per_call)` runs before the inner call in `get_opts`), and 
`get_ranges` already worked (it delegates directly). Only the per-byte 
stream-wrapping step in `throttle_get` panicked.
   
   Minimal repro:
   
   ```rust
   use object_store::{throttle::{ThrottledStore, ThrottleConfig}, 
local::LocalFileSystem, ObjectStore, path::Path};
   
   let dir = tempfile::TempDir::new().unwrap();
   let store = ThrottledStore::new(
       LocalFileSystem::new_with_prefix(dir.path()).unwrap(),
       ThrottleConfig::default(),
   );
   let path = Path::from("file.txt");
   store.put(&path, "hello".into()).await.unwrap();
   store.get(&path).await.unwrap(); // panics: not implemented
   ```
   
   # What changes are included in this PR?
   
   `throttle_get` now handles the File payload instead of panicking. The design 
preserves the local-file fast path rather than forcing every File read into a 
byte stream just so it can be throttled:
   
   - For a `Stream` payload, behavior is byte-for-byte unchanged: the per-byte 
throttle is applied lazily per chunk as before.
   - For a `File` payload, the per-byte component is applied as a single eager 
sleep computed from the known requested range (`result.range`), mirroring how 
`get_ranges` already throttles a whole vectored read up front, and then the 
File payload is returned untouched. Because `sleep` is a no-op on a zero 
duration, the common case where only `wait_get_per_call` is set (and 
`wait_get_per_byte` is zero) passes the File payload straight through with no 
allocation or stream conversion.
   
   `throttle_get` becomes `async` so the File-path sleep can be awaited; the 
single caller in `get_opts` awaits it.
   
   A regression test (`get_local_file_system`) wraps a real `LocalFileSystem` 
in a `ThrottledStore` with non-zero per-call and per-byte waits, reads an 
object back, asserts the payload is still a `File` (fast path preserved), and 
asserts the bytes are correct. This test panics on the previous code and passes 
now.
   
   # Are there any user-facing changes?
   
   Yes, a bug fix: `ThrottledStore` no longer panics when wrapping a store that 
returns a `GetResultPayload::File` (e.g. `LocalFileSystem`). No public API 
changes; `throttle_get` is a private function.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to