package content import ( "sync" "github.com/nightlyone/lockfile" "github.com/pkg/errors" ) // In addition to providing inter-process locks for content ingest, we also // define a global in process lock to prevent two goroutines writing to the // same file. // // This is pretty unsophisticated for now. In the future, we'd probably like to // have more information about who is holding which locks, as well as better // error reporting. var ( errLocked = errors.New("key is locked") // locks lets us lock in process, as well as output of process. locks = map[lockfile.Lockfile]struct{}{} locksMu sync.Mutex ) func tryLock(lock lockfile.Lockfile) error { locksMu.Lock() defer locksMu.Unlock() if _, ok := locks[lock]; ok { return errLocked } if err := lock.TryLock(); err != nil { if errors.Cause(err) == lockfile.ErrBusy { return errLocked } return errors.Wrapf(err, "lock.TryLock() encountered an error") } locks[lock] = struct{}{} return nil } func unlock(lock lockfile.Lockfile) error { locksMu.Lock() defer locksMu.Unlock() if _, ok := locks[lock]; !ok { return nil } delete(locks, lock) return lock.Unlock() }