Permalink
Browse files

usability changes and getting ready for new release

  • Loading branch information...
1 parent a638f9e commit edbe2feeea6412d4e5601b78cd962daa3fceb157 zeusfaber committed Jan 25, 2009
Showing with 103 additions and 121 deletions.
  1. +2 −2 Makefile
  2. +42 −99 README
  3. +59 −20 src/merle.erl
View
@@ -1,10 +1,10 @@
LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
APP_NAME="merle"
-VSN="0.1"
+VSN="0.2"
all: compile
-docs:
+docs:
erl -noshell -run edoc_run application "'$(APP_NAME)'" '"."' '$(VSN)' -s init stop
compile:
View
@@ -1,124 +1,67 @@
merle : An erlang based memcached client.
-Version : 0.1
+Version : 0.2
+
Author : Joe Williams <joe@joetify.com>
-Blog : http://www.joeandmotorboat.com/
+Contributors : Nick Gerakines <nick@gerakines.net>
+
Info : http://github.com/joewilliams/merle/
This code is available as Open Source Software under the MIT license.
+
Features:
-* Support for stats, version, get, delete, set, add, replace, cas
-* Supports making calls to memcached directly as well as through gen_server
+* Support for stats, version, getkey, getskey, delete, set, add, replace, cas, flushall, verbosity
-To Do:
-* The noreply option and the append, prepend, increment and decrement commands will likely be added in the future
-* Support for retrieving multiple keys at once
-* Socket pool/reuse
-Installation:
+Usage:
-$ cd /some/erlang/lib/location/
-$ tar zxvf merle-VERSION.tar.gz
-$ cd merle-VERSION
-$ make
-$ erl
-> merle:module_info().
+* Connecting to memcached *
-This should display info about merle if installd correctly.
+> merle:connect().
-Usage:
+> merle:connect("localhost", 11211).
-* Start it up *
-2> merle:start_link("localhost", 11211).
-{ok,<0.38.0>}
+* A few operations *
-* Set and get some data *
+> merle:set(a, asdf).
+ok
+> merle:getkey(a).
+asdf
-9> merle:set("b", "1", "0", [asdf,[{asdf, asdf}, asdf]]).
-["STORED"]
-10> merle:get("b").
-[[asdf,[{asdf,asdf},asdf]]]
+> merle:set(a, asdf).
+ok
+> merle:getskey(a).
+[4,asdf]
+> merle:cas(a, 4, asdfasdf).
+ok
+> merle:getskey(a).
+[5,asdfasdf]
-* Get the memcached version *
+> merle:delete(a).
+ok
-11> merle:version().
-["VERSION 1.2.6"]
+* Informational commands *
-* Get memcached stats *
+> merle:version().
+["VERSION 1.2.6"]
-12> merle:stats().
-["STAT pid 12177","STAT uptime 6146","STAT time 1231993128",
- "STAT version 1.2.6","STAT pointer_size 64",
- "STAT rusage_user 0.008000","STAT rusage_system 0.000000",
- "STAT curr_items 2","STAT total_items 2",
- "STAT bytes 128976","STAT curr_connections 2",
- "STAT total_connections 3","STAT connection_structures 3",
- "STAT cmd_get 3","STAT cmd_set 2","STAT get_hits 3",
- "STAT get_misses 0","STAT evictions 0",
- "STAT bytes_read 128911","STAT bytes_written 257735",
- "STAT limit_maxbytes 67108864","STAT threads 1","END"]
-
-* Get stats with arguments *
-
-145> merle:stats("localhost", 11211, "slabs").
+> merle:stats(slabs).
["STAT 1:chunk_size 104","STAT 1:chunks_per_page 10082",
"STAT 1:total_pages 1","STAT 1:total_chunks 10082",
"STAT 1:used_chunks 10081","STAT 1:free_chunks 1",
- "STAT 1:free_chunks_end 10080","STAT 21:chunk_size 10320",
- "STAT 21:chunks_per_page 101","STAT 21:total_pages 1",
- "STAT 21:total_chunks 101","STAT 21:used_chunks 101",
- "STAT 21:free_chunks 0","STAT 21:free_chunks_end 100",
- "STAT active_slabs 2","STAT total_malloced 2090848","END"]
-
-* Direct memcached call example *
-
-13> merle:set("localhost", 11211, "a", "1", "0", asdf).
-["STORED"]
-14> merle:get("localhost", 11211, "a").
-[asdf]
-
-
-
-API:
-
-start_link(Host, Port)
-
-stats()
-
-stats(Host, Port)
-
-stats(Args)
+ "STAT 1:free_chunks_end 10080","STAT active_slabs 1",
+ "STAT total_malloced 1048528","END"]
-stats(Host, Port, Args)
-
-version()
-
-version(Host, Port)
-
-get(Key)
-
-get(Host, Port, Key)
-
-delete(Key, Time)
-
-delete(Host, Port, Key, Time)
-
-set(Key, Flag, ExpTime, Data)
-
-set(Host, Port, Key, Flag, ExpTime, Data)
-
-add(Key, Flag, ExpTime, Data)
-
-add(Host, Port, Key, Flag, ExpTime, Data)
-
-replace(Key, Flag, ExpTime, Data)
-
-replace(Host, Port, Key, Flag, ExpTime, Data)
-
-cas(Key, Flag, ExpTime, CasUniq, Data)
-
-cas(Host, Port, Key, Flag, ExpTime, CasUniq, Data)
-
-quit()
+> merle:stats().
+["STAT pid 27195","STAT uptime 497","STAT time 1232843046",
+ "STAT version 1.2.6","STAT pointer_size 64",
+ "STAT rusage_user 0.000000","STAT rusage_system 0.008000",
+ "STAT curr_items 1","STAT total_items 5","STAT bytes 83",
+ "STAT curr_connections 2","STAT total_connections 5",
+ "STAT connection_structures 3","STAT cmd_get 5",
+ "STAT cmd_set 5","STAT get_hits 5","STAT get_misses 0",
+ "STAT evictions 0","STAT bytes_read 216",
+ "STAT bytes_written 468","STAT limit_maxbytes 67108864",
+ "STAT threads 1","END"]
View
@@ -24,7 +24,7 @@
%%
%% @author Joseph Williams <joe@joetify.com>
%% @copyright 2008 Joseph Williams
-%% @version 0.1
+%% @version 0.2
%% @seealso http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
%% @doc An Erlang memcached client.
%%
@@ -35,20 +35,22 @@
-module(merle).
-behaviour(gen_server).
--author("Joseph Williams <joe@joetify.com>").
--version("Version: 0.1").
+-author("Joe Williams <joe@joetify.com>").
+-version("Version: 0.2").
-define(SERVER, ?MODULE).
-define(TIMEOUT, 5000).
+-define(DEFAULT_HOST, "localhost").
+-define(DEFAULT_PORT, 11211).
-define(TCP_OPTS, [
binary, {packet, raw}, {nodelay, true},{reuseaddr, true}, {active, true}
]).
%% gen_server API
-export([
- start_link/2, stats/0, stats/1, version/0, getkey/1, delete/2, set/4, add/4,
- replace/4, cas/5, set/2, flushall/0, flushall/1, verbosity/1, add/2, replace/2,
- cas/3, getskey/1
+ stats/0, stats/1, version/0, getkey/1, delete/2, set/4, add/4, replace/2,
+ replace/4, cas/5, set/2, flushall/0, flushall/1, verbosity/1, add/2,
+ cas/3, getskey/1, connect/0, connect/2, delete/1
]).
%% gen_server callbacks
@@ -77,17 +79,26 @@ version() ->
verbosity(Args) when is_integer(Args) ->
verbosity(integer_to_list(Args));
verbosity(Args)->
- gen_server:call(?SERVER, {verbosity, {Args}}).
+ case gen_server:call(?SERVER, {verbosity, {Args}}) of
+ ["OK"] -> ok;
+ [X] -> X
+ end.
%% @doc invalidate all existing items immediately
flushall() ->
- gen_server:call(?SERVER, {flushall}).
+ case gen_server:call(?SERVER, {flushall}) of
+ ["OK"] -> ok;
+ [X] -> X
+ end.
%% @doc invalidate all existing items based on the expire time argument
-flushall(Args) when is_integer(Args) ->
- flushall(integer_to_list(Args));
-flushall(Args) ->
- gen_server:call(?SERVER, {flushall, {Args}}).
+flushall(Delay) when is_integer(Delay) ->
+ flushall(integer_to_list(Delay));
+flushall(Delay) ->
+ case gen_server:call(?SERVER, {flushall, {Delay}}) of
+ ["OK"] -> ok;
+ [X] -> X
+ end.
%% @doc retrieve value based off of key
getkey(Key) when is_atom(Key) ->
@@ -107,13 +118,20 @@ getskey(Key) ->
[X] -> X
end.
-%% @doc delete a key and specify time
+%% @doc delete a key
+delete(Key) ->
+ delete(Key, "0").
+
delete(Key, Time) when is_atom(Key) ->
delete(atom_to_list(Key), Time);
delete(Key, Time) when is_integer(Time) ->
delete(Key, integer_to_list(Time));
delete(Key, Time) ->
- gen_server:call(?SERVER, {delete, {Key, Time}}).
+ case gen_server:call(?SERVER, {delete, {Key, Time}}) of
+ ["DELETED"] -> ok;
+ ["NOT_FOUND"] -> not_found;
+ [X] -> X
+ end.
%% Time is the amount of time in seconds
%% the client wishes the server to refuse
@@ -151,6 +169,7 @@ set(Key, Flag, ExpTime, Value) when is_integer(ExpTime) ->
set(Key, Flag, ExpTime, Value) ->
case gen_server:call(?SERVER, {set, {Key, Flag, ExpTime, Value}}) of
["STORED"] -> ok;
+ ["NOT_STORED"] -> not_stored;
[X] -> X
end.
@@ -166,7 +185,11 @@ add(Key, Flag, ExpTime, Value) when is_integer(Flag) ->
add(Key, Flag, ExpTime, Value) when is_integer(ExpTime) ->
add(Key, Flag, integer_to_list(ExpTime), Value);
add(Key, Flag, ExpTime, Value) ->
- gen_server:call(?SERVER, {add, {Key, Flag, ExpTime, Value}}).
+ case gen_server:call(?SERVER, {add, {Key, Flag, ExpTime, Value}}) of
+ ["STORED"] -> ok;
+ ["NOT_STORED"] -> not_stored;
+ [X] -> X
+ end.
%% @doc Replace an existing key/value pair.
replace(Key, Value) ->
@@ -180,7 +203,11 @@ replace(Key, Flag, ExpTime, Value) when is_integer(Flag) ->
replace(Key, Flag, ExpTime, Value) when is_integer(ExpTime) ->
replace(Key, Flag, integer_to_list(ExpTime), Value);
replace(Key, Flag, ExpTime, Value) ->
- gen_server:call(?SERVER, {replace, {Key, Flag, ExpTime, Value}}).
+ case gen_server:call(?SERVER, {replace, {Key, Flag, ExpTime, Value}}) of
+ ["STORED"] -> ok;
+ ["NOT_STORED"] -> not_stored;
+ [X] -> X
+ end.
%% @doc Store a key/value pair if possible.
cas(Key, CasUniq, Value) ->
@@ -196,7 +223,19 @@ cas(Key, Flag, ExpTime, CasUniq, Value) when is_integer(ExpTime) ->
cas(Key, Flag, ExpTime, CasUniq, Value) when is_integer(CasUniq) ->
cas(Key, Flag, ExpTime, integer_to_list(CasUniq), Value);
cas(Key, Flag, ExpTime, CasUniq, Value) ->
- gen_server:call(?SERVER, {cas, {Key, Flag, ExpTime, CasUniq, Value}}).
+ case gen_server:call(?SERVER, {cas, {Key, Flag, ExpTime, CasUniq, Value}}) of
+ ["STORED"] -> ok;
+ ["NOT_STORED"] -> not_stored;
+ [X] -> X
+ end.
+
+%% @doc connect to memcached with defaults
+connect() ->
+ connect(?DEFAULT_HOST, ?DEFAULT_PORT).
+
+%% @doc connect to memcached
+connect(Host, Port) ->
+ start_link(Host, Port).
%% @private
start_link(Host, Port) ->
@@ -227,8 +266,8 @@ handle_call({flushall}, _From, Socket) ->
Reply = send_generic_cmd(Socket, iolist_to_binary([<<"flush_all">>])),
{reply, Reply, Socket};
-handle_call({flushall, {Args}}, _From, Socket) ->
- Reply = send_generic_cmd(Socket, iolist_to_binary([<<"flush_all ">>, Args])),
+handle_call({flushall, {Delay}}, _From, Socket) ->
+ Reply = send_generic_cmd(Socket, iolist_to_binary([<<"flush_all ">>, Delay])),
{reply, Reply, Socket};
handle_call({getkey, {Key}}, _From, Socket) ->
@@ -371,7 +410,7 @@ recv_complex_get_reply(Socket) ->
end.
%% @private
-%% @doc receive function for cas respones containing VALUEs
+%% @doc receive function for cas responses containing VALUEs
recv_complex_gets_reply(Socket) ->
receive
%% For receiving get responses where the key does not exist

0 comments on commit edbe2fe

Please sign in to comment.