Lock blocks until the exclusive advisory lock is acquired or ctx is canceled.
(ctx context.Context)
| 70 | |
| 71 | // Lock blocks until the exclusive advisory lock is acquired or ctx is canceled. |
| 72 | func (l *FileLock) Lock(ctx context.Context) error { |
| 73 | if ctx == nil { |
| 74 | ctx = context.Background() |
| 75 | } |
| 76 | if err := ctx.Err(); err != nil { |
| 77 | return err |
| 78 | } |
| 79 | |
| 80 | l.mu.Lock() |
| 81 | defer l.mu.Unlock() |
| 82 | |
| 83 | if l.file != nil { |
| 84 | return nil |
| 85 | } |
| 86 | |
| 87 | if err := l.lockProcess(ctx); err != nil { |
| 88 | return err |
| 89 | } |
| 90 | processLocked := true |
| 91 | defer func() { |
| 92 | if processLocked { |
| 93 | l.processLock.Unlock() |
| 94 | } |
| 95 | }() |
| 96 | |
| 97 | if err := os.MkdirAll(filepath.Dir(l.path), 0o700); err != nil { |
| 98 | return fmt.Errorf("creating memory lock directory %q: %w", filepath.Dir(l.path), err) |
| 99 | } |
| 100 | |
| 101 | f, err := os.OpenFile(l.path, os.O_RDWR|os.O_CREATE, 0o600) |
| 102 | if err != nil { |
| 103 | return fmt.Errorf("opening memory lock file %q: %w", l.path, err) |
| 104 | } |
| 105 | |
| 106 | for { |
| 107 | err = lockFileExclusive(f) |
| 108 | if err == nil { |
| 109 | l.file = f |
| 110 | processLocked = false |
| 111 | return nil |
| 112 | } |
| 113 | if !isLockUnavailable(err) { |
| 114 | _ = f.Close() |
| 115 | return fmt.Errorf("locking memory lock file %q: %w", l.path, err) |
| 116 | } |
| 117 | |
| 118 | select { |
| 119 | case <-ctx.Done(): |
| 120 | _ = f.Close() |
| 121 | return ctx.Err() |
| 122 | case <-time.After(lockRetryInterval): |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | func (l *FileLock) lockProcess(ctx context.Context) error { |
| 128 | return l.processLock.Lock(ctx) |