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]).
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
, [], []).
36 %%--------------------------------------------------------------------
37 %% Function: query(Id) -> seeding | {bitfield, BitField} | unknown
38 %% Description: Query for the state of TorrentId, Id.
39 %%--------------------------------------------------------------------
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} |
52 %% Description: Initiates the server
53 %%--------------------------------------------------------------------
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} |
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
}
73 handle_call(_Request
, _From
, State
) ->
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
) ->
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(),
99 handle_info(_Info
, 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
) ->
119 %%--------------------------------------------------------------------
120 %%% Internal functions
121 %%--------------------------------------------------------------------
123 %%--------------------------------------------------------------------
124 %% Func: prune_disk_state(Tracking) -> ok
125 %% Description: Prune the persistent disk state for anything we are
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
145 etorrent_piece_diskstate:new(FName
, seeding
);
147 BitField
= etorrent_piece_mgr:bitfield(Id
),
148 etorrent_piece_diskstate:new(FName
, {bitfield
, BitField
});
150 BitField
= etorrent_piece_mgr:bitfield(Id
),
151 etorrent_piece_diskstate:new(FName
, {bitfield
, BitField
});
155 persist_disk_state(Next
)