// Package keyspacemigration provides a process-local mutual-exclusion gate
// for per-keyspace meta-service-group migrations. Assumes a single
// tidb-manager replica.
package keyspacemigration

import "sync"

type Locker interface {
	// TryAcquire returns (nil, false) if another caller holds the lock for
	// keyspace. The returned release is safe to call more than once.
	TryAcquire(keyspace string) (release func(), ok bool)
	IsLocked(keyspace string) bool
}

func New() Locker {
	return &locker{held: make(map[string]struct{})}
}

type locker struct {
	mu   sync.Mutex
	held map[string]struct{}
}

func (l *locker) TryAcquire(keyspace string) (func(), bool) {
	l.mu.Lock()
	defer l.mu.Unlock()
	if _, ok := l.held[keyspace]; ok {
		return nil, false
	}
	l.held[keyspace] = struct{}{}

	var once sync.Once
	return func() {
		once.Do(func() {
			l.mu.Lock()
			defer l.mu.Unlock()
			delete(l.held, keyspace)
		})
	}, true
}

func (l *locker) IsLocked(keyspace string) bool {
	l.mu.Lock()
	defer l.mu.Unlock()
	_, ok := l.held[keyspace]
	return ok
}
