2
0

index.zig 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. const std = @import("std");
  2. const storage = @import("storage.zig");
  3. var tree_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
  4. const tree_allocator = tree_arena.allocator();
  5. const temp_allocator = std.heap.c_allocator;
  6. var tree_mutex: std.Thread.Mutex = .{};
  7. const RadixNode = struct {
  8. edge: []const u8,
  9. children: std.StringHashMap(*RadixNode),
  10. is_terminal: bool,
  11. fn init(edge: []const u8) *RadixNode {
  12. const node = tree_allocator.create(RadixNode) catch unreachable;
  13. node.* = .{
  14. .edge = tree_allocator.dupe(u8, edge) catch unreachable,
  15. .children = std.StringHashMap(*RadixNode).init(tree_allocator),
  16. .is_terminal = false,
  17. };
  18. return node;
  19. }
  20. fn deinit(self: *RadixNode) void {
  21. var it = self.children.iterator();
  22. while (it.next()) |entry| {
  23. entry.value_ptr.*.deinit();
  24. }
  25. self.children.deinit();
  26. tree_allocator.free(self.edge);
  27. tree_allocator.destroy(self);
  28. }
  29. };
  30. var root: *RadixNode = undefined;
  31. var root_initialized = false;
  32. fn ensureRoot() void {
  33. if (!root_initialized) {
  34. root = RadixNode.init("");
  35. root_initialized = true;
  36. }
  37. }
  38. fn commonPrefixLen(a: []const u8, b: []const u8) usize {
  39. var i: usize = 0;
  40. while (i < a.len and i < b.len and a[i] == b[i]) {
  41. i += 1;
  42. }
  43. return i;
  44. }
  45. pub fn insert(key: []const u8) void {
  46. tree_mutex.lock();
  47. defer tree_mutex.unlock();
  48. ensureRoot();
  49. if (key.len == 0) return;
  50. var node = root;
  51. var remaining = key;
  52. while (remaining.len > 0) {
  53. var found = false;
  54. var it = node.children.iterator();
  55. while (it.next()) |entry| {
  56. const child = entry.value_ptr.*;
  57. const prefix_len = commonPrefixLen(child.edge, remaining);
  58. if (prefix_len > 0) {
  59. found = true;
  60. if (prefix_len == child.edge.len) {
  61. if (prefix_len == remaining.len) {
  62. child.is_terminal = true;
  63. return;
  64. }
  65. remaining = remaining[prefix_len..];
  66. node = child;
  67. break;
  68. } else {
  69. const old_edge = child.edge;
  70. const common = old_edge[0..prefix_len];
  71. const child_suffix = old_edge[prefix_len..];
  72. const key_suffix = remaining[prefix_len..];
  73. const intermediate = RadixNode.init(common);
  74. tree_allocator.free(child.edge);
  75. child.edge = tree_allocator.dupe(u8, child_suffix) catch unreachable;
  76. intermediate.children.put(child_suffix, child) catch unreachable;
  77. _ = node.children.remove(old_edge);
  78. node.children.put(common, intermediate) catch unreachable;
  79. if (key_suffix.len == 0) {
  80. intermediate.is_terminal = true;
  81. return;
  82. } else {
  83. const new_child = RadixNode.init(key_suffix);
  84. new_child.is_terminal = true;
  85. intermediate.children.put(key_suffix, new_child) catch unreachable;
  86. return;
  87. }
  88. }
  89. }
  90. }
  91. if (!found) {
  92. const new_child = RadixNode.init(remaining);
  93. new_child.is_terminal = true;
  94. node.children.put(remaining, new_child) catch unreachable;
  95. return;
  96. }
  97. }
  98. node.is_terminal = true;
  99. }
  100. pub fn delete(key: []const u8) void {
  101. tree_mutex.lock();
  102. defer tree_mutex.unlock();
  103. ensureRoot();
  104. if (key.len == 0) return;
  105. const node = findNode(root, key);
  106. if (node) |n| {
  107. n.is_terminal = false;
  108. }
  109. }
  110. fn findNode(node: *RadixNode, key: []const u8) ?*RadixNode {
  111. if (key.len == 0) return node;
  112. var current = node;
  113. var remaining = key;
  114. while (remaining.len > 0) {
  115. var found = false;
  116. var it = current.children.iterator();
  117. while (it.next()) |entry| {
  118. const child = entry.value_ptr.*;
  119. const prefix_len = commonPrefixLen(child.edge, remaining);
  120. if (prefix_len > 0) {
  121. if (prefix_len < child.edge.len) {
  122. return null;
  123. }
  124. if (prefix_len == remaining.len) {
  125. return child;
  126. }
  127. remaining = remaining[prefix_len..];
  128. current = child;
  129. found = true;
  130. break;
  131. }
  132. }
  133. if (!found) return null;
  134. }
  135. return current;
  136. }
  137. pub fn searchByPrefix(prefix: []const u8) ?*RadixNode {
  138. ensureRoot();
  139. if (prefix.len == 0) return root;
  140. return findNode(root, prefix);
  141. }
  142. fn countKeys(node: *RadixNode) usize {
  143. var count: usize = 0;
  144. if (node.is_terminal) {
  145. count += 1;
  146. }
  147. var it = node.children.iterator();
  148. while (it.next()) |entry| {
  149. count += countKeys(entry.value_ptr.*);
  150. }
  151. return count;
  152. }
  153. const MAX_KEYS_RETURN = 10000;
  154. const MAX_KEY_LENGTH = 1024;
  155. fn collectKeysWithBuffer(node: *RadixNode, prefix_buffer: []u8, prefix_len: usize, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize) void {
  156. if (keys.items.len >= max_keys) return;
  157. if (node.is_terminal) {
  158. const key = temp_allocator.dupe(u8, prefix_buffer[0..prefix_len]) catch return;
  159. keys.append(temp_allocator, key) catch return;
  160. }
  161. var it = node.children.iterator();
  162. while (it.next()) |entry| {
  163. if (keys.items.len >= max_keys) break;
  164. const child = entry.value_ptr.*;
  165. const edge_len = child.edge.len;
  166. if (prefix_len + edge_len > MAX_KEY_LENGTH) continue;
  167. @memcpy(prefix_buffer[prefix_len .. prefix_len + edge_len], child.edge);
  168. collectKeysWithBuffer(child, prefix_buffer, prefix_len + edge_len, keys, max_keys);
  169. }
  170. }
  171. fn collectKeys(node: *RadixNode, prefix: []const u8, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize) void {
  172. var prefix_buffer: [MAX_KEY_LENGTH]u8 = undefined;
  173. if (prefix.len > MAX_KEY_LENGTH) return;
  174. @memcpy(prefix_buffer[0..prefix.len], prefix);
  175. collectKeysWithBuffer(node, &prefix_buffer, prefix.len, keys, max_keys);
  176. }
  177. pub fn getKeysFromNode(node: *RadixNode, prefix: []const u8) [][]const u8 {
  178. var keys_list = std.ArrayListUnmanaged([]const u8){};
  179. collectKeys(node, prefix, &keys_list, MAX_KEYS_RETURN);
  180. return keys_list.toOwnedSlice(temp_allocator) catch &[_][]const u8{};
  181. }
  182. pub fn getKeysByPrefix(prefix: []const u8) []const u8 {
  183. tree_mutex.lock();
  184. defer tree_mutex.unlock();
  185. ensureRoot();
  186. const node = searchByPrefix(prefix) orelse return "";
  187. const keys = getKeysFromNode(node, prefix);
  188. if (keys.len == 0) return "";
  189. return std.mem.join(temp_allocator, "\r", keys) catch "";
  190. }
  191. pub fn getValuesByPrefix(prefix: []const u8) []const u8 {
  192. tree_mutex.lock();
  193. defer tree_mutex.unlock();
  194. ensureRoot();
  195. const node = searchByPrefix(prefix) orelse return "";
  196. const keys = getKeysFromNode(node, prefix);
  197. if (keys.len == 0) return "";
  198. const values = temp_allocator.alloc([]const u8, keys.len) catch return "";
  199. for (keys, 0..) |key, i| {
  200. const value = storage.read(key) orelse "";
  201. values[i] = value;
  202. }
  203. return std.mem.join(temp_allocator, "\r", values) catch "";
  204. }
  205. pub fn getAllKeys() []const u8 {
  206. tree_mutex.lock();
  207. defer tree_mutex.unlock();
  208. ensureRoot();
  209. const keys = getKeysFromNode(root, &[_]u8{});
  210. if (keys.len == 0) return "";
  211. return std.mem.join(temp_allocator, "\r", keys) catch "";
  212. }