xref: /6.6.0/geocouch/vtree/src/vtree_cleanup.erl (revision 263b2ce8)
1% Licensed under the Apache License, Version 2.0 (the "License"); you may not
2% use this file except in compliance with the License. You may obtain a copy of
3% the License at
4%
5%   http://www.apache.org/licenses/LICENSE-2.0
6%
7% Unless required by applicable law or agreed to in writing, software
8% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10% License for the specific language governing permissions and limitations under
11% the License.
12
13-module(vtree_cleanup).
14
15-include("vtree.hrl").
16-include("couch_db.hrl").
17
18-export([cleanup/2]).
19
20-ifdef(makecheck).
21-compile(nowarn_export_all).
22-compile(export_all).
23-endif.
24
25
26% Nodes get cleaned up by partition ID, nothing else matters.
27-spec cleanup(Vt :: #vtree{}, Nodes :: [#kv_node{}]) -> #vtree{}.
28cleanup(Vt, []) ->
29    Vt;
30cleanup(#vtree{root=nil}=Vt, _Nodes) ->
31    Vt;
32cleanup(Vt, Nodes) ->
33    T1 = erlang:monotonic_time(),
34    Root = Vt#vtree.root,
35    PartitionedNodes = [Nodes],
36    KpNodes = cleanup_multiple(Vt, PartitionedNodes, [Root]),
37    NewRoot = case KpNodes of
38                  [] -> nil;
39                  KpNodes ->
40                      vtree_modify:write_new_root(Vt, KpNodes)
41              end,
42    ?LOG_DEBUG("Cleanup took: ~ps~n",
43               [erlang:convert_time_unit(erlang:monotonic_time() - T1, native, microsecond)/1000000]),
44    Vt#vtree{root=NewRoot}.
45
46-spec cleanup_multiple(Vt :: #vtree{}, ToCleanup :: [#kv_node{}],
47                       Existing :: [#kp_node{}]) -> [#kp_node{}].
48cleanup_multiple(Vt, ToCleanup, Existing) ->
49    ModifyFuns = {fun cleanup_nodes/2, fun partition_nodes/3},
50    vtree_modify:modify_multiple(Vt, ModifyFuns, ToCleanup, Existing, []).
51
52
53-spec cleanup_nodes(ToCleanup :: [#kv_node{}], Existing :: [#kv_node{}]) ->
54                           [#kv_node{}].
55cleanup_nodes(ToCleanup, Existing) ->
56    % Filter out all children that should be deleted
57    [E || E <- Existing, not(member_of_nodes(E, ToCleanup))].
58
59
60% Returns true if a given KV-node is member of a list of KV-nodes.
61% The `partition` is used to determine whether it is a member or not.
62-spec member_of_nodes(Node :: #kv_node{}, Nodes :: [#kv_node{}]) -> boolean().
63member_of_nodes(_A, []) ->
64    false;
65member_of_nodes(A, [B|_]) when A#kv_node.partition == B#kv_node.partition ->
66    true;
67member_of_nodes(A, [_B|Rest]) ->
68    member_of_nodes(A, Rest).
69
70
71% NOTE vmx 2014-08-05: This isn't efficient for the cleanup. But for now it's
72% the easist possible way with maximum code re-use. The cleanup will be moved
73% to C in one point anyway.
74-spec partition_nodes(ToPartition :: [#kv_node{}], KpNodes :: [#kp_node{}],
75                      Less :: lessfun()) -> [[#kv_node{}]].
76partition_nodes(ToPartition, KpNodes, _Less) ->
77    % Put the node into every partition as we want to search the full tree
78    lists:map(fun(_) -> ToPartition end, KpNodes).
79