Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: try to support lock/unlock tables function #305

Merged
merged 19 commits into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions ast/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,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
)

// AddIndexStr is a string related to the operation of "add index".
Expand Down Expand Up @@ -88,6 +90,8 @@ var actionMap = map[ActionType]string{
ActionDropView: "drop view",
ActionRecoverTable: "recover table",
ActionModifySchemaCharsetAndCollate: "modify schema charset and collate",
ActionLockTable: "lock table",
ActionUnlockTable: "unlock table",
}

// String return current ddl action in string
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 @@ -936,6 +936,7 @@ const (
ErrRequireVersionCheckFail = 8107
ErrUnsupportedReloadPlugin = 8018
ErrUnsupportedReloadPluginVar = 8019
ErrTableLocked = 8020

// TiKV/PD errors.
ErrPDServerTimeout = 9001
Expand Down
1 change: 1 addition & 0 deletions mysql/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,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",

// TiKV/PD errors.
ErrPDServerTimeout: "PD server timeout",
Expand Down
Loading