Skip to content

Commit 9a33505

Browse files
committed
chore: add benchmark
1 parent 9a4249b commit 9a33505

File tree

6 files changed

+302
-37
lines changed

6 files changed

+302
-37
lines changed

spannerlib/dotnet-spannerlib/Google.Cloud.SpannerLib.Tests/BasicTests.cs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
using Google.Cloud.Spanner.V1;
1+
using System.Diagnostics;
2+
using Google.Cloud.Spanner.V1;
23
using Google.Cloud.SpannerLib.Tests.MockServer;
4+
using Grpc.Core;
5+
using TypeCode = Google.Cloud.Spanner.V1.TypeCode;
36

47
namespace Google.Cloud.SpannerLib.Tests;
58

@@ -83,4 +86,111 @@ public void TestReadWriteTransaction()
8386
var commitResponse = transaction.Commit();
8487
Assert.That(commitResponse, Is.Not.Null);
8588
}
89+
90+
[Test]
91+
public void TestBenchmark()
92+
{
93+
var totalRowCount = 1000000;
94+
_fixture.SpannerMock.AddOrUpdateStatementResult(
95+
"select * from all_types",
96+
StatementResult.CreateResultSet(
97+
new List<Tuple<TypeCode, string>>
98+
{
99+
Tuple.Create(TypeCode.String, "col1"),
100+
Tuple.Create(TypeCode.String, "col2"),
101+
Tuple.Create(TypeCode.String, "col3"),
102+
Tuple.Create(TypeCode.String, "col4"),
103+
Tuple.Create(TypeCode.String, "col5"),
104+
},
105+
GenerateRandomValues(totalRowCount)));
106+
107+
using var pool = Pool.Create(ConnectionString);
108+
using var connection = pool.CreateConnection();
109+
110+
var stopwatch = Stopwatch.StartNew();
111+
using var rows = connection.Execute(new ExecuteSqlRequest { Sql = "select * from all_types" });
112+
var rowCount = 0;
113+
for (var row = rows.Next(); row != null; row = rows.Next())
114+
{
115+
rowCount++;
116+
}
117+
Assert.That(rowCount, Is.EqualTo(totalRowCount));
118+
stopwatch.Stop();
119+
Console.WriteLine(stopwatch.Elapsed);
120+
}
121+
122+
[Test]
123+
public void TestBenchmarkGrpcClient()
124+
{
125+
var totalRowCount = 1000000;
126+
_fixture.SpannerMock.AddOrUpdateStatementResult(
127+
"select * from all_types",
128+
StatementResult.CreateResultSet(
129+
new List<Tuple<TypeCode, string>>
130+
{
131+
Tuple.Create(TypeCode.String, "col1"),
132+
Tuple.Create(TypeCode.String, "col2"),
133+
Tuple.Create(TypeCode.String, "col3"),
134+
Tuple.Create(TypeCode.String, "col4"),
135+
Tuple.Create(TypeCode.String, "col5"),
136+
},
137+
GenerateRandomValues(totalRowCount)));
138+
var totalValueCount = totalRowCount * 5;
139+
var builder = new SpannerClientBuilder
140+
{
141+
Endpoint = $"http://{_fixture.Endpoint}",
142+
ChannelCredentials = ChannelCredentials.Insecure
143+
};
144+
SpannerClient client = builder.Build();
145+
var request = new CreateSessionRequest
146+
{
147+
Database = "projects/p1/instances/i1/databases/d1",
148+
Session = new Session()
149+
};
150+
var session = client.CreateSession(request);
151+
Assert.That(session, Is.Not.Null);
152+
153+
var stopwatch = Stopwatch.StartNew();
154+
var executeRequest = new ExecuteSqlRequest
155+
{
156+
Sql = "select * from all_types",
157+
Session = session.Name,
158+
};
159+
var stream = client.ExecuteStreamingSql(executeRequest);
160+
var valueCount = 0;
161+
foreach (var result in stream.GetResponseStream().ToBlockingEnumerable())
162+
{
163+
Assert.That(result, Is.Not.Null);
164+
valueCount += result.Values.Count;
165+
if (result.ChunkedValue)
166+
{
167+
valueCount--;
168+
}
169+
}
170+
Assert.That(valueCount, Is.EqualTo(totalValueCount));
171+
stopwatch.Stop();
172+
Console.WriteLine(stopwatch.Elapsed);
173+
}
174+
175+
176+
private List<object[]> GenerateRandomValues(int count)
177+
{
178+
var result = new List<object[]>(count);
179+
for (var i = 0; i < count; i++)
180+
{
181+
result.Add([
182+
GenerateRandomString(),
183+
GenerateRandomString(),
184+
GenerateRandomString(),
185+
GenerateRandomString(),
186+
GenerateRandomString(),
187+
]);
188+
}
189+
return result;
190+
}
191+
192+
private string GenerateRandomString()
193+
{
194+
return Guid.NewGuid().ToString();
195+
}
86196
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package exported
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
"time"
7+
8+
"cloud.google.com/go/spanner/apiv1/spannerpb"
9+
"google.golang.org/protobuf/proto"
10+
)
11+
12+
func TestExecute(t *testing.T) {
13+
t.Skip("only for manual testing")
14+
15+
pool := CreatePool("projects/appdev-soda-spanner-staging/instances/knut-test-probers/databases/prober")
16+
conn := CreateConnection(pool.ObjectId)
17+
request := spannerpb.ExecuteSqlRequest{Sql: "select * from all_types limit 10000"}
18+
requestBytes, err := proto.Marshal(&request)
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
23+
for range 50 {
24+
rowCount := 0
25+
start := time.Now()
26+
rows := Execute(pool.ObjectId, conn.ObjectId, requestBytes)
27+
for {
28+
row := Next(pool.ObjectId, conn.ObjectId, rows.ObjectId)
29+
if row.Length() == 0 {
30+
break
31+
}
32+
rowCount++
33+
}
34+
CloseRows(pool.ObjectId, conn.ObjectId, rows.ObjectId)
35+
end := time.Now()
36+
fmt.Printf("Execution took %s\n", end.Sub(start))
37+
if g, w := rowCount, 10000; g != w {
38+
t.Errorf("row count mismatch: got %d, want %d", g, w)
39+
}
40+
}
41+
CloseConnection(pool.ObjectId, conn.ObjectId)
42+
ClosePool(pool.ObjectId)
43+
}

spannerlib/exported/mock_server_test.go

Lines changed: 110 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"fmt"
77
"reflect"
88
"testing"
9+
"time"
910

1011
"cloud.google.com/go/spanner"
1112
"cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
1213
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
14+
"github.com/google/uuid"
1315
"github.com/googleapis/go-sql-spanner/testutil"
1416
"google.golang.org/api/option"
1517
"google.golang.org/grpc/codes"
@@ -58,6 +60,87 @@ func TestSimpleQuery(t *testing.T) {
5860
ClosePool(pool.ObjectId)
5961
}
6062

63+
func generateLargeResultSet(numRows int) *sppb.ResultSet {
64+
res := &sppb.ResultSet{
65+
Metadata: &sppb.ResultSetMetadata{
66+
RowType: &sppb.StructType{
67+
Fields: []*sppb.StructType_Field{
68+
{Type: &sppb.Type{Code: sppb.TypeCode_STRING}, Name: "col1"},
69+
{Type: &sppb.Type{Code: sppb.TypeCode_STRING}, Name: "col2"},
70+
{Type: &sppb.Type{Code: sppb.TypeCode_STRING}, Name: "col3"},
71+
{Type: &sppb.Type{Code: sppb.TypeCode_STRING}, Name: "col4"},
72+
{Type: &sppb.Type{Code: sppb.TypeCode_STRING}, Name: "col5"},
73+
},
74+
},
75+
},
76+
}
77+
rows := make([]*structpb.ListValue, 0, numRows)
78+
for i := 0; i < numRows; i++ {
79+
values := make([]*structpb.Value, 0, 5)
80+
for j := 0; j < 5; j++ {
81+
values = append(values, &structpb.Value{
82+
Kind: &structpb.Value_StringValue{StringValue: uuid.New().String()},
83+
})
84+
}
85+
rows = append(rows, &structpb.ListValue{
86+
Values: values,
87+
})
88+
}
89+
res.Rows = rows
90+
return res
91+
}
92+
93+
func TestLargeQuery(t *testing.T) {
94+
t.Skip("only for manual testing")
95+
t.Parallel()
96+
97+
dsn, server, teardown := setupTestDBConnection(t)
98+
defer teardown()
99+
100+
_ = server.TestSpanner.PutStatementResult("select * from all_types", &testutil.StatementResult{
101+
Type: testutil.StatementResultResultSet,
102+
ResultSet: generateLargeResultSet(1000000),
103+
})
104+
105+
pool := CreatePool(dsn)
106+
conn := CreateConnection(pool.ObjectId)
107+
statement := sppb.ExecuteSqlRequest{
108+
Sql: "select * from all_types",
109+
}
110+
statementBytes, err := proto.Marshal(&statement)
111+
if err != nil {
112+
t.Fatalf("failed to marshal statement: %v", err)
113+
}
114+
115+
startTime := time.Now()
116+
results := Execute(pool.ObjectId, conn.ObjectId, statementBytes)
117+
metadata := Metadata(pool.ObjectId, conn.ObjectId, results.ObjectId)
118+
if metadata.Code != 0 {
119+
t.Fatalf("metadata.Code: %v", metadata.Code)
120+
}
121+
for {
122+
row := Next(pool.ObjectId, conn.ObjectId, results.ObjectId)
123+
if row.Length() == 0 {
124+
break
125+
}
126+
values := structpb.ListValue{}
127+
if err := proto.Unmarshal(row.Res, &values); err != nil {
128+
t.Fatalf("failed to unmarshal row: %v", err)
129+
}
130+
}
131+
stats := ResultSetStats(pool.ObjectId, conn.ObjectId, results.ObjectId)
132+
if stats.Code != 0 {
133+
t.Fatalf("stats.Code: %v", stats.Code)
134+
}
135+
CloseRows(pool.ObjectId, conn.ObjectId, results.ObjectId)
136+
endTime := time.Now()
137+
138+
fmt.Printf("Query took %v\n", endTime.Sub(startTime))
139+
140+
CloseConnection(pool.ObjectId, conn.ObjectId)
141+
ClosePool(pool.ObjectId)
142+
}
143+
61144
func TestQueryWithTimestampBound(t *testing.T) {
62145
t.Parallel()
63146

@@ -285,18 +368,11 @@ func TestBufferWrite(t *testing.T) {
285368
}
286369

287370
requests := drainRequestsFromServer(server.TestSpanner)
371+
// There should not be any BeginTransaction requests yet, as we use inlined-begin.
288372
beginRequests := requestsOfType(requests, reflect.TypeOf(&sppb.BeginTransactionRequest{}))
289-
if g, w := len(beginRequests), 1; g != w {
373+
if g, w := len(beginRequests), 0; g != w {
290374
t.Fatalf("begin requests count mismatch\nGot: %v\nWant: %v", g, w)
291375
}
292-
req := beginRequests[0].(*sppb.BeginTransactionRequest)
293-
if req.Options == nil {
294-
t.Fatalf("missing tx opts")
295-
}
296-
if req.Options.GetReadWrite() == nil {
297-
t.Fatalf("missing tx read write")
298-
}
299-
300376
// There should not be any commit requests yet.
301377
commitRequests := requestsOfType(requests, reflect.TypeOf(&sppb.CommitRequest{}))
302378
if g, w := len(commitRequests), 0; g != w {
@@ -311,6 +387,17 @@ func TestBufferWrite(t *testing.T) {
311387

312388
// Verify that we have a commit request on the server.
313389
requests = drainRequestsFromServer(server.TestSpanner)
390+
beginRequests = requestsOfType(requests, reflect.TypeOf(&sppb.BeginTransactionRequest{}))
391+
if g, w := len(beginRequests), 1; g != w {
392+
t.Fatalf("begin requests count mismatch\nGot: %v\nWant: %v", g, w)
393+
}
394+
req := beginRequests[0].(*sppb.BeginTransactionRequest)
395+
if req.Options == nil {
396+
t.Fatalf("missing tx opts")
397+
}
398+
if req.Options.GetReadWrite() == nil {
399+
t.Fatalf("missing tx read write")
400+
}
314401
commitRequests = requestsOfType(requests, reflect.TypeOf(&sppb.CommitRequest{}))
315402
if g, w := len(commitRequests), 1; g != w {
316403
t.Fatalf("commit requests count mismatch\nGot: %v\nWant: %v", g, w)
@@ -368,18 +455,6 @@ func TestBufferWrite_RetryAborted(t *testing.T) {
368455
}
369456

370457
requests := drainRequestsFromServer(server.TestSpanner)
371-
beginRequests := requestsOfType(requests, reflect.TypeOf(&sppb.BeginTransactionRequest{}))
372-
if g, w := len(beginRequests), 1; g != w {
373-
t.Fatalf("begin requests count mismatch\nGot: %v\nWant: %v", g, w)
374-
}
375-
req := beginRequests[0].(*sppb.BeginTransactionRequest)
376-
if req.Options == nil {
377-
t.Fatalf("missing tx opts")
378-
}
379-
if req.Options.GetReadWrite() == nil {
380-
t.Fatalf("missing tx read write")
381-
}
382-
383458
// There should not be any commit requests yet.
384459
commitRequests := requestsOfType(requests, reflect.TypeOf(&sppb.CommitRequest{}))
385460
if g, w := len(commitRequests), 0; g != w {
@@ -397,8 +472,21 @@ func TestBufferWrite_RetryAborted(t *testing.T) {
397472
t.Fatalf("failed to commit: %v", res.Code)
398473
}
399474

400-
// Verify that we have a commit request on the server.
475+
// Verify that we have both begin and commit requests on the server.
401476
requests = drainRequestsFromServer(server.TestSpanner)
477+
beginRequests := requestsOfType(requests, reflect.TypeOf(&sppb.BeginTransactionRequest{}))
478+
if g, w := len(beginRequests), 2; g != w {
479+
t.Fatalf("begin requests count mismatch\nGot: %v\nWant: %v", g, w)
480+
}
481+
for _, beginReq := range beginRequests {
482+
req := beginReq.(*sppb.BeginTransactionRequest)
483+
if req.Options == nil {
484+
t.Fatalf("missing tx opts")
485+
}
486+
if req.Options.GetReadWrite() == nil {
487+
t.Fatalf("missing tx read write")
488+
}
489+
}
402490
commitRequests = requestsOfType(requests, reflect.TypeOf(&sppb.CommitRequest{}))
403491
if g, w := len(commitRequests), 2; g != w {
404492
t.Fatalf("commit requests count mismatch\nGot: %v\nWant: %v", g, w)

0 commit comments

Comments
 (0)