tiny.smg.command.check.refresh
Defined in command.check.
API (1)
Actions
Public operations.
Source
Source: tools/smg/src/command/check/refresh.zig
zig
const std = @import("std");const sql = @import("sql");const sys = @import("sys");const smg = @import("../../root.zig");const concepts = smg.concepts;const graph_mod = smg.graph;const scanner = smg.scan;const cli_options = smg.cli.options;const cli_output = smg.cli.output;const cli_scan = smg.command.scan;const cli_validation = smg.cli.validation;const storage = smg.storage;const runner = @import("run.zig");const ScanMode = enum { full, changed, matched };const signature = "[OPTIONS]";pub fn run(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, base_limits: smg.Limits) !u8 { if (try cli_validation.rejectMissingOptionValues(allocator, args, &.{ cli_options.max_source_file_bytes_option, cli_options.max_fragment_bytes_option, cli_options.max_git_file_list_bytes_option, cli_options.wal_recovery_limit_bytes_option, })) return 2; const limits = (try cli_validation.configuredLimitsOrReject( allocator, "refresh-check", signature, args, base_limits, )) orelse return 2; return runConfigured(allocator, phases, args, limits) catch |err| switch (err) { error.MaxSourceFileBytesExceeded => try cli_output.writeByteLimitExceeded( allocator, "max_source_file_bytes", limits.scan.max_source_file_bytes, cli_options.max_source_file_bytes_option, ), error.MaxFragmentBytesExceeded => try cli_output.writeByteLimitExceeded( allocator, "max_fragment_bytes", limits.scan.max_fragment_bytes, cli_options.max_fragment_bytes_option, ), error.MaxGitFileListBytesExceeded => try cli_output.writeByteLimitExceeded( allocator, "max_git_file_list_bytes", limits.scan.max_git_file_list_bytes, cli_options.max_git_file_list_bytes_option, ), error.WalRecoveryLimitBytesExceeded => try cli_output.writeByteLimitExceeded( allocator, "wal_recovery_limit_bytes", limits.storage.wal_recovery_limit_bytes, cli_options.wal_recovery_limit_bytes_option, ), else => return err, };}fn runConfigured(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits) !u8 { const total_started = sys.time.nanoTimestamp(); var phase_started = total_started; const root = try storage.initProject(allocator, null, limits.storage); const rules_path = try storage.files.rulesPath(allocator, root); try cli_output.writeErr(try cli_scan.refreshStartLine(allocator, root, rules_path)); const source = try loadSource(allocator, phases, root, limits.storage); const snapshot_ns = elapsedNanoseconds(&phase_started); var refreshed = try refreshGraph(allocator, phases, root, source.head, limits); defer refreshed.manifest.deinit(); const source_verify_ns = try verifySource(allocator, phases, root, &refreshed, limits); if (cli_options.hasFlag(args, "--scan") or cli_options.hasFlag(args, "--full")) { _ = try cli_output.writeOut(try cli_scan.renderText( allocator, refreshed.stats, cli_options.hasFlag(args, "--full"), )); } try cli_output.writeErr("refresh-check: check rules\n"); phase_started = sys.time.nanoTimestamp(); const result = try runner.run(allocator, root, refreshed.graph, source.concepts, args, limits); const rule_ns = elapsedNanoseconds(&phase_started); if (cli_options.hasFlag(args, "--timing")) { try cli_output.writeErr(try timingLine(allocator, .{ .total_ns = sinceNanoseconds(total_started), .snapshot_ns = snapshot_ns, .source_state_ns = refreshed.source_state_ns, .graph_load_ns = refreshed.graph_load_ns, .scan_ns = refreshed.scan_ns, .source_verify_ns = source_verify_ns, .scan_mode = refreshed.mode, .cache = refreshed.cache_timing, .publish = refreshed.publish, .rule_ns = rule_ns, })); } return result;}const SourceSnapshot = struct { head: sql.Hash, concepts: []const concepts.Concept,};fn loadSource( allocator: std.mem.Allocator, phases: std.mem.Allocator, root: []const u8, limits: smg.StorageLimits,) !SourceSnapshot { var opened = try storage.store.openRead(phases, root, limits); defer opened.close(); return .{ .head = opened.reader.head, .concepts = try concepts.loadFromReader(allocator, &opened.reader), };}const RefreshedGraph = struct { graph: graph_mod.Graph, stats: scanner.Stats, project: ?scanner.scan_files.ProjectState, executable: ?scanner.scan_files.SourceDigest, manifest: scanner.fragment.Manifest, mode: ScanMode, cache_timing: scanner.CachedProjectTiming, publish: storage.graph.PublishTiming, source_state_ns: u64, graph_load_ns: u64, scan_ns: u64,};fn refreshGraph( allocator: std.mem.Allocator, phases: std.mem.Allocator, root: []const u8, head: sql.Hash, limits: smg.Limits,) !RefreshedGraph { var phase_started = sys.time.nanoTimestamp(); const executable = storage.source.executableDigest(allocator) catch null; const stored_project = if (executable) |identity| try storage.source.projectForOwner(allocator, root, head, identity) else null; const project = scanner.scan_files.projectState(allocator, phases, root, &.{}, limits.scan) catch null; var manifest = if (executable) |identity| try scanner.fragment.loadManifest(allocator, phases, root, identity, limits.scan) else scanner.fragment.Manifest.empty(allocator); errdefer manifest.deinit(); const mode: ScanMode = if (stored_project != null and project != null and std.mem.eql(u8, &stored_project.?, &project.?.project.digest)) .matched else if (stored_project != null and project != null and manifest.matchesProject(stored_project.?)) .changed else .full; const changed_paths: []const []const u8 = if (mode == .changed) try manifest.changedPaths(allocator, root, project.?.sources) else &.{}; const source_state_ns = elapsedNanoseconds(&phase_started); var graph = switch (mode) { .full => graph_mod.init(allocator), .changed, .matched => try storage.graph.load(allocator, phases, root, limits.storage), }; const graph_load_ns = elapsedNanoseconds(&phase_started); var cache_timing: scanner.CachedProjectTiming = .{}; const stats = try scanGraph( allocator, phases, &graph, root, project, executable, changed_paths, mode, &cache_timing, limits, ); const scan_ns = elapsedNanoseconds(&phase_started); try writeProgress(allocator, mode, stats, changed_paths.len, project); const publish = switch (mode) { .full, .changed => try storage.graph.publishTimed(phases, root, graph, head, limits), .matched => try storage.graph.publishMatchedTimed(phases, root, graph, head, limits), }; return .{ .graph = graph, .stats = stats, .project = project, .executable = executable, .manifest = manifest, .mode = mode, .cache_timing = cache_timing, .publish = publish, .source_state_ns = source_state_ns, .graph_load_ns = graph_load_ns, .scan_ns = scan_ns, };}fn scanGraph( allocator: std.mem.Allocator, phases: std.mem.Allocator, graph: *graph_mod.Graph, root: []const u8, project: ?scanner.scan_files.ProjectState, executable: ?scanner.scan_files.SourceDigest, changed_paths: []const []const u8, mode: ScanMode, cache_timing: *scanner.CachedProjectTiming, limits: smg.Limits,) !scanner.Stats { return switch (mode) { .full => if (executable != null and project != null) cached: { const cached = try scanner.scanProjectCached( allocator, phases, graph, root, project.?, executable.?, limits, ); cache_timing.* = cached.timing; break :cached cached.stats; } else try scanner.scanPathsWithOptions( allocator, graph, root, &.{}, false, .{ .limits = limits, .phases = phases }, ), .changed => if (changed_paths.len == 0) scanner.Stats{} else try scanner.scanPathsWithOptions( allocator, graph, root, changed_paths, true, .{ .limits = limits, .phases = phases }, ), .matched => scanner.Stats{}, };}fn writeProgress( allocator: std.mem.Allocator, mode: ScanMode, stats: scanner.Stats, changed_files: usize, project: ?scanner.scan_files.ProjectState,) !void { const line = switch (mode) { .full => try cli_scan.refreshAbsentLine(allocator, stats), .changed => try cli_scan.refreshChangedLine(allocator, changed_files), .matched => try cli_scan.refreshMatchedLine(allocator, project.?.project.files), }; try cli_output.writeErr(line);}fn verifySource( allocator: std.mem.Allocator, phases: std.mem.Allocator, root: []const u8, refreshed: *RefreshedGraph, limits: smg.Limits,) !u64 { const started = sys.time.nanoTimestamp(); const expected = if (refreshed.project) |project| project.project.digest else null; const verified = if (refreshed.executable != null and expected != null) scanner.scan_files.projectIdentity(allocator, phases, root, &.{}, limits.scan) catch null else null; if (refreshed.executable != null and expected != null and verified != null and std.mem.eql(u8, &expected.?, &verified.?.digest)) { try updateSourceCaches(allocator, phases, root, refreshed, verified.?.digest, limits); } else if (refreshed.executable != null) { try cli_output.writeErr("refresh-check: source changed during refresh; next refresh will scan fully\n"); } return sinceNanoseconds(started);}fn updateSourceCaches( allocator: std.mem.Allocator, phases: std.mem.Allocator, root: []const u8, refreshed: *RefreshedGraph, verified: scanner.scan_files.SourceDigest, limits: smg.Limits,) !void { if (refreshed.mode == .changed) { const started = sys.time.nanoTimestamp(); _ = scanner.fragment.writeManifest( allocator, phases, root, refreshed.executable.?, refreshed.project.?.project, &refreshed.manifest, refreshed.project.?.sources, limits.scan, ) catch { try cli_output.writeErr( "refresh-check: source snapshot cache unavailable; next change will scan fully\n", ); }; refreshed.cache_timing.manifest_write_ns += sinceNanoseconds(started); } storage.source.writeForHead( allocator, root, refreshed.publish.head, refreshed.executable.?, verified, ) catch try cli_output.writeErr( "refresh-check: source identity cache unavailable; next refresh will scan fully\n", );}const Timing = struct { total_ns: u64, snapshot_ns: u64, source_state_ns: u64, graph_load_ns: u64, scan_ns: u64, source_verify_ns: u64, scan_mode: ScanMode, cache: scanner.CachedProjectTiming, publish: storage.graph.PublishTiming, rule_ns: u64,};fn timingLine(allocator: std.mem.Allocator, timing: Timing) ![]const u8 { return try std.fmt.allocPrint( allocator, "refresh-check timing total_ms={d} snapshot_ms={d} source_state_ms={d} graph_load_ms={d} scan_ms={d} source_verify_ms={d} scan_mode={s} " ++ "fragment_manifest_ms={d} fragment_read_ms={d} fragment_validation_ms={d} fragment_fold_ms={d} fragment_scan_ms={d} " ++ "suffix_index_ms={d} resolution_ms={d} call_metrics_ms={d} fragment_manifest_write_ms={d} " ++ "graph_encode_ms={d} summary_encode_ms={d} index_encode_ms={d} index_mode={s} " ++ "node_puts={d} node_deletes={d} edge_puts={d} edge_deletes={d} " ++ "atomic_publish_ms={d} rule_evaluation_ms={d}\n", .{ milliseconds(timing.total_ns), milliseconds(timing.snapshot_ns), milliseconds(timing.source_state_ns), milliseconds(timing.graph_load_ns), milliseconds(timing.scan_ns), milliseconds(timing.source_verify_ns), @tagName(timing.scan_mode), milliseconds(timing.cache.manifest_ns), milliseconds(timing.cache.fragment_read_ns), milliseconds(timing.cache.fragment_validation_ns), milliseconds(timing.cache.fragment_fold_ns), milliseconds(timing.cache.fragment_scan_ns), milliseconds(timing.cache.suffix_index_ns), milliseconds(timing.cache.resolution_ns), milliseconds(timing.cache.call_metrics_ns), milliseconds(timing.cache.manifest_write_ns), milliseconds(timing.publish.graph_ns), milliseconds(timing.publish.summary_ns), milliseconds(timing.publish.index_ns), @tagName(timing.publish.index_kind), timing.publish.node_puts, timing.publish.node_deletes, timing.publish.edge_puts, timing.publish.edge_deletes, milliseconds(timing.publish.atomicNanoseconds()), milliseconds(timing.rule_ns), }, );}fn elapsedNanoseconds(started: *i128) u64 { const finished = sys.time.nanoTimestamp(); std.debug.assert(finished >= started.*); const elapsed: u64 = @intCast(finished - started.*); started.* = finished; return elapsed;}fn sinceNanoseconds(started: i128) u64 { const finished = sys.time.nanoTimestamp(); std.debug.assert(finished >= started); return @intCast(finished - started);}fn milliseconds(nanoseconds: u64) u64 { return nanoseconds / std.time.ns_per_ms;}test "refresh timing names complete owner phases" { const rendered = try timingLine(std.testing.allocator, .{ .total_ns = 36 * std.time.ns_per_ms, .snapshot_ns = 1 * std.time.ns_per_ms, .source_state_ns = 2 * std.time.ns_per_ms, .graph_load_ns = 3 * std.time.ns_per_ms, .scan_ns = 2 * std.time.ns_per_ms, .source_verify_ns = 4 * std.time.ns_per_ms, .scan_mode = .matched, .cache = .{ .manifest_ns = 5 * std.time.ns_per_ms, .fragment_read_ns = 6 * std.time.ns_per_ms, .fragment_validation_ns = 7 * std.time.ns_per_ms, .fragment_fold_ns = 8 * std.time.ns_per_ms, .fragment_scan_ns = 9 * std.time.ns_per_ms, .suffix_index_ns = 10 * std.time.ns_per_ms, .resolution_ns = 11 * std.time.ns_per_ms, .call_metrics_ns = 12 * std.time.ns_per_ms, .manifest_write_ns = 13 * std.time.ns_per_ms, }, .publish = .{ .head = @splat(0), .begin_ns = 3 * std.time.ns_per_ms, .graph_ns = 4 * std.time.ns_per_ms, .summary_ns = 5 * std.time.ns_per_ms, .index_ns = 6 * std.time.ns_per_ms, .index_kind = .incremental, .node_puts = 9, .node_deletes = 10, .edge_puts = 11, .edge_deletes = 12, .finish_ns = 7 * std.time.ns_per_ms, }, .rule_ns = 8 * std.time.ns_per_ms, }); defer std.testing.allocator.free(rendered); try std.testing.expectEqualStrings( "refresh-check timing total_ms=36 snapshot_ms=1 source_state_ms=2 graph_load_ms=3 scan_ms=2 source_verify_ms=4 scan_mode=matched " ++ "fragment_manifest_ms=5 fragment_read_ms=6 fragment_validation_ms=7 fragment_fold_ms=8 fragment_scan_ms=9 " ++ "suffix_index_ms=10 resolution_ms=11 call_metrics_ms=12 fragment_manifest_write_ms=13 " ++ "graph_encode_ms=4 summary_encode_ms=5 index_encode_ms=6 index_mode=incremental " ++ "node_puts=9 node_deletes=10 edge_puts=11 edge_deletes=12 " ++ "atomic_publish_ms=10 rule_evaluation_ms=8\n", rendered, );}Source: tools/smg/src/command/check/root.zig:2
zig
pub const refresh = @import("refresh.zig");Audit
| Definitions | 2 |
|---|---|
| Public names | 2 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |