Skip to content

Commit cb9b366

Browse files
adityamaruclaude
authored andcommitted
Sync bbolt databases on close to prevent corruption
When bbolt is opened with NoSync: true, transactions complete in memory without fsync to disk. On graceful shutdown, dirty pages in the OS page cache may not be flushed before Close() returns, leading to corruption when the filesystem is unmounted or snapshots are taken. This is particularly problematic with network block devices (Ceph RBD) and container snapshot workflows where: 1. BuildKit stops gracefully (SIGTERM) 2. Close() returns without syncing dirty pages 3. Unmount forces writeback of partial/torn pages 4. Snapshot captures inconsistent B-tree state The fix wraps bolt.DB with syncingDB that calls Sync() before Close(), ensuring all pending writes are flushed to disk during graceful shutdown while preserving the NoSync performance benefits during normal operation. Signed-off-by: Aditya Maru <adityamaru@gmail.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0a4bb7d commit cb9b366

1 file changed

Lines changed: 26 additions & 1 deletion

File tree

util/db/boltutil/db.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,40 @@ package boltutil
22

33
import (
44
"io/fs"
5+
"sync"
56

7+
"github.com/moby/buildkit/util/bklog"
68
"github.com/moby/buildkit/util/db"
79
bolt "go.etcd.io/bbolt"
810
)
911

12+
// syncingDB wraps a bolt.DB to ensure data is synced to disk before closing.
13+
// This is important when using NoSync mode, as otherwise dirty pages may not
14+
// be flushed to disk before unmount, leading to corruption on network block
15+
// devices or when taking filesystem snapshots.
16+
type syncingDB struct {
17+
*bolt.DB
18+
closeOnce sync.Once
19+
closeErr error
20+
}
21+
22+
// Close syncs the database to disk before closing.
23+
// This ensures all pending writes are flushed even when NoSync is enabled,
24+
// preventing corruption during graceful shutdown. Safe to call multiple times.
25+
func (s *syncingDB) Close() error {
26+
s.closeOnce.Do(func() {
27+
if err := s.Sync(); err != nil {
28+
bklog.L.Warnf("failed to sync database before close: %v", err)
29+
}
30+
s.closeErr = s.DB.Close()
31+
})
32+
return s.closeErr
33+
}
34+
1035
func Open(p string, mode fs.FileMode, options *bolt.Options) (db.DB, error) {
1136
bdb, err := bolt.Open(p, mode, options)
1237
if err != nil {
1338
return nil, err
1439
}
15-
return bdb, nil
40+
return &syncingDB{DB: bdb}, nil
1641
}

0 commit comments

Comments
 (0)