db_test.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753
  1. package bbolt_test
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "flag"
  7. "fmt"
  8. "hash/fnv"
  9. "io/ioutil"
  10. "log"
  11. "math/rand"
  12. "os"
  13. "path/filepath"
  14. "regexp"
  15. "sync"
  16. "testing"
  17. "time"
  18. "unsafe"
  19. bolt "go.etcd.io/bbolt"
  20. )
  21. var statsFlag = flag.Bool("stats", false, "show performance stats")
  22. // pageSize is the size of one page in the data file.
  23. const pageSize = 4096
  24. // pageHeaderSize is the size of a page header.
  25. const pageHeaderSize = 16
  26. // meta represents a simplified version of a database meta page for testing.
  27. type meta struct {
  28. magic uint32
  29. version uint32
  30. _ uint32
  31. _ uint32
  32. _ [16]byte
  33. _ uint64
  34. pgid uint64
  35. _ uint64
  36. checksum uint64
  37. }
  38. // Ensure that a database can be opened without error.
  39. func TestOpen(t *testing.T) {
  40. path := tempfile()
  41. defer os.RemoveAll(path)
  42. db, err := bolt.Open(path, 0666, nil)
  43. if err != nil {
  44. t.Fatal(err)
  45. } else if db == nil {
  46. t.Fatal("expected db")
  47. }
  48. if s := db.Path(); s != path {
  49. t.Fatalf("unexpected path: %s", s)
  50. }
  51. if err := db.Close(); err != nil {
  52. t.Fatal(err)
  53. }
  54. }
  55. // Regression validation for https://github.com/etcd-io/bbolt/pull/122.
  56. // Tests multiple goroutines simultaneously opening a database.
  57. func TestOpen_MultipleGoroutines(t *testing.T) {
  58. const (
  59. instances = 30
  60. iterations = 30
  61. )
  62. path := tempfile()
  63. defer os.RemoveAll(path)
  64. var wg sync.WaitGroup
  65. for iteration := 0; iteration < iterations; iteration++ {
  66. for instance := 0; instance < instances; instance++ {
  67. wg.Add(1)
  68. go func() {
  69. defer wg.Done()
  70. db, err := bolt.Open(path, 0600, nil)
  71. if err != nil {
  72. t.Fatal(err)
  73. }
  74. if err := db.Close(); err != nil {
  75. t.Fatal(err)
  76. }
  77. }()
  78. }
  79. wg.Wait()
  80. }
  81. }
  82. // Ensure that opening a database with a blank path returns an error.
  83. func TestOpen_ErrPathRequired(t *testing.T) {
  84. _, err := bolt.Open("", 0666, nil)
  85. if err == nil {
  86. t.Fatalf("expected error")
  87. }
  88. }
  89. // Ensure that opening a database with a bad path returns an error.
  90. func TestOpen_ErrNotExists(t *testing.T) {
  91. _, err := bolt.Open(filepath.Join(tempfile(), "bad-path"), 0666, nil)
  92. if err == nil {
  93. t.Fatal("expected error")
  94. }
  95. }
  96. // Ensure that opening a file that is not a Bolt database returns ErrInvalid.
  97. func TestOpen_ErrInvalid(t *testing.T) {
  98. path := tempfile()
  99. defer os.RemoveAll(path)
  100. f, err := os.Create(path)
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. if _, err := fmt.Fprintln(f, "this is not a bolt database"); err != nil {
  105. t.Fatal(err)
  106. }
  107. if err := f.Close(); err != nil {
  108. t.Fatal(err)
  109. }
  110. if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrInvalid {
  111. t.Fatalf("unexpected error: %s", err)
  112. }
  113. }
  114. // Ensure that opening a file with two invalid versions returns ErrVersionMismatch.
  115. func TestOpen_ErrVersionMismatch(t *testing.T) {
  116. if pageSize != os.Getpagesize() {
  117. t.Skip("page size mismatch")
  118. }
  119. // Create empty database.
  120. db := MustOpenDB()
  121. path := db.Path()
  122. defer db.MustClose()
  123. // Close database.
  124. if err := db.DB.Close(); err != nil {
  125. t.Fatal(err)
  126. }
  127. // Read data file.
  128. buf, err := ioutil.ReadFile(path)
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. // Rewrite meta pages.
  133. meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
  134. meta0.version++
  135. meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize]))
  136. meta1.version++
  137. if err := ioutil.WriteFile(path, buf, 0666); err != nil {
  138. t.Fatal(err)
  139. }
  140. // Reopen data file.
  141. if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrVersionMismatch {
  142. t.Fatalf("unexpected error: %s", err)
  143. }
  144. }
  145. // Ensure that opening a file with two invalid checksums returns ErrChecksum.
  146. func TestOpen_ErrChecksum(t *testing.T) {
  147. if pageSize != os.Getpagesize() {
  148. t.Skip("page size mismatch")
  149. }
  150. // Create empty database.
  151. db := MustOpenDB()
  152. path := db.Path()
  153. defer db.MustClose()
  154. // Close database.
  155. if err := db.DB.Close(); err != nil {
  156. t.Fatal(err)
  157. }
  158. // Read data file.
  159. buf, err := ioutil.ReadFile(path)
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. // Rewrite meta pages.
  164. meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize]))
  165. meta0.pgid++
  166. meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize]))
  167. meta1.pgid++
  168. if err := ioutil.WriteFile(path, buf, 0666); err != nil {
  169. t.Fatal(err)
  170. }
  171. // Reopen data file.
  172. if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrChecksum {
  173. t.Fatalf("unexpected error: %s", err)
  174. }
  175. }
  176. // Ensure that opening a database does not increase its size.
  177. // https://github.com/boltdb/bolt/issues/291
  178. func TestOpen_Size(t *testing.T) {
  179. // Open a data file.
  180. db := MustOpenDB()
  181. path := db.Path()
  182. defer db.MustClose()
  183. pagesize := db.Info().PageSize
  184. // Insert until we get above the minimum 4MB size.
  185. if err := db.Update(func(tx *bolt.Tx) error {
  186. b, _ := tx.CreateBucketIfNotExists([]byte("data"))
  187. for i := 0; i < 10000; i++ {
  188. if err := b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)); err != nil {
  189. t.Fatal(err)
  190. }
  191. }
  192. return nil
  193. }); err != nil {
  194. t.Fatal(err)
  195. }
  196. // Close database and grab the size.
  197. if err := db.DB.Close(); err != nil {
  198. t.Fatal(err)
  199. }
  200. sz := fileSize(path)
  201. if sz == 0 {
  202. t.Fatalf("unexpected new file size: %d", sz)
  203. }
  204. // Reopen database, update, and check size again.
  205. db0, err := bolt.Open(path, 0666, nil)
  206. if err != nil {
  207. t.Fatal(err)
  208. }
  209. if err := db0.Update(func(tx *bolt.Tx) error {
  210. if err := tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}); err != nil {
  211. t.Fatal(err)
  212. }
  213. return nil
  214. }); err != nil {
  215. t.Fatal(err)
  216. }
  217. if err := db0.Close(); err != nil {
  218. t.Fatal(err)
  219. }
  220. newSz := fileSize(path)
  221. if newSz == 0 {
  222. t.Fatalf("unexpected new file size: %d", newSz)
  223. }
  224. // Compare the original size with the new size.
  225. // db size might increase by a few page sizes due to the new small update.
  226. if sz < newSz-5*int64(pagesize) {
  227. t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
  228. }
  229. }
  230. // Ensure that opening a database beyond the max step size does not increase its size.
  231. // https://github.com/boltdb/bolt/issues/303
  232. func TestOpen_Size_Large(t *testing.T) {
  233. if testing.Short() {
  234. t.Skip("short mode")
  235. }
  236. // Open a data file.
  237. db := MustOpenDB()
  238. path := db.Path()
  239. defer db.MustClose()
  240. pagesize := db.Info().PageSize
  241. // Insert until we get above the minimum 4MB size.
  242. var index uint64
  243. for i := 0; i < 10000; i++ {
  244. if err := db.Update(func(tx *bolt.Tx) error {
  245. b, _ := tx.CreateBucketIfNotExists([]byte("data"))
  246. for j := 0; j < 1000; j++ {
  247. if err := b.Put(u64tob(index), make([]byte, 50)); err != nil {
  248. t.Fatal(err)
  249. }
  250. index++
  251. }
  252. return nil
  253. }); err != nil {
  254. t.Fatal(err)
  255. }
  256. }
  257. // Close database and grab the size.
  258. if err := db.DB.Close(); err != nil {
  259. t.Fatal(err)
  260. }
  261. sz := fileSize(path)
  262. if sz == 0 {
  263. t.Fatalf("unexpected new file size: %d", sz)
  264. } else if sz < (1 << 30) {
  265. t.Fatalf("expected larger initial size: %d", sz)
  266. }
  267. // Reopen database, update, and check size again.
  268. db0, err := bolt.Open(path, 0666, nil)
  269. if err != nil {
  270. t.Fatal(err)
  271. }
  272. if err := db0.Update(func(tx *bolt.Tx) error {
  273. return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0})
  274. }); err != nil {
  275. t.Fatal(err)
  276. }
  277. if err := db0.Close(); err != nil {
  278. t.Fatal(err)
  279. }
  280. newSz := fileSize(path)
  281. if newSz == 0 {
  282. t.Fatalf("unexpected new file size: %d", newSz)
  283. }
  284. // Compare the original size with the new size.
  285. // db size might increase by a few page sizes due to the new small update.
  286. if sz < newSz-5*int64(pagesize) {
  287. t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
  288. }
  289. }
  290. // Ensure that a re-opened database is consistent.
  291. func TestOpen_Check(t *testing.T) {
  292. path := tempfile()
  293. defer os.RemoveAll(path)
  294. db, err := bolt.Open(path, 0666, nil)
  295. if err != nil {
  296. t.Fatal(err)
  297. }
  298. if err = db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil {
  299. t.Fatal(err)
  300. }
  301. if err = db.Close(); err != nil {
  302. t.Fatal(err)
  303. }
  304. db, err = bolt.Open(path, 0666, nil)
  305. if err != nil {
  306. t.Fatal(err)
  307. }
  308. if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil {
  309. t.Fatal(err)
  310. }
  311. if err := db.Close(); err != nil {
  312. t.Fatal(err)
  313. }
  314. }
  315. // Ensure that write errors to the meta file handler during initialization are returned.
  316. func TestOpen_MetaInitWriteError(t *testing.T) {
  317. t.Skip("pending")
  318. }
  319. // Ensure that a database that is too small returns an error.
  320. func TestOpen_FileTooSmall(t *testing.T) {
  321. path := tempfile()
  322. defer os.RemoveAll(path)
  323. db, err := bolt.Open(path, 0666, nil)
  324. if err != nil {
  325. t.Fatal(err)
  326. }
  327. pageSize := int64(db.Info().PageSize)
  328. if err = db.Close(); err != nil {
  329. t.Fatal(err)
  330. }
  331. // corrupt the database
  332. if err = os.Truncate(path, pageSize); err != nil {
  333. t.Fatal(err)
  334. }
  335. db, err = bolt.Open(path, 0666, nil)
  336. if err == nil || err.Error() != "file size too small" {
  337. t.Fatalf("unexpected error: %s", err)
  338. }
  339. }
  340. // TestDB_Open_InitialMmapSize tests if having InitialMmapSize large enough
  341. // to hold data from concurrent write transaction resolves the issue that
  342. // read transaction blocks the write transaction and causes deadlock.
  343. // This is a very hacky test since the mmap size is not exposed.
  344. func TestDB_Open_InitialMmapSize(t *testing.T) {
  345. path := tempfile()
  346. defer os.Remove(path)
  347. initMmapSize := 1 << 30 // 1GB
  348. testWriteSize := 1 << 27 // 134MB
  349. db, err := bolt.Open(path, 0666, &bolt.Options{InitialMmapSize: initMmapSize})
  350. if err != nil {
  351. t.Fatal(err)
  352. }
  353. // create a long-running read transaction
  354. // that never gets closed while writing
  355. rtx, err := db.Begin(false)
  356. if err != nil {
  357. t.Fatal(err)
  358. }
  359. // create a write transaction
  360. wtx, err := db.Begin(true)
  361. if err != nil {
  362. t.Fatal(err)
  363. }
  364. b, err := wtx.CreateBucket([]byte("test"))
  365. if err != nil {
  366. t.Fatal(err)
  367. }
  368. // and commit a large write
  369. err = b.Put([]byte("foo"), make([]byte, testWriteSize))
  370. if err != nil {
  371. t.Fatal(err)
  372. }
  373. done := make(chan struct{})
  374. go func() {
  375. if err := wtx.Commit(); err != nil {
  376. t.Fatal(err)
  377. }
  378. done <- struct{}{}
  379. }()
  380. select {
  381. case <-time.After(5 * time.Second):
  382. t.Errorf("unexpected that the reader blocks writer")
  383. case <-done:
  384. }
  385. if err := rtx.Rollback(); err != nil {
  386. t.Fatal(err)
  387. }
  388. }
  389. // TestDB_Open_ReadOnly checks a database in read only mode can read but not write.
  390. func TestDB_Open_ReadOnly(t *testing.T) {
  391. // Create a writable db, write k-v and close it.
  392. db := MustOpenDB()
  393. defer db.MustClose()
  394. if err := db.Update(func(tx *bolt.Tx) error {
  395. b, err := tx.CreateBucket([]byte("widgets"))
  396. if err != nil {
  397. t.Fatal(err)
  398. }
  399. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  400. t.Fatal(err)
  401. }
  402. return nil
  403. }); err != nil {
  404. t.Fatal(err)
  405. }
  406. if err := db.DB.Close(); err != nil {
  407. t.Fatal(err)
  408. }
  409. f := db.f
  410. o := &bolt.Options{ReadOnly: true}
  411. readOnlyDB, err := bolt.Open(f, 0666, o)
  412. if err != nil {
  413. panic(err)
  414. }
  415. if !readOnlyDB.IsReadOnly() {
  416. t.Fatal("expect db in read only mode")
  417. }
  418. // Read from a read-only transaction.
  419. if err := readOnlyDB.View(func(tx *bolt.Tx) error {
  420. value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  421. if !bytes.Equal(value, []byte("bar")) {
  422. t.Fatal("expect value 'bar', got", value)
  423. }
  424. return nil
  425. }); err != nil {
  426. t.Fatal(err)
  427. }
  428. // Can't launch read-write transaction.
  429. if _, err := readOnlyDB.Begin(true); err != bolt.ErrDatabaseReadOnly {
  430. t.Fatalf("unexpected error: %s", err)
  431. }
  432. if err := readOnlyDB.Close(); err != nil {
  433. t.Fatal(err)
  434. }
  435. }
  436. // TestOpen_BigPage checks the database uses bigger pages when
  437. // changing PageSize.
  438. func TestOpen_BigPage(t *testing.T) {
  439. pageSize := os.Getpagesize()
  440. db1 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 2})
  441. defer db1.MustClose()
  442. db2 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 4})
  443. defer db2.MustClose()
  444. if db1sz, db2sz := fileSize(db1.f), fileSize(db2.f); db1sz >= db2sz {
  445. t.Errorf("expected %d < %d", db1sz, db2sz)
  446. }
  447. }
  448. // TestOpen_RecoverFreeList tests opening the DB with free-list
  449. // write-out after no free list sync will recover the free list
  450. // and write it out.
  451. func TestOpen_RecoverFreeList(t *testing.T) {
  452. db := MustOpenWithOption(&bolt.Options{NoFreelistSync: true})
  453. defer db.MustClose()
  454. // Write some pages.
  455. tx, err := db.Begin(true)
  456. if err != nil {
  457. t.Fatal(err)
  458. }
  459. wbuf := make([]byte, 8192)
  460. for i := 0; i < 100; i++ {
  461. s := fmt.Sprintf("%d", i)
  462. b, err := tx.CreateBucket([]byte(s))
  463. if err != nil {
  464. t.Fatal(err)
  465. }
  466. if err = b.Put([]byte(s), wbuf); err != nil {
  467. t.Fatal(err)
  468. }
  469. }
  470. if err = tx.Commit(); err != nil {
  471. t.Fatal(err)
  472. }
  473. // Generate free pages.
  474. if tx, err = db.Begin(true); err != nil {
  475. t.Fatal(err)
  476. }
  477. for i := 0; i < 50; i++ {
  478. s := fmt.Sprintf("%d", i)
  479. b := tx.Bucket([]byte(s))
  480. if b == nil {
  481. t.Fatal(err)
  482. }
  483. if err := b.Delete([]byte(s)); err != nil {
  484. t.Fatal(err)
  485. }
  486. }
  487. if err := tx.Commit(); err != nil {
  488. t.Fatal(err)
  489. }
  490. if err := db.DB.Close(); err != nil {
  491. t.Fatal(err)
  492. }
  493. // Record freelist count from opening with NoFreelistSync.
  494. db.MustReopen()
  495. freepages := db.Stats().FreePageN
  496. if freepages == 0 {
  497. t.Fatalf("no free pages on NoFreelistSync reopen")
  498. }
  499. if err := db.DB.Close(); err != nil {
  500. t.Fatal(err)
  501. }
  502. // Check free page count is reconstructed when opened with freelist sync.
  503. db.o = &bolt.Options{}
  504. db.MustReopen()
  505. // One less free page for syncing the free list on open.
  506. freepages--
  507. if fp := db.Stats().FreePageN; fp < freepages {
  508. t.Fatalf("closed with %d free pages, opened with %d", freepages, fp)
  509. }
  510. }
  511. // Ensure that a database cannot open a transaction when it's not open.
  512. func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) {
  513. var db bolt.DB
  514. if _, err := db.Begin(false); err != bolt.ErrDatabaseNotOpen {
  515. t.Fatalf("unexpected error: %s", err)
  516. }
  517. }
  518. // Ensure that a read-write transaction can be retrieved.
  519. func TestDB_BeginRW(t *testing.T) {
  520. db := MustOpenDB()
  521. defer db.MustClose()
  522. tx, err := db.Begin(true)
  523. if err != nil {
  524. t.Fatal(err)
  525. } else if tx == nil {
  526. t.Fatal("expected tx")
  527. }
  528. if tx.DB() != db.DB {
  529. t.Fatal("unexpected tx database")
  530. } else if !tx.Writable() {
  531. t.Fatal("expected writable tx")
  532. }
  533. if err := tx.Commit(); err != nil {
  534. t.Fatal(err)
  535. }
  536. }
  537. // TestDB_Concurrent_WriteTo checks that issuing WriteTo operations concurrently
  538. // with commits does not produce corrupted db files.
  539. func TestDB_Concurrent_WriteTo(t *testing.T) {
  540. o := &bolt.Options{NoFreelistSync: false}
  541. db := MustOpenWithOption(o)
  542. defer db.MustClose()
  543. var wg sync.WaitGroup
  544. wtxs, rtxs := 5, 5
  545. wg.Add(wtxs * rtxs)
  546. f := func(tx *bolt.Tx) {
  547. defer wg.Done()
  548. f, err := ioutil.TempFile("", "bolt-")
  549. if err != nil {
  550. panic(err)
  551. }
  552. time.Sleep(time.Duration(rand.Intn(20)+1) * time.Millisecond)
  553. tx.WriteTo(f)
  554. tx.Rollback()
  555. f.Close()
  556. snap := &DB{nil, f.Name(), o}
  557. snap.MustReopen()
  558. defer snap.MustClose()
  559. snap.MustCheck()
  560. }
  561. tx1, err := db.Begin(true)
  562. if err != nil {
  563. t.Fatal(err)
  564. }
  565. if _, err := tx1.CreateBucket([]byte("abc")); err != nil {
  566. t.Fatal(err)
  567. }
  568. if err := tx1.Commit(); err != nil {
  569. t.Fatal(err)
  570. }
  571. for i := 0; i < wtxs; i++ {
  572. tx, err := db.Begin(true)
  573. if err != nil {
  574. t.Fatal(err)
  575. }
  576. if err := tx.Bucket([]byte("abc")).Put([]byte{0}, []byte{0}); err != nil {
  577. t.Fatal(err)
  578. }
  579. for j := 0; j < rtxs; j++ {
  580. rtx, rerr := db.Begin(false)
  581. if rerr != nil {
  582. t.Fatal(rerr)
  583. }
  584. go f(rtx)
  585. }
  586. if err := tx.Commit(); err != nil {
  587. t.Fatal(err)
  588. }
  589. }
  590. wg.Wait()
  591. }
  592. // Ensure that opening a transaction while the DB is closed returns an error.
  593. func TestDB_BeginRW_Closed(t *testing.T) {
  594. var db bolt.DB
  595. if _, err := db.Begin(true); err != bolt.ErrDatabaseNotOpen {
  596. t.Fatalf("unexpected error: %s", err)
  597. }
  598. }
  599. func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) }
  600. func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) }
  601. // Ensure that a database cannot close while transactions are open.
  602. func testDB_Close_PendingTx(t *testing.T, writable bool) {
  603. db := MustOpenDB()
  604. // Start transaction.
  605. tx, err := db.Begin(writable)
  606. if err != nil {
  607. t.Fatal(err)
  608. }
  609. // Open update in separate goroutine.
  610. done := make(chan struct{})
  611. go func() {
  612. if err := db.Close(); err != nil {
  613. t.Fatal(err)
  614. }
  615. close(done)
  616. }()
  617. // Ensure database hasn't closed.
  618. time.Sleep(100 * time.Millisecond)
  619. select {
  620. case <-done:
  621. t.Fatal("database closed too early")
  622. default:
  623. }
  624. // Commit/close transaction.
  625. if writable {
  626. err = tx.Commit()
  627. } else {
  628. err = tx.Rollback()
  629. }
  630. if err != nil {
  631. t.Fatal(err)
  632. }
  633. // Ensure database closed now.
  634. time.Sleep(100 * time.Millisecond)
  635. select {
  636. case <-done:
  637. default:
  638. t.Fatal("database did not close")
  639. }
  640. }
  641. // Ensure a database can provide a transactional block.
  642. func TestDB_Update(t *testing.T) {
  643. db := MustOpenDB()
  644. defer db.MustClose()
  645. if err := db.Update(func(tx *bolt.Tx) error {
  646. b, err := tx.CreateBucket([]byte("widgets"))
  647. if err != nil {
  648. t.Fatal(err)
  649. }
  650. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  651. t.Fatal(err)
  652. }
  653. if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
  654. t.Fatal(err)
  655. }
  656. if err := b.Delete([]byte("foo")); err != nil {
  657. t.Fatal(err)
  658. }
  659. return nil
  660. }); err != nil {
  661. t.Fatal(err)
  662. }
  663. if err := db.View(func(tx *bolt.Tx) error {
  664. b := tx.Bucket([]byte("widgets"))
  665. if v := b.Get([]byte("foo")); v != nil {
  666. t.Fatalf("expected nil value, got: %v", v)
  667. }
  668. if v := b.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
  669. t.Fatalf("unexpected value: %v", v)
  670. }
  671. return nil
  672. }); err != nil {
  673. t.Fatal(err)
  674. }
  675. }
  676. // Ensure a closed database returns an error while running a transaction block
  677. func TestDB_Update_Closed(t *testing.T) {
  678. var db bolt.DB
  679. if err := db.Update(func(tx *bolt.Tx) error {
  680. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  681. t.Fatal(err)
  682. }
  683. return nil
  684. }); err != bolt.ErrDatabaseNotOpen {
  685. t.Fatalf("unexpected error: %s", err)
  686. }
  687. }
  688. // Ensure a panic occurs while trying to commit a managed transaction.
  689. func TestDB_Update_ManualCommit(t *testing.T) {
  690. db := MustOpenDB()
  691. defer db.MustClose()
  692. var panicked bool
  693. if err := db.Update(func(tx *bolt.Tx) error {
  694. func() {
  695. defer func() {
  696. if r := recover(); r != nil {
  697. panicked = true
  698. }
  699. }()
  700. if err := tx.Commit(); err != nil {
  701. t.Fatal(err)
  702. }
  703. }()
  704. return nil
  705. }); err != nil {
  706. t.Fatal(err)
  707. } else if !panicked {
  708. t.Fatal("expected panic")
  709. }
  710. }
  711. // Ensure a panic occurs while trying to rollback a managed transaction.
  712. func TestDB_Update_ManualRollback(t *testing.T) {
  713. db := MustOpenDB()
  714. defer db.MustClose()
  715. var panicked bool
  716. if err := db.Update(func(tx *bolt.Tx) error {
  717. func() {
  718. defer func() {
  719. if r := recover(); r != nil {
  720. panicked = true
  721. }
  722. }()
  723. if err := tx.Rollback(); err != nil {
  724. t.Fatal(err)
  725. }
  726. }()
  727. return nil
  728. }); err != nil {
  729. t.Fatal(err)
  730. } else if !panicked {
  731. t.Fatal("expected panic")
  732. }
  733. }
  734. // Ensure a panic occurs while trying to commit a managed transaction.
  735. func TestDB_View_ManualCommit(t *testing.T) {
  736. db := MustOpenDB()
  737. defer db.MustClose()
  738. var panicked bool
  739. if err := db.View(func(tx *bolt.Tx) error {
  740. func() {
  741. defer func() {
  742. if r := recover(); r != nil {
  743. panicked = true
  744. }
  745. }()
  746. if err := tx.Commit(); err != nil {
  747. t.Fatal(err)
  748. }
  749. }()
  750. return nil
  751. }); err != nil {
  752. t.Fatal(err)
  753. } else if !panicked {
  754. t.Fatal("expected panic")
  755. }
  756. }
  757. // Ensure a panic occurs while trying to rollback a managed transaction.
  758. func TestDB_View_ManualRollback(t *testing.T) {
  759. db := MustOpenDB()
  760. defer db.MustClose()
  761. var panicked bool
  762. if err := db.View(func(tx *bolt.Tx) error {
  763. func() {
  764. defer func() {
  765. if r := recover(); r != nil {
  766. panicked = true
  767. }
  768. }()
  769. if err := tx.Rollback(); err != nil {
  770. t.Fatal(err)
  771. }
  772. }()
  773. return nil
  774. }); err != nil {
  775. t.Fatal(err)
  776. } else if !panicked {
  777. t.Fatal("expected panic")
  778. }
  779. }
  780. // Ensure a write transaction that panics does not hold open locks.
  781. func TestDB_Update_Panic(t *testing.T) {
  782. db := MustOpenDB()
  783. defer db.MustClose()
  784. // Panic during update but recover.
  785. func() {
  786. defer func() {
  787. if r := recover(); r != nil {
  788. t.Log("recover: update", r)
  789. }
  790. }()
  791. if err := db.Update(func(tx *bolt.Tx) error {
  792. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  793. t.Fatal(err)
  794. }
  795. panic("omg")
  796. }); err != nil {
  797. t.Fatal(err)
  798. }
  799. }()
  800. // Verify we can update again.
  801. if err := db.Update(func(tx *bolt.Tx) error {
  802. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  803. t.Fatal(err)
  804. }
  805. return nil
  806. }); err != nil {
  807. t.Fatal(err)
  808. }
  809. // Verify that our change persisted.
  810. if err := db.Update(func(tx *bolt.Tx) error {
  811. if tx.Bucket([]byte("widgets")) == nil {
  812. t.Fatal("expected bucket")
  813. }
  814. return nil
  815. }); err != nil {
  816. t.Fatal(err)
  817. }
  818. }
  819. // Ensure a database can return an error through a read-only transactional block.
  820. func TestDB_View_Error(t *testing.T) {
  821. db := MustOpenDB()
  822. defer db.MustClose()
  823. if err := db.View(func(tx *bolt.Tx) error {
  824. return errors.New("xxx")
  825. }); err == nil || err.Error() != "xxx" {
  826. t.Fatalf("unexpected error: %s", err)
  827. }
  828. }
  829. // Ensure a read transaction that panics does not hold open locks.
  830. func TestDB_View_Panic(t *testing.T) {
  831. db := MustOpenDB()
  832. defer db.MustClose()
  833. if err := db.Update(func(tx *bolt.Tx) error {
  834. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  835. t.Fatal(err)
  836. }
  837. return nil
  838. }); err != nil {
  839. t.Fatal(err)
  840. }
  841. // Panic during view transaction but recover.
  842. func() {
  843. defer func() {
  844. if r := recover(); r != nil {
  845. t.Log("recover: view", r)
  846. }
  847. }()
  848. if err := db.View(func(tx *bolt.Tx) error {
  849. if tx.Bucket([]byte("widgets")) == nil {
  850. t.Fatal("expected bucket")
  851. }
  852. panic("omg")
  853. }); err != nil {
  854. t.Fatal(err)
  855. }
  856. }()
  857. // Verify that we can still use read transactions.
  858. if err := db.View(func(tx *bolt.Tx) error {
  859. if tx.Bucket([]byte("widgets")) == nil {
  860. t.Fatal("expected bucket")
  861. }
  862. return nil
  863. }); err != nil {
  864. t.Fatal(err)
  865. }
  866. }
  867. // Ensure that DB stats can be returned.
  868. func TestDB_Stats(t *testing.T) {
  869. db := MustOpenDB()
  870. defer db.MustClose()
  871. if err := db.Update(func(tx *bolt.Tx) error {
  872. _, err := tx.CreateBucket([]byte("widgets"))
  873. return err
  874. }); err != nil {
  875. t.Fatal(err)
  876. }
  877. stats := db.Stats()
  878. if stats.TxStats.PageCount != 2 {
  879. t.Fatalf("unexpected TxStats.PageCount: %d", stats.TxStats.PageCount)
  880. } else if stats.FreePageN != 0 {
  881. t.Fatalf("unexpected FreePageN != 0: %d", stats.FreePageN)
  882. } else if stats.PendingPageN != 2 {
  883. t.Fatalf("unexpected PendingPageN != 2: %d", stats.PendingPageN)
  884. }
  885. }
  886. // Ensure that database pages are in expected order and type.
  887. func TestDB_Consistency(t *testing.T) {
  888. db := MustOpenDB()
  889. defer db.MustClose()
  890. if err := db.Update(func(tx *bolt.Tx) error {
  891. _, err := tx.CreateBucket([]byte("widgets"))
  892. return err
  893. }); err != nil {
  894. t.Fatal(err)
  895. }
  896. for i := 0; i < 10; i++ {
  897. if err := db.Update(func(tx *bolt.Tx) error {
  898. if err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")); err != nil {
  899. t.Fatal(err)
  900. }
  901. return nil
  902. }); err != nil {
  903. t.Fatal(err)
  904. }
  905. }
  906. if err := db.Update(func(tx *bolt.Tx) error {
  907. if p, _ := tx.Page(0); p == nil {
  908. t.Fatal("expected page")
  909. } else if p.Type != "meta" {
  910. t.Fatalf("unexpected page type: %s", p.Type)
  911. }
  912. if p, _ := tx.Page(1); p == nil {
  913. t.Fatal("expected page")
  914. } else if p.Type != "meta" {
  915. t.Fatalf("unexpected page type: %s", p.Type)
  916. }
  917. if p, _ := tx.Page(2); p == nil {
  918. t.Fatal("expected page")
  919. } else if p.Type != "free" {
  920. t.Fatalf("unexpected page type: %s", p.Type)
  921. }
  922. if p, _ := tx.Page(3); p == nil {
  923. t.Fatal("expected page")
  924. } else if p.Type != "free" {
  925. t.Fatalf("unexpected page type: %s", p.Type)
  926. }
  927. if p, _ := tx.Page(4); p == nil {
  928. t.Fatal("expected page")
  929. } else if p.Type != "leaf" {
  930. t.Fatalf("unexpected page type: %s", p.Type)
  931. }
  932. if p, _ := tx.Page(5); p == nil {
  933. t.Fatal("expected page")
  934. } else if p.Type != "freelist" {
  935. t.Fatalf("unexpected page type: %s", p.Type)
  936. }
  937. if p, _ := tx.Page(6); p != nil {
  938. t.Fatal("unexpected page")
  939. }
  940. return nil
  941. }); err != nil {
  942. t.Fatal(err)
  943. }
  944. }
  945. // Ensure that DB stats can be subtracted from one another.
  946. func TestDBStats_Sub(t *testing.T) {
  947. var a, b bolt.Stats
  948. a.TxStats.PageCount = 3
  949. a.FreePageN = 4
  950. b.TxStats.PageCount = 10
  951. b.FreePageN = 14
  952. diff := b.Sub(&a)
  953. if diff.TxStats.PageCount != 7 {
  954. t.Fatalf("unexpected TxStats.PageCount: %d", diff.TxStats.PageCount)
  955. }
  956. // free page stats are copied from the receiver and not subtracted
  957. if diff.FreePageN != 14 {
  958. t.Fatalf("unexpected FreePageN: %d", diff.FreePageN)
  959. }
  960. }
  961. // Ensure two functions can perform updates in a single batch.
  962. func TestDB_Batch(t *testing.T) {
  963. db := MustOpenDB()
  964. defer db.MustClose()
  965. if err := db.Update(func(tx *bolt.Tx) error {
  966. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  967. t.Fatal(err)
  968. }
  969. return nil
  970. }); err != nil {
  971. t.Fatal(err)
  972. }
  973. // Iterate over multiple updates in separate goroutines.
  974. n := 2
  975. ch := make(chan error)
  976. for i := 0; i < n; i++ {
  977. go func(i int) {
  978. ch <- db.Batch(func(tx *bolt.Tx) error {
  979. return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
  980. })
  981. }(i)
  982. }
  983. // Check all responses to make sure there's no error.
  984. for i := 0; i < n; i++ {
  985. if err := <-ch; err != nil {
  986. t.Fatal(err)
  987. }
  988. }
  989. // Ensure data is correct.
  990. if err := db.View(func(tx *bolt.Tx) error {
  991. b := tx.Bucket([]byte("widgets"))
  992. for i := 0; i < n; i++ {
  993. if v := b.Get(u64tob(uint64(i))); v == nil {
  994. t.Errorf("key not found: %d", i)
  995. }
  996. }
  997. return nil
  998. }); err != nil {
  999. t.Fatal(err)
  1000. }
  1001. }
  1002. func TestDB_Batch_Panic(t *testing.T) {
  1003. db := MustOpenDB()
  1004. defer db.MustClose()
  1005. var sentinel int
  1006. var bork = &sentinel
  1007. var problem interface{}
  1008. var err error
  1009. // Execute a function inside a batch that panics.
  1010. func() {
  1011. defer func() {
  1012. if p := recover(); p != nil {
  1013. problem = p
  1014. }
  1015. }()
  1016. err = db.Batch(func(tx *bolt.Tx) error {
  1017. panic(bork)
  1018. })
  1019. }()
  1020. // Verify there is no error.
  1021. if g, e := err, error(nil); g != e {
  1022. t.Fatalf("wrong error: %v != %v", g, e)
  1023. }
  1024. // Verify the panic was captured.
  1025. if g, e := problem, bork; g != e {
  1026. t.Fatalf("wrong error: %v != %v", g, e)
  1027. }
  1028. }
  1029. func TestDB_BatchFull(t *testing.T) {
  1030. db := MustOpenDB()
  1031. defer db.MustClose()
  1032. if err := db.Update(func(tx *bolt.Tx) error {
  1033. _, err := tx.CreateBucket([]byte("widgets"))
  1034. return err
  1035. }); err != nil {
  1036. t.Fatal(err)
  1037. }
  1038. const size = 3
  1039. // buffered so we never leak goroutines
  1040. ch := make(chan error, size)
  1041. put := func(i int) {
  1042. ch <- db.Batch(func(tx *bolt.Tx) error {
  1043. return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
  1044. })
  1045. }
  1046. db.MaxBatchSize = size
  1047. // high enough to never trigger here
  1048. db.MaxBatchDelay = 1 * time.Hour
  1049. go put(1)
  1050. go put(2)
  1051. // Give the batch a chance to exhibit bugs.
  1052. time.Sleep(10 * time.Millisecond)
  1053. // not triggered yet
  1054. select {
  1055. case <-ch:
  1056. t.Fatalf("batch triggered too early")
  1057. default:
  1058. }
  1059. go put(3)
  1060. // Check all responses to make sure there's no error.
  1061. for i := 0; i < size; i++ {
  1062. if err := <-ch; err != nil {
  1063. t.Fatal(err)
  1064. }
  1065. }
  1066. // Ensure data is correct.
  1067. if err := db.View(func(tx *bolt.Tx) error {
  1068. b := tx.Bucket([]byte("widgets"))
  1069. for i := 1; i <= size; i++ {
  1070. if v := b.Get(u64tob(uint64(i))); v == nil {
  1071. t.Errorf("key not found: %d", i)
  1072. }
  1073. }
  1074. return nil
  1075. }); err != nil {
  1076. t.Fatal(err)
  1077. }
  1078. }
  1079. func TestDB_BatchTime(t *testing.T) {
  1080. db := MustOpenDB()
  1081. defer db.MustClose()
  1082. if err := db.Update(func(tx *bolt.Tx) error {
  1083. _, err := tx.CreateBucket([]byte("widgets"))
  1084. return err
  1085. }); err != nil {
  1086. t.Fatal(err)
  1087. }
  1088. const size = 1
  1089. // buffered so we never leak goroutines
  1090. ch := make(chan error, size)
  1091. put := func(i int) {
  1092. ch <- db.Batch(func(tx *bolt.Tx) error {
  1093. return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
  1094. })
  1095. }
  1096. db.MaxBatchSize = 1000
  1097. db.MaxBatchDelay = 0
  1098. go put(1)
  1099. // Batch must trigger by time alone.
  1100. // Check all responses to make sure there's no error.
  1101. for i := 0; i < size; i++ {
  1102. if err := <-ch; err != nil {
  1103. t.Fatal(err)
  1104. }
  1105. }
  1106. // Ensure data is correct.
  1107. if err := db.View(func(tx *bolt.Tx) error {
  1108. b := tx.Bucket([]byte("widgets"))
  1109. for i := 1; i <= size; i++ {
  1110. if v := b.Get(u64tob(uint64(i))); v == nil {
  1111. t.Errorf("key not found: %d", i)
  1112. }
  1113. }
  1114. return nil
  1115. }); err != nil {
  1116. t.Fatal(err)
  1117. }
  1118. }
  1119. func ExampleDB_Update() {
  1120. // Open the database.
  1121. db, err := bolt.Open(tempfile(), 0666, nil)
  1122. if err != nil {
  1123. log.Fatal(err)
  1124. }
  1125. defer os.Remove(db.Path())
  1126. // Execute several commands within a read-write transaction.
  1127. if err := db.Update(func(tx *bolt.Tx) error {
  1128. b, err := tx.CreateBucket([]byte("widgets"))
  1129. if err != nil {
  1130. return err
  1131. }
  1132. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  1133. return err
  1134. }
  1135. return nil
  1136. }); err != nil {
  1137. log.Fatal(err)
  1138. }
  1139. // Read the value back from a separate read-only transaction.
  1140. if err := db.View(func(tx *bolt.Tx) error {
  1141. value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  1142. fmt.Printf("The value of 'foo' is: %s\n", value)
  1143. return nil
  1144. }); err != nil {
  1145. log.Fatal(err)
  1146. }
  1147. // Close database to release the file lock.
  1148. if err := db.Close(); err != nil {
  1149. log.Fatal(err)
  1150. }
  1151. // Output:
  1152. // The value of 'foo' is: bar
  1153. }
  1154. func ExampleDB_View() {
  1155. // Open the database.
  1156. db, err := bolt.Open(tempfile(), 0666, nil)
  1157. if err != nil {
  1158. log.Fatal(err)
  1159. }
  1160. defer os.Remove(db.Path())
  1161. // Insert data into a bucket.
  1162. if err := db.Update(func(tx *bolt.Tx) error {
  1163. b, err := tx.CreateBucket([]byte("people"))
  1164. if err != nil {
  1165. return err
  1166. }
  1167. if err := b.Put([]byte("john"), []byte("doe")); err != nil {
  1168. return err
  1169. }
  1170. if err := b.Put([]byte("susy"), []byte("que")); err != nil {
  1171. return err
  1172. }
  1173. return nil
  1174. }); err != nil {
  1175. log.Fatal(err)
  1176. }
  1177. // Access data from within a read-only transactional block.
  1178. if err := db.View(func(tx *bolt.Tx) error {
  1179. v := tx.Bucket([]byte("people")).Get([]byte("john"))
  1180. fmt.Printf("John's last name is %s.\n", v)
  1181. return nil
  1182. }); err != nil {
  1183. log.Fatal(err)
  1184. }
  1185. // Close database to release the file lock.
  1186. if err := db.Close(); err != nil {
  1187. log.Fatal(err)
  1188. }
  1189. // Output:
  1190. // John's last name is doe.
  1191. }
  1192. func ExampleDB_Begin_ReadOnly() {
  1193. // Open the database.
  1194. db, err := bolt.Open(tempfile(), 0666, nil)
  1195. if err != nil {
  1196. log.Fatal(err)
  1197. }
  1198. defer os.Remove(db.Path())
  1199. // Create a bucket using a read-write transaction.
  1200. if err = db.Update(func(tx *bolt.Tx) error {
  1201. _, err := tx.CreateBucket([]byte("widgets"))
  1202. return err
  1203. }); err != nil {
  1204. log.Fatal(err)
  1205. }
  1206. // Create several keys in a transaction.
  1207. tx, err := db.Begin(true)
  1208. if err != nil {
  1209. log.Fatal(err)
  1210. }
  1211. b := tx.Bucket([]byte("widgets"))
  1212. if err = b.Put([]byte("john"), []byte("blue")); err != nil {
  1213. log.Fatal(err)
  1214. }
  1215. if err = b.Put([]byte("abby"), []byte("red")); err != nil {
  1216. log.Fatal(err)
  1217. }
  1218. if err = b.Put([]byte("zephyr"), []byte("purple")); err != nil {
  1219. log.Fatal(err)
  1220. }
  1221. if err = tx.Commit(); err != nil {
  1222. log.Fatal(err)
  1223. }
  1224. // Iterate over the values in sorted key order.
  1225. tx, err = db.Begin(false)
  1226. if err != nil {
  1227. log.Fatal(err)
  1228. }
  1229. c := tx.Bucket([]byte("widgets")).Cursor()
  1230. for k, v := c.First(); k != nil; k, v = c.Next() {
  1231. fmt.Printf("%s likes %s\n", k, v)
  1232. }
  1233. if err = tx.Rollback(); err != nil {
  1234. log.Fatal(err)
  1235. }
  1236. if err = db.Close(); err != nil {
  1237. log.Fatal(err)
  1238. }
  1239. // Output:
  1240. // abby likes red
  1241. // john likes blue
  1242. // zephyr likes purple
  1243. }
  1244. func BenchmarkDBBatchAutomatic(b *testing.B) {
  1245. db := MustOpenDB()
  1246. defer db.MustClose()
  1247. if err := db.Update(func(tx *bolt.Tx) error {
  1248. _, err := tx.CreateBucket([]byte("bench"))
  1249. return err
  1250. }); err != nil {
  1251. b.Fatal(err)
  1252. }
  1253. b.ResetTimer()
  1254. for i := 0; i < b.N; i++ {
  1255. start := make(chan struct{})
  1256. var wg sync.WaitGroup
  1257. for round := 0; round < 1000; round++ {
  1258. wg.Add(1)
  1259. go func(id uint32) {
  1260. defer wg.Done()
  1261. <-start
  1262. h := fnv.New32a()
  1263. buf := make([]byte, 4)
  1264. binary.LittleEndian.PutUint32(buf, id)
  1265. _, _ = h.Write(buf[:])
  1266. k := h.Sum(nil)
  1267. insert := func(tx *bolt.Tx) error {
  1268. b := tx.Bucket([]byte("bench"))
  1269. return b.Put(k, []byte("filler"))
  1270. }
  1271. if err := db.Batch(insert); err != nil {
  1272. b.Error(err)
  1273. return
  1274. }
  1275. }(uint32(round))
  1276. }
  1277. close(start)
  1278. wg.Wait()
  1279. }
  1280. b.StopTimer()
  1281. validateBatchBench(b, db)
  1282. }
  1283. func BenchmarkDBBatchSingle(b *testing.B) {
  1284. db := MustOpenDB()
  1285. defer db.MustClose()
  1286. if err := db.Update(func(tx *bolt.Tx) error {
  1287. _, err := tx.CreateBucket([]byte("bench"))
  1288. return err
  1289. }); err != nil {
  1290. b.Fatal(err)
  1291. }
  1292. b.ResetTimer()
  1293. for i := 0; i < b.N; i++ {
  1294. start := make(chan struct{})
  1295. var wg sync.WaitGroup
  1296. for round := 0; round < 1000; round++ {
  1297. wg.Add(1)
  1298. go func(id uint32) {
  1299. defer wg.Done()
  1300. <-start
  1301. h := fnv.New32a()
  1302. buf := make([]byte, 4)
  1303. binary.LittleEndian.PutUint32(buf, id)
  1304. _, _ = h.Write(buf[:])
  1305. k := h.Sum(nil)
  1306. insert := func(tx *bolt.Tx) error {
  1307. b := tx.Bucket([]byte("bench"))
  1308. return b.Put(k, []byte("filler"))
  1309. }
  1310. if err := db.Update(insert); err != nil {
  1311. b.Error(err)
  1312. return
  1313. }
  1314. }(uint32(round))
  1315. }
  1316. close(start)
  1317. wg.Wait()
  1318. }
  1319. b.StopTimer()
  1320. validateBatchBench(b, db)
  1321. }
  1322. func BenchmarkDBBatchManual10x100(b *testing.B) {
  1323. db := MustOpenDB()
  1324. defer db.MustClose()
  1325. if err := db.Update(func(tx *bolt.Tx) error {
  1326. _, err := tx.CreateBucket([]byte("bench"))
  1327. return err
  1328. }); err != nil {
  1329. b.Fatal(err)
  1330. }
  1331. b.ResetTimer()
  1332. for i := 0; i < b.N; i++ {
  1333. start := make(chan struct{})
  1334. var wg sync.WaitGroup
  1335. for major := 0; major < 10; major++ {
  1336. wg.Add(1)
  1337. go func(id uint32) {
  1338. defer wg.Done()
  1339. <-start
  1340. insert100 := func(tx *bolt.Tx) error {
  1341. h := fnv.New32a()
  1342. buf := make([]byte, 4)
  1343. for minor := uint32(0); minor < 100; minor++ {
  1344. binary.LittleEndian.PutUint32(buf, uint32(id*100+minor))
  1345. h.Reset()
  1346. _, _ = h.Write(buf[:])
  1347. k := h.Sum(nil)
  1348. b := tx.Bucket([]byte("bench"))
  1349. if err := b.Put(k, []byte("filler")); err != nil {
  1350. return err
  1351. }
  1352. }
  1353. return nil
  1354. }
  1355. if err := db.Update(insert100); err != nil {
  1356. b.Fatal(err)
  1357. }
  1358. }(uint32(major))
  1359. }
  1360. close(start)
  1361. wg.Wait()
  1362. }
  1363. b.StopTimer()
  1364. validateBatchBench(b, db)
  1365. }
  1366. func validateBatchBench(b *testing.B, db *DB) {
  1367. var rollback = errors.New("sentinel error to cause rollback")
  1368. validate := func(tx *bolt.Tx) error {
  1369. bucket := tx.Bucket([]byte("bench"))
  1370. h := fnv.New32a()
  1371. buf := make([]byte, 4)
  1372. for id := uint32(0); id < 1000; id++ {
  1373. binary.LittleEndian.PutUint32(buf, id)
  1374. h.Reset()
  1375. _, _ = h.Write(buf[:])
  1376. k := h.Sum(nil)
  1377. v := bucket.Get(k)
  1378. if v == nil {
  1379. b.Errorf("not found id=%d key=%x", id, k)
  1380. continue
  1381. }
  1382. if g, e := v, []byte("filler"); !bytes.Equal(g, e) {
  1383. b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e)
  1384. }
  1385. if err := bucket.Delete(k); err != nil {
  1386. return err
  1387. }
  1388. }
  1389. // should be empty now
  1390. c := bucket.Cursor()
  1391. for k, v := c.First(); k != nil; k, v = c.Next() {
  1392. b.Errorf("unexpected key: %x = %q", k, v)
  1393. }
  1394. return rollback
  1395. }
  1396. if err := db.Update(validate); err != nil && err != rollback {
  1397. b.Error(err)
  1398. }
  1399. }
  1400. // DB is a test wrapper for bolt.DB.
  1401. type DB struct {
  1402. *bolt.DB
  1403. f string
  1404. o *bolt.Options
  1405. }
  1406. // MustOpenDB returns a new, open DB at a temporary location.
  1407. func MustOpenDB() *DB {
  1408. return MustOpenWithOption(nil)
  1409. }
  1410. // MustOpenDBWithOption returns a new, open DB at a temporary location with given options.
  1411. func MustOpenWithOption(o *bolt.Options) *DB {
  1412. f := tempfile()
  1413. db, err := bolt.Open(f, 0666, o)
  1414. if err != nil {
  1415. panic(err)
  1416. }
  1417. return &DB{
  1418. DB: db,
  1419. f: f,
  1420. o: o,
  1421. }
  1422. }
  1423. // Close closes the database and deletes the underlying file.
  1424. func (db *DB) Close() error {
  1425. // Log statistics.
  1426. if *statsFlag {
  1427. db.PrintStats()
  1428. }
  1429. // Check database consistency after every test.
  1430. db.MustCheck()
  1431. // Close database and remove file.
  1432. defer os.Remove(db.Path())
  1433. return db.DB.Close()
  1434. }
  1435. // MustClose closes the database and deletes the underlying file. Panic on error.
  1436. func (db *DB) MustClose() {
  1437. if err := db.Close(); err != nil {
  1438. panic(err)
  1439. }
  1440. }
  1441. // MustReopen reopen the database. Panic on error.
  1442. func (db *DB) MustReopen() {
  1443. indb, err := bolt.Open(db.f, 0666, db.o)
  1444. if err != nil {
  1445. panic(err)
  1446. }
  1447. db.DB = indb
  1448. }
  1449. // PrintStats prints the database stats
  1450. func (db *DB) PrintStats() {
  1451. var stats = db.Stats()
  1452. fmt.Printf("[db] %-20s %-20s %-20s\n",
  1453. fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc),
  1454. fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount),
  1455. fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref),
  1456. )
  1457. fmt.Printf(" %-20s %-20s %-20s\n",
  1458. fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)),
  1459. fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)),
  1460. fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)),
  1461. )
  1462. }
  1463. // MustCheck runs a consistency check on the database and panics if any errors are found.
  1464. func (db *DB) MustCheck() {
  1465. if err := db.Update(func(tx *bolt.Tx) error {
  1466. // Collect all the errors.
  1467. var errors []error
  1468. for err := range tx.Check() {
  1469. errors = append(errors, err)
  1470. if len(errors) > 10 {
  1471. break
  1472. }
  1473. }
  1474. // If errors occurred, copy the DB and print the errors.
  1475. if len(errors) > 0 {
  1476. var path = tempfile()
  1477. if err := tx.CopyFile(path, 0600); err != nil {
  1478. panic(err)
  1479. }
  1480. // Print errors.
  1481. fmt.Print("\n\n")
  1482. fmt.Printf("consistency check failed (%d errors)\n", len(errors))
  1483. for _, err := range errors {
  1484. fmt.Println(err)
  1485. }
  1486. fmt.Println("")
  1487. fmt.Println("db saved to:")
  1488. fmt.Println(path)
  1489. fmt.Print("\n\n")
  1490. os.Exit(-1)
  1491. }
  1492. return nil
  1493. }); err != nil && err != bolt.ErrDatabaseNotOpen {
  1494. panic(err)
  1495. }
  1496. }
  1497. // CopyTempFile copies a database to a temporary file.
  1498. func (db *DB) CopyTempFile() {
  1499. path := tempfile()
  1500. if err := db.View(func(tx *bolt.Tx) error {
  1501. return tx.CopyFile(path, 0600)
  1502. }); err != nil {
  1503. panic(err)
  1504. }
  1505. fmt.Println("db copied to: ", path)
  1506. }
  1507. // tempfile returns a temporary file path.
  1508. func tempfile() string {
  1509. f, err := ioutil.TempFile("", "bolt-")
  1510. if err != nil {
  1511. panic(err)
  1512. }
  1513. if err := f.Close(); err != nil {
  1514. panic(err)
  1515. }
  1516. if err := os.Remove(f.Name()); err != nil {
  1517. panic(err)
  1518. }
  1519. return f.Name()
  1520. }
  1521. func trunc(b []byte, length int) []byte {
  1522. if length < len(b) {
  1523. return b[:length]
  1524. }
  1525. return b
  1526. }
  1527. func truncDuration(d time.Duration) string {
  1528. return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
  1529. }
  1530. func fileSize(path string) int64 {
  1531. fi, err := os.Stat(path)
  1532. if err != nil {
  1533. return 0
  1534. }
  1535. return fi.Size()
  1536. }
  1537. // u64tob converts a uint64 into an 8-byte slice.
  1538. func u64tob(v uint64) []byte {
  1539. b := make([]byte, 8)
  1540. binary.BigEndian.PutUint64(b, v)
  1541. return b
  1542. }