tiny.smg.storage.names
Defined in storage.
API (6)
Actions
Public operations.
Values and defaults
Public values and defaults.
Source
Source: tools/smg/src/storage/names.zig
zig
const std = @import("std");const sql = @import("sql");const sys = @import("sys");const smg = @import("../root.zig");const storage = smg.storage;const fs_io = std.Options.debug_io;pub const file_name = "names.bin";pub const temp_file_name = "names.bin.tmp";const magic = "tiny.smg.names/v1\n";const digest_bytes = std.crypto.hash.sha2.Sha256.digest_length;const read_buffer_bytes = 64 * 1024;const write_buffer_bytes = 64 * 1024;const max_cache_bytes: u64 = 512 * 1024 * 1024;const header_bytes = magic.len + @sizeOf(sql.Hash) + @sizeOf(u64);const minimum_file_bytes = header_bytes + digest_bytes;pub fn matchesHead( allocator: std.mem.Allocator, root: []const u8, expected: sql.Hash,) std.mem.Allocator.Error!bool { const path = try cachePath(allocator, root, file_name); defer allocator.free(path); var file = std.Io.Dir.openFileAbsolute(fs_io, path, .{}) catch return false; defer file.close(fs_io); const stat = file.stat(fs_io) catch return false; if (stat.kind != .file or stat.size < minimum_file_bytes) return false; if (stat.size > max_cache_bytes) return false; var header: [header_bytes]u8 = undefined; const read = file.readPositionalAll(fs_io, &header, 0) catch return false; if (read != header.len) return false; if (!std.mem.eql(u8, header[0..magic.len], magic)) return false; return std.mem.eql( u8, header[magic.len .. magic.len + @sizeOf(sql.Hash)], expected[0..], );}pub fn scan( allocator: std.mem.Allocator, root: []const u8, expected: sql.Hash, visitor: anytype,) !void { const path = try cachePath(allocator, root, file_name); defer allocator.free(path); var file = try std.Io.Dir.openFileAbsolute(fs_io, path, .{}); defer file.close(fs_io); const stat = try file.stat(fs_io); if (stat.kind != .file or stat.size < minimum_file_bytes) { return error.InvalidNameProjection; } if (stat.size > max_cache_bytes) return error.InvalidNameProjection; var read_buffer: [read_buffer_bytes]u8 = undefined; var file_reader = file.reader(fs_io, &read_buffer); const reader = &file_reader.interface; var stored_magic: [magic.len]u8 = undefined; try readExact(reader, &stored_magic); if (!std.mem.eql(u8, &stored_magic, magic)) return error.InvalidNameProjection; var stored_head: sql.Hash = undefined; try readExact(reader, &stored_head); if (!std.mem.eql(u8, &stored_head, &expected)) return error.StaleNameProjection; var count_bytes: [@sizeOf(u64)]u8 = undefined; try readExact(reader, &count_bytes); const count = std.mem.readInt(u64, &count_bytes, .big); const entry_bytes = stat.size - minimum_file_bytes; if (count > entry_bytes / @sizeOf(u32)) return error.InvalidNameProjection; var hasher = std.crypto.hash.sha2.Sha256.init(.{}); var name_buffer: [sql.page.size]u8 = undefined; var index: u64 = 0; while (index < count) : (index += 1) { var length_bytes: [@sizeOf(u32)]u8 = undefined; try readExact(reader, &length_bytes); hasher.update(&length_bytes); const length: usize = @intCast(std.mem.readInt(u32, &length_bytes, .big)); if (length == 0 or length > name_buffer.len) return error.InvalidNameProjection; const name = name_buffer[0..length]; try readExact(reader, name); hasher.update(name); try visitor.visit(name); } var stored_digest: [digest_bytes]u8 = undefined; try readExact(reader, &stored_digest); var computed_digest: [digest_bytes]u8 = undefined; hasher.final(&computed_digest); if (!std.mem.eql(u8, &stored_digest, &computed_digest)) { return error.InvalidNameProjection; } _ = reader.takeByte() catch |err| switch (err) { error.EndOfStream => return, else => return error.InvalidNameProjection, }; return error.InvalidNameProjection;}pub fn writeForHead( allocator: std.mem.Allocator, root: []const u8, database: *storage.database.Database, head: sql.Hash,) !void { const temporary = try cachePath(allocator, root, temp_file_name); defer allocator.free(temporary); const destination = try cachePath(allocator, root, file_name); defer allocator.free(destination); errdefer std.Io.Dir.deleteFileAbsolute(fs_io, temporary) catch {}; { var file = try std.Io.Dir.createFileAbsolute(fs_io, temporary, .{ .truncate = true }); defer file.close(fs_io); var write_buffer: [write_buffer_bytes]u8 = undefined; var file_writer = file.writer(fs_io, &write_buffer); const writer = &file_writer.interface; try writer.writeAll(magic); try writer.writeAll(&head); var handle = try database.connection.catalog.openRelation( database.allocator, storage.rows.nodes_relation, ); defer handle.deinit(); const count = try handle.relation.table.count(); var count_bytes: [@sizeOf(u64)]u8 = undefined; std.mem.writeInt(u64, &count_bytes, @intCast(count), .big); try writer.writeAll(&count_bytes); const scan_index = try nodeNameIndexSlot(&handle); var entries: sql.IndexScan = undefined; try handle.relation.indexScan( &entries, database.allocator, scan_index, null, null, ); defer entries.deinit(); var values: [1]sql.row.Value = undefined; var key_scratch: [sql.page.size]u8 = undefined; var hasher = std.crypto.hash.sha2.Sha256.init(.{}); var projected_bytes: u64 = minimum_file_bytes; var written: usize = 0; while (written < count) : (written += 1) { const entry = (try entries.next()) orelse return error.StorageIndexCorrupt; const name = try indexedName(&values, &key_scratch, entry.key); if (name.len == 0 or name.len > sql.page.size) return error.InvalidName; const entry_bytes: u64 = @sizeOf(u32) + @as(u64, @intCast(name.len)); if (entry_bytes > max_cache_bytes - projected_bytes) { return error.NameProjectionTooLarge; } projected_bytes += entry_bytes; var length_bytes: [@sizeOf(u32)]u8 = undefined; std.mem.writeInt(u32, &length_bytes, @intCast(name.len), .big); try writer.writeAll(&length_bytes); try writer.writeAll(name); hasher.update(&length_bytes); hasher.update(name); } if (try entries.next() != null) return error.StorageIndexCorrupt; var digest: [digest_bytes]u8 = undefined; hasher.final(&digest); try writer.writeAll(&digest); try writer.flush(); try file.sync(fs_io); } try sys.fs.rename(temporary, destination);}pub fn indexedName( values: *[1]sql.row.Value, scratch: []u8, key_bytes: []const u8,) ![]const u8 { const decoded = sql.key.decodeIndex(values, scratch, key_bytes) catch return error.StorageIndexCorrupt; if (decoded.values.len != 1) return error.StorageIndexCorrupt; return switch (decoded.values[0]) { .text => |name| name, else => error.StorageIndexCorrupt, };}fn nodeNameIndexSlot(handle: anytype) !usize { for (handle.index_definitions, 0..) |definition, slot| { if (std.mem.eql(u8, definition.name, storage.rows.node_name_index)) { return slot; } } return error.StorageIndexMissing;}fn readExact(reader: *std.Io.Reader, target: []u8) !void { reader.readSliceAll(target) catch return error.InvalidNameProjection;}fn cachePath( allocator: std.mem.Allocator, root: []const u8, name: []const u8,) std.mem.Allocator.Error![]const u8 { return try std.fs.path.join( allocator, &.{ root, storage.paths.smg_dir_name, name }, );}Source: tools/smg/src/storage/root.zig:5
zig
pub const names = @import("names.zig");Audit
| Definitions | 7 |
|---|---|
| Public names | 7 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |