From 6caeaeb6b598c1a3c7bcb25f41d14455f0f1818f Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Sun, 31 Aug 2014 15:42:20 +0900 Subject: [PATCH] Ha! Damn quick and easy to add tango_dt_map.erl --- prototype/tango-prototype/src/tango_dt.erl | 2 +- .../tango-prototype/src/tango_dt_map.erl | 69 +++++++++++++++++++ .../tango-prototype/src/tango_dt_register.erl | 2 +- prototype/tango-prototype/test/tango_test.erl | 35 ++++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 prototype/tango-prototype/src/tango_dt_map.erl diff --git a/prototype/tango-prototype/src/tango_dt.erl b/prototype/tango-prototype/src/tango_dt.erl index 3eb98fa..a851e27 100644 --- a/prototype/tango-prototype/src/tango_dt.erl +++ b/prototype/tango-prototype/src/tango_dt.erl @@ -98,7 +98,7 @@ handle_call({cb_dirty_op, Op}, _From, handle_call({cb_pure_op, Op}, _From, #state{cb_mod=CallbackMod} = State) -> State2 = #state{i_state=I_State} = roll_log_forward(State), Reply = CallbackMod:do_pure_op(Op, I_State), - {reply, {ok, Reply}, State2}; + {reply, Reply, State2}; handle_call({stop}, _From, State) -> {stop, normal, ok, State}; handle_call(_Request, _From, State) -> diff --git a/prototype/tango-prototype/src/tango_dt_map.erl b/prototype/tango-prototype/src/tango_dt_map.erl new file mode 100644 index 0000000..1a4276b --- /dev/null +++ b/prototype/tango-prototype/src/tango_dt_map.erl @@ -0,0 +1,69 @@ +%% ------------------------------------------------------------------- +%% +%% Copyright (c) 2014 Basho Technologies, Inc. All Rights Reserved. +%% +%% This file is provided to you under the Apache License, +%% Version 2.0 (the "License"); you may not use this file +%% except in compliance with the License. You may obtain +%% a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% ------------------------------------------------------------------- + +-module(tango_dt_map). + +-behaviour(tango_dt). + +-export([start_link/4, + set/3, get/2]). + +%% Tango datatype callbacks +-export([fresh/0, + do_pure_op/2, do_dirty_op/6, play_log_mutate_i_state/3]). + +-define(DICTMOD, dict). + +-define(LONG_TIME, 30*1000). + +start_link(PageSize, SequencerPid, Proj, StreamNum) -> + gen_server:start_link(tango_dt, + [PageSize, SequencerPid, Proj, ?MODULE, StreamNum], + []). + +set(Pid, Key, Val) -> + gen_server:call(Pid, {cb_dirty_op, {o_set, Key, Val}}, ?LONG_TIME). + +get(Pid, Key) -> + gen_server:call(Pid, {cb_pure_op, {o_get, Key}}, ?LONG_TIME). + + +fresh() -> + ?DICTMOD:new(). + +do_pure_op({o_get, Key}, Dict) -> + ?DICTMOD:find(Key, Dict). + +do_dirty_op({o_set, _Key, _Val}=Op, + I_State, StreamNum, Proj0, PageSize, BackPs) -> + Page = term_to_binary(Op), + FullPage = tango:pack_v1([{StreamNum, BackPs}], Page, PageSize), + {{ok, LPN}, Proj1} = corfurl_client:append_page(Proj0, FullPage, + [StreamNum]), + NewBackPs = tango:add_back_pointer(BackPs, LPN), + {ok, I_State, Proj1, LPN, NewBackPs}. + +play_log_mutate_i_state(Pages, _SideEffectsP, I_State) -> + lists:foldl(fun({o_set, Key, Val}=_Op, Dict) -> + ?DICTMOD:store(Key, Val, Dict) + end, + I_State, + [binary_to_term(Page) || Page <- Pages]). + diff --git a/prototype/tango-prototype/src/tango_dt_register.erl b/prototype/tango-prototype/src/tango_dt_register.erl index 9da6f12..3c81e05 100644 --- a/prototype/tango-prototype/src/tango_dt_register.erl +++ b/prototype/tango-prototype/src/tango_dt_register.erl @@ -47,7 +47,7 @@ fresh() -> undefined. do_pure_op({o_get}, Register) -> - Register. + {ok, Register}. do_dirty_op({o_set, _Val}=Op, I_State, StreamNum, Proj0, PageSize, BackPs) -> diff --git a/prototype/tango-prototype/test/tango_test.erl b/prototype/tango-prototype/test/tango_test.erl index 2c60d93..b5c1e2e 100644 --- a/prototype/tango-prototype/test/tango_test.erl +++ b/prototype/tango-prototype/test/tango_test.erl @@ -193,5 +193,40 @@ tango_dt_register_int(PageSize, Seq, Proj) -> ok. +tango_dt_map_test() -> + ok = run_test("/tmp", "tango_dt_map", + 4096, 5*1024, 1, fun tango_dt_map_int/3). + +tango_dt_map_int(PageSize, Seq, Proj) -> + {ok, OID_Map} = tango_oid:start_link(PageSize, Seq, Proj), + + {ok, Reg1Num} = tango_oid:new(OID_Map, "map1"), + {ok, Reg1} = tango_dt_map:start_link(PageSize, Seq, Proj, Reg1Num), + {ok, Reg2Num} = tango_oid:new(OID_Map, "map2"), + {ok, Reg2} = tango_dt_map:start_link(PageSize, Seq, Proj, Reg2Num), + + NumVals = 8, + Vals = [lists:flatten(io_lib:format("version ~w", [X])) || + X <- lists:seq(1, NumVals)], + Keys = ["key1", "key2"], + [tango_dt_map:set(Reg, Key, Val) || Reg <- [Reg1, Reg2], + Key <- Keys, Val <- Vals], + LastVal = lists:last(Vals), + [{ok, LastVal} = tango_dt_map:get(Reg1, Key) || Key <- Keys], + [{ok, LastVal} = tango_dt_map:get(Reg2, Key) || Key <- Keys], + + %% If we instantiate a new instance of an existing map, then + %% a single get should show the most recent modification. + {ok, Reg2b} = tango_dt_map:start_link(PageSize, Seq, Proj, Reg2Num), + [{ok, LastVal} = tango_dt_map:get(Reg2b, Key) || Key <- Keys], + %% If we update the "old" instance of a map, then the "new" + %% instance should also see the update. + NewVal = {"Heh", "a new value"}, + [ok = tango_dt_map:set(Reg2, Key, NewVal) || Key <- Keys], + [{ok, NewVal} = tango_dt_map:get(Reg2b, Key) || Key <- Keys], + [{ok, NewVal} = tango_dt_map:get(Reg2, Key) || Key <- Keys], % sanity + + ok. + -endif. % not PULSE -endif. % TEST