diff options
author | 2022-11-12 18:32:53 -0800 | |
---|---|---|
committer | 2022-11-12 18:32:53 -0800 | |
commit | 1cce9da80a51d49e423223f24f94fee6a044ab10 (patch) | |
tree | 56daa58619a6544ec6a6a60334e2db051f7a274b /src | |
parent | 21bf3ddaf23c842dc12a1d76dbd3b48daf08f349 (diff) | |
download | bun-1cce9da80a51d49e423223f24f94fee6a044ab10.tar.gz bun-1cce9da80a51d49e423223f24f94fee6a044ab10.tar.zst bun-1cce9da80a51d49e423223f24f94fee6a044ab10.zip |
Fix memory leak in gzip pool + add test for gzip'd data
Diffstat (limited to 'src')
-rw-r--r-- | src/http/zlib.zig | 61 | ||||
-rw-r--r-- | src/http_client_async.zig | 15 |
2 files changed, 16 insertions, 60 deletions
diff --git a/src/http/zlib.zig b/src/http/zlib.zig index f6ada0452..4a2e88bec 100644 --- a/src/http/zlib.zig +++ b/src/http/zlib.zig @@ -4,65 +4,26 @@ const MutableString = @import("../global.zig").MutableString; const getAllocator = @import("../http_client_async.zig").getAllocator; const ZlibPool = @This(); const Zlib = @import("../zlib.zig"); +const bun = @import("../global.zig"); -lock: Lock = Lock.init(), -items: std.ArrayList(*MutableString), -allocator: std.mem.Allocator, - -pub var instance: ZlibPool = undefined; -pub var loaded: bool = false; - -pub fn init(allocator: std.mem.Allocator) ZlibPool { - return ZlibPool{ - .allocator = allocator, - .items = std.ArrayList(*MutableString).init(allocator), - }; +fn initMutableString(allocator: std.mem.Allocator) anyerror!MutableString { + return MutableString.initEmpty(allocator); } -pub fn get(this: *ZlibPool) !*MutableString { - std.debug.assert(loaded); - - switch (this.items.items.len) { - 0 => { - var mutable = try getAllocator().create(MutableString); - mutable.* = try MutableString.init(getAllocator(), 0); - return mutable; - }, - else => { - return this.items.pop(); - }, - } +const BufferPool = bun.ObjectPool(MutableString, initMutableString, false, 4); - unreachable; +pub fn get(allocator: std.mem.Allocator) *MutableString { + return &BufferPool.get(allocator).data; } -pub fn put(this: *ZlibPool, mutable: *MutableString) !void { - std.debug.assert(loaded); +pub fn put(mutable: *MutableString) void { mutable.reset(); - try this.items.append(mutable); + var node = @fieldParentPtr(BufferPool.Node, "data", mutable); + node.release(); } pub fn decompress(compressed_data: []const u8, output: *MutableString) Zlib.ZlibError!void { - // Heuristic: if we have more than 128 KB of data to decompress - // it may take 1ms or so - // We must keep the network thread unblocked as often as possible - // So if we have more than 50 KB of data to decompress, we do it off the network thread - // if (compressed_data.len < 50_000) { - var reader = try Zlib.ZlibReaderArrayList.init(compressed_data, &output.list, getAllocator()); + var reader = try Zlib.ZlibReaderArrayList.init(compressed_data, &output.list, output.allocator); try reader.readAll(); - return; - // } - - // var task = try DecompressionTask.get(default_allocator); - // defer task.release(); - // task.* = DecompressionTask{ - // .data = compressed_data, - // .output = output, - // .event_fd = AsyncIO.global.eventfd(), - // }; - // task.scheduleAndWait(); - - // if (task.err) |err| { - // return @errSetCast(Zlib.ZlibError, err); - // } + reader.deinit(); } diff --git a/src/http_client_async.zig b/src/http_client_async.zig index 495a3889f..06903db3a 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -652,7 +652,7 @@ pub const InternalState = struct { } if (this.compressed_body) |body| { - ZlibPool.instance.put(body) catch unreachable; + ZlibPool.put(body); this.compressed_body = null; } @@ -666,12 +666,7 @@ pub const InternalState = struct { switch (this.encoding) { Encoding.gzip, Encoding.deflate => { if (this.compressed_body == null) { - if (!ZlibPool.loaded) { - ZlibPool.instance = ZlibPool.init(default_allocator); - ZlibPool.loaded = true; - } - - this.compressed_body = ZlibPool.instance.get() catch unreachable; + this.compressed_body = ZlibPool.get(default_allocator); } return this.compressed_body.?; @@ -695,8 +690,8 @@ pub const InternalState = struct { gzip_timer = std.time.Timer.start() catch @panic("Timer failure"); body_out_str.list.expandToCapacity(); - defer ZlibPool.instance.put(buffer_) catch unreachable; - ZlibPool.decompress(buffer.list.items, body_out_str) catch |err| { + defer ZlibPool.put(buffer_); + ZlibPool.decompress(buffer_.list.items, body_out_str) catch |err| { Output.prettyErrorln("<r><red>Zlib error<r>", .{}); Output.flush(); return err; @@ -1725,7 +1720,7 @@ pub fn handleResponseBody(this: *HTTPClient, incoming_data: []const u8) !bool { buffer.list.ensureTotalCapacityPrecise(buffer.allocator, this.state.body_size) catch {}; } - const remaining_content_length = this.state.body_size - buffer.list.items.len; + const remaining_content_length = this.state.body_size -| buffer.list.items.len; var remainder = incoming_data[0..@minimum(incoming_data.len, remaining_content_length)]; _ = try buffer.write(remainder); |