aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/couchbase/gomemcached/mc_req.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/couchbase/gomemcached/mc_req.go')
-rw-r--r--vendor/github.com/couchbase/gomemcached/mc_req.go165
1 files changed, 150 insertions, 15 deletions
diff --git a/vendor/github.com/couchbase/gomemcached/mc_req.go b/vendor/github.com/couchbase/gomemcached/mc_req.go
index c4f154f224..9fbfde3457 100644
--- a/vendor/github.com/couchbase/gomemcached/mc_req.go
+++ b/vendor/github.com/couchbase/gomemcached/mc_req.go
@@ -33,6 +33,10 @@ type MCRequest struct {
CollId [binary.MaxVarintLen32]byte
// Length of collection id
CollIdLen int
+ // Impersonate user name - could go in FramingExtras, but for efficiency
+ Username [MAX_USER_LEN]byte
+ // Length of Impersonate user name
+ UserLen int
// Flexible Framing Extras
FramingExtras []FrameInfo
// Stored length of incoming framing extras
@@ -41,7 +45,24 @@ type MCRequest struct {
// Size gives the number of bytes this request requires.
func (req *MCRequest) HdrSize() int {
- return HDR_LEN + len(req.Extras) + req.CollIdLen + req.FramingElen + len(req.Key)
+ rv := HDR_LEN + len(req.Extras) + req.CollIdLen + req.FramingElen + len(req.Key)
+ if req.UserLen != 0 {
+ rv += req.UserLen + 1
+
+ // half byte shifting required
+ if req.UserLen > FAST_USER_LEN {
+ rv++
+ }
+ }
+ for _, e := range req.FramingExtras {
+ rv += e.ObjLen + 1
+
+ // half byte shifting required
+ if e.ObjLen > FAST_USER_LEN {
+ rv++
+ }
+ }
+ return rv
}
func (req *MCRequest) Size() int {
@@ -125,6 +146,85 @@ func (req *MCRequest) fillRegularHeaderBytes(data []byte) int {
return pos
}
+func (req *MCRequest) fillFastFlexHeaderBytes(data []byte) int {
+ // Byte/ 0 | 1 | 2 | 3 |
+ // / | | | |
+ // |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+ // +---------------+---------------+---------------+---------------+
+ // 0| Magic | Opcode | Framing extras| Key Length |
+ // +---------------+---------------+---------------+---------------+
+ // 4| Extras length | Data type | vbucket id |
+ // +---------------+---------------+---------------+---------------+
+ // 8| Total body length |
+ // +---------------+---------------+---------------+---------------+
+ // 12| Opaque |
+ // +---------------+---------------+---------------+---------------+
+ // 16| CAS |
+ // | |
+ // +---------------+---------------+---------------+---------------+
+ // Total 24 bytes
+
+ pos := 0
+ data[pos] = FLEX_MAGIC
+ pos++
+ data[pos] = byte(req.Opcode)
+ pos++
+ data[pos] = byte(req.UserLen + 1)
+ pos++
+ data[pos] = byte(len(req.Key) + req.CollIdLen)
+ pos++
+
+ // 4
+ data[pos] = byte(len(req.Extras))
+ pos++
+ // Data type
+ if req.DataType != 0 {
+ data[pos] = byte(req.DataType)
+ }
+ pos++
+ binary.BigEndian.PutUint16(data[pos:pos+2], req.VBucket)
+ pos += 2
+
+ // 8
+ binary.BigEndian.PutUint32(data[pos:pos+4],
+ uint32(len(req.Body)+req.CollIdLen+len(req.Key)+(req.UserLen+1)+len(req.Extras)+len(req.ExtMeta)))
+ pos += 4
+
+ // 12
+ binary.BigEndian.PutUint32(data[pos:pos+4], req.Opaque)
+ pos += 4
+
+ // 16
+ if req.Cas != 0 {
+ binary.BigEndian.PutUint64(data[pos:pos+8], req.Cas)
+ }
+ pos += 8
+
+ // 24 Flexible extras
+ if req.UserLen > 0 {
+ data[pos] = byte((uint8(FrameImpersonate) << 4) | uint8(req.UserLen))
+ pos++
+ copy(data[pos:pos+req.UserLen], req.Username[:req.UserLen])
+ pos += req.UserLen
+ }
+
+ if len(req.Extras) > 0 {
+ copy(data[pos:pos+len(req.Extras)], req.Extras)
+ pos += len(req.Extras)
+ }
+
+ if len(req.Key) > 0 {
+ if req.CollIdLen > 0 {
+ copy(data[pos:pos+req.CollIdLen], req.CollId[:])
+ pos += req.CollIdLen
+ }
+ copy(data[pos:pos+len(req.Key)], req.Key)
+ pos += len(req.Key)
+ }
+
+ return pos
+}
+
// Returns pos and if trailing by half byte
func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
@@ -147,16 +247,13 @@ func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
data[0] = FLEX_MAGIC
data[1] = byte(req.Opcode)
- data[2] = byte(req.FramingElen)
- data[3] = byte(req.Keylen + req.CollIdLen)
+ data[3] = byte(len(req.Key) + req.CollIdLen)
elen := len(req.Extras)
data[4] = byte(elen)
if req.DataType != 0 {
data[5] = byte(req.DataType)
}
binary.BigEndian.PutUint16(data[6:8], req.VBucket)
- binary.BigEndian.PutUint32(data[8:12],
- uint32(len(req.Body)+req.Keylen+req.CollIdLen+elen+len(req.ExtMeta)+req.FramingElen))
binary.BigEndian.PutUint32(data[12:16], req.Opaque)
if req.Cas != 0 {
binary.BigEndian.PutUint64(data[16:24], req.Cas)
@@ -197,12 +294,46 @@ func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
}
}
+ // fast impersonate Flexible Extra
+ if req.UserLen > 0 {
+ if !mergeMode {
+ outputBytes, halfByteMode = obj2Bytes(FrameImpersonate, req.UserLen, req.Username[:req.UserLen])
+ if !halfByteMode {
+ framingExtras = append(framingExtras, outputBytes...)
+ frameBytes += len(outputBytes)
+ } else {
+ mergeMode = true
+ mergeModeSrc = outputBytes
+ }
+ } else {
+ outputBytes, halfByteMode = obj2Bytes(FrameImpersonate, req.UserLen, req.Username[:req.UserLen])
+ outputBytes := ShiftByteSliceRight4Bits(outputBytes)
+ if halfByteMode {
+ // Previous halfbyte merge with this halfbyte will result in a complete byte
+ mergeMode = false
+ outputBytes = Merge2HalfByteSlices(mergeModeSrc, outputBytes)
+ framingExtras = append(framingExtras, outputBytes...)
+ frameBytes += len(outputBytes)
+ } else {
+ // Merge half byte with a non-half byte will result in a combined half-byte that will
+ // become the source for the next iteration
+ mergeModeSrc = Merge2HalfByteSlices(mergeModeSrc, outputBytes)
+ }
+ }
+ }
+
if mergeMode {
// Commit the temporary merge area into framingExtras
framingExtras = append(framingExtras, mergeModeSrc...)
frameBytes += len(mergeModeSrc)
}
+ req.FramingElen = frameBytes
+
+ // these have to be set after we have worked out the size of the Flexible Extras
+ data[2] = byte(req.FramingElen)
+ binary.BigEndian.PutUint32(data[8:12],
+ uint32(len(req.Body)+len(req.Key)+req.CollIdLen+elen+len(req.ExtMeta)+req.FramingElen))
copy(data[pos:pos+frameBytes], framingExtras)
pos += frameBytes
@@ -219,19 +350,21 @@ func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
}
// Add keys
- if req.Keylen > 0 {
+ if len(req.Key) > 0 {
if mergeMode {
var key []byte
var keylen int
+
if req.CollIdLen == 0 {
key = req.Key
- keylen = req.Keylen
+ keylen = len(req.Key)
} else {
key = append(key, req.CollId[:]...)
key = append(key, req.Key...)
- keylen = req.Keylen + req.CollIdLen
+ keylen = len(req.Key) + req.CollIdLen
}
- outputBytes = ShiftByteSliceRight4Bits(req.Key)
+
+ outputBytes = ShiftByteSliceRight4Bits(key)
data = Merge2HalfByteSlices(data, outputBytes)
pos += keylen
} else {
@@ -239,8 +372,8 @@ func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
copy(data[pos:pos+req.CollIdLen], req.CollId[:])
pos += req.CollIdLen
}
- copy(data[pos:pos+req.Keylen], req.Key)
- pos += req.Keylen
+ copy(data[pos:pos+len(req.Key)], req.Key)
+ pos += len(req.Key)
}
}
@@ -248,17 +381,19 @@ func (req *MCRequest) fillFlexHeaderBytes(data []byte) (int, bool) {
}
func (req *MCRequest) FillHeaderBytes(data []byte) (int, bool) {
- if req.FramingElen == 0 {
- return req.fillRegularHeaderBytes(data), false
- } else {
+ if len(req.FramingExtras) > 0 || req.UserLen > FAST_USER_LEN {
return req.fillFlexHeaderBytes(data)
+ } else if req.UserLen > 0 {
+ return req.fillFastFlexHeaderBytes(data), false
+ } else {
+ return req.fillRegularHeaderBytes(data), false
}
}
// HeaderBytes will return the wire representation of the request header
// (with the extras and key).
func (req *MCRequest) HeaderBytes() []byte {
- data := make([]byte, HDR_LEN+len(req.Extras)+req.CollIdLen+len(req.Key)+req.FramingElen)
+ data := make([]byte, req.HdrSize())
req.FillHeaderBytes(data)