A delete will now cause the proper collapse of cnodes into snodes up the tree to the root node.
This commit is contained in:
parent
e7ec1105eb
commit
c5fa370609
1 changed files with 32 additions and 21 deletions
53
src/hamt.erl
53
src/hamt.erl
|
@ -235,26 +235,43 @@ delete(Key, {hamt, Node}=T)
|
|||
when is_binary(Key) ->
|
||||
case delete_1(hash(Key), Key, Node, 0) of
|
||||
not_found -> T;
|
||||
delete -> {hamt, nil};
|
||||
N -> {hamt, N}
|
||||
{snode, Key, _} -> {hamt, nil};
|
||||
{snode, _, _}=N -> {hamt, N};
|
||||
{cnode, _, _}=N -> {hamt, N}
|
||||
end.
|
||||
|
||||
delete_1(H, Key, {cnode, Bitmap, Nodes}=CNode, L)
|
||||
delete_1(H, Key, {cnode, Bitmap, Nodes}, L)
|
||||
when is_integer(L), L =< 30 ->
|
||||
Bit = bitpos(H, L),
|
||||
Idx = index(Bit, Bitmap),
|
||||
case exists(Bit, Bitmap) of
|
||||
true ->
|
||||
case delete_1(H, Key, ba_get(Idx, Nodes), L + 5) of
|
||||
not_found -> not_found;
|
||||
delete -> delete_2(Key, Bit, CNode);
|
||||
N -> {cnode, Bitmap, ba_set(Idx, N, Nodes)}
|
||||
{cnode, _, _}=CN ->
|
||||
{cnode, Bitmap, ba_set(Idx, CN, Nodes)};
|
||||
{snode, Key, _} ->
|
||||
case length(Nodes) of
|
||||
2 ->
|
||||
[{snode, _, _}=SN] = ba_del(Key, Nodes),
|
||||
SN;
|
||||
false ->
|
||||
{cnode, (Bitmap bxor Bit), ba_del(Key, Nodes)}
|
||||
end;
|
||||
{snode, _, _}=SN ->
|
||||
case length(Nodes) > 1 of
|
||||
true ->
|
||||
{cnode, Bitmap, ba_set(Idx, SN, Nodes)};
|
||||
false ->
|
||||
SN
|
||||
end;
|
||||
not_found ->
|
||||
not_found
|
||||
end;
|
||||
false ->
|
||||
not_found
|
||||
end;
|
||||
delete_1(_H, Key, {snode, Key, _}, _L) ->
|
||||
delete;
|
||||
delete_1(_H, Key, {snode, Key, _}=SN, _L) ->
|
||||
SN;
|
||||
delete_1(_H, _Key, {snode, _, _}, _L) ->
|
||||
not_found;
|
||||
delete_1(_H, Key, {lnode, List}, _L) ->
|
||||
|
@ -267,16 +284,6 @@ delete_1(_H, Key, {lnode, List}, _L) ->
|
|||
{snode, Key, lists:keyfind(Key, 2, List)}
|
||||
end.
|
||||
|
||||
%% @doc This CNode only has 2 elements in it and one is about to be
|
||||
%% be deleted, time to collapse this CNode into an SNode.
|
||||
delete_2(Key, _Bit, {cnode, _Bitmap, Nodes})
|
||||
when length(Nodes) =:= 2 ->
|
||||
[{snode, _, _}=SN] = ba_del(Key, Nodes),
|
||||
SN;
|
||||
%% @doc Remove the right key and update the bitmap
|
||||
delete_2(Key, Bit, {cnode, Bitmap, Nodes}) ->
|
||||
{cnode, (Bitmap bxor Bit), ba_del(Key, Nodes)}.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
-spec map(Function, Hamt1) -> Hamt2 when
|
||||
|
@ -409,9 +416,13 @@ del_one_of_many_keys_test() ->
|
|||
{hamt,{snode,<<"k2">>,<<"v2">>}}).
|
||||
|
||||
del_causes_cascading_cnode_collapse_test() ->
|
||||
H = hamt:put([{<<X>>, <<X>>} || X <- lists:seq(1,5)], hamt:new()),
|
||||
?assertEqual(hamt:delete(<<5>>, H),
|
||||
hamt:put([{<<X>>, <<X>>} || X <- lists:seq(1,4)], hamt:new())).
|
||||
?assertEqual(hamt:delete(<<5>>, hamt:put([{<<X>>, <<X>>} || X <- lists:seq(1,6)], hamt:new())),
|
||||
{hamt,{cnode,17629440,
|
||||
[{snode,<<3>>,<<3>>},
|
||||
{snode,<<6>>,<<6>>},
|
||||
{snode,<<1>>,<<1>>},
|
||||
{snode,<<2>>,<<2>>},
|
||||
{snode,<<4>>,<<4>>}]}}).
|
||||
|
||||
put_lots_test() ->
|
||||
KVPs = [{<<X>>, <<X>>} || X <- lists:seq(1,10000)],
|
||||
|
|
Loading…
Reference in a new issue