(#15) : add atomic apply function to modify value

This commit is contained in:
Dmitry Kolesnikov 2017-03-09 20:38:10 +02:00
parent 9f31083a2a
commit 4ca5b8caba
6 changed files with 92 additions and 25 deletions

View File

@ -1,9 +1,6 @@
install: script: make && make test
- make rebar3
script:
- make && make test
language: erlang language: erlang
otp_release: otp_release:
- 18.2.1 - 19.2
- 17.5 - 18.3

View File

@ -4,7 +4,7 @@
## @description ## @description
## Makefile to build and release Erlang applications using standard development tools ## Makefile to build and release Erlang applications using standard development tools
## ##
## @version 0.11.5 ## @version 0.11.8
##################################################################### #####################################################################
## ##
@ -22,9 +22,12 @@ TEST ?= ${APP}
S3 ?= S3 ?=
VMI ?= fogfish/erlang VMI ?= fogfish/erlang
NET ?= lo0 NET ?= lo0
URL ?= undefined URL ?= undefined
LATEST ?= latest LATEST ?= latest
## rebar version (no spaces at end)
REBAR ?= 3.3.2
## root path to benchmark framework ## root path to benchmark framework
BB = ../basho_bench BB = ../basho_bench
SSHENV = /tmp/ssh-agent.conf SSHENV = /tmp/ssh-agent.conf
@ -46,17 +49,17 @@ EFLAGS = \
## self-extracting bundle wrapper ## self-extracting bundle wrapper
BUNDLE_INIT = PREFIX=${PREFIX}\nREL=${PREFIX}/${REL}\nAPP=${APP}\nVSN=${VSN}\nLINE=`grep -a -n "BUNDLE:$$" $$0`\nmkdir -p $${REL}\ntail -n +$$(( $${LINE%%%%:*} + 1)) $$0 | gzip -vdc - | tar -C $${REL} -xvf - > /dev/null\n BUNDLE_INIT = PREFIX=${PREFIX}\nREL=${PREFIX}/${REL}\nAPP=${APP}\nVSN=${VSN}\nLINE=`grep -a -n "BUNDLE:$$" $$0`\nmkdir -p $${REL}\ntail -n +$$(( $${LINE%%%%:*} + 1)) $$0 | gzip -vdc - | tar -C $${REL} -xvf - > /dev/null\n
BUNDLE_FREE = exit\nBUNDLE:\n BUNDLE_FREE = exit\nBUNDLE:\n
BUILDER = FROM ${VMI}\nRUN mkdir ${APP}\nCOPY . ${APP}/\nRUN cd ${APP} && make && make rel\n BUILDER = FROM ${VMI}\nARG VERSION=\nRUN mkdir ${APP}\nCOPY . ${APP}/\nRUN cd ${APP} && make VSN=\x24{VERSION} && make rel VSN=\x24{VERSION}\n
CTRUN = \ CTRUN = \
-module(test). \ -module(test). \
-export([run/1]). \ -export([run/1]). \
run(Spec) -> \ run(Spec) -> \
{ok, Test} = file:consult(Spec), \ {ok, Test} = file:consult(Spec), \
case lists:keyfind(node, 1, Test) of \ Error = case lists:keyfind(node, 1, Test) of \
false -> ct:run_test([{spec, Spec}]); \ false -> element(2, ct:run_test([{spec, Spec}])); \
true -> ct_master:run(Spec) \ true -> ct_master:run(Spec) \
end, \ end, \
erlang:halt(). erlang:halt(Error).
##################################################################### #####################################################################
## ##
@ -119,7 +122,7 @@ relx.config: rel/relx.config.src
@cat $< | sed 's/release/release, {${APP}, "${VSN}"}/' > $@ @cat $< | sed 's/release/release, {${APP}, "${VSN}"}/' > $@
else else
${PKG}.tar.gz: _build/dockermake ${PKG}.tar.gz: _build/dockermake
@docker build --file=$< --force-rm=true --tag=build/${APP}:latest . ;\ @docker build --file=$< --force-rm=true --build-arg="VERSION=${VSN}" --tag=build/${APP}:latest . ;\
I=`docker create build/${APP}:latest` ;\ I=`docker create build/${APP}:latest` ;\
docker cp $$I:/${APP}/$@ $@ ;\ docker cp $$I:/${APP}/$@ $@ ;\
docker rm -f $$I ;\ docker rm -f $$I ;\
@ -136,7 +139,7 @@ docker: rel/Dockerfile
--build-arg APP=${APP} \ --build-arg APP=${APP} \
--build-arg VSN=${VSN} \ --build-arg VSN=${VSN} \
-t ${URL}/${APP}:${VSN} -f $< . -t ${URL}/${APP}:${VSN} -f $< .
docker tag -f ${URL}/${APP}:${VSN} ${URL}/${APP}:${LATEST} docker tag ${URL}/${APP}:${VSN} ${URL}/${APP}:${LATEST}
@ -207,8 +210,9 @@ console: ${PKG}.tar.gz
## ##
##################################################################### #####################################################################
rebar3: rebar3:
@curl -L -O https://s3.amazonaws.com/rebar3/rebar3 ; \ @echo "==> install rebar (${REBAR})" ;\
chmod ugo+x $@ curl -L -O --progress-bar https://github.com/erlang/rebar3/releases/download/${REBAR}/rebar3 ;\
chmod +x $@
.PHONY: test rel deps all pkg .PHONY: test rel deps all pkg

View File

@ -1,7 +1,7 @@
{application, cache, {application, cache,
[ [
{description, "in-memory cache"}, {description, "in-memory cache"},
{vsn, "2.1.1"}, {vsn, "2.2.0"},
{modules, []}, {modules, []},
{registered, []}, {registered, []},
{applications,[ {applications,[

View File

@ -62,7 +62,11 @@
remove/2, remove/2,
remove/3, remove/3,
remove_/2, remove_/2,
remove_/3 remove_/3,
apply/3,
apply/4,
apply_/4,
apply_/3
]). ]).
%% extended cache i/o interface %% extended cache i/o interface
-export([ -export([
@ -303,6 +307,36 @@ remove_(Cache, Key, true) ->
remove_(Cache, Key, false) -> remove_(Cache, Key, false) ->
send(Cache, {remove, Key}). send(Cache, {remove, Key}).
%%
%% synchronous apply function to entity on cache
%% the function maps element, the new value is returned
%% the operation prolongs value ttl
-spec apply(cache(), key(), fun((_) -> _)) -> val() | undefined.
-spec apply(cache(), key(), fun((_) -> _), timeout()) -> val() | undefined.
apply(Cache, Key, Fun) ->
cache:apply(Cache, Key, Fun, ?CONFIG_TIMEOUT).
apply(Cache, Key, Fun, Timeout) ->
call(Cache, {apply, Key, Fun}, Timeout).
%%
%% asynchronous apply function to entity on cache
%% the function maps element, the new value is returned
%% the operation prolongs value ttl
-spec apply_(cache(), key(), fun((_) -> _)) -> ok | reference().
-spec apply_(cache(), key(), fun((_) -> _), true | false) -> ok | reference().
apply_(Cache, Key, Fun) ->
cache:apply_(Cache, Key, Fun, false).
apply_(Cache, Key, Fun, true) ->
cast(Cache, {apply, Key, Fun});
apply_(Cache, Key, Fun, false) ->
cast(Cache, {apply, Key, Fun}).
%%%---------------------------------------------------------------------------- %%%----------------------------------------------------------------------------
%%% %%%
%%% extended cache i/o interface %%% extended cache i/o interface

View File

@ -121,6 +121,10 @@ handle_call({ttl, Key}, _, State) ->
handle_call({remove, Key}, _, State) -> handle_call({remove, Key}, _, State) ->
{reply, ok, cache_remove(Key, State)}; {reply, ok, cache_remove(Key, State)};
handle_call({apply, Key, Fun}, _, State0) ->
{Result, State1} = cache_apply(Key, Fun, State0),
{reply, Result, State1};
handle_call({acc, Key, Val}, _, State0) -> handle_call({acc, Key, Val}, _, State0) ->
{Result, State1} = cache_acc(Key, Val, State0), {Result, State1} = cache_acc(Key, Val, State0),
{reply, Result, State1}; {reply, Result, State1};
@ -328,6 +332,16 @@ cache_remove(Key, #cache{name=_Name, heap=Heap}=State) ->
?DEBUG("cache ~p: remove ~p~n", [_Name, Key]), ?DEBUG("cache ~p: remove ~p~n", [_Name, Key]),
State. State.
%%
%%
cache_apply(Key, Fun, State) ->
case Fun(cache_get(Key, State)) of
undefined ->
{undefined, State};
Val ->
{Val, cache_put(Key, Val, undefined, State)}
end.
%% %%
%% @todo: reduce one write %% @todo: reduce one write
cache_acc(Key, Val, State) cache_acc(Key, Val, State)

View File

@ -42,7 +42,9 @@
lookup/1, lookup/1,
has/1, has/1,
remove/1, remove/1,
remove_/1 remove_/1,
apply/1,
apply_/1
]). ]).
%% %%
@ -77,7 +79,7 @@ groups() ->
{primitives, [parallel], {primitives, [parallel],
[lifecycle]}, [lifecycle]},
{basic_io, [parallel], {basic_io, [parallel],
[put, put_, get, lookup, has, remove, remove_]}, [put, put_, get, lookup, has, remove, remove_, apply, apply_]},
{extended_io, [parallel], {extended_io, [parallel],
[acc, set, add, replace, append, append_, prepend, prepend_, delete]} [acc, set, add, replace, append, append_, prepend, prepend_, delete]}
]. ].
@ -169,6 +171,22 @@ remove_(_Config) ->
false= cache:has(Cache, key), false= cache:has(Cache, key),
ok = cache:drop(Cache). ok = cache:drop(Cache).
apply(_Config) ->
{ok, Cache} = cache:start_link([]),
val = cache:apply(Cache, key, fun(undefined) -> val end),
val = cache:get(Cache, key),
lav = cache:apply(Cache, key, fun(val) -> lav end),
lav = cache:get(Cache, key),
ok = cache:drop(Cache).
apply_(_Config) ->
{ok, Cache} = cache:start_link([]),
cache:apply_(Cache, key, fun(undefined) -> val end),
val = cache:get(Cache, key),
cache:apply_(Cache, key, fun(val) -> lav end),
lav = cache:get(Cache, key),
ok = cache:drop(Cache).
%%%---------------------------------------------------------------------------- %%%----------------------------------------------------------------------------
%%% %%%
%%% cache extended i/o %%% cache extended i/o