Allow dependent applications to already be started.
[etorrent.git] / lib / etorrent-1.0 / src / etorrent_fast_resume.erl
blob306d973c1d358e999a9d0f67dbae578bd765c871
1 %%%-------------------------------------------------------------------
2 %%% File : etorrent_fast_resume.erl
3 %%% Author : Jesper Louis Andersen <jlouis@ogre.home>
4 %%% Description : Fast resume process
5 %%%
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").
14 %% API
15 -export([start_link/0, query_state/1]).
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 %%====================================================================
27 %% API
28 %%====================================================================
29 %%--------------------------------------------------------------------
30 %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
31 %% Description: Starts the server
32 %%--------------------------------------------------------------------
33 start_link() ->
34 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
36 %%--------------------------------------------------------------------
37 %% Function: query(Id) -> seeding | {bitfield, BitField} | unknown
38 %% Description: Query for the state of TorrentId, Id.
39 %%--------------------------------------------------------------------
40 query_state(Id) ->
41 gen_server:call(?SERVER, {query_state, Id}).
43 %%====================================================================
44 %% gen_server callbacks
45 %%====================================================================
47 %%--------------------------------------------------------------------
48 %% Function: init(Args) -> {ok, State} |
49 %% {ok, State, Timeout} |
50 %% ignore |
51 %% {stop, Reason}
52 %% Description: Initiates the server
53 %%--------------------------------------------------------------------
54 init([]) ->
55 {ok, TRef} = timer:send_interval(timer:seconds(?PERSIST_TIME), self(), persist),
56 {ok, #state{ timer = TRef}}.
58 %%--------------------------------------------------------------------
59 %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
60 %% {reply, Reply, State, Timeout} |
61 %% {noreply, State} |
62 %% {noreply, State, Timeout} |
63 %% {stop, Reason, Reply, State} |
64 %% {stop, Reason, State}
65 %% Description: Handling call messages
66 %%--------------------------------------------------------------------
67 handle_call({query_state, Id}, _From, S) ->
68 {atomic, [TM]} = etorrent_tracking_map:select(Id),
69 case etorrent_piece_diskstate:select(TM#tracking_map.filename) of
70 [] -> {reply, unknown, S};
71 [R] -> {reply, R#piece_diskstate.state, S}
72 end;
73 handle_call(_Request, _From, State) ->
74 Reply = ok,
75 {reply, Reply, State}.
77 %%--------------------------------------------------------------------
78 %% Function: handle_cast(Msg, State) -> {noreply, State} |
79 %% {noreply, State, Timeout} |
80 %% {stop, Reason, State}
81 %% Description: Handling cast messages
82 %%--------------------------------------------------------------------
83 handle_cast(_Msg, State) ->
84 {noreply, State}.
86 %%--------------------------------------------------------------------
87 %% Function: handle_info(Info, State) -> {noreply, State} |
88 %% {noreply, State, Timeout} |
89 %% {stop, Reason, State}
90 %% Description: Handling all non call/cast messages
91 %%--------------------------------------------------------------------
92 handle_info(persist, S) ->
93 error_logger:info_report([persist_to_disk]),
94 {atomic, Torrents} = etorrent_tracking_map:all(),
95 prune_disk_state(Torrents),
96 persist_disk_state(Torrents),
97 etorrent_event_mgr:persisted_state_to_disk(),
98 {noreply, S};
99 handle_info(_Info, State) ->
100 {noreply, State}.
102 %%--------------------------------------------------------------------
103 %% Function: terminate(Reason, State) -> void()
104 %% Description: This function is called by a gen_server when it is about to
105 %% terminate. It should be the opposite of Module:init/1 and do any necessary
106 %% cleaning up. When it returns, the gen_server terminates with Reason.
107 %% The return value is ignored.
108 %%--------------------------------------------------------------------
109 terminate(_Reason, _State) ->
112 %%--------------------------------------------------------------------
113 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
114 %% Description: Convert process state when code is changed
115 %%--------------------------------------------------------------------
116 code_change(_OldVsn, State, _Extra) ->
117 {ok, State}.
119 %%--------------------------------------------------------------------
120 %%% Internal functions
121 %%--------------------------------------------------------------------
123 %%--------------------------------------------------------------------
124 %% Func: prune_disk_state(Tracking) -> ok
125 %% Description: Prune the persistent disk state for anything we are
126 %% not tracking.
127 %%--------------------------------------------------------------------
128 prune_disk_state(Tracking) ->
129 TrackedSet = sets:from_list(
130 [T#tracking_map.filename || T <- Tracking]),
131 ok = etorrent_piece_diskstate:prune(TrackedSet).
133 %%--------------------------------------------------------------------
134 %% Func: persist_disk_state(Tracking) -> ok
135 %% Description: Persist state on disk
136 %%--------------------------------------------------------------------
137 persist_disk_state([]) ->
139 persist_disk_state([#tracking_map { id = Id,
140 filename = FName} | Next]) ->
141 case etorrent_torrent:select(Id) of
142 [] -> persist_disk_state(Next);
143 [S] -> case S#torrent.state of
144 seeding ->
145 etorrent_piece_diskstate:new(FName, seeding);
146 leeching ->
147 BitField = etorrent_piece_mgr:bitfield(Id),
148 etorrent_piece_diskstate:new(FName, {bitfield, BitField});
149 endgame ->
150 BitField = etorrent_piece_mgr:bitfield(Id),
151 etorrent_piece_diskstate:new(FName, {bitfield, BitField});
152 unknown ->
154 end,
155 persist_disk_state(Next)
156 end.