@muhkoo/connect 0.15.0-alpha.5 → 0.15.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6456,6 +6456,15 @@ async function safeText(response) {
6456
6456
  * manifest and reassembles the plaintext; {@link FileStorage.readFile} first
6457
6457
  * fetches the manifest from the space.
6458
6458
  */
6459
+ /**
6460
+ * How many chunks past the one being read a multi-chunk read fetches ahead
6461
+ * (see `chunksInOrder`). Two: enough to keep requests overlapping on a link
6462
+ * where each one waits on its round trip. While the caller holds chunk k,
6463
+ * up to `READ_AHEAD_CHUNKS + 1` more chunks can be in flight (the next
6464
+ * starts as k is handed over), so at the default 4 MB chunk about 16 MB of
6465
+ * reads in flight per file, on top of the chunk held.
6466
+ */
6467
+ const READ_AHEAD_CHUNKS = 2;
6459
6468
  class FileStorage {
6460
6469
  space;
6461
6470
  shards;
@@ -6561,11 +6570,10 @@ class FileStorage {
6561
6570
  await this.codec.ready(this.rsWasmModule);
6562
6571
  // Materialize each chunk into plaintext, then concatenate. We don't
6563
6572
  // stream across chunks here because the consuming surface returns
6564
- // `Uint8Array`; a streaming variant would reuse `readChunk` unchanged.
6573
+ // `Uint8Array`; `readChunksFromShards` is the streaming variant.
6565
6574
  const plaintextChunks = [];
6566
- for (const chunkManifest of [...manifest.chunks].sort((a, b) => a.chunkIndex - b.chunkIndex)) {
6567
- plaintextChunks.push(await this.readChunk(chunkManifest));
6568
- }
6575
+ for await (const chunk of this.chunksInOrder(manifest))
6576
+ plaintextChunks.push(chunk);
6569
6577
  let total = 0;
6570
6578
  for (const c of plaintextChunks)
6571
6579
  total += c.length;
@@ -6586,8 +6594,48 @@ class FileStorage {
6586
6594
  */
6587
6595
  async *readChunksFromShards(manifest) {
6588
6596
  await this.codec.ready(this.rsWasmModule);
6589
- for (const chunkManifest of [...manifest.chunks].sort((a, b) => a.chunkIndex - b.chunkIndex)) {
6590
- yield await this.readChunk(chunkManifest);
6597
+ yield* this.chunksInOrder(manifest);
6598
+ }
6599
+ /**
6600
+ * Each chunk's plaintext, in order, with the next {@link READ_AHEAD_CHUNKS}
6601
+ * already being fetched.
6602
+ *
6603
+ * One chunk at a time, a large file cost a full round trip per 4 MB chunk
6604
+ * with nothing overlapping it: a 33 MB file was eight serial requests,
6605
+ * each mostly waiting. Within a chunk the shard reads were already
6606
+ * parallel; this overlaps the chunks too.
6607
+ *
6608
+ * Bounded on purpose: while the caller holds a yielded chunk, at most
6609
+ * `1 + READ_AHEAD_CHUNKS` more are in flight, and nothing new starts until
6610
+ * it asks for the next — a slow consumer of the stream is not run away
6611
+ * from. A failure surfaces at its own chunk, in order; reads already
6612
+ * started past it are let finish, their failures swallowed rather than
6613
+ * left unhandled. If the caller stops early (`break` or `return()`), no
6614
+ * further read starts and the ones in flight settle on their own; they are
6615
+ * not awaited, so `return()` is not delayed by a slow shard.
6616
+ */
6617
+ async *chunksInOrder(manifest) {
6618
+ const ordered = [...manifest.chunks].sort((a, b) => a.chunkIndex - b.chunkIndex);
6619
+ const ahead = [];
6620
+ let next = 0;
6621
+ const start = () => {
6622
+ const read = this.readChunk(ordered[next++]);
6623
+ read.catch(() => { }); // reported when its turn comes
6624
+ ahead.push(read);
6625
+ };
6626
+ while (next < ordered.length && ahead.length < 1 + READ_AHEAD_CHUNKS)
6627
+ start();
6628
+ try {
6629
+ while (ahead.length > 0) {
6630
+ const chunk = await ahead.shift();
6631
+ if (next < ordered.length)
6632
+ start();
6633
+ yield chunk;
6634
+ }
6635
+ }
6636
+ finally {
6637
+ next = ordered.length; // nothing more is started
6638
+ ahead.length = 0; // in-flight reads settle unobserved; each has its own .catch
6591
6639
  }
6592
6640
  }
6593
6641
  // -------------------------------------------------------------------------
@@ -6855,7 +6903,7 @@ async function parseOrThrow(response, op) {
6855
6903
  * expect (and isn't serving a stale cached bundle). Keep this in sync with
6856
6904
  * `package.json` `version`.
6857
6905
  */
6858
- const VERSION = "0.15.0-alpha.5";
6906
+ const VERSION = "0.15.0-alpha.6";
6859
6907
 
6860
6908
  /**
6861
6909
  * `HttpClient` — the one place the unified {@link Client} talks to the