@@ -791,11 +791,12 @@ where
791791 self . root_addr = new_child. address ( ) ;
792792
793793 // Deallocate the root node.
794- self . allocator . deallocate ( node . address ( ) ) ;
794+ node . deallocate ( & mut self . allocator ) ;
795795 self . save ( ) ;
796+ } else {
797+ node. save ( self . allocator_mut ( ) ) ;
796798 }
797799
798- node. save ( self . allocator_mut ( ) ) ;
799800 new_child. save ( self . allocator_mut ( ) ) ;
800801
801802 // Recursively delete the key.
@@ -3126,4 +3127,70 @@ mod test {
31263127 // All chunks have been deallocated.
31273128 assert_eq ! ( btree. allocator. num_allocated_chunks( ) , 0 ) ;
31283129 }
3130+
3131+ #[ test]
3132+ fn deallocating_root_does_not_leak_memory ( ) {
3133+ let mem = make_memory ( ) ;
3134+ let mut btree: BTreeMap < Vec < u8 > , _ , _ > = BTreeMap :: new ( mem. clone ( ) ) ;
3135+
3136+ for i in 1 ..=11 {
3137+ // Large keys are stored so that each node overflows.
3138+ assert_eq ! ( btree. insert( vec![ i; 10_000 ] , ( ) ) , None ) ;
3139+ }
3140+
3141+ // Should now split a node.
3142+ assert_eq ! ( btree. insert( vec![ 0 ; 10_000 ] , ( ) ) , None ) ;
3143+
3144+ // The btree should look like this:
3145+ // [6]
3146+ // / \
3147+ // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11]
3148+ let root = btree. load_node ( btree. root_addr ) ;
3149+ assert_eq ! ( root. node_type( ) , NodeType :: Internal ) ;
3150+ assert_eq ! ( root. keys( ) , vec![ vec![ 6 ; 10_000 ] ] ) ;
3151+ assert_eq ! ( root. children_len( ) , 2 ) ;
3152+
3153+ // Remove the element in the root.
3154+ btree. remove ( & vec ! [ 6 ; 10_000 ] ) ;
3155+
3156+ // The btree should look like this:
3157+ // [5]
3158+ // / \
3159+ // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11]
3160+ let root = btree. load_node ( btree. root_addr ) ;
3161+ assert_eq ! ( root. node_type( ) , NodeType :: Internal ) ;
3162+ assert_eq ! ( root. keys( ) , vec![ vec![ 5 ; 10_000 ] ] ) ;
3163+ assert_eq ! ( root. children_len( ) , 2 ) ;
3164+
3165+ // Remove the element in the root. This triggers the case where the root
3166+ // node is deallocated and the children are merged into a single node.
3167+ btree. remove ( & vec ! [ 5 ; 10_000 ] ) ;
3168+
3169+ // The btree should look like this:
3170+ // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11]
3171+ let root = btree. load_node ( btree. root_addr ) ;
3172+ assert_eq ! ( root. node_type( ) , NodeType :: Leaf ) ;
3173+ assert_eq ! (
3174+ root. keys( ) ,
3175+ vec![
3176+ vec![ 0 ; 10_000 ] ,
3177+ vec![ 1 ; 10_000 ] ,
3178+ vec![ 2 ; 10_000 ] ,
3179+ vec![ 3 ; 10_000 ] ,
3180+ vec![ 4 ; 10_000 ] ,
3181+ vec![ 7 ; 10_000 ] ,
3182+ vec![ 8 ; 10_000 ] ,
3183+ vec![ 9 ; 10_000 ] ,
3184+ vec![ 10 ; 10_000 ] ,
3185+ vec![ 11 ; 10_000 ] ,
3186+ ]
3187+ ) ;
3188+
3189+ // Delete everything else.
3190+ for i in 0 ..=11 {
3191+ btree. remove ( & vec ! [ i; 10_000 ] ) ;
3192+ }
3193+
3194+ assert_eq ! ( btree. allocator. num_allocated_chunks( ) , 0 ) ;
3195+ }
31293196}
0 commit comments