Skip to content

Commit 64bdcb1

Browse files
feat(spanner): add LockHint feature (#10382)
* feat(spanner): add LockHint feature * fix * revert TestClient_ReadWriteTransaction_Query_ReadOptions * Override lockhint in RO txn * Fix comment * fix reviews * fix review comment --------- Co-authored-by: Sri Harsha CH <[email protected]>
1 parent b53c5fb commit 64bdcb1

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

spanner/client.go

+4
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ func (c *Client) Single() *ReadOnlyTransaction {
609609
}
610610
t.txReadOnly.qo.DirectedReadOptions = c.dro
611611
t.txReadOnly.ro.DirectedReadOptions = c.dro
612+
t.txReadOnly.ro.LockHint = sppb.ReadRequest_LOCK_HINT_UNSPECIFIED
612613
t.ct = c.ct
613614
t.otConfig = c.otConfig
614615
return t
@@ -635,6 +636,7 @@ func (c *Client) ReadOnlyTransaction() *ReadOnlyTransaction {
635636
t.txReadOnly.disableRouteToLeader = true
636637
t.txReadOnly.qo.DirectedReadOptions = c.dro
637638
t.txReadOnly.ro.DirectedReadOptions = c.dro
639+
t.txReadOnly.ro.LockHint = sppb.ReadRequest_LOCK_HINT_UNSPECIFIED
638640
t.ct = c.ct
639641
t.otConfig = c.otConfig
640642
return t
@@ -706,6 +708,7 @@ func (c *Client) BatchReadOnlyTransaction(ctx context.Context, tb TimestampBound
706708
t.txReadOnly.disableRouteToLeader = true
707709
t.txReadOnly.qo.DirectedReadOptions = c.dro
708710
t.txReadOnly.ro.DirectedReadOptions = c.dro
711+
t.txReadOnly.ro.LockHint = sppb.ReadRequest_LOCK_HINT_UNSPECIFIED
709712
t.ct = c.ct
710713
t.otConfig = c.otConfig
711714
return t, nil
@@ -740,6 +743,7 @@ func (c *Client) BatchReadOnlyTransactionFromID(tid BatchReadOnlyTransactionID)
740743
t.txReadOnly.disableRouteToLeader = true
741744
t.txReadOnly.qo.DirectedReadOptions = c.dro
742745
t.txReadOnly.ro.DirectedReadOptions = c.dro
746+
t.txReadOnly.ro.LockHint = sppb.ReadRequest_LOCK_HINT_UNSPECIFIED
743747
t.ct = c.ct
744748
t.otConfig = c.otConfig
745749
return t

spanner/client_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,9 @@ func checkReqsForReadOptions(t *testing.T, server InMemSpannerServer, ro ReadOpt
877877
if got, want := sqlReq.OrderBy, ro.OrderBy; got != want {
878878
t.Fatalf("OrderBy mismatch, got %v, want %v", got, want)
879879
}
880+
if got, want := sqlReq.LockHint, ro.LockHint; got != want {
881+
t.Fatalf("LockHint mismatch, got %v, want %v", got, want)
882+
}
880883
}
881884

882885
func checkReqsForTransactionOptions(t *testing.T, server InMemSpannerServer, txo TransactionOptions) {
@@ -2143,6 +2146,89 @@ func TestClient_ReadWriteTransaction_Query_QueryOptions(t *testing.T) {
21432146
}
21442147
}
21452148

2149+
func TestClient_ReadWriteTransaction_LockHintOptions(t *testing.T) {
2150+
readOptionsTestCases := []ReadOptionsTestCase{
2151+
{
2152+
name: "Client level",
2153+
client: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2154+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2155+
},
2156+
{
2157+
name: "Read level",
2158+
client: &ReadOptions{},
2159+
read: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2160+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2161+
},
2162+
{
2163+
name: "Read level has precedence than client level",
2164+
client: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_SHARED},
2165+
read: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2166+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2167+
},
2168+
{
2169+
name: "Client level has precendence when LOCK_HINT_UNSPECIFIED at read level",
2170+
client: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2171+
read: &ReadOptions{},
2172+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2173+
},
2174+
}
2175+
2176+
for _, tt := range readOptionsTestCases {
2177+
t.Run(tt.name, func(t *testing.T) {
2178+
ctx := context.Background()
2179+
server, client, teardown := setupMockedTestServerWithConfig(t, ClientConfig{ReadOptions: *tt.client})
2180+
defer teardown()
2181+
2182+
_, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error {
2183+
var iter *RowIterator
2184+
if tt.read == nil {
2185+
iter = tx.Read(ctx, "Albums", KeySets(Key{"foo"}), []string{"SingerId", "AlbumId", "AlbumTitle"})
2186+
} else {
2187+
iter = tx.ReadWithOptions(ctx, "Albums", KeySets(Key{"foo"}), []string{"SingerId", "AlbumId", "AlbumTitle"}, tt.read)
2188+
}
2189+
testReadOptions(t, iter, server.TestSpanner, *tt.want)
2190+
return nil
2191+
})
2192+
if err != nil {
2193+
t.Fatal(err)
2194+
}
2195+
})
2196+
}
2197+
}
2198+
2199+
func TestClient_ReadOnlyTransaction_LockHintOptions(t *testing.T) {
2200+
readOptionsTestCases := []ReadOptionsTestCase{
2201+
{
2202+
name: "Client level Lock hint overiden in request level",
2203+
client: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2204+
read: &ReadOptions{},
2205+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_UNSPECIFIED},
2206+
},
2207+
{
2208+
name: "Request level",
2209+
client: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_EXCLUSIVE},
2210+
read: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_SHARED},
2211+
want: &ReadOptions{LockHint: sppb.ReadRequest_LOCK_HINT_SHARED},
2212+
},
2213+
}
2214+
2215+
for _, tt := range readOptionsTestCases {
2216+
t.Run(tt.name, func(t *testing.T) {
2217+
ctx := context.Background()
2218+
server, client, teardown := setupMockedTestServerWithConfig(t, ClientConfig{ReadOptions: *tt.client})
2219+
defer teardown()
2220+
2221+
for _, tx := range []*ReadOnlyTransaction{
2222+
client.Single(),
2223+
client.ReadOnlyTransaction(),
2224+
} {
2225+
iter := tx.ReadWithOptions(ctx, "Albums", KeySets(Key{"foo"}), []string{"SingerId", "AlbumId", "AlbumTitle"}, tt.read)
2226+
testReadOptions(t, iter, server.TestSpanner, *tt.want)
2227+
}
2228+
2229+
})
2230+
}
2231+
}
21462232
func TestClient_ReadWriteTransaction_Query_ReadOptions(t *testing.T) {
21472233
for _, tt := range readOptionsTestCases() {
21482234
t.Run(tt.name, func(t *testing.T) {

spanner/transaction.go

+14
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ type ReadOptions struct {
185185

186186
// An option to control the order in which rows are returned from a read.
187187
OrderBy sppb.ReadRequest_OrderBy
188+
189+
// A lock hint mechanism to use for this request. This setting is only applicable for
190+
// read-write transaction as as read-only transactions do not take locks.
191+
LockHint sppb.ReadRequest_LockHint
188192
}
189193

190194
// merge combines two ReadOptions that the input parameter will have higher
@@ -198,6 +202,7 @@ func (ro ReadOptions) merge(opts ReadOptions) ReadOptions {
198202
DataBoostEnabled: ro.DataBoostEnabled,
199203
DirectedReadOptions: ro.DirectedReadOptions,
200204
OrderBy: ro.OrderBy,
205+
LockHint: ro.LockHint,
201206
}
202207
if opts.Index != "" {
203208
merged.Index = opts.Index
@@ -220,6 +225,9 @@ func (ro ReadOptions) merge(opts ReadOptions) ReadOptions {
220225
if opts.OrderBy != sppb.ReadRequest_ORDER_BY_UNSPECIFIED {
221226
merged.OrderBy = opts.OrderBy
222227
}
228+
if opts.LockHint != sppb.ReadRequest_LOCK_HINT_UNSPECIFIED {
229+
merged.LockHint = opts.LockHint
230+
}
223231
return merged
224232
}
225233

@@ -253,6 +261,7 @@ func (t *txReadOnly) ReadWithOptions(ctx context.Context, table string, keys Key
253261
dataBoostEnabled := t.ro.DataBoostEnabled
254262
directedReadOptions := t.ro.DirectedReadOptions
255263
orderBy := t.ro.OrderBy
264+
lockHint := t.ro.LockHint
256265
if opts != nil {
257266
index = opts.Index
258267
if opts.Limit > 0 {
@@ -269,6 +278,10 @@ func (t *txReadOnly) ReadWithOptions(ctx context.Context, table string, keys Key
269278
if opts.OrderBy != sppb.ReadRequest_ORDER_BY_UNSPECIFIED {
270279
orderBy = opts.OrderBy
271280
}
281+
if opts.LockHint != sppb.ReadRequest_LOCK_HINT_UNSPECIFIED {
282+
lockHint = opts.LockHint
283+
}
284+
272285
}
273286
var setTransactionID func(transactionID)
274287
if _, ok := ts.Selector.(*sppb.TransactionSelector_Begin); ok {
@@ -297,6 +310,7 @@ func (t *txReadOnly) ReadWithOptions(ctx context.Context, table string, keys Key
297310
DataBoostEnabled: dataBoostEnabled,
298311
DirectedReadOptions: directedReadOptions,
299312
OrderBy: orderBy,
313+
LockHint: lockHint,
300314
})
301315
if err != nil {
302316
if _, ok := t.getTransactionSelector().GetSelector().(*sppb.TransactionSelector_Begin); ok {

0 commit comments

Comments
 (0)