<HTML>
<HEAD>
<TITLE>Re: binary wire protocol in memcached</TITLE>
</HEAD>
<BODY>
<FONT FACE="Verdana, Helvetica, Arial"><SPAN STYLE='font-size:12.0px'>Hi,<BR>
<BR>
We have a working binary wire protocol implementation (client and server) though it does not reflect the changes that occurred at the last hackathon (at Sun). &nbsp;Some key differences:<BR>
<BR>
1) The magic byte is different, and also unique to request and response. &nbsp;We also maintain a notion of binary protocol versions for possible future (albeit limited) expansion.<BR>
<BR>
</SPAN></FONT><FONT SIZE="2"><FONT FACE="Courier New"><SPAN STYLE='font-size:10.0px'>// version number and magic byte.<BR>
#define BP_VERSION &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0x0<BR>
#define BP_REQ_MAGIC_BYTE &nbsp;(0x50 | BP_VERSION)<BR>
#define BP_REP_MAGIC_BYTE &nbsp;(0xA0 | BP_VERSION)<BR>
</SPAN></FONT></FONT><FONT FACE="Verdana, Helvetica, Arial"><SPAN STYLE='font-size:12.0px'><BR>
2) We specified the command IDs a bit differently, grouping them by request/response type.<BR>
<BR>
</SPAN></FONT><FONT SIZE="2"><FONT FACE="Courier New"><SPAN STYLE='font-size:10.0px'>#define BIT(x) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(1ULL &lt;&lt; (x))<BR>
#define FIELD(val, shift) &nbsp;((val) &lt;&lt; (shift))<BR>
<BR>
#define BP_E_E &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x0, 4)<BR>
#define BP_E_S &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x1, 4)<BR>
#define BP_K_V &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x2, 4)<BR>
#define BP_KV_E &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x3, 4)<BR>
#define BP_KN_E &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x4, 4)<BR>
#define BP_KN_N &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x5, 4)<BR>
#define BP_N_E &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x6, 4)<BR>
#define BP_S_E &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x7, 4)<BR>
#define BP_S_S &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIELD(0x8, 4)<BR>
<BR>
#define BP_QUIET &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BIT(3)<BR>
<BR>
typedef enum bp_cmd {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as an empty_req and return as an empty_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_ECHO_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_E_E | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_QUIT_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_E_E | FIELD(0x1, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as an empty_req and return as a string_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_VER_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_E_S | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_SERVERERR_CMD &nbsp;&nbsp;= (BP_E_S | FIELD(0x1, 0)), // this is actually not a<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// command. &nbsp;this is solely<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// used as a response when<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// the server wants to<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// indicate an error status.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a key_req and return as a value_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_GET_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_K_V | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_GETQ_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_K_V | BP_QUIET | FIELD(0x0, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a key_value_req and return as an empty_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_SET_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_ADD_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | FIELD(0x1, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_REPLACE_CMD &nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | FIELD(0x2, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_APPEND_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | FIELD(0x3, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_SETQ_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | BP_QUIET | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_ADDQ_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | BP_QUIET | FIELD(0x1, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_REPLACEQ_CMD &nbsp;&nbsp;&nbsp;= (BP_KV_E | BP_QUIET | FIELD(0x2, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_APPENDQ_CMD &nbsp;&nbsp;&nbsp;&nbsp;= (BP_KV_E | BP_QUIET | FIELD(0x3, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a key_number_req and return as an empty_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_DELETE_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KN_E | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_DELETEQ_CMD &nbsp;&nbsp;&nbsp;&nbsp;= (BP_KN_E | BP_QUIET | FIELD(0x0, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a key_number_req and return as a number_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_INCR_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KN_N | FIELD(0x0, 0)),<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_DECR_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_KN_N | FIELD(0x1, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a number_req and return as an empty_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_FLUSH_ALL_CMD &nbsp;&nbsp;= (BP_N_E | FIELD(0x0, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a string_req and return as an empty_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_FLUSH_REGEX_CMD = (BP_S_E | FIELD(0x0, 0)),<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// these commands go as a string_req and return as a string_rep.<BR>
&nbsp;&nbsp;&nbsp;&nbsp;BP_STATS_CMD &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= (BP_S_S | FIELD(0x0, 0)),<BR>
} bp_cmd_t;<BR>
</SPAN></FONT></FONT><FONT FACE="Verdana, Helvetica, Arial"><SPAN STYLE='font-size:12.0px'><BR>
3) We have no support for 64-bit arithmetic commands. &nbsp;We have retained decr (so far).<BR>
<BR>
4) The return value for arithmetic commands is binary and not a string. &nbsp;I wasn&#8217;t at the hackathon during which this was decided so I&#8217;d be interested in finding out why a string is preferable.<BR>
<BR>
Thanks,<BR>
Tony<BR>
<BR>
On 8/27/07 8:39 PM, &quot;Dustin Sallings&quot; &lt;dustin@spy.net&gt; wrote:<BR>
<BR>
</SPAN></FONT><BLOCKQUOTE><FONT FACE="Verdana, Helvetica, Arial"><SPAN STYLE='font-size:12.0px'><BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I just got memcached passing all of my tests with the binary wire <BR>
protocol (tcp). &nbsp;Sorry it took me so long to get going on it.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I've implemented this as a patch stack (using mercurial queues) over <BR>
trunk r608 with Evan Miller's 64-bit counter patch applied (since <BR>
everyone is excited by big numbers). &nbsp;I've got no idea where (if <BR>
anywhere) active development is going on. &nbsp;I can pick it up and move <BR>
it needed.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I don't know what clients are ready. &nbsp;I haven't done a release of my <BR>
java client with binary protocol support yet, but I can roll out a <BR>
pre-release if someone wants to try it (all of my interop tests pass <BR>
between my java client and memcached in binary mode, so I just need <BR>
to clean it up a bit). &nbsp;My test python client is functional for at <BR>
least interactive use as well.<BR>
<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Known issues:<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I didn't implement a timeout on delete. &nbsp;I suppose I should, but do <BR>
people actually use that?<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I didn't implement a timeout on flush. &nbsp;I'd rather avoid that one if <BR>
possible because the semantics are really confusing.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I basically ignored managed buckets because I have no idea how they <BR>
work.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;My 64-bit ntohl kind of thing might not work on big endian machines <BR>
(I haven't tried it yet). &nbsp;Moreover, I would hope something like that <BR>
would already exist somewhere, so I didn't bother making it fast.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I've only implemented version, flush, noop, set, add, replace, get, <BR>
getq, delete, and incr. &nbsp;Besides stats (for which we have no clearly <BR>
defined packet format), there seem to be other commands in there that <BR>
don't make much sense to me.<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;There may be more, but I don't know about them yet.<BR>
<BR>
--<BR>
Dustin Sallings<BR>
<BR>
<BR>
<BR>
</SPAN></FONT></BLOCKQUOTE><FONT FACE="Verdana, Helvetica, Arial"><SPAN STYLE='font-size:12.0px'><BR>
</SPAN></FONT>
</BODY>
</HTML>