Skip to content

Commit

Permalink
renaming mcerlang to erlmc
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Vorreuter committed Oct 20, 2009
1 parent 4e9885e commit f6d086a
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 98 deletions.
2 changes: 1 addition & 1 deletion Makefile
@@ -1,6 +1,6 @@
LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell`
VERSION=0.2
PKGNAME=mcerlang
PKGNAME=erlmc

all: app
mkdir -p ebin/
Expand Down
33 changes: 10 additions & 23 deletions README.markdown
@@ -1,54 +1,41 @@
# MC Erlang caches beats on your face
## erlmc

Erlang binary protocol memcached client

## Dependencies

Binary protocol build of memcached <http://github.com/dustin/memcached>

## External Documentation

Text Protocol Spec <http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt>

Binary Protocol Spec <http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol>

## Quick Start

**You must have the binary protocol branch of memcached running as mentioned above**
**You must have version 1.3 or greater of memcached**

$> make
$> make test
$> sudo make install
$> memcached -d -m 1024 -p 11211 -l localhost
$> memcached -d -m 1024 -p 11121 -l localhost
$> memcached -d

1> mcerlang:start_link([{"localhost", 11211, 1}, {"localhost", 11121, 1}]).
{ok,<0.37.0>}
1> erlmc:start().
ok

2> mcerlang:stats().
2> erlmc:stats().
[{{"localhost",11211},
[{evictions,"0"},
{total_items,"0"},
{curr_items,"0"},
{bytes,"0"},
{...}|...]},
{{"localhost",11121},
[{evictions,"0"},
{total_items,"0"},
{curr_items,"0"},
{bytes,"0"},
{...}|...]}]

3> mcerlang:set(hello, <<"World">>).
3> erlmc:set(hello, <<"World">>).
<<>>

4> mcerlang:get(hello).
4> erlmc:get(hello).
<<"World">>

5> mcerlang:add("foo", <<"bar">>).
5> erlmc:add("foo", <<"bar">>).
<<>>

6> mcerlang:get("foo").
6> erlmc:get("foo").
<<"bar">>

## Commands
Expand Down
6 changes: 3 additions & 3 deletions ebin/mcerlang.app.in → ebin/erlmc.app.in
Expand Up @@ -3,11 +3,11 @@
VERSION=${1}
MODULES=`ls -1 src/*.erl | awk -F[/.] '{ print "\t\t" $2 }' | sed '$q;s/$/,/g'`

cat > ebin/mcerlang.app << EOF
{application, mcerlang,
cat > ebin/erlmc.app << EOF
{application, erlmc,
[{description, "Erlang binary protocol memcached client"},
{vsn, "${VERSION}"},
{modules, [mcerlang]},
{modules, [erlmc]},
{registered, []},
{applications, [kernel, stdlib]}
]}.
Expand Down
File renamed without changes.
42 changes: 21 additions & 21 deletions src/mcerlang.erl → src/erlmc.erl
Expand Up @@ -24,7 +24,7 @@
%%
%% http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
%% @doc a binary protocol memcached client
-module(mcerlang).
-module(erlmc).

-export([start/0, start/1, start_link/0, start_link/1, init/2,
add_server/3, remove_server/2, add_connection/2, remove_connection/2]).
Expand All @@ -35,7 +35,7 @@
append/2, prepend/2, stats/0, flush/0, flush/1, quit/0,
version/0]).

-include("mcerlang.hrl").
-include("erlmc.hrl").

-define(TIMEOUT, 60000).

Expand Down Expand Up @@ -161,9 +161,9 @@ multi_call(Msg) ->
%%--------------------------------------------------------------------
init(Parent, CacheServers) ->
process_flag(trap_exit, true),
register(mcerlang, self()),
ets:new(mcerlang_continuum, [ordered_set, protected, named_table]),
ets:new(mcerlang_connections, [bag, protected, named_table]),
register(erlmc, self()),
ets:new(erlmc_continuum, [ordered_set, protected, named_table]),
ets:new(erlmc_connections, [bag, protected, named_table]),

%% Continuum = [{uint(), {Host, Port}}]
[add_server_to_continuum(Host, Port) || {Host, Port, _} <- CacheServers],
Expand All @@ -183,17 +183,17 @@ loop() ->
add_server_to_continuum(Host, Port),
[start_connection(Host, Port) || _ <- lists:seq(1, ConnPoolSize)];
{remove_server, Host, Port} ->
[(catch gen_server:call(Pid, quit, ?TIMEOUT)) || [Pid] <- ets:match(mcerlang_connections, {{Host, Port}, '$1'})],
[(catch gen_server:call(Pid, quit, ?TIMEOUT)) || [Pid] <- ets:match(erlmc_connections, {{Host, Port}, '$1'})],
remove_server_from_continuum(Host, Port);
{add_connection, Host, Port} ->
start_connection(Host, Port);
{remove_connection, Host, Port} ->
[[Pid]|_] = ets:match(mcerlang_connections, {{Host, Port}, '$1'}),
[[Pid]|_] = ets:match(erlmc_connections, {{Host, Port}, '$1'}),
(catch gen_server:call(Pid, quit, ?TIMEOUT));
{'EXIT', Pid, Err} ->
case ets:match(mcerlang_connections, {'$1', Pid}) of
case ets:match(erlmc_connections, {'$1', Pid}) of
[[{Host, Port}]] ->
ets:delete_object(mcerlang_connections, {{Host, Port}, Pid}),
ets:delete_object(erlmc_connections, {{Host, Port}, Pid}),
case Err of
shutdown -> ok;
_ -> start_connection(Host, Port)
Expand All @@ -205,23 +205,23 @@ loop() ->
loop().

start_connection(Host, Port) ->
case mcerlang_conn:start_link([Host, Port]) of
{ok, Pid} -> ets:insert(mcerlang_connections, {{Host, Port}, Pid});
case erlmc_conn:start_link([Host, Port]) of
{ok, Pid} -> ets:insert(erlmc_connections, {{Host, Port}, Pid});
_ -> ok
end.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
add_server_to_continuum(Host, Port) ->
[ets:insert(mcerlang_continuum, {hash_to_uint(Host, Port), {Host, Port}}) || _ <- lists:seq(1, 100)].
[ets:insert(erlmc_continuum, {hash_to_uint(Host, Port), {Host, Port}}) || _ <- lists:seq(1, 100)].

remove_server_from_continuum(Host, Port) ->
case ets:match(mcerlang_continuum, {'$1', {Host, Port}}) of
case ets:match(erlmc_continuum, {'$1', {Host, Port}}) of
[] ->
ok;
List ->
[ets:delete(mcerlang_continuum, Key) || [Key] <- List]
[ets:delete(erlmc_continuum, Key) || [Key] <- List]
end.

package_key(Key) when is_atom(Key) ->
Expand All @@ -240,7 +240,7 @@ unique_connections() ->
dict:to_list(lists:foldl(
fun({Key, Val}, Dict) ->
dict:append_list(Key, [Val], Dict)
end, dict:new(), ets:tab2list(mcerlang_connections))).
end, dict:new(), ets:tab2list(erlmc_connections))).

%% Consistent hashing functions
%%
Expand All @@ -259,19 +259,19 @@ hash_to_uint(Key) when is_list(Key) ->
%% Key = string()
%% Conn = pid()
map_key(Key) when is_list(Key) ->
First = ets:first(mcerlang_continuum),
First = ets:first(erlmc_continuum),
{Host, Port} =
case find_next_largest(hash_to_uint(Key), First) of
undefined ->
case First of
'$end_of_table' -> exit(mcerlang_continuum_empty);
'$end_of_table' -> exit(erlmc_continuum_empty);
_ ->
[{_, Value}] = ets:lookup(mcerlang_continuum, First),
[{_, Value}] = ets:lookup(erlmc_continuum, First),
Value
end;
Value -> Value
end,
case ets:lookup(mcerlang_connections, {Host, Port}) of
case ets:lookup(erlmc_connections, {Host, Port}) of
[] -> exit({error, {connection_not_found, {Host, Port}}});
Pids ->
{_, Pid} = lists:nth(random:uniform(length(Pids)), Pids),
Expand All @@ -283,8 +283,8 @@ find_next_largest(_, '$end_of_table') ->
undefined;

find_next_largest(Int, Key) when Key > Int ->
[{_, Val}] = ets:lookup(mcerlang_continuum, Key),
[{_, Val}] = ets:lookup(erlmc_continuum, Key),
Val;

find_next_largest(Int, Key) ->
find_next_largest(Int, ets:next(mcerlang_continuum, Key)).
find_next_largest(Int, ets:next(erlmc_continuum, Key)).
4 changes: 2 additions & 2 deletions src/mcerlang_conn.erl → src/erlmc_conn.erl
Expand Up @@ -24,10 +24,10 @@
%%
%% http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
%% @doc a binary protocol memcached client
-module(mcerlang_conn).
-module(erlmc_conn).
-behaviour(gen_server).

-include("mcerlang.hrl").
-include("erlmc.hrl").

%% gen_server callbacks
-export([start_link/1, init/1, handle_call/3, handle_cast/2,
Expand Down
48 changes: 48 additions & 0 deletions t/erlmc_t_001.t
@@ -0,0 +1,48 @@
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -pa ./ebin -sasl errlog_type error -boot start_sasl -noshell

main(_) ->
etap:plan(unknown),

(fun() ->
{ok, Socket} = gen_tcp:connect("localhost", 11211, [binary, {packet, 0}, {active, false}]),

gen_tcp:send(Socket, <<128,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>),
etap:ok((fun({ok, _}) -> true; (_) -> false end)(gen_tcp:recv(Socket, 0, 2000)), "noop"),

gen_tcp:send(Socket, <<128,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>),

ok
end)(),

(fun() ->
etap:is(erlmc:start(), ok, "erlmc connect to default memcached server ok"),

etap:is(erlmc:set("Hello", <<"World">>), <<>>, "set ok"),
etap:is(erlmc:add("Hello", <<"Fail">>), <<"Data exists for key.">>, "add ok"),
etap:is(erlmc:get("Hello"), <<"World">>, "get ok"),
etap:is(erlmc:delete("Hello"), <<>>, "delete ok"),
etap:is(erlmc:add("Hello", <<"World2">>), <<>>, "add ok"),
etap:is(erlmc:get("Hello"), <<"World2">>, "get ok"),
etap:is(erlmc:append("Hello", <<"!!!">>), <<>>, "append ok"),
etap:is(erlmc:get("Hello"), <<"World2!!!">>, "get ok"),
etap:is(erlmc:prepend("Hello", <<"$$$">>), <<>>, "prepend ok"),
etap:is(erlmc:get("Hello"), <<"$$$World2!!!">>, "get ok"),
etap:is(erlmc:delete("Hello"), <<>>, "delete ok"),
etap:is(erlmc:get("Hello"), <<>>, "get ok"),

erlmc:set("One", <<"A">>),
erlmc:set("Two", <<"B">>),
erlmc:set("Three", <<"C">>),

etap:is(erlmc:get_many(["One", "Two", "Two-and-a-half", "Three"]), [{"One",<<"A">>},{"Two",<<"B">>},{"Two-and-a-half",<<>>},{"Three",<<"C">>}], "get_many ok"),

etap:is(erlmc:flush(0), [{{"localhost",11211},<<>>}], "flush ok"),

etap:is(erlmc:quit(), [{{"localhost",11211},[true]}], "quit ok"),

ok
end)(),

etap:end_tests().
48 changes: 0 additions & 48 deletions t/mcerlang_t_001.t

This file was deleted.

1 comment on commit f6d086a

@ngerakines
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safe to drop my mcerlang repos then?

Please sign in to comment.