3535
3636% %% Start/stop functions
3737-export ([connect /3 ,
38- controlling_process /2 ,
39- transaction /3 ,
40- close /2 ]).
38+ controlling_process /2 ,
39+ transaction /3 ,
40+ close /2 ]).
4141
4242
4343-record (client , {socket , pool , event_callback :: module ()}).
4444
4545-define (SOCKET_OPTIONS , [binary ,
46- {packet , raw },
47- {active , false },
48- {reuseaddr , true },
49- {nodelay , true }]).
46+ {packet , raw },
47+ {active , false },
48+ {reuseaddr , true },
49+ {nodelay , true }]).
5050
5151% %%=============================================================================
5252% %% External functions
@@ -75,9 +75,9 @@ controlling_process(Client, Pid) ->
7575
7676transaction (Client , delete , [Key , TimeLimit ]) ->
7777 case send_receive (Client , {? MEMCACHE_DELETE , {Key }}, TimeLimit ) of
78- {ok , { <<>>, <<>>}} ->
78+ {ok , # mero_item { key = <<>>, value = <<>>}} ->
7979 {Client , ok };
80- {ok , { <<>>, undefined }} ->
80+ {ok , # mero_item { key = <<>>, value = undefined }} ->
8181 {Client , {error , not_found }};
8282 {ok , {error , Reason }} ->
8383 {Client , {error , Reason }};
@@ -92,15 +92,18 @@ transaction(Client, increment_counter, [Key, Value, Initial, ExpTime, TimeLimit]
9292 {error , Reason };
9393 {ok , {error , Reason }} ->
9494 {Client , {error , Reason }};
95- {ok , { <<>>, ActualValue }} ->
95+ {ok , # mero_item { key = <<>>, value = ActualValue }} ->
9696 {Client , {ok , to_integer (ActualValue )}}
9797 end ;
9898
9999
100- transaction (Client , set , [Key , Value , ExpTime , TimeLimit ]) ->
101- case send_receive (Client , {? MEMCACHE_SET , {Key , Value , ExpTime }}, TimeLimit ) of
102- {ok , { <<>>, <<>>}} ->
100+ transaction (Client , set , [Key , Value , ExpTime , TimeLimit , CAS ]) ->
101+ case send_receive (Client , {? MEMCACHE_SET , {Key , Value , ExpTime , CAS }}, TimeLimit ) of
102+ {ok , # mero_item { key = <<>>, value = <<>>}} ->
103103 {Client , ok };
104+ {ok , # mero_item {key = <<>>, value = undefined }} when CAS /= undefined ->
105+ % % attempt to set a key using CAS, but key wasn't present.
106+ {Client , {error , not_found }};
104107 {ok , {error , Reason }} ->
105108 {Client , {error , Reason }};
106109 {error , Reason } ->
@@ -109,7 +112,7 @@ transaction(Client, set, [Key, Value, ExpTime, TimeLimit]) ->
109112
110113transaction (Client , add , [Key , Value , ExpTime , TimeLimit ]) ->
111114 case send_receive (Client , {? MEMCACHE_ADD , {Key , Value , ExpTime }}, TimeLimit ) of
112- {ok , { <<>>, <<>>}} ->
115+ {ok , # mero_item { key = <<>>, value = <<>>}} ->
113116 {Client , ok };
114117 {ok , {error , Reason }} ->
115118 {Client , {error , Reason }};
@@ -119,7 +122,7 @@ transaction(Client, add, [Key, Value, ExpTime, TimeLimit]) ->
119122
120123transaction (Client , flush_all , [TimeLimit ]) ->
121124 case send_receive (Client , {? MEMCACHE_FLUSH_ALL , {}}, TimeLimit ) of
122- {ok , { <<>>, <<>>}} ->
125+ {ok , # mero_item { key = <<>>, value = <<>>}} ->
123126 {Client , ok };
124127 {ok , {error , Reason }} ->
125128 {Client , {error , Reason }};
@@ -219,9 +222,9 @@ pack({?MEMCACHE_ADD, {Key, Value, ExpTime}}) ->
219222 IntExpTime = value_to_integer (ExpTime ),
220223 pack (<<16#DEADBEEF :32 , IntExpTime :32 >>, ? MEMCACHE_ADD , Key , Value );
221224
222- pack ({? MEMCACHE_SET , {Key , Value , ExpTime }}) ->
225+ pack ({? MEMCACHE_SET , {Key , Value , ExpTime , CAS }}) ->
223226 IntExpTime = value_to_integer (ExpTime ),
224- pack (<<16#DEADBEEF :32 , IntExpTime :32 >>, ? MEMCACHE_SET , Key , Value );
227+ pack (<<16#DEADBEEF :32 , IntExpTime :32 >>, ? MEMCACHE_SET , Key , Value , CAS );
225228
226229pack ({? MEMCACHE_FLUSH_ALL , {}}) ->
227230 % % Flush inmediately by default
@@ -239,13 +242,28 @@ pack(Extras, Operator, Key) ->
239242 pack (Extras , Operator , Key , <<>>).
240243
241244pack (Extras , Operator , Key , Value ) ->
245+ pack (Extras , Operator , Key , Value , undefined ).
246+
247+ pack (Extras , Operator , Key , Value , undefined ) ->
248+ pack (Extras , Operator , Key , Value , 16#00 );
249+
250+ pack (Extras , Operator , Key , Value , CAS ) ->
242251 KeySize = size (Key ),
243252 ExtrasSize = size (Extras ),
244253 Body = <<Extras :ExtrasSize /binary , Key /binary , Value /binary >>,
245254 BodySize = size (Body ),
246- <<16#80 :8 , Operator :8 , KeySize :16 ,
247- ExtrasSize :8 , 16#00 :8 , 16#00 :16 ,
248- BodySize :32 , 16#00 :32 , 16#00 :64 , Body :BodySize /binary >>.
255+ <<
256+ 16#80 :8 , % magic (0)
257+ Operator :8 , % opcode (1)
258+ KeySize :16 , % key length (2,3)
259+ ExtrasSize :8 , % extra length (4)
260+ 16#00 :8 , % data type (5)
261+ 16#00 :16 , % reserved (6,7)
262+ BodySize :32 , % total body (8-11)
263+ 16#00 :32 , % opaque (12-15)
264+ CAS :64 , % CAS (16-23)
265+ Body :BodySize /binary
266+ >>.
249267
250268
251269send (Client , Data ) ->
@@ -258,17 +276,34 @@ send(Client, Data) ->
258276 end .
259277
260278
279+ cas_value (16#00 ) ->
280+ undefined ;
281+ cas_value (undefined ) ->
282+ 16#00 ;
283+ cas_value (Value ) when is_integer (Value ) andalso Value > 0 ->
284+ Value .
285+
286+
261287receive_response (Client , Op , TimeLimit ) ->
262288 case recv_bytes (Client , 24 , TimeLimit ) of
263- <<16#81 :8 , Op :8 , KeySize :16 , ExtrasSize :8 , _DT :8 , Status :16 ,
264- BodySize :32 , _Opq :32 , _CAS :64 >> ->
289+ <<
290+ 16#81 :8 , % magic (0)
291+ Op :8 , % opcode (1)
292+ KeySize :16 , % key length (2,3)
293+ ExtrasSize :8 , % extra length (4)
294+ _DT :8 , % data type (5)
295+ Status :16 , % status (6,7)
296+ BodySize :32 , % total body (8-11)
297+ _Opq :32 , % opaque (12-15)
298+ CAS :64 % CAS (16-23)
299+ >> ->
265300 case recv_bytes (Client , BodySize , TimeLimit ) of
266301 <<_Extras :ExtrasSize /binary , Key :KeySize /binary , Value /binary >> ->
267302 case Status of
268303 16#0001 ->
269- { Key , undefined };
304+ # mero_item { key = Key , cas = cas_value ( CAS ) };
270305 16#0000 ->
271- { Key , Value };
306+ # mero_item { key = Key , value = Value , cas = cas_value ( CAS ) };
272307 16#0002 ->
273308 {error , already_exists };
274309 16#0003 ->
@@ -362,12 +397,22 @@ async_response(Client, Keys, TimeLimit) ->
362397
363398receive_response (Client , TimeLimit , Keys , Acc ) ->
364399 case recv_bytes (Client , 24 , TimeLimit ) of
365- <<16#81 :8 , Op :8 , KeySize :16 , ExtrasSize :8 , _DT :8 , Status :16 ,
366- BodySize :32 , _Opq :32 , _CAS :64 >> = Data ->
400+ <<
401+ 16#81 :8 , % magic (0)
402+ Op :8 , % opcode (1)
403+ KeySize :16 , % key length (2,3)
404+ ExtrasSize :8 , % extra length (4)
405+ _DT :8 , % data type (5)
406+ Status :16 , % status (6,7)
407+ BodySize :32 , % total body (8-11)
408+ _Opq :32 , % opaque (12-15)
409+ CAS :64 % CAS (16-23)
410+ >> = Data ->
367411 case recv_bytes (Client , BodySize , TimeLimit ) of
368412 <<_Extras :ExtrasSize /binary , Key :KeySize /binary , ValueReceived /binary >> ->
369413 {Key , Value } = filter_by_status (Status , Op , Key , ValueReceived ),
370- Responses = [{Key , Value } | Acc ],
414+ Responses = [# mero_item {key = Key , value = Value , cas = cas_value (CAS )}
415+ | Acc ],
371416 NKeys = lists :delete (Key , Keys ),
372417 case Op of
373418 % % elasticache does not return the correct Op for
0 commit comments