_site/cover/mcd_protocol_binary.COVER.html

1 %% Copyright (c) 2022 Peter Morgan <peter.james.morgan@gmail.com>
2 %%
3 %% Licensed under the Apache License, Version 2.0 (the "License");
4 %% you may not use this file except in compliance with the License.
5 %% You may obtain a copy of the License at
6 %%
7 %% http://www.apache.org/licenses/LICENSE-2.0
8 %%
9 %% Unless required by applicable law or agreed to in writing, software
10 %% distributed under the License is distributed on an "AS IS" BASIS,
11 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 %% See the License for the specific language governing permissions and
13 %% limitations under the License.
14
15
16 -module(mcd_protocol_binary).
17
18
19 -export([decode/1]).
20 -export([encode/1]).
21 -include("mcd.hrl").
22
23
24 decode(<<?RESPONSE:8,
25 Opcode:8,
26 KeyLength:16,
27 ExtraLength:8,
28 ?RAW:8,
29 Status:16,
30 TotalBodyLength:32,
31 Opaque:32,
32 CAS:64,
33 Body:TotalBodyLength/bytes,
34 Remainder/bytes>>) ->
35
36 24 <<Extra:ExtraLength/bytes,
37 Key:KeyLength/bytes,
38 Value/bytes>> = Body,
39
40 24 {decode_binary(
41 #{magic => response,
42 opcode => mcd_opcode:lookup(Opcode),
43 data_type => raw,
44 status => mcd_status:lookup(Status),
45 opaque => Opaque,
46 cas => CAS},
47 Extra,
48 Key,
49 Value),
50 Remainder};
51
52 decode(<<?REQUEST:8,
53 Opcode:8,
54 KeyLength:16,
55 ExtraLength:8,
56 ?RAW:8,
57 VBucketId:16,
58 TotalBodyLength:32,
59 Opaque:32,
60 CAS:64,
61 Body:TotalBodyLength/bytes,
62 Remainder/bytes>>) ->
63
64 35 <<Extra:ExtraLength/bytes, Key:KeyLength/bytes, Value/bytes>> = Body,
65
66 35 {decode_binary(
67 #{magic => request,
68 opcode => mcd_opcode:lookup(Opcode),
69 data_type => raw,
70 vbucket_id => VBucketId,
71 opaque => Opaque,
72 cas => CAS},
73 Extra,
74 Key,
75 Value),
76 Remainder}.
77
78
79
80
81 %%
82 %% get, getq, getk, getkq
83 %%
84 decode_binary(#{magic := request, opcode := Opcode} = Header,
85 <<>>,
86 Key,
87 <<>>)
88 when Opcode == get;
89 Opcode == getq;
90 Opcode == getk;
91 Opcode == getkq ->
92 8 #{header => Header, key => Key};
93
94 decode_binary(#{magic := response,
95 opcode := Opcode,
96 status := key_not_found} = Header,
97 <<>>,
98 <<>>,
99 <<>>)
100 when Opcode == get;
101 Opcode == getq;
102 Opcode == getk;
103 Opcode == getkq ->
104 3 #{header => Header};
105
106 decode_binary(#{magic := response,
107 opcode := Opcode} = Header,
108 <<Flags:32>>,
109 <<>>,
110 <<>>)
111 when Opcode == get;
112 Opcode == getq;
113 Opcode == getk;
114 Opcode == getkq ->
115
:-(
#{header => Header, extra => #{flags => Flags}};
116
117 decode_binary(#{magic := response,
118 opcode := Opcode} = Header,
119 <<Flags:32>>,
120 <<>>,
121 Value)
122 when Opcode == get;
123 Opcode == getq;
124 Opcode == getk;
125 Opcode == getkq ->
126 4 #{header => Header,
127 extra => #{flags => Flags},
128 value => Value};
129
130 decode_binary(#{magic := response,
131 opcode := Opcode} = Header,
132 <<Flags:32>>,
133 Key,
134 <<>>)
135 when Opcode == get;
136 Opcode == getq;
137 Opcode == getk;
138 Opcode == getkq ->
139
:-(
#{header => Header,
140 extra => #{flags => Flags},
141 key => Key};
142
143 decode_binary(#{magic := response,
144 opcode := Opcode} = Header,
145 <<Flags:32>>,
146 Key,
147 Value)
148 when Opcode == get;
149 Opcode == getq;
150 Opcode == getk;
151 Opcode == getkq ->
152 1 #{header => Header,
153 extra => #{flags => Flags},
154 key => Key,
155 value => Value};
156
157 %%
158 %% set, add, replace
159 %%
160 decode_binary(#{magic := request,
161 opcode := Opcode} = Header,
162 <<Flags:32, Expiration:32>>,
163 Key,
164 Value)
165 when Opcode == set;
166 Opcode == add;
167 Opcode == replace ->
168 6 #{header => Header,
169 extra => #{flags => Flags, expiration => Expiration},
170 key => Key,
171 value => Value};
172
173 decode_binary(#{magic := response,
174 opcode := Opcode} = Header,
175 <<>>,
176 <<>>,
177 <<>>)
178 when Opcode == set;
179 Opcode == add;
180 Opcode == replace ->
181 5 #{header => Header};
182
183 %%
184 %% delete
185 %%
186
187 decode_binary(#{magic := request,
188 opcode := delete} = Header,
189 <<>>,
190 Key,
191 <<>>)
192 when Key /= <<>> ->
193 4 #{header => Header, key => Key};
194
195 decode_binary(#{magic := response,
196 opcode := delete} = Header,
197 <<>>,
198 <<>>,
199 <<>>) ->
200 2 #{header => Header};
201
202
203 %%
204 %% increment, decrement
205 %%
206
207
208 decode_binary(#{magic := request,
209 opcode := Opcode} = Header,
210 <<Delta:64, Initial:64, Expiration:32>>,
211 Key,
212 <<>>)
213 when Opcode == increment;
214 Opcode == decrement ->
215 2 #{header => Header,
216 extra => #{delta => Delta,
217 initial => Initial,
218 expiration => Expiration},
219 key => Key};
220
221 decode_binary(#{magic := response,
222 opcode := Opcode} = Header,
223 <<>>,
224 <<>>,
225 Value)
226 when Opcode == increment;
227 Opcode == decrement ->
228 1 #{header => Header, value => Value};
229
230
231 %% quit
232
233 decode_binary(#{magic := request,
234 opcode := quit} = Header,
235 <<>>,
236 <<>>,
237 <<>>) ->
238 2 #{header => Header};
239
240 decode_binary(#{magic := response,
241 opcode := quit} = Header,
242 <<>>,
243 <<>>,
244 <<>>) ->
245
:-(
#{header => Header};
246
247
248 %% flush
249
250
251 decode_binary(#{magic := request,
252 opcode := flush} = Header,
253 <<Expiration:32>>,
254 <<>>,
255 <<>>) ->
256 2 #{header => Header, extra => #{expiration => Expiration}};
257
258 decode_binary(#{opcode := flush} = Header, <<>>, <<>>, <<>>) ->
259 5 #{header => Header};
260
261 %% no op
262
263 decode_binary(#{opcode := no_op} = Header, <<>>, <<>>, <<>>) ->
264 5 #{header => Header};
265
266 %% version
267
268
269 decode_binary(#{magic := request,
270 opcode := version} = Header,
271 <<>>,
272 <<>>,
273 <<>>) ->
274 2 #{header => Header};
275
276 decode_binary(#{magic := response,
277 opcode := version} = Header,
278 <<>>,
279 <<>>,
280 Value) ->
281 1 #{header => Header, value => Value};
282
283
284 %% append, prepend
285
286
287 decode_binary(#{magic := request,
288 opcode := Opcode} = Header,
289 <<>>,
290 Key,
291 Value)
292 when Opcode == append;
293 Opcode == prepend ->
294 2 #{header => Header, key => Key, value => Value};
295
296 decode_binary(#{magic := response,
297 opcode := Opcode} = Header,
298 <<>>,
299 <<>>,
300 <<>>)
301 when Opcode == append;
302 Opcode == prepend ->
303
:-(
#{header => Header};
304
305
306 %% stat
307
308
309 decode_binary(#{magic := request,
310 opcode := stat} = Header,
311 <<>>,
312 <<>>,
313 <<>>) ->
314 2 #{header => Header};
315
316 decode_binary(#{magic := request,
317 opcode := stat} = Header,
318 <<>>,
319 Key,
320 <<>>) ->
321
:-(
#{header => Header, key => Key};
322
323 decode_binary(#{magic := response,
324 opcode := stat} = Header,
325 <<>>,
326 <<>>,
327 <<>>) ->
328 1 #{header => Header};
329
330 decode_binary(#{magic := response,
331 opcode := stat} = Header,
332 <<>>,
333 Key,
334 Value) ->
335 1 #{header => Header, key => Key, value => Value};
336
337
338 %%
339 %% verbosity
340 %%
341
342
343 decode_binary(#{magic := request, opcode := verbosity} = Header,
344 <<Verbosity:32>>,
345 <<>>,
346 <<>>) ->
347
:-(
#{header => Header, extra => #{verbosity => Verbosity}};
348
349 decode_binary(#{magic := response, opcode := verbosity} = Header,
350 <<>>,
351 <<>>,
352 <<>>) ->
353
:-(
#{header => Header};
354
355
356 %%
357 %% touch, gat and gatq
358 %%
359
360
361 decode_binary(#{magic := request, opcode := Opcode} = Header,
362 <<Expiration:32>>,
363 Key,
364 <<>>)
365 when Key /= <<>>,
366 Opcode == touch;
367 Opcode == gat;
368 Opcode == gatq ->
369
:-(
#{header => Header, extra => #{expiration => Expiration}}.
370
371
372 encode(#{header := #{magic := request, opcode := Opcode},
373 key := _} = Decoded)
374 when not(is_map_key(extra, Decoded)),
375 not(is_map_key(value, Decoded)),
376 Opcode == get;
377 Opcode == getq;
378 Opcode == getk;
379 Opcode == getkq ->
380 7 marshal(Decoded);
381
382 encode(#{header := #{magic := response,
383 status := key_not_found,
384 opcode := Opcode}} = Decoded)
385 when not(is_map_key(extra, Decoded)),
386 Opcode == get;
387 Opcode == getq;
388 Opcode == getk;
389 Opcode == getkq ->
390 3 marshal(Decoded);
391
392 encode(#{header := #{magic := response,
393 status := no_error,
394 opcode := Opcode},
395 extra := #{flags := Flags}} = Decoded)
396 when Opcode == get;
397 Opcode == getq;
398 Opcode == getk;
399 Opcode == getkq ->
400 5 marshal(Decoded#{extra := <<Flags:32>>});
401
402 encode(#{header := #{magic := request, opcode := Opcode},
403 key := _,
404 extra := #{flags := Flags, expiration := Expiration}} = Decoded)
405 when Opcode == set;
406 Opcode == add;
407 Opcode == replace ->
408 5 marshal(Decoded#{extra := <<Flags:32, Expiration:32>>});
409
410 encode(#{header := #{magic := response, opcode := Opcode}} = Decoded)
411 when not(is_map_key(extra, Decoded)),
412 not(is_map_key(key, Decoded)),
413 not(is_map_key(value, Decoded)),
414 Opcode == set;
415 Opcode == add;
416 Opcode == replace ->
417 5 marshal(Decoded);
418
419 encode(#{header := #{magic := request, opcode := Opcode},
420 key := _,
421 value := _} = Decoded)
422 when not(is_map_key(extra, Decoded)),
423 Opcode == append;
424 Opcode == prepend ->
425 1 marshal(Decoded);
426
427 encode(#{header := #{magic := response, opcode := Opcode}} = Decoded)
428 when not(is_map_key(extra, Decoded)),
429 not(is_map_key(key, Decoded)),
430 not(is_map_key(value, Decoded)),
431 Opcode == append;
432 Opcode == prepend ->
433
:-(
marshal(Decoded);
434
435 encode(#{header := #{magic := request, opcode := delete},
436 key := _} = Decoded)
437 when not(is_map_key(extra, Decoded)),
438 not(is_map_key(value, Decoded)) ->
439 3 marshal(Decoded);
440
441 encode(#{header := #{magic := response, opcode := delete}} = Decoded)
442 when not(is_map_key(extra, Decoded)),
443 not(is_map_key(key, Decoded)),
444 not(is_map_key(value, Decoded)) ->
445 2 marshal(Decoded);
446
447 encode(#{header := #{magic := request, opcode := flush},
448 extra := #{expiration := Expiration}} = Decoded)
449 when not(is_map_key(key, Decoded)),
450 not(is_map_key(value, Decoded)) ->
451 1 marshal(Decoded#{extra := <<Expiration:32>>});
452
453 encode(#{header := #{opcode := flush}} = Decoded)
454 when not(is_map_key(key, Decoded)),
455 not(is_map_key(value, Decoded)) ->
456 5 marshal(Decoded);
457
458 encode(#{header := #{opcode := no_op}} = Decoded)
459 when not(is_map_key(extra, Decoded)),
460 not(is_map_key(key, Decoded)),
461 not(is_map_key(value, Decoded)) ->
462 4 marshal(Decoded);
463
464 encode(#{header := #{opcode := quit}} = Decoded)
465 when not(is_map_key(extra, Decoded)),
466 not(is_map_key(key, Decoded)),
467 not(is_map_key(value, Decoded)) ->
468 1 marshal(Decoded);
469
470 encode(#{header := #{magic := request, opcode := version}} = Decoded)
471 when not(is_map_key(extra, Decoded)),
472 not(is_map_key(key, Decoded)),
473 not(is_map_key(value, Decoded)) ->
474 1 marshal(Decoded);
475
476 encode(#{header := #{magic := response, opcode := version},
477 value := _} = Decoded)
478 when not(is_map_key(extra, Decoded)),
479 not(is_map_key(key, Decoded)) ->
480 1 marshal(Decoded);
481
482 encode(#{header := #{magic := request, opcode := stat}} = Decoded)
483 when not(is_map_key(extra, Decoded)),
484 not(is_map_key(value, Decoded)) ->
485 1 marshal(Decoded);
486
487 encode(#{header := #{magic := response, opcode := stat}} = Decoded)
488 when not(is_map_key(extra, Decoded)) ->
489 2 marshal(Decoded);
490
491 encode(#{header := #{magic := request, opcode := Opcode},
492 key := _,
493 extra := #{delta := Delta,
494 initial := Initial,
495 expiration := Expiration}} = Decoded)
496 when not(is_map_key(value, Decoded)),
497 Opcode == increment;
498 Opcode == decrement ->
499 1 marshal(Decoded#{extra := <<Delta:64, Initial:64, Expiration:32>>});
500
501 encode(#{header := #{magic := response, opcode := Opcode},
502 value := _} = Decoded)
503 when not(is_map_key(extra, Decoded)),
504 not(is_map_key(key, Decoded)),
505 Opcode == increment;
506 Opcode == decrement ->
507 1 marshal(Decoded).
508
509
510 marshal(#{header := #{magic := request,
511 opcode := Opcode,
512 data_type := DataType,
513 vbucket_id := VBucketId,
514 opaque := Opaque,
515 cas := CAS}} = Decoded) ->
516 25 ?FUNCTION_NAME(
517 ?REQUEST,
518 mcd_opcode:lookup(Opcode),
519 DataType,
520 VBucketId,
521 Opaque,
522 CAS,
523 maps:without([header], Decoded));
524
525 marshal(#{header := #{magic := response,
526 opcode := Opcode,
527 data_type := DataType,
528 status := Status,
529 opaque := Opaque,
530 cas := CAS}} = Decoded) ->
531 24 ?FUNCTION_NAME(
532 ?RESPONSE,
533 mcd_opcode:lookup(Opcode),
534 DataType,
535 mcd_status:lookup(Status),
536 Opaque,
537 CAS,
538 maps:without([header], Decoded)).
539
540
541 marshal(Magic,
542 Opcode,
543 DataType,
544 BucketOrStatus,
545 Opaque,
546 CAS,
547 Decoded) ->
548 49 ?FUNCTION_NAME(Magic,
549 Opcode,
550 DataType,
551 BucketOrStatus,
552 Opaque,
553 CAS,
554 maps:get(extra, Decoded, <<>>),
555 maps:get(key, Decoded, <<>>),
556 maps:get(value, Decoded, <<>>)).
557
558
559 marshal(Magic,
560 Opcode,
561 raw,
562 BucketOrStatus,
563 Opaque,
564 CAS,
565 Extra,
566 Key,
567 Value) ->
568 49 [Magic,
569 Opcode,
570 <<(iolist_size(Key)):16>>,
571 iolist_size(Extra),
572 ?RAW,
573 <<BucketOrStatus:16,
574 (iolist_size(Extra) + iolist_size(Key) + iolist_size(Value)):32,
575 Opaque:32,
576 CAS:64>>,
577 Extra,
578 Key,
579 Value].
Line Hits Source