db.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. package bolt
  2. import (
  3. "errors"
  4. "fmt"
  5. "hash/fnv"
  6. "log"
  7. "os"
  8. "runtime"
  9. "sort"
  10. "sync"
  11. "time"
  12. "unsafe"
  13. )
  14. // The largest step that can be taken when remapping the mmap.
  15. const maxMmapStep = 1 << 30 // 1GB
  16. // The data file format version.
  17. const version = 2
  18. // Represents a marker value to indicate that a file is a Bolt DB.
  19. const magic uint32 = 0xED0CDAED
  20. const pgidNoFreelist pgid = 0xffffffffffffffff
  21. // IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
  22. // syncing changes to a file. This is required as some operating systems,
  23. // such as OpenBSD, do not have a unified buffer cache (UBC) and writes
  24. // must be synchronized using the msync(2) syscall.
  25. const IgnoreNoSync = runtime.GOOS == "openbsd"
  26. // Default values if not set in a DB instance.
  27. const (
  28. DefaultMaxBatchSize int = 1000
  29. DefaultMaxBatchDelay = 10 * time.Millisecond
  30. DefaultAllocSize = 16 * 1024 * 1024
  31. )
  32. // default page size for db is set to the OS page size.
  33. var defaultPageSize = os.Getpagesize()
  34. // The time elapsed between consecutive file locking attempts.
  35. const flockRetryTimeout = 50 * time.Millisecond
  36. // DB represents a collection of buckets persisted to a file on disk.
  37. // All data access is performed through transactions which can be obtained through the DB.
  38. // All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
  39. type DB struct {
  40. // When enabled, the database will perform a Check() after every commit.
  41. // A panic is issued if the database is in an inconsistent state. This
  42. // flag has a large performance impact so it should only be used for
  43. // debugging purposes.
  44. StrictMode bool
  45. // Setting the NoSync flag will cause the database to skip fsync()
  46. // calls after each commit. This can be useful when bulk loading data
  47. // into a database and you can restart the bulk load in the event of
  48. // a system failure or database corruption. Do not set this flag for
  49. // normal use.
  50. //
  51. // If the package global IgnoreNoSync constant is true, this value is
  52. // ignored. See the comment on that constant for more details.
  53. //
  54. // THIS IS UNSAFE. PLEASE USE WITH CAUTION.
  55. NoSync bool
  56. // When true, skips syncing freelist to disk. This improves the database
  57. // write performance under normal operation, but requires a full database
  58. // re-sync during recovery.
  59. NoFreelistSync bool
  60. // When true, skips the truncate call when growing the database.
  61. // Setting this to true is only safe on non-ext3/ext4 systems.
  62. // Skipping truncation avoids preallocation of hard drive space and
  63. // bypasses a truncate() and fsync() syscall on remapping.
  64. //
  65. // https://github.com/boltdb/bolt/issues/284
  66. NoGrowSync bool
  67. // If you want to read the entire database fast, you can set MmapFlag to
  68. // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead.
  69. MmapFlags int
  70. // MaxBatchSize is the maximum size of a batch. Default value is
  71. // copied from DefaultMaxBatchSize in Open.
  72. //
  73. // If <=0, disables batching.
  74. //
  75. // Do not change concurrently with calls to Batch.
  76. MaxBatchSize int
  77. // MaxBatchDelay is the maximum delay before a batch starts.
  78. // Default value is copied from DefaultMaxBatchDelay in Open.
  79. //
  80. // If <=0, effectively disables batching.
  81. //
  82. // Do not change concurrently with calls to Batch.
  83. MaxBatchDelay time.Duration
  84. // AllocSize is the amount of space allocated when the database
  85. // needs to create new pages. This is done to amortize the cost
  86. // of truncate() and fsync() when growing the data file.
  87. AllocSize int
  88. path string
  89. file *os.File
  90. lockfile *os.File // windows only
  91. dataref []byte // mmap'ed readonly, write throws SEGV
  92. data *[maxMapSize]byte
  93. datasz int
  94. filesz int // current on disk file size
  95. meta0 *meta
  96. meta1 *meta
  97. pageSize int
  98. opened bool
  99. rwtx *Tx
  100. txs []*Tx
  101. stats Stats
  102. freelist *freelist
  103. freelistLoad sync.Once
  104. pagePool sync.Pool
  105. batchMu sync.Mutex
  106. batch *batch
  107. rwlock sync.Mutex // Allows only one writer at a time.
  108. metalock sync.Mutex // Protects meta page access.
  109. mmaplock sync.RWMutex // Protects mmap access during remapping.
  110. statlock sync.RWMutex // Protects stats access.
  111. ops struct {
  112. writeAt func(b []byte, off int64) (n int, err error)
  113. }
  114. // Read only mode.
  115. // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately.
  116. readOnly bool
  117. }
  118. // Path returns the path to currently open database file.
  119. func (db *DB) Path() string {
  120. return db.path
  121. }
  122. // GoString returns the Go string representation of the database.
  123. func (db *DB) GoString() string {
  124. return fmt.Sprintf("bolt.DB{path:%q}", db.path)
  125. }
  126. // String returns the string representation of the database.
  127. func (db *DB) String() string {
  128. return fmt.Sprintf("DB<%q>", db.path)
  129. }
  130. // Open creates and opens a database at the given path.
  131. // If the file does not exist then it will be created automatically.
  132. // Passing in nil options will cause Bolt to open the database with the default options.
  133. func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
  134. db := &DB{
  135. opened: true,
  136. }
  137. // Set default options if no options are provided.
  138. if options == nil {
  139. options = DefaultOptions
  140. }
  141. db.NoSync = options.NoSync
  142. db.NoGrowSync = options.NoGrowSync
  143. db.MmapFlags = options.MmapFlags
  144. db.NoFreelistSync = options.NoFreelistSync
  145. // Set default values for later DB operations.
  146. db.MaxBatchSize = DefaultMaxBatchSize
  147. db.MaxBatchDelay = DefaultMaxBatchDelay
  148. db.AllocSize = DefaultAllocSize
  149. flag := os.O_RDWR
  150. if options.ReadOnly {
  151. flag = os.O_RDONLY
  152. db.readOnly = true
  153. }
  154. // Open data file and separate sync handler for metadata writes.
  155. db.path = path
  156. var err error
  157. if db.file, err = os.OpenFile(db.path, flag|os.O_CREATE, mode); err != nil {
  158. _ = db.close()
  159. return nil, err
  160. }
  161. // Lock file so that other processes using Bolt in read-write mode cannot
  162. // use the database at the same time. This would cause corruption since
  163. // the two processes would write meta pages and free pages separately.
  164. // The database file is locked exclusively (only one process can grab the lock)
  165. // if !options.ReadOnly.
  166. // The database file is locked using the shared lock (more than one process may
  167. // hold a lock at the same time) otherwise (options.ReadOnly is set).
  168. if err := flock(db, mode, !db.readOnly, options.Timeout); err != nil {
  169. db.lockfile = nil // make 'unused' happy. TODO: rework locks
  170. _ = db.close()
  171. return nil, err
  172. }
  173. // Default values for test hooks
  174. db.ops.writeAt = db.file.WriteAt
  175. if db.pageSize = options.PageSize; db.pageSize == 0 {
  176. // Set the default page size to the OS page size.
  177. db.pageSize = defaultPageSize
  178. }
  179. // Initialize the database if it doesn't exist.
  180. if info, err := db.file.Stat(); err != nil {
  181. _ = db.close()
  182. return nil, err
  183. } else if info.Size() == 0 {
  184. // Initialize new files with meta pages.
  185. if err := db.init(); err != nil {
  186. // clean up file descriptor on initialization fail
  187. _ = db.close()
  188. return nil, err
  189. }
  190. } else {
  191. // Read the first meta page to determine the page size.
  192. var buf [0x1000]byte
  193. // If we can't read the page size, but can read a page, assume
  194. // it's the same as the OS or one given -- since that's how the
  195. // page size was chosen in the first place.
  196. //
  197. // If the first page is invalid and this OS uses a different
  198. // page size than what the database was created with then we
  199. // are out of luck and cannot access the database.
  200. //
  201. // TODO: scan for next page
  202. if bw, err := db.file.ReadAt(buf[:], 0); err == nil && bw == len(buf) {
  203. if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil {
  204. db.pageSize = int(m.pageSize)
  205. }
  206. } else {
  207. _ = db.close()
  208. return nil, ErrInvalid
  209. }
  210. }
  211. // Initialize page pool.
  212. db.pagePool = sync.Pool{
  213. New: func() interface{} {
  214. return make([]byte, db.pageSize)
  215. },
  216. }
  217. // Memory map the data file.
  218. if err := db.mmap(options.InitialMmapSize); err != nil {
  219. _ = db.close()
  220. return nil, err
  221. }
  222. if db.readOnly {
  223. return db, nil
  224. }
  225. db.loadFreelist()
  226. // Flush freelist when transitioning from no sync to sync so
  227. // NoFreelistSync unaware boltdb can open the db later.
  228. if !db.NoFreelistSync && !db.hasSyncedFreelist() {
  229. tx, err := db.Begin(true)
  230. if tx != nil {
  231. err = tx.Commit()
  232. }
  233. if err != nil {
  234. _ = db.close()
  235. return nil, err
  236. }
  237. }
  238. // Mark the database as opened and return.
  239. return db, nil
  240. }
  241. // loadFreelist reads the freelist if it is synced, or reconstructs it
  242. // by scanning the DB if it is not synced. It assumes there are no
  243. // concurrent accesses being made to the freelist.
  244. func (db *DB) loadFreelist() {
  245. db.freelistLoad.Do(func() {
  246. db.freelist = newFreelist()
  247. if !db.hasSyncedFreelist() {
  248. // Reconstruct free list by scanning the DB.
  249. db.freelist.readIDs(db.freepages())
  250. } else {
  251. // Read free list from freelist page.
  252. db.freelist.read(db.page(db.meta().freelist))
  253. }
  254. db.stats.FreePageN = len(db.freelist.ids)
  255. })
  256. }
  257. func (db *DB) hasSyncedFreelist() bool {
  258. return db.meta().freelist != pgidNoFreelist
  259. }
  260. // mmap opens the underlying memory-mapped file and initializes the meta references.
  261. // minsz is the minimum size that the new mmap can be.
  262. func (db *DB) mmap(minsz int) error {
  263. db.mmaplock.Lock()
  264. defer db.mmaplock.Unlock()
  265. info, err := db.file.Stat()
  266. if err != nil {
  267. return fmt.Errorf("mmap stat error: %s", err)
  268. } else if int(info.Size()) < db.pageSize*2 {
  269. return fmt.Errorf("file size too small")
  270. }
  271. // Ensure the size is at least the minimum size.
  272. var size = int(info.Size())
  273. if size < minsz {
  274. size = minsz
  275. }
  276. size, err = db.mmapSize(size)
  277. if err != nil {
  278. return err
  279. }
  280. // Dereference all mmap references before unmapping.
  281. if db.rwtx != nil {
  282. db.rwtx.root.dereference()
  283. }
  284. // Unmap existing data before continuing.
  285. if err := db.munmap(); err != nil {
  286. return err
  287. }
  288. // Memory-map the data file as a byte slice.
  289. if err := mmap(db, size); err != nil {
  290. return err
  291. }
  292. // Save references to the meta pages.
  293. db.meta0 = db.page(0).meta()
  294. db.meta1 = db.page(1).meta()
  295. // Validate the meta pages. We only return an error if both meta pages fail
  296. // validation, since meta0 failing validation means that it wasn't saved
  297. // properly -- but we can recover using meta1. And vice-versa.
  298. err0 := db.meta0.validate()
  299. err1 := db.meta1.validate()
  300. if err0 != nil && err1 != nil {
  301. return err0
  302. }
  303. return nil
  304. }
  305. // munmap unmaps the data file from memory.
  306. func (db *DB) munmap() error {
  307. if err := munmap(db); err != nil {
  308. return fmt.Errorf("unmap error: " + err.Error())
  309. }
  310. return nil
  311. }
  312. // mmapSize determines the appropriate size for the mmap given the current size
  313. // of the database. The minimum size is 32KB and doubles until it reaches 1GB.
  314. // Returns an error if the new mmap size is greater than the max allowed.
  315. func (db *DB) mmapSize(size int) (int, error) {
  316. // Double the size from 32KB until 1GB.
  317. for i := uint(15); i <= 30; i++ {
  318. if size <= 1<<i {
  319. return 1 << i, nil
  320. }
  321. }
  322. // Verify the requested size is not above the maximum allowed.
  323. if size > maxMapSize {
  324. return 0, fmt.Errorf("mmap too large")
  325. }
  326. // If larger than 1GB then grow by 1GB at a time.
  327. sz := int64(size)
  328. if remainder := sz % int64(maxMmapStep); remainder > 0 {
  329. sz += int64(maxMmapStep) - remainder
  330. }
  331. // Ensure that the mmap size is a multiple of the page size.
  332. // This should always be true since we're incrementing in MBs.
  333. pageSize := int64(db.pageSize)
  334. if (sz % pageSize) != 0 {
  335. sz = ((sz / pageSize) + 1) * pageSize
  336. }
  337. // If we've exceeded the max size then only grow up to the max size.
  338. if sz > maxMapSize {
  339. sz = maxMapSize
  340. }
  341. return int(sz), nil
  342. }
  343. // init creates a new database file and initializes its meta pages.
  344. func (db *DB) init() error {
  345. // Create two meta pages on a buffer.
  346. buf := make([]byte, db.pageSize*4)
  347. for i := 0; i < 2; i++ {
  348. p := db.pageInBuffer(buf[:], pgid(i))
  349. p.id = pgid(i)
  350. p.flags = metaPageFlag
  351. // Initialize the meta page.
  352. m := p.meta()
  353. m.magic = magic
  354. m.version = version
  355. m.pageSize = uint32(db.pageSize)
  356. m.freelist = 2
  357. m.root = bucket{root: 3}
  358. m.pgid = 4
  359. m.txid = txid(i)
  360. m.checksum = m.sum64()
  361. }
  362. // Write an empty freelist at page 3.
  363. p := db.pageInBuffer(buf[:], pgid(2))
  364. p.id = pgid(2)
  365. p.flags = freelistPageFlag
  366. p.count = 0
  367. // Write an empty leaf page at page 4.
  368. p = db.pageInBuffer(buf[:], pgid(3))
  369. p.id = pgid(3)
  370. p.flags = leafPageFlag
  371. p.count = 0
  372. // Write the buffer to our data file.
  373. if _, err := db.ops.writeAt(buf, 0); err != nil {
  374. return err
  375. }
  376. if err := fdatasync(db); err != nil {
  377. return err
  378. }
  379. return nil
  380. }
  381. // Close releases all database resources.
  382. // It will block waiting for any open transactions to finish
  383. // before closing the database and returning.
  384. func (db *DB) Close() error {
  385. db.rwlock.Lock()
  386. defer db.rwlock.Unlock()
  387. db.metalock.Lock()
  388. defer db.metalock.Unlock()
  389. db.mmaplock.RLock()
  390. defer db.mmaplock.RUnlock()
  391. return db.close()
  392. }
  393. func (db *DB) close() error {
  394. if !db.opened {
  395. return nil
  396. }
  397. db.opened = false
  398. db.freelist = nil
  399. // Clear ops.
  400. db.ops.writeAt = nil
  401. // Close the mmap.
  402. if err := db.munmap(); err != nil {
  403. return err
  404. }
  405. // Close file handles.
  406. if db.file != nil {
  407. // No need to unlock read-only file.
  408. if !db.readOnly {
  409. // Unlock the file.
  410. if err := funlock(db); err != nil {
  411. log.Printf("bolt.Close(): funlock error: %s", err)
  412. }
  413. }
  414. // Close the file descriptor.
  415. if err := db.file.Close(); err != nil {
  416. return fmt.Errorf("db file close: %s", err)
  417. }
  418. db.file = nil
  419. }
  420. db.path = ""
  421. return nil
  422. }
  423. // Begin starts a new transaction.
  424. // Multiple read-only transactions can be used concurrently but only one
  425. // write transaction can be used at a time. Starting multiple write transactions
  426. // will cause the calls to block and be serialized until the current write
  427. // transaction finishes.
  428. //
  429. // Transactions should not be dependent on one another. Opening a read
  430. // transaction and a write transaction in the same goroutine can cause the
  431. // writer to deadlock because the database periodically needs to re-mmap itself
  432. // as it grows and it cannot do that while a read transaction is open.
  433. //
  434. // If a long running read transaction (for example, a snapshot transaction) is
  435. // needed, you might want to set DB.InitialMmapSize to a large enough value
  436. // to avoid potential blocking of write transaction.
  437. //
  438. // IMPORTANT: You must close read-only transactions after you are finished or
  439. // else the database will not reclaim old pages.
  440. func (db *DB) Begin(writable bool) (*Tx, error) {
  441. if writable {
  442. return db.beginRWTx()
  443. }
  444. return db.beginTx()
  445. }
  446. func (db *DB) beginTx() (*Tx, error) {
  447. // Lock the meta pages while we initialize the transaction. We obtain
  448. // the meta lock before the mmap lock because that's the order that the
  449. // write transaction will obtain them.
  450. db.metalock.Lock()
  451. // Obtain a read-only lock on the mmap. When the mmap is remapped it will
  452. // obtain a write lock so all transactions must finish before it can be
  453. // remapped.
  454. db.mmaplock.RLock()
  455. // Exit if the database is not open yet.
  456. if !db.opened {
  457. db.mmaplock.RUnlock()
  458. db.metalock.Unlock()
  459. return nil, ErrDatabaseNotOpen
  460. }
  461. // Create a transaction associated with the database.
  462. t := &Tx{}
  463. t.init(db)
  464. // Keep track of transaction until it closes.
  465. db.txs = append(db.txs, t)
  466. n := len(db.txs)
  467. // Unlock the meta pages.
  468. db.metalock.Unlock()
  469. // Update the transaction stats.
  470. db.statlock.Lock()
  471. db.stats.TxN++
  472. db.stats.OpenTxN = n
  473. db.statlock.Unlock()
  474. return t, nil
  475. }
  476. func (db *DB) beginRWTx() (*Tx, error) {
  477. // If the database was opened with Options.ReadOnly, return an error.
  478. if db.readOnly {
  479. return nil, ErrDatabaseReadOnly
  480. }
  481. // Obtain writer lock. This is released by the transaction when it closes.
  482. // This enforces only one writer transaction at a time.
  483. db.rwlock.Lock()
  484. // Once we have the writer lock then we can lock the meta pages so that
  485. // we can set up the transaction.
  486. db.metalock.Lock()
  487. defer db.metalock.Unlock()
  488. // Exit if the database is not open yet.
  489. if !db.opened {
  490. db.rwlock.Unlock()
  491. return nil, ErrDatabaseNotOpen
  492. }
  493. // Create a transaction associated with the database.
  494. t := &Tx{writable: true}
  495. t.init(db)
  496. db.rwtx = t
  497. db.freePages()
  498. return t, nil
  499. }
  500. // freePages releases any pages associated with closed read-only transactions.
  501. func (db *DB) freePages() {
  502. // Free all pending pages prior to earliest open transaction.
  503. sort.Sort(txsById(db.txs))
  504. minid := txid(0xFFFFFFFFFFFFFFFF)
  505. if len(db.txs) > 0 {
  506. minid = db.txs[0].meta.txid
  507. }
  508. if minid > 0 {
  509. db.freelist.release(minid - 1)
  510. }
  511. // Release unused txid extents.
  512. for _, t := range db.txs {
  513. db.freelist.releaseRange(minid, t.meta.txid-1)
  514. minid = t.meta.txid + 1
  515. }
  516. db.freelist.releaseRange(minid, txid(0xFFFFFFFFFFFFFFFF))
  517. // Any page both allocated and freed in an extent is safe to release.
  518. }
  519. type txsById []*Tx
  520. func (t txsById) Len() int { return len(t) }
  521. func (t txsById) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
  522. func (t txsById) Less(i, j int) bool { return t[i].meta.txid < t[j].meta.txid }
  523. // removeTx removes a transaction from the database.
  524. func (db *DB) removeTx(tx *Tx) {
  525. // Release the read lock on the mmap.
  526. db.mmaplock.RUnlock()
  527. // Use the meta lock to restrict access to the DB object.
  528. db.metalock.Lock()
  529. // Remove the transaction.
  530. for i, t := range db.txs {
  531. if t == tx {
  532. last := len(db.txs) - 1
  533. db.txs[i] = db.txs[last]
  534. db.txs[last] = nil
  535. db.txs = db.txs[:last]
  536. break
  537. }
  538. }
  539. n := len(db.txs)
  540. // Unlock the meta pages.
  541. db.metalock.Unlock()
  542. // Merge statistics.
  543. db.statlock.Lock()
  544. db.stats.OpenTxN = n
  545. db.stats.TxStats.add(&tx.stats)
  546. db.statlock.Unlock()
  547. }
  548. // Update executes a function within the context of a read-write managed transaction.
  549. // If no error is returned from the function then the transaction is committed.
  550. // If an error is returned then the entire transaction is rolled back.
  551. // Any error that is returned from the function or returned from the commit is
  552. // returned from the Update() method.
  553. //
  554. // Attempting to manually commit or rollback within the function will cause a panic.
  555. func (db *DB) Update(fn func(*Tx) error) error {
  556. t, err := db.Begin(true)
  557. if err != nil {
  558. return err
  559. }
  560. // Make sure the transaction rolls back in the event of a panic.
  561. defer func() {
  562. if t.db != nil {
  563. t.rollback()
  564. }
  565. }()
  566. // Mark as a managed tx so that the inner function cannot manually commit.
  567. t.managed = true
  568. // If an error is returned from the function then rollback and return error.
  569. err = fn(t)
  570. t.managed = false
  571. if err != nil {
  572. _ = t.Rollback()
  573. return err
  574. }
  575. return t.Commit()
  576. }
  577. // View executes a function within the context of a managed read-only transaction.
  578. // Any error that is returned from the function is returned from the View() method.
  579. //
  580. // Attempting to manually rollback within the function will cause a panic.
  581. func (db *DB) View(fn func(*Tx) error) error {
  582. t, err := db.Begin(false)
  583. if err != nil {
  584. return err
  585. }
  586. // Make sure the transaction rolls back in the event of a panic.
  587. defer func() {
  588. if t.db != nil {
  589. t.rollback()
  590. }
  591. }()
  592. // Mark as a managed tx so that the inner function cannot manually rollback.
  593. t.managed = true
  594. // If an error is returned from the function then pass it through.
  595. err = fn(t)
  596. t.managed = false
  597. if err != nil {
  598. _ = t.Rollback()
  599. return err
  600. }
  601. return t.Rollback()
  602. }
  603. // Batch calls fn as part of a batch. It behaves similar to Update,
  604. // except:
  605. //
  606. // 1. concurrent Batch calls can be combined into a single Bolt
  607. // transaction.
  608. //
  609. // 2. the function passed to Batch may be called multiple times,
  610. // regardless of whether it returns error or not.
  611. //
  612. // This means that Batch function side effects must be idempotent and
  613. // take permanent effect only after a successful return is seen in
  614. // caller.
  615. //
  616. // The maximum batch size and delay can be adjusted with DB.MaxBatchSize
  617. // and DB.MaxBatchDelay, respectively.
  618. //
  619. // Batch is only useful when there are multiple goroutines calling it.
  620. func (db *DB) Batch(fn func(*Tx) error) error {
  621. errCh := make(chan error, 1)
  622. db.batchMu.Lock()
  623. if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
  624. // There is no existing batch, or the existing batch is full; start a new one.
  625. db.batch = &batch{
  626. db: db,
  627. }
  628. db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
  629. }
  630. db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
  631. if len(db.batch.calls) >= db.MaxBatchSize {
  632. // wake up batch, it's ready to run
  633. go db.batch.trigger()
  634. }
  635. db.batchMu.Unlock()
  636. err := <-errCh
  637. if err == trySolo {
  638. err = db.Update(fn)
  639. }
  640. return err
  641. }
  642. type call struct {
  643. fn func(*Tx) error
  644. err chan<- error
  645. }
  646. type batch struct {
  647. db *DB
  648. timer *time.Timer
  649. start sync.Once
  650. calls []call
  651. }
  652. // trigger runs the batch if it hasn't already been run.
  653. func (b *batch) trigger() {
  654. b.start.Do(b.run)
  655. }
  656. // run performs the transactions in the batch and communicates results
  657. // back to DB.Batch.
  658. func (b *batch) run() {
  659. b.db.batchMu.Lock()
  660. b.timer.Stop()
  661. // Make sure no new work is added to this batch, but don't break
  662. // other batches.
  663. if b.db.batch == b {
  664. b.db.batch = nil
  665. }
  666. b.db.batchMu.Unlock()
  667. retry:
  668. for len(b.calls) > 0 {
  669. var failIdx = -1
  670. err := b.db.Update(func(tx *Tx) error {
  671. for i, c := range b.calls {
  672. if err := safelyCall(c.fn, tx); err != nil {
  673. failIdx = i
  674. return err
  675. }
  676. }
  677. return nil
  678. })
  679. if failIdx >= 0 {
  680. // take the failing transaction out of the batch. it's
  681. // safe to shorten b.calls here because db.batch no longer
  682. // points to us, and we hold the mutex anyway.
  683. c := b.calls[failIdx]
  684. b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
  685. // tell the submitter re-run it solo, continue with the rest of the batch
  686. c.err <- trySolo
  687. continue retry
  688. }
  689. // pass success, or bolt internal errors, to all callers
  690. for _, c := range b.calls {
  691. c.err <- err
  692. }
  693. break retry
  694. }
  695. }
  696. // trySolo is a special sentinel error value used for signaling that a
  697. // transaction function should be re-run. It should never be seen by
  698. // callers.
  699. var trySolo = errors.New("batch function returned an error and should be re-run solo")
  700. type panicked struct {
  701. reason interface{}
  702. }
  703. func (p panicked) Error() string {
  704. if err, ok := p.reason.(error); ok {
  705. return err.Error()
  706. }
  707. return fmt.Sprintf("panic: %v", p.reason)
  708. }
  709. func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
  710. defer func() {
  711. if p := recover(); p != nil {
  712. err = panicked{p}
  713. }
  714. }()
  715. return fn(tx)
  716. }
  717. // Sync executes fdatasync() against the database file handle.
  718. //
  719. // This is not necessary under normal operation, however, if you use NoSync
  720. // then it allows you to force the database file to sync against the disk.
  721. func (db *DB) Sync() error { return fdatasync(db) }
  722. // Stats retrieves ongoing performance stats for the database.
  723. // This is only updated when a transaction closes.
  724. func (db *DB) Stats() Stats {
  725. db.statlock.RLock()
  726. defer db.statlock.RUnlock()
  727. return db.stats
  728. }
  729. // This is for internal access to the raw data bytes from the C cursor, use
  730. // carefully, or not at all.
  731. func (db *DB) Info() *Info {
  732. return &Info{uintptr(unsafe.Pointer(&db.data[0])), db.pageSize}
  733. }
  734. // page retrieves a page reference from the mmap based on the current page size.
  735. func (db *DB) page(id pgid) *page {
  736. pos := id * pgid(db.pageSize)
  737. return (*page)(unsafe.Pointer(&db.data[pos]))
  738. }
  739. // pageInBuffer retrieves a page reference from a given byte array based on the current page size.
  740. func (db *DB) pageInBuffer(b []byte, id pgid) *page {
  741. return (*page)(unsafe.Pointer(&b[id*pgid(db.pageSize)]))
  742. }
  743. // meta retrieves the current meta page reference.
  744. func (db *DB) meta() *meta {
  745. // We have to return the meta with the highest txid which doesn't fail
  746. // validation. Otherwise, we can cause errors when in fact the database is
  747. // in a consistent state. metaA is the one with the higher txid.
  748. metaA := db.meta0
  749. metaB := db.meta1
  750. if db.meta1.txid > db.meta0.txid {
  751. metaA = db.meta1
  752. metaB = db.meta0
  753. }
  754. // Use higher meta page if valid. Otherwise fallback to previous, if valid.
  755. if err := metaA.validate(); err == nil {
  756. return metaA
  757. } else if err := metaB.validate(); err == nil {
  758. return metaB
  759. }
  760. // This should never be reached, because both meta1 and meta0 were validated
  761. // on mmap() and we do fsync() on every write.
  762. panic("bolt.DB.meta(): invalid meta pages")
  763. }
  764. // allocate returns a contiguous block of memory starting at a given page.
  765. func (db *DB) allocate(txid txid, count int) (*page, error) {
  766. // Allocate a temporary buffer for the page.
  767. var buf []byte
  768. if count == 1 {
  769. buf = db.pagePool.Get().([]byte)
  770. } else {
  771. buf = make([]byte, count*db.pageSize)
  772. }
  773. p := (*page)(unsafe.Pointer(&buf[0]))
  774. p.overflow = uint32(count - 1)
  775. // Use pages from the freelist if they are available.
  776. if p.id = db.freelist.allocate(txid, count); p.id != 0 {
  777. return p, nil
  778. }
  779. // Resize mmap() if we're at the end.
  780. p.id = db.rwtx.meta.pgid
  781. var minsz = int((p.id+pgid(count))+1) * db.pageSize
  782. if minsz >= db.datasz {
  783. if err := db.mmap(minsz); err != nil {
  784. return nil, fmt.Errorf("mmap allocate error: %s", err)
  785. }
  786. }
  787. // Move the page id high water mark.
  788. db.rwtx.meta.pgid += pgid(count)
  789. return p, nil
  790. }
  791. // grow grows the size of the database to the given sz.
  792. func (db *DB) grow(sz int) error {
  793. // Ignore if the new size is less than available file size.
  794. if sz <= db.filesz {
  795. return nil
  796. }
  797. // If the data is smaller than the alloc size then only allocate what's needed.
  798. // Once it goes over the allocation size then allocate in chunks.
  799. if db.datasz < db.AllocSize {
  800. sz = db.datasz
  801. } else {
  802. sz += db.AllocSize
  803. }
  804. // Truncate and fsync to ensure file size metadata is flushed.
  805. // https://github.com/boltdb/bolt/issues/284
  806. if !db.NoGrowSync && !db.readOnly {
  807. if runtime.GOOS != "windows" {
  808. if err := db.file.Truncate(int64(sz)); err != nil {
  809. return fmt.Errorf("file resize error: %s", err)
  810. }
  811. }
  812. if err := db.file.Sync(); err != nil {
  813. return fmt.Errorf("file sync error: %s", err)
  814. }
  815. }
  816. db.filesz = sz
  817. return nil
  818. }
  819. func (db *DB) IsReadOnly() bool {
  820. return db.readOnly
  821. }
  822. func (db *DB) freepages() []pgid {
  823. tx, err := db.beginTx()
  824. defer func() {
  825. err = tx.Rollback()
  826. if err != nil {
  827. panic("freepages: failed to rollback tx")
  828. }
  829. }()
  830. if err != nil {
  831. panic("freepages: failed to open read only tx")
  832. }
  833. reachable := make(map[pgid]*page)
  834. nofreed := make(map[pgid]bool)
  835. ech := make(chan error)
  836. go func() {
  837. for e := range ech {
  838. panic(fmt.Sprintf("freepages: failed to get all reachable pages (%v)", e))
  839. }
  840. }()
  841. tx.checkBucket(&tx.root, reachable, nofreed, ech)
  842. close(ech)
  843. var fids []pgid
  844. for i := pgid(2); i < db.meta().pgid; i++ {
  845. if _, ok := reachable[i]; !ok {
  846. fids = append(fids, i)
  847. }
  848. }
  849. return fids
  850. }
  851. // Options represents the options that can be set when opening a database.
  852. type Options struct {
  853. // Timeout is the amount of time to wait to obtain a file lock.
  854. // When set to zero it will wait indefinitely. This option is only
  855. // available on Darwin and Linux.
  856. Timeout time.Duration
  857. // Sets the DB.NoGrowSync flag before memory mapping the file.
  858. NoGrowSync bool
  859. // Do not sync freelist to disk. This improves the database write performance
  860. // under normal operation, but requires a full database re-sync during recovery.
  861. NoFreelistSync bool
  862. // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to
  863. // grab a shared lock (UNIX).
  864. ReadOnly bool
  865. // Sets the DB.MmapFlags flag before memory mapping the file.
  866. MmapFlags int
  867. // InitialMmapSize is the initial mmap size of the database
  868. // in bytes. Read transactions won't block write transaction
  869. // if the InitialMmapSize is large enough to hold database mmap
  870. // size. (See DB.Begin for more information)
  871. //
  872. // If <=0, the initial map size is 0.
  873. // If initialMmapSize is smaller than the previous database size,
  874. // it takes no effect.
  875. InitialMmapSize int
  876. // PageSize overrides the default OS page size.
  877. PageSize int
  878. // NoSync sets the initial value of DB.NoSync. Normally this can just be
  879. // set directly on the DB itself when returned from Open(), but this option
  880. // is useful in APIs which expose Options but not the underlying DB.
  881. NoSync bool
  882. }
  883. // DefaultOptions represent the options used if nil options are passed into Open().
  884. // No timeout is used which will cause Bolt to wait indefinitely for a lock.
  885. var DefaultOptions = &Options{
  886. Timeout: 0,
  887. NoGrowSync: false,
  888. }
  889. // Stats represents statistics about the database.
  890. type Stats struct {
  891. // Freelist stats
  892. FreePageN int // total number of free pages on the freelist
  893. PendingPageN int // total number of pending pages on the freelist
  894. FreeAlloc int // total bytes allocated in free pages
  895. FreelistInuse int // total bytes used by the freelist
  896. // Transaction stats
  897. TxN int // total number of started read transactions
  898. OpenTxN int // number of currently open read transactions
  899. TxStats TxStats // global, ongoing stats.
  900. }
  901. // Sub calculates and returns the difference between two sets of database stats.
  902. // This is useful when obtaining stats at two different points and time and
  903. // you need the performance counters that occurred within that time span.
  904. func (s *Stats) Sub(other *Stats) Stats {
  905. if other == nil {
  906. return *s
  907. }
  908. var diff Stats
  909. diff.FreePageN = s.FreePageN
  910. diff.PendingPageN = s.PendingPageN
  911. diff.FreeAlloc = s.FreeAlloc
  912. diff.FreelistInuse = s.FreelistInuse
  913. diff.TxN = s.TxN - other.TxN
  914. diff.TxStats = s.TxStats.Sub(&other.TxStats)
  915. return diff
  916. }
  917. type Info struct {
  918. Data uintptr
  919. PageSize int
  920. }
  921. type meta struct {
  922. magic uint32
  923. version uint32
  924. pageSize uint32
  925. flags uint32
  926. root bucket
  927. freelist pgid
  928. pgid pgid
  929. txid txid
  930. checksum uint64
  931. }
  932. // validate checks the marker bytes and version of the meta page to ensure it matches this binary.
  933. func (m *meta) validate() error {
  934. if m.magic != magic {
  935. return ErrInvalid
  936. } else if m.version != version {
  937. return ErrVersionMismatch
  938. } else if m.checksum != 0 && m.checksum != m.sum64() {
  939. return ErrChecksum
  940. }
  941. return nil
  942. }
  943. // copy copies one meta object to another.
  944. func (m *meta) copy(dest *meta) {
  945. *dest = *m
  946. }
  947. // write writes the meta onto a page.
  948. func (m *meta) write(p *page) {
  949. if m.root.root >= m.pgid {
  950. panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
  951. } else if m.freelist >= m.pgid && m.freelist != pgidNoFreelist {
  952. // TODO: reject pgidNoFreeList if !NoFreelistSync
  953. panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
  954. }
  955. // Page id is either going to be 0 or 1 which we can determine by the transaction ID.
  956. p.id = pgid(m.txid % 2)
  957. p.flags |= metaPageFlag
  958. // Calculate the checksum.
  959. m.checksum = m.sum64()
  960. m.copy(p.meta())
  961. }
  962. // generates the checksum for the meta.
  963. func (m *meta) sum64() uint64 {
  964. var h = fnv.New64a()
  965. _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
  966. return h.Sum64()
  967. }
  968. // _assert will panic with a given formatted message if the given condition is false.
  969. func _assert(condition bool, msg string, v ...interface{}) {
  970. if !condition {
  971. panic(fmt.Sprintf("assertion failed: "+msg, v...))
  972. }
  973. }