From edcefd4efbc0ead10e7afb76a23eef01544dcf92 Mon Sep 17 00:00:00 2001 From: Albin Kerouanton Date: Sat, 15 Jun 2024 11:04:53 +0200 Subject: [PATCH] libnet/i/kv/boltdb: fail fast in case of contention Make sure an error is returned straight away if there's contention on the underlying db file. This makes sure we don't reintroduce the issue fixed in d21d088, and it will help detect contention in parallelized tests if they're badly written. It effectively adds a new error mode to the daemon, but if anyone faces this error, they should fix their process manager. Signed-off-by: Albin Kerouanton --- libnetwork/internal/kvstore/boltdb/boltdb.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libnetwork/internal/kvstore/boltdb/boltdb.go b/libnetwork/internal/kvstore/boltdb/boltdb.go index d79c6155c9..8b2c05140e 100644 --- a/libnetwork/internal/kvstore/boltdb/boltdb.go +++ b/libnetwork/internal/kvstore/boltdb/boltdb.go @@ -3,6 +3,8 @@ package boltdb import ( "bytes" "encoding/binary" + "errors" + "fmt" "os" "path/filepath" "sync" @@ -34,9 +36,20 @@ func New(path, bucket string) (store.Store, error) { } db, err := bolt.Open(path, filePerm, &bolt.Options{ - Timeout: time.Minute, + // The bbolt package opens the underlying db file and then issues an + // exclusive flock to ensures that it can safely write to the db. If + // it fails, it'll re-issue flocks every few ms until Timeout is + // reached. + // This nanosecond timeout bypasses that retry loop and make sure the + // bbolt package returns an ErrTimeout straight away. That way, the + // daemon, and unit tests, will fail fast and loudly instead of + // silently introducing delays. + Timeout: time.Nanosecond, }) if err != nil { + if errors.Is(err, bolt.ErrTimeout) { + return nil, fmt.Errorf("boltdb file %s is already open", path) + } return nil, err }