@@ -116,8 +116,7 @@ type DB struct {
116
116
// Supported only on Unix via mlock/munlock syscalls.
117
117
Mlock bool
118
118
119
- // Logger is the logger used for bbolt.
120
- Logger Logger
119
+ logger Logger
121
120
122
121
path string
123
122
openFile func (string , int , os.FileMode ) (* os.File , error )
@@ -176,10 +175,11 @@ func (db *DB) String() string {
176
175
// If the file does not exist then it will be created automatically with a given file mode.
177
176
// Passing in nil options will cause Bolt to open the database with the default options.
178
177
// Note: For read/write transactions, ensure the owner has write permission on the created/opened database file, e.g. 0600
179
- func Open (path string , mode os.FileMode , options * Options ) (* DB , error ) {
180
- db : = & DB {
178
+ func Open (path string , mode os.FileMode , options * Options ) (db * DB , err error ) {
179
+ db = & DB {
181
180
opened : true ,
182
181
}
182
+
183
183
// Set default options if no options are provided.
184
184
if options == nil {
185
185
options = DefaultOptions
@@ -198,11 +198,21 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
198
198
db .AllocSize = common .DefaultAllocSize
199
199
200
200
if options .Logger == nil {
201
- db .Logger = getDiscardLogger ()
201
+ db .logger = getDiscardLogger ()
202
202
} else {
203
- db .Logger = options .Logger
203
+ db .logger = options .Logger
204
204
}
205
205
206
+ lg := db .Logger ()
207
+ lg .Infof ("Opening db file (%s) with mode %x and with options: %s" , path , mode , options )
208
+ defer func () {
209
+ if err != nil {
210
+ lg .Errorf ("Opening bbolt db (%s) failed: %v" , path , err )
211
+ } else {
212
+ lg .Infof ("Opening bbolt db (%s) successfully" , path )
213
+ }
214
+ }()
215
+
206
216
flag := os .O_RDWR
207
217
if options .ReadOnly {
208
218
flag = os .O_RDONLY
@@ -219,9 +229,9 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
219
229
}
220
230
221
231
// Open data file and separate sync handler for metadata writes.
222
- var err error
223
232
if db .file , err = db .openFile (path , flag , mode ); err != nil {
224
233
_ = db .close ()
234
+ lg .Errorf ("failed to open db file (%s): %v" , path , err )
225
235
return nil , err
226
236
}
227
237
db .path = db .file .Name ()
@@ -235,6 +245,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
235
245
// hold a lock at the same time) otherwise (options.ReadOnly is set).
236
246
if err := flock (db , ! db .readOnly , options .Timeout ); err != nil {
237
247
_ = db .close ()
248
+ lg .Errorf ("failed to lock db file (%s), readonly: %t, error: %v" , path , db .readOnly , err )
238
249
return nil , err
239
250
}
240
251
@@ -249,12 +260,14 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
249
260
// Initialize the database if it doesn't exist.
250
261
if info , err := db .file .Stat (); err != nil {
251
262
_ = db .close ()
263
+ lg .Errorf ("failed to get db file's stats (%s): %v" , path , err )
252
264
return nil , err
253
265
} else if info .Size () == 0 {
254
266
// Initialize new files with meta pages.
255
267
if err := db .init (); err != nil {
256
268
// clean up file descriptor on initialization fail
257
269
_ = db .close ()
270
+ lg .Errorf ("failed to initialize db file (%s): %v" , path , err )
258
271
return nil , err
259
272
}
260
273
} else {
@@ -263,7 +276,8 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
263
276
db .pageSize = pgSize
264
277
} else {
265
278
_ = db .close ()
266
- return nil , berrors .ErrInvalid
279
+ lg .Errorf ("failed to get page size from db file (%s): %v" , path , err )
280
+ return nil , err
267
281
}
268
282
}
269
283
@@ -277,6 +291,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
277
291
// Memory map the data file.
278
292
if err := db .mmap (options .InitialMmapSize ); err != nil {
279
293
_ = db .close ()
294
+ lg .Errorf ("failed to map db file (%s): %v" , path , err )
280
295
return nil , err
281
296
}
282
297
@@ -296,13 +311,13 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
296
311
err = tx .Commit ()
297
312
}
298
313
if err != nil {
314
+ lg .Errorf ("starting readwrite transaction failed: %v" , err )
299
315
_ = db .close ()
300
316
return nil , err
301
317
}
302
318
}
303
319
304
320
// Mark the database as opened and return.
305
- db .Logger .Debug ("bbolt opened successfully" )
306
321
return db , nil
307
322
}
308
323
@@ -435,9 +450,12 @@ func (db *DB) mmap(minsz int) (err error) {
435
450
db .mmaplock .Lock ()
436
451
defer db .mmaplock .Unlock ()
437
452
453
+ lg := db .Logger ()
454
+
438
455
// Ensure the size is at least the minimum size.
439
456
fileSize , err := db .fileSize ()
440
457
if err != nil {
458
+ lg .Errorf ("getting file size failed: %w" , err )
441
459
return err
442
460
}
443
461
var size = fileSize
@@ -446,6 +464,7 @@ func (db *DB) mmap(minsz int) (err error) {
446
464
}
447
465
size , err = db .mmapSize (size )
448
466
if err != nil {
467
+ lg .Errorf ("getting map size failed: %w" , err )
449
468
return err
450
469
}
451
470
@@ -470,6 +489,7 @@ func (db *DB) mmap(minsz int) (err error) {
470
489
// gofail: var mapError string
471
490
// return errors.New(mapError)
472
491
if err = mmap (db , size ); err != nil {
492
+ lg .Errorf ("[GOOS: %s, GOARCH: %s] mmap failed, size: %d, error: %v" , runtime .GOOS , runtime .GOARCH , size , err )
473
493
return err
474
494
}
475
495
@@ -500,6 +520,7 @@ func (db *DB) mmap(minsz int) (err error) {
500
520
err0 := db .meta0 .Validate ()
501
521
err1 := db .meta1 .Validate ()
502
522
if err0 != nil && err1 != nil {
523
+ lg .Errorf ("both meta pages are invalid, meta0: %v, meta1: %v" , err0 , err1 )
503
524
return err0
504
525
}
505
526
@@ -522,6 +543,7 @@ func (db *DB) munmap() error {
522
543
// gofail: var unmapError string
523
544
// return errors.New(unmapError)
524
545
if err := munmap (db ); err != nil {
546
+ db .Logger ().Errorf ("[GOOS: %s, GOARCH: %s] munmap failed, db.datasz: %d, error: %v" , runtime .GOOS , runtime .GOARCH , db .datasz , err )
525
547
return fmt .Errorf ("unmap error: " + err .Error ())
526
548
}
527
549
@@ -569,6 +591,7 @@ func (db *DB) munlock(fileSize int) error {
569
591
// gofail: var munlockError string
570
592
// return errors.New(munlockError)
571
593
if err := munlock (db , fileSize ); err != nil {
594
+ db .Logger ().Errorf ("[GOOS: %s, GOARCH: %s] munlock failed, fileSize: %d, db.datasz: %d, error: %v" , runtime .GOOS , runtime .GOARCH , fileSize , db .datasz , err )
572
595
return fmt .Errorf ("munlock error: " + err .Error ())
573
596
}
574
597
return nil
@@ -578,6 +601,7 @@ func (db *DB) mlock(fileSize int) error {
578
601
// gofail: var mlockError string
579
602
// return errors.New(mlockError)
580
603
if err := mlock (db , fileSize ); err != nil {
604
+ db .Logger ().Errorf ("[GOOS: %s, GOARCH: %s] mlock failed, fileSize: %d, db.datasz: %d, error: %v" , runtime .GOOS , runtime .GOARCH , fileSize , db .datasz , err )
581
605
return fmt .Errorf ("mlock error: " + err .Error ())
582
606
}
583
607
return nil
@@ -628,9 +652,11 @@ func (db *DB) init() error {
628
652
629
653
// Write the buffer to our data file.
630
654
if _ , err := db .ops .writeAt (buf , 0 ); err != nil {
655
+ db .Logger ().Errorf ("writeAt failed: %w" , err )
631
656
return err
632
657
}
633
658
if err := fdatasync (db ); err != nil {
659
+ db .Logger ().Errorf ("[GOOS: %s, GOARCH: %s] fdatasync failed: %w" , runtime .GOOS , runtime .GOARCH , err )
634
660
return err
635
661
}
636
662
@@ -713,13 +739,29 @@ func (db *DB) close() error {
713
739
//
714
740
// IMPORTANT: You must close read-only transactions after you are finished or
715
741
// else the database will not reclaim old pages.
716
- func (db * DB ) Begin (writable bool ) (* Tx , error ) {
742
+ func (db * DB ) Begin (writable bool ) (t * Tx , err error ) {
743
+ db .Logger ().Debugf ("Starting a new transaction [writable: %t]" , writable )
744
+ defer func () {
745
+ if err != nil {
746
+ db .Logger ().Errorf ("Starting a new transaction [writable: %t] failed: %v" , writable , err )
747
+ } else {
748
+ db .Logger ().Debugf ("Starting a new transaction [writable: %t] successfully" , writable )
749
+ }
750
+ }()
751
+
717
752
if writable {
718
753
return db .beginRWTx ()
719
754
}
720
755
return db .beginTx ()
721
756
}
722
757
758
+ func (db * DB ) Logger () Logger {
759
+ if db == nil || db .logger == nil {
760
+ return getDiscardLogger ()
761
+ }
762
+ return db .logger
763
+ }
764
+
723
765
func (db * DB ) beginTx () (* Tx , error ) {
724
766
// Lock the meta pages while we initialize the transaction. We obtain
725
767
// the meta lock before the mmap lock because that's the order that the
@@ -1053,7 +1095,18 @@ func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
1053
1095
//
1054
1096
// This is not necessary under normal operation, however, if you use NoSync
1055
1097
// then it allows you to force the database file to sync against the disk.
1056
- func (db * DB ) Sync () error { return fdatasync (db ) }
1098
+ func (db * DB ) Sync () (err error ) {
1099
+ db .Logger ().Debug ("Syncing bbolt db (%s)" , db .path )
1100
+ defer func () {
1101
+ if err != nil {
1102
+ db .Logger ().Errorf ("[GOOS: %s, GOARCH: %s] syncing bbolt db (%s) failed: %v" , runtime .GOOS , runtime .GOARCH , db .path , err )
1103
+ } else {
1104
+ db .Logger ().Debugf ("Syncing bbolt db (%s) successfully" , db .path )
1105
+ }
1106
+ }()
1107
+
1108
+ return fdatasync (db )
1109
+ }
1057
1110
1058
1111
// Stats retrieves ongoing performance stats for the database.
1059
1112
// This is only updated when a transaction closes.
@@ -1142,8 +1195,10 @@ func (db *DB) allocate(txid common.Txid, count int) (*common.Page, error) {
1142
1195
// grow grows the size of the database to the given sz.
1143
1196
func (db * DB ) grow (sz int ) error {
1144
1197
// Ignore if the new size is less than available file size.
1198
+ lg := db .Logger ()
1145
1199
fileSize , err := db .fileSize ()
1146
1200
if err != nil {
1201
+ lg .Errorf ("getting file size failed: %w" , err )
1147
1202
return err
1148
1203
}
1149
1204
if sz <= fileSize {
@@ -1165,10 +1220,12 @@ func (db *DB) grow(sz int) error {
1165
1220
// gofail: var resizeFileError string
1166
1221
// return errors.New(resizeFileError)
1167
1222
if err := db .file .Truncate (int64 (sz )); err != nil {
1223
+ lg .Errorf ("[GOOS: %s, GOARCH: %s] truncating file failed, size: %d, db.datasz: %d, error: %v" , runtime .GOOS , runtime .GOARCH , sz , db .datasz , err )
1168
1224
return fmt .Errorf ("file resize error: %s" , err )
1169
1225
}
1170
1226
}
1171
1227
if err := db .file .Sync (); err != nil {
1228
+ lg .Errorf ("[GOOS: %s, GOARCH: %s] syncing file failed, db.datasz: %d, error: %v" , runtime .GOOS , runtime .GOARCH , db .datasz , err )
1172
1229
return fmt .Errorf ("file sync error: %s" , err )
1173
1230
}
1174
1231
if db .Mlock {
@@ -1283,6 +1340,16 @@ type Options struct {
1283
1340
Logger Logger
1284
1341
}
1285
1342
1343
+ func (o * Options ) String () string {
1344
+ if o == nil {
1345
+ return "{}"
1346
+ }
1347
+
1348
+ return fmt .Sprintf ("{Timeout: %s, NoGrowSync: %t, NoFreelistSync: %t, PreLoadFreelist: %t, FreelistType: %s, ReadOnly: %t, MmapFlags: %x, InitialMmapSize: %d, PageSize: %d, NoSync: %t, OpenFile: %p, Mlock: %t, Logger: %p}" ,
1349
+ o .Timeout , o .NoGrowSync , o .NoFreelistSync , o .PreLoadFreelist , o .FreelistType , o .ReadOnly , o .MmapFlags , o .InitialMmapSize , o .PageSize , o .NoSync , o .OpenFile , o .Mlock , o .Logger )
1350
+
1351
+ }
1352
+
1286
1353
// DefaultOptions represent the options used if nil options are passed into Open().
1287
1354
// No timeout is used which will cause Bolt to wait indefinitely for a lock.
1288
1355
var DefaultOptions = & Options {
0 commit comments