From 80c8ef847d996af04ec677a79555d640733641f2 Mon Sep 17 00:00:00 2001 From: Magnus Ahltorp Date: Sun, 19 Oct 2014 01:37:29 +0200 Subject: db:get_by_leaf_hash(): Return notfound instead of crashing when no entry could be found. db:get_by_entry_hash(): Don't fetch index, isn't used and might not exist. index:add(): Allow writes at exiting indicies. --- src/db.erl | 25 +++++++++++++++++------ src/index.erl | 64 +++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/db.erl b/src/db.erl index 6315ae5..6fce8a3 100644 --- a/src/db.erl +++ b/src/db.erl @@ -103,7 +103,12 @@ entry_for_leafhash(LeafHash) -> perm:readfile(entry_root_path(), LeafHash). index_for_leafhash(LeafHash) -> - binary_to_integer(perm:readfile(indexforhash_root_path(), LeafHash)). + case perm:readfile(indexforhash_root_path(), LeafHash) of + noentry -> + noentry; + Index -> + binary_to_integer(Index) + end. leafhash_for_index(Index) -> index:get(index_path(), Index). @@ -148,9 +153,17 @@ handle_call({get_by_index, Index}, _From, State) -> {reply, R, State}; handle_call({get_by_leaf_hash, LeafHash}, _From, State) -> - Entry = entry_for_leafhash(LeafHash), - Index = index_for_leafhash(LeafHash), - R = {Index, LeafHash, Entry}, + R = case entry_for_leafhash(LeafHash) of + noentry -> + notfound; + Entry -> + case index_for_leafhash(LeafHash) of + noentry -> + notfound; + Index -> + {Index, LeafHash, Entry} + end + end, {reply, R, State}; handle_call({get_by_entry_hash, EntryHash}, _From, State) -> @@ -159,7 +172,7 @@ handle_call({get_by_entry_hash, EntryHash}, _From, State) -> notfound; LeafHash -> Entry = entry_for_leafhash(LeafHash), - Index = index_for_leafhash(LeafHash), - {Index, LeafHash, Entry} + %% Don't fetch index, isn't used and might not exist + {notfetched, LeafHash, Entry} end, {reply, R, State}. diff --git a/src/index.erl b/src/index.erl index 7871215..5169fbb 100644 --- a/src/index.erl +++ b/src/index.erl @@ -1,17 +1,18 @@ %%% Copyright (c) 2014, NORDUnet A/S. %%% See LICENSE for licensing information. -%% Implements an interface to a file pair (basename and basename.chksum) -%% that stores an ordered list of fixed-size entries. Entries can be -%% added at the end and are retrieved by index. The list can also be -%% truncated. +%% Implements an interface to a file pair (basename and +%% basename.chksum) that stores an ordered list of fixed-size entries. +%% Entries can be added at the end and are retrieved by index. Entries +%% can also be added at already existing indices, but then the +%% contents must be the same. %% -%% Writes(add, truncate, addlast) need to be serialized. +%% Writes(add, addlast) need to be serialized. %% TODO: Checksums -module(index). --export([get/2, add/3, addlast/2, truncate/2]). +-export([get/2, add/3, addlast/2]). -define(ENTRYSIZE, 32). -define(ENTRYSIZEINFILE, (?ENTRYSIZE*2+1)). @@ -21,27 +22,38 @@ add(Basepath, Index, Entry) when is_binary(Entry), size(Entry) == ?ENTRYSIZE -> case file:open(Basepath, [read, write, binary]) of {ok, File} -> {ok, Position} = file:position(File, eof), - case Index of - last when Position rem ?ENTRYSIZEINFILE == 0 -> - ok; - Index when is_integer(Index), - Index * ?ENTRYSIZEINFILE == Position -> - ok - end, + 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", - ok = file:write(File, EntryText), - ok = file:close(File), - util:fsync([Basepath, filename:dirname(Basepath)]); - {error, Error} -> - util:exit_with_error(Error, writefile, - "Error opening file for writing") - end. - -truncate(Basepath, Index) -> - case file:open(Basepath, [read, write, binary]) of - {ok, File} -> - {ok, _Position} = file:position(File, Index * ?ENTRYSIZEINFILE), - ok = file:truncate(File), + 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), util:fsync([Basepath, filename:dirname(Basepath)]); {error, Error} -> -- cgit v1.1