Skip to content
This repository
Browse code

Merge pull request #30 from cloudant/13606-node-info-ets

Publish node metadata in a protected ets table

BugzID: 13606
  • Loading branch information...
commit 4704323acf066edd95a9b3be33ada9cb0d903e56 2 parents 6469c35 + 57bb83e
Adam Kocoloski authored May 25, 2012

Showing 1 changed file with 42 additions and 27 deletions. Show diff stats Hide diff stats

  1. 69  src/mem3_nodes.erl
69  src/mem3_nodes.erl
@@ -22,37 +22,48 @@
22 22
 -include("mem3.hrl").
23 23
 -include_lib("couch/include/couch_db.hrl").
24 24
 
25  
--record(state, {changes_pid, update_seq, nodes}).
  25
+-record(state, {changes_pid, update_seq}).
26 26
 
27 27
 start_link() ->
28 28
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
29 29
 
30 30
 get_nodelist() ->
31  
-    gen_server:call(?MODULE, get_nodelist).
  31
+    try
  32
+        lists:sort([N || {N,_} <- ets:tab2list(?MODULE)])
  33
+    catch error:badarg ->
  34
+        gen_server:call(?MODULE, get_nodelist)
  35
+    end.
32 36
 
33 37
 get_node_info(Node, Key) ->
34  
-    gen_server:call(?MODULE, {get_node_info, Node, Key}).
  38
+    try
  39
+        couch_util:get_value(Key, ets:lookup_element(?MODULE, Node, 2))
  40
+    catch error:badarg ->
  41
+        gen_server:call(?MODULE, {get_node_info, Node, Key})
  42
+    end.
35 43
 
36 44
 init([]) ->
37  
-    {Nodes, UpdateSeq} = initialize_nodelist(),
  45
+    ets:new(?MODULE, [named_table, {read_concurrency, true}]),
  46
+    UpdateSeq = initialize_nodelist(),
38 47
     {Pid, _} = spawn_monitor(fun() -> listen_for_changes(UpdateSeq) end),
39  
-    {ok, #state{changes_pid = Pid, update_seq = UpdateSeq, nodes = Nodes}}.
  48
+    {ok, #state{changes_pid = Pid, update_seq = UpdateSeq}}.
40 49
 
41 50
 handle_call(get_nodelist, _From, State) ->
42  
-    {reply, lists:sort(dict:fetch_keys(State#state.nodes)), State};
  51
+    {reply, lists:sort([N || {N,_} <- ets:tab2list(?MODULE)]), State};
43 52
 handle_call({get_node_info, Node, Key}, _From, State) ->
44  
-    case dict:find(Node, State#state.nodes) of
45  
-        {ok, NodeInfo} ->
46  
-            {reply, couch_util:get_value(Key, NodeInfo), State};
47  
-        error ->
48  
-            {reply, error, State}
49  
-    end;
50  
-handle_call({add_node, Node, NodeInfo}, _From, #state{nodes=Nodes} = State) ->
  53
+    Resp = try
  54
+        couch_util:get_value(Key, ets:lookup_element(?MODULE, Node, 2))
  55
+    catch error:badarg ->
  56
+        error
  57
+    end,
  58
+    {reply, Resp, State};
  59
+handle_call({add_node, Node, NodeInfo}, _From, State) ->
51 60
     gen_event:notify(mem3_events, {add_node, Node}),
52  
-    {reply, ok, State#state{nodes = dict:store(Node, NodeInfo, Nodes)}};
53  
-handle_call({remove_node, Node}, _From, #state{nodes=Nodes} = State) ->
  61
+    ets:insert(?MODULE, Node, NodeInfo),
  62
+    {reply, ok, State};
  63
+handle_call({remove_node, Node}, _From, State) ->
54 64
     gen_event:notify(mem3_events, {remove_node, Node}),
55  
-    {reply, ok, State#state{nodes = dict:erase(Node, Nodes)}};
  65
+    ets:delete(?MODULE, Node),
  66
+    {reply, ok, State};
56 67
 handle_call(_Call, _From, State) ->
57 68
     {noreply, State}.
58 69
 
@@ -74,6 +85,10 @@ handle_info(_Info, State) ->
74 85
 terminate(_Reason, _State) ->
75 86
     ok.
76 87
 
  88
+code_change(_OldVsn, {state, ChangesPid, UpdateSeq, _}, _Extra) ->
  89
+    ets:new(?MODULE, [named_table, {read_concurrency, true}]),
  90
+    initialize_nodelist(),
  91
+    {ok, #state{changes_pid = ChangesPid, update_seq = UpdateSeq}};
77 92
 code_change(_OldVsn, State, _Extra) ->
78 93
     {ok, State}.
79 94
 
@@ -82,27 +97,27 @@ code_change(_OldVsn, State, _Extra) ->
82 97
 initialize_nodelist() ->
83 98
     DbName = couch_config:get("mem3", "node_db", "nodes"),
84 99
     {ok, Db} = mem3_util:ensure_exists(DbName),
85  
-    {ok, _, {_, Nodes0}} = couch_btree:fold(Db#db.id_tree, fun first_fold/3,
86  
-                                       {Db, dict:new()}, []),
  100
+    {ok, _, Db} = couch_btree:fold(Db#db.id_tree, fun first_fold/3, Db, []),
87 101
     % add self if not already present
88  
-    case dict:find(node(), Nodes0) of
89  
-    {ok, _} ->
90  
-        Nodes = Nodes0;
91  
-    error ->
  102
+    case ets:lookup(?MODULE, node()) of
  103
+    [_] ->
  104
+        ok;
  105
+    [] ->
  106
+        ets:insert(?MODULE, {node(), []}),
92 107
         Doc = #doc{id = couch_util:to_binary(node())},
93  
-        {ok, _} = couch_db:update_doc(Db, Doc, []),
94  
-        Nodes = dict:store(node(), [], Nodes0)
  108
+        {ok, _} = couch_db:update_doc(Db, Doc, [])
95 109
     end,
96 110
     couch_db:close(Db),
97  
-    {Nodes, Db#db.update_seq}.
  111
+    Db#db.update_seq.
98 112
 
99 113
 first_fold(#full_doc_info{id = <<"_design/", _/binary>>}, _, Acc) ->
100 114
     {ok, Acc};
101 115
 first_fold(#full_doc_info{deleted=true}, _, Acc) ->
102 116
     {ok, Acc};
103  
-first_fold(#full_doc_info{id=Id}=DocInfo, _, {Db, Dict}) ->
  117
+first_fold(#full_doc_info{id=Id}=DocInfo, _, Db) ->
104 118
     {ok, #doc{body={Props}}} = couch_db:open_doc(Db, DocInfo),
105  
-    {ok, {Db, dict:store(mem3_util:to_atom(Id), Props, Dict)}}.
  119
+    ets:insert(?MODULE, {mem3_util:to_atom(Id), Props}),
  120
+    {ok, Db}.
106 121
 
107 122
 listen_for_changes(Since) ->
108 123
     DbName = couch_config:get("mem3", "node_db", "nodes"),

0 notes on commit 4704323

Please sign in to comment.
Something went wrong with that request. Please try again.