|
- package gomemcached
-
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "strings"
- )
-
- type TapConnectFlag uint32
-
- // Tap connect option flags
- const (
- BACKFILL = TapConnectFlag(0x01)
- DUMP = TapConnectFlag(0x02)
- LIST_VBUCKETS = TapConnectFlag(0x04)
- TAKEOVER_VBUCKETS = TapConnectFlag(0x08)
- SUPPORT_ACK = TapConnectFlag(0x10)
- REQUEST_KEYS_ONLY = TapConnectFlag(0x20)
- CHECKPOINT = TapConnectFlag(0x40)
- REGISTERED_CLIENT = TapConnectFlag(0x80)
- FIX_FLAG_BYTEORDER = TapConnectFlag(0x100)
- )
-
- // Tap opaque event subtypes
- const (
- TAP_OPAQUE_ENABLE_AUTO_NACK = 0
- TAP_OPAQUE_INITIAL_VBUCKET_STREAM = 1
- TAP_OPAQUE_ENABLE_CHECKPOINT_SYNC = 2
- TAP_OPAQUE_CLOSE_TAP_STREAM = 7
- TAP_OPAQUE_CLOSE_BACKFILL = 8
- )
-
- // Tap item flags
- const (
- TAP_ACK = 1
- TAP_NO_VALUE = 2
- TAP_FLAG_NETWORK_BYTE_ORDER = 4
- )
-
- // TapConnectFlagNames for TapConnectFlag
- var TapConnectFlagNames = map[TapConnectFlag]string{
- BACKFILL: "BACKFILL",
- DUMP: "DUMP",
- LIST_VBUCKETS: "LIST_VBUCKETS",
- TAKEOVER_VBUCKETS: "TAKEOVER_VBUCKETS",
- SUPPORT_ACK: "SUPPORT_ACK",
- REQUEST_KEYS_ONLY: "REQUEST_KEYS_ONLY",
- CHECKPOINT: "CHECKPOINT",
- REGISTERED_CLIENT: "REGISTERED_CLIENT",
- FIX_FLAG_BYTEORDER: "FIX_FLAG_BYTEORDER",
- }
-
- // TapItemParser is a function to parse a single tap extra.
- type TapItemParser func(io.Reader) (interface{}, error)
-
- // TapParseUint64 is a function to parse a single tap uint64.
- func TapParseUint64(r io.Reader) (interface{}, error) {
- var rv uint64
- err := binary.Read(r, binary.BigEndian, &rv)
- return rv, err
- }
-
- // TapParseUint16 is a function to parse a single tap uint16.
- func TapParseUint16(r io.Reader) (interface{}, error) {
- var rv uint16
- err := binary.Read(r, binary.BigEndian, &rv)
- return rv, err
- }
-
- // TapParseBool is a function to parse a single tap boolean.
- func TapParseBool(r io.Reader) (interface{}, error) {
- return true, nil
- }
-
- // TapParseVBList parses a list of vBucket numbers as []uint16.
- func TapParseVBList(r io.Reader) (interface{}, error) {
- num, err := TapParseUint16(r)
- if err != nil {
- return nil, err
- }
- n := int(num.(uint16))
-
- rv := make([]uint16, n)
- for i := 0; i < n; i++ {
- x, err := TapParseUint16(r)
- if err != nil {
- return nil, err
- }
- rv[i] = x.(uint16)
- }
-
- return rv, err
- }
-
- // TapFlagParsers parser functions for TAP fields.
- var TapFlagParsers = map[TapConnectFlag]TapItemParser{
- BACKFILL: TapParseUint64,
- LIST_VBUCKETS: TapParseVBList,
- }
-
- // SplitFlags will split the ORed flags into the individual bit flags.
- func (f TapConnectFlag) SplitFlags() []TapConnectFlag {
- rv := []TapConnectFlag{}
- for i := uint32(1); f != 0; i = i << 1 {
- if uint32(f)&i == i {
- rv = append(rv, TapConnectFlag(i))
- }
- f = TapConnectFlag(uint32(f) & (^i))
- }
- return rv
- }
-
- func (f TapConnectFlag) String() string {
- parts := []string{}
- for _, x := range f.SplitFlags() {
- p := TapConnectFlagNames[x]
- if p == "" {
- p = fmt.Sprintf("0x%x", int(x))
- }
- parts = append(parts, p)
- }
- return strings.Join(parts, "|")
- }
-
- type TapConnect struct {
- Flags map[TapConnectFlag]interface{}
- RemainingBody []byte
- Name string
- }
-
- // ParseTapCommands parse the tap request into the interesting bits we may
- // need to do something with.
- func (req *MCRequest) ParseTapCommands() (TapConnect, error) {
- rv := TapConnect{
- Flags: map[TapConnectFlag]interface{}{},
- Name: string(req.Key),
- }
-
- if len(req.Extras) < 4 {
- return rv, fmt.Errorf("not enough extra bytes: %x", req.Extras)
- }
-
- flags := TapConnectFlag(binary.BigEndian.Uint32(req.Extras))
-
- r := bytes.NewReader(req.Body)
-
- for _, f := range flags.SplitFlags() {
- fun := TapFlagParsers[f]
- if fun == nil {
- fun = TapParseBool
- }
-
- val, err := fun(r)
- if err != nil {
- return rv, err
- }
-
- rv.Flags[f] = val
- }
-
- var err error
- rv.RemainingBody, err = ioutil.ReadAll(r)
-
- return rv, err
- }
|