summaryrefslogtreecommitdiff
path: root/src/couch_pse_tests/src/cpse_test_ref_counting.erl
blob: a0123d1ca0d3dd5eecd453755601794365c68698 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.

-module(cpse_test_ref_counting).
-compile(export_all).
-compile(nowarn_export_all).

-include_lib("eunit/include/eunit.hrl").
-include_lib("couch/include/couch_db.hrl").

-define(NUM_CLIENTS, 1000).

setup_each() ->
    {ok, Db} = cpse_util:create_db(),
    {Db, self()}.

teardown_each({Db, _}) ->
    ok = couch_server:delete(couch_db:name(Db), []).

cpse_empty_monitors({Db, Pid}) ->
    Pids = couch_db_engine:monitored_by(Db),
    ?assert(is_list(Pids)),
    Expected = [
        Pid,
        couch_db:get_pid(Db),
        whereis(couch_stats_process_tracker)
    ],
    ?assertEqual([], Pids -- Expected).

cpse_incref_decref({Db, _}) ->
    {Pid, _} = Client = start_client(Db),
    wait_client(Client),

    Pids1 = couch_db_engine:monitored_by(Db),
    ?assert(lists:member(Pid, Pids1)),

    close_client(Client),

    Pids2 = couch_db_engine:monitored_by(Db),
    ?assert(not lists:member(Pid, Pids2)).

cpse_incref_decref_many({Db, _}) ->
    Clients = lists:map(
        fun(_) ->
            start_client(Db)
        end,
        lists:seq(1, ?NUM_CLIENTS)
    ),

    lists:foreach(fun(C) -> wait_client(C) end, Clients),

    Pids1 = couch_db_engine:monitored_by(Db),
    % +3 for self, db pid, and process tracker
    ?assertEqual(?NUM_CLIENTS + 3, length(Pids1)),

    lists:foreach(fun(C) -> close_client(C) end, Clients),

    Pids2 = couch_db_engine:monitored_by(Db),
    ?assertEqual(3, length(Pids2)).

start_client(Db0) ->
    spawn_monitor(fun() ->
        {ok, Db1} = couch_db:open_int(couch_db:name(Db0), []),

        receive
            {waiting, Pid} ->
                Pid ! go
        after 1000 ->
            erlang:error(timeout)
        end,

        receive
            close ->
                couch_db:close(Db1),
                ok
        after 1000 ->
            erlang:error(timeout)
        end
    end).

wait_client({Pid, _Ref}) ->
    Pid ! {waiting, self()},
    receive
        go -> ok
    after 1000 ->
        erlang:error(timeout)
    end.

close_client({Pid, Ref}) ->
    Pid ! close,
    receive
        {'DOWN', Ref, _, _, _} ->
            ok
    after 1000 ->
        erlang:error(timeout)
    end.