mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
129 lines
2.4 KiB
Go
129 lines
2.4 KiB
Go
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||
|
// SPDX-License-Identifier: MIT
|
||
|
|
||
|
package globallock
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"code.gitea.io/gitea/modules/nosql"
|
||
|
"code.gitea.io/gitea/modules/setting"
|
||
|
|
||
|
redsync "github.com/go-redsync/redsync/v4"
|
||
|
goredis "github.com/go-redsync/redsync/v4/redis/goredis/v9"
|
||
|
)
|
||
|
|
||
|
type Locker interface {
|
||
|
Lock() error
|
||
|
TryLock() (bool, error)
|
||
|
Unlock() (bool, error)
|
||
|
}
|
||
|
|
||
|
type LockService interface {
|
||
|
GetLock(name string) Locker
|
||
|
}
|
||
|
|
||
|
type memoryLock struct {
|
||
|
mutex sync.Mutex
|
||
|
}
|
||
|
|
||
|
func (r *memoryLock) Lock() error {
|
||
|
r.mutex.Lock()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *memoryLock) TryLock() (bool, error) {
|
||
|
return r.mutex.TryLock(), nil
|
||
|
}
|
||
|
|
||
|
func (r *memoryLock) Unlock() (bool, error) {
|
||
|
r.mutex.Unlock()
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
var _ Locker = &memoryLock{}
|
||
|
|
||
|
type memoryLockService struct {
|
||
|
syncMap sync.Map
|
||
|
}
|
||
|
|
||
|
var _ LockService = &memoryLockService{}
|
||
|
|
||
|
func newMemoryLockService() *memoryLockService {
|
||
|
return &memoryLockService{
|
||
|
syncMap: sync.Map{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (l *memoryLockService) GetLock(name string) Locker {
|
||
|
v, _ := l.syncMap.LoadOrStore(name, &memoryLock{})
|
||
|
return v.(*memoryLock)
|
||
|
}
|
||
|
|
||
|
type redisLockService struct {
|
||
|
rs *redsync.Redsync
|
||
|
}
|
||
|
|
||
|
var _ LockService = &redisLockService{}
|
||
|
|
||
|
func newRedisLockService(connection string) *redisLockService {
|
||
|
client := nosql.GetManager().GetRedisClient(connection)
|
||
|
|
||
|
pool := goredis.NewPool(client)
|
||
|
|
||
|
// Create an instance of redisync to be used to obtain a mutual exclusion
|
||
|
// lock.
|
||
|
rs := redsync.New(pool)
|
||
|
|
||
|
return &redisLockService{
|
||
|
rs: rs,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type redisLock struct {
|
||
|
mutex *redsync.Mutex
|
||
|
}
|
||
|
|
||
|
func (r *redisLockService) GetLock(name string) Locker {
|
||
|
return &redisLock{mutex: r.rs.NewMutex(name)}
|
||
|
}
|
||
|
|
||
|
func (r *redisLock) Lock() error {
|
||
|
return r.mutex.Lock()
|
||
|
}
|
||
|
|
||
|
func (r *redisLock) TryLock() (bool, error) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||
|
defer cancel()
|
||
|
if err := r.mutex.LockContext(ctx); err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func (r *redisLock) Unlock() (bool, error) {
|
||
|
return r.mutex.Unlock()
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
syncOnce sync.Once
|
||
|
lockService LockService
|
||
|
)
|
||
|
|
||
|
func getLockService() LockService {
|
||
|
syncOnce.Do(func() {
|
||
|
if setting.GlobalLock.ServiceType == "redis" {
|
||
|
lockService = newRedisLockService(setting.GlobalLock.ServiceConnStr)
|
||
|
} else {
|
||
|
lockService = newMemoryLockService()
|
||
|
}
|
||
|
})
|
||
|
return lockService
|
||
|
}
|
||
|
|
||
|
func GetLock(name string) Locker {
|
||
|
return getLockService().GetLock(name)
|
||
|
}
|