fix(streams): don't lose bytes on drain (#9768)

* fix

* clear

* update

* test

* fix test

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
Dylan Conway
2024-04-01 05:23:47 -07:00
committed by GitHub
parent 2dd2fc6ed0
commit 6e07f9477c
4 changed files with 30 additions and 3 deletions

View File

@@ -3749,6 +3749,9 @@ pub const FileReader = struct {
if (!bun.isSliceInBuffer(buf, this.buffered.allocatedSlice())) {
if (this.reader.isDone()) {
if (bun.isSliceInBuffer(buf, this.reader.buffer().allocatedSlice())) {
this.reader.buffer().* = std.ArrayList(u8).init(bun.default_allocator);
}
this.pending.result = .{
.temporary_and_done = bun.ByteList.init(buf),
};
@@ -3756,6 +3759,10 @@ pub const FileReader = struct {
this.pending.result = .{
.temporary = bun.ByteList.init(buf),
};
if (bun.isSliceInBuffer(buf, this.reader.buffer().allocatedSlice())) {
this.reader.buffer().clearRetainingCapacity();
}
}
this.pending_value.clear();
@@ -3780,6 +3787,9 @@ pub const FileReader = struct {
return !was_done;
} else if (!bun.isSliceInBuffer(buf, this.buffered.allocatedSlice())) {
this.buffered.appendSlice(bun.default_allocator, buf) catch bun.outOfMemory();
if (bun.isSliceInBuffer(buf, this.reader.buffer().allocatedSlice())) {
this.reader.buffer().clearRetainingCapacity();
}
}
// For pipes, we have to keep pulling or the other process will block.
@@ -3886,6 +3896,9 @@ pub const FileReader = struct {
if (this.buffered.items.len > 0) {
const out = bun.ByteList.init(this.buffered.items);
this.buffered = .{};
if (comptime Environment.allow_assert) {
std.debug.assert(this.reader.buffer().items.ptr != out.ptr);
}
return out;
}
@@ -3893,7 +3906,7 @@ pub const FileReader = struct {
return .{};
}
const out = this.reader.buffer();
const out = this.reader.buffer().*;
this.reader.buffer().* = std.ArrayList(u8).init(bun.default_allocator);
return bun.ByteList.fromList(out);
}

View File

@@ -339,7 +339,7 @@ pub fn WindowsPipeReader(
var this = bun.cast(*This, stream.data);
const nread_int = nread.int();
bun.sys.syslog("onStreamRead() = {d}", .{nread_int});
bun.sys.syslog("onStreamRead(0x{d}) = {d}", .{ @intFromPtr(this), nread_int });
// NOTE: pipes/tty need to call stopReading on errors (yeah)
switch (nread_int) {

View File

@@ -1656,7 +1656,7 @@ export function lazyLoadStream(stream, autoAllocateChunkSize) {
$assert(controller, "controller is missing");
if (result && $isPromise(result)) {
return result.then(
return result.$then(
handleNativeReadableStreamPromiseResult.bind({
c: controller,
v: view,

View File

@@ -490,6 +490,20 @@ for (let [gcTick, label] of [
});
});
}
it("should allow reading stdout after a few milliseconds", async () => {
for (let i = 0; i < 50; i++) {
const proc = Bun.spawn({
cmd: ["git", "--version"],
stdout: "pipe",
stderr: "ignore",
stdin: "ignore",
});
await Bun.sleep(1);
const out = await Bun.readableStreamToText(proc.stdout);
expect(out).not.toBe("");
}
});
});
it("throws errors for invalid arguments", async () => {