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.
 
 
 

284 lines
8.3 KiB

// Copyright (C) 2016 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.
// +build testing
package region
import (
"bytes"
"context"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/golang/protobuf/proto"
"github.com/tsuna/gohbase/hrpc"
"github.com/tsuna/gohbase/pb"
)
type testClient struct {
addr string
numNSRE int32
}
var nsreRegion = &pb.Result{Cell: []*pb.Cell{
&pb.Cell{
Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("regioninfo"),
Value: []byte("PBUF\b\xc4\xcd\xe9\x99\xe0)\x12\x0f\n\adefault\x12\x04nsre" +
"\x1a\x00\"\x00(\x000\x008\x00"),
},
&pb.Cell{
Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("seqnumDuringOpen"),
Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"),
},
&pb.Cell{
Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("server"),
Value: []byte("regionserver:1"),
},
&pb.Cell{
Row: []byte("nsre,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("serverstartcode"),
Value: []byte("\x00\x00\x01N\x02\x92R\xb1"),
},
}}
// makeRegionResult returns a region that spans the whole table
// and uses name of the table as the hostname of the regionserver
func makeRegionResult(key []byte) *pb.ScanResponse {
s := bytes.SplitN(key, []byte(","), 2)
fqtable := s[0]
row := append(fqtable, []byte(",,1434573235908.56f833d5569a27c7a43fbf547b4924a4.")...)
t := bytes.SplitN(fqtable, []byte{':'}, 2)
var namespace, table []byte
if len(t) == 2 {
namespace = t[0]
table = t[1]
} else {
namespace = []byte("default")
table = fqtable
}
regionInfo := &pb.RegionInfo{
RegionId: proto.Uint64(1434573235908),
TableName: &pb.TableName{
Namespace: namespace,
Qualifier: table,
},
Offline: proto.Bool(false),
}
regionInfoValue, err := proto.Marshal(regionInfo)
if err != nil {
panic(err)
}
regionInfoValue = append([]byte("PBUF"), regionInfoValue...)
return &pb.ScanResponse{Results: []*pb.Result{
&pb.Result{Cell: []*pb.Cell{
&pb.Cell{
Row: row,
Family: []byte("info"),
Qualifier: []byte("regioninfo"),
Value: regionInfoValue,
},
&pb.Cell{
Row: row,
Family: []byte("info"),
Qualifier: []byte("seqnumDuringOpen"),
Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"),
},
&pb.Cell{
Row: row,
Family: []byte("info"),
Qualifier: []byte("server"),
Value: fqtable,
},
&pb.Cell{
Row: row,
Family: []byte("info"),
Qualifier: []byte("serverstartcode"),
Value: []byte("\x00\x00\x01N\x02\x92R\xb1"),
},
}}}}
}
var metaRow = &pb.Result{Cell: []*pb.Cell{
&pb.Cell{
Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("regioninfo"),
Value: []byte("PBUF\b\xc4\xcd\xe9\x99\xe0)\x12\x0f\n\adefault\x12\x04test" +
"\x1a\x00\"\x00(\x000\x008\x00"),
},
&pb.Cell{
Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("seqnumDuringOpen"),
Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x02"),
},
&pb.Cell{
Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("server"),
Value: []byte("regionserver:2"),
},
&pb.Cell{
Row: []byte("test,,1434573235908.56f833d5569a27c7a43fbf547b4924a4."),
Family: []byte("info"),
Qualifier: []byte("serverstartcode"),
Value: []byte("\x00\x00\x01N\x02\x92R\xb1"),
},
}}
var test1SplitA = &pb.Result{Cell: []*pb.Cell{
&pb.Cell{
Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."),
Family: []byte("info"),
Qualifier: []byte("regioninfo"),
Value: []byte("PBUF\b\xfbÖ\xbc\x8b+\x12\x10\n\adefault\x12\x05" +
"test1\x1a\x00\"\x03baz(\x000\x008\x00"),
},
&pb.Cell{
Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."),
Family: []byte("info"),
Qualifier: []byte("seqnumDuringOpen"),
Value: []byte("\x00\x00\x00\x00\x00\x00\x00\v"),
},
&pb.Cell{
Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."),
Family: []byte("info"),
Qualifier: []byte("server"),
Value: []byte("regionserver:1"),
},
&pb.Cell{
Row: []byte("test1,,1480547738107.825c5c7e480c76b73d6d2bad5d3f7bb8."),
Family: []byte("info"),
Qualifier: []byte("serverstartcode"),
Value: []byte("\x00\x00\x01X\xb6\x83^3"),
},
}}
var test1SplitB = &pb.Result{Cell: []*pb.Cell{
&pb.Cell{
Row: []byte("test1,baz,1480547738107.3f2483f5618e1b791f58f83a8ebba6a9."),
Family: []byte("info"),
Qualifier: []byte("regioninfo"),
Value: []byte("PBUF\b\xfbÖ\xbc\x8b+\x12\x10\n\adefault\x12\x05" +
"test1\x1a\x03baz\"\x00(\x000\x008\x00"),
},
&pb.Cell{
Row: []byte("test1,baz,1480547738107.3f2483f5618e1b791f58f83a8ebba6a9."),
Family: []byte("info"),
Qualifier: []byte("seqnumDuringOpen"),
Value: []byte("\x00\x00\x00\x00\x00\x00\x00\f"),
},
&pb.Cell{
Row: []byte("test1,baz,1480547738107.3f2483f5618e1b791f58f83a8ebba6a9."),
Family: []byte("info"),
Qualifier: []byte("server"),
Value: []byte("regionserver:3"),
},
&pb.Cell{
Row: []byte("test1,baz,1480547738107.3f2483f5618e1b791f58f83a8ebba6a9."),
Family: []byte("info"),
Qualifier: []byte("serverstartcode"),
Value: []byte("\x00\x00\x01X\xb6\x83^3"),
},
}}
var m sync.RWMutex
var clients map[string]uint32
func init() {
clients = make(map[string]uint32)
}
// NewClient creates a new test region client.
func NewClient(ctx context.Context, addr string, ctype ClientType,
queueSize int, flushInterval time.Duration, effectiveUser string,
readTimeout time.Duration) (hrpc.RegionClient, error) {
m.Lock()
clients[addr]++
m.Unlock()
return &testClient{addr: addr}, nil
}
func (c *testClient) Addr() string {
return c.addr
}
func (c *testClient) String() string {
return fmt.Sprintf("RegionClient{Addr: %s}", c.addr)
}
func (c *testClient) QueueRPC(call hrpc.Call) {
// ignore timed out rpcs to mock the region client
select {
case <-call.Context().Done():
return
default:
}
if !bytes.Equal(call.Table(), []byte("hbase:meta")) {
_, ok := call.(*hrpc.Get)
if !ok || !bytes.HasSuffix(call.Key(), bytes.Repeat([]byte{0}, 17)) {
// not a get and not a region probe
// just return as the mock call should just populate the ResultChan in test
return
}
// region probe, fail for the nsre region 3 times to force retry
if bytes.Equal(call.Table(), []byte("nsre")) {
i := atomic.AddInt32(&c.numNSRE, 1)
if i <= 3 {
call.ResultChan() <- hrpc.RPCResult{Error: RetryableError{}}
return
}
}
m.RLock()
i := clients[c.addr]
m.RUnlock()
// if we are connected to this client the first time,
// pretend it's down to fail the probe and start a reconnect
if bytes.Equal(call.Table(), []byte("down")) {
if i <= 1 {
call.ResultChan() <- hrpc.RPCResult{Error: UnrecoverableError{}}
} else {
// otherwise, the region is fine
call.ResultChan() <- hrpc.RPCResult{}
}
return
}
}
if bytes.HasSuffix(call.Key(), bytes.Repeat([]byte{0}, 17)) {
// meta region probe, return empty to signify that region is online
call.ResultChan() <- hrpc.RPCResult{}
} else if bytes.HasPrefix(call.Key(), []byte("test,")) {
call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{
Results: []*pb.Result{metaRow}}}
} else if bytes.HasPrefix(call.Key(), []byte("test1,,")) {
call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{
Results: []*pb.Result{test1SplitA}}}
} else if bytes.HasPrefix(call.Key(), []byte("nsre,,")) {
call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{
Results: []*pb.Result{nsreRegion}}}
} else if bytes.HasPrefix(call.Key(), []byte("tablenotfound,")) {
call.ResultChan() <- hrpc.RPCResult{Msg: &pb.ScanResponse{
Results: []*pb.Result{},
MoreResults: proto.Bool(false),
}}
} else {
call.ResultChan() <- hrpc.RPCResult{Msg: makeRegionResult(call.Key())}
}
}
func (c *testClient) Close() {}