for ; ; time.Sleep(retryDelay) {
dbl.mtx.Lock()
if dbl.conn != nil {
- // Already locked by another caller in this
- // process. Wait for them to release.
+ // Another goroutine is already locked/waiting
+ // on this lock. Wait for them to release.
dbl.mtx.Unlock()
continue
}
dbl.mtx.Unlock()
continue
}
- _, err = conn.ExecContext(ctx, `SELECT pg_advisory_lock($1)`, dbl.key)
+ var locked bool
+ err = conn.QueryRowContext(ctx, `SELECT pg_try_advisory_lock($1)`, dbl.key).Scan(&locked)
if err != nil {
- logger.WithError(err).Infof("error getting pg_advisory_lock %d", dbl.key)
+ logger.WithError(err).Infof("error getting pg_try_advisory_lock %d", dbl.key)
+ conn.Close()
+ dbl.mtx.Unlock()
+ continue
+ }
+ if !locked {
conn.Close()
dbl.mtx.Unlock()
continue
continue
}
blockdirpath := filepath.Join(v.Root, subdir)
- blockdir, err := v.os.Open(blockdirpath)
- if err != nil {
- v.logger.WithError(err).Errorf("error reading %q", blockdirpath)
- return fmt.Errorf("error reading %q: %s", blockdirpath, err)
- }
- v.os.stats.TickOps("readdir")
- v.os.stats.Tick(&v.os.stats.ReaddirOps)
- // ReadDir() (compared to Readdir(), which returns
- // FileInfo structs) helps complete the sequence of
- // readdirent calls as quickly as possible, reducing
- // the likelihood of NFS EBADCOOKIE (523) errors.
- dirents, err := blockdir.ReadDir(-1)
- blockdir.Close()
- if err != nil {
- v.logger.WithError(err).Errorf("error reading %q", blockdirpath)
- return fmt.Errorf("error reading %q: %s", blockdirpath, err)
+
+ var dirents []os.DirEntry
+ for attempt := 0; ; attempt++ {
+ v.os.stats.TickOps("readdir")
+ v.os.stats.Tick(&v.os.stats.ReaddirOps)
+ dirents, err = os.ReadDir(blockdirpath)
+ if err == nil {
+ break
+ } else if attempt < 5 && strings.Contains(err.Error(), "errno 523") {
+ // EBADCOOKIE (NFS stopped accepting
+ // our readdirent cookie) -- retry a
+ // few times before giving up
+ v.logger.WithError(err).Printf("retry after error reading %s", blockdirpath)
+ continue
+ } else {
+ return err
+ }
}
+
for _, dirent := range dirents {
fileInfo, err := dirent.Info()
if os.IsNotExist(err) {