diff --git a/pkg/frontend/test/mock_lock/types.go b/pkg/frontend/test/mock_lock/types.go index 451518f3a0f78..f1a00b1ab4144 100644 --- a/pkg/frontend/test/mock_lock/types.go +++ b/pkg/frontend/test/mock_lock/types.go @@ -261,6 +261,22 @@ func (mr *MockLockServiceMockRecorder) GetLockTableBind(group, tableID any) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLockTableBind", reflect.TypeOf((*MockLockService)(nil).GetLockTableBind), group, tableID) } +// GetLockHolder mocks base method. +func (m *MockLockService) GetLockHolder(ctx context.Context, tableID uint64, row []byte, options lock.LockOptions) (lock.WaitTxn, bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLockHolder", ctx, tableID, row, options) + ret0, _ := ret[0].(lock.WaitTxn) + ret1, _ := ret[1].(bool) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetLockHolder indicates an expected call of GetLockHolder. +func (mr *MockLockServiceMockRecorder) GetLockHolder(ctx, tableID, row, options any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLockHolder", reflect.TypeOf((*MockLockService)(nil).GetLockHolder), ctx, tableID, row, options) +} + // GetServiceID mocks base method. func (m *MockLockService) GetServiceID() string { m.ctrl.T.Helper() diff --git a/pkg/incrservice/store_sql_test.go b/pkg/incrservice/store_sql_test.go index 25f05bb3fed80..44536a37f1733 100644 --- a/pkg/incrservice/store_sql_test.go +++ b/pkg/incrservice/store_sql_test.go @@ -138,6 +138,11 @@ func (tls *testLockService) GetWaitingList(ctx context.Context, txnID []byte) (b panic("implement me") } +func (tls *testLockService) GetLockHolder(ctx context.Context, tableID uint64, row []byte, options lock.LockOptions) (lock.WaitTxn, bool, error) { + //TODO implement me + panic("implement me") +} + func (tls *testLockService) ForceRefreshLockTableBinds(targets []uint64, matcher func(bind lock.LockTable) bool) { //TODO implement me panic("implement me") diff --git a/pkg/lockservice/lock_table_local.go b/pkg/lockservice/lock_table_local.go index dd537acced514..f51cf3a4befff 100644 --- a/pkg/lockservice/lock_table_local.go +++ b/pkg/lockservice/lock_table_local.go @@ -354,6 +354,26 @@ func (l *localLockTable) getLock( } } +func (l *localLockTable) getLockHolder(ctx context.Context, key []byte) (pb.WaitTxn, bool, error) { + l.mu.RLock() + defer l.mu.RUnlock() + if l.mu.closed { + return pb.WaitTxn{}, false, nil + } + lock, ok := l.mu.store.Get(key) + if !ok { + return pb.WaitTxn{}, false, nil + } + var holder pb.WaitTxn + var found bool + lock.IterHolders(func(v pb.WaitTxn) bool { + holder = v + found = true + return false + }) + return holder, found, nil +} + func (l *localLockTable) getBind() pb.LockTable { return l.bind } diff --git a/pkg/lockservice/lock_table_proxy.go b/pkg/lockservice/lock_table_proxy.go index a694bcb918df0..360a708c0c164 100644 --- a/pkg/lockservice/lock_table_proxy.go +++ b/pkg/lockservice/lock_table_proxy.go @@ -202,6 +202,10 @@ func (lp *localLockTableProxy) getLock( lp.remote.getLock(key, txn, fn) } +func (lp *localLockTableProxy) getLockHolder(ctx context.Context, key []byte) (pb.WaitTxn, bool, error) { + return lp.remote.getLockHolder(ctx, key) +} + func (lp *localLockTableProxy) getBind() pb.LockTable { return lp.remote.getBind() } diff --git a/pkg/lockservice/lock_table_remote.go b/pkg/lockservice/lock_table_remote.go index 869c16deb2d74..7a4d657474dec 100644 --- a/pkg/lockservice/lock_table_remote.go +++ b/pkg/lockservice/lock_table_remote.go @@ -242,12 +242,52 @@ func (l *remoteLockTable) getLock( } } +func (l *remoteLockTable) getLockHolder(ctx context.Context, key []byte) (pb.WaitTxn, bool, error) { + backoff := remoteRetryInitialBackoff + for { + if err := ctx.Err(); err != nil { + return pb.WaitTxn{}, false, err + } + holder, ok, err := l.doGetLockHolder(ctx, key) + if err == nil { + return holder, ok, nil + } + if err := ctx.Err(); err != nil { + return pb.WaitTxn{}, false, err + } + if err = l.handleError(err, false); err == nil { + // The bind-change handler replaces the lock-table object in service.tableGroups. + // This in-flight remote table still carries the stale bind, so let the service + // reacquire the current table before retrying the holder lookup. + return pb.WaitTxn{}, false, ErrLockTableBindChanged + } + if err := waitRemoteRetryBackoffWithContext(ctx, backoff); err != nil { + return pb.WaitTxn{}, false, err + } + backoff = nextRemoteRetryBackoff(backoff) + } +} + func waitRemoteRetryBackoff(backoff time.Duration) { if backoff > 0 { time.Sleep(backoff) } } +func waitRemoteRetryBackoffWithContext(ctx context.Context, backoff time.Duration) error { + if backoff <= 0 { + return ctx.Err() + } + timer := time.NewTimer(backoff) + defer timer.Stop() + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + return nil + } +} + func nextRemoteRetryBackoff(backoff time.Duration) time.Duration { if backoff <= 0 { return remoteRetryInitialBackoff @@ -320,6 +360,32 @@ func (l *remoteLockTable) doGetLock(key []byte, txn pb.WaitTxn) (Lock, bool, err return Lock{}, false, moerr.AttachCause(ctx, err) } +func (l *remoteLockTable) doGetLockHolder(ctx context.Context, key []byte) (pb.WaitTxn, bool, error) { + ctx, cancel := context.WithTimeoutCause(ctx, defaultRPCTimeout, moerr.CauseDoGetLock) + defer cancel() + + req := acquireRequest() + defer releaseRequest(req) + + req.Method = pb.Method_GetLockHolder + req.LockTable = l.bind + req.GetLockHolder.Row = key + req.GetLockHolder.Sharding = l.bind.Sharding + + resp, err := l.client.Send(ctx, req) + if err == nil { + defer releaseResponse(resp) + if err := l.maybeHandleBindChanged(resp); err != nil { + return pb.WaitTxn{}, false, err + } + if len(resp.GetLockHolder.Holder.TxnID) == 0 { + return pb.WaitTxn{}, false, nil + } + return resp.GetLockHolder.Holder, true, nil + } + return pb.WaitTxn{}, false, moerr.AttachCause(ctx, err) +} + func (l *remoteLockTable) getBind() pb.LockTable { return l.bind } diff --git a/pkg/lockservice/lock_table_remote_test.go b/pkg/lockservice/lock_table_remote_test.go index 85b7f03cd3631..3312e1f249887 100644 --- a/pkg/lockservice/lock_table_remote_test.go +++ b/pkg/lockservice/lock_table_remote_test.go @@ -384,6 +384,133 @@ func TestGetLockRemoteWithRetry(t *testing.T) { ) } +func TestGetLockHolderRemoteReturnsBindChangedAfterBindRefresh(t *testing.T) { + oldInitial := remoteRetryInitialBackoff + oldMaxBackoff := remoteRetryMaxBackoff + remoteRetryInitialBackoff = time.Millisecond + remoteRetryMaxBackoff = time.Millisecond + defer func() { + remoteRetryInitialBackoff = oldInitial + remoteRetryMaxBackoff = oldMaxBackoff + }() + + n := 0 + refreshedBind := pb.LockTable{ServiceID: "s1", Table: 1, Version: 2} + runRemoteLockTableTests( + t, + pb.LockTable{ServiceID: "s1", Table: 1, Version: 1}, + func(s Server) { + s.RegisterMethodHandler( + pb.Method_GetLockHolder, + func( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + n++ + writeResponse(getLogger(""), cancel, resp, moerr.NewRPCTimeout(ctx), cs) + }, + ) + s.RegisterMethodHandler( + pb.Method_GetBind, + func( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + resp.GetBind.LockTable = refreshedBind + writeResponse(getLogger(""), cancel, resp, nil, cs) + }, + ) + }, + func(l *remoteLockTable, s Server) { + _, ok, err := l.getLockHolder(context.Background(), []byte("row1")) + require.True(t, moerr.IsMoErrCode(err, moerr.ErrLockTableBindChanged)) + require.False(t, ok) + require.Equal(t, 1, n) + }, + func(lt pb.LockTable) {}, + ) +} + +func TestGetLockHolderRemoteCarriesSharding(t *testing.T) { + runRemoteLockTableTests( + t, + pb.LockTable{ServiceID: "s1", Table: 1, Sharding: pb.Sharding_ByRow}, + func(s Server) { + s.RegisterMethodHandler( + pb.Method_GetLockHolder, + func( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + require.Equal(t, pb.Sharding_ByRow, req.GetLockHolder.Sharding) + writeResponse(getLogger(""), cancel, resp, nil, cs) + }, + ) + }, + func(l *remoteLockTable, s Server) { + _, ok, err := l.getLockHolder(context.Background(), []byte("row1")) + require.NoError(t, err) + require.False(t, ok) + }, + func(lt pb.LockTable) {}, + ) +} + +func TestGetLockHolderRemoteStopsRetryWhenContextCanceled(t *testing.T) { + oldInitial := remoteRetryInitialBackoff + oldMaxBackoff := remoteRetryMaxBackoff + remoteRetryInitialBackoff = time.Millisecond + remoteRetryMaxBackoff = time.Millisecond + defer func() { + remoteRetryInitialBackoff = oldInitial + remoteRetryMaxBackoff = oldMaxBackoff + }() + + runRemoteLockTableTests( + t, + pb.LockTable{ServiceID: "s1", Table: 1, Version: 1}, + func(s Server) { + s.RegisterMethodHandler( + pb.Method_GetLockHolder, + func( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + writeResponse(getLogger(""), cancel, resp, moerr.NewRPCTimeout(ctx), cs) + }, + ) + s.RegisterMethodHandler( + pb.Method_GetBind, + func( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + resp.GetBind.LockTable = req.LockTable + writeResponse(getLogger(""), cancel, resp, nil, cs) + }, + ) + }, + func(l *remoteLockTable, s Server) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + _, ok, err := l.getLockHolder(ctx, []byte("row1")) + require.ErrorIs(t, err, context.Canceled) + require.False(t, ok) + }, + func(lt pb.LockTable) {}, + ) +} + func TestRemoteWithBindChanged(t *testing.T) { newBind := pb.LockTable{ ServiceID: "s2", diff --git a/pkg/lockservice/rpc.go b/pkg/lockservice/rpc.go index 0b50f96446b3e..fdad2ce3dd50d 100644 --- a/pkg/lockservice/rpc.go +++ b/pkg/lockservice/rpc.go @@ -170,6 +170,7 @@ func (c *client) AsyncSend(ctx context.Context, request *pb.Request) (*morpc.Fut case pb.Method_Lock, pb.Method_Unlock, pb.Method_GetTxnLock, + pb.Method_GetLockHolder, pb.Method_KeepRemoteLock: sid = getUUIDFromServiceIdentifier(request.LockTable.ServiceID) c.cluster.GetCNServiceWithoutWorkingState( diff --git a/pkg/lockservice/service_observability.go b/pkg/lockservice/service_observability.go index 37c9061e6a1a0..9997846bf46fc 100644 --- a/pkg/lockservice/service_observability.go +++ b/pkg/lockservice/service_observability.go @@ -17,6 +17,7 @@ package lockservice import ( "context" + "github.com/matrixorigin/matrixone/pkg/common/moerr" pb "github.com/matrixorigin/matrixone/pkg/pb/lock" ) @@ -49,6 +50,30 @@ func (s *service) GetWaitingList( return true, waitingList, nil } +func (s *service) GetLockHolder( + ctx context.Context, + tableID uint64, + row []byte, + options pb.LockOptions) (pb.WaitTxn, bool, error) { + s.wait() + for { + if err := ctx.Err(); err != nil { + return pb.WaitTxn{}, false, err + } + s.bindChangeMu.RLock() + l, err := s.getLockTableWithCreate(options.Group, tableID, [][]byte{row}, options.Sharding) + if err != nil { + s.bindChangeMu.RUnlock() + return pb.WaitTxn{}, false, err + } + holder, ok, err := l.getLockHolder(ctx, row) + s.bindChangeMu.RUnlock() + if !moerr.IsMoErrCode(err, moerr.ErrLockTableBindChanged) { + return holder, ok, err + } + } +} + func (s *service) ForceRefreshLockTableBinds( targets []uint64, matcher func(bind pb.LockTable) bool) { diff --git a/pkg/lockservice/service_observability_test.go b/pkg/lockservice/service_observability_test.go index a3c4f412a779a..e4b2f343e8393 100644 --- a/pkg/lockservice/service_observability_test.go +++ b/pkg/lockservice/service_observability_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "github.com/matrixorigin/matrixone/pkg/common/morpc" pb "github.com/matrixorigin/matrixone/pkg/pb/lock" "github.com/matrixorigin/matrixone/pkg/pb/timestamp" "github.com/stretchr/testify/assert" @@ -90,6 +91,248 @@ func TestGetWaitingList(t *testing.T) { ) } +func TestGetLockHolder(t *testing.T) { + runLockServiceTests( + t, + []string{"s1", "s2"}, + func(alloc *lockTableAllocator, s []*service) { + l1 := s[0] + l2 := s[1] + + ctx, cancel := context.WithTimeout( + context.Background(), + time.Second*10) + defer cancel() + + table := uint64(10) + row := []byte{1} + txnID := []byte("txn1") + option := pb.LockOptions{ + Granularity: pb.Granularity_Row, + Mode: pb.LockMode_Exclusive, + Policy: pb.WaitPolicy_Wait, + } + + _, err := l1.Lock( + ctx, + table, + [][]byte{row}, + txnID, + option) + require.NoError(t, err) + + holder, ok, err := l2.GetLockHolder(ctx, table, row, option) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, txnID, holder.TxnID) + + _, ok, err = l2.GetLockHolder(ctx, table, []byte{2}, option) + require.NoError(t, err) + require.False(t, ok) + + require.NoError(t, l1.Unlock( + ctx, + txnID, + timestamp.Timestamp{PhysicalTime: 1})) + }, + ) +} + +func TestGetLockHolderReacquiresLockTableAfterBindChanged(t *testing.T) { + runLockServiceTests( + t, + []string{"s1", "s2"}, + func(alloc *lockTableAllocator, s []*service) { + l2 := s[1] + + ctx, cancel := context.WithTimeout( + context.Background(), + time.Second*10) + defer cancel() + + table := uint64(11) + row := []byte{1} + holder := pb.WaitTxn{TxnID: []byte("txn-new-holder")} + oldBind := pb.LockTable{ + Group: 0, + Table: table, + OriginTable: table, + ServiceID: "stale-service", + Version: 1, + Valid: true, + } + newBind := pb.LockTable{ + Group: 0, + Table: table, + OriginTable: table, + ServiceID: l2.serviceID, + Version: 2, + Valid: true, + } + + newTable := &getLockHolderTestTable{ + bind: newBind, + holder: holder, + found: true, + } + client := &getLockHolderBindChangedClient{ + t: t, + wantBind: oldBind, + newBind: newBind, + } + staleRemote := newRemoteLockTable( + l2.serviceID, + time.Second, + oldBind, + client, + func(bind pb.LockTable) { + require.Equal(t, newBind, bind) + l2.tableGroups.set(bind.Group, bind.Table, newTable) + }, + l2.logger, + ) + l2.tableGroups.set(oldBind.Group, oldBind.Table, staleRemote) + + got, ok, err := l2.GetLockHolder(ctx, table, row, pb.LockOptions{ + Granularity: pb.Granularity_Row, + Mode: pb.LockMode_Exclusive, + Policy: pb.WaitPolicy_Wait, + }) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, holder, got) + require.Equal(t, 1, client.calls) + require.Equal(t, 1, newTable.calls) + require.Same(t, newTable, l2.tableGroups.get(newBind.Group, newBind.Table)) + }, + ) +} + +func TestGetLockHolderHoldsBindChangeLockAcrossLocalLookup(t *testing.T) { + runLockServiceTests( + t, + []string{"s1"}, + func(alloc *lockTableAllocator, s []*service) { + l := s[0] + + ctx, cancel := context.WithTimeout( + context.Background(), + time.Second*10) + defer cancel() + + table := uint64(12) + row := []byte{1} + holder := pb.WaitTxn{TxnID: []byte("txn-holder")} + bind := pb.LockTable{ + Group: 0, + Table: table, + OriginTable: table, + ServiceID: l.serviceID, + Version: 1, + Valid: true, + } + lockTable := &getLockHolderTestTable{ + bind: bind, + holder: holder, + found: true, + onGetLockHolder: func() { + if l.bindChangeMu.TryLock() { + l.bindChangeMu.Unlock() + require.Fail(t, "GetLockHolder must hold bindChangeMu while reading a local lock table") + } + }, + } + l.tableGroups.set(bind.Group, bind.Table, lockTable) + + got, ok, err := l.GetLockHolder(ctx, table, row, pb.LockOptions{ + Granularity: pb.Granularity_Row, + Mode: pb.LockMode_Exclusive, + Policy: pb.WaitPolicy_Wait, + }) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, holder, got) + require.Equal(t, 1, lockTable.calls) + }, + ) +} + +type getLockHolderBindChangedClient struct { + t *testing.T + wantBind pb.LockTable + newBind pb.LockTable + calls int +} + +func (c *getLockHolderBindChangedClient) Send( + ctx context.Context, + req *pb.Request) (*pb.Response, error) { + c.calls++ + require.Equal(c.t, pb.Method_GetLockHolder, req.Method) + require.Equal(c.t, c.wantBind, req.LockTable) + resp := acquireResponse() + resp.NewBind = &c.newBind + return resp, nil +} + +func (c *getLockHolderBindChangedClient) AsyncSend( + ctx context.Context, + req *pb.Request) (*morpc.Future, error) { + panic("unexpected async send") +} + +func (c *getLockHolderBindChangedClient) Close() error { + return nil +} + +type getLockHolderTestTable struct { + bind pb.LockTable + holder pb.WaitTxn + found bool + calls int + onGetLockHolder func() +} + +func (l *getLockHolderTestTable) lock( + ctx context.Context, + txn *activeTxn, + rows [][]byte, + options LockOptions, + cb func(pb.Result, error)) { + panic("unexpected lock") +} + +func (l *getLockHolderTestTable) unlock( + txn *activeTxn, + ls *cowSlice, + commitTS timestamp.Timestamp, + mutations ...pb.ExtraMutation) { + panic("unexpected unlock") +} + +func (l *getLockHolderTestTable) getLock( + key []byte, + txn pb.WaitTxn, + fn func(Lock)) { + panic("unexpected getLock") +} + +func (l *getLockHolderTestTable) getLockHolder( + ctx context.Context, + key []byte) (pb.WaitTxn, bool, error) { + l.calls++ + if l.onGetLockHolder != nil { + l.onGetLockHolder() + } + return l.holder, l.found, nil +} + +func (l *getLockHolderTestTable) getBind() pb.LockTable { + return l.bind +} + +func (l *getLockHolderTestTable) close(reason closeReason) {} + func TestForceRefreshLockTableBinds(t *testing.T) { runBindChangedTests( t, diff --git a/pkg/lockservice/service_remote.go b/pkg/lockservice/service_remote.go index beefd182b2c4a..83f0f91ff1dca 100644 --- a/pkg/lockservice/service_remote.go +++ b/pkg/lockservice/service_remote.go @@ -35,6 +35,7 @@ var methodVersions = map[pb.Method]int64{ pb.Method_ForwardLock: defines.MORPCVersion1, pb.Method_Unlock: defines.MORPCVersion1, pb.Method_GetTxnLock: defines.MORPCVersion1, + pb.Method_GetLockHolder: defines.MORPCVersion2, pb.Method_GetWaitingList: defines.MORPCVersion1, pb.Method_KeepRemoteLock: defines.MORPCVersion1, pb.Method_GetBind: defines.MORPCVersion1, @@ -166,6 +167,8 @@ func (s *service) initRemoteHandler() { s.handleRemoteUnlock) s.remote.server.RegisterMethodHandler(pb.Method_GetTxnLock, s.handleRemoteGetLock) + s.remote.server.RegisterMethodHandler(pb.Method_GetLockHolder, + s.handleRemoteGetLockHolder) s.remote.server.RegisterMethodHandler(pb.Method_GetWaitingList, s.handleRemoteGetWaitingList) s.remote.server.RegisterMethodHandler(pb.Method_KeepRemoteLock, @@ -427,6 +430,28 @@ func (s *service) handleRemoteGetLock( writeResponse(s.logger, cancel, resp, err, cs) } +func (s *service) handleRemoteGetLockHolder( + ctx context.Context, + cancel context.CancelFunc, + req *pb.Request, + resp *pb.Response, + cs morpc.ClientSession) { + s.bindChangeMu.RLock() + l, err := s.getLocalLockTable(req, resp) + if err != nil || l == nil { + s.bindChangeMu.RUnlock() + writeResponse(s.logger, cancel, resp, err, cs) + return + } + + holder, found, err := l.getLockHolder(ctx, req.GetLockHolder.Row) + s.bindChangeMu.RUnlock() + if err == nil && found { + resp.GetLockHolder.Holder = holder + } + writeResponse(s.logger, cancel, resp, err, cs) +} + func (s *service) handleRemoteGetWaitingList( ctx context.Context, cancel context.CancelFunc, @@ -480,11 +505,12 @@ func (s *service) getLocalLockTable( return nil, err } if l == nil { + rows, sharding := lockTableLookupInputsFromRequest(req) l, err = s.getLockTableWithCreate( req.LockTable.Group, req.LockTable.Table, - req.Lock.Rows, - req.Lock.Options.Sharding) + rows, + sharding) if err != nil || l.getBind().Changed(req.LockTable) { return nil, ErrLockTableNotFound } @@ -529,6 +555,17 @@ func (s *service) getLocalLockTable( return l, nil } +func lockTableLookupInputsFromRequest(req *pb.Request) ([][]byte, pb.Sharding) { + switch req.Method { + case pb.Method_GetLockHolder: + return [][]byte{req.GetLockHolder.Row}, req.GetLockHolder.Sharding + case pb.Method_GetTxnLock: + return [][]byte{req.GetTxnLock.Row}, req.LockTable.Sharding + default: + return req.Lock.Rows, req.Lock.Options.Sharding + } +} + func (s *service) getTxnWaitingListOnRemote( txnID []byte, createdOn string) ([]pb.WaitTxn, error) { diff --git a/pkg/lockservice/service_remote_test.go b/pkg/lockservice/service_remote_test.go index b74bca603a14f..70f26fc3b9fa1 100644 --- a/pkg/lockservice/service_remote_test.go +++ b/pkg/lockservice/service_remote_test.go @@ -61,6 +61,32 @@ func TestLockBlockedOnRemote(t *testing.T) { ) } +func TestGetLocalLockTableUsesGetLockHolderLookupInputs(t *testing.T) { + runLockServiceTests( + t, + []string{"s1"}, + func(alloc *lockTableAllocator, s []*service) { + l := s[0] + originTableID := uint64(10) + row := []byte("row1") + tableID := ShardingByRow(row) + bind := alloc.Get(l.serviceID, 0, tableID, originTableID, pb.Sharding_ByRow) + req := &pb.Request{ + Method: pb.Method_GetLockHolder, + LockTable: bind, + } + req.GetLockHolder.Row = row + req.GetLockHolder.Sharding = pb.Sharding_ByRow + resp := &pb.Response{} + + lt, err := l.getLocalLockTable(req, resp) + require.NoError(t, err) + require.NotNil(t, lt) + require.Equal(t, bind, lt.getBind()) + }, + ) +} + func TestRemoteLockResponseLogFieldsDoNotRetainRequest(t *testing.T) { req := &pb.Request{ LockTable: pb.LockTable{ diff --git a/pkg/lockservice/types.go b/pkg/lockservice/types.go index 3196c5c384464..b34226d6586f1 100644 --- a/pkg/lockservice/types.go +++ b/pkg/lockservice/types.go @@ -116,6 +116,8 @@ type LockService interface { // GetWaitingList get special txnID's waiting list GetWaitingList(ctx context.Context, txnID []byte) (bool, []pb.WaitTxn, error) + // GetLockHolder returns the current holder of a row lock if it exists. + GetLockHolder(ctx context.Context, tableID uint64, row []byte, options pb.LockOptions) (pb.WaitTxn, bool, error) // ForceRefreshLockTableBinds force refresh all lock tables binds ForceRefreshLockTableBinds(targets []uint64, matcher func(bind pb.LockTable) bool) // GetLockTableBind returns lock table bind @@ -156,6 +158,8 @@ type lockTable interface { unlock(txn *activeTxn, ls *cowSlice, commitTS timestamp.Timestamp, mutations ...pb.ExtraMutation) // getLock get a lock getLock(key []byte, txn pb.WaitTxn, fn func(Lock)) + // getLockHolder returns the current holder if the lock is actively held. + getLockHolder(ctx context.Context, key []byte) (pb.WaitTxn, bool, error) // getBind returns lock table binding getBind() pb.LockTable // close close the locktable diff --git a/pkg/pb/lock/lock.pb.go b/pkg/pb/lock/lock.pb.go index 2e30860a91c0b..f28dbf10d3cec 100644 --- a/pkg/pb/lock/lock.pb.go +++ b/pkg/pb/lock/lock.pb.go @@ -170,6 +170,8 @@ const ( Method_ResumeInvalidCN Method = 16 // AbortRemoteDeadlockTxn abort remote txn for deadlock Method_AbortRemoteDeadlockTxn Method = 17 + // GetLockHolder get current holder on a special lock + Method_GetLockHolder Method = 18 ) var Method_name = map[int32]string{ @@ -191,6 +193,7 @@ var Method_name = map[int32]string{ 15: "CheckOrphan", 16: "ResumeInvalidCN", 17: "AbortRemoteDeadlockTxn", + 18: "GetLockHolder", } var Method_value = map[string]int32{ @@ -212,6 +215,7 @@ var Method_value = map[string]int32{ "CheckOrphan": 15, "ResumeInvalidCN": 16, "AbortRemoteDeadlockTxn": 17, + "GetLockHolder": 18, } func (x Method) String() string { @@ -488,6 +492,7 @@ type Request struct { RemainTxnInService RemainTxnInServiceRequest `protobuf:"bytes,16,opt,name=RemainTxnInService,proto3" json:"RemainTxnInService"` CheckOrphan CheckOrphanRequest `protobuf:"bytes,17,opt,name=CheckOrphan,proto3" json:"CheckOrphan"` ResumeInvalidCN ResumeInvalidCNRequest `protobuf:"bytes,18,opt,name=ResumeInvalidCN,proto3" json:"ResumeInvalidCN"` + GetLockHolder GetLockHolderRequest `protobuf:"bytes,19,opt,name=GetLockHolder,proto3" json:"GetLockHolder"` AbortRemoteDeadlockTxn AbortRemoteDeadlockTxnRequest `protobuf:"bytes,20,opt,name=AbortRemoteDeadlockTxn,proto3" json:"AbortRemoteDeadlockTxn"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -653,6 +658,13 @@ func (m *Request) GetResumeInvalidCN() ResumeInvalidCNRequest { return ResumeInvalidCNRequest{} } +func (m *Request) GetGetLockHolder() GetLockHolderRequest { + if m != nil { + return m.GetLockHolder + } + return GetLockHolderRequest{} +} + func (m *Request) GetAbortRemoteDeadlockTxn() AbortRemoteDeadlockTxnRequest { if m != nil { return m.AbortRemoteDeadlockTxn @@ -685,6 +697,7 @@ type Response struct { CheckOrphan CheckOrphanResponse `protobuf:"bytes,18,opt,name=CheckOrphan,proto3" json:"CheckOrphan"` ResumeInvalidCN ResumeInvalidCNResponse `protobuf:"bytes,19,opt,name=ResumeInvalidCN,proto3" json:"ResumeInvalidCN"` AbortRemoteDeadlockTxn AbortRemoteDeadlockTxnResponse `protobuf:"bytes,20,opt,name=AbortRemoteDeadlockTxn,proto3" json:"AbortRemoteDeadlockTxn"` + GetLockHolder GetLockHolderResponse `protobuf:"bytes,21,opt,name=GetLockHolder,proto3" json:"GetLockHolder"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -863,6 +876,13 @@ func (m *Response) GetAbortRemoteDeadlockTxn() AbortRemoteDeadlockTxnResponse { return AbortRemoteDeadlockTxnResponse{} } +func (m *Response) GetGetLockHolder() GetLockHolderResponse { + if m != nil { + return m.GetLockHolder + } + return GetLockHolderResponse{} +} + // LockRequest lock request type LockRequest struct { TxnID []byte `protobuf:"bytes,1,opt,name=TxnID,proto3" json:"TxnID,omitempty"` @@ -1097,6 +1117,110 @@ func (m *GetTxnLockResponse) GetWaitingList() []WaitTxn { return nil } +// GetLockHolderRequest gets the current holder on a special row lock. +type GetLockHolderRequest struct { + Row []byte `protobuf:"bytes,1,opt,name=Row,proto3" json:"Row,omitempty"` + Sharding Sharding `protobuf:"varint,2,opt,name=Sharding,proto3,enum=lock.Sharding" json:"Sharding,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetLockHolderRequest) Reset() { *m = GetLockHolderRequest{} } +func (m *GetLockHolderRequest) String() string { return proto.CompactTextString(m) } +func (*GetLockHolderRequest) ProtoMessage() {} +func (*GetLockHolderRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_164ad2988c7acaf1, []int{8} +} +func (m *GetLockHolderRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetLockHolderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetLockHolderRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetLockHolderRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetLockHolderRequest.Merge(m, src) +} +func (m *GetLockHolderRequest) XXX_Size() int { + return m.ProtoSize() +} +func (m *GetLockHolderRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetLockHolderRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetLockHolderRequest proto.InternalMessageInfo + +func (m *GetLockHolderRequest) GetRow() []byte { + if m != nil { + return m.Row + } + return nil +} + +func (m *GetLockHolderRequest) GetSharding() Sharding { + if m != nil { + return m.Sharding + } + return Sharding_None +} + +// GetLockHolderResponse gets the current holder on a special row lock. +type GetLockHolderResponse struct { + Holder WaitTxn `protobuf:"bytes,1,opt,name=Holder,proto3" json:"Holder"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetLockHolderResponse) Reset() { *m = GetLockHolderResponse{} } +func (m *GetLockHolderResponse) String() string { return proto.CompactTextString(m) } +func (*GetLockHolderResponse) ProtoMessage() {} +func (*GetLockHolderResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_164ad2988c7acaf1, []int{9} +} +func (m *GetLockHolderResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetLockHolderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetLockHolderResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetLockHolderResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetLockHolderResponse.Merge(m, src) +} +func (m *GetLockHolderResponse) XXX_Size() int { + return m.ProtoSize() +} +func (m *GetLockHolderResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetLockHolderResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetLockHolderResponse proto.InternalMessageInfo + +func (m *GetLockHolderResponse) GetHolder() WaitTxn { + if m != nil { + return m.Holder + } + return WaitTxn{} +} + // GetWaitingListRequest get a waiting txn list on a specical txn request. CN -> CN type GetWaitingListRequest struct { Txn WaitTxn `protobuf:"bytes,1,opt,name=Txn,proto3" json:"Txn"` @@ -1109,7 +1233,7 @@ func (m *GetWaitingListRequest) Reset() { *m = GetWaitingListRequest{} } func (m *GetWaitingListRequest) String() string { return proto.CompactTextString(m) } func (*GetWaitingListRequest) ProtoMessage() {} func (*GetWaitingListRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{8} + return fileDescriptor_164ad2988c7acaf1, []int{10} } func (m *GetWaitingListRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1157,7 +1281,7 @@ func (m *GetWaitingListResponse) Reset() { *m = GetWaitingListResponse{} func (m *GetWaitingListResponse) String() string { return proto.CompactTextString(m) } func (*GetWaitingListResponse) ProtoMessage() {} func (*GetWaitingListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{9} + return fileDescriptor_164ad2988c7acaf1, []int{11} } func (m *GetWaitingListResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1207,7 +1331,7 @@ func (m *WaitTxn) Reset() { *m = WaitTxn{} } func (m *WaitTxn) String() string { return proto.CompactTextString(m) } func (*WaitTxn) ProtoMessage() {} func (*WaitTxn) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{10} + return fileDescriptor_164ad2988c7acaf1, []int{12} } func (m *WaitTxn) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1273,7 +1397,7 @@ func (m *UnlockRequest) Reset() { *m = UnlockRequest{} } func (m *UnlockRequest) String() string { return proto.CompactTextString(m) } func (*UnlockRequest) ProtoMessage() {} func (*UnlockRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{11} + return fileDescriptor_164ad2988c7acaf1, []int{13} } func (m *UnlockRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1334,7 +1458,7 @@ func (m *UnlockResponse) Reset() { *m = UnlockResponse{} } func (m *UnlockResponse) String() string { return proto.CompactTextString(m) } func (*UnlockResponse) ProtoMessage() {} func (*UnlockResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{12} + return fileDescriptor_164ad2988c7acaf1, []int{14} } func (m *UnlockResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1379,7 +1503,7 @@ func (m *GetBindRequest) Reset() { *m = GetBindRequest{} } func (m *GetBindRequest) String() string { return proto.CompactTextString(m) } func (*GetBindRequest) ProtoMessage() {} func (*GetBindRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{13} + return fileDescriptor_164ad2988c7acaf1, []int{15} } func (m *GetBindRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1455,7 +1579,7 @@ func (m *GetBindResponse) Reset() { *m = GetBindResponse{} } func (m *GetBindResponse) String() string { return proto.CompactTextString(m) } func (*GetBindResponse) ProtoMessage() {} func (*GetBindResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{14} + return fileDescriptor_164ad2988c7acaf1, []int{16} } func (m *GetBindResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1506,7 +1630,7 @@ func (m *KeepLockTableBindRequest) Reset() { *m = KeepLockTableBindReque func (m *KeepLockTableBindRequest) String() string { return proto.CompactTextString(m) } func (*KeepLockTableBindRequest) ProtoMessage() {} func (*KeepLockTableBindRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{15} + return fileDescriptor_164ad2988c7acaf1, []int{17} } func (m *KeepLockTableBindRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1576,7 +1700,7 @@ func (m *KeepLockTableBindResponse) Reset() { *m = KeepLockTableBindResp func (m *KeepLockTableBindResponse) String() string { return proto.CompactTextString(m) } func (*KeepLockTableBindResponse) ProtoMessage() {} func (*KeepLockTableBindResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{16} + return fileDescriptor_164ad2988c7acaf1, []int{18} } func (m *KeepLockTableBindResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1631,7 +1755,7 @@ func (m *SetRestartServiceRequest) Reset() { *m = SetRestartServiceReque func (m *SetRestartServiceRequest) String() string { return proto.CompactTextString(m) } func (*SetRestartServiceRequest) ProtoMessage() {} func (*SetRestartServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{17} + return fileDescriptor_164ad2988c7acaf1, []int{19} } func (m *SetRestartServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1679,7 +1803,7 @@ func (m *SetRestartServiceResponse) Reset() { *m = SetRestartServiceResp func (m *SetRestartServiceResponse) String() string { return proto.CompactTextString(m) } func (*SetRestartServiceResponse) ProtoMessage() {} func (*SetRestartServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{18} + return fileDescriptor_164ad2988c7acaf1, []int{20} } func (m *SetRestartServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1727,7 +1851,7 @@ func (m *CanRestartServiceRequest) Reset() { *m = CanRestartServiceReque func (m *CanRestartServiceRequest) String() string { return proto.CompactTextString(m) } func (*CanRestartServiceRequest) ProtoMessage() {} func (*CanRestartServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{19} + return fileDescriptor_164ad2988c7acaf1, []int{21} } func (m *CanRestartServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1775,7 +1899,7 @@ func (m *CanRestartServiceResponse) Reset() { *m = CanRestartServiceResp func (m *CanRestartServiceResponse) String() string { return proto.CompactTextString(m) } func (*CanRestartServiceResponse) ProtoMessage() {} func (*CanRestartServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{20} + return fileDescriptor_164ad2988c7acaf1, []int{22} } func (m *CanRestartServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1823,7 +1947,7 @@ func (m *RemainTxnInServiceRequest) Reset() { *m = RemainTxnInServiceReq func (m *RemainTxnInServiceRequest) String() string { return proto.CompactTextString(m) } func (*RemainTxnInServiceRequest) ProtoMessage() {} func (*RemainTxnInServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{21} + return fileDescriptor_164ad2988c7acaf1, []int{23} } func (m *RemainTxnInServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1871,7 +1995,7 @@ func (m *RemainTxnInServiceResponse) Reset() { *m = RemainTxnInServiceRe func (m *RemainTxnInServiceResponse) String() string { return proto.CompactTextString(m) } func (*RemainTxnInServiceResponse) ProtoMessage() {} func (*RemainTxnInServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{22} + return fileDescriptor_164ad2988c7acaf1, []int{24} } func (m *RemainTxnInServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1919,7 +2043,7 @@ func (m *KeepRemoteLockRequest) Reset() { *m = KeepRemoteLockRequest{} } func (m *KeepRemoteLockRequest) String() string { return proto.CompactTextString(m) } func (*KeepRemoteLockRequest) ProtoMessage() {} func (*KeepRemoteLockRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{23} + return fileDescriptor_164ad2988c7acaf1, []int{25} } func (m *KeepRemoteLockRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1967,7 +2091,7 @@ func (m *KeepRemoteLockResponse) Reset() { *m = KeepRemoteLockResponse{} func (m *KeepRemoteLockResponse) String() string { return proto.CompactTextString(m) } func (*KeepRemoteLockResponse) ProtoMessage() {} func (*KeepRemoteLockResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{24} + return fileDescriptor_164ad2988c7acaf1, []int{26} } func (m *KeepRemoteLockResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2015,7 +2139,7 @@ func (m *ValidateServiceRequest) Reset() { *m = ValidateServiceRequest{} func (m *ValidateServiceRequest) String() string { return proto.CompactTextString(m) } func (*ValidateServiceRequest) ProtoMessage() {} func (*ValidateServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{25} + return fileDescriptor_164ad2988c7acaf1, []int{27} } func (m *ValidateServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2063,7 +2187,7 @@ func (m *ValidateServiceResponse) Reset() { *m = ValidateServiceResponse func (m *ValidateServiceResponse) String() string { return proto.CompactTextString(m) } func (*ValidateServiceResponse) ProtoMessage() {} func (*ValidateServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{26} + return fileDescriptor_164ad2988c7acaf1, []int{28} } func (m *ValidateServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2111,7 +2235,7 @@ func (m *AbortRemoteDeadlockTxnRequest) Reset() { *m = AbortRemoteDeadlo func (m *AbortRemoteDeadlockTxnRequest) String() string { return proto.CompactTextString(m) } func (*AbortRemoteDeadlockTxnRequest) ProtoMessage() {} func (*AbortRemoteDeadlockTxnRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{27} + return fileDescriptor_164ad2988c7acaf1, []int{29} } func (m *AbortRemoteDeadlockTxnRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2159,7 +2283,7 @@ func (m *AbortRemoteDeadlockTxnResponse) Reset() { *m = AbortRemoteDeadl func (m *AbortRemoteDeadlockTxnResponse) String() string { return proto.CompactTextString(m) } func (*AbortRemoteDeadlockTxnResponse) ProtoMessage() {} func (*AbortRemoteDeadlockTxnResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{28} + return fileDescriptor_164ad2988c7acaf1, []int{30} } func (m *AbortRemoteDeadlockTxnResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2207,7 +2331,7 @@ func (m *CannotCommitRequest) Reset() { *m = CannotCommitRequest{} } func (m *CannotCommitRequest) String() string { return proto.CompactTextString(m) } func (*CannotCommitRequest) ProtoMessage() {} func (*CannotCommitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{29} + return fileDescriptor_164ad2988c7acaf1, []int{31} } func (m *CannotCommitRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2255,7 +2379,7 @@ func (m *CannotCommitResponse) Reset() { *m = CannotCommitResponse{} } func (m *CannotCommitResponse) String() string { return proto.CompactTextString(m) } func (*CannotCommitResponse) ProtoMessage() {} func (*CannotCommitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{30} + return fileDescriptor_164ad2988c7acaf1, []int{32} } func (m *CannotCommitResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2302,7 +2426,7 @@ func (m *GetActiveTxnRequest) Reset() { *m = GetActiveTxnRequest{} } func (m *GetActiveTxnRequest) String() string { return proto.CompactTextString(m) } func (*GetActiveTxnRequest) ProtoMessage() {} func (*GetActiveTxnRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{31} + return fileDescriptor_164ad2988c7acaf1, []int{33} } func (m *GetActiveTxnRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2350,7 +2474,7 @@ func (m *GetActiveTxnResponse) Reset() { *m = GetActiveTxnResponse{} } func (m *GetActiveTxnResponse) String() string { return proto.CompactTextString(m) } func (*GetActiveTxnResponse) ProtoMessage() {} func (*GetActiveTxnResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{32} + return fileDescriptor_164ad2988c7acaf1, []int{34} } func (m *GetActiveTxnResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2405,7 +2529,7 @@ func (m *CheckOrphanRequest) Reset() { *m = CheckOrphanRequest{} } func (m *CheckOrphanRequest) String() string { return proto.CompactTextString(m) } func (*CheckOrphanRequest) ProtoMessage() {} func (*CheckOrphanRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{33} + return fileDescriptor_164ad2988c7acaf1, []int{35} } func (m *CheckOrphanRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2459,7 +2583,7 @@ func (m *CheckOrphanResponse) Reset() { *m = CheckOrphanResponse{} } func (m *CheckOrphanResponse) String() string { return proto.CompactTextString(m) } func (*CheckOrphanResponse) ProtoMessage() {} func (*CheckOrphanResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{34} + return fileDescriptor_164ad2988c7acaf1, []int{36} } func (m *CheckOrphanResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2507,7 +2631,7 @@ func (m *OrphanTxn) Reset() { *m = OrphanTxn{} } func (m *OrphanTxn) String() string { return proto.CompactTextString(m) } func (*OrphanTxn) ProtoMessage() {} func (*OrphanTxn) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{35} + return fileDescriptor_164ad2988c7acaf1, []int{37} } func (m *OrphanTxn) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2581,7 +2705,7 @@ func (m *Result) Reset() { *m = Result{} } func (m *Result) String() string { return proto.CompactTextString(m) } func (*Result) ProtoMessage() {} func (*Result) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{36} + return fileDescriptor_164ad2988c7acaf1, []int{38} } func (m *Result) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2693,7 +2817,7 @@ func (m *ExtraMutation) Reset() { *m = ExtraMutation{} } func (m *ExtraMutation) String() string { return proto.CompactTextString(m) } func (*ExtraMutation) ProtoMessage() {} func (*ExtraMutation) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{37} + return fileDescriptor_164ad2988c7acaf1, []int{39} } func (m *ExtraMutation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2754,7 +2878,7 @@ func (m *ResumeInvalidCNRequest) Reset() { *m = ResumeInvalidCNRequest{} func (m *ResumeInvalidCNRequest) String() string { return proto.CompactTextString(m) } func (*ResumeInvalidCNRequest) ProtoMessage() {} func (*ResumeInvalidCNRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{38} + return fileDescriptor_164ad2988c7acaf1, []int{40} } func (m *ResumeInvalidCNRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2800,7 +2924,7 @@ func (m *ResumeInvalidCNResponse) Reset() { *m = ResumeInvalidCNResponse func (m *ResumeInvalidCNResponse) String() string { return proto.CompactTextString(m) } func (*ResumeInvalidCNResponse) ProtoMessage() {} func (*ResumeInvalidCNResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_164ad2988c7acaf1, []int{39} + return fileDescriptor_164ad2988c7acaf1, []int{41} } func (m *ResumeInvalidCNResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2844,6 +2968,8 @@ func init() { proto.RegisterType((*LockResponse)(nil), "lock.LockResponse") proto.RegisterType((*GetTxnLockRequest)(nil), "lock.GetTxnLockRequest") proto.RegisterType((*GetTxnLockResponse)(nil), "lock.GetTxnLockResponse") + proto.RegisterType((*GetLockHolderRequest)(nil), "lock.GetLockHolderRequest") + proto.RegisterType((*GetLockHolderResponse)(nil), "lock.GetLockHolderResponse") proto.RegisterType((*GetWaitingListRequest)(nil), "lock.GetWaitingListRequest") proto.RegisterType((*GetWaitingListResponse)(nil), "lock.GetWaitingListResponse") proto.RegisterType((*WaitTxn)(nil), "lock.WaitTxn") @@ -2881,139 +3007,144 @@ func init() { func init() { proto.RegisterFile("lock.proto", fileDescriptor_164ad2988c7acaf1) } var fileDescriptor_164ad2988c7acaf1 = []byte{ - // 2099 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x59, 0xcd, 0x72, 0x1b, 0xc7, - 0xf1, 0xe7, 0x02, 0x20, 0x3e, 0x1a, 0x00, 0xb9, 0x1c, 0x52, 0xd4, 0x92, 0x7f, 0x9b, 0xc2, 0x7f, - 0x43, 0x57, 0xc1, 0x74, 0x2c, 0x46, 0x54, 0x64, 0x3b, 0x72, 0xa2, 0x0a, 0x05, 0x8a, 0x34, 0x2d, - 0x51, 0x74, 0x06, 0x90, 0x52, 0x95, 0xdb, 0x12, 0x18, 0x91, 0x5b, 0x04, 0x77, 0x91, 0xc5, 0x82, - 0x04, 0x1f, 0x20, 0x55, 0xa9, 0xca, 0x3d, 0xe7, 0x1c, 0x7d, 0xc9, 0x7b, 0xf8, 0xe8, 0xaa, 0xdc, - 0xf3, 0xa1, 0xbc, 0x42, 0x1e, 0x20, 0xd5, 0x33, 0xb3, 0xd8, 0x99, 0xfd, 0x20, 0xec, 0xdc, 0x76, - 0xba, 0x7b, 0x7e, 0xdd, 0xd3, 0xdb, 0xf8, 0x4d, 0xf7, 0x02, 0x60, 0xe8, 0xf7, 0x2f, 0x1f, 0x8e, - 0x02, 0x3f, 0xf4, 0x49, 0x09, 0x9f, 0x37, 0x3f, 0x3d, 0x77, 0xc3, 0x8b, 0xc9, 0xd9, 0xc3, 0xbe, - 0x7f, 0xb5, 0x7b, 0xee, 0x9f, 0xfb, 0xbb, 0x5c, 0x79, 0x36, 0x79, 0xc7, 0x57, 0x7c, 0xc1, 0x9f, - 0xc4, 0xa6, 0xcd, 0xe5, 0xd0, 0xbd, 0x62, 0xe3, 0xd0, 0xb9, 0x1a, 0x09, 0x81, 0xfd, 0x9f, 0x02, - 0xd4, 0x5f, 0xf9, 0xfd, 0xcb, 0xd3, 0x51, 0xe8, 0xfa, 0xde, 0x98, 0x3c, 0x86, 0xfa, 0x51, 0xe0, - 0x78, 0x93, 0xa1, 0x13, 0xb8, 0xe1, 0xad, 0x65, 0xb4, 0x8c, 0xf6, 0xd2, 0xde, 0xca, 0x43, 0xee, - 0x57, 0x51, 0x50, 0xd5, 0x8a, 0xd8, 0x50, 0x3a, 0xf1, 0x07, 0xcc, 0x2a, 0x70, 0xeb, 0x25, 0x61, - 0x8d, 0xa8, 0x28, 0xa5, 0x5c, 0x47, 0xda, 0x50, 0xfe, 0xc6, 0x1f, 0xba, 0xfd, 0x5b, 0xab, 0xc8, - 0xad, 0x4c, 0x61, 0xf5, 0x5b, 0xc7, 0x0d, 0x85, 0x9c, 0x4a, 0x3d, 0xf9, 0x00, 0x6a, 0x87, 0x7e, - 0x70, 0xe3, 0x04, 0x83, 0x9e, 0x6f, 0x95, 0x5a, 0x46, 0xbb, 0x46, 0x63, 0x01, 0x69, 0xc3, 0x72, - 0xcf, 0x39, 0x1b, 0xb2, 0x03, 0xf6, 0xae, 0x73, 0xe1, 0x78, 0xe7, 0x6c, 0x60, 0x2d, 0xb6, 0x8c, - 0x76, 0x95, 0x26, 0xc5, 0x88, 0x43, 0x59, 0x18, 0xdc, 0xa2, 0x0b, 0xab, 0xdc, 0x32, 0xda, 0x45, - 0x1a, 0x0b, 0xc8, 0x1a, 0x2c, 0x1e, 0x05, 0xfe, 0x64, 0x64, 0x55, 0x5a, 0x46, 0xbb, 0x49, 0xc5, - 0x82, 0xec, 0x40, 0xb5, 0x7b, 0xe1, 0x04, 0x03, 0xd7, 0x3b, 0xb7, 0xaa, 0xea, 0x69, 0x22, 0x29, - 0x9d, 0xe9, 0xc9, 0x53, 0x80, 0xae, 0xe7, 0x8c, 0xba, 0x17, 0x7e, 0xd8, 0x1b, 0x5b, 0xb5, 0x96, - 0xd1, 0xae, 0xef, 0xad, 0x3d, 0x8c, 0x13, 0xdc, 0x8b, 0x9e, 0x9e, 0x97, 0xbe, 0xfb, 0xfb, 0x83, - 0x05, 0xaa, 0x58, 0xdb, 0x7f, 0x33, 0xa0, 0x86, 0x09, 0xe2, 0x31, 0x63, 0x2c, 0xfc, 0x81, 0xa7, - 0xbb, 0x44, 0xc5, 0x02, 0xe3, 0xef, 0xb2, 0xe0, 0xda, 0xed, 0xb3, 0xe3, 0x03, 0x9e, 0xda, 0x1a, - 0x8d, 0x05, 0xc4, 0x82, 0xca, 0x5b, 0x16, 0x8c, 0x5d, 0xdf, 0xe3, 0x09, 0x2d, 0xd1, 0x68, 0x89, - 0x68, 0x6f, 0x9d, 0xa1, 0x3b, 0xe0, 0xb9, 0xab, 0x52, 0xb1, 0x88, 0xcf, 0xbb, 0x98, 0x77, 0xde, - 0xf2, 0x9c, 0xf3, 0xb6, 0xa0, 0x7e, 0x1a, 0xb8, 0xe7, 0xae, 0x27, 0x62, 0xad, 0x70, 0xaf, 0xaa, - 0xc8, 0xfe, 0x13, 0x40, 0x85, 0xb2, 0xdf, 0x4f, 0xd8, 0x38, 0x14, 0xd9, 0xe7, 0x8f, 0xc7, 0x07, - 0xf2, 0x5c, 0xb1, 0x80, 0x3c, 0x56, 0x8e, 0xcf, 0xcf, 0x56, 0xdf, 0x5b, 0x8e, 0xcb, 0x86, 0x8b, - 0x65, 0xd6, 0x94, 0x34, 0x6d, 0x43, 0xf9, 0x84, 0x85, 0x17, 0xfe, 0x40, 0x96, 0x50, 0x43, 0xec, - 0x10, 0x32, 0x2a, 0x75, 0xe4, 0x13, 0x28, 0xe1, 0x16, 0x7e, 0xfa, 0x7a, 0x54, 0xba, 0x28, 0x91, - 0xde, 0x25, 0x2e, 0x37, 0x22, 0x8f, 0xa0, 0xfc, 0xc6, 0x43, 0x0b, 0x9e, 0x96, 0xfa, 0xde, 0xaa, - 0x30, 0x17, 0x32, 0x7d, 0x83, 0x34, 0x24, 0xbf, 0x02, 0x38, 0x62, 0x61, 0x6f, 0xea, 0x71, 0x2f, - 0x65, 0xbe, 0xed, 0xbe, 0xfc, 0x81, 0xcc, 0xe4, 0xfa, 0x56, 0x65, 0x03, 0x39, 0x86, 0xa5, 0x23, - 0x16, 0x62, 0x09, 0xba, 0xde, 0xf9, 0x2b, 0x77, 0x1c, 0xf2, 0x44, 0xd6, 0xf7, 0xfe, 0x6f, 0x06, - 0xa1, 0xe8, 0x74, 0x98, 0xc4, 0x46, 0xf2, 0x73, 0xa8, 0x1c, 0xb1, 0xf0, 0xb9, 0xeb, 0x0d, 0x78, - 0xad, 0x62, 0xf5, 0x45, 0x18, 0x28, 0xd4, 0x37, 0x47, 0xa6, 0x84, 0xc2, 0xca, 0x4b, 0xc6, 0x46, - 0x71, 0x9e, 0x71, 0xbf, 0xa8, 0xde, 0x2d, 0xb1, 0x3f, 0xa5, 0xd6, 0x91, 0xd2, 0xdb, 0xf1, 0x50, - 0x28, 0xa4, 0xec, 0xca, 0x0f, 0x19, 0xcf, 0x0b, 0xa8, 0x87, 0xd2, 0x75, 0x89, 0x43, 0xe9, 0x4a, - 0xf2, 0x0a, 0x96, 0x79, 0xc1, 0x3a, 0x21, 0x93, 0xc5, 0x6e, 0xd5, 0x39, 0xd6, 0x07, 0x02, 0x2b, - 0xa1, 0xd4, 0xc1, 0x92, 0x5b, 0x49, 0x07, 0x1a, 0x1d, 0xc7, 0xf3, 0xfc, 0xb0, 0xe3, 0x5f, 0x5d, - 0xb9, 0xa1, 0xd5, 0xe0, 0x50, 0x1b, 0x02, 0x4a, 0xd5, 0xe8, 0x38, 0xda, 0x26, 0x04, 0x39, 0x62, - 0xe1, 0x7e, 0x3f, 0x74, 0xaf, 0x59, 0x6f, 0xea, 0x59, 0x4d, 0x15, 0x44, 0xd5, 0x24, 0x40, 0x54, - 0x15, 0xa6, 0xbd, 0xcb, 0x42, 0x8a, 0x8c, 0x10, 0x84, 0xd1, 0xc9, 0x96, 0xd4, 0xb4, 0xa7, 0xd4, - 0x89, 0xb4, 0xa7, 0xf4, 0x88, 0xd9, 0x71, 0xbc, 0x04, 0xe6, 0xb2, 0x8a, 0x99, 0x52, 0x27, 0x30, - 0x53, 0x7a, 0xf2, 0x06, 0x08, 0x65, 0x57, 0x8e, 0xeb, 0xf5, 0xa6, 0xde, 0xb1, 0x17, 0x81, 0x9a, - 0x1c, 0xf4, 0x81, 0x00, 0x4d, 0xeb, 0x75, 0xd4, 0x0c, 0x00, 0xf2, 0x6b, 0xa8, 0x77, 0x2e, 0x58, - 0xff, 0xf2, 0x34, 0x18, 0x5d, 0x38, 0x9e, 0xb5, 0xc2, 0xf1, 0x2c, 0x19, 0x64, 0xac, 0xd0, 0x81, - 0xd4, 0x2d, 0x58, 0x18, 0x94, 0x8d, 0x27, 0x57, 0xec, 0xd8, 0xbb, 0xc6, 0xb7, 0xdc, 0x79, 0x6d, - 0x11, 0xb5, 0x30, 0x12, 0xca, 0x44, 0x61, 0x24, 0xb4, 0xc4, 0x81, 0xf5, 0xfd, 0x33, 0x3f, 0x08, - 0x45, 0xe5, 0x1d, 0x30, 0x67, 0x80, 0x20, 0xf8, 0x76, 0xd7, 0x38, 0xe8, 0x4f, 0x04, 0x68, 0xb6, - 0x8d, 0x8e, 0x9d, 0x03, 0x64, 0x7f, 0x0b, 0x50, 0xa5, 0x6c, 0x3c, 0xf2, 0xbd, 0x31, 0x9b, 0x43, - 0x87, 0x31, 0xb3, 0x15, 0xee, 0x60, 0xb6, 0x35, 0x58, 0x7c, 0x11, 0x04, 0x7e, 0xc0, 0xe9, 0xaf, - 0x41, 0xc5, 0x82, 0x7c, 0x0c, 0x95, 0xd7, 0xec, 0x86, 0xff, 0x8a, 0x4b, 0x99, 0x44, 0x4a, 0x23, - 0x3d, 0xf9, 0xa9, 0xa4, 0x46, 0xc1, 0x75, 0x44, 0xa5, 0x46, 0x11, 0xa6, 0xc6, 0x8d, 0x7b, 0x33, - 0x6e, 0x2c, 0xab, 0xec, 0x12, 0x71, 0xa3, 0xb6, 0x23, 0x22, 0xc7, 0x67, 0x1a, 0x39, 0x56, 0xd4, - 0xb7, 0xac, 0x92, 0xa3, 0xb6, 0x57, 0x65, 0xc7, 0xaf, 0x53, 0xec, 0x58, 0x55, 0xdf, 0x71, 0x92, - 0x1d, 0x35, 0x9c, 0x24, 0x3d, 0x3e, 0x89, 0xe9, 0x51, 0xd0, 0xdb, 0xbd, 0x04, 0x3d, 0x6a, 0xbb, - 0x67, 0xfc, 0xd8, 0xcd, 0xe2, 0x47, 0x50, 0xeb, 0x3f, 0x83, 0x1f, 0x35, 0xa8, 0x0c, 0x82, 0xfc, - 0x3a, 0x45, 0x90, 0x1a, 0xa9, 0x25, 0x09, 0x52, 0x3f, 0x57, 0x82, 0x21, 0x4f, 0xd2, 0x0c, 0x29, - 0x68, 0xed, 0xc3, 0x1c, 0x86, 0xd4, 0xd0, 0x52, 0x14, 0x79, 0x90, 0xa0, 0x48, 0xc1, 0x6e, 0x9b, - 0x59, 0x14, 0xa9, 0x01, 0xe9, 0x1c, 0x79, 0x90, 0xe0, 0xc8, 0x25, 0x15, 0x45, 0xe7, 0x48, 0x1d, - 0x45, 0x23, 0xc9, 0x6e, 0x16, 0x49, 0x2e, 0xab, 0xb9, 0xcf, 0x20, 0x49, 0x3d, 0xf7, 0x69, 0x96, - 0xec, 0x66, 0xb1, 0xa4, 0x46, 0x68, 0x19, 0x2c, 0xa9, 0x83, 0xa6, 0x69, 0xf2, 0x6d, 0x26, 0x4d, - 0x0a, 0x5a, 0x6b, 0xe5, 0xd3, 0xa4, 0x06, 0x9b, 0xc5, 0x93, 0xfb, 0x3a, 0x4f, 0x12, 0xed, 0xbe, - 0x52, 0x79, 0x52, 0x43, 0xd2, 0x88, 0xf2, 0x24, 0x4d, 0x94, 0xab, 0x6a, 0x7d, 0xa4, 0x88, 0x52, - 0xaf, 0x8f, 0x24, 0x53, 0x9e, 0xcd, 0x61, 0xca, 0xed, 0xbb, 0x99, 0x52, 0x03, 0xcf, 0xa3, 0xca, - 0x3f, 0x1a, 0x62, 0x0a, 0x89, 0x9a, 0x47, 0x6c, 0x88, 0xa7, 0x9e, 0x64, 0xca, 0x06, 0x15, 0x8b, - 0x39, 0x0d, 0x31, 0x81, 0x12, 0xf5, 0x6f, 0xc6, 0x56, 0xb1, 0x55, 0x6c, 0x37, 0x28, 0x7f, 0x26, - 0x8f, 0xa0, 0x22, 0x07, 0x9b, 0x74, 0x3b, 0x28, 0x15, 0xd1, 0xcf, 0x5f, 0x2e, 0xed, 0xa7, 0xd0, - 0x50, 0x7f, 0x83, 0x64, 0x07, 0xca, 0x98, 0x91, 0x61, 0xc8, 0x63, 0xa9, 0x47, 0xd4, 0x2c, 0x64, - 0x11, 0xfb, 0x89, 0x95, 0xfd, 0x25, 0xac, 0xa4, 0x5a, 0xc0, 0x9c, 0xb3, 0x98, 0x50, 0xa4, 0xfe, - 0x0d, 0x3f, 0x45, 0x83, 0xe2, 0xa3, 0xed, 0x00, 0x49, 0x53, 0xa4, 0x6c, 0xe6, 0x27, 0x62, 0x34, - 0x58, 0xa4, 0x62, 0x41, 0x9e, 0x40, 0x5d, 0xe5, 0xc8, 0x42, 0xab, 0xd8, 0xae, 0xef, 0x35, 0xe3, - 0x89, 0xaa, 0x37, 0xf5, 0xa2, 0xca, 0x50, 0xec, 0xec, 0x67, 0x70, 0x2f, 0xb3, 0xbf, 0x24, 0x1f, - 0x41, 0x11, 0x5f, 0xa8, 0x38, 0x61, 0x26, 0x0e, 0xea, 0xed, 0x53, 0x58, 0xcf, 0x66, 0xe0, 0x64, - 0x40, 0xc6, 0x0f, 0x0c, 0xa8, 0x0f, 0x15, 0xa9, 0xcd, 0x7f, 0xe5, 0x9d, 0x80, 0x39, 0x21, 0x1b, - 0x9c, 0x7a, 0xd1, 0x2b, 0x9f, 0x09, 0xc8, 0x36, 0x34, 0x71, 0x3b, 0x0b, 0xf6, 0x07, 0x83, 0x80, - 0x8d, 0xc7, 0xfc, 0x62, 0xac, 0x51, 0x5d, 0x68, 0xff, 0xd9, 0x80, 0xa6, 0xd6, 0xd0, 0xe7, 0xf8, - 0xfa, 0x0c, 0xaa, 0x82, 0xcc, 0x7a, 0x5d, 0x39, 0x92, 0xdc, 0x35, 0xcd, 0xcd, 0x6c, 0xc9, 0xe7, - 0x50, 0x3b, 0x99, 0x84, 0x8e, 0x28, 0xb3, 0x22, 0x3f, 0xb9, 0x1c, 0x23, 0x5e, 0x4c, 0xc3, 0xc0, - 0x89, 0x74, 0xd1, 0x3c, 0x33, 0xb3, 0xb5, 0x4d, 0x58, 0xd2, 0x2f, 0x53, 0xfb, 0x5b, 0x83, 0xdf, - 0x7f, 0x4a, 0xcf, 0xad, 0x17, 0xbd, 0x91, 0x2c, 0xfa, 0xd9, 0xe4, 0x58, 0x50, 0x27, 0xc7, 0xd9, - 0xac, 0x57, 0xcc, 0x9b, 0xf5, 0x4a, 0x3f, 0x6e, 0xd6, 0x5b, 0x4c, 0xcf, 0x7a, 0x87, 0xb0, 0x9c, - 0xb8, 0x48, 0xff, 0xa7, 0xa1, 0xce, 0xfe, 0xab, 0x01, 0x56, 0xde, 0xc0, 0x31, 0xe7, 0xf0, 0xdb, - 0x50, 0xee, 0x86, 0x4e, 0x38, 0x19, 0xeb, 0x5d, 0x93, 0x90, 0x51, 0xa9, 0x23, 0xeb, 0x50, 0xe6, - 0xef, 0x37, 0x62, 0x06, 0xb9, 0x22, 0x4f, 0x00, 0x66, 0x3e, 0x91, 0x1e, 0x8a, 0xf9, 0xe1, 0x2a, - 0x86, 0xf6, 0x6f, 0x60, 0x23, 0xf7, 0xfe, 0x27, 0x4b, 0x50, 0x38, 0x7d, 0xc9, 0x03, 0xad, 0xd2, - 0xc2, 0xe9, 0xcb, 0x1f, 0x16, 0xa1, 0xfd, 0x05, 0x58, 0x79, 0xbd, 0xff, 0xdd, 0x19, 0xb0, 0x3f, - 0x81, 0x8d, 0xdc, 0x0b, 0x31, 0x19, 0x0c, 0xba, 0xc9, 0x1b, 0x07, 0xe6, 0xbb, 0xc9, 0xbd, 0x22, - 0x53, 0x6e, 0x7e, 0x01, 0x1b, 0xb9, 0x03, 0xc2, 0x1c, 0x3f, 0x4f, 0x61, 0x33, 0xff, 0xd2, 0x14, - 0x2d, 0xb4, 0xd4, 0x4a, 0x3a, 0x8c, 0x05, 0xf6, 0x13, 0xb8, 0x97, 0x39, 0x66, 0xce, 0x71, 0xd9, - 0x86, 0xf5, 0xec, 0xe6, 0x2b, 0x75, 0xae, 0xcf, 0x60, 0x3d, 0x7b, 0xf6, 0x9c, 0xe3, 0xe1, 0x63, - 0xb8, 0x9f, 0xd3, 0x91, 0xa5, 0x5c, 0x1c, 0xc2, 0x87, 0x77, 0x0e, 0x1c, 0xc8, 0xd3, 0xe1, 0x1c, - 0x9e, 0x0e, 0xa7, 0x9e, 0xfd, 0x33, 0xd8, 0xba, 0xfb, 0x3a, 0x4e, 0x79, 0xa6, 0xb0, 0x9a, 0x31, - 0x0d, 0x93, 0x2f, 0xa1, 0x29, 0x9a, 0x0a, 0xbc, 0x96, 0x62, 0x62, 0x97, 0x3f, 0x93, 0x99, 0x4a, - 0xfa, 0xd6, 0x6d, 0xed, 0x5f, 0xc2, 0x5a, 0x56, 0xfb, 0x88, 0xac, 0x2d, 0x24, 0x78, 0x0d, 0x88, - 0x77, 0x89, 0xbf, 0x4b, 0x5d, 0x68, 0x3f, 0x86, 0xd5, 0x8c, 0xd1, 0x7a, 0x4e, 0xae, 0x9f, 0xc1, - 0x5a, 0x56, 0xaf, 0x19, 0x7f, 0x12, 0x33, 0xd4, 0x4f, 0x62, 0xa6, 0xb8, 0xf5, 0x0a, 0xdc, 0x3d, - 0xbf, 0xe0, 0x0e, 0x80, 0xa4, 0x87, 0xd1, 0x39, 0x2c, 0x34, 0x43, 0x31, 0x22, 0x94, 0x4f, 0x61, - 0x35, 0xa3, 0x55, 0x43, 0x22, 0x92, 0x5d, 0x9d, 0x88, 0x42, 0xae, 0xec, 0xcf, 0xa1, 0x36, 0x4b, - 0x1c, 0xb1, 0xa0, 0x12, 0x35, 0x93, 0xc2, 0x53, 0xb4, 0xcc, 0x88, 0xf6, 0x0f, 0xc5, 0xa8, 0x37, - 0x21, 0x8f, 0xa0, 0x8a, 0xc5, 0xcb, 0xaf, 0x49, 0xe3, 0x2e, 0xe6, 0x9d, 0x99, 0x21, 0xc5, 0x7f, - 0xe5, 0x8c, 0x3b, 0xbe, 0xf7, 0x6e, 0xe8, 0xf6, 0x43, 0x1e, 0x7f, 0x95, 0xaa, 0x22, 0x7c, 0x51, - 0x5f, 0x39, 0xe3, 0x6f, 0x02, 0x76, 0x2d, 0x47, 0x83, 0x22, 0xb7, 0xd1, 0x85, 0xe4, 0x0b, 0xa8, - 0xcd, 0xee, 0x46, 0xd9, 0x65, 0xdd, 0x75, 0x6f, 0xc6, 0xc6, 0x3f, 0xe2, 0x53, 0x6e, 0x0b, 0xea, - 0x51, 0x54, 0x2f, 0xd9, 0x2d, 0x9f, 0x47, 0x1b, 0x54, 0x15, 0xa9, 0x16, 0x98, 0xa5, 0x8a, 0x6e, - 0x81, 0x99, 0xdd, 0x02, 0xc0, 0xa8, 0x45, 0x6f, 0xc0, 0xc7, 0xca, 0x06, 0x55, 0x24, 0x98, 0x79, - 0xf1, 0x24, 0xbe, 0xe5, 0x36, 0x69, 0xb4, 0xc4, 0x9d, 0xaf, 0xd9, 0x0d, 0x26, 0x6e, 0x7f, 0x20, - 0x46, 0xc1, 0x2a, 0x55, 0x24, 0x76, 0x17, 0x9a, 0xda, 0x4d, 0x8f, 0xaf, 0xea, 0x92, 0xdd, 0xca, - 0xee, 0x02, 0x1f, 0xb1, 0x39, 0x1d, 0x5f, 0xba, 0x23, 0x99, 0x65, 0xfe, 0x8c, 0x65, 0x15, 0xb0, - 0xd1, 0xd0, 0xe9, 0xb3, 0x9e, 0x2f, 0x47, 0xfa, 0x58, 0x80, 0x74, 0x93, 0xfd, 0x45, 0x63, 0xce, - 0x4f, 0x60, 0x03, 0xee, 0xe7, 0x34, 0xf8, 0x3b, 0xff, 0xaf, 0x7d, 0xdb, 0x27, 0x15, 0xde, 0x82, - 0x9a, 0x0b, 0xa4, 0x06, 0x8b, 0x14, 0xf3, 0x6c, 0x1a, 0x3b, 0x1f, 0x89, 0x3a, 0xe2, 0x5f, 0xec, - 0x9b, 0x50, 0x7b, 0x31, 0xed, 0x0f, 0x27, 0x63, 0xf7, 0x9a, 0x99, 0x0b, 0x04, 0xa0, 0x8c, 0xed, - 0x01, 0x1b, 0x98, 0xc6, 0xce, 0x36, 0x40, 0xfc, 0xe1, 0x9e, 0x54, 0xa1, 0x84, 0x2b, 0x73, 0x81, - 0x34, 0xa0, 0x7a, 0xe8, 0x8c, 0xc3, 0x43, 0xc7, 0x1d, 0x9a, 0xc6, 0xce, 0x83, 0xb8, 0xe1, 0x40, - 0x9b, 0xd7, 0xbe, 0xc7, 0x84, 0xb7, 0xe7, 0xb7, 0xe8, 0xd8, 0xd8, 0xf9, 0x47, 0x21, 0xfa, 0xee, - 0x81, 0x7a, 0x74, 0x2c, 0xfc, 0x88, 0xae, 0xc8, 0x34, 0xc8, 0x92, 0xfa, 0x39, 0xc1, 0x2c, 0x10, - 0x92, 0xfc, 0x3c, 0x60, 0x16, 0x51, 0xa6, 0x33, 0xb8, 0x59, 0x22, 0xf5, 0xd9, 0xe8, 0x6f, 0x2e, - 0x92, 0x7b, 0x19, 0x03, 0xbd, 0x59, 0x26, 0xcb, 0x50, 0x97, 0xff, 0x2a, 0xf0, 0x4d, 0x15, 0xb2, - 0x02, 0x4d, 0x29, 0x90, 0xfe, 0xab, 0x64, 0x35, 0x35, 0x6a, 0x9b, 0x35, 0x62, 0xea, 0x03, 0xb3, - 0x09, 0x28, 0x51, 0x69, 0xc7, 0xac, 0xa3, 0xcf, 0xd4, 0xc5, 0x6c, 0x36, 0xc8, 0x7a, 0xd6, 0xd4, - 0x68, 0x36, 0xd1, 0x3c, 0x75, 0xc1, 0x9a, 0x4b, 0x18, 0xa2, 0x42, 0x24, 0xe6, 0x32, 0xc6, 0x93, - 0x78, 0xb9, 0xa6, 0x49, 0x36, 0xf3, 0x06, 0x34, 0x73, 0x65, 0x87, 0x45, 0x0d, 0x88, 0x88, 0x88, - 0x03, 0xe3, 0x71, 0x5f, 0x78, 0x98, 0x09, 0x73, 0x01, 0x23, 0x52, 0xc4, 0x32, 0xb3, 0xa6, 0xa1, - 0x98, 0xbf, 0xe1, 0xc9, 0xef, 0x4e, 0xfa, 0x7d, 0xb3, 0xa0, 0x88, 0xe3, 0x78, 0xcd, 0xe2, 0xf3, - 0xce, 0xf7, 0xff, 0xda, 0x32, 0xbe, 0x7b, 0xbf, 0x65, 0x7c, 0xff, 0x7e, 0xcb, 0xf8, 0xe7, 0xfb, - 0xad, 0x85, 0xbf, 0xfc, 0x7b, 0xcb, 0xf8, 0x9d, 0xfa, 0xdf, 0xd4, 0x95, 0x13, 0x06, 0xee, 0xd4, - 0xe7, 0x0d, 0x64, 0xb4, 0xf0, 0xd8, 0xee, 0xe8, 0xf2, 0x7c, 0x77, 0x74, 0xb6, 0x8b, 0x01, 0x9f, - 0x95, 0xf9, 0x3f, 0x52, 0x8f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x34, 0x3d, 0xff, 0xe5, - 0x1a, 0x00, 0x00, + // 2182 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x59, 0xdb, 0x72, 0xdb, 0xc8, + 0xd1, 0x16, 0x48, 0x8a, 0x87, 0x26, 0x29, 0x41, 0xa3, 0x83, 0x21, 0xfd, 0xbb, 0x32, 0x7f, 0x44, + 0x5b, 0xc5, 0x95, 0xb3, 0x56, 0x2c, 0xc7, 0xbb, 0x1b, 0x6f, 0xe2, 0x8a, 0x4c, 0x59, 0xb2, 0xd6, + 0x96, 0xb5, 0x19, 0xd2, 0x4e, 0x55, 0xee, 0x20, 0x72, 0x2c, 0xa1, 0x44, 0x01, 0x0c, 0x38, 0x94, + 0xa8, 0x07, 0x48, 0x55, 0x9e, 0x20, 0xd7, 0xb9, 0xcc, 0x4d, 0xde, 0x63, 0x2f, 0xb7, 0x6a, 0xef, + 0x53, 0x89, 0xf3, 0x04, 0x49, 0xe5, 0x01, 0x52, 0x73, 0x00, 0x30, 0x83, 0x03, 0xb9, 0x9b, 0x3b, + 0x4c, 0x77, 0xcf, 0xd7, 0x33, 0x8d, 0xc6, 0x37, 0xdd, 0x03, 0x80, 0xa1, 0xdf, 0xbf, 0x7a, 0x38, + 0x0a, 0x7c, 0xea, 0xa3, 0x12, 0x7b, 0xde, 0xfa, 0xec, 0xc2, 0xa5, 0x97, 0x93, 0xf3, 0x87, 0x7d, + 0xff, 0x7a, 0xef, 0xc2, 0xbf, 0xf0, 0xf7, 0xb8, 0xf2, 0x7c, 0xf2, 0x9e, 0x8f, 0xf8, 0x80, 0x3f, + 0x89, 0x49, 0x5b, 0xcb, 0xd4, 0xbd, 0x26, 0x63, 0xea, 0x5c, 0x8f, 0x84, 0xc0, 0xfe, 0x4f, 0x01, + 0xea, 0xaf, 0xfd, 0xfe, 0xd5, 0xd9, 0x88, 0xba, 0xbe, 0x37, 0x46, 0x8f, 0xa1, 0x7e, 0x1c, 0x38, + 0xde, 0x64, 0xe8, 0x04, 0x2e, 0xbd, 0xb3, 0x8c, 0x96, 0xd1, 0x5e, 0xda, 0x5f, 0x79, 0xc8, 0xfd, + 0x2a, 0x0a, 0xac, 0x5a, 0x21, 0x1b, 0x4a, 0xa7, 0xfe, 0x80, 0x58, 0x05, 0x6e, 0xbd, 0x24, 0xac, + 0x19, 0x2a, 0x93, 0x62, 0xae, 0x43, 0x6d, 0x28, 0x7f, 0xe3, 0x0f, 0xdd, 0xfe, 0x9d, 0x55, 0xe4, + 0x56, 0xa6, 0xb0, 0xfa, 0xad, 0xe3, 0x52, 0x21, 0xc7, 0x52, 0x8f, 0x3e, 0x82, 0xda, 0x91, 0x1f, + 0xdc, 0x3a, 0xc1, 0xa0, 0xe7, 0x5b, 0xa5, 0x96, 0xd1, 0xae, 0xe1, 0x58, 0x80, 0xda, 0xb0, 0xdc, + 0x73, 0xce, 0x87, 0xe4, 0x90, 0xbc, 0xef, 0x5c, 0x3a, 0xde, 0x05, 0x19, 0x58, 0x8b, 0x2d, 0xa3, + 0x5d, 0xc5, 0x49, 0x31, 0xc3, 0xc1, 0x84, 0x06, 0x77, 0xcc, 0x85, 0x55, 0x6e, 0x19, 0xed, 0x22, + 0x8e, 0x05, 0x68, 0x0d, 0x16, 0x8f, 0x03, 0x7f, 0x32, 0xb2, 0x2a, 0x2d, 0xa3, 0xdd, 0xc4, 0x62, + 0x80, 0x76, 0xa1, 0xda, 0xbd, 0x74, 0x82, 0x81, 0xeb, 0x5d, 0x58, 0x55, 0x75, 0x37, 0xa1, 0x14, + 0x47, 0x7a, 0xf4, 0x14, 0xa0, 0xeb, 0x39, 0xa3, 0xee, 0xa5, 0x4f, 0x7b, 0x63, 0xab, 0xd6, 0x32, + 0xda, 0xf5, 0xfd, 0xb5, 0x87, 0x71, 0x80, 0x7b, 0xe1, 0xd3, 0xf3, 0xd2, 0xb7, 0x7f, 0xbb, 0xbf, + 0x80, 0x15, 0x6b, 0xfb, 0x7b, 0x03, 0x6a, 0x2c, 0x40, 0x7c, 0xcd, 0x6c, 0x2d, 0xfc, 0x81, 0x87, + 0xbb, 0x84, 0xc5, 0x80, 0xad, 0xbf, 0x4b, 0x82, 0x1b, 0xb7, 0x4f, 0x4e, 0x0e, 0x79, 0x68, 0x6b, + 0x38, 0x16, 0x20, 0x0b, 0x2a, 0xef, 0x48, 0x30, 0x76, 0x7d, 0x8f, 0x07, 0xb4, 0x84, 0xc3, 0x21, + 0x43, 0x7b, 0xe7, 0x0c, 0xdd, 0x01, 0x8f, 0x5d, 0x15, 0x8b, 0x41, 0xbc, 0xdf, 0xc5, 0xbc, 0xfd, + 0x96, 0xe7, 0xec, 0xb7, 0x05, 0xf5, 0xb3, 0xc0, 0xbd, 0x70, 0x3d, 0xb1, 0xd6, 0x0a, 0xf7, 0xaa, + 0x8a, 0xec, 0xef, 0x01, 0x2a, 0x98, 0xfc, 0x7e, 0x42, 0xc6, 0x54, 0x44, 0x9f, 0x3f, 0x9e, 0x1c, + 0xca, 0x7d, 0xc5, 0x02, 0xf4, 0x58, 0xd9, 0x3e, 0xdf, 0x5b, 0x7d, 0x7f, 0x39, 0x4e, 0x1b, 0x2e, + 0x96, 0x51, 0x53, 0xc2, 0xb4, 0x03, 0xe5, 0x53, 0x42, 0x2f, 0xfd, 0x81, 0x4c, 0xa1, 0x86, 0x98, + 0x21, 0x64, 0x58, 0xea, 0xd0, 0x03, 0x28, 0xb1, 0x29, 0x7c, 0xf7, 0xf5, 0x30, 0x75, 0x99, 0x44, + 0x7a, 0x97, 0xb8, 0xdc, 0x08, 0x3d, 0x82, 0xf2, 0x5b, 0x8f, 0x59, 0xf0, 0xb0, 0xd4, 0xf7, 0x57, + 0x85, 0xb9, 0x90, 0xe9, 0x13, 0xa4, 0x21, 0xfa, 0x15, 0xc0, 0x31, 0xa1, 0xbd, 0xa9, 0xc7, 0xbd, + 0x94, 0xf9, 0xb4, 0x7b, 0xf2, 0x03, 0x89, 0xe4, 0xfa, 0x54, 0x65, 0x02, 0x3a, 0x81, 0xa5, 0x63, + 0x42, 0x59, 0x0a, 0xba, 0xde, 0xc5, 0x6b, 0x77, 0x4c, 0x79, 0x20, 0xeb, 0xfb, 0xff, 0x17, 0x41, + 0x28, 0x3a, 0x1d, 0x26, 0x31, 0x11, 0xfd, 0x1c, 0x2a, 0xc7, 0x84, 0x3e, 0x77, 0xbd, 0x01, 0xcf, + 0x55, 0x96, 0x7d, 0x21, 0x06, 0x13, 0xea, 0x93, 0x43, 0x53, 0x84, 0x61, 0xe5, 0x15, 0x21, 0xa3, + 0x38, 0xce, 0x6c, 0xbe, 0xc8, 0xde, 0x6d, 0x31, 0x3f, 0xa5, 0xd6, 0x91, 0xd2, 0xd3, 0xd9, 0xa6, + 0x98, 0x10, 0x93, 0x6b, 0x9f, 0x12, 0x1e, 0x17, 0x50, 0x37, 0xa5, 0xeb, 0x12, 0x9b, 0xd2, 0x95, + 0xe8, 0x35, 0x2c, 0xf3, 0x84, 0x75, 0x28, 0x91, 0xc9, 0x6e, 0xd5, 0x39, 0xd6, 0x47, 0x02, 0x2b, + 0xa1, 0xd4, 0xc1, 0x92, 0x53, 0x51, 0x07, 0x1a, 0x1d, 0xc7, 0xf3, 0x7c, 0xda, 0xf1, 0xaf, 0xaf, + 0x5d, 0x6a, 0x35, 0x38, 0xd4, 0xa6, 0x80, 0x52, 0x35, 0x3a, 0x8e, 0x36, 0x89, 0x81, 0x1c, 0x13, + 0x7a, 0xd0, 0xa7, 0xee, 0x0d, 0xe9, 0x4d, 0x3d, 0xab, 0xa9, 0x82, 0xa8, 0x9a, 0x04, 0x88, 0xaa, + 0x62, 0x61, 0xef, 0x12, 0x8a, 0x19, 0x23, 0x04, 0x34, 0xdc, 0xd9, 0x92, 0x1a, 0xf6, 0x94, 0x3a, + 0x11, 0xf6, 0x94, 0x9e, 0x61, 0x76, 0x1c, 0x2f, 0x81, 0xb9, 0xac, 0x62, 0xa6, 0xd4, 0x09, 0xcc, + 0x94, 0x1e, 0xbd, 0x05, 0x84, 0xc9, 0xb5, 0xe3, 0x7a, 0xbd, 0xa9, 0x77, 0xe2, 0x85, 0xa0, 0x26, + 0x07, 0xbd, 0x2f, 0x40, 0xd3, 0x7a, 0x1d, 0x35, 0x03, 0x00, 0xfd, 0x1a, 0xea, 0x9d, 0x4b, 0xd2, + 0xbf, 0x3a, 0x0b, 0x46, 0x97, 0x8e, 0x67, 0xad, 0x70, 0x3c, 0x4b, 0x2e, 0x32, 0x56, 0xe8, 0x40, + 0xea, 0x14, 0x96, 0x18, 0x98, 0x8c, 0x27, 0xd7, 0xe4, 0xc4, 0xbb, 0x61, 0x6f, 0xb9, 0xf3, 0xc6, + 0x42, 0x6a, 0x62, 0x24, 0x94, 0x89, 0xc4, 0x48, 0x68, 0xd1, 0x11, 0x34, 0x8f, 0x09, 0x65, 0x19, + 0xf7, 0xd2, 0x1f, 0x0e, 0x48, 0x60, 0xad, 0x72, 0xac, 0xad, 0xe8, 0xa5, 0xc6, 0x2a, 0x1d, 0x49, + 0x9f, 0x86, 0x1c, 0xd8, 0x38, 0x38, 0xf7, 0x03, 0x2a, 0x32, 0xf8, 0x90, 0x38, 0x03, 0x06, 0xc0, + 0xb2, 0x64, 0x8d, 0x03, 0xfe, 0x44, 0x00, 0x66, 0xdb, 0xe8, 0xc8, 0x39, 0x40, 0xf6, 0xbf, 0x00, + 0xaa, 0x98, 0x8c, 0x47, 0xbe, 0x37, 0x26, 0x73, 0x68, 0x35, 0x66, 0xc8, 0xc2, 0x0c, 0x86, 0x5c, + 0x83, 0xc5, 0x17, 0x41, 0xe0, 0x07, 0x9c, 0x46, 0x1b, 0x58, 0x0c, 0xd0, 0xa7, 0x50, 0x79, 0x43, + 0x6e, 0x39, 0x1b, 0x94, 0x32, 0x09, 0x19, 0x87, 0x7a, 0xf4, 0x53, 0x49, 0xb1, 0x82, 0x33, 0x91, + 0x4a, 0xb1, 0x62, 0x99, 0x1a, 0xc7, 0xee, 0x47, 0x1c, 0x5b, 0x56, 0x59, 0x2a, 0xe4, 0x58, 0x6d, + 0x46, 0x48, 0xb2, 0xcf, 0x34, 0x92, 0xad, 0xa8, 0xd9, 0xa2, 0x92, 0xac, 0x36, 0x57, 0x65, 0xd9, + 0xaf, 0x53, 0x2c, 0x5b, 0x55, 0x73, 0x25, 0xc9, 0xb2, 0x1a, 0x4e, 0x92, 0x66, 0x9f, 0xc4, 0x34, + 0x2b, 0x68, 0x72, 0x3d, 0x41, 0xb3, 0xda, 0xec, 0x88, 0x67, 0xbb, 0x59, 0x3c, 0x0b, 0xea, 0x77, + 0x94, 0xc1, 0xb3, 0x1a, 0x54, 0x06, 0xd1, 0x7e, 0x9d, 0x22, 0x5a, 0x8d, 0x1c, 0x93, 0x44, 0xab, + 0xef, 0x2b, 0xc1, 0xb4, 0xa7, 0x69, 0xa6, 0x15, 0xf4, 0xf8, 0x71, 0x0e, 0xd3, 0x6a, 0x68, 0x29, + 0xaa, 0x3d, 0x4c, 0x50, 0x6d, 0x53, 0xfd, 0xa0, 0x74, 0xaa, 0xd5, 0x80, 0x74, 0xae, 0x3d, 0x4c, + 0x70, 0xed, 0x52, 0xe2, 0xb3, 0x54, 0xb8, 0x56, 0x47, 0xd1, 0xc8, 0xb6, 0x9b, 0x45, 0xb6, 0xcb, + 0x6a, 0xec, 0x33, 0xc8, 0x56, 0x8f, 0x7d, 0x9a, 0x6d, 0xbb, 0x59, 0x6c, 0xab, 0x11, 0x63, 0x06, + 0xdb, 0xea, 0xa0, 0x69, 0xba, 0x7d, 0x97, 0x49, 0xb7, 0x82, 0x1e, 0x5b, 0xf9, 0x74, 0xab, 0xc1, + 0x66, 0xf1, 0xed, 0x81, 0xce, 0xb7, 0x48, 0x3b, 0xf7, 0x54, 0xbe, 0xd5, 0x90, 0x34, 0xc2, 0x3d, + 0x4d, 0x13, 0xee, 0xaa, 0x9a, 0x1f, 0x29, 0xc2, 0xd5, 0xf3, 0x23, 0xc9, 0xb8, 0xe7, 0x73, 0x98, + 0x72, 0x67, 0x36, 0x53, 0x6a, 0xe0, 0x39, 0x48, 0xe8, 0x38, 0xc9, 0xea, 0xeb, 0x89, 0xda, 0x4a, + 0x65, 0x75, 0x0d, 0x51, 0x9f, 0x67, 0xff, 0xd1, 0x10, 0x6d, 0x51, 0x58, 0xcd, 0xb2, 0x0a, 0x7d, + 0xea, 0x49, 0xca, 0x6d, 0x60, 0x31, 0x98, 0x53, 0xa1, 0x23, 0x28, 0x61, 0xff, 0x76, 0x6c, 0x15, + 0x5b, 0xc5, 0x76, 0x03, 0xf3, 0x67, 0xf4, 0x08, 0x2a, 0xb2, 0xd3, 0x4a, 0xd7, 0xa7, 0x52, 0x11, + 0xf2, 0x88, 0x1c, 0xda, 0x4f, 0xa1, 0xa1, 0x7e, 0xcc, 0x68, 0x17, 0xca, 0x2c, 0xb4, 0x43, 0xca, + 0xd7, 0x52, 0x0f, 0x39, 0x5e, 0xc8, 0x42, 0x1a, 0x15, 0x23, 0xfb, 0x2b, 0x58, 0x49, 0xd5, 0xa4, + 0x39, 0x7b, 0x31, 0xa1, 0x88, 0xfd, 0x5b, 0xbe, 0x8b, 0x06, 0x66, 0x8f, 0xb6, 0x03, 0x28, 0xcd, + 0xb5, 0xb2, 0xbb, 0x98, 0x88, 0x5e, 0x65, 0x11, 0x8b, 0x01, 0x7a, 0x02, 0x75, 0x95, 0x6c, 0x0b, + 0xad, 0x62, 0xbb, 0xbe, 0xdf, 0x8c, 0x5b, 0xbc, 0xde, 0xd4, 0x0b, 0x53, 0x4c, 0xb1, 0xb3, 0x7b, + 0xb0, 0x96, 0x75, 0xd4, 0x86, 0x8b, 0x31, 0xa2, 0xc5, 0x68, 0x8d, 0x4a, 0x61, 0x76, 0xa3, 0x62, + 0x1f, 0xc2, 0x7a, 0xe6, 0xab, 0x46, 0x0f, 0xa0, 0x2c, 0xf3, 0x42, 0x84, 0x2e, 0x73, 0x81, 0xd2, + 0xc4, 0x7e, 0xc6, 0x51, 0xd2, 0xc5, 0x38, 0xfa, 0x04, 0x8a, 0x2c, 0x6b, 0x67, 0x40, 0x30, 0xbd, + 0x7d, 0x06, 0x1b, 0xd9, 0xc7, 0x4c, 0x32, 0x58, 0xc6, 0x0f, 0x0c, 0x56, 0x1f, 0x2a, 0x52, 0x9b, + 0x9f, 0x8e, 0x9d, 0x80, 0x38, 0x94, 0x0c, 0xce, 0xbc, 0x30, 0x1d, 0x23, 0x01, 0xda, 0x81, 0x26, + 0x9b, 0x4e, 0x82, 0x83, 0xc1, 0x20, 0x20, 0xe3, 0x31, 0x3f, 0xfd, 0x6b, 0x58, 0x17, 0xda, 0x7f, + 0x32, 0xa0, 0xa9, 0x75, 0x3f, 0x39, 0xbe, 0x3e, 0x87, 0xaa, 0x60, 0xec, 0x5e, 0x57, 0xf6, 0x6f, + 0xb3, 0x5a, 0xdf, 0xc8, 0x16, 0x7d, 0x01, 0xb5, 0xd3, 0x09, 0x75, 0xc4, 0x27, 0x50, 0xe4, 0x3b, + 0x97, 0x3d, 0xd7, 0x8b, 0x29, 0x0d, 0x9c, 0x50, 0x17, 0x36, 0x7f, 0x91, 0xad, 0x6d, 0xc2, 0x92, + 0x5e, 0x31, 0xd8, 0x7f, 0x31, 0xf8, 0x21, 0xaf, 0x34, 0x28, 0xfa, 0x07, 0x69, 0x24, 0x3f, 0xc8, + 0xa8, 0xcd, 0x2e, 0xa8, 0x6d, 0x76, 0xd4, 0x18, 0x17, 0xf3, 0x1a, 0xe3, 0xd2, 0x8f, 0x6b, 0x8c, + 0x17, 0xd3, 0x8d, 0xf1, 0x11, 0x2c, 0x27, 0xaa, 0x85, 0xff, 0xa9, 0x03, 0xb6, 0xff, 0x6a, 0x80, + 0x95, 0xd7, 0x9d, 0xcd, 0xd9, 0xfc, 0x0e, 0x94, 0xbb, 0xd4, 0xa1, 0x93, 0xb1, 0x5e, 0x1a, 0x0a, + 0x19, 0x96, 0x3a, 0xb4, 0x01, 0x65, 0xfe, 0x7e, 0x43, 0xd6, 0x92, 0x23, 0xf4, 0x04, 0x20, 0xf2, + 0xc9, 0xa8, 0xab, 0x98, 0xbf, 0x5c, 0xc5, 0xd0, 0xfe, 0x0d, 0x6c, 0xe6, 0x16, 0x39, 0x68, 0x09, + 0x0a, 0x67, 0xaf, 0xf8, 0x42, 0xab, 0xb8, 0x70, 0xf6, 0xea, 0x87, 0xad, 0xd0, 0xfe, 0x12, 0xac, + 0xbc, 0x46, 0x69, 0x76, 0x04, 0xec, 0x07, 0xb0, 0x99, 0x7b, 0xea, 0x27, 0x17, 0xc3, 0xdc, 0xe4, + 0xf5, 0x4e, 0xf3, 0xdd, 0xe4, 0xd6, 0x01, 0x29, 0x37, 0xbf, 0x80, 0xcd, 0xdc, 0x6e, 0x6a, 0x8e, + 0x9f, 0xa7, 0xb0, 0x95, 0x5f, 0x19, 0x88, 0x3e, 0x41, 0x6a, 0x25, 0x55, 0xc7, 0x02, 0xfb, 0x09, + 0xac, 0x67, 0xf6, 0xe4, 0x73, 0x5c, 0xb6, 0x61, 0x23, 0xbb, 0xc2, 0x4c, 0xed, 0xeb, 0x73, 0xd8, + 0xc8, 0x6e, 0xd4, 0xe7, 0x78, 0xf8, 0x14, 0xee, 0xe5, 0x94, 0x9d, 0x29, 0x17, 0x47, 0xf0, 0xf1, + 0xcc, 0xae, 0x8a, 0xf1, 0x34, 0x9d, 0xc3, 0xd3, 0x74, 0xea, 0xd9, 0x3f, 0x83, 0xed, 0xd9, 0x35, + 0x47, 0xca, 0x33, 0x86, 0xd5, 0x8c, 0xab, 0x03, 0xf4, 0x15, 0x34, 0x45, 0xe5, 0xc4, 0x8e, 0xcc, + 0x98, 0xd8, 0xe5, 0x67, 0x12, 0xa9, 0xc2, 0x82, 0x43, 0xb3, 0xb5, 0x7f, 0x09, 0x6b, 0x59, 0x35, + 0x32, 0x63, 0x6d, 0x21, 0x61, 0xc7, 0x80, 0x78, 0x97, 0xec, 0xbb, 0xd4, 0x85, 0xf6, 0x63, 0x58, + 0xcd, 0xb8, 0x87, 0x98, 0x13, 0xeb, 0x67, 0xfc, 0xf0, 0x4d, 0x15, 0xd4, 0xf1, 0xfd, 0xa1, 0xa1, + 0xde, 0x1f, 0x9a, 0xe2, 0xd4, 0x2b, 0x70, 0xf7, 0xfc, 0x80, 0x3b, 0x04, 0x94, 0xee, 0xdc, 0xe7, + 0xb0, 0x50, 0x84, 0x62, 0x84, 0x28, 0x9f, 0xc1, 0x6a, 0x46, 0x3d, 0xca, 0x88, 0x48, 0x96, 0xae, + 0x62, 0x15, 0x72, 0x64, 0x7f, 0x01, 0xb5, 0x28, 0x70, 0xc8, 0x82, 0x4a, 0x58, 0x31, 0x0b, 0x4f, + 0xe1, 0x30, 0x63, 0xb5, 0x7f, 0x28, 0x86, 0x75, 0x13, 0x7a, 0x04, 0x55, 0x96, 0xbc, 0xfc, 0x98, + 0x34, 0x66, 0x31, 0x6f, 0x64, 0xc6, 0x28, 0xfe, 0xa5, 0x33, 0xee, 0xf8, 0xde, 0xfb, 0xa1, 0xdb, + 0xa7, 0x7c, 0xfd, 0x55, 0xac, 0x8a, 0xd8, 0x8b, 0x7a, 0xe9, 0x8c, 0xbf, 0x09, 0xc8, 0x8d, 0xec, + 0x7f, 0x8a, 0xdc, 0x46, 0x17, 0xa2, 0x2f, 0xa1, 0x16, 0x9d, 0x8d, 0xb2, 0x02, 0x9c, 0x75, 0x6e, + 0xc6, 0xc6, 0x3f, 0xe2, 0xde, 0xbb, 0x05, 0xf5, 0x70, 0x55, 0xaf, 0xc8, 0x1d, 0x6f, 0xba, 0x1b, + 0x58, 0x15, 0xa9, 0x16, 0x2c, 0x4a, 0x15, 0xdd, 0x82, 0x45, 0x76, 0x1b, 0x80, 0xad, 0x5a, 0xd4, + 0x06, 0xbc, 0x77, 0x6e, 0x60, 0x45, 0xc2, 0x22, 0x2f, 0x9e, 0xc4, 0xc5, 0x77, 0x13, 0x87, 0x43, + 0x36, 0xf3, 0x0d, 0xb9, 0x65, 0x81, 0x3b, 0x18, 0x88, 0x7e, 0xb7, 0x8a, 0x15, 0x89, 0xdd, 0x85, + 0xa6, 0x76, 0xd2, 0xb3, 0x57, 0x75, 0x45, 0xee, 0xc2, 0x5a, 0xef, 0x8a, 0xdc, 0xb1, 0xc2, 0x79, + 0x7c, 0xe5, 0x8e, 0x64, 0x94, 0xf9, 0x33, 0x4b, 0xab, 0x80, 0x8c, 0x86, 0x4e, 0x9f, 0xf4, 0x7c, + 0x79, 0x6f, 0x11, 0x0b, 0x18, 0xdd, 0x64, 0x5f, 0xff, 0xcc, 0xf9, 0x04, 0x36, 0xe1, 0x5e, 0x4e, + 0x17, 0xb3, 0xfb, 0xff, 0xda, 0x8f, 0x10, 0x54, 0xe1, 0x15, 0xa9, 0xb9, 0x80, 0x6a, 0xb0, 0x88, + 0x59, 0x9c, 0x4d, 0x63, 0xf7, 0x13, 0x91, 0x47, 0xfc, 0xf7, 0x46, 0x13, 0x6a, 0x2f, 0xa6, 0xfd, + 0xe1, 0x64, 0xec, 0xde, 0x10, 0x73, 0x01, 0x01, 0x94, 0x59, 0x79, 0x40, 0x06, 0xa6, 0xb1, 0xbb, + 0x03, 0x10, 0xff, 0xe5, 0x40, 0x55, 0x28, 0xb1, 0x91, 0xb9, 0x80, 0x1a, 0x50, 0x3d, 0x72, 0xc6, + 0xf4, 0xc8, 0x71, 0x87, 0xa6, 0xb1, 0x7b, 0x3f, 0x2e, 0x38, 0x98, 0xcd, 0x1b, 0xdf, 0x23, 0xc2, + 0xdb, 0xf3, 0x3b, 0xe6, 0xd8, 0xd8, 0xfd, 0x77, 0x21, 0xbc, 0xdc, 0x61, 0x7a, 0xe6, 0x58, 0xf8, + 0x11, 0x55, 0x91, 0x69, 0xa0, 0x25, 0xf5, 0xce, 0xc4, 0x2c, 0x20, 0x94, 0xbc, 0x03, 0x31, 0x8b, + 0x4c, 0xa6, 0x33, 0xb8, 0x59, 0x42, 0xf5, 0xe8, 0x7e, 0xc3, 0x5c, 0x44, 0xeb, 0x19, 0xb7, 0x16, + 0x66, 0x19, 0x2d, 0x43, 0x5d, 0xfe, 0x82, 0xe1, 0x93, 0x2a, 0x68, 0x05, 0x9a, 0x52, 0x20, 0xfd, + 0x57, 0xd1, 0x6a, 0xea, 0x3e, 0xc1, 0xac, 0x21, 0x53, 0xbf, 0x15, 0x30, 0x81, 0x49, 0x54, 0xda, + 0x31, 0xeb, 0xcc, 0x67, 0xea, 0x60, 0x36, 0x1b, 0x68, 0x23, 0xab, 0x35, 0x36, 0x9b, 0xcc, 0x3c, + 0x75, 0xc0, 0x9a, 0x4b, 0x6c, 0x89, 0x0a, 0x91, 0x98, 0xcb, 0x6c, 0x3d, 0x89, 0x97, 0x6b, 0x9a, + 0x68, 0x2b, 0xaf, 0x0b, 0x35, 0x57, 0xd8, 0x9e, 0xb4, 0xbe, 0xc1, 0x44, 0xbb, 0x24, 0xac, 0x49, + 0xc4, 0x22, 0xb9, 0x2f, 0x66, 0xf0, 0xc2, 0x63, 0xc1, 0x31, 0x17, 0xd8, 0x22, 0x15, 0xb1, 0x0c, + 0xb6, 0x69, 0x28, 0xe6, 0x6f, 0xf9, 0xfb, 0xe8, 0x4e, 0xfa, 0x7d, 0xb3, 0xa0, 0x88, 0xe3, 0x2d, + 0x98, 0xc5, 0xe7, 0x9d, 0xef, 0xfe, 0xb1, 0x6d, 0x7c, 0xfb, 0x61, 0xdb, 0xf8, 0xee, 0xc3, 0xb6, + 0xf1, 0xf7, 0x0f, 0xdb, 0x0b, 0x7f, 0xfe, 0xe7, 0xb6, 0xf1, 0x3b, 0xf5, 0xdf, 0xde, 0xb5, 0x43, + 0x03, 0x77, 0xea, 0xf3, 0x9a, 0x32, 0x1c, 0x78, 0x64, 0x6f, 0x74, 0x75, 0xb1, 0x37, 0x3a, 0xdf, + 0x63, 0x7b, 0x38, 0x2f, 0xf3, 0x3f, 0x7a, 0x8f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x91, 0xd7, + 0xe0, 0x62, 0x25, 0x1c, 0x00, 0x00, } func (m *LockOptions) Marshal() (dAtA []byte, err error) { @@ -3205,6 +3336,18 @@ func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1 i-- dAtA[i] = 0xa2 + { + size, err := m.GetLockHolder.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLock(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x9a { size, err := m.ResumeInvalidCN.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -3408,6 +3551,18 @@ func (m *Response) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + { + size, err := m.GetLockHolder.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLock(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xaa { size, err := m.AbortRemoteDeadlockTxn.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -3794,6 +3949,82 @@ func (m *GetTxnLockResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GetLockHolderRequest) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetLockHolderRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetLockHolderRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Sharding != 0 { + i = encodeVarintLock(dAtA, i, uint64(m.Sharding)) + i-- + dAtA[i] = 0x10 + } + if len(m.Row) > 0 { + i -= len(m.Row) + copy(dAtA[i:], m.Row) + i = encodeVarintLock(dAtA, i, uint64(len(m.Row))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GetLockHolderResponse) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetLockHolderResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetLockHolderResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.Holder.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLock(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *GetWaitingListRequest) Marshal() (dAtA []byte, err error) { size := m.ProtoSize() dAtA = make([]byte, size) @@ -5255,6 +5486,8 @@ func (m *Request) ProtoSize() (n int) { n += 2 + l + sovLock(uint64(l)) l = m.ResumeInvalidCN.ProtoSize() n += 2 + l + sovLock(uint64(l)) + l = m.GetLockHolder.ProtoSize() + n += 2 + l + sovLock(uint64(l)) l = m.AbortRemoteDeadlockTxn.ProtoSize() n += 2 + l + sovLock(uint64(l)) if m.XXX_unrecognized != nil { @@ -5315,6 +5548,8 @@ func (m *Response) ProtoSize() (n int) { n += 2 + l + sovLock(uint64(l)) l = m.AbortRemoteDeadlockTxn.ProtoSize() n += 2 + l + sovLock(uint64(l)) + l = m.GetLockHolder.ProtoSize() + n += 2 + l + sovLock(uint64(l)) if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -5404,6 +5639,39 @@ func (m *GetTxnLockResponse) ProtoSize() (n int) { return n } +func (m *GetLockHolderRequest) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Row) + if l > 0 { + n += 1 + l + sovLock(uint64(l)) + } + if m.Sharding != 0 { + n += 1 + sovLock(uint64(m.Sharding)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GetLockHolderResponse) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Holder.ProtoSize() + n += 1 + l + sovLock(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *GetWaitingListRequest) ProtoSize() (n int) { if m == nil { return 0 @@ -7044,6 +7312,39 @@ func (m *Request) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 19: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GetLockHolder", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLock + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLock + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GetLockHolder.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex case 20: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AbortRemoteDeadlockTxn", wireType) @@ -7764,6 +8065,39 @@ func (m *Response) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 21: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GetLockHolder", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLock + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLock + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GetLockHolder.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipLock(dAtA[iNdEx:]) @@ -8275,6 +8609,194 @@ func (m *GetTxnLockResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *GetLockHolderRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetLockHolderRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetLockHolderRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Row", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthLock + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthLock + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Row = append(m.Row[:0], dAtA[iNdEx:postIndex]...) + if m.Row == nil { + m.Row = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sharding", wireType) + } + m.Sharding = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sharding |= Sharding(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLock(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLock + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetLockHolderResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetLockHolderResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetLockHolderResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Holder", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLock + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLock + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLock + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Holder.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLock(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLock + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *GetWaitingListRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/sql/plan/function/func_unary.go b/pkg/sql/plan/function/func_unary.go index d0176d275b79a..09088ff9031a6 100644 --- a/pkg/sql/plan/function/func_unary.go +++ b/pkg/sql/plan/function/func_unary.go @@ -6984,7 +6984,9 @@ type userLevelLockKey struct { var userLevelLocks = struct { sync.Mutex - counts map[userLevelLockKey]uint64 + //owner, lockname -> count + counts map[userLevelLockKey]uint64 + //owner -> lockername byOwner map[string]map[string]struct{} }{ counts: make(map[userLevelLockKey]uint64), @@ -7005,8 +7007,15 @@ func userLevelLockOwner(proc *process.Process) string { return fmt.Sprintf("%d", si.GetConnectionID()) } +func userLevelLockConnectionID(proc *process.Process) uint64 { + if proc == nil || proc.GetSessionInfo() == nil { + return 0 + } + return proc.GetSessionInfo().GetConnectionID() +} + // maxUserLevelLockNameLength is the MySQL-compatible maximum length for -// user-level lock names (GET_LOCK, RELEASE_LOCK, IS_FREE_LOCK). +// user-level lock names (GET_LOCK, RELEASE_LOCK, IS_FREE_LOCK, IS_USED_LOCK). const maxUserLevelLockNameLength = 64 // normalizeUserLevelLockName validates and normalizes a MySQL user-level lock name. @@ -7016,6 +7025,9 @@ func normalizeUserLevelLockName(name string) (string, error) { if len(name) == 0 { return "", moerr.NewInternalErrorNoCtx("user-level lock name must not be empty") } + if strings.IndexByte(name, 0) >= 0 { + return "", moerr.NewInternalErrorNoCtx("user-level lock name must not contain NUL bytes") + } normalized := strings.ToLower(name) if utf8.RuneCountInString(normalized) > maxUserLevelLockNameLength { return "", moerr.NewInternalErrorNoCtxf( @@ -7026,10 +7038,33 @@ func normalizeUserLevelLockName(name string) (string, error) { return normalized, nil } -func userLevelLockTxnID(owner, name string) []byte { +func userLevelLockTxnID(owner string, connID uint64, name string) []byte { + return []byte(fmt.Sprintf("mo-user-level-lock\x00%s\x00%s\x00%d", owner, name, connID)) +} + +func userLevelLockTxnIDOld(owner, name string) []byte { return []byte("mo-user-level-lock\x00" + owner + "\x00" + name) } +func userLevelLockProbeTxnID(owner string, connID uint64, name, probeType string) []byte { + return []byte(fmt.Sprintf("mo-user-level-lock-probe\x00%s\x00%s\x00%s\x00%d", probeType, owner, name, connID)) +} + +func userLevelLockConnectionIDFromTxnID(txnID []byte) (uint64, bool) { + parts := strings.Split(string(txnID), "\x00") + if len(parts) < 3 || len(parts) > 4 || parts[0] != "mo-user-level-lock" { + return 0, false + } + if len(parts) == 3 { + return 0, false + } + connID, err := strconv.ParseUint(parts[3], 10, 64) + if err != nil { + return 0, false + } + return connID, true +} + func userLevelLockRow(proc *process.Process, name string) []byte { account := "" if proc != nil && proc.GetSessionInfo() != nil { @@ -7045,6 +7080,13 @@ func userLevelLockService(proc *process.Process) (lockservice.LockService, error return proc.GetLockService(), nil } +func unlockUserLevelLockTxnIDs(ctx context.Context, ls lockservice.LockService, owner string, connID uint64, name string) error { + if err := ls.Unlock(ctx, userLevelLockTxnID(owner, connID, name), timestamp.Timestamp{}); err != nil { + return err + } + return ls.Unlock(ctx, userLevelLockTxnIDOld(owner, name), timestamp.Timestamp{}) +} + func userLevelLockOptions(policy lockpb.WaitPolicy) lockpb.LockOptions { return lockpb.LockOptions{ Granularity: lockpb.Granularity_Row, @@ -7115,6 +7157,25 @@ func untrackUserLevelLock(owner, name string) (uint64, bool) { return 0, true } +func untrackAllUserLevelLock(owner, name string) (uint64, bool) { + key := userLevelLockKey{owner: owner, name: name} + userLevelLocks.Lock() + defer userLevelLocks.Unlock() + + count := userLevelLocks.counts[key] + if count == 0 { + return 0, false + } + delete(userLevelLocks.counts, key) + if names := userLevelLocks.byOwner[owner]; names != nil { + delete(names, name) + if len(names) == 0 { + delete(userLevelLocks.byOwner, owner) + } + } + return count, true +} + func userLevelLocksForOwner(owner string) []string { userLevelLocks.Lock() defer userLevelLocks.Unlock() @@ -7139,8 +7200,15 @@ func getUserLevelLock(name string, timeout float64, proc *process.Process) (int6 if err != nil { return 0, err } + //owner = sessionid or serviceid:connectionid or connectionid owner := userLevelLockOwner(proc) + //connectionid + connID := userLevelLockConnectionID(proc) + //owner+lockname -> count + //serviceid:connectionid + lockname -> count if userLevelLockRefCount(owner, name) > 0 { + //count++ + //owner -> lockname trackUserLevelLock(owner, name) return 1, nil } @@ -7152,7 +7220,7 @@ func getUserLevelLock(name string, timeout float64, proc *process.Process) (int6 ctx, userLevelLockTableID, [][]byte{userLevelLockRow(proc, name)}, - userLevelLockTxnID(owner, name), + userLevelLockTxnID(owner, connID, name), userLevelLockOptions(policy)) if err != nil { if userLevelLockConflictOrTimeout(err) { @@ -7179,16 +7247,16 @@ func releaseUserLevelLock(name string, proc *process.Process) (int64, bool, erro return 0, false, err } owner := userLevelLockOwner(proc) + connID := userLevelLockConnectionID(proc) count := userLevelLockRefCount(owner, name) if count == 0 { // Probe the lockservice to distinguish "lock does not exist" (NULL) // from "lock exists but held by another session" (0). - probeOwner := owner + "\x00release_probe\x00" + name _, probeErr := ls.Lock( proc.Ctx, userLevelLockTableID, [][]byte{userLevelLockRow(proc, name)}, - userLevelLockTxnID(probeOwner, name), + userLevelLockProbeTxnID(owner, connID, name, "release"), userLevelLockOptions(lockpb.WaitPolicy_FastFail)) if probeErr != nil { if userLevelLockConflictOrTimeout(probeErr) { @@ -7199,7 +7267,7 @@ func releaseUserLevelLock(name string, proc *process.Process) (int64, bool, erro } // Lock did not exist — we acquired it via the probe. Release it and // return NULL to signal the lock was already free. - if err := ls.Unlock(proc.Ctx, userLevelLockTxnID(probeOwner, name), timestamp.Timestamp{}); err != nil { + if err := ls.Unlock(proc.Ctx, userLevelLockProbeTxnID(owner, connID, name, "release"), timestamp.Timestamp{}); err != nil { return 0, false, err } return 0, true, nil @@ -7208,7 +7276,7 @@ func releaseUserLevelLock(name string, proc *process.Process) (int64, bool, erro untrackUserLevelLock(owner, name) return 1, false, nil } - if err := ls.Unlock(proc.Ctx, userLevelLockTxnID(owner, name), timestamp.Timestamp{}); err != nil { + if err := unlockUserLevelLockTxnIDs(proc.Ctx, ls, owner, connID, name); err != nil { return 0, false, err } untrackUserLevelLock(owner, name) @@ -7225,12 +7293,12 @@ func isUserLevelLockFree(name string, proc *process.Process) (int64, error) { return 0, err } owner := userLevelLockOwner(proc) - probeOwner := owner + "\x00probe\x00" + name + connID := userLevelLockConnectionID(proc) _, err = ls.Lock( proc.Ctx, userLevelLockTableID, [][]byte{userLevelLockRow(proc, name)}, - userLevelLockTxnID(probeOwner, name), + userLevelLockProbeTxnID(owner, connID, name, "is_free"), userLevelLockOptions(lockpb.WaitPolicy_FastFail)) if err != nil { if userLevelLockConflictOrTimeout(err) { @@ -7238,29 +7306,71 @@ func isUserLevelLockFree(name string, proc *process.Process) (int64, error) { } return 0, err } - if err := ls.Unlock(proc.Ctx, userLevelLockTxnID(probeOwner, name), timestamp.Timestamp{}); err != nil { + if err := ls.Unlock(proc.Ctx, userLevelLockProbeTxnID(owner, connID, name, "is_free"), timestamp.Timestamp{}); err != nil { return 0, err } return 1, nil } -func ReleaseUserLevelLocks(proc *process.Process) { +func isUserLevelLockUsed(name string, proc *process.Process) (uint64, bool, error) { + name, err := normalizeUserLevelLockName(name) + if err != nil { + return 0, false, err + } + ls, err := userLevelLockService(proc) + if err != nil { + return 0, false, err + } + + holder, ok, err := ls.GetLockHolder( + proc.Ctx, + userLevelLockTableID, + userLevelLockRow(proc, name), + userLevelLockOptions(lockpb.WaitPolicy_FastFail)) + if err != nil { + if moerr.IsMoErrCode(err, moerr.ErrNotSupported) { + return 0, true, nil + } + return 0, false, err + } + if !ok { + return 0, true, nil + } + holderConnID, ok := userLevelLockConnectionIDFromTxnID(holder.TxnID) + if !ok { + return 0, true, nil + } + return holderConnID, false, nil +} + +func releaseAllUserLevelLocks(proc *process.Process) (int64, error) { if proc == nil || proc.GetLockService() == nil { - return + return 0, nil } owner := userLevelLockOwner(proc) + connID := userLevelLockConnectionID(proc) + var released int64 + var firstErr error for _, name := range userLevelLocksForOwner(owner) { - for { - count, held := untrackUserLevelLock(owner, name) - if !held { - break - } - if count == 0 { - _ = proc.GetLockService().Unlock(context.Background(), userLevelLockTxnID(owner, name), timestamp.Timestamp{}) - break + if userLevelLockRefCount(owner, name) == 0 { + continue + } + if err := unlockUserLevelLockTxnIDs(context.Background(), proc.GetLockService(), owner, connID, name); err != nil { + logutil.Warn(fmt.Sprintf("releaseAllUserLevelLocks unlock failed: owner=%s lock=%s err=%v", owner, name, err)) + if firstErr == nil { + firstErr = err } + continue + } + if _, held := untrackAllUserLevelLock(owner, name); held { + released++ } } + return released, firstErr +} + +func ReleaseUserLevelLocks(proc *process.Process) { + _, _ = releaseAllUserLevelLocks(proc) } func GetLock(ivecs []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { @@ -7334,6 +7444,44 @@ func IsFreeLock(ivecs []*vector.Vector, result vector.FunctionResultWrapper, pro return nil } +func IsUsedLock(ivecs []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { + names := vector.GenerateFunctionStrParameter(ivecs[0]) + rs := vector.MustFunctionResult[uint64](result) + + for i := uint64(0); i < uint64(length); i++ { + name, null := names.GetStrValue(i) + if null { + if err := rs.Append(0, true); err != nil { + return err + } + continue + } + value, isNull, err := isUserLevelLockUsed(string(name), proc) + if err != nil { + return err + } + if err := rs.Append(value, isNull); err != nil { + return err + } + } + return nil +} + +func ReleaseAllLocks(_ []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { + rs := vector.MustFunctionResult[int64](result) + rsVec := rs.GetResultVector() + rss := vector.MustFixedColNoTypeCheck[int64](rsVec) + + for i := 0; i < length; i++ { + released, err := releaseAllUserLevelLocks(proc) + if err != nil { + return err + } + rss[i] = released + } + return nil +} + func Version( _ []*vector.Vector, result vector.FunctionResultWrapper, diff --git a/pkg/sql/plan/function/func_unary_test.go b/pkg/sql/plan/function/func_unary_test.go index ec04a6b35ec59..7cc1ac7b1741f 100644 --- a/pkg/sql/plan/function/func_unary_test.go +++ b/pkg/sql/plan/function/func_unary_test.go @@ -7175,8 +7175,17 @@ type userLevelLockTestState struct { } type userLevelLockTestService struct { - id string - state *userLevelLockTestState + id string + state *userLevelLockTestState + unlockErr error +} + +type userLevelLockNotSupportedService struct { + lockservice.LockService +} + +func (s *userLevelLockNotSupportedService) GetLockHolder(context.Context, uint64, []byte, lockpb.LockOptions) (lockpb.WaitTxn, bool, error) { + return lockpb.WaitTxn{}, false, moerr.NewNotSupportedNoCtx("GetLockHolder") } func (s *userLevelLockTestService) GetServiceID() string { @@ -7215,6 +7224,9 @@ func (s *userLevelLockTestService) Lock(ctx context.Context, tableID uint64, row } func (s *userLevelLockTestService) Unlock(ctx context.Context, txnID []byte, commitTS timestamp.Timestamp, mutations ...lockpb.ExtraMutation) error { + if s.unlockErr != nil { + return s.unlockErr + } owner := string(txnID) s.state.Lock() defer s.state.Unlock() @@ -7238,6 +7250,16 @@ func (s *userLevelLockTestService) GetWaitingList(ctx context.Context, txnID []b return false, nil, nil } +func (s *userLevelLockTestService) GetLockHolder(ctx context.Context, tableID uint64, row []byte, options lockpb.LockOptions) (lockpb.WaitTxn, bool, error) { + s.state.Lock() + defer s.state.Unlock() + holder := s.state.locks[string(row)] + if holder == "" { + return lockpb.WaitTxn{}, false, nil + } + return lockpb.WaitTxn{TxnID: []byte(holder)}, true, nil +} + func (s *userLevelLockTestService) ForceRefreshLockTableBinds(targets []uint64, matcher func(bind lockpb.LockTable) bool) { } @@ -7263,6 +7285,13 @@ func runUserLevelLockTest(t *testing.T, fn func([]lockservice.LockService)) { resetUserLevelLocksForTest(t) } +func TestUserLevelLockConnectionIDFromProbeTxnID(t *testing.T) { + txnID := userLevelLockProbeTxnID("owner-1", 1001, "probe_lock", "is_free") + connID, ok := userLevelLockConnectionIDFromTxnID(txnID) + require.False(t, ok) + require.Equal(t, uint64(0), connID) +} + func TestUserLevelLockFunctions(t *testing.T) { runUserLevelLockTest(t, func(services []lockservice.LockService) { proc := newUserLevelLockTestProcess(t, services[0], "acc") @@ -7290,6 +7319,14 @@ func TestUserLevelLockFunctions(t *testing.T) { expect: NewFunctionTestResult(types.T_int64.ToType(), false, []int64{0}, []bool{false}), fn: IsFreeLock, }, + { + name: "used lock returns holder connection id", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"prisma_migrate_lock"}, []bool{false}), + }, + expect: NewFunctionTestResult(types.T_uint64.ToType(), false, []uint64{proc.GetSessionInfo().ConnectionID}, []bool{false}), + fn: IsUsedLock, + }, { name: "release held lock", inputs: []FunctionTestInput{ @@ -7327,6 +7364,52 @@ func TestUserLevelLockFunctions(t *testing.T) { }) } +func TestUserLevelLockFunctionNullInputs(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc := newUserLevelLockTestProcess(t, services[0], "acc") + + cases := []struct { + name string + inputs []FunctionTestInput + expect FunctionTestResult + fn fEvalFn + }{ + { + name: "release lock returns null for null name", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{""}, []bool{true}), + }, + expect: NewFunctionTestResult(types.T_int64.ToType(), false, []int64{0}, []bool{true}), + fn: ReleaseLock, + }, + { + name: "is free lock returns null for null name", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{""}, []bool{true}), + }, + expect: NewFunctionTestResult(types.T_int64.ToType(), false, []int64{0}, []bool{true}), + fn: IsFreeLock, + }, + { + name: "is used lock returns null for null name", + inputs: []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{""}, []bool{true}), + }, + expect: NewFunctionTestResult(types.T_uint64.ToType(), false, []uint64{0}, []bool{true}), + fn: IsUsedLock, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + fcTC := NewFunctionTestCase(proc, tc.inputs, tc.expect, tc.fn) + s, info := fcTC.Run() + require.True(t, s, info) + }) + } + }) +} + func TestUserLevelLockContention(t *testing.T) { runUserLevelLockTest(t, func(services []lockservice.LockService) { proc1 := newUserLevelLockTestProcess(t, services[0], "acc") @@ -7452,6 +7535,323 @@ func TestReleaseUserLevelLocksCleanup(t *testing.T) { }) } +func TestUserLevelLockConcurrentSessionOperations(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + const ( + workers = 8 + iterations = 40 + ) + + lockName := "concurrent_lock" + procs := make([]*process.Process, 0, workers) + for i := 0; i < workers; i++ { + procs = append(procs, newUserLevelLockTestProcess(t, services[i%len(services)], "acc")) + } + + start := make(chan struct{}) + errCh := make(chan error, workers) + var wg sync.WaitGroup + + for idx, proc := range procs { + wg.Add(1) + go func(worker int, proc *process.Process) { + defer wg.Done() + <-start + + for iter := 0; iter < iterations; iter++ { + value, err := getUserLevelLock(lockName, 0, proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d get lock: %w", worker, iter, err) + return + } + if value == 1 { + if iter%3 == 0 { + reentrant, err := getUserLevelLock(lockName, 0, proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d reentrant get: %w", worker, iter, err) + return + } + if reentrant != 1 { + errCh <- fmt.Errorf("worker %d iter %d expected reentrant get to succeed, got %d", worker, iter, reentrant) + return + } + } + + if iter%2 == 0 { + released, isNull, err := releaseUserLevelLock(lockName, proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d release lock: %w", worker, iter, err) + return + } + if isNull || released != 1 { + errCh <- fmt.Errorf("worker %d iter %d unexpected release result: released=%d isNull=%v", worker, iter, released, isNull) + return + } + } else { + released, err := releaseAllUserLevelLocks(proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d release_all: %w", worker, iter, err) + return + } + if released < 1 { + errCh <- fmt.Errorf("worker %d iter %d expected release_all to release at least one lock, got %d", worker, iter, released) + return + } + } + } else { + _, _, err := isUserLevelLockUsed(lockName, proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d is_used_lock: %w", worker, iter, err) + return + } + if iter%5 == 0 { + released, err := releaseAllUserLevelLocks(proc) + if err != nil { + errCh <- fmt.Errorf("worker %d iter %d release_all: %w", worker, iter, err) + return + } + if released != 0 { + errCh <- fmt.Errorf("worker %d iter %d expected release_all to release 0 locks, got %d", worker, iter, released) + return + } + } + } + } + }(idx, proc) + } + + close(start) + wg.Wait() + close(errCh) + for err := range errCh { + require.NoError(t, err) + } + + for _, proc := range procs { + released, err := releaseAllUserLevelLocks(proc) + require.NoError(t, err) + require.Equal(t, int64(0), released) + } + + finalProc := newUserLevelLockTestProcess(t, services[0], "acc") + value, err := getUserLevelLock(lockName, 0, finalProc) + require.NoError(t, err) + require.Equal(t, int64(1), value) + released, isNull, err := releaseUserLevelLock(lockName, finalProc) + require.NoError(t, err) + require.False(t, isNull) + require.Equal(t, int64(1), released) + }) +} + +func TestIsUsedLockReturnsHolderConnectionID(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + proc2 := newUserLevelLockTestProcess(t, services[1], "acc") + proc1.GetSessionInfo().ConnectionID = 1001 + proc2.GetSessionInfo().ConnectionID = 1002 + + v, err := getUserLevelLock("holder_lock", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + + holder, isNull, err := isUserLevelLockUsed("holder_lock", proc2) + require.NoError(t, err) + require.False(t, isNull) + require.Equal(t, uint64(1001), holder) + + holder, isNull, err = isUserLevelLockUsed("missing_holder_lock", proc2) + require.NoError(t, err) + require.True(t, isNull) + require.Equal(t, uint64(0), holder) + }) +} + +func TestIsUsedLockReturnsNullForLegacyHolderTxnID(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc := newUserLevelLockTestProcess(t, services[0], "acc") + state := services[0].(*userLevelLockTestService).state + state.Lock() + state.locks[string(userLevelLockRow(proc, "legacy_holder"))] = string(userLevelLockTxnIDOld(userLevelLockOwner(proc), "legacy_holder")) + state.Unlock() + + holder, isNull, err := isUserLevelLockUsed("legacy_holder", proc) + require.NoError(t, err) + require.True(t, isNull) + require.Equal(t, uint64(0), holder) + }) +} + +func TestIsUsedLockReturnsNullWhenHolderLookupNotSupported(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc := newUserLevelLockTestProcess(t, &userLevelLockNotSupportedService{LockService: services[0]}, "acc") + + holder, isNull, err := isUserLevelLockUsed("holder_lookup_not_supported", proc) + require.NoError(t, err) + require.True(t, isNull) + require.Equal(t, uint64(0), holder) + }) +} + +func TestIsUsedLockReturnsZeroConnectionID(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc := newUserLevelLockTestProcess(t, services[0], "acc") + state := services[0].(*userLevelLockTestService).state + state.Lock() + state.locks[string(userLevelLockRow(proc, "zero_conn_holder"))] = string(userLevelLockTxnID(userLevelLockOwner(proc), 0, "zero_conn_holder")) + state.Unlock() + + holder, isNull, err := isUserLevelLockUsed("zero_conn_holder", proc) + require.NoError(t, err) + require.False(t, isNull) + require.Equal(t, uint64(0), holder) + }) +} + +func TestIsUsedLockReturnsNullForMalformedHolderTxnID(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc := newUserLevelLockTestProcess(t, services[0], "acc") + state := services[0].(*userLevelLockTestService).state + state.Lock() + state.locks[string(userLevelLockRow(proc, "bad_holder"))] = "not-a-user-level-lock-txn" + state.Unlock() + + holder, isNull, err := isUserLevelLockUsed("bad_holder", proc) + require.NoError(t, err) + require.True(t, isNull) + require.Equal(t, uint64(0), holder) + }) +} + +func TestReleaseAllUserLevelLocksReturnsReleasedCount(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + proc2 := newUserLevelLockTestProcess(t, services[1], "acc") + + v, err := getUserLevelLock("release_all_a", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + v, err = getUserLevelLock("release_all_a", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + v, err = getUserLevelLock("release_all_b", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + + released, err := releaseAllUserLevelLocks(proc1) + require.NoError(t, err) + require.Equal(t, int64(2), released) + released, err = releaseAllUserLevelLocks(proc1) + require.NoError(t, err) + require.Equal(t, int64(0), released) + + v, err = getUserLevelLock("release_all_a", 0, proc2) + require.NoError(t, err) + require.Equal(t, int64(1), v) + v, isNull, err := releaseUserLevelLock("release_all_a", proc2) + require.NoError(t, err) + require.False(t, isNull) + require.Equal(t, int64(1), v) + + fcTC := NewFunctionTestCase( + proc1, + nil, + NewFunctionTestResult(types.T_int64.ToType(), false, []int64{0}, []bool{false}), + ReleaseAllLocks, + ) + s, info := fcTC.Run() + require.True(t, s, info) + }) +} + +func TestReleaseAllUserLevelLocksReturnsCountWhenUnlockFails(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + proc2 := newUserLevelLockTestProcess(t, services[1], "acc") + services[0].(*userLevelLockTestService).unlockErr = moerr.NewInternalErrorNoCtx("unlock failed") + + v, err := getUserLevelLock("release_all_fail_a", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + v, err = getUserLevelLock("release_all_fail_a", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + v, err = getUserLevelLock("release_all_fail_b", 0, proc1) + require.NoError(t, err) + require.Equal(t, int64(1), v) + + released, err := releaseAllUserLevelLocks(proc1) + require.Error(t, err) + require.Equal(t, int64(0), released) + + released, err = releaseAllUserLevelLocks(proc1) + require.Error(t, err) + require.Equal(t, int64(0), released) + + services[0].(*userLevelLockTestService).unlockErr = nil + released, err = releaseAllUserLevelLocks(proc1) + require.NoError(t, err) + require.Equal(t, int64(2), released) + + v, err = getUserLevelLock("release_all_fail_a", 0, proc2) + require.NoError(t, err) + require.Equal(t, int64(1), v) + }) +} + +func TestReleaseLockLegacyTxnIDCompatible(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + proc2 := newUserLevelLockTestProcess(t, services[1], "acc") + owner := userLevelLockOwner(proc1) + state := services[0].(*userLevelLockTestService).state + name := "legacy_release" + + state.Lock() + state.locks[string(userLevelLockRow(proc1, name))] = string(userLevelLockTxnIDOld(owner, name)) + state.Unlock() + trackUserLevelLock(owner, name) + + v, isNull, err := releaseUserLevelLock(name, proc1) + require.NoError(t, err) + require.False(t, isNull) + require.Equal(t, int64(1), v) + + v, err = getUserLevelLock(name, 0, proc2) + require.NoError(t, err) + require.Equal(t, int64(1), v) + }) +} + +func TestReleaseAllUserLevelLocksLegacyTxnIDCompatible(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + proc2 := newUserLevelLockTestProcess(t, services[1], "acc") + owner := userLevelLockOwner(proc1) + state := services[0].(*userLevelLockTestService).state + + state.Lock() + state.locks[string(userLevelLockRow(proc1, "legacy_all_a"))] = string(userLevelLockTxnIDOld(owner, "legacy_all_a")) + state.locks[string(userLevelLockRow(proc1, "legacy_all_b"))] = string(userLevelLockTxnIDOld(owner, "legacy_all_b")) + state.Unlock() + trackUserLevelLock(owner, "legacy_all_a") + trackUserLevelLock(owner, "legacy_all_a") + trackUserLevelLock(owner, "legacy_all_b") + + released, err := releaseAllUserLevelLocks(proc1) + require.NoError(t, err) + require.Equal(t, int64(2), released) + + v, err := getUserLevelLock("legacy_all_a", 0, proc2) + require.NoError(t, err) + require.Equal(t, int64(1), v) + + v, err = getUserLevelLock("legacy_all_b", 0, proc2) + require.NoError(t, err) + require.Equal(t, int64(1), v) + }) +} + func TestReleaseLockNeverCreatedReturnsNull(t *testing.T) { runUserLevelLockTest(t, func(services []lockservice.LockService) { proc1 := newUserLevelLockTestProcess(t, services[0], "acc") @@ -7548,6 +7948,25 @@ func TestUserLevelLockEmptyName(t *testing.T) { }) } +func TestUserLevelLockNameContainsNUL(t *testing.T) { + runUserLevelLockTest(t, func(services []lockservice.LockService) { + proc1 := newUserLevelLockTestProcess(t, services[0], "acc") + name := "bad\x00lock" + + _, err := getUserLevelLock(name, 0, proc1) + require.Error(t, err) + + _, _, err = releaseUserLevelLock(name, proc1) + require.Error(t, err) + + _, err = isUserLevelLockFree(name, proc1) + require.Error(t, err) + + _, _, err = isUserLevelLockUsed(name, proc1) + require.Error(t, err) + }) +} + func TestUserLevelLockCaseInsensitive(t *testing.T) { runUserLevelLockTest(t, func(services []lockservice.LockService) { proc1 := newUserLevelLockTestProcess(t, services[0], "acc") diff --git a/pkg/sql/plan/function/function_id.go b/pkg/sql/plan/function/function_id.go index adc8216cfd71b..7182739cae87f 100644 --- a/pkg/sql/plan/function/function_id.go +++ b/pkg/sql/plan/function/function_id.go @@ -727,14 +727,16 @@ const ( UUID_TO_BIN = 516 BIN_TO_UUID = 517 - GET_LOCK = 518 - RELEASE_LOCK = 519 - IS_FREE_LOCK = 520 - NAME_CONST = 521 + GET_LOCK = 518 + RELEASE_LOCK = 519 + IS_FREE_LOCK = 520 + NAME_CONST = 521 + IS_USED_LOCK = 522 + RELEASE_ALL_LOCKS = 523 // FUNCTION_END_NUMBER is not a function, just a flag to record the max number of function. // TODO: every one should put the new function id in front of this one if you want to make a new function. - FUNCTION_END_NUMBER = 522 + FUNCTION_END_NUMBER = 524 ) // functionIdRegister is what function we have registered already. @@ -1080,6 +1082,8 @@ var functionIdRegister = map[string]int32{ "get_lock": GET_LOCK, "release_lock": RELEASE_LOCK, "is_free_lock": IS_FREE_LOCK, + "is_used_lock": IS_USED_LOCK, + "release_all_locks": RELEASE_ALL_LOCKS, "split_part": SPLIT_PART, "insert": INSERT, "instr": INSTR, diff --git a/pkg/sql/plan/function/function_id_test.go b/pkg/sql/plan/function/function_id_test.go index 6e3170a8e784a..b712f382dacaa 100644 --- a/pkg/sql/plan/function/function_id_test.go +++ b/pkg/sql/plan/function/function_id_test.go @@ -575,9 +575,11 @@ var predefinedFunids = map[int]int{ RELEASE_LOCK: 519, IS_FREE_LOCK: 520, NAME_CONST: 521, + IS_USED_LOCK: 522, + RELEASE_ALL_LOCKS: 523, // FUNCTION_END_NUMBER is not a function, just a flag to record the max number of function. // TODO: every one should put the new function id in front of this one if you want to make a new function. - FUNCTION_END_NUMBER: 522, + FUNCTION_END_NUMBER: 524, } func Test_funids(t *testing.T) { diff --git a/pkg/sql/plan/function/function_test.go b/pkg/sql/plan/function/function_test.go index 76e0c8a26e967..27118dd717845 100644 --- a/pkg/sql/plan/function/function_test.go +++ b/pkg/sql/plan/function/function_test.go @@ -295,10 +295,13 @@ func TestUserLevelLockBuiltinRegistration(t *testing.T) { name string id int args []types.T + ret types.Type }{ - {name: "get_lock", id: GET_LOCK, args: []types.T{types.T_varchar, types.T_float64}}, - {name: "release_lock", id: RELEASE_LOCK, args: []types.T{types.T_varchar}}, - {name: "is_free_lock", id: IS_FREE_LOCK, args: []types.T{types.T_varchar}}, + {name: "get_lock", id: GET_LOCK, args: []types.T{types.T_varchar, types.T_float64}, ret: types.T_int64.ToType()}, + {name: "release_lock", id: RELEASE_LOCK, args: []types.T{types.T_varchar}, ret: types.T_int64.ToType()}, + {name: "is_free_lock", id: IS_FREE_LOCK, args: []types.T{types.T_varchar}, ret: types.T_int64.ToType()}, + {name: "is_used_lock", id: IS_USED_LOCK, args: []types.T{types.T_varchar}, ret: types.T_uint64.ToType()}, + {name: "release_all_locks", id: RELEASE_ALL_LOCKS, args: []types.T{}, ret: types.T_int64.ToType()}, } for _, tc := range cases { @@ -319,7 +322,7 @@ func TestUserLevelLockBuiltinRegistration(t *testing.T) { require.Equal(t, tc.args, overload.args) require.True(t, overload.volatile) require.True(t, overload.realTimeRelated) - require.Equal(t, types.T_int64.ToType(), overload.retType(nil)) + require.Equal(t, tc.ret, overload.retType(nil)) require.NotNil(t, overload.newOp()) }) } diff --git a/pkg/sql/plan/function/list_builtIn.go b/pkg/sql/plan/function/list_builtIn.go index 561e615d5a3ea..5c38b433805d8 100644 --- a/pkg/sql/plan/function/list_builtIn.go +++ b/pkg/sql/plan/function/list_builtIn.go @@ -10651,6 +10651,52 @@ var supportedControlBuiltIns = []FuncNew{ }, }, + // function `is_used_lock` + { + functionId: IS_USED_LOCK, + class: plan.Function_STRICT, + layout: STANDARD_FUNCTION, + checkFn: fixedTypeMatch, + + Overloads: []overload{ + { + overloadId: 0, + args: []types.T{types.T_varchar}, + volatile: true, + realTimeRelated: true, + retType: func(parameters []types.Type) types.Type { + return types.T_uint64.ToType() + }, + newOp: func() executeLogicOfOverload { + return IsUsedLock + }, + }, + }, + }, + + // function `release_all_locks` + { + functionId: RELEASE_ALL_LOCKS, + class: plan.Function_STRICT, + layout: STANDARD_FUNCTION, + checkFn: fixedTypeMatch, + + Overloads: []overload{ + { + overloadId: 0, + args: []types.T{}, + volatile: true, + realTimeRelated: true, + retType: func(parameters []types.Type) types.Type { + return types.T_int64.ToType() + }, + newOp: func() executeLogicOfOverload { + return ReleaseAllLocks + }, + }, + }, + }, + // function `trigger_fault_point` { functionId: TRIGGER_FAULT_POINT, diff --git a/pkg/vm/engine/test/testutil/disttae_engine.go b/pkg/vm/engine/test/testutil/disttae_engine.go index e2ab4cca4d420..785d933642bd9 100644 --- a/pkg/vm/engine/test/testutil/disttae_engine.go +++ b/pkg/vm/engine/test/testutil/disttae_engine.go @@ -597,6 +597,9 @@ func (ml *mockLockService) Close() error { func (ml *mockLockService) GetWaitingList(ctx context.Context, txnID []byte) (bool, []lock.WaitTxn, error) { return false, nil, nil } +func (ml *mockLockService) GetLockHolder(ctx context.Context, tableID uint64, row []byte, options lock.LockOptions) (lock.WaitTxn, bool, error) { + return lock.WaitTxn{}, false, nil +} func (ml *mockLockService) ForceRefreshLockTableBinds(targets []uint64, matcher func(bind lock.LockTable) bool) { } func (ml *mockLockService) GetLockTableBind(group uint32, tableID uint64) (lock.LockTable, error) { diff --git a/proto/lock.proto b/proto/lock.proto index 4e35d8aa5c678..956bd914fc6c9 100644 --- a/proto/lock.proto +++ b/proto/lock.proto @@ -117,6 +117,8 @@ enum Method { ResumeInvalidCN = 16; // AbortRemoteDeadlockTxn abort remote txn for deadlock AbortRemoteDeadlockTxn = 17; + // GetLockHolder get current holder on a special lock + GetLockHolder = 18; } enum Status { @@ -149,6 +151,7 @@ message Request { RemainTxnInServiceRequest RemainTxnInService = 16 [(gogoproto.nullable) = false]; CheckOrphanRequest CheckOrphan = 17 [(gogoproto.nullable) = false]; ResumeInvalidCNRequest ResumeInvalidCN = 18 [(gogoproto.nullable) = false]; + GetLockHolderRequest GetLockHolder = 19 [(gogoproto.nullable) = false]; AbortRemoteDeadlockTxnRequest AbortRemoteDeadlockTxn = 20 [(gogoproto.nullable) = false]; } @@ -179,6 +182,7 @@ message Response { CheckOrphanResponse CheckOrphan = 18 [(gogoproto.nullable) = false]; ResumeInvalidCNResponse ResumeInvalidCN = 19 [(gogoproto.nullable) = false]; AbortRemoteDeadlockTxnResponse AbortRemoteDeadlockTxn = 20 [(gogoproto.nullable) = false]; + GetLockHolderResponse GetLockHolder = 21 [(gogoproto.nullable) = false]; } // LockRequest lock request @@ -208,6 +212,17 @@ message GetTxnLockResponse { repeated WaitTxn WaitingList = 2 [(gogoproto.nullable) = false]; } +// GetLockHolderRequest gets the current holder on a special row lock. +message GetLockHolderRequest { + bytes Row = 1; + Sharding Sharding = 2; +} + +// GetLockHolderResponse gets the current holder on a special row lock. +message GetLockHolderResponse { + WaitTxn Holder = 1 [(gogoproto.nullable) = false]; +} + // GetWaitingListRequest get a waiting txn list on a specical txn request. CN -> CN message GetWaitingListRequest { WaitTxn Txn = 1 [(gogoproto.nullable) = false]; @@ -397,4 +412,4 @@ message ResumeInvalidCNRequest { message ResumeInvalidCNResponse { -} \ No newline at end of file +} diff --git a/test/distributed/cases/function/user_lock.result b/test/distributed/cases/function/user_lock.result new file mode 100644 index 0000000000000..dc5edfc8f99c9 --- /dev/null +++ b/test/distributed/cases/function/user_lock.result @@ -0,0 +1,103 @@ +drop database if exists user_lock_bvt_db; +create database user_lock_bvt_db; +use user_lock_bvt_db; +create table user_lock_bvt_holder (conn_id bigint unsigned); +select is_free_lock('user_lock_bvt_lock'); +➤ is_free_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +1 +select is_used_lock('user_lock_bvt_lock') is null; +➤ is_used_lock(user_lock_bvt_lock) is null[-7,1,0] 𝄀 +1 +select release_lock('user_lock_bvt_lock') is null; +➤ release_lock(user_lock_bvt_lock) is null[-7,1,0] 𝄀 +1 +use user_lock_bvt_db; +insert into user_lock_bvt_holder values (connection_id()); +select get_lock('user_lock_bvt_lock', 0); +➤ get_lock(user_lock_bvt_lock, 0)[-5,64,0] 𝄀 +1 +select get_lock('user_lock_bvt_lock', 0); +➤ get_lock(user_lock_bvt_lock, 0)[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_lock'); +➤ is_free_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +0 +select get_lock('user_lock_bvt_lock', 0); +➤ get_lock(user_lock_bvt_lock, 0)[-5,64,0] 𝄀 +0 +select is_used_lock('user_lock_bvt_lock') = (select conn_id from user_lock_bvt_holder); +➤ is_used_lock(user_lock_bvt_lock) = (select conn_id from user_lock_bvt_holder)[-7,1,0] 𝄀 +1 +select release_lock('user_lock_bvt_lock'); +➤ release_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +0 +use user_lock_bvt_db; +select is_used_lock('user_lock_bvt_lock') = (select conn_id from user_lock_bvt_holder); +➤ is_used_lock(user_lock_bvt_lock) = (select conn_id from user_lock_bvt_holder)[-7,1,0] 𝄀 +1 +select release_all_locks(); +➤ release_all_locks()[-5,64,0] 𝄀 +0 +use user_lock_bvt_db; +select is_free_lock('user_lock_bvt_lock'); +➤ is_free_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +0 +select release_lock('user_lock_bvt_lock'); +➤ release_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_lock'); +➤ is_free_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +0 +select release_all_locks(); +➤ release_all_locks()[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_lock'); +➤ is_free_lock(user_lock_bvt_lock)[-5,64,0] 𝄀 +1 +select is_used_lock('user_lock_bvt_lock') is null; +➤ is_used_lock(user_lock_bvt_lock) is null[-7,1,0] 𝄀 +1 +select get_lock('user_lock_bvt_lock', 0); +➤ get_lock(user_lock_bvt_lock, 0)[-5,64,0] 𝄀 +1 +select release_all_locks(); +➤ release_all_locks()[-5,64,0] 𝄀 +1 +select release_all_locks(); +➤ release_all_locks()[-5,64,0] 𝄀 +0 +select get_lock('user_lock_bvt_multi_a', 0); +➤ get_lock(user_lock_bvt_multi_a, 0)[-5,64,0] 𝄀 +1 +select get_lock('user_lock_bvt_multi_a', 0); +➤ get_lock(user_lock_bvt_multi_a, 0)[-5,64,0] 𝄀 +1 +select get_lock('user_lock_bvt_multi_a', 0); +➤ get_lock(user_lock_bvt_multi_a, 0)[-5,64,0] 𝄀 +1 +select get_lock('user_lock_bvt_multi_b', 0); +➤ get_lock(user_lock_bvt_multi_b, 0)[-5,64,0] 𝄀 +1 +select release_all_locks(); +➤ release_all_locks()[-5,64,0] 𝄀 +2 +select is_free_lock('user_lock_bvt_multi_a'); +➤ is_free_lock(user_lock_bvt_multi_a)[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_multi_b'); +➤ is_free_lock(user_lock_bvt_multi_b)[-5,64,0] 𝄀 +1 +select get_lock('User_Lock_Bvt_Case', 0); +➤ get_lock(User_Lock_Bvt_Case, 0)[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_case'); +➤ is_free_lock(user_lock_bvt_case)[-5,64,0] 𝄀 +0 +select release_lock('USER_LOCK_BVT_CASE'); +➤ release_lock(USER_LOCK_BVT_CASE)[-5,64,0] 𝄀 +1 +select is_free_lock('user_lock_bvt_case'); +➤ is_free_lock(user_lock_bvt_case)[-5,64,0] 𝄀 +1 +drop table user_lock_bvt_holder; +drop database user_lock_bvt_db; diff --git a/test/distributed/cases/function/user_lock.sql b/test/distributed/cases/function/user_lock.sql new file mode 100644 index 0000000000000..74aa7805cbd6b --- /dev/null +++ b/test/distributed/cases/function/user_lock.sql @@ -0,0 +1,62 @@ +-- @suite +-- @case +-- @desc:test mysql-compatible user-level lock functions +-- @label:bvt + +drop database if exists user_lock_bvt_db; +create database user_lock_bvt_db; +use user_lock_bvt_db; + +create table user_lock_bvt_holder (conn_id bigint unsigned); + +select is_free_lock('user_lock_bvt_lock'); +select is_used_lock('user_lock_bvt_lock') is null; +select release_lock('user_lock_bvt_lock') is null; + +-- @session:id=1{ +use user_lock_bvt_db; +insert into user_lock_bvt_holder values (connection_id()); +select get_lock('user_lock_bvt_lock', 0); +select get_lock('user_lock_bvt_lock', 0); +-- @session} + +select is_free_lock('user_lock_bvt_lock'); +select get_lock('user_lock_bvt_lock', 0); +select is_used_lock('user_lock_bvt_lock') = (select conn_id from user_lock_bvt_holder); +select release_lock('user_lock_bvt_lock'); + +-- @session:id=2{ +use user_lock_bvt_db; +select is_used_lock('user_lock_bvt_lock') = (select conn_id from user_lock_bvt_holder); +select release_all_locks(); +-- @session} + +-- @session:id=1{ +use user_lock_bvt_db; +select is_free_lock('user_lock_bvt_lock'); +select release_lock('user_lock_bvt_lock'); +select is_free_lock('user_lock_bvt_lock'); +select release_all_locks(); +-- @session} + +select is_free_lock('user_lock_bvt_lock'); +select is_used_lock('user_lock_bvt_lock') is null; +select get_lock('user_lock_bvt_lock', 0); +select release_all_locks(); +select release_all_locks(); + +select get_lock('user_lock_bvt_multi_a', 0); +select get_lock('user_lock_bvt_multi_a', 0); +select get_lock('user_lock_bvt_multi_a', 0); +select get_lock('user_lock_bvt_multi_b', 0); +select release_all_locks(); +select is_free_lock('user_lock_bvt_multi_a'); +select is_free_lock('user_lock_bvt_multi_b'); + +select get_lock('User_Lock_Bvt_Case', 0); +select is_free_lock('user_lock_bvt_case'); +select release_lock('USER_LOCK_BVT_CASE'); +select is_free_lock('user_lock_bvt_case'); + +drop table user_lock_bvt_holder; +drop database user_lock_bvt_db;