From b6b67f8dd688ca51eab80340a23e8a27f7334623 Mon Sep 17 00:00:00 2001 From: Bob Farrell Date: Fri, 24 May 2024 19:13:25 +0100 Subject: [PATCH] Use http.zig arena pool --- build.zig | 3 +++ build.zig.zon | 4 ++-- demo/src/main.zig | 5 +++-- src/jetzig.zig | 13 +++++++++++++ src/jetzig/http/Request.zig | 18 +----------------- src/jetzig/http/Server.zig | 24 ++++++++++-------------- src/jetzig/loggers/DevelopmentLogger.zig | 2 ++ 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/build.zig b/build.zig index a0f535c..1afc7e5 100644 --- a/build.zig +++ b/build.zig @@ -115,6 +115,9 @@ pub fn jetzigInit(b: *std.Build, exe: *std.Build.Step.Compile, options: JetzigIn const target = b.host; const optimize = exe.root_module.optimize orelse .Debug; + + if (optimize != .Debug) exe.linkLibC(); + const jetzig_dep = b.dependency( "jetzig", .{ .optimize = optimize, .target = target }, diff --git a/build.zig.zon b/build.zig.zon index db5bd28..c506570 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -23,8 +23,8 @@ .hash = "1220d4f1c2472769b0d689ea878f41f0a66cb07f28569a138aea2c0a648a5c90dd4e", }, .httpz = .{ - .url = "https://github.com/karlseguin/http.zig/archive/4ed728d21999ffcb11cc0b0604dcebc9e02cfc17.tar.gz", - .hash = "122010547ef8bbc781372311b66ce72b297c4e61e3423437825da076055ff9c07bb4", + .url = "https://github.com/karlseguin/http.zig/archive/f3ad561fd23262c3f9b8081ff7bb8a5ded0e74bd.tar.gz", + .hash = "1220ea0d5860657d59cf1ca0fe0e553bfabc7d9cd467005488155baffb1ddf65ecf2", }, }, diff --git a/demo/src/main.zig b/demo/src/main.zig index 685efd1..df13950 100644 --- a/demo/src/main.zig +++ b/demo/src/main.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const jetzig = @import("jetzig"); const zmd = @import("zmd"); @@ -163,8 +164,8 @@ pub const jetzig_options = struct { pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer std.debug.assert(gpa.deinit() == .ok); - const allocator = gpa.allocator(); + const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator; + defer if (builtin.mode == .Debug) std.debug.assert(gpa.deinit() == .ok); const app = try jetzig.init(allocator); defer app.deinit(); diff --git a/src/jetzig.zig b/src/jetzig.zig index 57255bf..2ce95ec 100644 --- a/src/jetzig.zig +++ b/src/jetzig.zig @@ -98,6 +98,19 @@ pub const config = struct { /// freed instead of recycled. pub const max_log_pool_len: usize = 256; + /// Number of request threads. Defaults to number of detected CPUs. + pub const thread_count: ?u16 = null; + + /// Number of response worker threads. + pub const worker_count: u16 = 4; + + /// Total number of connections managed by worker threads. + pub const max_connections: u16 = 512; + + /// The size of each item in the available memory pool used by requests for rendering. + /// Total retained allocation: `worker_count * max_connections`. + pub const arena_size: usize = 1024 * 1024; + /// Path relative to cwd() to serve public content from. Symlinks are not followed. pub const public_content_path = "public"; diff --git a/src/jetzig/http/Request.zig b/src/jetzig/http/Request.zig index 6dbbb5c..416fe71 100644 --- a/src/jetzig/http/Request.zig +++ b/src/jetzig/http/Request.zig @@ -141,23 +141,8 @@ pub fn process(self: *Request) !void { self.processed = true; } -pub const CallbackState = struct { - arena: *std.heap.ArenaAllocator, - allocator: std.mem.Allocator, -}; - -pub fn responseCompleteCallback(ptr: *anyopaque) void { - var state: *CallbackState = @ptrCast(@alignCast(ptr)); - state.arena.deinit(); - state.allocator.destroy(state.arena); - state.allocator.destroy(state); -} - /// Set response headers, write response payload, and finalize the response. -pub fn respond( - self: *Request, - state: *CallbackState, -) !void { +pub fn respond(self: *Request) !void { if (!self.processed) unreachable; try self.setCookieHeaders(); @@ -165,7 +150,6 @@ pub fn respond( const status = jetzig.http.status_codes.get(self.response.status_code); self.httpz_response.status = try status.getCodeInt(); self.httpz_response.body = self.response.content; - self.httpz_response.callback(responseCompleteCallback, @ptrCast(state)); } /// Render a response. This function can only be called once per request (repeat calls will diff --git a/src/jetzig/http/Server.zig b/src/jetzig/http/Server.zig index 9eafcd6..413854f 100644 --- a/src/jetzig/http/Server.zig +++ b/src/jetzig/http/Server.zig @@ -81,7 +81,14 @@ pub fn listen(self: *Server) !void { .{ .port = self.options.port, .address = self.options.bind, - .thread_pool = .{ .count = @intCast(try std.Thread.getCpuCount()) }, + .thread_pool = .{ + .count = jetzig.config.get(?u16, "thread_count") orelse @intCast(try std.Thread.getCpuCount()), + }, + .workers = .{ + .count = jetzig.config.get(u16, "worker_count"), + .max_conn = jetzig.config.get(u16, "max_connections"), + .retain_allocated_bytes = jetzig.config.get(usize, "arena_size"), + }, }, Dispatcher{ .server = self }, ); @@ -112,18 +119,7 @@ fn processNextRequest( ) !void { const start_time = std.time.nanoTimestamp(); - const state = try self.allocator.create(jetzig.http.Request.CallbackState); - const arena = try self.allocator.create(std.heap.ArenaAllocator); - arena.* = std.heap.ArenaAllocator.init(self.allocator); - state.* = .{ - .arena = arena, - .allocator = self.allocator, - }; - - // Regular arena deinit occurs in jetzig.http.Request.responseCompletCallback - errdefer state.arena.deinit(); - - const allocator = state.arena.allocator(); + const allocator = httpz_request.arena; var response = try jetzig.http.Response.init(allocator, httpz_response); var request = try jetzig.http.Request.init( @@ -144,7 +140,7 @@ fn processNextRequest( try jetzig.http.middleware.beforeResponse(&middleware_data, &request); - try request.respond(state); + try request.respond(); try jetzig.http.middleware.afterResponse(&middleware_data, &request); jetzig.http.middleware.deinit(&middleware_data, &request); diff --git a/src/jetzig/loggers/DevelopmentLogger.zig b/src/jetzig/loggers/DevelopmentLogger.zig index 2f9135f..3d3e722 100644 --- a/src/jetzig/loggers/DevelopmentLogger.zig +++ b/src/jetzig/loggers/DevelopmentLogger.zig @@ -56,6 +56,8 @@ pub fn log( /// Log a one-liner including response status code, path, method, duration, etc. pub fn logRequest(self: DevelopmentLogger, request: *const jetzig.http.Request) !void { + if (@intFromEnum(LogLevel.INFO) < @intFromEnum(self.level)) return; + var duration_buf: [256]u8 = undefined; const formatted_duration = try jetzig.colors.duration( &duration_buf,