From 704be793a55a71e6e2f738a21764727f6e595658 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 1 Jun 2026 08:52:54 -0700 Subject: [PATCH] Revert "use arena for refresh loop" This reverts commit dbe487e0f4dc7ee8d635f42f41aca026d3f66e50. --- src/main.zig | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/src/main.zig b/src/main.zig index c6c4e26..51bc063 100644 --- a/src/main.zig +++ b/src/main.zig @@ -508,31 +508,27 @@ fn writeNewPortfolio(io: std.Io, allocator: std.mem.Allocator, path: []const u8, // ── Refresh command ────────────────────────────────────────── -fn refresh( - io: std.Io, - gpa: std.mem.Allocator, - environ: *const std.process.Environ.Map, -) !void { - var config = zfin.Config.fromEnv(io, gpa, environ); +fn refresh(io: std.Io, allocator: std.mem.Allocator, environ: *const std.process.Environ.Map) !void { + var config = zfin.Config.fromEnv(io, allocator, environ); defer config.deinit(); - var svc = zfin.DataService.init(io, gpa, config); + var svc = zfin.DataService.init(io, allocator, config); defer svc.deinit(); const portfolio_path = environ.get("ZFIN_PORTFOLIO") orelse "portfolio.srf"; - const data = std.Io.Dir.cwd().readFileAlloc(io, portfolio_path, gpa, .limited(10 * 1024 * 1024)) catch { + const data = std.Io.Dir.cwd().readFileAlloc(io, portfolio_path, allocator, .limited(10 * 1024 * 1024)) catch { log.err("failed to read portfolio: {s}", .{portfolio_path}); return error.ReadFailed; }; - defer gpa.free(data); + defer allocator.free(data); - var portfolio = zfin.cache.deserializePortfolio(gpa, data) catch { + var portfolio = zfin.cache.deserializePortfolio(allocator, data) catch { log.err("failed to parse portfolio", .{}); return error.ParseFailed; }; defer portfolio.deinit(); - var symbols = std.StringHashMap(void).init(gpa); + var symbols = std.StringHashMap(void).init(allocator); defer symbols.deinit(); for (portfolio.lots) |lot| { if (lot.security_type != .stock and lot.security_type != .watch) continue; @@ -581,25 +577,6 @@ fn refresh( try stdout.flush(); } - // Per-iteration scratch arena. Wraps the gpa so iteration-scoped - // allocations get freed in bulk via `reset(.retain_capacity)` at - // the bottom of each loop iteration — no per-allocation defers, - // no manual `free` mistakes. Capacity is retained so we're not - // re-acquiring pages every symbol. - // - // What goes through this arena: any per-iteration scratch we - // allocate ourselves (CIK dupes, future symbol-derived strings). - // NOT the `FetchResult` payloads — those are owned by the - // service's gpa and freed via `result.deinit()` at their own - // call sites. - // - // We don't use juicy-main's `init.arena` because that's - // process-lifetime; resetting it mid-run would clobber other - // startup allocations. - var iter_arena_state = std.heap.ArenaAllocator.init(gpa); - defer iter_arena_state.deinit(); - const iter_arena = iter_arena_state.allocator(); - var it = symbols.iterator(); while (it.next()) |entry| { const sym = entry.key_ptr.*; @@ -660,16 +637,14 @@ fn refresh( // had it — used to chain into entity_facts below. // NotFound is logged as `n/a` (symbol genuinely has no // Wikidata entry) and doesn't flip sym_ok. - // - // The CIK dupe goes through `iter_arena`. No defer-free - // needed — the arena is reset at end of iteration. - var cik_str: ?[]const u8 = null; + var cik_buf: ?[]u8 = null; + defer if (cik_buf) |b| allocator.free(b); try printRateLimitWait(&svc, stdout); if (svc.getClassification(sym, .{})) |result| { defer result.deinit(); if (result.data.len > 0) { if (result.data[0].cik) |cik| { - cik_str = iter_arena.dupe(u8, cik) catch null; + cik_buf = allocator.dupe(u8, cik) catch null; } } try stdout.print(", classification ok", .{}); @@ -703,7 +678,7 @@ fn refresh( // have an EDGAR CIK from the ticker map (production // zfin chains entity_facts off Wikidata's CIK, so the // server warms the cache the same way). - if (cik_str) |cik| { + if (cik_buf) |cik| { try printRateLimitWait(&svc, stdout); if (svc.getEntityFacts(cik, .{})) |result| { result.deinit(); @@ -721,10 +696,6 @@ fn refresh( try stdout.flush(); if (sym_ok) success_count += 1 else fail_count += 1; - - // Reset per-iteration scratch. Retains capacity so the - // next iteration's allocations reuse the same pages. - _ = iter_arena_state.reset(.retain_capacity); } try stdout.print("\nRefresh complete: {d} ok, {d} failed\n", .{ success_count, fail_count });