Permalink
Browse files

Pulled everything from japerk :

  • Loading branch information...
1 parent e45cdf6 commit df4d58de588cc2b24d2aa834851d3cad9b04ac57 @cstar cstar committed Dec 2, 2009
View
@@ -0,0 +1,5 @@
+{"src/*", [
+ debug_info,
+ {i, "include/"},
+ {outdir, "ebin/"}
+]}.
View
@@ -1,10 +1,10 @@
-LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
+# store output so is only executed once
+LIBDIR=$(shell erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell)
+# get application vsn from app file
+VSN=$(shell erl -pa ebin/ -eval 'application:load(erldis), {ok, Vsn} = application:get_key(erldis, vsn), io:format("~s~n", [Vsn])' -s init stop -noshell)
all:
- mkdir -p ebin/
- (cd src;$(MAKE))
- # test compile fails if eunit not present
- #(cd test;$(MAKE))
+ @erl -make
clean: clean_tests
(cd src;$(MAKE) clean)
@@ -24,12 +24,17 @@ testrun: all
mkdir -p ebin/
(cd test;$(MAKE) test)
-install: all
- # original "mkdir -p {LIBDIR}/erldis-0.0.1/{ebin,include}"
- # actually makes a directory called {ebin,include}
- mkdir -p ${LIBDIR}/erldis-0.0.1/ebin
- mkdir -p ${LIBDIR}/erldis-0.0.1/include
- for i in ebin/*.beam; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done
- for i in include/*.hrl; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done
+install: all
+ mkdir -p $(ERL_LIBS)/erldis-$(VSN)/ebin
+ mkdir -p $(ERL_LIBS)/erldis-$(VSN)/include
+ for i in ebin/*.beam; do install $$i $(ERL_LIBS)/erldis-$(VSN)/$$i ; done
+ for i in include/*.hrl; do install $$i $(ERL_LIBS)/erldis-$(VSN)/$$i ; done
# also install .app file
- install ebin/erldis.app $(LIBDIR)/erldis-0.0.1/ebin/erldis.app
+ install ebin/erldis.app $(ERL_LIBS)/erldis-$(VSN)/ebin/erldis.app
+ install ebin/erldis.appup $(ERL_LIBS)/erldis-$(VSN)/ebin/erldis.appup
+
+plt:
+ @dialyzer --build_plt --plt .plt -q -r . -I include/
+
+check: all
+ @dialyzer --check_plt --plt .plt -q -r . -I include/
View
@@ -0,0 +1,11 @@
+@doc Redis erlang client
+
+From dialtone on erldis_client:
+handle_info is the function that deals with parsing every line that comes from redis. save_or_reply is what is currently used to send replies back to the users.
+going through the State parameters:
+ * socket is of course the current connection to redis
+ * buffer contains intermediate results of parsing. it's used for multi-bulk replies. but it gets handy also for single bulk replies, although clearly it will be at most long 1 in those cases
+ * reply_caller is a function used to abstract the reply to the user. since the call is synchronous, the client might put itself in listening slower than redis can answer the request. when it manages to listen before the answer it adds a call that registers the call request and when it's done the system uses that function to send back the results. if it comes afterwards it simply gets the results in save_or_reply the function checks for reply_caller and if it's not there it just appends to results
+ * the field remaining is for how many remaining packets you need to handle before the end of this call. this is also especially useful for multi-bulk replies. when a call is made it's set to 1 then the rest of the state machine figures out if only 1 packet will be received or how many more (the state machine is in erldis_proto)
+ * then the field calls is the number of calls that are waiting. basically at the end of a call remaining would go to 0. but if it goes to 0 the state machine would parse the remaining stuff. so using calls we keep track of how many more calls are incoming and until calls is 0 remaining is reset to 1 when it goes to 0 at the end of a parsing. and this is done in save_or_reply
+ * then pstate is the parser state, there can be only 4 right now error, hold, read, empty. error means that the next line is an error message. hold means that the next number is the number of multi-bulk items in the reply and is used to set the remaining field to something else than 1. read tells you how long the next field is so you need to read those bytes + 2 (\r\n are added by redis but not counted in the bytes... I fought hard to avoid this but salvatore didn't change it...). then empty means that the system is ready to accept a new reply. the function trim2 exists just to remove the \r\n at the end of the reply
View
@@ -1,10 +1,11 @@
{application, erldis, [
{description, "Erlang Redis application"},
- {vsn, "0.0.1"},
+ {vsn, "0.0.7"},
{registered, [erldis_sup]},
{mod, {erldis_app, []}},
% TODO: include eunit?
{applications, [kernel, stdlib]},
- {modules, [erldis_client, erldis, erldis_proto, erldis_app, erldis_sup]},
+ {modules, [erldis_client, erldis, erldis_proto, erldis_app, erldis_sup,
+ erldis_sync_client, erldis_sets, erldis_dict, erldis_list]},
{env, [{host, "localhost"}, {port, 6379}, {timeout, 500}]}
-]}.
+]}.
View
@@ -0,0 +1,65 @@
+{"0.0.7", [
+ {"0.0.6", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_dict},
+ {load_module, erldis_list}
+ ]},
+ {"0.0.5", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets},
+ {add_module, erldis_dict},
+ {add_module, erldis_list}
+ ]},
+ {"0.0.4", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.3", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.2", [
+ {add_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.1", [
+ {add_module, erldis_client},
+ {add_module, erldis_proto},
+ {load_module, erldis},
+ {delete_module, client},
+ {delete_module, proto},
+ {add_module, erldis_sets}
+ ]}
+], [
+ {"0.0.6", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_dict},
+ {load_module, erldis_list}
+ ]},
+ {"0.0.5", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets},
+ {delete_module, erldis_dict},
+ {delete_module, erldis_list}
+ ]},
+ {"0.0.4", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.3", [
+ {load_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.2", [
+ {delete_module, erldis_sync_client},
+ {load_module, erldis_sets}
+ ]},
+ {"0.0.1", [
+ {add_module, client},
+ {add_module, proto},
+ {load_module, erldis},
+ {delete_module, erldis_client},
+ {delete_module, erldis_proto},
+ {delete_module, erldis_sets}
+ ]}
+]}.
View
@@ -256,18 +256,16 @@ handle_info({tcp, Socket, Data}, State=#redis{calls=Calls}) ->
inet:setopts(Socket, [{active, once}]),
{noreply, NewState};
handle_info({tcp_closed, Socket}, State=#redis{socket=Socket}) ->
- {stop, erldis_client_tcp_host_socket_closed, State};
+ % japerk: shutdown Reason does not generate an error message
+ {stop, shutdown, State};
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, State) ->
case State#redis.socket of
- undefined ->
- pass;
- Socket ->
- gen_tcp:close(Socket)
- end,
- ok.
+ undefined -> ok;
+ Socket -> gen_tcp:close(Socket)
+ end.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
View
@@ -0,0 +1,77 @@
+-module(erldis_dict).
+
+-export([append/3, append_list/3, erase/2, fetch/2, fetch_keys/2, find/2,
+ is_key/2, size/1, store/3, update/3, update/4,
+ update_counter/2, update_counter/3]).
+
+% NOTE: use erldis_lists instead, fetch & find won't work for lists
+append(Key, Value, Client) -> set_call(Client, rpush, Key, Value).
+
+append_list(Key, Values, Client) ->
+ lists:foreach(fun(Value) -> append(Key, Value, Client) end, Values).
+
+erase(Key, Client) -> scall(Client, del, [Key]).
+
+fetch(Key, Client) ->
+ case scall(Client, get, [Key]) of
+ [nil] -> undefined;
+ [Value] -> Value
+ end.
+
+% NOTE: this is only useful if keys have a known prefix
+fetch_keys(Pattern, Client) -> scall(Client, keys, [Pattern]).
+
+%filter(Pred, Client) -> ok.
+
+find(Key, Client) ->
+ case fetch(Key, Client) of
+ undefined -> error;
+ Value -> {ok, Value}
+ end.
+
+%fold(Fun, Acc0, Client) -> ok.
+
+%from_list(List, Client) -> ok.
+
+is_key(Key, Client) -> hd(scall(Client, exists, [Key])).
+
+size(Client) ->
+ numeric_value(erldis_sync_client:scall(Client, dbsize)).
+
+store(Key, [], Client) -> erase(Key, Client);
+store(Key, Value, Client) -> set_call(Client, set, Key, Value).
+
+%to_list(Client) -> ok.
+
+% NOTE: update/3 & update/4 are not atomic
+
+update(Key, Fun, Client) -> store(Key, Fun(fetch(Key, Client)), Client).
+
+update(Key, Fun, Initial, Client) ->
+ case find(Key, Client) of
+ {ok, Value} -> store(Key, Fun(Value), Client);
+ error -> store(Key, Initial, Client)
+ end.
+
+update_counter(Key, Client) -> update_counter(Key, 1, Client).
+
+% NOTE: this returns new count value, not a modified dict
+update_counter(Key, 1, Client) ->
+ numeric_value(scall(Client, incr, [Key]));
+update_counter(Key, Incr, Client) ->
+ numeric_value(scall(Client, incrby, [Key, Incr])).
+
+%%%%%%%%%%%%%
+%% helpers %%
+%%%%%%%%%%%%%
+
+numeric_value([false]) -> 0;
+numeric_value([true]) -> 1;
+numeric_value([Val]) -> Val.
+
+% TODO: copied from erldis_sets, abstract if possible, maybe use a macro
+
+scall(Client, Cmd, Args) -> erldis_sync_client:scall(Client, Cmd, Args).
+
+set_call(Client, Cmd, Key, Val) ->
+ erldis_sync_client:call(Client, Cmd, [[Key, length(Val)], [Val]]).
Oops, something went wrong.

0 comments on commit df4d58d

Please sign in to comment.