151 lines
3.8 KiB
Go
151 lines
3.8 KiB
Go
|
// Copyright (C) 2015 The GoHBase Authors. All rights reserved.
|
||
|
// This file is part of GoHBase.
|
||
|
// Use of this source code is governed by the Apache License 2.0
|
||
|
// that can be found in the COPYING file.
|
||
|
|
||
|
package hrpc
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/golang/protobuf/proto"
|
||
|
"github.com/tsuna/gohbase/pb"
|
||
|
)
|
||
|
|
||
|
// Get represents a Get HBase call.
|
||
|
type Get struct {
|
||
|
base
|
||
|
baseQuery
|
||
|
// Don't return any KeyValue, just say whether the row key exists in the
|
||
|
// table or not.
|
||
|
existsOnly bool
|
||
|
skipbatch bool
|
||
|
}
|
||
|
|
||
|
// baseGet returns a Get struct with default values set.
|
||
|
func baseGet(ctx context.Context, table []byte, key []byte,
|
||
|
options ...func(Call) error) (*Get, error) {
|
||
|
g := &Get{
|
||
|
base: base{
|
||
|
key: key,
|
||
|
table: table,
|
||
|
ctx: ctx,
|
||
|
resultch: make(chan RPCResult, 1),
|
||
|
},
|
||
|
baseQuery: newBaseQuery(),
|
||
|
}
|
||
|
err := applyOptions(g, options...)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return g, nil
|
||
|
}
|
||
|
|
||
|
// NewGet creates a new Get request for the given table and row key.
|
||
|
func NewGet(ctx context.Context, table, key []byte,
|
||
|
options ...func(Call) error) (*Get, error) {
|
||
|
return baseGet(ctx, table, key, options...)
|
||
|
}
|
||
|
|
||
|
// NewGetStr creates a new Get request for the given table and row key.
|
||
|
func NewGetStr(ctx context.Context, table, key string,
|
||
|
options ...func(Call) error) (*Get, error) {
|
||
|
return NewGet(ctx, []byte(table), []byte(key), options...)
|
||
|
}
|
||
|
|
||
|
// Name returns the name of this RPC call.
|
||
|
func (g *Get) Name() string {
|
||
|
return "Get"
|
||
|
}
|
||
|
|
||
|
// SkipBatch returns true if the Get request shouldn't be batched,
|
||
|
// but should be sent to Region Server right away.
|
||
|
func (g *Get) SkipBatch() bool {
|
||
|
return g.skipbatch
|
||
|
}
|
||
|
|
||
|
func (g *Get) setSkipBatch(v bool) {
|
||
|
g.skipbatch = v
|
||
|
}
|
||
|
|
||
|
// ExistsOnly makes this Get request not return any KeyValue, merely whether
|
||
|
// or not the given row key exists in the table.
|
||
|
func (g *Get) ExistsOnly() {
|
||
|
g.existsOnly = true
|
||
|
}
|
||
|
|
||
|
// ToProto converts this RPC into a protobuf message.
|
||
|
func (g *Get) ToProto() proto.Message {
|
||
|
get := &pb.GetRequest{
|
||
|
Region: g.regionSpecifier(),
|
||
|
Get: &pb.Get{
|
||
|
Row: g.key,
|
||
|
Column: familiesToColumn(g.families),
|
||
|
TimeRange: &pb.TimeRange{},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
/* added support for limit number of cells per row */
|
||
|
if g.storeLimit != DefaultMaxResultsPerColumnFamily {
|
||
|
get.Get.StoreLimit = &g.storeLimit
|
||
|
}
|
||
|
if g.storeOffset != 0 {
|
||
|
get.Get.StoreOffset = &g.storeOffset
|
||
|
}
|
||
|
|
||
|
if g.maxVersions != DefaultMaxVersions {
|
||
|
get.Get.MaxVersions = &g.maxVersions
|
||
|
}
|
||
|
if g.fromTimestamp != MinTimestamp {
|
||
|
get.Get.TimeRange.From = &g.fromTimestamp
|
||
|
}
|
||
|
if g.toTimestamp != MaxTimestamp {
|
||
|
get.Get.TimeRange.To = &g.toTimestamp
|
||
|
}
|
||
|
if g.existsOnly {
|
||
|
get.Get.ExistenceOnly = proto.Bool(true)
|
||
|
}
|
||
|
get.Get.Filter = g.filter
|
||
|
return get
|
||
|
}
|
||
|
|
||
|
// NewResponse creates an empty protobuf message to read the response of this
|
||
|
// RPC.
|
||
|
func (g *Get) NewResponse() proto.Message {
|
||
|
return &pb.GetResponse{}
|
||
|
}
|
||
|
|
||
|
// DeserializeCellBlocks deserializes get result from cell blocks
|
||
|
func (g *Get) DeserializeCellBlocks(m proto.Message, b []byte) (uint32, error) {
|
||
|
resp := m.(*pb.GetResponse)
|
||
|
if resp.Result == nil {
|
||
|
// TODO: is this possible?
|
||
|
return 0, nil
|
||
|
}
|
||
|
cells, read, err := deserializeCellBlocks(b, uint32(resp.Result.GetAssociatedCellCount()))
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
resp.Result.Cell = append(resp.Result.Cell, cells...)
|
||
|
return read, nil
|
||
|
}
|
||
|
|
||
|
// familiesToColumn takes a map from strings to lists of strings, and converts
|
||
|
// them into protobuf Columns
|
||
|
func familiesToColumn(families map[string][]string) []*pb.Column {
|
||
|
cols := make([]*pb.Column, len(families))
|
||
|
counter := 0
|
||
|
for family, qualifiers := range families {
|
||
|
bytequals := make([][]byte, len(qualifiers))
|
||
|
for i, qual := range qualifiers {
|
||
|
bytequals[i] = []byte(qual)
|
||
|
}
|
||
|
cols[counter] = &pb.Column{
|
||
|
Family: []byte(family),
|
||
|
Qualifier: bytequals,
|
||
|
}
|
||
|
counter++
|
||
|
}
|
||
|
return cols
|
||
|
}
|