index.zig 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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 findNodeForPrefix(node: *RadixNode, prefix: []const u8, actual_path: *[]u8) ?*RadixNode {
  111. if (prefix.len == 0) {
  112. actual_path.* = &[_]u8{};
  113. return node;
  114. }
  115. var current = node;
  116. var remaining = prefix;
  117. var path_buffer: [MAX_KEY_LENGTH]u8 = undefined;
  118. var path_len: usize = 0;
  119. while (remaining.len > 0) {
  120. var found = false;
  121. var it = current.children.iterator();
  122. while (it.next()) |entry| {
  123. const child = entry.value_ptr.*;
  124. const prefix_match_len = commonPrefixLen(child.edge, remaining);
  125. if (prefix_match_len > 0) {
  126. if (prefix_match_len == remaining.len) {
  127. actual_path.* = temp_allocator.dupe(u8, path_buffer[0..path_len]) catch &[_]u8{};
  128. return child;
  129. }
  130. if (prefix_match_len == child.edge.len) {
  131. @memcpy(path_buffer[path_len .. path_len + prefix_match_len], child.edge[0..prefix_match_len]);
  132. path_len += prefix_match_len;
  133. remaining = remaining[prefix_match_len..];
  134. current = child;
  135. found = true;
  136. break;
  137. }
  138. return null;
  139. }
  140. }
  141. if (!found) {
  142. return null;
  143. }
  144. }
  145. actual_path.* = temp_allocator.dupe(u8, path_buffer[0..path_len]) catch &[_]u8{};
  146. return current;
  147. }
  148. fn findNode(node: *RadixNode, key: []const u8) ?*RadixNode {
  149. var dummy_path: []u8 = &[_]u8{};
  150. return findNodeForPrefix(node, key, &dummy_path);
  151. }
  152. pub fn searchByPrefix(prefix: []const u8) ?*RadixNode {
  153. ensureRoot();
  154. if (prefix.len == 0) return root;
  155. return findNode(root, prefix);
  156. }
  157. fn countKeys(node: *RadixNode) usize {
  158. var count: usize = 0;
  159. if (node.is_terminal) {
  160. count += 1;
  161. }
  162. var it = node.children.iterator();
  163. while (it.next()) |entry| {
  164. count += countKeys(entry.value_ptr.*);
  165. }
  166. return count;
  167. }
  168. const MAX_KEYS_RETURN = 100_000_000;
  169. const MAX_KEY_LENGTH = 1024;
  170. fn collectKeysWithBuffer(node: *RadixNode, prefix_buffer: []u8, prefix_len: usize, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize, search_prefix: []const u8, include_node_edge: bool) void {
  171. if (keys.items.len >= max_keys) return;
  172. var current_len = prefix_len;
  173. if (include_node_edge and node.edge.len > 0) {
  174. if (current_len + node.edge.len > MAX_KEY_LENGTH) return;
  175. @memcpy(prefix_buffer[current_len .. current_len + node.edge.len], node.edge);
  176. current_len += node.edge.len;
  177. }
  178. if (node.is_terminal) {
  179. const key = prefix_buffer[0..current_len];
  180. if (key.len >= search_prefix.len and std.mem.eql(u8, key[0..search_prefix.len], search_prefix)) {
  181. const key_copy = temp_allocator.dupe(u8, key) catch return;
  182. keys.append(temp_allocator, key_copy) catch return;
  183. }
  184. }
  185. var it = node.children.iterator();
  186. while (it.next()) |entry| {
  187. if (keys.items.len >= max_keys) break;
  188. const child = entry.value_ptr.*;
  189. collectKeysWithBuffer(child, prefix_buffer, current_len, keys, max_keys, search_prefix, true);
  190. }
  191. }
  192. fn collectKeys(node: *RadixNode, prefix: []const u8, keys: *std.ArrayListUnmanaged([]const u8), max_keys: usize, search_prefix: []const u8) void {
  193. var prefix_buffer: [MAX_KEY_LENGTH]u8 = undefined;
  194. if (prefix.len > MAX_KEY_LENGTH) return;
  195. @memcpy(prefix_buffer[0..prefix.len], prefix);
  196. collectKeysWithBuffer(node, &prefix_buffer, prefix.len, keys, max_keys, search_prefix, true);
  197. }
  198. pub fn getKeysFromNode(node: *RadixNode, prefix: []const u8) [][]const u8 {
  199. var keys_list = std.ArrayListUnmanaged([]const u8){};
  200. collectKeys(node, prefix, &keys_list, MAX_KEYS_RETURN, prefix);
  201. return keys_list.toOwnedSlice(temp_allocator) catch &[_][]const u8{};
  202. }
  203. pub fn getKeysByPrefix(prefix: []const u8) []const u8 {
  204. tree_mutex.lock();
  205. defer tree_mutex.unlock();
  206. ensureRoot();
  207. const node = searchByPrefix(prefix) orelse return "";
  208. const keys = getKeysFromNode(node, prefix);
  209. if (keys.len == 0) return "";
  210. return std.mem.join(temp_allocator, "\n", keys) catch "";
  211. }
  212. pub fn getValuesByPrefix(prefix: []const u8) []const u8 {
  213. tree_mutex.lock();
  214. defer tree_mutex.unlock();
  215. ensureRoot();
  216. var actual_path: []u8 = &[_]u8{};
  217. const node = findNodeForPrefix(root, prefix, &actual_path) orelse {
  218. return "";
  219. };
  220. var keys_list = std.ArrayListUnmanaged([]const u8){};
  221. collectKeys(node, actual_path, &keys_list, MAX_KEYS_RETURN, prefix);
  222. const keys = keys_list.toOwnedSlice(temp_allocator) catch &[_][]const u8{};
  223. if (keys.len == 0) return "";
  224. const values = temp_allocator.alloc([]const u8, keys.len) catch return "";
  225. for (keys, 0..) |key, i| {
  226. const value = storage.read(key) orelse "";
  227. values[i] = value;
  228. }
  229. return std.mem.join(temp_allocator, "\n", values) catch "";
  230. }
  231. pub fn getAllKeys() []const u8 {
  232. tree_mutex.lock();
  233. defer tree_mutex.unlock();
  234. ensureRoot();
  235. const keys = getKeysFromNode(root, &[_]u8{});
  236. if (keys.len == 0) return "";
  237. return std.mem.join(temp_allocator, "\n", keys) catch "";
  238. }