1// Package gomemcached is binary protocol packet formats and constants.
2package gomemcached
3
4import (
5	"fmt"
6)
7
8const (
9	REQ_MAGIC = 0x80
10	RES_MAGIC = 0x81
11)
12
13// CommandCode for memcached packets.
14type CommandCode uint8
15
16const (
17	GET        = CommandCode(0x00)
18	SET        = CommandCode(0x01)
19	ADD        = CommandCode(0x02)
20	REPLACE    = CommandCode(0x03)
21	DELETE     = CommandCode(0x04)
22	INCREMENT  = CommandCode(0x05)
23	DECREMENT  = CommandCode(0x06)
24	QUIT       = CommandCode(0x07)
25	FLUSH      = CommandCode(0x08)
26	GETQ       = CommandCode(0x09)
27	NOOP       = CommandCode(0x0a)
28	VERSION    = CommandCode(0x0b)
29	GETK       = CommandCode(0x0c)
30	GETKQ      = CommandCode(0x0d)
31	APPEND     = CommandCode(0x0e)
32	PREPEND    = CommandCode(0x0f)
33	STAT       = CommandCode(0x10)
34	SETQ       = CommandCode(0x11)
35	ADDQ       = CommandCode(0x12)
36	REPLACEQ   = CommandCode(0x13)
37	DELETEQ    = CommandCode(0x14)
38	INCREMENTQ = CommandCode(0x15)
39	DECREMENTQ = CommandCode(0x16)
40	QUITQ      = CommandCode(0x17)
41	FLUSHQ     = CommandCode(0x18)
42	APPENDQ    = CommandCode(0x19)
43	AUDIT      = CommandCode(0x27)
44	PREPENDQ   = CommandCode(0x1a)
45	GAT        = CommandCode(0x1d)
46	HELLO      = CommandCode(0x1f)
47	RGET       = CommandCode(0x30)
48	RSET       = CommandCode(0x31)
49	RSETQ      = CommandCode(0x32)
50	RAPPEND    = CommandCode(0x33)
51	RAPPENDQ   = CommandCode(0x34)
52	RPREPEND   = CommandCode(0x35)
53	RPREPENDQ  = CommandCode(0x36)
54	RDELETE    = CommandCode(0x37)
55	RDELETEQ   = CommandCode(0x38)
56	RINCR      = CommandCode(0x39)
57	RINCRQ     = CommandCode(0x3a)
58	RDECR      = CommandCode(0x3b)
59	RDECRQ     = CommandCode(0x3c)
60
61	SASL_LIST_MECHS = CommandCode(0x20)
62	SASL_AUTH       = CommandCode(0x21)
63	SASL_STEP       = CommandCode(0x22)
64
65	SET_VBUCKET = CommandCode(0x3d)
66
67	TAP_CONNECT          = CommandCode(0x40) // Client-sent request to initiate Tap feed
68	TAP_MUTATION         = CommandCode(0x41) // Notification of a SET/ADD/REPLACE/etc. on the server
69	TAP_DELETE           = CommandCode(0x42) // Notification of a DELETE on the server
70	TAP_FLUSH            = CommandCode(0x43) // Replicates a flush_all command
71	TAP_OPAQUE           = CommandCode(0x44) // Opaque control data from the engine
72	TAP_VBUCKET_SET      = CommandCode(0x45) // Sets state of vbucket in receiver (used in takeover)
73	TAP_CHECKPOINT_START = CommandCode(0x46) // Notifies start of new checkpoint
74	TAP_CHECKPOINT_END   = CommandCode(0x47) // Notifies end of checkpoint
75
76	UPR_OPEN        = CommandCode(0x50) // Open a UPR connection with a name
77	UPR_ADDSTREAM   = CommandCode(0x51) // Sent by ebucketMigrator to UPR Consumer
78	UPR_CLOSESTREAM = CommandCode(0x52) // Sent by eBucketMigrator to UPR Consumer
79	UPR_FAILOVERLOG = CommandCode(0x54) // Request failover logs
80	UPR_STREAMREQ   = CommandCode(0x53) // Stream request from consumer to producer
81	UPR_STREAMEND   = CommandCode(0x55) // Sent by producer when it has no more messages to stream
82	UPR_SNAPSHOT    = CommandCode(0x56) // Start of a new snapshot
83	UPR_MUTATION    = CommandCode(0x57) // Key mutation
84	UPR_DELETION    = CommandCode(0x58) // Key deletion
85	UPR_EXPIRATION  = CommandCode(0x59) // Key expiration
86	UPR_FLUSH       = CommandCode(0x5a) // Delete all the data for a vbucket
87	UPR_NOOP        = CommandCode(0x5c) // UPR NOOP
88	UPR_BUFFERACK   = CommandCode(0x5d) // UPR Buffer Acknowledgement
89	UPR_CONTROL     = CommandCode(0x5e) // Set flow control params
90
91	SELECT_BUCKET = CommandCode(0x89) // Select bucket
92
93	OBSERVE_SEQNO = CommandCode(0x91) // Sequence Number based Observe
94	OBSERVE       = CommandCode(0x92)
95
96	GET_META            = CommandCode(0xA0) // Get meta. returns with expiry, flags, cas etc
97	SUBDOC_GET          = CommandCode(0xc5) // Get subdoc. Returns with xattrs
98	SUBDOC_MULTI_LOOKUP = CommandCode(0xd0) // Multi lookup. Doc xattrs and meta.
99)
100
101// command codes that are counted toward DCP control buffer
102// when DCP clients receive DCP messages with these command codes, they need to provide acknowledgement
103var BufferedCommandCodeMap = map[CommandCode]bool{
104	SET_VBUCKET:    true,
105	UPR_STREAMEND:  true,
106	UPR_SNAPSHOT:   true,
107	UPR_MUTATION:   true,
108	UPR_DELETION:   true,
109	UPR_EXPIRATION: true}
110
111// Status field for memcached response.
112type Status uint16
113
114// Matches with protocol_binary.h as source of truth
115const (
116	SUCCESS         = Status(0x00)
117	KEY_ENOENT      = Status(0x01)
118	KEY_EEXISTS     = Status(0x02)
119	E2BIG           = Status(0x03)
120	EINVAL          = Status(0x04)
121	NOT_STORED      = Status(0x05)
122	DELTA_BADVAL    = Status(0x06)
123	NOT_MY_VBUCKET  = Status(0x07)
124	NO_BUCKET       = Status(0x08)
125	LOCKED          = Status(0x09)
126	AUTH_STALE      = Status(0x1f)
127	AUTH_ERROR      = Status(0x20)
128	AUTH_CONTINUE   = Status(0x21)
129	ERANGE          = Status(0x22)
130	ROLLBACK        = Status(0x23)
131	EACCESS         = Status(0x24)
132	NOT_INITIALIZED = Status(0x25)
133	UNKNOWN_COMMAND = Status(0x81)
134	ENOMEM          = Status(0x82)
135	NOT_SUPPORTED   = Status(0x83)
136	EINTERNAL       = Status(0x84)
137	EBUSY           = Status(0x85)
138	TMPFAIL         = Status(0x86)
139
140	// SUBDOC
141	SUBDOC_PATH_NOT_FOUND             = Status(0xc0)
142	SUBDOC_BAD_MULTI                  = Status(0xcc)
143	SUBDOC_MULTI_PATH_FAILURE_DELETED = Status(0xd3)
144)
145
146// for log redaction
147const (
148	UdTagBegin = "<ud>"
149	UdTagEnd   = "</ud>"
150)
151
152var isFatal = map[Status]bool{
153	DELTA_BADVAL:   true,
154	NO_BUCKET:      true,
155	AUTH_STALE:     true,
156	AUTH_ERROR:     true,
157	ERANGE:         true,
158	ROLLBACK:       true,
159	EACCESS:        true,
160	ENOMEM:         true,
161}
162
163// the producer/consumer bit in dcp flags
164var DCP_PRODUCER uint32 = 0x01
165
166// the include XATTRS bit in dcp flags
167var DCP_OPEN_INCLUDE_XATTRS uint32 = 0x04
168
169// the include deletion time bit in dcp flags
170var DCP_OPEN_INCLUDE_DELETE_TIMES uint32 = 0x20
171
172// Datatype to Include XATTRS in SUBDOC GET
173var SUBDOC_FLAG_XATTR uint8 = 0x04
174
175// MCItem is an internal representation of an item.
176type MCItem struct {
177	Cas               uint64
178	Flags, Expiration uint32
179	Data              []byte
180}
181
182// Number of bytes in a binary protocol header.
183const HDR_LEN = 24
184
185// Mapping of CommandCode -> name of command (not exhaustive)
186var CommandNames map[CommandCode]string
187
188// StatusNames human readable names for memcached response.
189var StatusNames map[Status]string
190
191func init() {
192	CommandNames = make(map[CommandCode]string)
193	CommandNames[GET] = "GET"
194	CommandNames[SET] = "SET"
195	CommandNames[ADD] = "ADD"
196	CommandNames[REPLACE] = "REPLACE"
197	CommandNames[DELETE] = "DELETE"
198	CommandNames[INCREMENT] = "INCREMENT"
199	CommandNames[DECREMENT] = "DECREMENT"
200	CommandNames[QUIT] = "QUIT"
201	CommandNames[FLUSH] = "FLUSH"
202	CommandNames[GETQ] = "GETQ"
203	CommandNames[NOOP] = "NOOP"
204	CommandNames[VERSION] = "VERSION"
205	CommandNames[GETK] = "GETK"
206	CommandNames[GETKQ] = "GETKQ"
207	CommandNames[APPEND] = "APPEND"
208	CommandNames[PREPEND] = "PREPEND"
209	CommandNames[STAT] = "STAT"
210	CommandNames[SETQ] = "SETQ"
211	CommandNames[ADDQ] = "ADDQ"
212	CommandNames[REPLACEQ] = "REPLACEQ"
213	CommandNames[DELETEQ] = "DELETEQ"
214	CommandNames[INCREMENTQ] = "INCREMENTQ"
215	CommandNames[DECREMENTQ] = "DECREMENTQ"
216	CommandNames[QUITQ] = "QUITQ"
217	CommandNames[FLUSHQ] = "FLUSHQ"
218	CommandNames[APPENDQ] = "APPENDQ"
219	CommandNames[PREPENDQ] = "PREPENDQ"
220	CommandNames[RGET] = "RGET"
221	CommandNames[RSET] = "RSET"
222	CommandNames[RSETQ] = "RSETQ"
223	CommandNames[RAPPEND] = "RAPPEND"
224	CommandNames[RAPPENDQ] = "RAPPENDQ"
225	CommandNames[RPREPEND] = "RPREPEND"
226	CommandNames[RPREPENDQ] = "RPREPENDQ"
227	CommandNames[RDELETE] = "RDELETE"
228	CommandNames[RDELETEQ] = "RDELETEQ"
229	CommandNames[RINCR] = "RINCR"
230	CommandNames[RINCRQ] = "RINCRQ"
231	CommandNames[RDECR] = "RDECR"
232	CommandNames[RDECRQ] = "RDECRQ"
233
234	CommandNames[SASL_LIST_MECHS] = "SASL_LIST_MECHS"
235	CommandNames[SASL_AUTH] = "SASL_AUTH"
236	CommandNames[SASL_STEP] = "SASL_STEP"
237
238	CommandNames[TAP_CONNECT] = "TAP_CONNECT"
239	CommandNames[TAP_MUTATION] = "TAP_MUTATION"
240	CommandNames[TAP_DELETE] = "TAP_DELETE"
241	CommandNames[TAP_FLUSH] = "TAP_FLUSH"
242	CommandNames[TAP_OPAQUE] = "TAP_OPAQUE"
243	CommandNames[TAP_VBUCKET_SET] = "TAP_VBUCKET_SET"
244	CommandNames[TAP_CHECKPOINT_START] = "TAP_CHECKPOINT_START"
245	CommandNames[TAP_CHECKPOINT_END] = "TAP_CHECKPOINT_END"
246
247	CommandNames[UPR_OPEN] = "UPR_OPEN"
248	CommandNames[UPR_ADDSTREAM] = "UPR_ADDSTREAM"
249	CommandNames[UPR_CLOSESTREAM] = "UPR_CLOSESTREAM"
250	CommandNames[UPR_FAILOVERLOG] = "UPR_FAILOVERLOG"
251	CommandNames[UPR_STREAMREQ] = "UPR_STREAMREQ"
252	CommandNames[UPR_STREAMEND] = "UPR_STREAMEND"
253	CommandNames[UPR_SNAPSHOT] = "UPR_SNAPSHOT"
254	CommandNames[UPR_MUTATION] = "UPR_MUTATION"
255	CommandNames[UPR_DELETION] = "UPR_DELETION"
256	CommandNames[UPR_EXPIRATION] = "UPR_EXPIRATION"
257	CommandNames[UPR_FLUSH] = "UPR_FLUSH"
258	CommandNames[UPR_NOOP] = "UPR_NOOP"
259	CommandNames[UPR_BUFFERACK] = "UPR_BUFFERACK"
260	CommandNames[UPR_CONTROL] = "UPR_CONTROL"
261	CommandNames[SUBDOC_GET] = "SUBDOC_GET"
262	CommandNames[SUBDOC_MULTI_LOOKUP] = "SUBDOC_MULTI_LOOKUP"
263
264	StatusNames = make(map[Status]string)
265	StatusNames[SUCCESS] = "SUCCESS"
266	StatusNames[KEY_ENOENT] = "KEY_ENOENT"
267	StatusNames[KEY_EEXISTS] = "KEY_EEXISTS"
268	StatusNames[E2BIG] = "E2BIG"
269	StatusNames[EINVAL] = "EINVAL"
270	StatusNames[NOT_STORED] = "NOT_STORED"
271	StatusNames[DELTA_BADVAL] = "DELTA_BADVAL"
272	StatusNames[NOT_MY_VBUCKET] = "NOT_MY_VBUCKET"
273	StatusNames[NO_BUCKET] = "NO_BUCKET"
274	StatusNames[AUTH_STALE] = "AUTH_STALE"
275	StatusNames[AUTH_ERROR] = "AUTH_ERROR"
276	StatusNames[AUTH_CONTINUE] = "AUTH_CONTINUE"
277	StatusNames[ERANGE] = "ERANGE"
278	StatusNames[ROLLBACK] = "ROLLBACK"
279	StatusNames[EACCESS] = "EACCESS"
280	StatusNames[NOT_INITIALIZED] = "NOT_INITIALIZED"
281	StatusNames[UNKNOWN_COMMAND] = "UNKNOWN_COMMAND"
282	StatusNames[ENOMEM] = "ENOMEM"
283	StatusNames[NOT_SUPPORTED] = "NOT_SUPPORTED"
284	StatusNames[EINTERNAL] = "EINTERNAL"
285	StatusNames[EBUSY] = "EBUSY"
286	StatusNames[TMPFAIL] = "TMPFAIL"
287	StatusNames[SUBDOC_PATH_NOT_FOUND] = "SUBDOC_PATH_NOT_FOUND"
288	StatusNames[SUBDOC_BAD_MULTI] = "SUBDOC_BAD_MULTI"
289
290}
291
292// String an op code.
293func (o CommandCode) String() (rv string) {
294	rv = CommandNames[o]
295	if rv == "" {
296		rv = fmt.Sprintf("0x%02x", int(o))
297	}
298	return rv
299}
300
301// String an op code.
302func (s Status) String() (rv string) {
303	rv = StatusNames[s]
304	if rv == "" {
305		rv = fmt.Sprintf("0x%02x", int(s))
306	}
307	return rv
308}
309
310// IsQuiet will return true if a command is a "quiet" command.
311func (o CommandCode) IsQuiet() bool {
312	switch o {
313	case GETQ,
314		GETKQ,
315		SETQ,
316		ADDQ,
317		REPLACEQ,
318		DELETEQ,
319		INCREMENTQ,
320		DECREMENTQ,
321		QUITQ,
322		FLUSHQ,
323		APPENDQ,
324		PREPENDQ,
325		RSETQ,
326		RAPPENDQ,
327		RPREPENDQ,
328		RDELETEQ,
329		RINCRQ,
330		RDECRQ:
331		return true
332	}
333	return false
334}
335