diff options
author | Magnus Ahltorp <map@kth.se> | 2015-10-01 12:39:28 +0200 |
---|---|---|
committer | Linus Nordberg <linus@nordu.net> | 2015-11-11 13:32:37 +0100 |
commit | 0a3e6aafee314eaf9e5343c4cad89a9e2ae1d913 (patch) | |
tree | 2ceb97ebf656a26ac384e0e550dc2070d1b7ec72 /src/index.erl | |
parent | 55820add0bda7ac926f11ee49b232dc11d6fe39c (diff) |
Change index.erl to use gen_server and named databases.
Prefetch indices in frontend:fetchmissingentries/2.
Diffstat (limited to 'src/index.erl')
-rw-r--r-- | src/index.erl | 167 |
1 files changed, 108 insertions, 59 deletions
diff --git a/src/index.erl b/src/index.erl index a91c17c..fe47f59 100644 --- a/src/index.erl +++ b/src/index.erl @@ -12,75 +12,121 @@ %% TODO: Checksums -module(index). +-behaviour(gen_server). + +-export([start_link/2, stop/1, init_module/0]). -export([get/2, getrange/3, add/3, add_nosync/3, addlast_nosync/2, indexsize/1, sync/1]). --define(ENTRYSIZE, 32). --define(ENTRYSIZEINFILE, (?ENTRYSIZE*2+1)). +%% gen_server callbacks. +-export([init/1, handle_call/3, terminate/2, handle_cast/2, handle_info/2, + code_change/3]). --spec add(string(), integer() | last, binary()) -> ok. -add(Basepath, Index, Entry) -> - add(Basepath, Index, Entry, sync). +-record(state, {name, add_file}). --spec add_nosync(string(), integer() | last, binary()) -> ok. -add_nosync(Basepath, Index, Entry) -> - add(Basepath, Index, Entry, nosync). +-define(DIRECTORY_TABLE, index_directory). + +init_module() -> + case ets:info(?DIRECTORY_TABLE) of + undefined -> ok; + _ -> ets:delete(?DIRECTORY_TABLE) + end, + ets:new(?DIRECTORY_TABLE, [set, public, named_table]). + +start_link(Name, Filename) -> + gen_server:start_link({local, Name}, ?MODULE, + [Name, Filename], []). -add(Basepath, Index, Entry, Syncflag) when is_binary(Entry), size(Entry) == ?ENTRYSIZE -> - case file:open(Basepath, [read, write, binary]) of +stop(Name) -> + gen_server:call(Name, stop). + +init([Name, Filename]) -> + lager:debug("registering ~p with file name ~p", [Name, Filename]), + true = ets:insert(?DIRECTORY_TABLE, {Name, Filename}), + case file:open(Filename, [read, write, binary]) of {ok, File} -> - {ok, Position} = file:position(File, eof), - Mode = case Index of - last when Position rem ?ENTRYSIZEINFILE == 0 -> - write; - Index when is_integer(Index), - Index * ?ENTRYSIZEINFILE == Position -> - write; - Index when is_integer(Index), - Index * ?ENTRYSIZEINFILE < Position -> - read; - _ -> - util:exit_with_error(invalid, writefile, - "Index not valid") - end, - EntryText = hex:bin_to_hexstr(Entry) ++ "\n", - case Mode of - write -> - ok = file:write(File, EntryText); - read -> - {ok, _Position} = - file:position(File, {bof, Index * ?ENTRYSIZEINFILE}), - {ok, OldEntryText} = file:read(File, ?ENTRYSIZEINFILE), - %% check that the written content is the same as - %% the old content - case binary_to_list(OldEntryText) of - EntryText -> - ok; - _ -> - util:exit_with_error(invalid, writefile, - "Written content not the" ++ - " same as old content") - end - end, - ok = file:close(File), - case Syncflag of - sync -> - sync(Basepath); - nosync -> - ok - end; + {ok, #state{name = Name, add_file = File}}; {error, Error} -> - util:exit_with_error(Error, writefile, - "Error opening file for writing") + {stop, Error} + end. + +handle_cast(_Request, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +terminate(_Reason, _State) -> + io:format("~p terminating~n", [?MODULE]), + ok. + + +-spec add(string(), integer() | last, binary()) -> ok. +add(Name, Index, Entry) -> + ok = gen_server:call(Name, {add, Index, Entry}), + sync(Name). + +-spec add_nosync(string(), integer() | last, binary()) -> ok. +add_nosync(Name, Index, Entry) -> + gen_server:call(Name, {add, Index, Entry}). + +handle_call({add, Index, Entry}, _From, State) -> + Result = add_internal(State#state.add_file, Index, Entry), + {reply, Result, State}; +handle_call(stop, _From, State) -> + {stop, normal, stopped, State}. + + +-define(ENTRYSIZE, 32). +-define(ENTRYSIZEINFILE, (?ENTRYSIZE*2+1)). + + +add_internal(File, Index, Entry) when is_binary(Entry), size(Entry) == ?ENTRYSIZE -> + {ok, Position} = file:position(File, eof), + Mode = case Index of + last when Position rem ?ENTRYSIZEINFILE == 0 -> + write; + Index when is_integer(Index), + Index * ?ENTRYSIZEINFILE == Position -> + write; + Index when is_integer(Index), + Index * ?ENTRYSIZEINFILE < Position -> + read; + _ -> + util:exit_with_error(invalid, writefile, + "Index not valid") + end, + EntryText = hex:bin_to_hexstr(Entry) ++ "\n", + case Mode of + write -> + ok = file:write(File, EntryText); + read -> + {ok, _Position} = + file:position(File, {bof, Index * ?ENTRYSIZEINFILE}), + {ok, OldEntryText} = file:read(File, ?ENTRYSIZEINFILE), + %% check that the written content is the same as + %% the old content + case binary_to_list(OldEntryText) of + EntryText -> + ok; + _ -> + util:exit_with_error(invalid, writefile, + "Written content not the" ++ + " same as old content") + end end. -spec sync(string()) -> ok. -sync(Basepath) -> +sync(Name) -> + [{_, Basepath}] = ets:lookup(?DIRECTORY_TABLE, Name), util:fsync([Basepath, filename:dirname(Basepath)]). -spec addlast_nosync(string(), binary()) -> ok. -addlast_nosync(Basepath, Entry) -> - add_nosync(Basepath, last, Entry). +addlast_nosync(Name, Entry) -> + add_nosync(Name, last, Entry). decodedata(Binary) -> lists:reverse(decodedata(Binary, [])). @@ -94,7 +140,8 @@ decodedata(<<_:?ENTRYSIZE/binary-unit:16, _>>, _Acc) -> "Index line not ending with linefeed"). -spec indexsize(string()) -> integer(). -indexsize(Basepath) -> +indexsize(Name) -> + [{_, Basepath}] = ets:lookup(?DIRECTORY_TABLE, Name), case file:open(Basepath, [read, binary]) of {ok, File} -> {ok, Filesize} = file:position(File, eof), @@ -107,8 +154,8 @@ indexsize(Basepath) -> end. -spec get(string(), integer()) -> binary() | noentry. -get(Basepath, Index) -> - case getrange(Basepath, Index, Index) of +get(Name, Index) -> + case getrange(Name, Index, Index) of noentry -> noentry; [Entry] -> @@ -116,7 +163,9 @@ get(Basepath, Index) -> end. -spec getrange(string(), integer(), integer()) -> [binary()] | noentry. -getrange(Basepath, Start, End) when Start =< End -> +getrange(Name, Start, End) when Start =< End -> + lager:debug("db ~p", [Name]), + [{_, Basepath}] = ets:lookup(?DIRECTORY_TABLE, Name), lager:debug("path ~p start ~p end ~p", [Basepath, Start, End]), case file:open(Basepath, [read, binary]) of {ok, File} -> |