call.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // Copyright (C) 2015 The GoHBase Authors. All rights reserved.
  2. // This file is part of GoHBase.
  3. // Use of this source code is governed by the Apache License 2.0
  4. // that can be found in the COPYING file.
  5. package hrpc
  6. import (
  7. "context"
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "unsafe"
  12. "github.com/golang/protobuf/proto"
  13. "github.com/tsuna/gohbase/pb"
  14. )
  15. // RegionInfo represents HBase region.
  16. type RegionInfo interface {
  17. IsUnavailable() bool
  18. AvailabilityChan() <-chan struct{}
  19. MarkUnavailable() bool
  20. MarkAvailable()
  21. MarkDead()
  22. Context() context.Context
  23. String() string
  24. ID() uint64
  25. Name() []byte
  26. StartKey() []byte
  27. StopKey() []byte
  28. Namespace() []byte
  29. Table() []byte
  30. SetClient(RegionClient)
  31. Client() RegionClient
  32. }
  33. // RegionClient represents HBase region client.
  34. type RegionClient interface {
  35. // Dial connects and bootstraps region client. Only the first caller to Dial gets to
  36. // actually connect, other concurrent callers will block until connected or an error.
  37. Dial(context.Context) error
  38. Close()
  39. Addr() string
  40. QueueRPC(Call)
  41. String() string
  42. }
  43. // Call represents an HBase RPC call.
  44. type Call interface {
  45. Table() []byte
  46. Name() string
  47. Key() []byte
  48. Region() RegionInfo
  49. SetRegion(region RegionInfo)
  50. ToProto() proto.Message
  51. // Returns a newly created (default-state) protobuf in which to store the
  52. // response of this call.
  53. NewResponse() proto.Message
  54. ResultChan() chan RPCResult
  55. Context() context.Context
  56. }
  57. type withOptions interface {
  58. Options() []func(Call) error
  59. setOptions([]func(Call) error)
  60. }
  61. // Batchable interface should be implemented by calls that can be batched into MultiRequest
  62. type Batchable interface {
  63. // SkipBatch returns true if a call shouldn't be batched into MultiRequest and
  64. // should be sent right away.
  65. SkipBatch() bool
  66. setSkipBatch(v bool)
  67. }
  68. // SkipBatch is an option for batchable requests (Get and Mutate) to tell
  69. // the client to skip batching and just send the request to Region Server
  70. // right away.
  71. func SkipBatch() func(Call) error {
  72. return func(c Call) error {
  73. if b, ok := c.(Batchable); ok {
  74. b.setSkipBatch(true)
  75. return nil
  76. }
  77. return errors.New("'SkipBatch' option only works with Get and Mutate requests")
  78. }
  79. }
  80. // hasQueryOptions is interface that needs to be implemented by calls
  81. // that allow to provide Families and Filters options.
  82. type hasQueryOptions interface {
  83. setFamilies(families map[string][]string)
  84. setFilter(filter *pb.Filter)
  85. setTimeRangeUint64(from, to uint64)
  86. setMaxVersions(versions uint32)
  87. setMaxResultsPerColumnFamily(maxresults uint32)
  88. setResultOffset(offset uint32)
  89. }
  90. // RPCResult is struct that will contain both the resulting message from an RPC
  91. // call, and any errors that may have occurred related to making the RPC call.
  92. type RPCResult struct {
  93. Msg proto.Message
  94. Error error
  95. }
  96. type base struct {
  97. ctx context.Context
  98. table []byte
  99. key []byte
  100. options []func(Call) error
  101. region RegionInfo
  102. resultch chan RPCResult
  103. }
  104. func (b *base) Context() context.Context {
  105. return b.ctx
  106. }
  107. func (b *base) Region() RegionInfo {
  108. return b.region
  109. }
  110. func (b *base) SetRegion(region RegionInfo) {
  111. b.region = region
  112. }
  113. func (b *base) regionSpecifier() *pb.RegionSpecifier {
  114. return &pb.RegionSpecifier{
  115. Type: pb.RegionSpecifier_REGION_NAME.Enum(),
  116. Value: []byte(b.region.Name()),
  117. }
  118. }
  119. func (b *base) setOptions(options []func(Call) error) {
  120. b.options = options
  121. }
  122. // Options returns all the options passed to this call
  123. func (b *base) Options() []func(Call) error {
  124. return b.options
  125. }
  126. func applyOptions(call Call, options ...func(Call) error) error {
  127. call.(withOptions).setOptions(options)
  128. for _, option := range options {
  129. err := option(call)
  130. if err != nil {
  131. return err
  132. }
  133. }
  134. return nil
  135. }
  136. func (b *base) Table() []byte {
  137. return b.table
  138. }
  139. func (b *base) Key() []byte {
  140. return b.key
  141. }
  142. func (b *base) ResultChan() chan RPCResult {
  143. return b.resultch
  144. }
  145. // Cell is the smallest level of granularity in returned results.
  146. // Represents a single cell in HBase (a row will have one cell for every qualifier).
  147. type Cell pb.Cell
  148. func (c *Cell) String() string {
  149. return (*pb.Cell)(c).String()
  150. }
  151. // cellFromCellBlock deserializes a cell from a reader
  152. func cellFromCellBlock(b []byte) (*pb.Cell, uint32, error) {
  153. if len(b) < 4 {
  154. return nil, 0, fmt.Errorf(
  155. "buffer is too small: expected %d, got %d", 4, len(b))
  156. }
  157. kvLen := binary.BigEndian.Uint32(b[0:4])
  158. if len(b) < int(kvLen)+4 {
  159. return nil, 0, fmt.Errorf(
  160. "buffer is too small: expected %d, got %d", int(kvLen)+4, len(b))
  161. }
  162. rowKeyLen := binary.BigEndian.Uint32(b[4:8])
  163. valueLen := binary.BigEndian.Uint32(b[8:12])
  164. keyLen := binary.BigEndian.Uint16(b[12:14])
  165. b = b[14:]
  166. key := b[:keyLen]
  167. b = b[keyLen:]
  168. familyLen := uint8(b[0])
  169. b = b[1:]
  170. family := b[:familyLen]
  171. b = b[familyLen:]
  172. qualifierLen := rowKeyLen - uint32(keyLen) - uint32(familyLen) - 2 - 1 - 8 - 1
  173. if 4 /*rowKeyLen*/ +4 /*valueLen*/ +2 /*keyLen*/ +
  174. uint32(keyLen)+1 /*familyLen*/ +uint32(familyLen)+qualifierLen+
  175. 8 /*timestamp*/ +1 /*cellType*/ +valueLen != kvLen {
  176. return nil, 0, fmt.Errorf("HBase has lied about KeyValue length: expected %d, got %d",
  177. kvLen, 4+4+2+uint32(keyLen)+1+uint32(familyLen)+qualifierLen+8+1+valueLen)
  178. }
  179. qualifier := b[:qualifierLen]
  180. b = b[qualifierLen:]
  181. timestamp := binary.BigEndian.Uint64(b[:8])
  182. b = b[8:]
  183. cellType := uint8(b[0])
  184. b = b[1:]
  185. value := b[:valueLen]
  186. return &pb.Cell{
  187. Row: key,
  188. Family: family,
  189. Qualifier: qualifier,
  190. Timestamp: &timestamp,
  191. Value: value,
  192. CellType: pb.CellType(cellType).Enum(),
  193. }, kvLen + 4, nil
  194. }
  195. func deserializeCellBlocks(b []byte, cellsLen uint32) ([]*pb.Cell, uint32, error) {
  196. cells := make([]*pb.Cell, cellsLen)
  197. var readLen uint32
  198. for i := 0; i < int(cellsLen); i++ {
  199. c, l, err := cellFromCellBlock(b[readLen:])
  200. if err != nil {
  201. return nil, readLen, err
  202. }
  203. cells[i] = c
  204. readLen += l
  205. }
  206. return cells, readLen, nil
  207. }
  208. // Result holds a slice of Cells as well as miscellaneous information about the response.
  209. type Result struct {
  210. Cells []*Cell
  211. Stale bool
  212. Partial bool
  213. // Exists is only set if existance_only was set in the request query.
  214. Exists *bool
  215. }
  216. func (c *Result) String() string {
  217. return fmt.Sprintf("cells:%v stale:%v partial:%v exists:%v ",
  218. c.Cells, c.Stale, c.Partial, c.Exists)
  219. }
  220. func extractBool(v *bool) bool {
  221. return v != nil && *v
  222. }
  223. // ToLocalResult takes a protobuf Result type and converts it to our own
  224. // Result type in constant time.
  225. func ToLocalResult(pbr *pb.Result) *Result {
  226. if pbr == nil {
  227. return &Result{}
  228. }
  229. return &Result{
  230. // Should all be O(1) operations.
  231. Cells: toLocalCells(pbr),
  232. Stale: extractBool(pbr.Stale),
  233. Partial: extractBool(pbr.Partial),
  234. Exists: pbr.Exists,
  235. }
  236. }
  237. func toLocalCells(pbr *pb.Result) []*Cell {
  238. return *(*[]*Cell)(unsafe.Pointer(pbr))
  239. }
  240. // We can now define any helper functions on Result that we want.