Skip to content

Commit

Permalink
*: try to support lock/unlock tables function (#305) (#827)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazycs520 authored Apr 24, 2020
1 parent 70ac9ca commit b7f2b6e
Show file tree
Hide file tree
Showing 8 changed files with 2,627 additions and 2,386 deletions.
62 changes: 62 additions & 0 deletions ast/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,68 @@ func (n *DropIndexStmt) Accept(v Visitor) (Node, bool) {
return v.Leave(n)
}

// LockTablesStmt is a statement to lock tables.
type LockTablesStmt struct {
ddlNode

TableLocks []TableLock
}

// TableLock contains the table name and lock type.
type TableLock struct {
Table *TableName
Type model.TableLockType
}

// Accept implements Node Accept interface.
func (n *LockTablesStmt) Accept(v Visitor) (Node, bool) {
newNode, skipChildren := v.Enter(n)
if skipChildren {
return v.Leave(newNode)
}
n = newNode.(*LockTablesStmt)
for i := range n.TableLocks {
node, ok := n.TableLocks[i].Table.Accept(v)
if !ok {
return n, false
}
n.TableLocks[i].Table = node.(*TableName)
}
return v.Leave(n)
}

// Restore implements Node interface.
func (n *LockTablesStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("LOCK TABLES ")
for i, tl := range n.TableLocks {
if i != 0 {
ctx.WritePlain(", ")
}
if err := tl.Table.Restore(ctx); err != nil {
return errors.Annotate(err, "An error occurred while add index")
}
ctx.WriteKeyWord(" " + tl.Type.String())
}
return nil
}

// UnlockTablesStmt is a statement to unlock tables.
type UnlockTablesStmt struct {
ddlNode
}

// Accept implements Node Accept interface.
func (n *UnlockTablesStmt) Accept(v Visitor) (Node, bool) {
_, _ = v.Enter(n)
return v.Leave(n)
}

// Restore implements Node interface.
func (n *UnlockTablesStmt) Restore(ctx *RestoreCtx) error {
ctx.WriteKeyWord("UNLOCK TABLES")
return nil
}

// TableOptionType is the type for TableOption
type TableOptionType int

Expand Down
4 changes: 4 additions & 0 deletions model/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ const (
ActionDropView ActionType = 24
ActionRecoverTable ActionType = 25
ActionModifySchemaCharsetAndCollate ActionType = 26
ActionLockTable ActionType = 27
ActionUnlockTable ActionType = 28
ActionAddPrimaryKey ActionType = 32
ActionDropPrimaryKey ActionType = 33
)
Expand Down Expand Up @@ -93,6 +95,8 @@ var actionMap = map[ActionType]string{
ActionDropView: "drop view",
ActionRecoverTable: "recover table",
ActionModifySchemaCharsetAndCollate: "modify schema charset and collate",
ActionLockTable: "lock table",
ActionUnlockTable: "unlock table",
ActionAddPrimaryKey: AddPrimaryKeyStr,
ActionDropPrimaryKey: "drop primary key",
}
Expand Down
93 changes: 93 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package model

import (
"encoding/json"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -230,11 +231,98 @@ type TableInfo struct {
Compression string `json:"compression"`

View *ViewInfo `json:"view"`
// Lock represent the table lock info.
Lock *TableLockInfo `json:"Lock"`

// Version means the version of the table info.
Version uint16 `json:"version"`
}

// TableLockInfo provides meta data describing a table lock.
type TableLockInfo struct {
Tp TableLockType
// Use array because there may be multiple sessions holding the same read lock.
Sessions []SessionInfo
State TableLockState
// TS is used to record the timestamp this table lock been locked.
TS uint64
}

// SessionInfo contain the session ID and the server ID.
type SessionInfo struct {
ServerID string
SessionID uint64
}

func (s SessionInfo) String() string {
return "server: " + s.ServerID + "_session: " + strconv.FormatUint(s.SessionID, 10)
}

// TableLockTpInfo is composed by schema ID, table ID and table lock type.
type TableLockTpInfo struct {
SchemaID int64
TableID int64
Tp TableLockType
}

// TableLockState is the state for table lock.
type TableLockState byte

const (
// TableLockStateNone means this table lock is absent.
TableLockStateNone TableLockState = iota
// TableLockStatePreLock means this table lock is pre-lock state. Other session doesn't hold this lock should't do corresponding operation according to the lock type.
TableLockStatePreLock
// TableLockStatePublic means this table lock is public state.
TableLockStatePublic
)

// String implements fmt.Stringer interface.
func (t TableLockState) String() string {
switch t {
case TableLockStatePreLock:
return "pre-lock"
case TableLockStatePublic:
return "public"
default:
return "none"
}
}

// TableLockType is the type of the table lock.
type TableLockType byte

const (
TableLockNone TableLockType = iota
// TableLockRead means the session with this lock can read the table (but not write it).
// Multiple sessions can acquire a READ lock for the table at the same time.
// Other sessions can read the table without explicitly acquiring a READ lock.
TableLockRead
// TableLockReadLocal is not supported.
TableLockReadLocal
// TableLockWrite means only the session with this lock has write/read permission.
// Only the session that holds the lock can access the table. No other session can access it until the lock is released.
TableLockWrite
// TableLockWriteLocal means the session with this lock has write/read permission, and the other session still has read permission.
TableLockWriteLocal
)

func (t TableLockType) String() string {
switch t {
case TableLockNone:
return "NONE"
case TableLockRead:
return "READ"
case TableLockReadLocal:
return "READ LOCAL"
case TableLockWriteLocal:
return "WRITE LOCAL"
case TableLockWrite:
return "WRITE"
}
return ""
}

// GetPartitionInfo returns the partition information.
func (t *TableInfo) GetPartitionInfo() *PartitionInfo {
if t.Partition != nil && t.Partition.Enable {
Expand Down Expand Up @@ -345,6 +433,11 @@ func (t *TableInfo) FindIndexByName(idxName string) *IndexInfo {
return nil
}

// IsLocked checks whether the table was locked.
func (t *TableInfo) IsLocked() bool {
return t.Lock != nil && len(t.Lock.Sessions) > 0
}

// NewExtraHandleColInfo mocks a column info for extra handle column.
func NewExtraHandleColInfo() *ColumnInfo {
colInfo := &ColumnInfo{
Expand Down
1 change: 1 addition & 0 deletions mysql/errcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ const (
ErrRequireVersionCheckFail = 8107
ErrUnsupportedReloadPlugin = 8018
ErrUnsupportedReloadPluginVar = 8019
ErrTableLocked = 8020
ErrInfoSchemaExpired = 8027
ErrInfoSchemaChanged = 8028
ErrInvalidIncrementAndOffset = 8060
Expand Down
1 change: 1 addition & 0 deletions mysql/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,7 @@ var MySQLErrName = map[uint16]string{
ErrRequireVersionCheckFail: "Plugin %s require %s be %v but got %v",
ErrUnsupportedReloadPlugin: "Plugin %s isn't loaded so cannot be reloaded",
ErrUnsupportedReloadPluginVar: "Reload plugin with different sysVar is unsupported %v",
ErrTableLocked: "Table '%s' was locked in %s by %v",
ErrInfoSchemaExpired: "Information schema is out of date: schema failed to update in 1 lease, please make sure TiDB can connect to TiKV",
ErrInfoSchemaChanged: "Information schema is changed during the execution of the statement(for example, table definition may be updated by other DDL ran in parallel). If you see this error often, try increasing `tidb_max_delta_schema_count`",
ErrInvalidIncrementAndOffset: "Invalid auto_increment settings: auto_increment_increment: %d, auto_increment_offset: %d, both of them must be in range [1..65535]",
Expand Down
Loading

0 comments on commit b7f2b6e

Please sign in to comment.