From 9068058e43eb4fe65632d575d186144ada7191fe Mon Sep 17 00:00:00 2001 From: Jesper Louis Andersen Date: Thu, 17 Jul 2008 20:42:32 +0200 Subject: [PATCH] Optimize the startup. * Only manipulate the #piece table once in startup. * Cache the path-map value to avoid doing excessive amounts of mnesia lookups. --- lib/etorrent-1.0/src/etorrent_fs_checker.erl | 77 +++++++++++++--------------- lib/etorrent-1.0/src/etorrent_piece.erl | 11 +++- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/lib/etorrent-1.0/src/etorrent_fs_checker.erl b/lib/etorrent-1.0/src/etorrent_fs_checker.erl index bb4a89c..9d3417f 100644 --- a/lib/etorrent-1.0/src/etorrent_fs_checker.erl +++ b/lib/etorrent-1.0/src/etorrent_fs_checker.erl @@ -11,10 +11,7 @@ -include("etorrent_mnesia_table.hrl"). %% API --export([read_and_check_torrent/3, load_torrent/1, ensure_file_sizes_correct/1, - check_torrent_contents/2]). - --define(DEFAULT_CHECK_SLEEP_TIME, 10). +-export([read_and_check_torrent/3, load_torrent/1, ensure_file_sizes_correct/1]). %%==================================================================== %% API @@ -38,11 +35,11 @@ read_and_check_torrent(Id, SupervisorPid, Path) -> %% Check the contents of the torrent, updates the state of the piecemap FS = etorrent_t_sup:get_pid(SupervisorPid, fs), case etorrent_fast_resume:query_state(Id) of - seeding -> check_torrent_contents_seed(Id); - {bitfield, BF} -> check_torrent_contents_bitfield(Id, BF, NumberOfPieces); - leeching -> ok = check_torrent_contents(FS, Id); + seeding -> initialize_pieces_seed(Id, FilePieceList); + {bitfield, BF} -> initialize_pieces_from_bitfield(Id, BF, NumberOfPieces, FilePieceList); + leeching -> ok = initialize_pieces_from_disk(FS, Id, FilePieceList); %% XXX: The next one here could initialize with not_fetched all over - unknown -> ok = check_torrent_contents(FS, Id) + unknown -> ok = initialize_pieces_from_disk(FS, Id, FilePieceList) end, {ok, Torrent, FS, Infohash, NumberOfPieces}. @@ -76,46 +73,37 @@ ensure_file_sizes_correct(Files) -> Files), ok. -check_torrent_contents_seed(Id) -> - {atomic, Pieces} = etorrent_piece:select(Id), +initialize_pieces_seed(Id, FilePieceList) -> lists:foreach( - fun(#piece { piece_number = PN }) -> - ok = etorrent_piece:dirty_statechange(Id, PN, fetched) + fun ({PN, {Hash, Files}}) -> + ok = etorrent_piece:new(Id, PN, Hash, Files, fetched) end, - Pieces), - ok. + FilePieceList). -check_torrent_contents_bitfield(Id, BitField, NumPieces) -> - {atomic, Pieces} = etorrent_piece:select(Id), +initialize_pieces_from_bitfield(Id, BitField, NumPieces, FilePieceList) -> {ok, Set} = etorrent_peer_communication:destruct_bitfield(NumPieces, BitField), lists:foreach( - fun(#piece { piece_number = PN }) -> - State = case gb_sets:is_element(PN, Set) of - true -> fetched; - false -> not_fetched - end, - ok = etorrent_piece:dirty_statechange(Id, PN, State) + fun ({PN, {Hash, Files}}) -> + ok = etorrent_piece:new(Id, PN, Hash, Files, + case gb_sets:is_element(PN, Set) of + true -> fetched; + false -> not_fetched + end) end, - Pieces), - ok. + FilePieceList). + -check_torrent_contents(FS, Id) -> - {atomic, Pieces} = etorrent_piece:select(Id), +initialize_pieces_from_disk(FS, Id, FilePieceList) -> lists:foreach( - fun(#piece{piece_number = PieceNum, hash = Hash}) -> - {ok, Data} = etorrent_fs:read_piece(FS, PieceNum), - State = - case Hash =:= crypto:sha(Data) of - true -> - fetched; - false -> - not_fetched - end, - ok = etorrent_piece:dirty_statechange(Id, PieceNum, State), - timer:sleep(?DEFAULT_CHECK_SLEEP_TIME) + fun ({PN, {Hash, Files}}) -> + {ok, Data} = etorrent_fs:read_piece(FS, PN), + State = case Hash =:= crypto:sha(Data) of + true -> fetched; + false -> not_fetched + end, + ok = etorrent_piece:new(Id, PN, Hash, Files, State) end, - Pieces), - ok. + FilePieceList). build_dictionary_on_files(TorrentId, Torrent, Files) -> Pieces = etorrent_metainfo:get_pieces(Torrent), @@ -165,8 +153,15 @@ construct_fpmap(FileList, Offset, PieceSize, LastPieceSize, [{Num, {Hash, lists:reverse(Ops)}} | Done], N+1). insert_into_path_map(Ops, TorrentId) -> - [{etorrent_path_map:select(Path, TorrentId), Offset, Size} || - {Path, Offset, Size} <- Ops]. + insert_into_path_map(Ops, TorrentId, none, none). + +insert_into_path_map([], _, _, _) -> []; +insert_into_path_map([{Path, Offset, Size} | Next], TorrentId, Path, Keyval) -> + [{Keyval, Offset, Size} | insert_into_path_map(Next, TorrentId, Path, Keyval)]; +insert_into_path_map([{Path, Offset, Size} | Next], TorrentId, _Key, _KeyVal) -> + KeyVal = etorrent_path_map:select(Path, TorrentId), + [{KeyVal, Offset, Size} | insert_into_path_map(Next, TorrentId, Path, KeyVal)]. + fill_file_ensure_path(Path, Missing) -> case file:open(Path, [read, write, delayed_write, binary, raw]) of diff --git a/lib/etorrent-1.0/src/etorrent_piece.erl b/lib/etorrent-1.0/src/etorrent_piece.erl index eba89d3..94a4919 100644 --- a/lib/etorrent-1.0/src/etorrent_piece.erl +++ b/lib/etorrent-1.0/src/etorrent_piece.erl @@ -12,7 +12,7 @@ -include("etorrent_mnesia_table.hrl"). %% API --export([new/2, statechange/3, dirty_statechange/3, complete/1, +-export([new/2, new/5, statechange/3, dirty_statechange/3, complete/1, select/1, select/2, num_not_fetched/1, delete/1, valid/2, interesting/2, bitfield/1, check_interest/2]). @@ -27,6 +27,15 @@ %% FPList ::= [{Hash, Files, Done}] %% Description: Add a list of pieces to the database. %%-------------------------------------------------------------------- +new(Id, PN, Hash, Files, State) when is_integer(Id) -> + mnesia:dirty_write( + #piece {idpn = {Id, PN}, + id = Id, + piece_number = PN, + hash = Hash, + files = Files, + state = State}). + new(Id, FPList) when is_integer(Id) -> lists:foreach( fun ({PN, {Hash, Files}}) -> -- 2.11.4.GIT