Browse Source

Merge pull request #61 from synrc/empprev

handle prev exceptions
Andrii Zadorozhnii 4 years ago
parent
commit
1ec2a8fe1b
2 changed files with 17 additions and 6 deletions
  1. 7 6
      src/stores/kvs_rocks.erl
  2. 10 0
      test/fd_test.exs

+ 7 - 6
src/stores/kvs_rocks.erl

@@ -12,7 +12,7 @@ e(X,Y) -> element(X,Y).
 bt([]) -> [];
 bt(X)  -> binary_to_term(X).
 
-tb([]) -> [];
+tb([]) -> <<>>;
 tb(T) when is_list(T) -> list_to_binary(T);
 tb(T) when is_atom(T) -> atom_to_binary(T, utf8);
 tb(T) when is_binary(T) -> T;
@@ -23,7 +23,8 @@ sz(B)  -> byte_size(B).
 key(R) when is_tuple(R) andalso tuple_size(R) > 1 -> key(e(1,R), e(2,R));
 key(R) -> key(R,[]).
 key(Tab,R) when is_tuple(R) andalso tuple_size(R) > 1 -> key(Tab, e(2,R));
-key(Tab,R) -> iolist_to_binary([lists:join(<<"/">>, lists:flatten([<<>>, tb(Tab), fmt(R)]))]).
+key(Tab,R) -> Fd = case Tab of [] -> []; _ -> tb(Tab) end,
+              iolist_to_binary([lists:join(<<"/">>, lists:flatten([<<>>, Fd, fmt(R)]))]).
 
 fmt([]) -> [];
 fmt(K) -> Key = tb(K),
@@ -65,7 +66,8 @@ o(Key, % key
   Range_Check = fun(F,K,H,V) -> case F(H,prev) of                       % backward prefetch                |
       {ok,K1,V1} when binary_part(K,{0,S}) == SK -> {{ok,K1,V1},H,[V]}; % return (range-check error)       |
       {ok,K1,V1} -> Run(F,K1,H,V1,[]);                                  % run prev-take chain              | loop
-      E -> E                                                            % violation                        |
+      _ -> stop_it(H),                                                  % fail-safe closing                |
+           throw({ok, fd(K), bt(V), [bt(V)]})                           % acc unfold                       |
   end end,                                                              %                                  |
                                                                         %                                  |
   State_Machine = fun                                                   %                                  |
@@ -73,9 +75,8 @@ o(Key, % key
     (F,{{ok,K,V},H}) when Dir =:= prev -> Range_Check(F,K,H,V);         % first chained prev-take          |
     (F,{{ok,K,V},H})      -> Run(F,K,H,V,[]);                           % first chained next-take          |
     (F,{{ok,K,V},H,A})    -> Run(F,K,H,V,A);                            % chained CPS-take continuator +---+
-    (_,{{error,_},H,Acc}) -> {{ok,[],[]},H,Acc};                        % error effects
-    (F,{R,O})             -> F(R,O);                                    % chain constructor
-    (F,H)                 -> F(H)
+    (_,{{error,E},H,Acc}) -> {{error,E},H,Acc};                         % error effects
+    (F,{R,O})             -> F(R,O)                                     % chain constructor
   end,
 
   catch case lists:foldl(State_Machine, {ref(), []}, Compiled_Operations) of

+ 10 - 0
test/fd_test.exs

@@ -94,6 +94,16 @@ defmodule Fd.Test do
         assert r = KVS.reader(:kvs.prev(:kvs.top(r)), args: [])                 
     end
 
+    test "prev to empty" do        
+        :lists.map(fn _ -> :kvs.append(msg(id: :kvs.seq([],[])), "/aco") end, :lists.seq(1,2))
+        all = :kvs.all("/aco")
+        head = Enum.at(all,0)
+
+        r = :kvs.bot(:kvs.reader("/aco"))
+        r1 = KVS.reader(args: args) = :kvs.take(KVS.reader(r, args: 2, dir: 1))
+        assert all == :lists.reverse(args)
+        assert KVS.reader(args: [^head]) = :kvs.take(KVS.reader(r1, args: 1000, dir: 1))
+    end
 
     defp log(x), do: IO.puts '#{inspect(x)}'
     defp log(m, x), do: IO.puts '#{m} #{inspect(x)}'