ordered_index.zig 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. const std = @import("std");
  2. const RecordRef = @import("keydir.zig").RecordRef;
  3. pub const Node = struct {
  4. key: []u8,
  5. inline_key: [32]u8 = undefined,
  6. external_key: bool,
  7. record: RecordRef,
  8. priority: u64,
  9. parent: ?*Node = null,
  10. left: ?*Node = null,
  11. right: ?*Node = null,
  12. };
  13. pub const Prepared = struct {
  14. node: ?*Node,
  15. };
  16. pub const OrderedIndex = struct {
  17. allocator: std.mem.Allocator,
  18. root: ?*Node = null,
  19. count: usize = 0,
  20. allocated_bytes: usize = 0,
  21. pub fn init(allocator: std.mem.Allocator) OrderedIndex {
  22. return .{ .allocator = allocator };
  23. }
  24. pub fn deinit(self: *OrderedIndex) void {
  25. while (self.root) |node| _ = self.remove(node.key);
  26. self.* = undefined;
  27. }
  28. fn priority(key: []const u8) u64 {
  29. var value: u64 = 14695981039346656037;
  30. for (key) |byte| {
  31. value ^= byte;
  32. value *%= 1099511628211;
  33. }
  34. value ^= value >> 30;
  35. value *%= 0xbf58476d1ce4e5b9;
  36. value ^= value >> 27;
  37. value *%= 0x94d049bb133111eb;
  38. return value ^ (value >> 31);
  39. }
  40. fn rotateLeft(self: *OrderedIndex, node: *Node) void {
  41. const child = node.right.?;
  42. node.right = child.left;
  43. if (child.left) |left| left.parent = node;
  44. child.parent = node.parent;
  45. if (node.parent) |parent| {
  46. if (parent.left == node) parent.left = child else parent.right = child;
  47. } else self.root = child;
  48. child.left = node;
  49. node.parent = child;
  50. }
  51. fn rotateRight(self: *OrderedIndex, node: *Node) void {
  52. const child = node.left.?;
  53. node.left = child.right;
  54. if (child.right) |right| right.parent = node;
  55. child.parent = node.parent;
  56. if (node.parent) |parent| {
  57. if (parent.left == node) parent.left = child else parent.right = child;
  58. } else self.root = child;
  59. child.right = node;
  60. node.parent = child;
  61. }
  62. pub fn put(self: *OrderedIndex, key: []const u8, record: RecordRef) !void {
  63. var parent: ?*Node = null;
  64. var current = self.root;
  65. var order: std.math.Order = .eq;
  66. while (current) |node| {
  67. order = std.mem.order(u8, key, node.key);
  68. if (order == .eq) {
  69. node.record = record;
  70. return;
  71. }
  72. parent = node;
  73. current = if (order == .lt) node.left else node.right;
  74. }
  75. var prepared = try self.prepare(key);
  76. const node = prepared.node.?;
  77. prepared.node = null;
  78. node.record = record;
  79. node.parent = parent;
  80. if (parent) |value| {
  81. if (order == .lt) value.left = node else value.right = node;
  82. } else self.root = node;
  83. self.count += 1;
  84. self.allocated_bytes += @sizeOf(Node) + if (node.external_key) key.len else 0;
  85. while (node.parent) |value| {
  86. if (value.priority <= node.priority) break;
  87. if (value.left == node) self.rotateRight(value) else self.rotateLeft(value);
  88. }
  89. }
  90. pub fn prepare(self: *OrderedIndex, key: []const u8) !Prepared {
  91. const node = try self.allocator.create(Node);
  92. errdefer self.allocator.destroy(node);
  93. node.* = .{ .key = undefined, .external_key = key.len > 32, .record = undefined, .priority = priority(key) };
  94. if (node.external_key) {
  95. node.key = try self.allocator.dupe(u8, key);
  96. } else {
  97. @memcpy(node.inline_key[0..key.len], key);
  98. node.key = node.inline_key[0..key.len];
  99. }
  100. return .{ .node = node };
  101. }
  102. pub fn discard(self: *OrderedIndex, prepared: *Prepared) void {
  103. const node = prepared.node orelse return;
  104. if (node.external_key) self.allocator.free(node.key);
  105. self.allocator.destroy(node);
  106. prepared.node = null;
  107. }
  108. pub fn putPrepared(self: *OrderedIndex, prepared: *Prepared, record: RecordRef) void {
  109. const node = prepared.node.?;
  110. var parent: ?*Node = null;
  111. var current = self.root;
  112. var order: std.math.Order = .eq;
  113. while (current) |existing| {
  114. order = std.mem.order(u8, node.key, existing.key);
  115. if (order == .eq) {
  116. existing.record = record;
  117. self.discard(prepared);
  118. return;
  119. }
  120. parent = existing;
  121. current = if (order == .lt) existing.left else existing.right;
  122. }
  123. prepared.node = null;
  124. node.record = record;
  125. node.parent = parent;
  126. if (parent) |value| {
  127. if (order == .lt) value.left = node else value.right = node;
  128. } else self.root = node;
  129. self.count += 1;
  130. self.allocated_bytes += @sizeOf(Node) + if (node.external_key) node.key.len else 0;
  131. while (node.parent) |value| {
  132. if (value.priority <= node.priority) break;
  133. if (value.left == node) self.rotateRight(value) else self.rotateLeft(value);
  134. }
  135. }
  136. pub fn remove(self: *OrderedIndex, key: []const u8) bool {
  137. const node = self.find(key) orelse return false;
  138. while (node.left != null or node.right != null) {
  139. if (node.left == null) {
  140. self.rotateLeft(node);
  141. } else if (node.right == null) {
  142. self.rotateRight(node);
  143. } else if (node.left.?.priority < node.right.?.priority) {
  144. self.rotateRight(node);
  145. } else {
  146. self.rotateLeft(node);
  147. }
  148. }
  149. if (node.parent) |parent| {
  150. if (parent.left == node) parent.left = null else parent.right = null;
  151. } else self.root = null;
  152. self.count -= 1;
  153. self.allocated_bytes -= @sizeOf(Node) + if (node.external_key) node.key.len else 0;
  154. if (node.external_key) self.allocator.free(node.key);
  155. self.allocator.destroy(node);
  156. return true;
  157. }
  158. pub fn find(self: *const OrderedIndex, key: []const u8) ?*Node {
  159. var current = self.root;
  160. while (current) |node| switch (std.mem.order(u8, key, node.key)) {
  161. .eq => return node,
  162. .lt => current = node.left,
  163. .gt => current = node.right,
  164. };
  165. return null;
  166. }
  167. pub fn lowerBound(self: *const OrderedIndex, key: []const u8) ?*Node {
  168. var current = self.root;
  169. var result: ?*Node = null;
  170. while (current) |node| {
  171. if (std.mem.order(u8, node.key, key) == .lt) {
  172. current = node.right;
  173. } else {
  174. result = node;
  175. current = node.left;
  176. }
  177. }
  178. return result;
  179. }
  180. pub fn next(node: *Node) ?*Node {
  181. if (node.right) |right| {
  182. var current = right;
  183. while (current.left) |left| current = left;
  184. return current;
  185. }
  186. var current = node;
  187. while (current.parent) |parent| {
  188. if (parent.left == current) return parent;
  189. current = parent;
  190. }
  191. return null;
  192. }
  193. pub fn records(self: *const OrderedIndex, allocator: std.mem.Allocator) ![]RecordRef {
  194. const result = try allocator.alloc(RecordRef, self.count);
  195. var node = self.lowerBound("");
  196. var index: usize = 0;
  197. while (node) |value| {
  198. result[index] = value.record;
  199. index += 1;
  200. node = next(value);
  201. }
  202. return result;
  203. }
  204. };
  205. test "ordered insert update remove and lower bound" {
  206. var index = OrderedIndex.init(std.testing.allocator);
  207. defer index.deinit();
  208. try index.put("b", .{ .hash = 2, .lsn = 1, .key_offset = 0, .value_offset = 0, .key_len = 1, .value_len = 0 });
  209. try index.put("a", .{ .hash = 1, .lsn = 1, .key_offset = 0, .value_offset = 0, .key_len = 1, .value_len = 0 });
  210. try index.put("c", .{ .hash = 3, .lsn = 1, .key_offset = 0, .value_offset = 0, .key_len = 1, .value_len = 0 });
  211. try index.put("b", .{ .hash = 2, .lsn = 2, .key_offset = 0, .value_offset = 0, .key_len = 1, .value_len = 0 });
  212. try std.testing.expectEqual(@as(usize, 3), index.count);
  213. try std.testing.expectEqualStrings("b", index.lowerBound("az").?.key);
  214. try std.testing.expectEqual(@as(u64, 2), index.find("b").?.record.lsn);
  215. try std.testing.expect(index.remove("b"));
  216. try std.testing.expectEqualStrings("c", index.lowerBound("b").?.key);
  217. try std.testing.expectEqual(@as(usize, 2), index.count);
  218. }