xref: /5.5.2/couchdb/test/etap/022-btree-copy.t (revision 6b32ccaa)
1#!/usr/bin/env escript
2%% -*- erlang -*-
3%%! -pa ./src/couchdb -sasl errlog_type error -noshell -smp enable
4
5% Licensed under the Apache License, Version 2.0 (the "License"); you may not
6% use this file except in compliance with the License. You may obtain a copy of
7% the License at
8%
9%   http://www.apache.org/licenses/LICENSE-2.0
10%
11% Unless required by applicable law or agreed to in writing, software
12% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14% License for the specific language governing permissions and limitations under
15% the License.
16
17-record(btree, {
18    fd,
19    root,
20    extract_kv,
21    assemble_kv,
22    less,
23    reduce,
24    kv_chunk_threshold = 16#4ff,
25    kp_chunk_threshold = 2 * 16#4ff,
26    binary_mode = false
27}).
28
29path(FileName) ->
30    test_util:build_file(FileName).
31
32main(_) ->
33    test_util:init_code_path(),
34    etap:plan(76),
35    case (catch test()) of
36        ok ->
37            etap:end_tests();
38        Other ->
39            etap:diag(io_lib:format("Test died abnormally: ~p", [Other])),
40            etap:bail()
41    end,
42    ok.
43
44test() ->
45    couch_file_write_guard:sup_start_link(),
46    ReduceCount = fun(reduce, KVs) ->
47            length(KVs);
48        (rereduce, Reds) ->
49            lists:sum(Reds)
50    end,
51
52    test_copy(10, ReduceCount),
53    test_copy(20, ReduceCount),
54    test_copy(50, ReduceCount),
55    test_copy(100, ReduceCount),
56    test_copy(300, ReduceCount),
57    test_copy(500, ReduceCount),
58    test_copy(700, ReduceCount),
59    test_copy(811, ReduceCount),
60    test_copy(2333, ReduceCount),
61    test_copy(6594, ReduceCount),
62    test_copy(6666, ReduceCount),
63    test_copy(9999, ReduceCount),
64    test_copy(15003, ReduceCount),
65    test_copy(21477, ReduceCount),
66    test_copy(38888, ReduceCount),
67    test_copy(66069, ReduceCount),
68    test_copy(150123, ReduceCount),
69    test_copy(420789, ReduceCount),
70    test_copy(711321, ReduceCount),
71    ok.
72
73
74test_copy(NumItems, ReduceFun) ->
75    etap:diag("Running btree copy test for " ++ integer_to_list(NumItems) ++ " items"),
76    KVs = [{I, I} || I <- lists:seq(1, NumItems)],
77
78    OriginalFileName = path(
79        "test/etap/test_btree_" ++ integer_to_list(length(KVs)) ++ ".dat"),
80    CopyFileName = path(
81        "test/etap/test_btree_" ++ integer_to_list(NumItems) ++ "_copy.dat"),
82
83    {ok, #btree{fd = Fd} = Btree} = make_btree(OriginalFileName, KVs, ReduceFun),
84    {_, Red, _} = couch_btree:get_state(Btree),
85
86    {ok, FdCopy} = couch_file:open(CopyFileName, [create, overwrite]),
87    CopyCallback = fun(KV, Acc) -> {KV, Acc + 1} end,
88    {ok, RootCopy, FinalAcc} = couch_btree_copy:copy(
89        Btree, FdCopy, [{before_kv_write, {CopyCallback, 0}}]),
90    ok = couch_file:flush(FdCopy),
91    etap:is(FinalAcc, length(KVs),
92        "couch_btree_copy returned the right final user acc"),
93
94    {ok, BtreeCopy} = couch_btree:open(
95        RootCopy, FdCopy, [{reduce, ReduceFun}]),
96    check_btree_copy(BtreeCopy, Red, KVs),
97
98    ok = couch_file:close(Fd),
99    ok = couch_file:close(FdCopy),
100    ok = file:delete(OriginalFileName),
101    ok = file:delete(CopyFileName).
102
103
104check_btree_copy(Btree, Red, KVs) ->
105    {_, RedCopy, _} = couch_btree:get_state(Btree),
106    etap:is(Red, RedCopy, "btree copy has same reduce value"),
107    {ok, _, CopyKVs} = couch_btree:fold(
108        Btree,
109        fun(KV, _, Acc) -> {ok, [KV | Acc]} end,
110        [], []),
111    etap:is(KVs, lists:reverse(CopyKVs), "btree copy has same keys").
112
113
114make_btree(Filename, KVs, ReduceFun) ->
115    {ok, Fd} = couch_file:open(Filename, [create, overwrite]),
116    {ok, Btree} = couch_btree:open(
117        nil, Fd, [{reduce, ReduceFun}]),
118    {ok, Btree2} = couch_btree:add_remove(Btree, KVs, []),
119    {_, Red, _} = couch_btree:get_state(Btree2),
120    etap:is(length(KVs), Red,
121        "Inserted " ++ integer_to_list(length(KVs)) ++ " items into a new btree"),
122    ok = couch_file:sync(Fd),
123    {ok, Btree2}.
124