Handle HAVE_ALL and HAVE_NONE. Cleanup the BITFIELD message.
[etorrent.git] / lib / etorrent-1.0 / src / etorrent_fast_resume.erl
blob3e7ad32267e797b45622fb4896a0605b1b3a2389
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, 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 %%====================================================================
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, [], []).
37 %%--------------------------------------------------------------------
38 %% Function: query(Id) -> seeding | {bitfield, BitField} | unknown
39 %% Description: Query for the state of TorrentId, Id.
40 %%--------------------------------------------------------------------
41 query_state(Id) ->
42 gen_server:call(?SERVER, {query_state, Id}).
44 %%--------------------------------------------------------------------
45 %% Function: stop()
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} |
57 %% ignore |
58 %% {stop, Reason}
59 %% Description: Initiates the server
60 %%--------------------------------------------------------------------
61 init([]) ->
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} |
69 %% {noreply, State} |
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}
80 end;
81 handle_call(stop, _From, S) ->
82 {stop, normal, ok, S};
83 handle_call(_Request, _From, State) ->
84 Reply = ok,
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) ->
94 {noreply, 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]),
104 persist_to_disk(),
105 {noreply, S};
106 handle_info(_Info, State) ->
107 {noreply, 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) ->
118 persist_to_disk(),
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) ->
129 {ok, State}.
131 %%--------------------------------------------------------------------
132 %%% Internal functions
133 %%--------------------------------------------------------------------
135 %%--------------------------------------------------------------------
136 %% Func: prune_disk_state(Tracking) -> ok
137 %% Description: Prune the persistent disk state for anything we are
138 %% not tracking.
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
156 seeding ->
157 etorrent_piece_diskstate:new(FName, seeding);
158 leeching ->
159 BitField = etorrent_piece_mgr:bitfield(Id),
160 etorrent_piece_diskstate:new(FName, {bitfield, BitField});
161 endgame ->
162 BitField = etorrent_piece_mgr:bitfield(Id),
163 etorrent_piece_diskstate:new(FName, {bitfield, BitField});
164 unknown ->
166 end,
167 persist_disk_state(Next)
168 end.
170 persist_to_disk() ->
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(),