internal/indexing_lock/indexing_lock.go (59 lines of code) (raw):
package indexing_lock //nolint:staticcheck
import (
"errors"
"log/slog"
"sync"
)
type IndexingLock struct {
mu sync.Mutex
inProgress map[uint32]lockStructValue
globalLock bool
}
type lockStructValue struct{}
func NewIndexingLock() *IndexingLock {
return &IndexingLock{
inProgress: make(map[uint32]lockStructValue),
}
}
func (l *IndexingLock) LockAll() error {
l.mu.Lock()
defer l.mu.Unlock()
if l.isLockActive() {
return errors.New("indexing is in progress")
}
l.globalLock = true
return nil
}
func (l *IndexingLock) UnlockAll() {
l.mu.Lock()
defer l.mu.Unlock()
l.globalLock = false
}
func (l *IndexingLock) InProgressCount() int {
l.mu.Lock()
defer l.mu.Unlock()
return len(l.inProgress)
}
// TryLock tries to acquire a lock for a given repository id.
func (l *IndexingLock) TryLock(repoID uint32) bool {
l.mu.Lock()
defer l.mu.Unlock()
if l.globalLock {
return false
}
_, ok := l.inProgress[repoID]
if ok {
return false
}
l.inProgress[repoID] = lockStructValue{}
slog.Info("lock", "project_id", repoID, "status", "obtained")
return true
}
func (l *IndexingLock) Unlock(repoID uint32) {
l.mu.Lock()
defer l.mu.Unlock()
defer slog.Info("lock", "project_id", repoID, "status", "released")
delete(l.inProgress, repoID)
}
func (l *IndexingLock) isLockActive() bool {
return l.globalLock || len(l.inProgress) != 0
}