github.com/tsuna/gohbase@v0.0.0-20250731002811-4ffcadfba63e/hrpc/get.go (about)

     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  
     6  package hrpc
     7  
     8  import (
     9  	"context"
    10  
    11  	"github.com/tsuna/gohbase/pb"
    12  	"google.golang.org/protobuf/proto"
    13  )
    14  
    15  // Get represents a Get HBase call.
    16  type Get struct {
    17  	base
    18  	baseQuery
    19  	// Don't return any KeyValue, just say whether the row key exists in the
    20  	// table or not.
    21  	existsOnly bool
    22  	skipbatch  bool
    23  }
    24  
    25  // baseGet returns a Get struct with default values set.
    26  func baseGet(ctx context.Context, table []byte, key []byte,
    27  	options ...func(Call) error) (*Get, error) {
    28  	g := &Get{
    29  		base: base{
    30  			key:      key,
    31  			table:    table,
    32  			ctx:      ctx,
    33  			resultch: make(chan RPCResult, 1),
    34  		},
    35  		baseQuery: newBaseQuery(),
    36  	}
    37  	err := applyOptions(g, options...)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	return g, nil
    42  }
    43  
    44  // NewGet creates a new Get request for the given table and row key.
    45  func NewGet(ctx context.Context, table, key []byte,
    46  	options ...func(Call) error) (*Get, error) {
    47  	return baseGet(ctx, table, key, options...)
    48  }
    49  
    50  // NewGetStr creates a new Get request for the given table and row key.
    51  func NewGetStr(ctx context.Context, table, key string,
    52  	options ...func(Call) error) (*Get, error) {
    53  	return NewGet(ctx, []byte(table), []byte(key), options...)
    54  }
    55  
    56  // Name returns the name of this RPC call.
    57  func (g *Get) Name() string {
    58  	return "Get"
    59  }
    60  
    61  // Description returns the description of this RPC call.
    62  func (g *Get) Description() string {
    63  	return g.Name()
    64  }
    65  
    66  // SkipBatch returns true if the Get request shouldn't be batched,
    67  // but should be sent to Region Server right away.
    68  func (g *Get) SkipBatch() bool {
    69  	return g.skipbatch
    70  }
    71  
    72  func (g *Get) setSkipBatch(v bool) {
    73  	g.skipbatch = v
    74  }
    75  
    76  // ExistsOnly makes this Get request not return any KeyValue, merely whether
    77  // or not the given row key exists in the table.
    78  func (g *Get) ExistsOnly() {
    79  	g.existsOnly = true
    80  }
    81  
    82  // ToProto converts this RPC into a protobuf message.
    83  func (g *Get) ToProto() proto.Message {
    84  	get := &pb.GetRequest{
    85  		Region: g.regionSpecifier(),
    86  		Get: &pb.Get{
    87  			Row:       g.key,
    88  			Column:    familiesToColumn(g.families),
    89  			TimeRange: &pb.TimeRange{},
    90  		},
    91  	}
    92  
    93  	/* added support for limit number of cells per row */
    94  	if g.storeLimit != DefaultMaxResultsPerColumnFamily {
    95  		get.Get.StoreLimit = &g.storeLimit
    96  	}
    97  	if g.storeOffset != 0 {
    98  		get.Get.StoreOffset = &g.storeOffset
    99  	}
   100  
   101  	if g.maxVersions != DefaultMaxVersions {
   102  		get.Get.MaxVersions = &g.maxVersions
   103  	}
   104  	if g.fromTimestamp != MinTimestamp {
   105  		get.Get.TimeRange.From = &g.fromTimestamp
   106  	}
   107  	if g.toTimestamp != MaxTimestamp {
   108  		get.Get.TimeRange.To = &g.toTimestamp
   109  	}
   110  	if g.existsOnly {
   111  		get.Get.ExistenceOnly = proto.Bool(true)
   112  	}
   113  	if g.cacheBlocks != DefaultCacheBlocks {
   114  		get.Get.CacheBlocks = &g.cacheBlocks
   115  	}
   116  	if g.consistency != DefaultConsistency {
   117  		get.Get.Consistency = g.consistency.toProto()
   118  	}
   119  	get.Get.Filter = g.filter
   120  	return get
   121  }
   122  
   123  // NewResponse creates an empty protobuf message to read the response of this
   124  // RPC.
   125  func (g *Get) NewResponse() proto.Message {
   126  	return &pb.GetResponse{}
   127  }
   128  
   129  // DeserializeCellBlocks deserializes get result from cell blocks
   130  func (g *Get) DeserializeCellBlocks(m proto.Message, b []byte) (uint32, error) {
   131  	resp := m.(*pb.GetResponse)
   132  	if resp.Result == nil {
   133  		// TODO: is this possible?
   134  		return 0, nil
   135  	}
   136  	cells, read, err := deserializeCellBlocks(b, uint32(resp.Result.GetAssociatedCellCount()))
   137  	if err != nil {
   138  		return 0, err
   139  	}
   140  	resp.Result.Cell = append(resp.Result.Cell, cells...)
   141  	return read, nil
   142  }
   143  
   144  // familiesToColumn takes a map from strings to lists of strings, and converts
   145  // them into protobuf Columns
   146  func familiesToColumn(families map[string][]string) []*pb.Column {
   147  	cols := make([]*pb.Column, len(families))
   148  	counter := 0
   149  	for family, qualifiers := range families {
   150  		bytequals := make([][]byte, len(qualifiers))
   151  		for i, qual := range qualifiers {
   152  			bytequals[i] = []byte(qual)
   153  		}
   154  		cols[counter] = &pb.Column{
   155  			Family:    []byte(family),
   156  			Qualifier: bytequals,
   157  		}
   158  		counter++
   159  	}
   160  	return cols
   161  }