const std = @import("std"); const Io = std.Io; pub fn ShardedLocks(comptime count: usize) type { if (count == 0) @compileError("ShardedLocks requires at least one shard"); return struct { const Self = @This(); locks: [count]Io.Mutex = @splat(.init), pub const Guard = struct { owner: *Self, io: Io, index: usize, pub fn unlock(self: Guard) void { self.owner.locks[self.index].unlock(self.io); } }; pub fn lock(self: *Self, io: Io, key: []const u8) Guard { const index = shardIndex(key); self.locks[index].lockUncancelable(io); return .{ .owner = self, .io = io, .index = index }; } pub fn shardIndex(key: []const u8) usize { return @intCast(std.hash.Wyhash.hash(0, key) % count); } }; } test "same key maps to same shard" { const Locks = ShardedLocks(16); try std.testing.expectEqual(Locks.shardIndex("did:plc:abc"), Locks.shardIndex("did:plc:abc")); }