diff options
Diffstat (limited to 'src/allocators.zig')
-rw-r--r-- | src/allocators.zig | 291 |
1 files changed, 46 insertions, 245 deletions
diff --git a/src/allocators.zig b/src/allocators.zig index 4150a37c8..b29435a2d 100644 --- a/src/allocators.zig +++ b/src/allocators.zig @@ -144,14 +144,19 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { overflow_list: OverflowListType, allocator: *Allocator, + mutex: Mutex = Mutex.init(), pub var instance: Self = undefined; + pub var loaded = false; pub fn init(allocator: *std.mem.Allocator) *Self { - instance = Self{ - .allocator = allocator, - .overflow_list = OverflowListType{}, - }; + if (!loaded) { + instance = Self{ + .allocator = allocator, + .overflow_list = OverflowListType{}, + }; + loaded = true; + } return &instance; } @@ -175,6 +180,8 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { } pub fn append(self: *Self, value: ValueType) !IndexType { + self.mutex.lock(); + defer self.mutex.unlock(); var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = backing_buf_used > max_index }; if (result.is_overflow) { result.index = @intCast(u31, self.overflow_list.items.len); @@ -192,6 +199,9 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { } pub const Pair = struct { index: IndexType, value: *ValueType }; pub fn appendGet(self: *Self, value: ValueType) !Pair { + self.mutex.lock(); + defer self.mutex.unlock(); + var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = backing_buf_used > max_index }; if (result.is_overflow) { result.index = @intCast(u31, self.overflow_list.items.len); @@ -209,6 +219,9 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { } pub fn update(self: *Self, result: *IndexType, value: ValueType) !*ValueType { + self.mutex.lock(); + defer self.mutex.unlock(); + if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { result.index.is_overflow = backing_buf_used > max_index; if (result.index.is_overflow) { @@ -267,7 +280,7 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { }; } -const Mutex = @import("./sync.zig").Mutex; +const Mutex = @import("./lock.zig").Lock; /// Append-only list. /// Stores an initial count in .bss section of the object file @@ -480,15 +493,21 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo index: IndexMap, overflow_list: std.ArrayListUnmanaged(ValueType), allocator: *Allocator, + mutex: Mutex = Mutex.init(), pub var instance: Self = undefined; + var loaded: bool = false; + pub fn init(allocator: *std.mem.Allocator) *Self { - instance = Self{ - .index = IndexMap{}, - .allocator = allocator, - .overflow_list = std.ArrayListUnmanaged(ValueType){}, - }; + if (!loaded) { + instance = Self{ + .index = IndexMap{}, + .allocator = allocator, + .overflow_list = std.ArrayListUnmanaged(ValueType){}, + }; + loaded = true; + } return &instance; } @@ -500,6 +519,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo pub fn getOrPut(self: *Self, denormalized_key: []const u8) !Result { const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key; const _key = Wyhash.hash(Seed, key); + + self.mutex.lock(); + defer self.mutex.unlock(); var index = try self.index.getOrPut(self.allocator, _key); if (index.found_existing) { @@ -522,14 +544,19 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo }; } - pub fn get(self: *const Self, denormalized_key: []const u8) ?*ValueType { + pub fn get(self: *Self, denormalized_key: []const u8) ?*ValueType { const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key; const _key = Wyhash.hash(Seed, key); + self.mutex.lock(); + defer self.mutex.unlock(); const index = self.index.get(_key) orelse return null; return self.atIndex(index); } pub fn markNotFound(self: *Self, result: Result) void { + self.mutex.lock(); + defer self.mutex.unlock(); + self.index.put(self.allocator, result.hash, NotFound) catch unreachable; } @@ -544,6 +571,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo } pub fn put(self: *Self, result: *Result, value: ValueType) !*ValueType { + self.mutex.lock(); + defer self.mutex.unlock(); + if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { result.index.is_overflow = backing_buf_used > max_index; if (result.index.is_overflow) { @@ -576,6 +606,9 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo } pub fn remove(self: *Self, denormalized_key: []const u8) void { + self.mutex.lock(); + defer self.mutex.unlock(); + const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, "/") else denormalized_key; const _key = Wyhash.hash(Seed, key); @@ -671,6 +704,8 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo // 1. Storing the underyling string. // 2. Making the key accessible at the index. pub fn putKey(self: *Self, key: anytype, result: *Result) !void { + self.map.mutex.lock(); + defer self.map.mutex.unlock(); var slice: []u8 = undefined; // Is this actually a slice into the map? Don't free it. @@ -715,240 +750,6 @@ pub fn BSSMap(comptime ValueType: type, comptime count: anytype, store_keys: boo }; } -pub fn TBSSMap(comptime ValueType: type, comptime count: anytype, store_keys: bool, estimated_key_length: usize) type { - const max_index = count - 1; - const BSSMapType = struct { - pub threadlocal var backing_buf: [count]ValueType = undefined; - pub threadlocal var backing_buf_used: u16 = 0; - const Allocator = std.mem.Allocator; - const Self = @This(); - - index: IndexMap, - overflow_list: std.ArrayListUnmanaged(ValueType), - allocator: *Allocator, - - pub threadlocal var instance: Self = undefined; - - pub fn init(allocator: *std.mem.Allocator) *Self { - instance = Self{ - .index = IndexMap{}, - .allocator = allocator, - .overflow_list = std.ArrayListUnmanaged(ValueType){}, - }; - - return &instance; - } - - pub fn isOverflowing() bool { - return backing_buf_used >= @as(u16, count); - } - - pub fn getOrPut(self: *Self, key: []const u8) !Result { - const _key = Wyhash.hash(Seed, key); - var index = try self.index.getOrPut(self.allocator, _key); - - if (index.found_existing) { - return Result{ - .hash = _key, - .index = index.value_ptr.*, - .status = switch (index.value_ptr.index) { - NotFound.index => .not_found, - Unassigned.index => .unknown, - else => .exists, - }, - }; - } - index.value_ptr.* = Unassigned; - - return Result{ - .hash = _key, - .index = Unassigned, - .status = .unknown, - }; - } - - pub fn get(self: *const Self, key: []const u8) ?*ValueType { - const _key = Wyhash.hash(Seed, key); - const index = self.index.get(_key) orelse return null; - return self.atIndex(index); - } - - pub fn markNotFound(self: *Self, result: Result) void { - self.index.put(self.allocator, result.hash, NotFound) catch unreachable; - } - - pub fn atIndex(self: *const Self, index: IndexType) ?*ValueType { - if (index.index == NotFound.index or index.index == Unassigned.index) return null; - - if (index.is_overflow) { - return &self.overflow_list.items[index.index]; - } else { - return &backing_buf[index.index]; - } - } - - pub fn put(self: *Self, result: *Result, value: ValueType) !*ValueType { - if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { - result.index.is_overflow = backing_buf_used > max_index; - if (result.index.is_overflow) { - result.index.index = @intCast(u31, self.overflow_list.items.len); - } else { - result.index.index = backing_buf_used; - backing_buf_used += 1; - if (backing_buf_used >= max_index) { - self.overflow_list = try @TypeOf(self.overflow_list).initCapacity(self.allocator, count); - } - } - } - - try self.index.put(self.allocator, result.hash, result.index); - - if (result.index.is_overflow) { - if (self.overflow_list.items.len == result.index.index) { - const real_index = self.overflow_list.items.len; - try self.overflow_list.append(self.allocator, value); - } else { - self.overflow_list.items[result.index.index] = value; - } - - return &self.overflow_list.items[result.index.index]; - } else { - backing_buf[result.index.index] = value; - - return &backing_buf[result.index.index]; - } - } - - pub fn remove(self: *Self, key: []const u8) IndexType { - const _key = Wyhash.hash(Seed, key); - const index = self.index.get(_key) orelse return; - defer _ = self.index.remove(_key); - - switch (index) { - NotFound.index, Unassigned.index => {}, - 0...max_index => { - // if (hasDeinit(ValueType)) { - // backing_buf[index].deinit(); - // } - backing_buf[index] = undefined; - }, - else => { - const i = index - count; - if (hasDeinit(ValueType)) { - self.overflow_list.items[i].deinit(); - } - self.overflow_list.items[index - count] = undefined; - }, - } - - return index; - } - }; - if (!store_keys) { - return BSSMapType; - } - - return struct { - map: *BSSMapType, - const Self = @This(); - pub threadlocal var instance: Self = undefined; - threadlocal var key_list_buffer: [count * estimated_key_length]u8 = undefined; - threadlocal var key_list_buffer_used: usize = 0; - threadlocal var key_list_slices: [count][]u8 = undefined; - threadlocal var key_list_overflow: std.ArrayListUnmanaged([]u8) = undefined; - - pub fn init(allocator: *std.mem.Allocator) *Self { - instance = Self{ - .map = BSSMapType.init(allocator), - }; - - return &instance; - } - - pub fn isOverflowing() bool { - return instance.map.backing_buf_used >= count; - } - pub fn getOrPut(self: *Self, key: []const u8) !Result { - return try self.map.getOrPut(key); - } - pub fn get(self: *Self, key: []const u8) ?*ValueType { - return @call(.{ .modifier = .always_inline }, BSSMapType.get, .{ self.map, key }); - } - - pub fn atIndex(self: *Self, index: IndexType) ?*ValueType { - return @call(.{ .modifier = .always_inline }, BSSMapType.atIndex, .{ self.map, index }); - } - - pub fn keyAtIndex(self: *Self, index: IndexType) ?[]const u8 { - return switch (index.index) { - Unassigned.index, NotFound.index => null, - else => { - if (!index.is_overflow) { - return key_list_slices[index.index]; - } else { - return key_list_overflow.items[index.index]; - } - }, - }; - } - - pub fn put(self: *Self, key: anytype, comptime store_key: bool, result: *Result, value: ValueType) !*ValueType { - var ptr = try self.map.put(result, value); - if (store_key) { - try self.putKey(key, result); - } - - return ptr; - } - - pub fn isKeyStaticallyAllocated(key: anytype) bool { - return isSliceInBuffer(key, &key_list_buffer); - } - - // There's two parts to this. - // 1. Storing the underyling string. - // 2. Making the key accessible at the index. - pub fn putKey(self: *Self, key: anytype, result: *Result) !void { - var slice: []u8 = undefined; - - // Is this actually a slice into the map? Don't free it. - if (isKeyStaticallyAllocated(key)) { - slice = constStrToU8(key); - } else if (key_list_buffer_used + key.len < key_list_buffer.len) { - const start = key_list_buffer_used; - key_list_buffer_used += key.len; - slice = key_list_buffer[start..key_list_buffer_used]; - std.mem.copy(u8, slice, key); - } else { - slice = try self.map.allocator.dupe(u8, key); - } - - if (!result.index.is_overflow) { - key_list_slices[result.index.index] = slice; - } else { - if (@intCast(u31, key_list_overflow.items.len) > result.index.index) { - const existing_slice = key_list_overflow.items[result.index.index]; - if (!isKeyStaticallyAllocated(existing_slice)) { - self.map.allocator.free(existing_slice); - } - key_list_overflow.items[result.index.index] = slice; - } else { - try key_list_overflow.append(self.map.allocator, slice); - } - } - } - - pub fn markNotFound(self: *Self, result: Result) void { - self.map.markNotFound(result); - } - - // For now, don't free the keys. - pub fn remove(self: *Self, key: string) IndexType { - return self.map.remove(key); - } - }; -} - pub inline fn constStrToU8(s: []const u8) []u8 { return @intToPtr([*]u8, @ptrToInt(s.ptr))[0..s.len]; } |