本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 line
3.9KB

  1. package gomemcached
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "strings"
  9. )
  10. type TapConnectFlag uint32
  11. // Tap connect option flags
  12. const (
  13. BACKFILL = TapConnectFlag(0x01)
  14. DUMP = TapConnectFlag(0x02)
  15. LIST_VBUCKETS = TapConnectFlag(0x04)
  16. TAKEOVER_VBUCKETS = TapConnectFlag(0x08)
  17. SUPPORT_ACK = TapConnectFlag(0x10)
  18. REQUEST_KEYS_ONLY = TapConnectFlag(0x20)
  19. CHECKPOINT = TapConnectFlag(0x40)
  20. REGISTERED_CLIENT = TapConnectFlag(0x80)
  21. FIX_FLAG_BYTEORDER = TapConnectFlag(0x100)
  22. )
  23. // Tap opaque event subtypes
  24. const (
  25. TAP_OPAQUE_ENABLE_AUTO_NACK = 0
  26. TAP_OPAQUE_INITIAL_VBUCKET_STREAM = 1
  27. TAP_OPAQUE_ENABLE_CHECKPOINT_SYNC = 2
  28. TAP_OPAQUE_CLOSE_TAP_STREAM = 7
  29. TAP_OPAQUE_CLOSE_BACKFILL = 8
  30. )
  31. // Tap item flags
  32. const (
  33. TAP_ACK = 1
  34. TAP_NO_VALUE = 2
  35. TAP_FLAG_NETWORK_BYTE_ORDER = 4
  36. )
  37. // TapConnectFlagNames for TapConnectFlag
  38. var TapConnectFlagNames = map[TapConnectFlag]string{
  39. BACKFILL: "BACKFILL",
  40. DUMP: "DUMP",
  41. LIST_VBUCKETS: "LIST_VBUCKETS",
  42. TAKEOVER_VBUCKETS: "TAKEOVER_VBUCKETS",
  43. SUPPORT_ACK: "SUPPORT_ACK",
  44. REQUEST_KEYS_ONLY: "REQUEST_KEYS_ONLY",
  45. CHECKPOINT: "CHECKPOINT",
  46. REGISTERED_CLIENT: "REGISTERED_CLIENT",
  47. FIX_FLAG_BYTEORDER: "FIX_FLAG_BYTEORDER",
  48. }
  49. // TapItemParser is a function to parse a single tap extra.
  50. type TapItemParser func(io.Reader) (interface{}, error)
  51. // TapParseUint64 is a function to parse a single tap uint64.
  52. func TapParseUint64(r io.Reader) (interface{}, error) {
  53. var rv uint64
  54. err := binary.Read(r, binary.BigEndian, &rv)
  55. return rv, err
  56. }
  57. // TapParseUint16 is a function to parse a single tap uint16.
  58. func TapParseUint16(r io.Reader) (interface{}, error) {
  59. var rv uint16
  60. err := binary.Read(r, binary.BigEndian, &rv)
  61. return rv, err
  62. }
  63. // TapParseBool is a function to parse a single tap boolean.
  64. func TapParseBool(r io.Reader) (interface{}, error) {
  65. return true, nil
  66. }
  67. // TapParseVBList parses a list of vBucket numbers as []uint16.
  68. func TapParseVBList(r io.Reader) (interface{}, error) {
  69. num, err := TapParseUint16(r)
  70. if err != nil {
  71. return nil, err
  72. }
  73. n := int(num.(uint16))
  74. rv := make([]uint16, n)
  75. for i := 0; i < n; i++ {
  76. x, err := TapParseUint16(r)
  77. if err != nil {
  78. return nil, err
  79. }
  80. rv[i] = x.(uint16)
  81. }
  82. return rv, err
  83. }
  84. // TapFlagParsers parser functions for TAP fields.
  85. var TapFlagParsers = map[TapConnectFlag]TapItemParser{
  86. BACKFILL: TapParseUint64,
  87. LIST_VBUCKETS: TapParseVBList,
  88. }
  89. // SplitFlags will split the ORed flags into the individual bit flags.
  90. func (f TapConnectFlag) SplitFlags() []TapConnectFlag {
  91. rv := []TapConnectFlag{}
  92. for i := uint32(1); f != 0; i = i << 1 {
  93. if uint32(f)&i == i {
  94. rv = append(rv, TapConnectFlag(i))
  95. }
  96. f = TapConnectFlag(uint32(f) & (^i))
  97. }
  98. return rv
  99. }
  100. func (f TapConnectFlag) String() string {
  101. parts := []string{}
  102. for _, x := range f.SplitFlags() {
  103. p := TapConnectFlagNames[x]
  104. if p == "" {
  105. p = fmt.Sprintf("0x%x", int(x))
  106. }
  107. parts = append(parts, p)
  108. }
  109. return strings.Join(parts, "|")
  110. }
  111. type TapConnect struct {
  112. Flags map[TapConnectFlag]interface{}
  113. RemainingBody []byte
  114. Name string
  115. }
  116. // ParseTapCommands parse the tap request into the interesting bits we may
  117. // need to do something with.
  118. func (req *MCRequest) ParseTapCommands() (TapConnect, error) {
  119. rv := TapConnect{
  120. Flags: map[TapConnectFlag]interface{}{},
  121. Name: string(req.Key),
  122. }
  123. if len(req.Extras) < 4 {
  124. return rv, fmt.Errorf("not enough extra bytes: %x", req.Extras)
  125. }
  126. flags := TapConnectFlag(binary.BigEndian.Uint32(req.Extras))
  127. r := bytes.NewReader(req.Body)
  128. for _, f := range flags.SplitFlags() {
  129. fun := TapFlagParsers[f]
  130. if fun == nil {
  131. fun = TapParseBool
  132. }
  133. val, err := fun(r)
  134. if err != nil {
  135. return rv, err
  136. }
  137. rv.Flags[f] = val
  138. }
  139. var err error
  140. rv.RemainingBody, err = ioutil.ReadAll(r)
  141. return rv, err
  142. }
上海开阖软件有限公司 沪ICP备12045867号-1