From d4a8ca5adedeb529ab39baa576f7f3744747f211 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sat, 10 Oct 2026 13:10:15 +0000 Subject: [PATCH 1/2] perf: fuse no-split add path for leaves and branches When a leaf or branch does not split after an insert, emit the updated node directly instead of going through the generic chunking pipelines (add_leaf_refs / tree_*_refs_of_arrays / branch_replace_one). This mirrors the direct emission remove already uses for leaves and saves a few intermediate allocations and list traversals per add. Tree shape and node contents are unchanged. --- lib/persistent_sorted_set.ml | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/persistent_sorted_set.ml b/lib/persistent_sorted_set.ml index c7180d6..a0a72f1 100644 --- a/lib/persistent_sorted_set.ml +++ b/lib/persistent_sorted_set.ml @@ -826,7 +826,21 @@ and add_to_node storage settings order_cmp equality_cmp key_cmp value = function | `Found _ -> Tree_edit_unchanged | `Insert index -> let inserted = array_insert_len values len index value in - Tree_edit_changed (add_leaf_refs settings ?address inserted)) + if len < settings.branching_factor then + (* common case: the leaf does not split, emit it directly + instead of going through the generic chunking pipeline *) + Tree_edit_changed + [ + ( inserted.(len), + Node.Leaf + { + values = inserted; + len = len + 1; + address; + dirty = true; + } ); + ] + else Tree_edit_changed (add_leaf_refs settings ?address inserted)) | Node.Branch { keys; children; address; _ } -> ( let index = find_child_index key_cmp value keys in match @@ -835,8 +849,22 @@ and add_to_node storage settings order_cmp equality_cmp key_cmp value = function with | Tree_edit_unchanged -> Tree_edit_unchanged | Tree_edit_changed [ (key, child) ] -> - branch_replace_one settings ?address keys children index key child - |> fun changed -> Tree_edit_changed changed + if Array.length keys <= settings.branching_factor then ( + (* common case: the branch does not split, replace the child + in place and emit the branch directly *) + let keys = Array.copy keys in + let children = Array.copy children in + keys.(index) <- key; + children.(index) <- child; + Tree_edit_changed + [ + ( keys.(Array.length keys - 1), + Node.Branch { keys; children; address; dirty = true } ); + ]) + else + branch_replace_one settings ?address keys children index key + child + |> fun changed -> Tree_edit_changed changed | Tree_edit_changed changed -> let keys, children = branch_splice_one keys children index changed in branch_refs_of_arrays ?first_address:address settings keys children From b4c97e37b4d62175b376d76e795c298071444343 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sat, 10 Oct 2026 13:32:45 +0000 Subject: [PATCH 2/2] remove: fused emit for branch child replacement without rebalance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a removed child does not underflow, the branch keeps its shape — replace the child slot in place and emit the branch directly instead of routing through branch_replace_one's generic ref-array chunking. --- lib/persistent_sorted_set.ml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/persistent_sorted_set.ml b/lib/persistent_sorted_set.ml index a0a72f1..d0d411d 100644 --- a/lib/persistent_sorted_set.ml +++ b/lib/persistent_sorted_set.ml @@ -932,8 +932,20 @@ and remove_from_node storage settings order_cmp equality_cmp key_cmp value = with | Some changed -> changed | None -> - branch_replace_one settings ?address keys children index - key child) + if Array.length keys <= settings.branching_factor then ( + (* common case: the child stays a single node, replace + it in place instead of rebuilding the branch *) + let keys = Array.copy keys in + let children = Array.copy children in + keys.(index) <- key; + children.(index) <- child; + [ ( keys.(Array.length keys - 1) + , Node.Branch + { keys; children; address; dirty = true } ) + ]) + else + branch_replace_one settings ?address keys children + index key child) in Tree_edit_changed changed | Tree_edit_changed changed ->