mirror of
https://github.com/restic/restic.git
synced 2026-10-12 13:07:14 +00:00
Update dependencies
Among others, this updates minio-go, so that the new "eu-west-3" zone for AWS is supported.
This commit is contained in:
1 parent
b63de7c798
commit
2b39f9f4b2
3435 files changed
+1317989
-315639
No files matched your search
+1
-1
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
func ExampleNewServer() {
|
||||
|
||||
srv, err := bttest.NewServer("127.0.0.1:0")
|
||||
srv, err := bttest.NewServer("localhost:0")
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
|
||||
+136
-97
@@ -19,7 +19,7 @@ Package bttest contains test helpers for working with the bigtable package.
|
||||
|
||||
To use a Server, create it, and then connect to it with no security:
|
||||
(The project/instance values are ignored.)
|
||||
srv, err := bttest.NewServer("127.0.0.1:0")
|
||||
srv, err := bttest.NewServer("localhost:0")
|
||||
...
|
||||
conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure())
|
||||
...
|
||||
@@ -45,12 +45,14 @@ import (
|
||||
|
||||
emptypb "github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"github.com/google/btree"
|
||||
"golang.org/x/net/context"
|
||||
btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2"
|
||||
btpb "google.golang.org/genproto/googleapis/bigtable/v2"
|
||||
statpb "google.golang.org/genproto/googleapis/rpc/status"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Server is an in-memory Cloud Bigtable fake.
|
||||
@@ -162,7 +164,7 @@ func (s *server) DeleteTable(ctx context.Context, req *btapb.DeleteTableRequest)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if _, ok := s.tables[req.Name]; !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
}
|
||||
delete(s.tables, req.Name)
|
||||
return &emptypb.Empty{}, nil
|
||||
@@ -224,65 +226,103 @@ func (s *server) DropRowRange(ctx context.Context, req *btapb.DropRowRangeReques
|
||||
defer s.mu.Unlock()
|
||||
tbl, ok := s.tables[req.Name]
|
||||
if !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
}
|
||||
|
||||
if req.GetDeleteAllDataFromTable() {
|
||||
tbl.rows = nil
|
||||
tbl.rowIndex = make(map[string]*row)
|
||||
tbl.rows = btree.New(btreeDegree)
|
||||
} else {
|
||||
// Delete rows by prefix
|
||||
// Delete rows by prefix.
|
||||
prefixBytes := req.GetRowKeyPrefix()
|
||||
if prefixBytes == nil {
|
||||
return nil, fmt.Errorf("missing row key prefix")
|
||||
}
|
||||
prefix := string(prefixBytes)
|
||||
|
||||
start := -1
|
||||
end := 0
|
||||
for i, row := range tbl.rows {
|
||||
match := strings.HasPrefix(row.key, prefix)
|
||||
if match {
|
||||
// Delete the mapping. Row will be deleted from sorted range below.
|
||||
delete(tbl.rowIndex, row.key)
|
||||
// The BTree does not specify what happens if rows are deleted during
|
||||
// iteration, and it provides no "delete range" method.
|
||||
// So we collect the rows first, then delete them one by one.
|
||||
var rowsToDelete []*row
|
||||
tbl.rows.AscendGreaterOrEqual(btreeKey(prefix), func(i btree.Item) bool {
|
||||
r := i.(*row)
|
||||
if strings.HasPrefix(r.key, prefix) {
|
||||
rowsToDelete = append(rowsToDelete, r)
|
||||
return true
|
||||
} else {
|
||||
return false // stop iteration
|
||||
}
|
||||
if match && start == -1 {
|
||||
start = i
|
||||
} else if !match && start != -1 {
|
||||
break
|
||||
}
|
||||
end++
|
||||
}
|
||||
if start != -1 {
|
||||
// Delete the range, using method from https://github.com/golang/go/wiki/SliceTricks
|
||||
copy(tbl.rows[start:], tbl.rows[end:])
|
||||
for k, n := len(tbl.rows)-end+start, len(tbl.rows); k < n; k++ {
|
||||
tbl.rows[k] = nil
|
||||
}
|
||||
tbl.rows = tbl.rows[:len(tbl.rows)-end+start]
|
||||
})
|
||||
for _, r := range rowsToDelete {
|
||||
tbl.rows.Delete(r)
|
||||
}
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// This is a private alpha release of Cloud Bigtable replication. This feature
|
||||
// is not currently available to most Cloud Bigtable customers. This feature
|
||||
// might be changed in backward-incompatible ways and is not recommended for
|
||||
// production use. It is not subject to any SLA or deprecation policy.
|
||||
func (s *server) GenerateConsistencyToken(ctx context.Context, req *btapb.GenerateConsistencyTokenRequest) (*btapb.GenerateConsistencyTokenResponse, error) {
|
||||
// Check that the table exists.
|
||||
_, ok := s.tables[req.Name]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
}
|
||||
|
||||
return &btapb.GenerateConsistencyTokenResponse{
|
||||
ConsistencyToken: "TokenFor-" + req.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// This is a private alpha release of Cloud Bigtable replication. This feature
|
||||
// is not currently available to most Cloud Bigtable customers. This feature
|
||||
// might be changed in backward-incompatible ways and is not recommended for
|
||||
// production use. It is not subject to any SLA or deprecation policy.
|
||||
func (s *server) CheckConsistency(ctx context.Context, req *btapb.CheckConsistencyRequest) (*btapb.CheckConsistencyResponse, error) {
|
||||
// Check that the table exists.
|
||||
_, ok := s.tables[req.Name]
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name)
|
||||
}
|
||||
|
||||
// Check this is the right token.
|
||||
if req.ConsistencyToken != "TokenFor-"+req.Name {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "token %q not valid", req.ConsistencyToken)
|
||||
}
|
||||
|
||||
// Single cluster instances are always consistent.
|
||||
return &btapb.CheckConsistencyResponse{
|
||||
Consistent: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRowsServer) error {
|
||||
s.mu.Lock()
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
|
||||
// Rows to read can be specified by a set of row keys and/or a set of row ranges.
|
||||
// Output is a stream of sorted, de-duped rows.
|
||||
tbl.mu.RLock()
|
||||
rowSet := make(map[string]*row)
|
||||
|
||||
addRow := func(i btree.Item) bool {
|
||||
r := i.(*row)
|
||||
rowSet[r.key] = r
|
||||
return true
|
||||
}
|
||||
|
||||
if req.Rows != nil {
|
||||
// Add the explicitly given keys
|
||||
for _, key := range req.Rows.RowKeys {
|
||||
start := string(key)
|
||||
addRows(start, start+"\x00", tbl, rowSet)
|
||||
k := string(key)
|
||||
if i := tbl.rows.Get(btreeKey(k)); i != nil {
|
||||
addRow(i)
|
||||
}
|
||||
}
|
||||
|
||||
// Add keys from row ranges
|
||||
@@ -300,12 +340,20 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo
|
||||
case *btpb.RowRange_EndKeyOpen:
|
||||
end = string(ek.EndKeyOpen)
|
||||
}
|
||||
|
||||
addRows(start, end, tbl, rowSet)
|
||||
switch {
|
||||
case start == "" && end == "":
|
||||
tbl.rows.Ascend(addRow) // all rows
|
||||
case start == "":
|
||||
tbl.rows.AscendLessThan(btreeKey(end), addRow)
|
||||
case end == "":
|
||||
tbl.rows.AscendGreaterOrEqual(btreeKey(start), addRow)
|
||||
default:
|
||||
tbl.rows.AscendRange(btreeKey(start), btreeKey(end), addRow)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Read all rows
|
||||
addRows("", "", tbl, rowSet)
|
||||
tbl.rows.Ascend(addRow)
|
||||
}
|
||||
tbl.mu.RUnlock()
|
||||
|
||||
@@ -332,21 +380,6 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRows(start, end string, tbl *table, rowSet map[string]*row) {
|
||||
si, ei := 0, len(tbl.rows) // half-open interval
|
||||
if start != "" {
|
||||
si = sort.Search(len(tbl.rows), func(i int) bool { return tbl.rows[i].key >= start })
|
||||
}
|
||||
if end != "" {
|
||||
ei = sort.Search(len(tbl.rows), func(i int) bool { return tbl.rows[i].key >= end })
|
||||
}
|
||||
if si < ei {
|
||||
for _, row := range tbl.rows[si:ei] {
|
||||
rowSet[row.key] = row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// streamRow filters the given row and sends it via the given stream.
|
||||
// Returns true if at least one cell matched the filter and was streamed, false otherwise.
|
||||
func streamRow(stream btpb.Bigtable_ReadRowsServer, r *row, f *btpb.RowFilter) (bool, error) {
|
||||
@@ -421,12 +454,14 @@ func filterRow(f *btpb.RowFilter, r *row) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
var count int
|
||||
for _, fam := range r.families {
|
||||
for _, cs := range fam.cells {
|
||||
sort.Sort(byDescTS(cs))
|
||||
count += len(cs)
|
||||
}
|
||||
}
|
||||
return true
|
||||
return count > 0
|
||||
case *btpb.RowFilter_CellsPerColumnLimitFilter:
|
||||
lim := int(f.CellsPerColumnLimitFilter)
|
||||
for _, fam := range r.families {
|
||||
@@ -621,12 +656,11 @@ func (s *server) MutateRow(ctx context.Context, req *btpb.MutateRowRequest) (*bt
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
fs := tbl.columnFamilies()
|
||||
r, _ := tbl.mutableRow(string(req.RowKey))
|
||||
r := tbl.mutableRow(string(req.RowKey))
|
||||
r.mu.Lock()
|
||||
defer tbl.resortRowIndex() // Make sure the row lock is released before this grabs the table lock
|
||||
defer r.mu.Unlock()
|
||||
if err := applyMutations(tbl, r, req.Mutations, fs); err != nil {
|
||||
return nil, err
|
||||
@@ -639,15 +673,14 @@ func (s *server) MutateRows(req *btpb.MutateRowsRequest, stream btpb.Bigtable_Mu
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
res := &btpb.MutateRowsResponse{Entries: make([]*btpb.MutateRowsResponse_Entry, len(req.Entries))}
|
||||
|
||||
fs := tbl.columnFamilies()
|
||||
|
||||
defer tbl.resortRowIndex()
|
||||
for i, entry := range req.Entries {
|
||||
r, _ := tbl.mutableRow(string(entry.RowKey))
|
||||
r := tbl.mutableRow(string(entry.RowKey))
|
||||
r.mu.Lock()
|
||||
code, msg := int32(codes.OK), ""
|
||||
if err := applyMutations(tbl, r, entry.Mutations, fs); err != nil {
|
||||
@@ -669,13 +702,13 @@ func (s *server) CheckAndMutateRow(ctx context.Context, req *btpb.CheckAndMutate
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
res := &btpb.CheckAndMutateRowResponse{}
|
||||
|
||||
fs := tbl.columnFamilies()
|
||||
|
||||
r, _ := tbl.mutableRow(string(req.RowKey))
|
||||
r := tbl.mutableRow(string(req.RowKey))
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
@@ -690,16 +723,13 @@ func (s *server) CheckAndMutateRow(ctx context.Context, req *btpb.CheckAndMutate
|
||||
nr := r.copy()
|
||||
filterRow(req.PredicateFilter, nr)
|
||||
whichMut = !nr.isEmpty()
|
||||
// TODO(dsymonds): Figure out if this is supposed to be set
|
||||
// even when there's no predicate filter.
|
||||
res.PredicateMatched = whichMut
|
||||
}
|
||||
res.PredicateMatched = whichMut
|
||||
muts := req.FalseMutations
|
||||
if whichMut {
|
||||
muts = req.TrueMutations
|
||||
}
|
||||
|
||||
defer tbl.resortRowIndex()
|
||||
if err := applyMutations(tbl, r, muts, fs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -824,18 +854,15 @@ func (s *server) ReadModifyWriteRow(ctx context.Context, req *btpb.ReadModifyWri
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return nil, grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
updates := make(map[string]cell) // copy of updated cells; keyed by full column name
|
||||
|
||||
fs := tbl.columnFamilies()
|
||||
|
||||
rowKey := string(req.RowKey)
|
||||
r, isNewRow := tbl.mutableRow(rowKey)
|
||||
r := tbl.mutableRow(rowKey)
|
||||
// This must be done before the row lock, acquired below, is released.
|
||||
if isNewRow {
|
||||
defer tbl.resortRowIndex()
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
// Assume all mutations apply to the most recent version of the cell.
|
||||
@@ -907,7 +934,8 @@ func (s *server) ReadModifyWriteRow(ctx context.Context, req *btpb.ReadModifyWri
|
||||
f.Columns = append(f.Columns, &btpb.Column{
|
||||
Qualifier: []byte(qual),
|
||||
Cells: []*btpb.Cell{{
|
||||
Value: cell.value,
|
||||
TimestampMicros: cell.ts,
|
||||
Value: cell.value,
|
||||
}},
|
||||
})
|
||||
}
|
||||
@@ -919,7 +947,7 @@ func (s *server) SampleRowKeys(req *btpb.SampleRowKeysRequest, stream btpb.Bigta
|
||||
tbl, ok := s.tables[req.TableName]
|
||||
s.mu.Unlock()
|
||||
if !ok {
|
||||
return grpc.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
return status.Errorf(codes.NotFound, "table %q not found", req.TableName)
|
||||
}
|
||||
|
||||
tbl.mu.RLock()
|
||||
@@ -928,20 +956,25 @@ func (s *server) SampleRowKeys(req *btpb.SampleRowKeysRequest, stream btpb.Bigta
|
||||
// The return value of SampleRowKeys is very loosely defined. Return at least the
|
||||
// final row key in the table and choose other row keys randomly.
|
||||
var offset int64
|
||||
for i, row := range tbl.rows {
|
||||
if i == len(tbl.rows)-1 || rand.Int31n(100) == 0 {
|
||||
var err error
|
||||
i := 0
|
||||
tbl.rows.Ascend(func(it btree.Item) bool {
|
||||
row := it.(*row)
|
||||
if i == tbl.rows.Len()-1 || rand.Int31n(100) == 0 {
|
||||
resp := &btpb.SampleRowKeysResponse{
|
||||
RowKey: []byte(row.key),
|
||||
OffsetBytes: offset,
|
||||
}
|
||||
err := stream.Send(resp)
|
||||
err = stream.Send(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return false
|
||||
}
|
||||
}
|
||||
offset += int64(row.size())
|
||||
}
|
||||
return nil
|
||||
i++
|
||||
return true
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// needGC is invoked whenever the server needs gcloop running.
|
||||
@@ -986,10 +1019,11 @@ type table struct {
|
||||
mu sync.RWMutex
|
||||
counter uint64 // increment by 1 when a new family is created
|
||||
families map[string]*columnFamily // keyed by plain family name
|
||||
rows []*row // sorted by row key
|
||||
rowIndex map[string]*row // indexed by row key
|
||||
rows *btree.BTree // indexed by row key
|
||||
}
|
||||
|
||||
const btreeDegree = 16
|
||||
|
||||
func newTable(ctr *btapb.CreateTableRequest) *table {
|
||||
fams := make(map[string]*columnFamily)
|
||||
c := uint64(0)
|
||||
@@ -1006,7 +1040,7 @@ func newTable(ctr *btapb.CreateTableRequest) *table {
|
||||
return &table{
|
||||
families: fams,
|
||||
counter: c,
|
||||
rowIndex: make(map[string]*row),
|
||||
rows: btree.New(btreeDegree),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,31 +1059,26 @@ func (t *table) columnFamilies() map[string]*columnFamily {
|
||||
return cp
|
||||
}
|
||||
|
||||
func (t *table) mutableRow(row string) (mutRow *row, isNewRow bool) {
|
||||
func (t *table) mutableRow(key string) *row {
|
||||
bkey := btreeKey(key)
|
||||
// Try fast path first.
|
||||
t.mu.RLock()
|
||||
r := t.rowIndex[row]
|
||||
i := t.rows.Get(bkey)
|
||||
t.mu.RUnlock()
|
||||
if r != nil {
|
||||
return r, false
|
||||
if i != nil {
|
||||
return i.(*row)
|
||||
}
|
||||
|
||||
// We probably need to create the row.
|
||||
t.mu.Lock()
|
||||
r = t.rowIndex[row]
|
||||
if r == nil {
|
||||
r = newRow(row)
|
||||
t.rowIndex[row] = r
|
||||
t.rows = append(t.rows, r)
|
||||
defer t.mu.Unlock()
|
||||
i = t.rows.Get(bkey)
|
||||
if i != nil {
|
||||
return i.(*row)
|
||||
}
|
||||
t.mu.Unlock()
|
||||
return r, true
|
||||
}
|
||||
|
||||
func (t *table) resortRowIndex() {
|
||||
t.mu.Lock()
|
||||
sort.Sort(byRowKey(t.rows))
|
||||
t.mu.Unlock()
|
||||
r := newRow(key)
|
||||
t.rows.ReplaceOrInsert(r)
|
||||
return r
|
||||
}
|
||||
|
||||
func (t *table) gc() {
|
||||
@@ -1068,11 +1097,13 @@ func (t *table) gc() {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range t.rows {
|
||||
t.rows.Ascend(func(i btree.Item) bool {
|
||||
r := i.(*row)
|
||||
r.mu.Lock()
|
||||
r.gc(rules)
|
||||
r.mu.Unlock()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
type byRowKey []*row
|
||||
@@ -1176,6 +1207,14 @@ func (r *row) size() int {
|
||||
return size
|
||||
}
|
||||
|
||||
// Less implements btree.Less.
|
||||
func (r *row) Less(i btree.Item) bool {
|
||||
return r.key < i.(*row).key
|
||||
}
|
||||
|
||||
// btreeKey returns a row for use as a key into the BTree.
|
||||
func btreeKey(s string) *row { return &row{key: s} }
|
||||
|
||||
func (r *row) String() string {
|
||||
return r.key
|
||||
}
|
||||
|
||||
+116
-12
@@ -17,6 +17,7 @@ package bttest
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2"
|
||||
btpb "google.golang.org/genproto/googleapis/bigtable/v2"
|
||||
"google.golang.org/grpc"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func TestConcurrentMutationsReadModifyAndGC(t *testing.T) {
|
||||
@@ -271,7 +271,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
}
|
||||
|
||||
doWrite()
|
||||
tblSize := len(tbl.rows)
|
||||
tblSize := tbl.rows.Len()
|
||||
req := &btapb.DropRowRangeRequest{
|
||||
Name: tblInfo.Name,
|
||||
Target: &btapb.DropRowRangeRequest_RowKeyPrefix{[]byte("AAA")},
|
||||
@@ -279,7 +279,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
if _, err = s.DropRowRange(ctx, req); err != nil {
|
||||
t.Fatalf("Dropping first range: %v", err)
|
||||
}
|
||||
got, want := len(tbl.rows), tblSize-count
|
||||
got, want := tbl.rows.Len(), tblSize-count
|
||||
if got != want {
|
||||
t.Errorf("Row count after first drop: got %d (%v), want %d", got, tbl.rows, want)
|
||||
}
|
||||
@@ -291,7 +291,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
if _, err = s.DropRowRange(ctx, req); err != nil {
|
||||
t.Fatalf("Dropping second range: %v", err)
|
||||
}
|
||||
got, want = len(tbl.rows), tblSize-(2*count)
|
||||
got, want = tbl.rows.Len(), tblSize-(2*count)
|
||||
if got != want {
|
||||
t.Errorf("Row count after second drop: got %d (%v), want %d", got, tbl.rows, want)
|
||||
}
|
||||
@@ -303,7 +303,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
if _, err = s.DropRowRange(ctx, req); err != nil {
|
||||
t.Fatalf("Dropping invalid range: %v", err)
|
||||
}
|
||||
got, want = len(tbl.rows), tblSize-(2*count)
|
||||
got, want = tbl.rows.Len(), tblSize-(2*count)
|
||||
if got != want {
|
||||
t.Errorf("Row count after invalid drop: got %d (%v), want %d", got, tbl.rows, want)
|
||||
}
|
||||
@@ -315,7 +315,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
if _, err = s.DropRowRange(ctx, req); err != nil {
|
||||
t.Fatalf("Dropping all data: %v", err)
|
||||
}
|
||||
got, want = len(tbl.rows), 0
|
||||
got, want = tbl.rows.Len(), 0
|
||||
if got != want {
|
||||
t.Errorf("Row count after drop all: got %d, want %d", got, want)
|
||||
}
|
||||
@@ -331,13 +331,13 @@ func TestDropRowRange(t *testing.T) {
|
||||
if _, err = s.DropRowRange(ctx, req); err != nil {
|
||||
t.Fatalf("Dropping all data: %v", err)
|
||||
}
|
||||
got, want = len(tbl.rows), 0
|
||||
got, want = tbl.rows.Len(), 0
|
||||
if got != want {
|
||||
t.Errorf("Row count after drop all: got %d, want %d", got, want)
|
||||
}
|
||||
|
||||
doWrite()
|
||||
got, want = len(tbl.rows), len(prefixes)
|
||||
got, want = tbl.rows.Len(), len(prefixes)
|
||||
if got != want {
|
||||
t.Errorf("Row count after rewrite: got %d, want %d", got, want)
|
||||
}
|
||||
@@ -350,7 +350,7 @@ func TestDropRowRange(t *testing.T) {
|
||||
t.Fatalf("Dropping range: %v", err)
|
||||
}
|
||||
doWrite()
|
||||
got, want = len(tbl.rows), len(prefixes)
|
||||
got, want = tbl.rows.Len(), len(prefixes)
|
||||
if got != want {
|
||||
t.Errorf("Row count after drop range: got %d, want %d", got, want)
|
||||
}
|
||||
@@ -366,6 +366,56 @@ func (s *MockReadRowsServer) Send(resp *btpb.ReadRowsResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestReadRows(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s := &server{
|
||||
tables: make(map[string]*table),
|
||||
}
|
||||
newTbl := btapb.Table{
|
||||
ColumnFamilies: map[string]*btapb.ColumnFamily{
|
||||
"cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{1}}},
|
||||
},
|
||||
}
|
||||
tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
|
||||
if err != nil {
|
||||
t.Fatalf("Creating table: %v", err)
|
||||
}
|
||||
mreq := &btpb.MutateRowRequest{
|
||||
TableName: tblInfo.Name,
|
||||
RowKey: []byte("row"),
|
||||
Mutations: []*btpb.Mutation{{
|
||||
Mutation: &btpb.Mutation_SetCell_{&btpb.Mutation_SetCell{
|
||||
FamilyName: "cf0",
|
||||
ColumnQualifier: []byte("col"),
|
||||
TimestampMicros: 1000,
|
||||
Value: []byte{},
|
||||
}},
|
||||
}},
|
||||
}
|
||||
if _, err := s.MutateRow(ctx, mreq); err != nil {
|
||||
t.Fatalf("Populating table: %v", err)
|
||||
}
|
||||
|
||||
for _, rowset := range []*btpb.RowSet{
|
||||
{RowKeys: [][]byte{[]byte("row")}},
|
||||
{RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{[]byte("")}}}},
|
||||
{RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{[]byte("r")}}}},
|
||||
{RowRanges: []*btpb.RowRange{{
|
||||
StartKey: &btpb.RowRange_StartKeyClosed{[]byte("")},
|
||||
EndKey: &btpb.RowRange_EndKeyOpen{[]byte("s")},
|
||||
}}},
|
||||
} {
|
||||
mock := &MockReadRowsServer{}
|
||||
req := &btpb.ReadRowsRequest{TableName: tblInfo.Name, Rows: rowset}
|
||||
if err = s.ReadRows(req, mock); err != nil {
|
||||
t.Fatalf("ReadRows error: %v", err)
|
||||
}
|
||||
if got, want := len(mock.responses), 1; got != want {
|
||||
t.Errorf("%+v: response count: got %d, want %d", rowset, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadRowsOrder(t *testing.T) {
|
||||
s := &server{
|
||||
tables: make(map[string]*table),
|
||||
@@ -430,7 +480,7 @@ func TestReadRowsOrder(t *testing.T) {
|
||||
t.Fatal("Response count: got 0, want > 0")
|
||||
}
|
||||
if len(mock.responses[0].Chunks) != 27 {
|
||||
t.Fatal("Chunk count: got %d, want 27", len(mock.responses[0].Chunks))
|
||||
t.Fatalf("Chunk count: got %d, want 27", len(mock.responses[0].Chunks))
|
||||
}
|
||||
testOrder := func(ms *MockReadRowsServer) {
|
||||
var prevFam, prevCol string
|
||||
@@ -480,7 +530,7 @@ func TestReadRowsOrder(t *testing.T) {
|
||||
t.Fatal("Response count: got 0, want > 0")
|
||||
}
|
||||
if len(mock.responses[0].Chunks) != 18 {
|
||||
t.Fatal("Chunk count: got %d, want 18", len(mock.responses[0].Chunks))
|
||||
t.Fatalf("Chunk count: got %d, want 18", len(mock.responses[0].Chunks))
|
||||
}
|
||||
testOrder(mock)
|
||||
|
||||
@@ -511,7 +561,61 @@ func TestReadRowsOrder(t *testing.T) {
|
||||
t.Fatal("Response count: got 0, want > 0")
|
||||
}
|
||||
if len(mock.responses[0].Chunks) != 30 {
|
||||
t.Fatal("Chunk count: got %d, want 30", len(mock.responses[0].Chunks))
|
||||
t.Fatalf("Chunk count: got %d, want 30", len(mock.responses[0].Chunks))
|
||||
}
|
||||
testOrder(mock)
|
||||
}
|
||||
|
||||
func TestCheckAndMutateRowWithoutPredicate(t *testing.T) {
|
||||
s := &server{
|
||||
tables: make(map[string]*table),
|
||||
}
|
||||
ctx := context.Background()
|
||||
newTbl := btapb.Table{
|
||||
ColumnFamilies: map[string]*btapb.ColumnFamily{
|
||||
"cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{1}}},
|
||||
},
|
||||
}
|
||||
tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
|
||||
if err != nil {
|
||||
t.Fatalf("Creating table: %v", err)
|
||||
}
|
||||
|
||||
// Populate the table
|
||||
val := []byte("value")
|
||||
mrreq := &btpb.MutateRowRequest{
|
||||
TableName: tbl.Name,
|
||||
RowKey: []byte("row-present"),
|
||||
Mutations: []*btpb.Mutation{{
|
||||
Mutation: &btpb.Mutation_SetCell_{&btpb.Mutation_SetCell{
|
||||
FamilyName: "cf",
|
||||
ColumnQualifier: []byte("col"),
|
||||
TimestampMicros: 0,
|
||||
Value: val,
|
||||
}},
|
||||
}},
|
||||
}
|
||||
if _, err := s.MutateRow(ctx, mrreq); err != nil {
|
||||
t.Fatalf("Populating table: %v", err)
|
||||
}
|
||||
|
||||
req := &btpb.CheckAndMutateRowRequest{
|
||||
TableName: tbl.Name,
|
||||
RowKey: []byte("row-not-present"),
|
||||
}
|
||||
if res, err := s.CheckAndMutateRow(ctx, req); err != nil {
|
||||
t.Errorf("CheckAndMutateRow error: %v", err)
|
||||
} else if got, want := res.PredicateMatched, false; got != want {
|
||||
t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want)
|
||||
}
|
||||
|
||||
req = &btpb.CheckAndMutateRowRequest{
|
||||
TableName: tbl.Name,
|
||||
RowKey: []byte("row-present"),
|
||||
}
|
||||
if res, err := s.CheckAndMutateRow(ctx, req); err != nil {
|
||||
t.Errorf("CheckAndMutateRow error: %v", err)
|
||||
} else if got, want := res.PredicateMatched, true; got != want {
|
||||
t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user