Skip to content

Commit

Permalink
Plug a state-close-down hole in etorrent_dht.
Browse files Browse the repository at this point in the history
When we terminate, we should store the state of the DHT table upon normal and shutdowns.
This is achieved by trapping exits and then handling the case explicitly in a nice way in the
code base. I have verified that there are no other linked processes to this process by inspection,
so we don't expect any other kind of 'EXIT' messages to show up.
  • Loading branch information
jlouis committed Oct 27, 2012
1 parent 4575584 commit 9e4d1c0
Showing 1 changed file with 22 additions and 13 deletions.
35 changes: 22 additions & 13 deletions src/etorrent_dht_state.erl
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@
code_change/3]).

-record(state, {
node_id,
buckets=b_new(), % The actual routing table
node_timers=timer_tree(), % Node activity times and timeout references
buck_timers=timer_tree(),% Bucker activity times and timeout references
node_timeout=10*60*1000, % Default node keepalive timeout
buck_timeout=5*60*1000, % Default bucket refresh timeout
state_file="/tmp/dht_state"}). % Path to persistent state
node_id :: pos_integer(),
buckets=b_new() :: term(), % The actual routing table
node_timers=timer_tree() :: term(), % Node activity times and timeout references
buck_timers=timer_tree() :: term(),% Bucker activity times and timeout references
node_timeout=10*60*1000 :: pos_integer(), % Default node keepalive timeout
buck_timeout=5*60*1000 :: pos_integer(), % Default bucket refresh timeout
state_file="/tmp/dht_state" :: string() }). % Path to persistent state
%
% The bucket refresh timeout is the amount of time that the
% server will tolerate a node to be disconnected before it
Expand Down Expand Up @@ -322,6 +322,10 @@ random_node_tag() ->

%% @private
init([StateFile]) ->
%% This function has to trap exits in order to save the state file upon a close-down
%% of the service.
process_flag(trap_exit, true),

% Initialize the table of unreachable nodes when the server is started.
% The safe_ping and unsafe_ping functions aren't exported outside of
% of this module so they should fail unless the server is not running.
Expand Down Expand Up @@ -638,12 +642,17 @@ handle_info({inactive_bucket, Range}, State) ->
{noreply, NewState}.

%% @private
terminate(_, State) ->
#state{
node_id=Self,
buckets=Buckets,
state_file=StateFile} = State,
dump_state(StateFile, Self, b_node_list(Buckets)).
terminate(Reason,
#state {
node_id = NodeId,
buckets = Buckets,
state_file = Statefile })
when Reason == normal; Reason == shutdown ->
dump_state(Statefile, NodeId, b_node_list(Buckets));
terminate(_Reason, _State) ->
%% Any other error type means that we can't trust the internal state, so just
%% close down without storing the state file.
ok.

dump_state(Filename, Self, NodeList) ->
PersistentState = [{node_id, Self}, {node_set, NodeList}],
Expand Down

0 comments on commit 9e4d1c0

Please sign in to comment.