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 }