Skip to content

Commit

Permalink
GH2 (hibari/gdss-brick): new client API - rename
Browse files Browse the repository at this point in the history
  • Loading branch information
norton committed Feb 4, 2011
1 parent 0d687bb commit a55c96e
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 16 deletions.
10 changes: 7 additions & 3 deletions include/brick_public.hrl
Expand Up @@ -26,11 +26,15 @@

%% Used by scavenger to re-locate a bigdata_dir value hunk. This is
%% the magic atom to use. For more security despite the obscurity,
%% we'll require that the client give the correct current hunk location,
%% which is a piece of data that's harder to leak out of the system.
%% (Sssh! Don't tell anyone about the 'get_many_raw_storetuples' flag!)
%% we'll require that the client give the correct current hunk
%% location, which is a piece of data that's harder to leak out of the
%% system. (Sssh! Don't tell anyone about the
%% 'get_many_raw_storetuples' flag!)
-define(VALUE_SWITCHAROO, '$value_switch-a-roo/$').

%% Used to rename a oldkey/value pair to a newkey/value pair.
-define(KEY_SWITCHAROO, '$key_switch-a-roo/$').

-define(BRICK__SMALLEST_KEY, <<>>).
-define(BRICK__BIGGEST_KEY, <<255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255>>). % list_to_binary(lists:duplicate(255, 255)).

Expand Down
7 changes: 4 additions & 3 deletions include/brick_specs.hrl
Expand Up @@ -31,7 +31,7 @@
-type time_t() :: integer().
-type ts() :: non_neg_integer().
-type val() :: binary() | iolist(). % Differs from UBF contract
-type val_impl() :: val() | '$disk_remains_constant/$' | {'$value_switch-a-roo/$', val(), val()}.
-type val_impl() :: val() | '$disk_remains_constant/$' | {'$value_switch-a-roo/$', val(), val()} | {'$key_switch-a-roo/$', key()}.

-type exp_time() :: time_t().
-type do_op_flag0() :: {testset, ts()} |
Expand Down Expand Up @@ -66,9 +66,10 @@
-type replace() :: {replace, bin_key(), ts(), val_impl(), exp_time(), flags_list()}.
%% set() is a built-in type now, must use a different name for this type.
-type 'set__'() :: {set, bin_key(), ts(), val(), exp_time(), flags_list()}.
-type rename() :: {rename, bin_key(), ts(), bin_key(), exp_time(), flags_list()}.

-type do1_op() :: txn() | add() | delete() | get() | get_many() |
replace() | 'set__'().
-type do1_op() :: txn() | add() | replace() | 'set__'() | rename() |
delete() | get() | get_many().
-type do_op_list() :: [do1_op()].

-type do1_res_ok() :: ok |
Expand Down
59 changes: 59 additions & 0 deletions src/brick_ets.erl
Expand Up @@ -139,6 +139,7 @@
n_add = 0 :: non_neg_integer(),
n_replace = 0 :: non_neg_integer(),
n_set = 0 :: non_neg_integer(),
n_rename = 0 :: non_neg_integer(),
n_get = 0 :: non_neg_integer(),
n_get_many = 0 :: non_neg_integer(),
n_delete = 0 :: non_neg_integer(),
Expand Down Expand Up @@ -643,6 +644,7 @@ do_status(S) ->
{n_add, S#state.n_add},
{n_replace, S#state.n_replace},
{n_set, S#state.n_set},
{n_rename, S#state.n_rename},
{n_get, S#state.n_get},
{n_get_many, S#state.n_get_many},
{n_delete, S#state.n_delete},
Expand Down Expand Up @@ -743,6 +745,10 @@ do_dolist([{set, Key, TStamp, Value, ExpTime, Flags}|T], State, DoFlags, Acc) ->
{Res, NewState} = set_key(Key, TStamp, Value, ExpTime, Flags, State),
N_set = NewState#state.n_set,
do_dolist(T, NewState#state{n_set = N_set + 1}, DoFlags, [Res|Acc]);
do_dolist([{rename, Key, TStamp, OldKey, ExpTime, Flags}|T], State, DoFlags, Acc) ->
{Res, NewState} = rename_key(Key, TStamp, OldKey, ExpTime, Flags, State),
N_rename = NewState#state.n_rename,
do_dolist(T, NewState#state{n_rename = N_rename + 1}, DoFlags, [Res|Acc]);
do_dolist([{get, Key, Flags}|T], State, DoFlags, Acc) ->
Res = get_key(Key, Flags, State),
N_get = State#state.n_get,
Expand Down Expand Up @@ -813,6 +819,23 @@ do_txnlist([{set, _Key, _TStamp, _Value, _ExpTime, Flags} = H|T], State,
Err = invalid_flag_present,
do_txnlist(T, State, [Err|Acc], false, N+1, DoFlags, [{N, Err}|ErrAcc])
end;
do_txnlist([{rename, Key, _TStamp, OldKey, _ExpTime, Flags} = H|T], State,
Acc, Good, N, DoFlags, ErrAcc) ->
case key_exists_p(Key, proplists:delete(testset,Flags), State) of
{Key, TS, _, _, _, _} ->
Err = {key_exists, TS},
do_txnlist(T, State, [Err|Acc], false, N+1, DoFlags, [{N,Err}|ErrAcc]);
_ ->
case key_exists_p(OldKey, Flags, State) of
{OldKey, _, _, _, _, _} ->
do_txnlist(T, State, [H|Acc], Good, N+1, DoFlags, ErrAcc);
{ts_error, _} = Err ->
do_txnlist(T, State, [Err|Acc], false, N+1, DoFlags, [{N, Err}|ErrAcc]);
_ ->
Err = key_not_exist,
do_txnlist(T, State, [Err|Acc], false, N+1, DoFlags, [{N, Err}|ErrAcc])
end
end;
do_txnlist([{Primitive, Key, Flags} = H|T], State,
Acc, Good, N, DoFlags, ErrAcc)
when Primitive == get ; Primitive == delete ; Primitive == get_many ->
Expand Down Expand Up @@ -953,6 +976,32 @@ set_key(Key, TStamp, Value, ExpTime, Flags, State) ->
{ok, NewState}
end.

rename_key(Key, TStamp, OldKey, ExpTime, Flags, State) ->
case key_exists_p(Key, proplists:delete(testset,Flags), State, false) of
{Key, TS, _, _, _, _} ->
{{key_exists, TS}, State};
_ ->
case key_exists_p(OldKey, Flags, State, false) of
{OldKey, TS, _Value, _ValueLen, _PreviousExp, _} ->
rename_key2(Key, TStamp, OldKey, ExpTime, Flags, State, TS);
{ts_error, _} = Err ->
{Err, State};
_ ->
{key_not_exist, State}
end
end.

rename_key2(Key, TStamp, OldKey, ExpTime, Flags, State, TS) ->
if
TStamp > TS ->
Value = {?KEY_SWITCHAROO, OldKey},
NewState = my_insert(State, Key, TStamp, Value, ExpTime, Flags),
NewState1 = my_delete(NewState, OldKey, 0),
{ok, NewState1};
true ->
{{ts_error, TS}, State}
end.

get_key(Key, Flags, State) ->
case key_exists_p(Key, Flags, State) of
{Key, KeyTStamp, Value, ValueLen, ExpTime, KeyFlags} ->
Expand Down Expand Up @@ -1522,6 +1571,7 @@ my_insert2(S, Key, TStamp, Value, ExpTime, Flags) ->
Mod =
case Value of
?VALUE_REMAINS_CONSTANT ->
%% @TODO - value_in_ram support?
[ST] = my_lookup(S, Key, false),
CurVal = storetuple_val(ST),
CurValLen = storetuple_vallen(ST),
Expand All @@ -1535,6 +1585,7 @@ my_insert2(S, Key, TStamp, Value, ExpTime, Flags) ->
storetuple_make(Key, TStamp, CurVal, CurValLen, ExpTime,
Flags)};
{?VALUE_SWITCHAROO, OldVal, NewVal} ->
%% @TODO - value_in_ram support?
%% NOTE: If testset has been specified, it has already
%% been validated and stripped from Flags.
[ST] = my_lookup(S, Key, false),
Expand All @@ -1553,6 +1604,14 @@ my_insert2(S, Key, TStamp, Value, ExpTime, Flags) ->
%% change what we scribble to the local log.
{log_noop}
end;
{?KEY_SWITCHAROO, OldKey} ->
%% @TODO - value_in_ram support?
[ST] = my_lookup(S, OldKey, false),
Val = storetuple_val(ST),
ValLen = storetuple_vallen(ST),
{insert_constant_value,
storetuple_make(Key, TStamp, Val, ValLen, ExpTime,
Flags)};
_ ->
Val = gmt_util:bin_ify(Value),
UseRamP = lists:member(value_in_ram, Flags),
Expand Down
85 changes: 75 additions & 10 deletions src/brick_server.erl
Expand Up @@ -354,17 +354,22 @@

%% External exports
-export([start_link/2, stop/1, dump_state/1]).
-export([add/4, add/5, add/7, replace/4, replace/5, replace/7,
set/4, set/5, set/7, get/3, get/4, get/5,
delete/3, delete/4, get_many/4, get_many/5, get_many/6, get_many/7,
-export([add/4, add/5, add/7,
replace/4, replace/5, replace/7,
set/4, set/5, set/7,
rename/4, rename/5, rename/7,
get/3, get/4, get/5,
delete/3, delete/4,
get_many/4, get_many/5, get_many/6, get_many/7,
do/3, do/4, do/5]).

%% Quota management
-export([get_quota/3, set_quota/5, resum_quota/3]).

-export([make_add/2, make_add/4, make_add/5,
make_set/2, make_set/4, make_set/5,
make_replace/2, make_replace/4, make_replace/5,
make_set/2, make_set/4, make_set/5,
make_rename/2, make_rename/4, make_rename/5,
make_get/1, make_get/2,
make_delete/1, make_delete/2,
make_txn/0,
Expand Down Expand Up @@ -471,8 +476,9 @@
-type do_reply() :: list() | {txn_fail, list()} | {wrong_brick, term()}.
-type syncdown_reply() :: list({state_r(), node_name()}).
-type add_reply() :: {key_exists, integer()} | {ts_error, ts()} | ok.
-type set_reply() :: {ts_error, ts()} | ok.
-type replace_reply() :: {ts_error, ts()} | key_not_exist | ok.
-type set_reply() :: {ts_error, ts()} | ok.
-type rename_reply() :: {key_exists, integer()} | {ts_error, ts()} | key_not_exist | ok.
-type quota_reply() :: {ts_error, ts()} | ok.
-type get_reply() :: {ts_error, ts()} | key_not_exist |
{ok, ts()} | {ok, ts(), flags_list()} | {ok, ts(), val()} |
Expand Down Expand Up @@ -750,6 +756,44 @@ set(ServerName, Node, Key, Value, ExpTime, Flags, Timeout)
Else -> Else
end.

%% @spec (brick_name(), node_name(), io_list(), io_list())
%% -> zzz_add_reply()
%% @equiv rename(ServerName, Node, Key, OldKey, 0, [], DefaultTimeout)

%% @doc Rename a OldKey/Value pair to Key/Value pair in a brick,
%% failing if OldKey does not already exist or if Key already exists.

-spec rename(brick_name(), node_name(), key(), key()) -> rename_reply().
rename(ServerName, Node, Key, OldKey) ->
rename(ServerName, Node, Key, OldKey, 0, [], foo_timeout()).

%% @spec (brick_name(), node_name(), io_list(), io_list(), prop_list() | timeout())
%% -> zzz_add_reply()
%% @equiv rename(ServerName, Node, Key, OldKey, 0, Flags, DefaultTimeoutOrFlags)

%% @doc Rename a OldKey/Value pair to Key/Value pair in a brick,
%% failing if OldKey does not already exist or if Key already exists.

-spec rename(brick_name(), node_name(), key(), key(), flags_list0() | timeout()) -> rename_reply().
rename(ServerName, Node, Key, OldKey, Flags) when is_list(Flags) ->
rename(ServerName, Node, Key, OldKey, 0, Flags, foo_timeout());
rename(ServerName, Node, Key, OldKey, Timeout) when is_integer(Timeout) ->
rename(ServerName, Node, Key, OldKey, 0, [], Timeout).

%% @spec (brick_name(), node_name(), io_list(), io_list(), integer(), prop_list(), timeout())
%% -> zzz_add_reply()
%% @doc Rename a OldKey/Value pair to Key/Value pair in a brick,
%% failing if OldKey does not already exist or if Key already exists.

-spec rename(brick_name(), node_name(), key(), key(), integer(), flags_list(), timeout()) -> rename_reply().
rename(ServerName, Node, Key, OldKey, ExpTime, Flags, Timeout)
when not is_list(Node) ->
case do(ServerName, Node, [make_rename(Key, OldKey, ExpTime, Flags)],
Timeout) of
[Res] -> Res;
Else -> Else
end.

%% @spec (brick_name(), node_name(), io_list())
%% -> zzz_get_reply()
%% @equiv get(ServerName, Node, Key, [], DefaultTimeout)
Expand Down Expand Up @@ -2533,6 +2577,27 @@ make_set(Key, Value, ExpTime, Flags) ->
make_set(Key, TStamp, Value, ExpTime, Flags) ->
make_op6(set, Key, TStamp, Value, ExpTime, Flags).

%% @spec (term(), term()) -> do_op()
%% @equiv make_rename(Key, OldKey, 0, [])

-spec make_rename(key(), key()) -> rename().
make_rename(Key, OldKey) ->
make_rename(Key, OldKey, 0, []).

%% @spec (term(), term(), integer(), prop_list()) -> do_op()
%% @doc Create an "rename" do op (see encode_op_flags() for valid flags).

-spec make_rename(key(), key(), exp_time(), flags_list()) -> rename().
make_rename(Key, OldKey, ExpTime, Flags) ->
make_op5(rename, Key, OldKey, ExpTime, Flags).

%% @spec (term(), integer(), term(), integer(), prop_list()) -> do_op()
%% @doc Create an "rename" do op (see encode_op_flags() for valid flags).

-spec make_rename(key(), integer(), key(), exp_time(), flags_list()) -> rename().
make_rename(Key, TStamp, OldKey, ExpTime, Flags) ->
make_op6(rename, Key, TStamp, OldKey, ExpTime, Flags).

%% @spec (term()) -> do_op()
%% @equiv make_get(Key, [])

Expand Down Expand Up @@ -2843,7 +2908,7 @@ harvest_do_keys(DoList, S) ->
%% them in <tt>{read|write, term()}</tt> form.

harvest_do_keys([{OpName, Key, _, _, _, _}|T], Acc, S)
when OpName == add; OpName == replace; OpName == set ->
when OpName == add; OpName == replace; OpName == set; OpName == rename ->
harvest_do_keys(T, [{write, Key}|Acc], S);
harvest_do_keys([{delete, Key, _}|T], Acc, S) ->
harvest_do_keys(T, [{write, Key}|Acc], S);
Expand Down Expand Up @@ -5448,7 +5513,7 @@ quotas_pre_enforce_quota2(DoList, S) ->
Check = check_key_for_quota_root(Key, S),
if Check /= not_found andalso
(OpName == add orelse OpName == replace orelse
OpName == set orelse OpName == delete) ->
OpName == set orelse OpName == rename orelse OpName == delete) ->
{ok, QPrefix, QuotaTuple0} = Check,
QuotaTuple =
case orddict:find(QPrefix, QDict) of
Expand Down Expand Up @@ -5518,7 +5583,7 @@ quota_more_ops(DoOp, OpName, Key, QPrefix, QTS,
case KeyRecList of
[] ->
NotExistOp = make_get(Key, [must_not_exist]),
if OpName == add ; OpName == replace ; OpName == set ->
if OpName == add ; OpName == replace ; OpName == set ; OpName == rename ->
%% Adding a key that doesn't exist, so calculating
%% new quota usage is easy.
NewVal = element(4, DoOp),
Expand Down Expand Up @@ -5663,7 +5728,7 @@ ssf_impl_details(S) when is_record(S, state) ->
impl_details(S).

get_op_flags({OpName, _, _, _, _, Flags})
when OpName == add ; OpName == replace ; OpName == set ->
when OpName == add ; OpName == replace ; OpName == set ; OpName == rename ->
Flags;
get_op_flags({OpName, _, Flags})
when OpName == get ; OpName == delete ; OpName == get_many ->
Expand All @@ -5672,7 +5737,7 @@ get_op_flags(_) ->
[].

set_op_flags({OpName, _, _, _, _, _} = Do, NewFlags)
when OpName == add ; OpName == replace ; OpName == set ->
when OpName == add ; OpName == replace ; OpName == set ; OpName == rename ->
setelement(6, Do, NewFlags);
set_op_flags({OpName, _, _} = Do, NewFlags)
when OpName == get ; OpName == delete ; OpName == get_many ->
Expand Down

0 comments on commit a55c96e

Please sign in to comment.