Fetch specific block only
Rely on CRC check in zlib. Still need to catch on failure
This commit is contained in:
parent
3c5740e7bf
commit
04cfb453c4
1 changed files with 158 additions and 115 deletions
|
@ -404,20 +404,22 @@ fetch(LedgerKey, Hash, State) ->
|
||||||
State#state.blockindex_cache),
|
State#state.blockindex_cache),
|
||||||
case CachedBlockIdx of
|
case CachedBlockIdx of
|
||||||
none ->
|
none ->
|
||||||
|
io:format("Looking for key without cache~n"),
|
||||||
SlotBin = read_slot(State#state.handle, Slot),
|
SlotBin = read_slot(State#state.handle, Slot),
|
||||||
{Result, BlockIdx} = binaryslot_get(SlotBin,
|
{Result,
|
||||||
LedgerKey,
|
BlockLengths,
|
||||||
Hash,
|
BlockIdx} = binaryslot_get(SlotBin, LedgerKey, Hash),
|
||||||
none),
|
|
||||||
BlockIndexCache = array:set(SlotID - 1,
|
BlockIndexCache = array:set(SlotID - 1,
|
||||||
BlockIdx,
|
<<BlockLengths/binary,
|
||||||
|
BlockIdx/binary>>,
|
||||||
State#state.blockindex_cache),
|
State#state.blockindex_cache),
|
||||||
{Result,
|
{Result,
|
||||||
slot_fetch,
|
slot_fetch,
|
||||||
Slot#slot_index_value.slot_id,
|
Slot#slot_index_value.slot_id,
|
||||||
State#state{blockindex_cache = BlockIndexCache}};
|
State#state{blockindex_cache = BlockIndexCache}};
|
||||||
_ ->
|
<<BlockLengths:20/binary, BlockIdx/binary>> ->
|
||||||
PosList = find_pos(CachedBlockIdx,
|
io:format("Looking for key with cache~n"),
|
||||||
|
PosList = find_pos(BlockIdx,
|
||||||
double_hash(Hash, LedgerKey),
|
double_hash(Hash, LedgerKey),
|
||||||
[],
|
[],
|
||||||
0),
|
0),
|
||||||
|
@ -425,12 +427,12 @@ fetch(LedgerKey, Hash, State) ->
|
||||||
[] ->
|
[] ->
|
||||||
{not_present, slot_bloom, SlotID, State};
|
{not_present, slot_bloom, SlotID, State};
|
||||||
_ ->
|
_ ->
|
||||||
SlotBin = read_slot(State#state.handle, Slot),
|
Result = check_blocks(PosList,
|
||||||
Result = binaryslot_get(SlotBin,
|
State#state.handle,
|
||||||
LedgerKey,
|
Slot,
|
||||||
Hash,
|
BlockLengths,
|
||||||
{true, PosList}),
|
LedgerKey),
|
||||||
{element(1, Result), slot_fetch, SlotID, State}
|
{Result, slot_fetch, SlotID, State}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
@ -607,45 +609,6 @@ build_all_slots(KVL, SC, Pos, SlotID, SlotIdx, BlockIdxA, SlotsBin) ->
|
||||||
array:set(SlotID - 1, BlockIndex, BlockIdxA),
|
array:set(SlotID - 1, BlockIndex, BlockIdxA),
|
||||||
<<SlotsBin/binary, SlotBin/binary>>).
|
<<SlotsBin/binary, SlotBin/binary>>).
|
||||||
|
|
||||||
read_slot(Handle, Slot) ->
|
|
||||||
{ok, SlotBin} = file:pread(Handle,
|
|
||||||
Slot#slot_index_value.start_position,
|
|
||||||
Slot#slot_index_value.length),
|
|
||||||
SlotBin.
|
|
||||||
|
|
||||||
read_slots(Handle, SlotList) ->
|
|
||||||
PointerMapFun =
|
|
||||||
fun(Pointer) ->
|
|
||||||
{Slot, SK, EK} =
|
|
||||||
case Pointer of
|
|
||||||
{pointer, _Pid, Slot0, SK0, EK0} ->
|
|
||||||
{Slot0, SK0, EK0};
|
|
||||||
{pointer, Slot0, SK0, EK0} ->
|
|
||||||
{Slot0, SK0, EK0}
|
|
||||||
end,
|
|
||||||
|
|
||||||
{Slot#slot_index_value.start_position,
|
|
||||||
Slot#slot_index_value.length,
|
|
||||||
SK,
|
|
||||||
EK}
|
|
||||||
end,
|
|
||||||
|
|
||||||
LengthList = lists:map(PointerMapFun, SlotList),
|
|
||||||
StartPos = element(1, lists:nth(1, LengthList)),
|
|
||||||
EndPos = element(1, lists:last(LengthList))
|
|
||||||
+ element(2, lists:last(LengthList)),
|
|
||||||
{ok, MultiSlotBin} = file:pread(Handle, StartPos, EndPos - StartPos),
|
|
||||||
|
|
||||||
BinSplitMapFun =
|
|
||||||
fun({SP, L, SK, EK}) ->
|
|
||||||
Start = SP - StartPos,
|
|
||||||
<<_Pre:Start/binary,
|
|
||||||
SlotBin:L/binary,
|
|
||||||
_Post/binary>> = MultiSlotBin,
|
|
||||||
{SlotBin, SK, EK}
|
|
||||||
end,
|
|
||||||
|
|
||||||
lists:map(BinSplitMapFun, LengthList).
|
|
||||||
|
|
||||||
generate_filenames(RootFilename) ->
|
generate_filenames(RootFilename) ->
|
||||||
Ext = filename:extension(RootFilename),
|
Ext = filename:extension(RootFilename),
|
||||||
|
@ -819,27 +782,96 @@ generate_binary_slot(KVL) ->
|
||||||
CRC32 = erlang:crc32(SlotBin),
|
CRC32 = erlang:crc32(SlotBin),
|
||||||
FullBin = <<CRC32:32/integer, SlotBin/binary>>,
|
FullBin = <<CRC32:32/integer, SlotBin/binary>>,
|
||||||
|
|
||||||
{PosBinIndex1, FullBin, HashL}.
|
{<<Lengths/binary, PosBinIndex1/binary>>, FullBin, HashL}.
|
||||||
|
|
||||||
|
|
||||||
binaryslot_get(FullBin, Key, Hash, CachedPosLookup) ->
|
check_blocks([], _Handle, _Slot, _BlockLengths, _LedgerKey) ->
|
||||||
|
not_present;
|
||||||
|
check_blocks([Pos|Rest], Handle, Slot, BlockLengths, LedgerKey) ->
|
||||||
|
{BlockNumber, BlockPos} = revert_position(Pos),
|
||||||
|
io:format("Checking BlockNumber ~w in BlockPos ~w~n",
|
||||||
|
[BlockNumber, BlockPos]),
|
||||||
|
BlockBin = read_block(Handle, Slot, BlockLengths, BlockNumber),
|
||||||
|
BlockL = binary_to_term(BlockBin),
|
||||||
|
{K, V} = lists:nth(BlockPos, BlockL),
|
||||||
|
case K of
|
||||||
|
LedgerKey ->
|
||||||
|
io:format("Key mismatch in check_blocks~n"),
|
||||||
|
{K, V};
|
||||||
|
_ ->
|
||||||
|
check_blocks(Rest, Handle, Slot, BlockLengths, LedgerKey)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
read_block(Handle, Slot, BlockLengths, BlockID) ->
|
||||||
|
{BlockPos, Offset, Length} = block_offsetandlength(BlockLengths, BlockID),
|
||||||
|
io:format("Reading offset ~w Length ~w~n", [Offset, Length]),
|
||||||
|
{ok, BlockBin} = file:pread(Handle,
|
||||||
|
Slot#slot_index_value.start_position
|
||||||
|
+ BlockPos
|
||||||
|
+ Offset
|
||||||
|
+ 24,
|
||||||
|
% 4-byte CRC, 4 byte pos, 4x4 byte lengths
|
||||||
|
Length),
|
||||||
|
BlockBin.
|
||||||
|
|
||||||
|
read_slot(Handle, Slot) ->
|
||||||
|
{ok, SlotBin} = file:pread(Handle,
|
||||||
|
Slot#slot_index_value.start_position,
|
||||||
|
Slot#slot_index_value.length),
|
||||||
|
SlotBin.
|
||||||
|
|
||||||
|
read_slots(Handle, SlotList) ->
|
||||||
|
PointerMapFun =
|
||||||
|
fun(Pointer) ->
|
||||||
|
{Slot, SK, EK} =
|
||||||
|
case Pointer of
|
||||||
|
{pointer, _Pid, Slot0, SK0, EK0} ->
|
||||||
|
{Slot0, SK0, EK0};
|
||||||
|
{pointer, Slot0, SK0, EK0} ->
|
||||||
|
{Slot0, SK0, EK0}
|
||||||
|
end,
|
||||||
|
|
||||||
|
{Slot#slot_index_value.start_position,
|
||||||
|
Slot#slot_index_value.length,
|
||||||
|
SK,
|
||||||
|
EK}
|
||||||
|
end,
|
||||||
|
|
||||||
|
LengthList = lists:map(PointerMapFun, SlotList),
|
||||||
|
StartPos = element(1, lists:nth(1, LengthList)),
|
||||||
|
EndPos = element(1, lists:last(LengthList))
|
||||||
|
+ element(2, lists:last(LengthList)),
|
||||||
|
{ok, MultiSlotBin} = file:pread(Handle, StartPos, EndPos - StartPos),
|
||||||
|
|
||||||
|
BinSplitMapFun =
|
||||||
|
fun({SP, L, SK, EK}) ->
|
||||||
|
Start = SP - StartPos,
|
||||||
|
<<_Pre:Start/binary,
|
||||||
|
SlotBin:L/binary,
|
||||||
|
_Post/binary>> = MultiSlotBin,
|
||||||
|
{SlotBin, SK, EK}
|
||||||
|
end,
|
||||||
|
|
||||||
|
lists:map(BinSplitMapFun, LengthList).
|
||||||
|
|
||||||
|
|
||||||
|
binaryslot_get(FullBin, Key, Hash) ->
|
||||||
case crc_check_slot(FullBin) of
|
case crc_check_slot(FullBin) of
|
||||||
{Lengths, Rest} ->
|
{BlockLengths, Rest} ->
|
||||||
B1P = element(1, Lengths),
|
<<B1P:32/integer, _R/binary>> = BlockLengths,
|
||||||
case CachedPosLookup of
|
|
||||||
{true, PosList} ->
|
|
||||||
<<_PosBinIndex:B1P/binary, Blocks/binary>> = Rest,
|
|
||||||
{fetch_value(PosList, Lengths, Blocks, Key), none};
|
|
||||||
none ->
|
|
||||||
<<PosBinIndex:B1P/binary, Blocks/binary>> = Rest,
|
<<PosBinIndex:B1P/binary, Blocks/binary>> = Rest,
|
||||||
PosList = find_pos(PosBinIndex,
|
PosList = find_pos(PosBinIndex,
|
||||||
double_hash(Hash, Key),
|
double_hash(Hash, Key),
|
||||||
[],
|
[],
|
||||||
0),
|
0),
|
||||||
{fetch_value(PosList, Lengths, Blocks, Key), PosBinIndex}
|
{fetch_value(PosList, BlockLengths, Blocks, Key),
|
||||||
end;
|
BlockLengths,
|
||||||
|
PosBinIndex};
|
||||||
crc_wonky ->
|
crc_wonky ->
|
||||||
{not_present, none}
|
{not_present,
|
||||||
|
none,
|
||||||
|
none}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
binaryslot_tolist(FullBin) ->
|
binaryslot_tolist(FullBin) ->
|
||||||
|
@ -856,8 +888,12 @@ binaryslot_tolist(FullBin) ->
|
||||||
|
|
||||||
{Out, _Rem} =
|
{Out, _Rem} =
|
||||||
case crc_check_slot(FullBin) of
|
case crc_check_slot(FullBin) of
|
||||||
{Lengths, RestBin} ->
|
{BlockLengths, RestBin} ->
|
||||||
{B1P, B1L, B2L, B3L, B4L} = Lengths,
|
<<B1P:32/integer,
|
||||||
|
B1L:32/integer,
|
||||||
|
B2L:32/integer,
|
||||||
|
B3L:32/integer,
|
||||||
|
B4L:32/integer>> = BlockLengths,
|
||||||
<<_PosBinIndex:B1P/binary, Blocks/binary>> = RestBin,
|
<<_PosBinIndex:B1P/binary, Blocks/binary>> = RestBin,
|
||||||
lists:foldl(BlockFetchFun, {[], Blocks}, [B1L, B2L, B3L, B4L]);
|
lists:foldl(BlockFetchFun, {[], Blocks}, [B1L, B2L, B3L, B4L]);
|
||||||
crc_wonky ->
|
crc_wonky ->
|
||||||
|
@ -908,8 +944,12 @@ binaryslot_trimmedlist(FullBin, StartKey, EndKey) ->
|
||||||
|
|
||||||
{Out, _Rem} =
|
{Out, _Rem} =
|
||||||
case crc_check_slot(FullBin) of
|
case crc_check_slot(FullBin) of
|
||||||
{Lengths, RestBin} ->
|
{BlockLengths, RestBin} ->
|
||||||
{B1P, B1L, B2L, B3L, B4L} = Lengths,
|
<<B1P:32/integer,
|
||||||
|
B1L:32/integer,
|
||||||
|
B2L:32/integer,
|
||||||
|
B3L:32/integer,
|
||||||
|
B4L:32/integer>> = BlockLengths,
|
||||||
<<_PosBinIndex:B1P/binary, Blocks/binary>> = RestBin,
|
<<_PosBinIndex:B1P/binary, Blocks/binary>> = RestBin,
|
||||||
lists:foldl(BlockFetchFun, {[], Blocks}, [B1L, B2L, B3L, B4L]);
|
lists:foldl(BlockFetchFun, {[], Blocks}, [B1L, B2L, B3L, B4L]);
|
||||||
crc_wonky ->
|
crc_wonky ->
|
||||||
|
@ -957,65 +997,68 @@ trim_booleans(FirstKey, LastKey, StartKey, EndKey) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
crc_check_slot(FullBin) ->
|
crc_check_slot(FullBin) ->
|
||||||
<<CRC32:32/integer, SlotBin/binary>> = FullBin,
|
<<CRC32:32/integer, SlotBin/binary>> = FullBin,
|
||||||
case erlang:crc32(SlotBin) of
|
case erlang:crc32(SlotBin) of
|
||||||
CRC32 ->
|
CRC32 ->
|
||||||
<<B1P:32/integer,
|
<<BlockLengths:20/binary, Rest/binary>> = SlotBin,
|
||||||
B1L:32/integer,
|
{BlockLengths, Rest};
|
||||||
B2L:32/integer,
|
|
||||||
B3L:32/integer,
|
|
||||||
B4L:32/integer,
|
|
||||||
Rest/binary>> = SlotBin,
|
|
||||||
Lengths = {B1P, B1L, B2L, B3L, B4L},
|
|
||||||
{Lengths, Rest};
|
|
||||||
_ ->
|
_ ->
|
||||||
leveled_log:log("SST09", []),
|
leveled_log:log("SST09", []),
|
||||||
crc_wonky
|
crc_wonky
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
block_offsetandlength(BlockLengths, BlockID) ->
|
||||||
|
<<BlocksPos:32/integer, BlockLengths0:16/binary>> = BlockLengths,
|
||||||
|
case BlockID of
|
||||||
|
1 ->
|
||||||
|
<<B1L:32/integer, _BR/binary>> = BlockLengths0,
|
||||||
|
{BlocksPos, 0, B1L};
|
||||||
|
2 ->
|
||||||
|
<<B1L:32/integer, B2L:32/integer, _BR/binary>> = BlockLengths0,
|
||||||
|
{BlocksPos, B1L, B2L};
|
||||||
|
3 ->
|
||||||
|
<<B1L:32/integer,
|
||||||
|
B2L:32/integer,
|
||||||
|
B3L:32/integer,
|
||||||
|
_BR/binary>> = BlockLengths0,
|
||||||
|
{BlocksPos, B1L + B2L, B3L};
|
||||||
|
4 ->
|
||||||
|
<<B1L:32/integer,
|
||||||
|
B2L:32/integer,
|
||||||
|
B3L:32/integer,
|
||||||
|
B4L:32/integer>> = BlockLengths0,
|
||||||
|
{BlocksPos, B1L + B2L + B3L, B4L}
|
||||||
|
end.
|
||||||
|
|
||||||
double_hash(Hash, Key) ->
|
double_hash(Hash, Key) ->
|
||||||
H2 = erlang:phash2(Key),
|
H2 = erlang:phash2(Key),
|
||||||
(Hash bxor H2) band 32767.
|
(Hash bxor H2) band 32767.
|
||||||
|
|
||||||
fetch_value([], _Lengths, _Blocks, _Key) ->
|
fetch_value([], _BlockLengths, _Blocks, _Key) ->
|
||||||
not_present;
|
not_present;
|
||||||
fetch_value([Pos|Rest], Lengths, Blocks, Key) ->
|
fetch_value([Pos|Rest], BlockLengths, Blocks, Key) ->
|
||||||
BlockNumber = (Pos div 32) + 1,
|
{BlockNumber, BlockPos} = revert_position(Pos),
|
||||||
BlockPos = (Pos rem 32) + 1,
|
{_BlockPos,
|
||||||
BlockL =
|
Offset,
|
||||||
case BlockNumber of
|
Length} = block_offsetandlength(BlockLengths, BlockNumber),
|
||||||
1 ->
|
<<_Pre:Offset/binary, Block:Length/binary, _Rest/binary>> = Blocks,
|
||||||
B1L = element(2, Lengths),
|
BlockL = binary_to_term(Block),
|
||||||
<<Block:B1L/binary, _Rest/binary>> = Blocks,
|
|
||||||
binary_to_term(Block);
|
|
||||||
2 ->
|
|
||||||
B1L = element(2, Lengths),
|
|
||||||
B2L = element(3, Lengths),
|
|
||||||
<<_Pass:B1L/binary, Block:B2L/binary, _Rest/binary>> = Blocks,
|
|
||||||
binary_to_term(Block);
|
|
||||||
3 ->
|
|
||||||
PreL = element(2, Lengths) + element(3, Lengths),
|
|
||||||
B3L = element(4, Lengths),
|
|
||||||
<<_Pass:PreL/binary, Block:B3L/binary, _Rest/binary>> = Blocks,
|
|
||||||
binary_to_term(Block);
|
|
||||||
4 ->
|
|
||||||
{_B1P, B1L, B2L, B3L, B4L} = Lengths,
|
|
||||||
PreL = B1L + B2L + B3L,
|
|
||||||
<<_Pass:PreL/binary, Block:B4L/binary>> = Blocks,
|
|
||||||
binary_to_term(Block)
|
|
||||||
end,
|
|
||||||
|
|
||||||
{K, V} = lists:nth(BlockPos, BlockL),
|
{K, V} = lists:nth(BlockPos, BlockL),
|
||||||
case K of
|
case K of
|
||||||
Key ->
|
Key ->
|
||||||
|
io:format("Key mismatch in fetch_value~n"),
|
||||||
{K, V};
|
{K, V};
|
||||||
_ ->
|
_ ->
|
||||||
fetch_value(Rest, Lengths, Blocks, Key)
|
fetch_value(Rest, BlockLengths, Blocks, Key)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
revert_position(Pos) ->
|
||||||
|
BlockNumber = (Pos div 32) + 1,
|
||||||
|
BlockPos = (Pos rem 32) + 1,
|
||||||
|
{BlockNumber, BlockPos}.
|
||||||
|
|
||||||
find_pos(<<>>, _Hash, PosList, _Count) ->
|
find_pos(<<>>, _Hash, PosList, _Count) ->
|
||||||
PosList;
|
PosList;
|
||||||
find_pos(<<1:1/integer, Hash:15/integer, T/binary>>, Hash, PosList, Count) ->
|
find_pos(<<1:1/integer, Hash:15/integer, T/binary>>, Hash, PosList, Count) ->
|
||||||
|
@ -1272,7 +1315,7 @@ indexed_list_mixedkeys2_test() ->
|
||||||
indexed_list_allindexkeys_test() ->
|
indexed_list_allindexkeys_test() ->
|
||||||
Keys = lists:sublist(lists:ukeysort(1, generate_indexkeys(150)), 128),
|
Keys = lists:sublist(lists:ukeysort(1, generate_indexkeys(150)), 128),
|
||||||
{PosBinIndex1, FullBin, _HL} = generate_binary_slot(Keys),
|
{PosBinIndex1, FullBin, _HL} = generate_binary_slot(Keys),
|
||||||
?assertMatch(<<127:8/integer>>, PosBinIndex1),
|
?assertMatch(<<_BL:20/binary, 127:8/integer>>, PosBinIndex1),
|
||||||
% SW = os:timestamp(),
|
% SW = os:timestamp(),
|
||||||
BinToList = binaryslot_tolist(FullBin),
|
BinToList = binaryslot_tolist(FullBin),
|
||||||
% io:format(user,
|
% io:format(user,
|
||||||
|
@ -1285,7 +1328,7 @@ indexed_list_allindexkeys_test() ->
|
||||||
indexed_list_allindexkeys_trimmed_test() ->
|
indexed_list_allindexkeys_trimmed_test() ->
|
||||||
Keys = lists:sublist(lists:ukeysort(1, generate_indexkeys(150)), 128),
|
Keys = lists:sublist(lists:ukeysort(1, generate_indexkeys(150)), 128),
|
||||||
{PosBinIndex1, FullBin, _HL} = generate_binary_slot(Keys),
|
{PosBinIndex1, FullBin, _HL} = generate_binary_slot(Keys),
|
||||||
?assertMatch(<<127:8/integer>>, PosBinIndex1),
|
?assertMatch(<<_BL:20/binary, 127:8/integer>>, PosBinIndex1),
|
||||||
?assertMatch(Keys, binaryslot_trimmedlist(FullBin,
|
?assertMatch(Keys, binaryslot_trimmedlist(FullBin,
|
||||||
{i,
|
{i,
|
||||||
"Bucket",
|
"Bucket",
|
||||||
|
@ -1351,7 +1394,7 @@ indexed_list_mixedkeys_bitflip_test() ->
|
||||||
|
|
||||||
test_binary_slot(FullBin, Key, Hash, ExpectedValue) ->
|
test_binary_slot(FullBin, Key, Hash, ExpectedValue) ->
|
||||||
% SW = os:timestamp(),
|
% SW = os:timestamp(),
|
||||||
{ReturnedValue, _} = binaryslot_get(FullBin, Key, Hash, none),
|
{ReturnedValue, _BLs, _Idx} = binaryslot_get(FullBin, Key, Hash),
|
||||||
?assertMatch(ExpectedValue, ReturnedValue).
|
?assertMatch(ExpectedValue, ReturnedValue).
|
||||||
% io:format(user, "Fetch success in ~w microseconds ~n",
|
% io:format(user, "Fetch success in ~w microseconds ~n",
|
||||||
% [timer:now_diff(os:timestamp(), SW)]).
|
% [timer:now_diff(os:timestamp(), SW)]).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue