1 %%%-------------------------------------------------------------------
2 %%% File : etorrent_fast_resume.erl
3 %%% Author : Jesper Louis Andersen <jlouis@ogre.home>
4 %%% Description : Fast resume process
6 %%% Created : 16 Jul 2008 by Jesper Louis Andersen <jlouis@ogre.home>
7 %%%-------------------------------------------------------------------
8 -module(etorrent_fast_resume
).
10 -behaviour(gen_server
).
12 -include("etorrent_mnesia_table.hrl").
15 -export([start_link
/0, query_state
/1, stop
/0]).
17 %% gen_server callbacks
18 -export([init
/1, handle_call
/3, handle_cast
/2, handle_info
/2,
19 terminate
/2, code_change
/3]).
21 -record(state
, { timer
= none
}).
23 -define(SERVER
, ?MODULE
).
24 -define(PERSIST_TIME
, 300). % Every 300 secs, may be done configurable.
26 %%====================================================================
28 %%====================================================================
29 %%--------------------------------------------------------------------
30 %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
31 %% Description: Starts the server
32 %%--------------------------------------------------------------------
34 gen_server:start_link({local
, ?SERVER
}, ?MODULE
, [], []).
37 %%--------------------------------------------------------------------
38 %% Function: query(Id) -> seeding | {bitfield, BitField} | unknown
39 %% Description: Query for the state of TorrentId, Id.
40 %%--------------------------------------------------------------------
42 gen_server:call(?SERVER
, {query_state
, Id
}).
44 %%--------------------------------------------------------------------
46 %% Description: Stop the fast-resume server.
47 %%--------------------------------------------------------------------
48 stop() -> gen_server:call(?SERVER
, stop
).
50 %%====================================================================
51 %% gen_server callbacks
52 %%====================================================================
54 %%--------------------------------------------------------------------
55 %% Function: init(Args) -> {ok, State} |
56 %% {ok, State, Timeout} |
59 %% Description: Initiates the server
60 %%--------------------------------------------------------------------
62 process_flag(trap_exit
, true
),
63 {ok
, TRef
} = timer:send_interval(timer:seconds(?PERSIST_TIME
), self(), persist
),
64 {ok
, #state
{ timer
= TRef
}}.
66 %%--------------------------------------------------------------------
67 %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
68 %% {reply, Reply, State, Timeout} |
70 %% {noreply, State, Timeout} |
71 %% {stop, Reason, Reply, State} |
72 %% {stop, Reason, State}
73 %% Description: Handling call messages
74 %%--------------------------------------------------------------------
75 handle_call({query_state
, Id
}, _From
, S
) ->
76 {atomic
, [TM
]} = etorrent_tracking_map:select(Id
),
77 case etorrent_piece_diskstate:select(TM#tracking_map
.filename
) of
78 [] -> {reply
, unknown
, S
};
79 [R
] -> {reply
, R#piece_diskstate
.state
, S
}
81 handle_call(stop
, _From
, S
) ->
82 {stop
, normal
, ok
, S
};
83 handle_call(_Request
, _From
, State
) ->
85 {reply
, Reply
, State
}.
87 %%--------------------------------------------------------------------
88 %% Function: handle_cast(Msg, State) -> {noreply, State} |
89 %% {noreply, State, Timeout} |
90 %% {stop, Reason, State}
91 %% Description: Handling cast messages
92 %%--------------------------------------------------------------------
93 handle_cast(_Msg
, State
) ->
96 %%--------------------------------------------------------------------
97 %% Function: handle_info(Info, State) -> {noreply, State} |
98 %% {noreply, State, Timeout} |
99 %% {stop, Reason, State}
100 %% Description: Handling all non call/cast messages
101 %%--------------------------------------------------------------------
102 handle_info(persist
, S
) ->
103 error_logger:info_report([persist_to_disk
]),
106 handle_info(_Info
, State
) ->
110 %%--------------------------------------------------------------------
111 %% Function: terminate(Reason, State) -> void()
112 %% Description: This function is called by a gen_server when it is about to
113 %% terminate. It should be the opposite of Module:init/1 and do any necessary
114 %% cleaning up. When it returns, the gen_server terminates with Reason.
115 %% The return value is ignored.
116 %%--------------------------------------------------------------------
117 terminate(normal
, _State
) ->
120 terminate(_Reason
, _State
) ->
124 %%--------------------------------------------------------------------
125 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
126 %% Description: Convert process state when code is changed
127 %%--------------------------------------------------------------------
128 code_change(_OldVsn
, State
, _Extra
) ->
131 %%--------------------------------------------------------------------
132 %%% Internal functions
133 %%--------------------------------------------------------------------
135 %%--------------------------------------------------------------------
136 %% Func: prune_disk_state(Tracking) -> ok
137 %% Description: Prune the persistent disk state for anything we are
139 %%--------------------------------------------------------------------
140 prune_disk_state(Tracking
) ->
141 TrackedSet
= sets:from_list(
142 [T#tracking_map
.filename
|| T
<- Tracking
]),
143 ok
= etorrent_piece_diskstate:prune(TrackedSet
).
145 %%--------------------------------------------------------------------
146 %% Func: persist_disk_state(Tracking) -> ok
147 %% Description: Persist state on disk
148 %%--------------------------------------------------------------------
149 persist_disk_state([]) ->
151 persist_disk_state([#tracking_map
{ id
= Id
,
152 filename
= FName
} | Next
]) ->
153 case etorrent_torrent:select(Id
) of
154 [] -> persist_disk_state(Next
);
155 [S
] -> case S#torrent
.state
of
157 etorrent_piece_diskstate:new(FName
, seeding
);
159 BitField
= etorrent_piece_mgr:bitfield(Id
),
160 etorrent_piece_diskstate:new(FName
, {bitfield
, BitField
});
162 BitField
= etorrent_piece_mgr:bitfield(Id
),
163 etorrent_piece_diskstate:new(FName
, {bitfield
, BitField
});
167 persist_disk_state(Next
)
171 {atomic
, Torrents
} = etorrent_tracking_map:all(),
172 prune_disk_state(Torrents
),
173 persist_disk_state(Torrents
),
174 etorrent_event_mgr:persisted_state_to_disk(),