Skip to content
This repository
Browse code

remote files not needed

  • Loading branch information...
commit 9370e3cd1cc243b519be7ba5c3f702a9c2198cc1 1 parent bb0239e
Zhou Li authored July 09, 2012
6  lib/mcache/src/Makefile
... ...
@@ -1,6 +0,0 @@
1  
-#NATIVE=1
2  
-
3  
-APP_NAME=mcache
4  
-#ERL_COMPILE_FLAGS += -I ../include 
5  
-
6  
-include $(ERL_TOP)/make/app.mk
106  lib/mcache/src/mcache.erl
... ...
@@ -1,106 +0,0 @@
1  
--module(mcache).
2  
--author('echou327@gmail.com').
3  
-
4  
-%-compile([inline]). 
5  
-%-compile([native, {hipe, o3}]).
6  
-
7  
--export([get_server/2, get/2, mget/2, set/5, set/4, delete/2]).
8  
-
9  
--define(SEP, ":").
10  
--define(MGET_TIMEOUT, 500).
11  
-
12  
-get(Class, Key) ->
13  
-    {Key1, Server, _DefaultExpiry} = get_server(Class, Key),
14  
-    {_, Value} = mcache_client:mc_get(Server, Key1),
15  
-    %io:format("get ~p~n", [Value]),
16  
-	mcache_util:decode_value(Value).
17  
-
18  
-mget(Class, [_|_]=Keys) ->
19  
-    erlang:yield(),
20  
-    {KeyDict, ServerDict} = lists:foldl(
21  
-                                fun(K, {KAcc,SAcc}) ->
22  
-                                    {K1, Server, _DefaultExpiry} = get_server(Class, K),
23  
-                                    {dict:store(K1, K, KAcc), dict:append(Server, K1, SAcc)}
24  
-                                end, {dict:new(), dict:new()}, Keys),
25  
-    Ref = erlang:make_ref(),
26  
-    dict:map(fun(Server, Ks) -> 
27  
-                mcache_client:ab_mget(Server, Ref, Ks) 
28  
-            end, ServerDict),
29  
-    Results = mget_receive(dict:size(KeyDict), Ref, ?MGET_TIMEOUT*1000, []),
30  
-    %io:format("~p~n", [Results]),
31  
-    flat_foldl(
32  
-        fun({RealKey, Val}, LAcc) ->
33  
-            case dict:find(RealKey, KeyDict) of
34  
-                {ok, Key} ->
35  
-                    [{Key, mcache_util:decode_value(Val)}|LAcc];
36  
-                _ ->
37  
-                    LAcc
38  
-            end
39  
-        end, [], Results).
40  
-
41  
-mget2(Class, [_|_]=Keys) ->
42  
-    ServerDict = lists:foldl(
43  
-                    fun(K, SAcc) ->
44  
-                        {K1, Server, _DefaultExpiry} = get_server(Class, K),
45  
-                        dict:append(Server, K1, SAcc)
46  
-                    end, dict:new(), Keys),
47  
-    Ref = erlang:make_ref(),
48  
-    dict:map(fun(Server, Ks) -> 
49  
-                mcache_client:ab_mget(Server, Ref, Ks) 
50  
-            end, ServerDict),
51  
-    Results = mget_receive(length(Keys), Ref, ?MGET_TIMEOUT*1000, []).
52  
-
53  
-set(Class, Key, Value, Format, Expiry) ->
54  
-	{Key1, Server, DefaultExpiry} = get_server(Class, Key),
55  
-	{Value1, Flags} = mcache_util:encode_value(Value, Format),
56  
-	Expiry1 = mcache_util:encode_expiry(Expiry, DefaultExpiry),
57  
-	mcache_client:ab_set(Server, Key1, Value1, Flags, Expiry1),
58  
-	ok.
59  
-
60  
-set(Class, Key, Value, Format) ->
61  
-    set(Class, Key, Value, Format, default).
62  
-
63  
-delete(Class, Key) ->
64  
-	{Key1, Server} = get_server(Class, Key),
65  
-	mcache_client:ab_delete(Server, Key1),
66  
-	ok.
67  
-
68  
-% internal functions
69  
-
70  
-flat_foldl(_Fun, Acc, []) ->
71  
-    Acc;
72  
-flat_foldl(Fun, Acc, [H|T]) ->
73  
-    Acc1 = case H of
74  
-            [] -> Acc;
75  
-            [_|_] -> flat_foldl(Fun, Acc, H);
76  
-            _ -> Fun(H, Acc)
77  
-        end,
78  
-    flat_foldl(Fun, Acc1, T).
79  
-
80  
-my_now() ->
81  
-    erlang:now().
82  
-
83  
-wrap_items(nil, L) ->
84  
-    L;
85  
-wrap_items(Items, L) ->
86  
-    [Items|L].
87  
-
88  
-mget_receive(N, _Ref, Timeout, L) when N =< 0; Timeout =< 0 ->
89  
-    L;
90  
-mget_receive(N, Ref, Timeout, L) ->
91  
-    Now = my_now(),
92  
-    TimeoutMillis = Timeout div 1000,
93  
-    receive
94  
-        {Ref, {mget, NumKeys, Items}} -> 
95  
-            Now1 = my_now(),
96  
-            T1 = Timeout - timer:now_diff(Now1, Now),
97  
-            mget_receive(N-NumKeys, Ref, T1, wrap_items(Items, L))
98  
-    after TimeoutMillis ->
99  
-        L
100  
-    end.
101  
-
102  
-get_server(Class, Key) ->
103  
-    Key1 = mcache_util:map_key(Class, Key),
104  
-    {Pool, Expiry} = mcache_expires:expire(Class),
105  
-    Server = mcache_continuum:find(Pool, mcache_util:hash(Key1, md5)),
106  
-    {Key1, Server, Expiry}.
55  lib/mcache/src/mcache2.erl
... ...
@@ -1,55 +0,0 @@
1  
-%
2  
-% wraps memcached_drv
3  
-%
4  
-
5  
--module(mcache2).
6  
--author('echou327@gmail.com').
7  
-
8  
--export([get/2, mget/2, mget2/2, set/5, delete/3]).
9  
-
10  
--define(DICT, dict).
11  
-
12  
-get(Class, Key) ->
13  
-    {Pool, _Expiry} = mcache_expires:expire(Class),
14  
-    {mc_async, 0, {ok, Value}} = memcached_drv:get(Pool, 0, mcache_util:map_key(Class, Key)),
15  
-    mcache_util:decode_value(Value).
16  
-    
17  
-mget(Class, [_|_]=Keys) ->
18  
-    {Pool, _Expiry} = mcache_expires:expire(Class),
19  
-    {RealKeys, KeyDict} = lists:foldl(fun(K, {RK,D}) ->
20  
-                            K1 = mcache_util:map_key(Class, K),
21  
-                            {[K1|RK], ?DICT:store(K1, K, D)}
22  
-                        end, {[], ?DICT:new()}, Keys),
23  
-
24  
-    {mc_async, 0, {ok, Values}} = memcached_drv:mget(Pool, 0, RealKeys),
25  
-    lists:foldl(fun({Key, Val, Flag}, Acc) ->
26  
-                    case ?DICT:find(Key, KeyDict) of
27  
-                        error -> Acc;
28  
-                        {ok, K} -> [{K, mcache_util:decode_value({Val, Flag})}|Acc]
29  
-                    end
30  
-                end, [], Values).
31  
-
32  
-decode_values([], [], L) ->
33  
-    lists:reverse(L);
34  
-decode_values([K|Ks], [undefined|Vs],  L) ->
35  
-    decode_values(Ks, Vs, L);
36  
-decode_values([K|Ks], [V|Vs], L) ->
37  
-    decode_values(Ks, Vs, [{K, mcache_util:decode_value(V)}|L]).
38  
-    
39  
-mget2(Class, [_|_]=Keys) ->
40  
-    {Pool, _Expiry} = mcache_expires:expire(Class),
41  
-    {mc_async, 0, {ok, Values}} = memcached_drv:mget2(Pool, 0, Class, Keys),
42  
-    decode_values(Keys, Values, []).
43  
-
44  
-set(Class, Key, Value, Format, Expiry) ->
45  
-    {Pool, DefaultExpiry} = mcache_expires:expire(Class),
46  
-	{Value1, Flags} = mcache_util:encode_value(Value, Format),
47  
-	Expiry1 = mcache_util:encode_expiry(Expiry, DefaultExpiry),
48  
-    {mc_async, 0, ok} = memcached_drv:set(Pool, 0, mcache_util:map_key(Class, Key), Value1, Flags, Expiry1),
49  
-    ok.
50  
-
51  
-delete(Class, Key, Expiry) ->
52  
-    {Pool, _} = mcache_expires:expire(Class),
53  
-	Expiry1 = mcache_util:encode_expiry(Expiry, 0),
54  
-    {mc_async, 0, ok} = memcached_drv:delete(Pool, 0, mcache_util:map_key(Class, Key), Expiry1),
55  
-    ok.
65  lib/mcache/src/mcache_app.erl
... ...
@@ -1,65 +0,0 @@
1  
--module(mcache_app).
2  
--author('echou327@gmail.com').
3  
-
4  
--behaviour(application).
5  
--behaviour(supervisor).
6  
-
7  
--export([start/2, stop/1, config_change/3]).
8  
--export([init/1]).
9  
-
10  
-
11  
--export([restart/0, start/0, start_link/0, stop/0]).
12  
-
13  
-% API
14  
-
15  
-start_link() ->
16  
-    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
17  
-
18  
-start() ->
19  
-    application:start(mcache).
20  
-
21  
-stop() ->
22  
-    application:stop(mcache).
23  
-
24  
-restart() ->
25  
-	io:format("[MCACHE_APP] restart() ~n", []),	
26  
-	mcache_util:reload_config([mcache]),
27  
-    ?MODULE:stop(),
28  
-	?MODULE:start().
29  
-
30  
-% application callbacks
31  
-
32  
-start(_Type, _Args) ->
33  
-    ?MODULE:start_link().
34  
-
35  
-stop(_State) ->
36  
-    ok.
37  
-
38  
-config_change(_Changed, _New, _Removed) ->
39  
-    ok.
40  
-
41  
-% supervisor callback
42  
-init([]) ->
43  
-    io:format("[MCACHE] Starting~n"),
44  
-    Specs = specs([{mcache_client_sup, 1}, % must be 1
45  
-                   {mcache_config, 1},
46  
-                   {mcache_memcached_drv_sup, 1}
47  
-                   ]),  % must be 1
48  
-    {ok, {{one_for_one, 10, 10}, Specs}}.
49  
-
50  
-% supervisor local functions
51  
-specs(Specs) ->
52  
-    lists:foldl(fun({Module, Count}, Acc) ->
53  
-                    Acc ++ mcache_util:sup_child_spec(Module, fun one_spec/2, Count)
54  
-                end, [], Specs).
55  
-
56  
-one_spec(mcache_config, Id) ->
57  
-    PoolsConfig = mcache_util:get_app_env(pools, []),
58  
-    ExpiresConfig = mcache_util:get_app_env(expires, []),
59  
-    {Id, {mcache_config, start_link, [ {PoolsConfig, ExpiresConfig} ]}, permanent, 2000, worker, []};
60  
-one_spec(mcache_client_sup, Id) ->
61  
-    {Id, {mcache_client_sup, start_link, []}, permanent, infinity, supervisor, []};
62  
-one_spec(mcache_memcached_drv_sup, Id) ->
63  
-    {Id, {mcache_memcached_drv_sup, start_link, []}, permanent, infinity, supervisor, []};
64  
-one_spec(Module, Id) ->
65  
-    {Id, {Module, start_link, []}, permanent, 2000, worker, []}.
62  lib/mcache/src/mcache_binary_frame.erl
... ...
@@ -1,62 +0,0 @@
1  
--module(mcache_binary_frame).
2  
--author('echou327@gmail.com').
3  
-
4  
--compile(bin_opt_info).
5  
-
6  
--export([initial_state/0, parse/2, encode/1]).
7  
-
8  
--include("mcache_binary_frame.hrl").
9  
-
10  
--define(HEADER_LEN, 24). % magic (0x81) + header (23 bytes)
11  
-
12  
--record(frame, {data_len=?HEADER_LEN, data= <<>>, resp=nil}).
13  
--record(packet, {seq,opcode,status,key_len,extra_len,body}).
14  
-
15  
-% parse response packets
16  
-
17  
-initial_state() ->
18  
-    {header, #frame{data_len=?HEADER_LEN, data= <<>>, resp=nil}, []}.
19  
-    
20  
-
21  
-parse({State, Frame, Acc}, <<>>) ->
22  
-    { {State, Frame, []}, lists:reverse(Acc)};
23  
-
24  
-parse({State, Frame, Acc}, Data) ->
25  
-    case parse_fsm(State, Frame, Data) of
26  
-        {done, Rest, Frame1} ->
27  
-            parse({header, #frame{}, [Frame1#frame.resp|Acc]}, Rest);
28  
-        {State1, Rest1, Frame1} ->
29  
-            parse({State1, Frame1, Acc}, Rest1)
30  
-    end.
31  
-
32  
-parse_fsm(header, #frame{data_len=Len, data=Data}=Frame, Bin) when byte_size(Bin) >= Len ->
33  
-    <<16#81, Opcode, KeyLen:16, ExtraLen, DataType, Status:16, TotalBodyLen:32, Seq:32, CAS:64, Rest/binary>> = <<Data/binary, Bin/binary>>,
34  
-    Resp = #resp{opcode=Opcode,
35  
-                 status=Status,
36  
-                 key_len=KeyLen, extra_len=ExtraLen, 
37  
-                 body_len=TotalBodyLen-KeyLen-ExtraLen,
38  
-                 seq=Seq, data_type=DataType, cas=CAS},
39  
-    State = if TotalBodyLen =:= 0 -> done; true -> body end,
40  
-    {State, Rest, Frame#frame{data_len=TotalBodyLen, data= <<>>, resp=Resp}};
41  
-
42  
-parse_fsm(body, #frame{data_len=Len, data=Data, resp=Resp}=Frame, Bin) when byte_size(Bin) >= Len ->
43  
-    KeyLen = Resp#resp.key_len,
44  
-    ExtraLen = Resp#resp.extra_len,
45  
-    BodyLen = Resp#resp.body_len,
46  
-    <<Extra:ExtraLen/binary, Key:KeyLen/binary, Body:BodyLen/binary, Rest/binary>> = <<Data/binary, Bin/binary>>,
47  
-    {done, Rest, Frame#frame{data_len=0, data= <<>>, resp=Resp#resp{key=Key, extra=Extra, body=Body}}};
48  
-
49  
-parse_fsm(State, #frame{data_len=Len, data=Data}=Frame, Bin) ->
50  
-    {State, <<>>, Frame#frame{data_len=Len-byte_size(Bin), data= <<Data/binary, Bin/binary>>}}.
51  
-
52  
-
53  
-% encode
54  
-encode(#req{opcode=Opcode, data_type=DataType, seq=Seq, cas=CAS, extra=Extra, key=Key, body=Body}) ->
55  
-	KeyLen = iolist_size(Key),
56  
-	BodyLen = iolist_size(Body),
57  
-	ExtraLen = iolist_size(Extra),
58  
-	TotalBodyLen = KeyLen + BodyLen + ExtraLen,
59  
-    %OpcodeNum = mcache_proto:opcode(Opcode),
60  
-    [ <<16#80, Opcode:8, KeyLen:16, ExtraLen:8, DataType:8, 0:16, TotalBodyLen:32, Seq:32, CAS:64>>, Extra, Key, Body ].
61  
-
62  
-
392  lib/mcache/src/mcache_client.erl
... ...
@@ -1,392 +0,0 @@
1  
--module(mcache_client).
2  
--author('echou327@gmail.com').
3  
-
4  
--compile([inline, bin_opt_info]).
5  
-
6  
--behaviour(gen_server).
7  
-
8  
--export([start_link/1]).
9  
--export([init/1,handle_call/3,handle_cast/2,handle_info/2,code_change/3,terminate/2]).
10  
--export([mc_get/2, ab_get/2, mc_mget/2, ab_mget/3, mc_set/5, ab_set/5, mc_delete/2, ab_delete/2]).
11  
-
12  
-
13  
--include_lib("kernel/src/inet_int.hrl").
14  
-
15  
--define(PG2_GROUP_TAG, ?MODULE).
16  
--define(SOCK_OPTS, [binary, {active, true}, {delay_send, false}, {nodelay, true}, {packet, raw}]).
17  
--define(CONNECT_TIMEOUT, 2000).
18  
--define(RECONNECT_AFTER, 5000).
19  
-
20  
--define(DICT, pdict).
21  
-
22  
--record(state, {addr, seq=0, parser, pendings, sock=not_connected, connecting}).
23  
-
24  
--include("mcache_binary_frame.hrl").
25  
-
26  
--record(pending, {from, time}).
27  
--record(mget_pending, {from, time, num_keys, items}).
28  
-
29  
-start_link({Host, Port}) ->
30  
-    gen_server:start_link(?MODULE, [{Host, Port}], []).
31  
-
32  
-init([{Host, Port}=Server]) ->
33  
-    process_flag(trap_exit, true),
34  
-
35  
-    pg2:create({?PG2_GROUP_TAG, Server}),
36  
-    pg2:join({?PG2_GROUP_TAG, Server}, self()),
37  
-
38  
-    {ok, Sock, Ref} = async_connect(Host, Port, ?SOCK_OPTS, ?CONNECT_TIMEOUT),
39  
-
40  
-    {ok, #state{sock=not_connected,
41  
-                addr={Host, Port},
42  
-                seq=0,
43  
-                parser=mcache_binary_frame:initial_state(),
44  
-                pendings=?DICT:new(),
45  
-                connecting={Sock, Ref}}}.
46  
-
47  
-% HANDLE_CALL
48  
-
49  
-handle_call({mc, _Req}, _From, #state{sock=not_connected}=State) ->
50  
-    {reply, {error, not_connected}, State};
51  
-
52  
-handle_call({mc, Req}, From, State) ->
53  
-    case send_wrapper(Req, From, State) of
54  
-        {ok, NewState} ->
55  
-            {noreply, NewState};
56  
-        {Any, NewState} ->
57  
-            {reply, {error, Any}, NewState}
58  
-    end;
59  
-
60  
-handle_call({mc_ab, Req}, From, State) ->
61  
-    case send_wrapper(Req, From, State) of
62  
-        {ok, NewState} ->
63  
-            {reply, pending, NewState};
64  
-        {Any, NewState} ->
65  
-            {reply, {error, Any}, NewState}
66  
-    end;
67  
-
68  
-handle_call(_Req, _From, State) ->
69  
-    {noreply, State}.
70  
-
71  
-% HANDLE_CAST
72  
-
73  
-handle_cast({mc, _Req}, #state{sock=not_connected}=State) ->
74  
-    {noreply, State};
75  
-
76  
-handle_cast({mc_ab, {mget, From, Keys}}, State) ->
77  
-    {_, State1} = send_wrapper({mget, Keys}, From, State),
78  
-    {noreply, State1};
79  
-
80  
-handle_cast({mc, Req}, #state{sock=Sock, seq=Seq}=State) ->
81  
-    case (catch send_req(Sock, Seq, Req)) of
82  
-        ok ->
83  
-            {noreply, State#state{seq=Seq+1}};
84  
-        _ ->
85  
-            {noreply, State}
86  
-    end;
87  
-
88  
-handle_cast(_Req, State) ->
89  
-    {noreply, State}.
90  
-
91  
-
92  
-    
93  
-% HANDLE_INFO
94  
-
95  
-handle_info({inet_async, Sock, Ref, Status}, #state{connecting={Sock, Ref}}=State) ->
96  
-    %error_logger:info_msg("inet_async: ~p, ~p, ~p~n", [Sock, Ref, Status]),
97  
-    case Status of
98  
-        ok ->
99  
-            {noreply, State#state{sock=Sock, connecting=undefined}};
100  
-        _ ->
101  
-            {noreply, socket_close(State), hibernate}
102  
-    end;
103  
-
104  
-handle_info({tcp_closed, Sock}, #state{sock=Sock}=State) ->
105  
-    catch gen_tcp:close(Sock),
106  
-    {stop, tcp_closed, State};
107  
-
108  
-handle_info(reconnect, #state{addr={Host, Port}}=State) ->
109  
-    {ok, Sock, Ref} = async_connect(Host, Port, ?SOCK_OPTS, ?CONNECT_TIMEOUT),
110  
-    {noreply, State#state{sock=not_connected, connecting={Sock, Ref}}, hibernate};
111  
-
112  
-handle_info({tcp, Sock, Data}, #state{sock=Sock,parser=Parser,pendings=Pendings}=State) ->
113  
-    {NewParser, Resps} = mcache_binary_frame:parse(Parser, Data),
114  
-    case Resps of
115  
-        [] ->
116  
-            {noreply, State#state{parser=NewParser}};
117  
-        [_|_] ->
118  
-            NewPendings = lists:foldl(fun handle_one_resp/2, Pendings, Resps),
119  
-            {noreply, State#state{parser=NewParser,pendings=NewPendings}}
120  
-    end;
121  
-
122  
-handle_info({tcp_old, Sock, Data}, #state{sock=Sock,pendings=Pendings}=State) ->
123  
-    Resps = parse(Data),
124  
-    %error_logger:info_msg("recv: ~p~n", [Resps]),
125  
-    case Resps of
126  
-        [] ->
127  
-            {noreply, State};
128  
-        [_|_] ->
129  
-            NewPendings = lists:foldl(fun handle_one_resp/2, Pendings, Resps),
130  
-            {noreply, State#state{pendings=NewPendings}}
131  
-    end;
132  
-    
133  
-    
134  
-
135  
-handle_info(_Msg, State) ->
136  
-    %error_logger:info_msg("handle_info: ~p~n", [_Msg]),
137  
-    {noreply, State}.
138  
-
139  
-% MISC CALLBACKS
140  
-
141  
-code_change(_OldVsn, State, _Extra) ->
142  
-    {ok, State}.
143  
-
144  
-terminate(_Reason, _State) ->
145  
-    ok.
146  
-
147  
-%%%% internal functions
148  
-
149  
-pending_create({mget, Keys}, From) ->
150  
-    #mget_pending{from=From, time=erlang:now(), num_keys=length(Keys), items=nil};
151  
-pending_create(_Req, From) ->
152  
-    #pending{from=From, time=erlang:now()}.
153  
-
154  
-send_wrapper(Req, From, #state{sock=Sock, seq=Seq, pendings=Pendings}=State) ->
155  
-    case (catch send_req(Sock, Seq, Req)) of
156  
-        true ->
157  
-            P = pending_create(Req, From), 
158  
-            {ok, State#state{seq=Seq+1, pendings=?DICT:store(Seq,P,Pendings)}};
159  
-        _Any ->
160  
-            io:format("send_wrapper ~p~n", [_Any]),
161  
-            {not_sent, State}
162  
-    end.
163  
-
164  
-socket_close(#state{sock=not_connected, pendings=Pendings}=State) ->
165  
-    flush_pendings(Pendings, {error, closed}),
166  
-    erlang:send_after(?RECONNECT_AFTER, self(), reconnect),
167  
-    State#state{connecting=undefined, pendings=?DICT:new(), parser=mcache_binary_frame:initial_state()};
168  
-socket_close(#state{sock=Sock}=State) when is_port(Sock) ->
169  
-    catch gen_tcp:close(Sock),
170  
-    socket_close(State#state{sock=not_connected}).
171  
-
172  
-prepend_list(Key, Value, nil) ->
173  
-    [{Key,Value}];
174  
-prepend_list(Key, Value, L) ->
175  
-    [{Key,Value}|L].
176  
-
177  
-parse(Bin) ->
178  
-    L = 
179  
-        case erlang:get(current_data) of
180  
-            undefined ->
181  
-                parse_resp(Bin, []);
182  
-            Data ->
183  
-                parse_resp(<<Data/binary, Bin/binary>>, [])
184  
-        end,
185  
-    lists:reverse(L).
186  
-
187  
-parse_resp(<<>>, L) ->
188  
-    erlang:erase(current_data),
189  
-    L;
190  
-parse_resp(<<16#81, Opcode, KeyLen:16, ExtraLen, _DataType, Status:16, TotalBodyLen:32, Seq:32, CAS:64, Body:TotalBodyLen/binary, Rest/binary>>, L) ->
191  
-    parse_resp(Rest, [build_resp(Opcode, Status, Seq, CAS, KeyLen, ExtraLen, Body)|L]);
192  
-
193  
-parse_resp(Bin, L) ->
194  
-    case erlang:get(current_data) of
195  
-        undefined ->
196  
-            erlang:put(current_data, Bin),
197  
-            L;
198  
-        Data ->
199  
-            parse_resp(<<Data/binary, Bin/binary>>, L)
200  
-    end.
201  
-
202  
-build_resp(Opcode, Status, Seq, CAS, KeyLen, ExtraLen, Body) ->
203  
-    <<Extra:ExtraLen/binary, Key:KeyLen/binary, Data/binary>> = Body,
204  
-    #resp{opcode=Opcode,
205  
-          status=Status,
206  
-          seq=Seq,
207  
-          cas=CAS,
208  
-          key=Key,
209  
-          extra=Extra,
210  
-          body=Data}.
211  
-
212  
-% Handles mget sequences (getkq, getkq, ..., noop)
213  
-handle_one_resp(#resp{opcode=?getkq, seq=Seq}=Resp, Pendings) ->
214  
-    case ?DICT:find(Seq, Pendings) of
215  
-        {ok, #mget_pending{items=Items}=P} ->
216  
-            case decode_resp(Resp) of
217  
-                {ok, {Key, Value}} ->
218  
-                    ?DICT:store(Seq, P#mget_pending{items=prepend_list(Key,Value,Items)}, Pendings);
219  
-                _ ->
220  
-                    Pendings
221  
-            end;
222  
-        _ -> % normal pendings
223  
-            Pendings
224  
-    end;
225  
-
226  
-handle_one_resp(#resp{opcode=?noop,seq=Seq}, Pendings) ->
227  
-    case ?DICT:find(Seq, Pendings) of
228  
-        {ok, #mget_pending{from=From, num_keys=NumKeys, items=Items}} ->
229  
-            gen_server:reply(From, {mget, NumKeys, Items});
230  
-        _ ->
231  
-            ok
232  
-    end,
233  
-    ?DICT:erase(Seq, Pendings);
234  
-
235  
-
236  
-handle_one_resp(#resp{seq=Seq}=Resp, Pendings) ->
237  
-    case ?DICT:find(Seq, Pendings) of
238  
-        {ok, #pending{from=From}} ->
239  
-            Result = case (catch decode_resp(Resp)) of
240  
-                        {ok, Any} -> Any;
241  
-                        {'EXIT', Reason} -> {error, Reason};
242  
-                        Status -> Status
243  
-                    end,
244  
-            gen_server:reply(From, Result);
245  
-        _ ->
246  
-            ok
247  
-    end,
248  
-    ?DICT:erase(Seq, Pendings).
249  
-
250  
-% TODO modification not done yet!
251  
-flush_pendings(Pendings, Result) ->
252  
-    dict:map(
253  
-        fun(_Seq, #pending{from=From}) ->
254  
-            gen_server:reply(From, Result),
255  
-            ok;
256  
-        (_Seq, #mget_pending{from=From, items=Items}) ->
257  
-            gen_server:reply(From, {mget, Items}),
258  
-            ok;
259  
-        (_, _) ->
260  
-            ok
261  
-        end,
262  
-        Pendings).
263  
-
264  
-
265  
-% internal apis
266  
-
267  
-get_client_pid(Server) ->
268  
-    case pg2:get_closest_pid({?PG2_GROUP_TAG, Server}) of
269  
-        {error, {no_process, _Reason}} ->
270  
-            exit(no_process);
271  
-        Pid when is_pid(Pid) ->
272  
-            %error_logger:info_msg("get_client_pid ~p ~p~n", [Server, Pid]),
273  
-            Pid
274  
-    end.
275  
-
276  
-async_connect({A,B,C,D}=_Addr, Port, Opts, Time) ->
277  
-    case inet:connect_options(Opts, inet) of
278  
-        {error, Reason} ->
279  
-            exit(Reason);
280  
-        {ok, #connect_opts{fd=Fd, ifaddr=BAddr={_,_,_,_}, port=BPort, opts=SockOpts}} ->
281  
-            case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of
282  
-                {ok, S} ->
283  
-                    prim_inet:async_connect(S, {A,B,C,D}, Port, Time);
284  
-                Error ->
285  
-                    Error
286  
-            end;
287  
-        {ok, _} ->
288  
-            exit(badarg)
289  
-    end.
290  
-
291  
-do_send_req(Sock, [_|_]=Reqs) ->
292  
-    erlang:port_command(Sock, [ mcache_binary_frame:encode(Req) || Req <- Reqs ]);
293  
-do_send_req(Sock, Req) ->
294  
-    erlang:port_command(Sock, mcache_binary_frame:encode(Req)).
295  
-
296  
-send_req(Sock, Seq, {mget, Keys}) ->
297  
-    Reqs = [ #req{opcode=?getkq, seq=Seq, key=K} || K <- Keys ],
298  
-    do_send_req(Sock, lists:reverse([#req{opcode=?noop, seq=Seq}|Reqs]));
299  
-
300  
-send_req(Sock, Seq, version) ->
301  
-    do_send_req(Sock, #req{opcode=?version, seq=Seq});
302  
-
303  
-send_req(Sock, Seq, {delete, Key}) ->
304  
-    do_send_req(Sock, #req{opcode=?delete, seq=Seq, key=Key});
305  
-
306  
-send_req(Sock, Seq, {flush, Expiry}) ->
307  
-    do_send_req(Sock, #req{opcode=?flush, seq=Seq, extra= <<Expiry:32>>});
308  
-send_req(Sock, Seq, flush) ->
309  
-    do_send_req(Sock, #req{opcode=?flush, seq=Seq});
310  
-
311  
-send_req(Sock, Seq, {getk, Key}) ->
312  
-    do_send_req(Sock, #req{opcode=?getk, seq=Seq, key=Key});
313  
-
314  
-send_req(Sock, Seq, {set, Key, Value, Flags, Expiry}) ->
315  
-    do_send_req(Sock, #req{opcode=?set, seq=Seq, key=Key, body=Value, extra= <<Flags:32, Expiry:32>>});
316  
-
317  
-send_req(Sock, Seq, {add, Key, Value, Flags, Expiry}) ->
318  
-    do_send_req(Sock, #req{opcode=?add, seq=Seq, key=Key, body=Value, extra= <<Flags:32, Expiry:32>>});
319  
-
320  
-send_req(Sock, Seq, {replace, Key, Value, Flags, Expiry}) ->
321  
-    do_send_req(Sock, #req{opcode=?replace, seq=Seq, key=Key, body=Value, extra= <<Flags:32, Expiry:32>>});
322  
-
323  
-send_req(Sock, Seq, {incr, Key, Delta, Initial, Expiry}) ->
324  
-    do_send_req(Sock, #req{opcode=?incr, seq=Seq, key=Key, extra= <<Delta:64, Initial:64, Expiry:32>>});
325  
-
326  
-send_req(Sock, Seq, {decr, Key, Delta, Initial, Expiry}) ->
327  
-    do_send_req(Sock, #req{opcode=?decr, seq=Seq, key=Key, extra= <<Delta:64, Initial:64, Expiry:32>>}).
328  
-
329  
-
330  
-decode_resp(#resp{opcode=?noop}) ->
331  
-    {ok, noop};
332  
-
333  
-decode_resp(#resp{opcode=?getk, status=Status, extra=Extra, key=Key, body=Value}) ->
334  
-    case Status of
335  
-        ?ok ->
336  
-            <<Flags:32>> = Extra,
337  
-            {ok, {Key, {Value, Flags}}};
338  
-        _ -> 
339  
-            {ok, {Key, undefined}}
340  
-    end;
341  
-
342  
-decode_resp(#resp{opcode=?getkq, status=Status, extra=Extra, key=Key, body=Value}) ->
343  
-    case Status of
344  
-        ?ok ->
345  
-            <<Flags:32>> = Extra,
346  
-            {ok, {Key, {Value, Flags}}};
347  
-        _ -> 
348  
-            {ok, {Key, undefined}}
349  
-    end;
350  
-
351  
-decode_resp(#resp{opcode=?incr, status=?ok, body= <<Value:64>>}) ->
352  
-	{ok, Value};
353  
-
354  
-decode_resp(#resp{opcode=?decr, status=?ok, body= <<Value:64>>}) ->
355  
-	{ok, Value};
356  
-
357  
-decode_resp(#resp{opcode=?version, status=?ok, body=Body}) ->
358  
-	{ok, binary_to_list(Body)};
359  
-
360  
-decode_resp(#resp{opcode=_, status=Status}) ->
361  
-	mcache_proto:status(Status).
362  
-
363  
-
364  
-% ======================================================= 
365  
-%                    PUBLIC API
366  
-% =======================================================
367  
-
368  
-mc_get(Server, Key) ->
369  
-    gen_server:call(get_client_pid(Server), {mc, {getk, Key}}).
370  
-
371  
-ab_get(Server, Key) ->
372  
-    gen_server:call(get_client_pid(Server), {mc_ab, {getk, Key}}).
373  
-
374  
-mc_mget(Server, Keys) ->
375  
-    gen_server:call(get_client_pid(Server), {mc, {mget, Keys}}).
376  
-
377  
-ab_mget(Server, Ref, Keys) ->
378  
-    % gen_server:call(get_client_pid(Server), {mc_ab, {mget, Keys}}).
379  
-    gen_server:cast(get_client_pid(Server), {mc_ab, {mget, {self(), Ref}, Keys}}).
380  
-
381  
-
382  
-mc_set(Server, Key, Value, Flags, Expiry) ->
383  
-	gen_server:call(get_client_pid(Server), {mc, {set, Key, Value, Flags, Expiry}}).
384  
-
385  
-ab_set(Server, Key, Value, Flags, Expiry) ->
386  
-	gen_server:cast(get_client_pid(Server), {mc, {set, Key, Value, Flags, Expiry}}).
387  
-
388  
-mc_delete(Server, Key) ->
389  
-	gen_server:call(get_client_pid(Server), {mc, {delete, Key}}).
390  
-
391  
-ab_delete(Server, Key) ->
392  
-	gen_server:cast(get_client_pid(Server), {mc, {delete, Key}}).
54  lib/mcache/src/mcache_client_sup.erl
... ...
@@ -1,54 +0,0 @@
1  
--module(mcache_client_sup).
2  
--author('echou327@gmail.com').
3  
-
4  
--behaviour(supervisor).
5  
--export([init/1]).
6  
-
7  
--export([start_link/0, start_child/3, restart_child/2, terminate_child/2]).
8  
-
9  
--define(mcache_client, mcache_client3).
10  
-
11  
-start_link() ->
12  
-    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
13  
-
14  
-init([]) ->
15  
-    error_logger:info_msg("[MCACHE_CLIENT_SUP] Started.~n"),
16  
-
17  
-    {ok, {{one_for_one, 10, 10}, []}}.
18  
-
19  
-start_child(Name, {Host, Port}, Num) ->
20  
-    lists:foreach(
21  
-        fun(I) ->
22  
-            Id = {mcache_client, {Name, Host, Port}, I},
23  
-			Spec = {Id,{?mcache_client,start_link,[{Host,Port}]},permanent,2000,worker,[?mcache_client]},
24  
-            case supervisor:start_child(?MODULE, Spec) of
25  
-				{ok, _} -> ok;
26  
-				{ok, _, _} -> ok;
27  
-				{error, {already_started,_}} ->
28  
-					supervisor:terminate_child(?MODULE, Id),
29  
-					supervisor:delete_child(?MODULE, Id),
30  
-					supervisor:start_child(?MODULE, Spec);
31  
-				{error, already_present} ->
32  
-					supervisor:delete_child(?MODULE, Id),
33  
-					supervisor:start_child(?MODULE, Spec);
34  
-				{error, _Error} ->
35  
-					erlang:error(_Error)
36  
-			end
37  
-        end,
38  
-        lists:seq(1, Num)).
39  
-
40  
-terminate_child(Name, {Host, Port}) ->
41  
-    F = fun({{mcache_client, {Name1, Host1, Port1}, _Index} = Id, _Child, _Type, _Modules}) when Name=:=Name1,Host=:=Host1,Port=:=Port1-> 
42  
-				supervisor:terminate_child(?MODULE, Id);
43  
-           (_) -> 
44  
-				ignore
45  
-        end,
46  
-    lists:foreach(F, supervisor:which_children(?MODULE)).
47  
-
48  
-restart_child(Name, {Host, Port}) ->
49  
-    F = fun({{mcache_client, {Name1, Host1, Port1}, _Index} = Id, _Child, _Type, _Modules}) when Name=:=Name1,Host=:=Host1,Port=:=Port1-> 
50  
-				supervisor:restart_child(?MODULE, Id);
51  
-           (_) -> 
52  
-				ignore
53  
-        end,
54  
-    lists:foreach(F, supervisor:which_children(?MODULE)).
168  lib/mcache/src/mcache_config.erl
... ...
@@ -1,168 +0,0 @@
1  
--module(mcache_config).
2  
--author('thijsterlouw@gmail.com').
3  
--author('echou327@gmail.com').
4  
-
5  
--behaviour(gen_server).
6  
-
7  
--export([start_link/1]).
8  
--export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
9  
-
10  
--export([update_expires/1,get_expires/0]).
11  
-
12  
--define(DEFAULT_EXPIRE_SECONDS, 300).		%5 minutes
13  
--define(DEFAULT_POOL, generic).
14  
-
15  
--record(state, {expires, initial_expires}).
16  
-
17  
-%%%=========================================================================
18  
-%%%  Start the config
19  
-%%%=========================================================================
20  
-
21  
-start_link(Opts) ->
22  
-    	gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []).
23  
-
24  
-init({Pools, Expires}=Opts) ->
25  
-	io:format("[MCACHE_CONFIG] init~n", []),
26  
-	process_flag(trap_exit, true),
27  
-	
28  
-	parse_expires(Expires),
29  
-	parse_pools(Pools),
30  
-	{ok, #state{expires=Expires, initial_expires=Expires}}.
31  
-
32  
-
33  
-handle_call({update_expires, Info}, _From, #state{expires=OldExpires, initial_expires=InitialExpires}=State) ->
34  
-	NewExpires = case Info of
35  
-					restore ->		
36  
-						% restore to initial config
37  
-						InitialExpires;
38  
-					{assign, Expires} -> 
39  
-						% set a new set of config
40  
-						Expires;
41  
-					{delete, Class} ->
42  
-						proplists:delete(Class, OldExpires);
43  
-					{set, Class, {PoolName, Expiry}} -> 
44  
-						Expires1 = proplists:delete(Class, OldExpires),
45  
-						[{Class, {PoolName, Expiry}}|Expires1];
46  
-					_ ->
47  
-						not_modified
48  
-				end,
49  
-	if NewExpires =:= not_modified ->
50  
-		{reply, ok, State};
51  
-	true ->
52  
-		case (catch parse_expires(NewExpires)) of
53  
-			{'EXIT', Reason} ->
54  
-				{reply, {error, Reason}, State};
55  
-			_ ->
56  
-				{reply, ok, #state{expires=NewExpires}}
57  
-		end
58  
-	end;
59  
-
60  
-handle_call(get_expires, _From, #state{expires=Expires}=State) ->
61  
-    {reply, {ok, Expires}, State};
62  
-
63  
-handle_call(_Request, _From, State) ->
64  
-	{noreply, State}.
65  
-
66  
-%handle_call(_Request, _From, State) -> {reply, ok, State}.
67  
-handle_cast(_Request, State) -> 
68  
-	{noreply, State}.
69  
-
70  
-handle_info(_Info, State) -> 
71  
-	{noreply, State}.
72  
-
73  
-terminate(Reason, _State) ->
74  
-	io:format("[MCACHE_CONFIG] terminate() reason: ~p~n", [Reason]).
75  
-
76  
-code_change(_OldVsn, _Extra, State) ->
77  
-    io:format("blabla~n",[]),
78  
-	State.
79  
-
80  
-
81  
-% API
82  
-update_expires(UpdateInfo) ->
83  
-	gen_server:call(?MODULE, {update_expires, UpdateInfo}).
84  
-
85  
-get_expires() ->
86  
-	gen_server:call(?MODULE, get_expires).
87  
-
88  
-
89  
-
90  
-% internal functions
91  
-
92  
-parse_expires(Expires) ->
93  
-	io:format("[MCACHE_CONFIG] Generating mcache_expires module ...~n", []),
94  
-
95  
-	Code =
96  
-[
97  
-"-module(mcache_expires).\n-author('echou327@gmail.com').\n-export([expire/1]).% DO NOT EDIT.\n\n",
98  
-[
99  
-io_lib:format("expire(~p) -> ~p;~n", [Class, {PoolName, Expire}]) || {Class, {PoolName, Expire}} <- Expires
100  
-],
101  
-io_lib:format("expire(_) -> ~p.~n", [{?DEFAULT_POOL, ?DEFAULT_EXPIRE_SECONDS}])
102  
-],
103  
-	Code1 = lists:flatten(Code),
104  
-	{M, B} = dynamic_compile:from_string(Code1),
105  
-    code:load_binary(M, "", B),
106  
-    Code1.
107  
-
108  
-parse_pools(Pools) ->
109  
-
110  
-    % generate mcache_continuum
111  
-    io:format("[MCACHE_CONFIG] Generating mcache_continuum module ...~n", []),
112  
-    Continuums = lists:map(
113  
-					fun(PoolConfig) ->
114  
-						Name = proplists:get_value(name, PoolConfig, generic),
115  
-						Servers = proplists:get_value(servers, PoolConfig, []),
116  
-                        Servers1 = [normalize_server(S) || S <- Servers],
117  
-						{Name, Servers1}
118  
-					end,
119  
-					Pools),
120  
-    {NewPools, _} = mcache_continuum_gen:gen(Continuums, gb_trees),
121  
-
122  
-    PoolsDict = lists:foldl(
123  
-                fun(PoolConfig, Acc) ->
124  
-                    Name = proplists:get_value(name, PoolConfig),
125  
-                    dict:store(Name, PoolConfig, Acc)
126  
-                end, dict:new(), Pools),
127  
-
128  
-    % start mcache_clients
129  
-    lists:foreach(
130  
-        fun({Name, Servers, _}) ->
131  
-            %io:format("[MCACHE_CONFIG] ~p ~p~n", [Name, Pools]),
132  
-            {ok, PoolConfig} = dict:find(Name, PoolsDict),
133  
-            ConnectionCount = proplists:get_value(connection_count, PoolConfig, 10),
134  
-            lists:foreach(
135  
-                fun({{A,B,C,D}=Host,Port}) ->
136  
-                    io:format("[MCACHE_CONFIG] Starting ~p mcache clients at [~p, ~p.~p.~p.~p:~p] ...~n", [ConnectionCount, Name, A,B,C,D,Port]),
137  
-                    mcache_client_sup:start_child(Name, {Host, Port}, ConnectionCount)
138  
-                end,
139  
-                Servers)
140  
-        end,
141  
-        NewPools).
142  
-
143  
-% now only allow "A.B.C.D:11211" style address
144  
-
145  
-%normalize_server({{_,_,_,_}=Addr, Port, Weight}) ->
146  
-%    {Addr, Port, Weight};
147  
-%normalize_server({Addr, Port, Weight}) when is_list(Addr) ->
148  
-%    {Addr1, _} = normalize_addr(Addr),
149  
-%    {Addr1, Port, Weight};
150  
-normalize_server({Addr, Weight}) when is_list(Addr), is_integer(Weight) ->
151  
-    {Addr1, Port1} = normalize_addr(Addr),
152  
-    {Addr1, Port1, Weight}.
153  
-
154  
-normalize_addr(Addr) when is_list(Addr) ->
155  
-    case string:tokens(Addr, ":") of
156  
-        [IP] ->
157  
-            {ok, Addr1} = inet:getaddr(IP, inet),
158  
-            {Addr1, 11211};
159  
-        [IP,PortStr|_] ->
160  
-            {ok, Addr1} = inet:getaddr(IP, inet),
161  
-            Port1 = case string:to_integer(PortStr) of
162  
-                        {Port, []} -> Port;
163  
-                        _ -> 11211
164  
-                    end,
165  
-            {Addr1, Port1};
166  
-        _ ->
167  
-            {{127,0,0,1}, 11211}
168  
-    end.
274  lib/mcache/src/mcache_continuum_gen.erl
... ...
@@ -1,274 +0,0 @@
1  
--module(mcache_continuum_gen).
2  
-
3  
--author('echou327@gmail.com').
4  
-
5  
--export([gen/2]).
6  
-
7  
--define(HAVE_CASE_WHEN, 1).
8  
-%-define(HAVE_FUNC_MATCH, 1).
9  
-%-define(HAVE_BINARY_SEARCH, 1).
10  
-%-define(HAVE_GB_TREES, 1).
11  
-
12  
-% API exports
13  
--define(UINT32_LITTLE, 32/unsigned-little-integer).
14  
--define(POINTS_PER_SERVER, 160).
15  
--define(DEFAULT_PORT, 11211).
16  
-
17  
--define(HEADER,
18  
-"-module(mcache_continuum).
19  
--author('echou327@gmail.com').
20  
--compile(inline).
21  
--export([find/2]).
22  
-
23  
-% auto-generated code. DO NOT EDIT.
24  
-
25  
-").
26  
-
27  
-
28  
-gen(Pools, Mode) ->
29  
-    Continuums = lists:map(
30  
-                    fun({Name, Servers}) ->
31  
-                        {S, C} = make(Servers),
32  
-                        {Name, S, C}
33  
-                    end,
34  
-                    Pools),
35  
-    %io:format("~p~n", [Continuums]),
36  
-    Code = codegen(Mode, Continuums),
37  
-    {Continuums, compile(Code)}.
38  
-
39  
-% make continuum
40  
-
41  
-my_floor(X) ->
42  
-    T = erlang:trunc(X),
43  
-    case (X - T) of
44  
-        Neg when Neg < 0 -> T - 1;
45  
-        Pos when Pos > 0 -> T;
46  
-        _ -> T
47  
-    end.
48  
-
49  
-my_ceiling(X) ->
50  
-    T = erlang:trunc(X),
51  
-    case (X - T) of
52  
-        Neg when Neg < 0 -> T;
53  
-        Pos when Pos > 0 -> T + 1;
54  
-        _ -> T
55  
-    end.
56  
-
57  
-points_per_server(Weight, TotalWeight, NumberOfServers) -> 
58  
-    Pct = Weight / TotalWeight,
59  
-    my_floor(Pct * ?POINTS_PER_SERVER/ 4 * NumberOfServers + 0.0000000001) * 4.
60  
-
61  
-calc_total_weight([{_IP,_Port,Weight}|R], W) ->
62  
-    calc_total_weight(R, Weight+W);
63  
-calc_total_weight([], W) ->
64  
-    W.
65  
-
66  
-standardize_server_list({IP,Ports}) when is_list(Ports) ->
67  
-	[standardize_server_list({IP, Port})||Port <- Ports];
68  
-standardize_server_list({IP,Port,Weight}) ->
69  
-    [{IP,Port,Weight}];
70  
-standardize_server_list({IP,{Port,Weight}}) ->
71  
-    [{IP,Port,Weight}];
72  
-standardize_server_list({IP,Port}) ->
73  
-    [{IP,Port,100}].
74  
-
75  
-server_key({A,B,C,D}, ?DEFAULT_PORT, Index) ->
76  
-	io_lib:format("~p.~p.~p.~p-~p", [A,B,C,D,Index-1]);
77  
-server_key({A,B,C,D}, Port, Index) ->
78  
-	io_lib:format("~p.~p.~p.~p:~p-~p", [A,B,C,D,Port,Index-1]).
79  
-
80  
-ketama_server_hash(Key) ->
81  
-    <<Int1 : ?UINT32_LITTLE,  Int2 : ?UINT32_LITTLE, Int3 : ?UINT32_LITTLE, Int4 : ?UINT32_LITTLE>> = erlang:md5(Key),
82  
-    [Int1, Int2, Int3, Int4].
83  
-
84  
-% API
85  
-make(Servers) ->
86  
-    Servers1 = lists:flatmap(fun standardize_server_list/1, Servers),
87  
-    TotalWeight = calc_total_weight(Servers1, 0),
88  
-	make(Servers1, TotalWeight).
89  
-
90  
-make([], _TotalWeight) ->
91  
-	throw(no_servers);
92  
-make(Servers, TotalWeight) ->
93  
-    PointsPerHash = 4,
94  
-	NumberOfServers = length(Servers),
95  
-    {_, Continuum, ServersRev} = lists:foldl(
96  
-						fun({IP,Port,Weight}, {ServerIndex, ContinuumAcc, ServerAcc}) ->
97  
-							Points = points_per_server(Weight, TotalWeight, NumberOfServers),
98  
-							N = my_ceiling(Points/PointsPerHash),
99  
-							R = lists:flatmap(
100  
-									fun(Index) ->
101  
-										Key = server_key(IP,Port,Index),
102  
-										[{Int,ServerIndex}||Int <- ketama_server_hash(Key)]
103  
-									end,
104  
-									lists:seq(1,N)),
105  
-							{ServerIndex+1, R ++ ContinuumAcc, [{IP,Port}|ServerAcc] }
106  
-						end, 
107  
-                        {1, [], []},
108  
-						Servers),
109  
-    {lists:reverse(ServersRev), lists:keysort(1, Continuum)}.
110  
-
111  
-
112  
-func_match_clause({-1, Index}) ->
113  
-    io_lib:format("find_1(_H) ->~n    ~p.~n", [Index]);
114  
-func_match_clause({K, Index}) ->
115  
-    io_lib:format("find_1(H) when H<~p ->~n    ~p;~n", [K, Index]).
116  
-
117  
-% API
118  
-
119  
-codegen(case_when, Continuums) ->
120  
-
121  
-    ServersFunc = [ lists:map(
122  
-                        fun({PoolName, Servers, _Continuum}) ->
123  
-                            io_lib:format("servers(~p) -> ~p;~n", [PoolName, list_to_tuple(Servers)])
124  
-                        end,
125  
-                        Continuums),
126  
-                    "servers(_) -> erlang:error(not_implemented).\n\n"],
127  
-
128  
-    FindFunc = 
129  
-"find(PoolName, Hash) ->
130  
-    Index = find_1(PoolName, Hash),
131  
-    element(Index, servers(PoolName)).
132  
-
133  
-",
134  
-    
135  
-    Find1Func = lists:map(
136  
-                    fun({PoolName, _Servers, [{_,SmallestIndex}|_]=Continuum}) ->
137  
-                        [
138  
-io_lib:format("find_1(~p, H) ->~n",[PoolName]),    
139  
-io_lib:format("    case H of~n",[]),
140  
-[
141  
-io_lib:format("        H when H<~p -> ~p;~n",[K,I]) || {K,I} <-Continuum
142  
-],
143  
-io_lib:format("        _ -> ~p~n",[SmallestIndex]),
144  
-io_lib:format("    end;~n",[])
145  
-                        ]
146  
-                    end,
147  
-                    Continuums),
148  
-                    
149  
-    lists:flatten([?HEADER, ServersFunc, FindFunc, Find1Func, "find_1(_,_) -> erlang:error(not_implemented).\n"]);
150  
-
151  
-codegen(func_match, {Servers, Continuum}) ->
152  
-
153  
-    [{_,SmallestIndex}|_] = Continuum,
154  
-    Clauses = [func_match_clause(X) || X<-Continuum],
155  
-    TermClause = func_match_clause({-1, SmallestIndex}),
156  
-    
157  
-    Func = io_lib:format(
158  
-"-define(SERVERS, ~p).
159  
-
160  
-find(H) ->
161  
-    Index = find_1(H),
162  
-    element(Index, ?SERVERS).
163  
-
164  
-", [list_to_tuple(Servers)]),
165  
-
166  
-    lists:flatten([?HEADER, Func, Clauses, TermClause]);
167  
-
168  
-codegen(binary_search, {Servers, Continuum}) ->
169  
-	ContinuumSize = length(Continuum),
170  
-	ServersTuple = list_to_tuple(Servers),
171  
-	ContinuumTuple = list_to_tuple(Continuum),
172  
-
173  
-	Func = io_lib:format(
174  
-"-define(CONTINUUM_SIZE, ~p).
175  
-continuum() ->
176  
-    ~p.
177  
-servers() ->
178  
-    ~p.
179  
-
180  
-find(Hash) ->
181  
-	Index = find_server_index(Hash, 0, ?CONTINUUM_SIZE),
182  
-    Item = element(Index+1, continuum()),
183  
-    ServerIndex = element(2, Item),
184  
-    element(ServerIndex, servers()).
185  
-
186  
-% binary search
187  
-find_server_index(Hash, LowP, HighP) ->
188  
-    MidP = round((LowP + HighP)/2),
189  
-    MaxP = ?CONTINUUM_SIZE,
190  
-    if MidP =:= MaxP; LowP > HighP ->
191  
-        0;
192  
-    true ->
193  
-        MidVal = continuum_val(MidP),
194  
-        MidVal1 = continuum_val(MidP-1),
195  
-        if Hash =< MidVal1 ->
196  
-            find_server_index(Hash, LowP, MidP-1);
197  
-        Hash > MidVal ->
198  
-            find_server_index(Hash, MidP+1, HighP);
199  
-        true ->
200  
-            MidP
201  
-        end
202  
-    end.
203  
-
204  
-continuum_val(Index) when Index<0 ->
205  
-	0;
206  
-continuum_val(Index) ->
207  
-    Item = element(Index+1, continuum()),
208  
-    element(1, Item).
209  
-
210  
-", [ContinuumSize, ContinuumTuple, ServersTuple]),
211  
-