lock

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2022 License: MIT Imports: 11 Imported by: 0

README

mysql-lock

golang-ci

a simple distributed lock based on mysql

Usage

go get github.com/vearne/mysql-lock

mysql-lock uses 2 methods to build MySQL's distributed lock

  • Method 1: row lock initialization
mlock.NewRowLockWithDSN()
mlock.NewRowLockWithConn()
  • Method 2: set flag initialization
mlock.NewCounterLockWithDSN()
mlock.NewCounterLockWithConn()

Notice :Distributed locks based on mysql are not rigorous for method 1.

For example, at t1, A holds the lock, and B waits for the lock. At t2, the network between A and MySQL is abnormal. MySQL actively releases the lock imposed by A (rolling back the transaction that A has not committed), and B adds the lock. At this time, A will think that it owns the lock; B will also think that it holds the lock. The distributed lock actually fails.

Notice: mysql-lock will create the table.

  • Method 1 creates the table _lock_store.
  • Method 2 creates the table _lock_counter.

So mysql-lock needs CREATE permission. Or you can use doc/schema.sql to create the table yourself.

Example

import (
	mlock "github.com/vearne/mysql-lock"
	"log"
	"time"
)

func main() {
	//debug := false
	debug := true
	dsn := "tc_user:20C462C9C614@tcp(127.0.0.1:3306)/xxx?charset=utf8&loc=Asia%2FShanghai&parseTime=true"

	var locker *mlock.MySQCounterLock
	locker = mlock.NewCounterLockWithDSN(dsn, debug)

	// init() can be executed multiple times
	locker.Init([]string{"lock1", "lock2"})
	// optional, only for CounterLock
	//locker.SetClientID("client1")
	// optional, only for CounterLock
	// default 1 minutes
	locker.SetMaxLockTime(1 * time.Minute)
	// optional, only for CounterLock
	// default NewLinearBackOff(1*time.Second)
	locker.WithBackOff(mlock.NewLinearBackOff(2 * time.Second))

	beginTime := time.Now()
	// max wait for 5 secs
	err := locker.Acquire("lock1", 50*time.Second)
	if err != nil {
		log.Println("can't acquire lock", "error", err)
		log.Println(time.Since(beginTime))
		return
	}

	log.Println("got lock1")
	log.Println(time.Since(beginTime))
	time.Sleep(30 * time.Second)
	locker.Release("lock1")
	log.Println("release lock1")
}

Documentation

Index

Constants

View Source
const (
	LockStatusOpen   = 0
	LockStatusClosed = 1
)

Variables

This section is empty.

Functions

func InitMySQLWithConn added in v0.0.4

func InitMySQLWithConn(sqlDB *sql.DB, debug bool) *gorm.DB

initialize *gorm.DB with an existing database connection

func InitMySQLWithDSN added in v0.0.4

func InitMySQLWithDSN(dsn string, debug bool) *gorm.DB

initialize *gorm.DB with dsn

Types

type BackOff added in v0.0.8

type BackOff interface {
	NextBackOff() time.Duration

	// Reset to initial state.
	Reset()
}

BackOff is a backoff policy for retrying an operation.

type ConstantBackOff added in v0.0.8

type ConstantBackOff struct {
	Interval time.Duration
}

func NewConstantBackOff added in v0.0.8

func NewConstantBackOff(d time.Duration) *ConstantBackOff

func (*ConstantBackOff) NextBackOff added in v0.0.8

func (b *ConstantBackOff) NextBackOff() time.Duration

func (*ConstantBackOff) Reset added in v0.0.8

func (b *ConstantBackOff) Reset()

type DoneStore added in v0.0.8

type DoneStore struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewDoneStore added in v0.0.8

func NewDoneStore() *DoneStore

func (*DoneStore) CLoseDoneChan added in v0.0.8

func (d *DoneStore) CLoseDoneChan(lockName string)

func (*DoneStore) CreateDoneChan added in v0.0.8

func (d *DoneStore) CreateDoneChan(lockName string)

func (*DoneStore) GetDoneChan added in v0.0.8

func (d *DoneStore) GetDoneChan(lockName string) chan struct{}

type ExponentialBackOff added in v0.0.8

type ExponentialBackOff struct {
	InitialInterval time.Duration
	Multiplier      float64
	Counter         int
}

func NewExponentialBackOff added in v0.0.8

func NewExponentialBackOff(initInterval time.Duration, multiplier float64) *ExponentialBackOff

func (*ExponentialBackOff) NextBackOff added in v0.0.8

func (l *ExponentialBackOff) NextBackOff() time.Duration

func (*ExponentialBackOff) Reset added in v0.0.8

func (l *ExponentialBackOff) Reset()

type LinearBackOff added in v0.0.8

type LinearBackOff struct {
	InitialInterval time.Duration
	Counter         int
}

func NewLinearBackOff added in v0.0.8

func NewLinearBackOff(initInterval time.Duration) *LinearBackOff

func (*LinearBackOff) NextBackOff added in v0.0.8

func (l *LinearBackOff) NextBackOff() time.Duration

func (*LinearBackOff) Reset added in v0.0.8

func (l *LinearBackOff) Reset()

type LockCounter added in v0.0.4

type LockCounter struct {
	Name       string    `gorm:"column:name;size:100;index:uni_name,unique" json:"name"`
	Owner      string    `gorm:"column:owner;size:100" json:"owner"`
	Counter    uint64    `gorm:"column:counter" json:"counter"`
	CreatedAt  time.Time `gorm:"column:created_at" json:"createdAt"`
	ModifiedAt time.Time `gorm:"column:modified_at" json:"modifiedAt"`
	ExpiredAt  time.Time `gorm:"column:expired_at" json:"expiredAt"`
	// other
	ID int `gorm:"column:id" json:"id"`
}

func (LockCounter) TableName added in v0.0.4

func (LockCounter) TableName() string

type LockStore

type LockStore struct {
	Name      string    `gorm:"column:name;size:100;index:uni_name,unique" json:"name"`
	CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"`
	// other
	ID int `gorm:"column:id" json:"id"`
}

func (LockStore) TableName

func (LockStore) TableName() string

type MySQCounterLock added in v0.0.4

type MySQCounterLock struct {
	MySQLClient *gorm.DB
	ClientID    string
	MaxLockTime time.Duration
	// contains filtered or unexported fields
}

func NewCounterLockWithConn added in v0.0.4

func NewCounterLockWithConn(db *sql.DB, debug bool) *MySQCounterLock

func NewCounterLockWithDSN added in v0.0.4

func NewCounterLockWithDSN(dsn string, debug bool) *MySQCounterLock

func (*MySQCounterLock) Acquire added in v0.0.4

func (l *MySQCounterLock) Acquire(lockName string, wait time.Duration) error

Lock :If the lock cannot be obtained, it will keep blocking wait: < 0 no wait

func (*MySQCounterLock) Init added in v0.0.4

func (l *MySQCounterLock) Init(lockNameList []string)

Init :Create tables

func (*MySQCounterLock) Refresh added in v0.0.8

func (l *MySQCounterLock) Refresh(lockName string) error

func (*MySQCounterLock) Release added in v0.0.4

func (l *MySQCounterLock) Release(lockName string) error

func (*MySQCounterLock) SetClientID added in v0.0.6

func (l *MySQCounterLock) SetClientID(clientID string)

func (*MySQCounterLock) SetMaxLockTime added in v0.0.8

func (l *MySQCounterLock) SetMaxLockTime(d time.Duration)

func (*MySQCounterLock) StopRefresh added in v0.0.8

func (l *MySQCounterLock) StopRefresh(lockName string)

func (*MySQCounterLock) WithBackOff added in v0.0.8

func (l *MySQCounterLock) WithBackOff(b BackOff)

type MySQLLockItf added in v0.0.4

type MySQLLockItf interface {
	Init(lockNameList []string)
	Acquire(lockName string, wait time.Duration) error
	Release(lockName string) error
}

type MySQRowLock added in v0.0.5

type MySQRowLock struct {
	sync.Mutex
	MySQLClient *gorm.DB
	TXMap       map[string]*gorm.DB
}

func NewRowLockWithConn added in v0.0.4

func NewRowLockWithConn(db *sql.DB, debug bool) *MySQRowLock

func NewRowLockWithDSN added in v0.0.4

func NewRowLockWithDSN(dsn string, debug bool) *MySQRowLock

func (*MySQRowLock) Acquire added in v0.0.5

func (l *MySQRowLock) Acquire(lockName string, wait time.Duration) error

Lock :If the lock cannot be obtained, it will keep blocking

func (*MySQRowLock) Init added in v0.0.5

func (l *MySQRowLock) Init(lockNameList []string)

Init :Create tables Create row record

func (*MySQRowLock) Release added in v0.0.5

func (l *MySQRowLock) Release(lockName string) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL