-module(stm). -export([new/1, add/2, add/3, read/1, write/2, pull/2, push/3, example/0, example_buffer/0]). %% new(Tm) -> Pid %% create the transaction memory store (TM) %% %% add(Tm, Name) -> Var %% add a uninitialized variable to the TM store %% %% add(Tm, Name, Init) -> Var %% add a variable to the TM store which is initialized with Init %% If it already exists, it returns the variable %% %% read(Var) -> Value %% return the value of the TM variable %% %% write(Var, Value) -> ok %% write Value into TM variable Var %% %% pull(Tm, Name) -> Var %% lookup variable V in the TM store %% %% push(Tm, Var) -> Bool %% update variable Var in the TM store new(Tm) -> genserver:start(Tm, dict:new(), fun loop/2). add(Tm, Name) -> genserver:request(Tm, {add, Name, void}). add(Tm, Name, Init) -> genserver:request(Tm, {add, Name, Init}). read({_Name, _Version, Value}) -> Value. write({Name, Version, _Value}, NewValue) -> {Name, Version, NewValue}. pull(Tm, Var) -> genserver:request(Tm, {pull, Var}). push(Tm, Name, {Name, Ver, Value}) -> genserver:request(Tm, {push, {Name, Ver, Value}}). %% TM store logic! loop(Vars, {add, Name, Init}) -> case dict:find(Name, Vars) of {ok, _} -> {ok, Vars} ; error -> {ok, dict:store(Name, {0,Init}, Vars)} end ; loop(Vars, {pull, Name}) -> case dict:find(Name, Vars) of {ok, {Ver, Value}} -> {{Name, Ver, Value}, Vars} ; _ -> {error, Vars} end ; loop(Vars, {push, {Name, Ver, Value}}) -> {VerTM, _} = dict:fetch(Name, Vars), case Ver of VerTM -> {true, dict:store(Name, {Ver+1, Value}, Vars)} ; _ -> {false, Vars} end. %% Example example() -> catch(unregister(tm)), new(tm), add(tm, x, 42), add(tm, v, 70), spawn(fun () -> transaction1(tm) end), spawn(fun () -> transaction2(tm) end), timer:sleep(500), io:format("Final value of x:~p~n", [read(pull(tm,x))]), tm ! stop. transaction1(Tm) -> X = pull(Tm, x), I = read(X), timer:sleep(150), NewX = write(X, I + 1), case push(Tm, x, NewX) of true -> io:format("Transaction 1 succeeded!~n",[]) ; false -> io:format("Transaction 1 failed!~n",[]) end. transaction2(Tm) -> X = pull(Tm, x), V = pull(Tm, v), timer:sleep(200), I = read(V), J = read(X), NewX = write(X, I+J), case push(Tm, x, NewX) of true -> io:format("Transaction 2 succeeded!~n",[]) ; false -> io:format("Transaction 2 failed!~n",[]) end. %% Example with the buffer get_buff(Tm, Name) -> Buff = pull(Tm, Name), [X | Xs] = read(Buff), NewBuff = write(Buff, Xs), case push(Tm, Name, NewBuff) of true -> X ; false -> get_buff(Tm, Name) end. put_buff(Tm, Name, X) -> Buff = pull(Tm, Name), Xs = read(Buff), NewBuff = write(Buff, Xs ++ [X]), case push(Tm, Name, NewBuff) of true -> ok ; false -> put_buff(Tm, Name, X) end. get_put_buff(Tm, Name1, Name2) -> Elem = get_buff(Tm, Name1), put_buff(Tm, Name2, Elem). example_buffer() -> catch(unregister(tm)), new(tm), add(tm, buff1, [1,2]), add(tm, buff2, []), io:format("Buffer 1 = ~p~n", [read(pull(tm, buff1))]), io:format("Buffer 2 = ~p~n", [read(pull(tm, buff2))]), get_put_buff(tm, buff1, buff2), io:format("Buffer 1 = ~p~n", [read(pull(tm, buff1))]), io:format("Buffer 2 = ~p~n", [read(pull(tm, buff2))]), tm ! stop.