tx_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. package bbolt_test
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "os"
  8. "testing"
  9. bolt "go.etcd.io/bbolt"
  10. )
  11. // TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database.
  12. func TestTx_Check_ReadOnly(t *testing.T) {
  13. db := MustOpenDB()
  14. defer db.Close()
  15. if err := db.Update(func(tx *bolt.Tx) error {
  16. b, err := tx.CreateBucket([]byte("widgets"))
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  21. t.Fatal(err)
  22. }
  23. return nil
  24. }); err != nil {
  25. t.Fatal(err)
  26. }
  27. if err := db.DB.Close(); err != nil {
  28. t.Fatal(err)
  29. }
  30. readOnlyDB, err := bolt.Open(db.f, 0666, &bolt.Options{ReadOnly: true})
  31. if err != nil {
  32. t.Fatal(err)
  33. }
  34. defer readOnlyDB.Close()
  35. tx, err := readOnlyDB.Begin(false)
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. // ReadOnly DB will load freelist on Check call.
  40. numChecks := 2
  41. errc := make(chan error, numChecks)
  42. check := func() {
  43. err, _ := <-tx.Check()
  44. errc <- err
  45. }
  46. // Ensure the freelist is not reloaded and does not race.
  47. for i := 0; i < numChecks; i++ {
  48. go check()
  49. }
  50. for i := 0; i < numChecks; i++ {
  51. if err := <-errc; err != nil {
  52. t.Fatal(err)
  53. }
  54. }
  55. // Close the view transaction
  56. tx.Rollback()
  57. }
  58. // Ensure that committing a closed transaction returns an error.
  59. func TestTx_Commit_ErrTxClosed(t *testing.T) {
  60. db := MustOpenDB()
  61. defer db.MustClose()
  62. tx, err := db.Begin(true)
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. if _, err := tx.CreateBucket([]byte("foo")); err != nil {
  67. t.Fatal(err)
  68. }
  69. if err := tx.Commit(); err != nil {
  70. t.Fatal(err)
  71. }
  72. if err := tx.Commit(); err != bolt.ErrTxClosed {
  73. t.Fatalf("unexpected error: %s", err)
  74. }
  75. }
  76. // Ensure that rolling back a closed transaction returns an error.
  77. func TestTx_Rollback_ErrTxClosed(t *testing.T) {
  78. db := MustOpenDB()
  79. defer db.MustClose()
  80. tx, err := db.Begin(true)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if err := tx.Rollback(); err != nil {
  85. t.Fatal(err)
  86. }
  87. if err := tx.Rollback(); err != bolt.ErrTxClosed {
  88. t.Fatalf("unexpected error: %s", err)
  89. }
  90. }
  91. // Ensure that committing a read-only transaction returns an error.
  92. func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
  93. db := MustOpenDB()
  94. defer db.MustClose()
  95. tx, err := db.Begin(false)
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. if err := tx.Commit(); err != bolt.ErrTxNotWritable {
  100. t.Fatal(err)
  101. }
  102. // Close the view transaction
  103. tx.Rollback()
  104. }
  105. // Ensure that a transaction can retrieve a cursor on the root bucket.
  106. func TestTx_Cursor(t *testing.T) {
  107. db := MustOpenDB()
  108. defer db.MustClose()
  109. if err := db.Update(func(tx *bolt.Tx) error {
  110. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  111. t.Fatal(err)
  112. }
  113. if _, err := tx.CreateBucket([]byte("woojits")); err != nil {
  114. t.Fatal(err)
  115. }
  116. c := tx.Cursor()
  117. if k, v := c.First(); !bytes.Equal(k, []byte("widgets")) {
  118. t.Fatalf("unexpected key: %v", k)
  119. } else if v != nil {
  120. t.Fatalf("unexpected value: %v", v)
  121. }
  122. if k, v := c.Next(); !bytes.Equal(k, []byte("woojits")) {
  123. t.Fatalf("unexpected key: %v", k)
  124. } else if v != nil {
  125. t.Fatalf("unexpected value: %v", v)
  126. }
  127. if k, v := c.Next(); k != nil {
  128. t.Fatalf("unexpected key: %v", k)
  129. } else if v != nil {
  130. t.Fatalf("unexpected value: %v", k)
  131. }
  132. return nil
  133. }); err != nil {
  134. t.Fatal(err)
  135. }
  136. }
  137. // Ensure that creating a bucket with a read-only transaction returns an error.
  138. func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
  139. db := MustOpenDB()
  140. defer db.MustClose()
  141. if err := db.View(func(tx *bolt.Tx) error {
  142. _, err := tx.CreateBucket([]byte("foo"))
  143. if err != bolt.ErrTxNotWritable {
  144. t.Fatalf("unexpected error: %s", err)
  145. }
  146. return nil
  147. }); err != nil {
  148. t.Fatal(err)
  149. }
  150. }
  151. // Ensure that creating a bucket on a closed transaction returns an error.
  152. func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
  153. db := MustOpenDB()
  154. defer db.MustClose()
  155. tx, err := db.Begin(true)
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. if err := tx.Commit(); err != nil {
  160. t.Fatal(err)
  161. }
  162. if _, err := tx.CreateBucket([]byte("foo")); err != bolt.ErrTxClosed {
  163. t.Fatalf("unexpected error: %s", err)
  164. }
  165. }
  166. // Ensure that a Tx can retrieve a bucket.
  167. func TestTx_Bucket(t *testing.T) {
  168. db := MustOpenDB()
  169. defer db.MustClose()
  170. if err := db.Update(func(tx *bolt.Tx) error {
  171. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  172. t.Fatal(err)
  173. }
  174. if tx.Bucket([]byte("widgets")) == nil {
  175. t.Fatal("expected bucket")
  176. }
  177. return nil
  178. }); err != nil {
  179. t.Fatal(err)
  180. }
  181. }
  182. // Ensure that a Tx retrieving a non-existent key returns nil.
  183. func TestTx_Get_NotFound(t *testing.T) {
  184. db := MustOpenDB()
  185. defer db.MustClose()
  186. if err := db.Update(func(tx *bolt.Tx) error {
  187. b, err := tx.CreateBucket([]byte("widgets"))
  188. if err != nil {
  189. t.Fatal(err)
  190. }
  191. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  192. t.Fatal(err)
  193. }
  194. if b.Get([]byte("no_such_key")) != nil {
  195. t.Fatal("expected nil value")
  196. }
  197. return nil
  198. }); err != nil {
  199. t.Fatal(err)
  200. }
  201. }
  202. // Ensure that a bucket can be created and retrieved.
  203. func TestTx_CreateBucket(t *testing.T) {
  204. db := MustOpenDB()
  205. defer db.MustClose()
  206. // Create a bucket.
  207. if err := db.Update(func(tx *bolt.Tx) error {
  208. b, err := tx.CreateBucket([]byte("widgets"))
  209. if err != nil {
  210. t.Fatal(err)
  211. } else if b == nil {
  212. t.Fatal("expected bucket")
  213. }
  214. return nil
  215. }); err != nil {
  216. t.Fatal(err)
  217. }
  218. // Read the bucket through a separate transaction.
  219. if err := db.View(func(tx *bolt.Tx) error {
  220. if tx.Bucket([]byte("widgets")) == nil {
  221. t.Fatal("expected bucket")
  222. }
  223. return nil
  224. }); err != nil {
  225. t.Fatal(err)
  226. }
  227. }
  228. // Ensure that a bucket can be created if it doesn't already exist.
  229. func TestTx_CreateBucketIfNotExists(t *testing.T) {
  230. db := MustOpenDB()
  231. defer db.MustClose()
  232. if err := db.Update(func(tx *bolt.Tx) error {
  233. // Create bucket.
  234. if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil {
  235. t.Fatal(err)
  236. } else if b == nil {
  237. t.Fatal("expected bucket")
  238. }
  239. // Create bucket again.
  240. if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil {
  241. t.Fatal(err)
  242. } else if b == nil {
  243. t.Fatal("expected bucket")
  244. }
  245. return nil
  246. }); err != nil {
  247. t.Fatal(err)
  248. }
  249. // Read the bucket through a separate transaction.
  250. if err := db.View(func(tx *bolt.Tx) error {
  251. if tx.Bucket([]byte("widgets")) == nil {
  252. t.Fatal("expected bucket")
  253. }
  254. return nil
  255. }); err != nil {
  256. t.Fatal(err)
  257. }
  258. }
  259. // Ensure transaction returns an error if creating an unnamed bucket.
  260. func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
  261. db := MustOpenDB()
  262. defer db.MustClose()
  263. if err := db.Update(func(tx *bolt.Tx) error {
  264. if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired {
  265. t.Fatalf("unexpected error: %s", err)
  266. }
  267. if _, err := tx.CreateBucketIfNotExists(nil); err != bolt.ErrBucketNameRequired {
  268. t.Fatalf("unexpected error: %s", err)
  269. }
  270. return nil
  271. }); err != nil {
  272. t.Fatal(err)
  273. }
  274. }
  275. // Ensure that a bucket cannot be created twice.
  276. func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
  277. db := MustOpenDB()
  278. defer db.MustClose()
  279. // Create a bucket.
  280. if err := db.Update(func(tx *bolt.Tx) error {
  281. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  282. t.Fatal(err)
  283. }
  284. return nil
  285. }); err != nil {
  286. t.Fatal(err)
  287. }
  288. // Create the same bucket again.
  289. if err := db.Update(func(tx *bolt.Tx) error {
  290. if _, err := tx.CreateBucket([]byte("widgets")); err != bolt.ErrBucketExists {
  291. t.Fatalf("unexpected error: %s", err)
  292. }
  293. return nil
  294. }); err != nil {
  295. t.Fatal(err)
  296. }
  297. }
  298. // Ensure that a bucket is created with a non-blank name.
  299. func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
  300. db := MustOpenDB()
  301. defer db.MustClose()
  302. if err := db.Update(func(tx *bolt.Tx) error {
  303. if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired {
  304. t.Fatalf("unexpected error: %s", err)
  305. }
  306. return nil
  307. }); err != nil {
  308. t.Fatal(err)
  309. }
  310. }
  311. // Ensure that a bucket can be deleted.
  312. func TestTx_DeleteBucket(t *testing.T) {
  313. db := MustOpenDB()
  314. defer db.MustClose()
  315. // Create a bucket and add a value.
  316. if err := db.Update(func(tx *bolt.Tx) error {
  317. b, err := tx.CreateBucket([]byte("widgets"))
  318. if err != nil {
  319. t.Fatal(err)
  320. }
  321. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  322. t.Fatal(err)
  323. }
  324. return nil
  325. }); err != nil {
  326. t.Fatal(err)
  327. }
  328. // Delete the bucket and make sure we can't get the value.
  329. if err := db.Update(func(tx *bolt.Tx) error {
  330. if err := tx.DeleteBucket([]byte("widgets")); err != nil {
  331. t.Fatal(err)
  332. }
  333. if tx.Bucket([]byte("widgets")) != nil {
  334. t.Fatal("unexpected bucket")
  335. }
  336. return nil
  337. }); err != nil {
  338. t.Fatal(err)
  339. }
  340. if err := db.Update(func(tx *bolt.Tx) error {
  341. // Create the bucket again and make sure there's not a phantom value.
  342. b, err := tx.CreateBucket([]byte("widgets"))
  343. if err != nil {
  344. t.Fatal(err)
  345. }
  346. if v := b.Get([]byte("foo")); v != nil {
  347. t.Fatalf("unexpected phantom value: %v", v)
  348. }
  349. return nil
  350. }); err != nil {
  351. t.Fatal(err)
  352. }
  353. }
  354. // Ensure that deleting a bucket on a closed transaction returns an error.
  355. func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
  356. db := MustOpenDB()
  357. defer db.MustClose()
  358. tx, err := db.Begin(true)
  359. if err != nil {
  360. t.Fatal(err)
  361. }
  362. if err := tx.Commit(); err != nil {
  363. t.Fatal(err)
  364. }
  365. if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxClosed {
  366. t.Fatalf("unexpected error: %s", err)
  367. }
  368. }
  369. // Ensure that deleting a bucket with a read-only transaction returns an error.
  370. func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
  371. db := MustOpenDB()
  372. defer db.MustClose()
  373. if err := db.View(func(tx *bolt.Tx) error {
  374. if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable {
  375. t.Fatalf("unexpected error: %s", err)
  376. }
  377. return nil
  378. }); err != nil {
  379. t.Fatal(err)
  380. }
  381. }
  382. // Ensure that nothing happens when deleting a bucket that doesn't exist.
  383. func TestTx_DeleteBucket_NotFound(t *testing.T) {
  384. db := MustOpenDB()
  385. defer db.MustClose()
  386. if err := db.Update(func(tx *bolt.Tx) error {
  387. if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound {
  388. t.Fatalf("unexpected error: %s", err)
  389. }
  390. return nil
  391. }); err != nil {
  392. t.Fatal(err)
  393. }
  394. }
  395. // Ensure that no error is returned when a tx.ForEach function does not return
  396. // an error.
  397. func TestTx_ForEach_NoError(t *testing.T) {
  398. db := MustOpenDB()
  399. defer db.MustClose()
  400. if err := db.Update(func(tx *bolt.Tx) error {
  401. b, err := tx.CreateBucket([]byte("widgets"))
  402. if err != nil {
  403. t.Fatal(err)
  404. }
  405. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  406. t.Fatal(err)
  407. }
  408. if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
  409. return nil
  410. }); err != nil {
  411. t.Fatal(err)
  412. }
  413. return nil
  414. }); err != nil {
  415. t.Fatal(err)
  416. }
  417. }
  418. // Ensure that an error is returned when a tx.ForEach function returns an error.
  419. func TestTx_ForEach_WithError(t *testing.T) {
  420. db := MustOpenDB()
  421. defer db.MustClose()
  422. if err := db.Update(func(tx *bolt.Tx) error {
  423. b, err := tx.CreateBucket([]byte("widgets"))
  424. if err != nil {
  425. t.Fatal(err)
  426. }
  427. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  428. t.Fatal(err)
  429. }
  430. marker := errors.New("marker")
  431. if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error {
  432. return marker
  433. }); err != marker {
  434. t.Fatalf("unexpected error: %s", err)
  435. }
  436. return nil
  437. }); err != nil {
  438. t.Fatal(err)
  439. }
  440. }
  441. // Ensure that Tx commit handlers are called after a transaction successfully commits.
  442. func TestTx_OnCommit(t *testing.T) {
  443. db := MustOpenDB()
  444. defer db.MustClose()
  445. var x int
  446. if err := db.Update(func(tx *bolt.Tx) error {
  447. tx.OnCommit(func() { x += 1 })
  448. tx.OnCommit(func() { x += 2 })
  449. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  450. t.Fatal(err)
  451. }
  452. return nil
  453. }); err != nil {
  454. t.Fatal(err)
  455. } else if x != 3 {
  456. t.Fatalf("unexpected x: %d", x)
  457. }
  458. }
  459. // Ensure that Tx commit handlers are NOT called after a transaction rolls back.
  460. func TestTx_OnCommit_Rollback(t *testing.T) {
  461. db := MustOpenDB()
  462. defer db.MustClose()
  463. var x int
  464. if err := db.Update(func(tx *bolt.Tx) error {
  465. tx.OnCommit(func() { x += 1 })
  466. tx.OnCommit(func() { x += 2 })
  467. if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  468. t.Fatal(err)
  469. }
  470. return errors.New("rollback this commit")
  471. }); err == nil || err.Error() != "rollback this commit" {
  472. t.Fatalf("unexpected error: %s", err)
  473. } else if x != 0 {
  474. t.Fatalf("unexpected x: %d", x)
  475. }
  476. }
  477. // Ensure that the database can be copied to a file path.
  478. func TestTx_CopyFile(t *testing.T) {
  479. db := MustOpenDB()
  480. defer db.MustClose()
  481. path := tempfile()
  482. if err := db.Update(func(tx *bolt.Tx) error {
  483. b, err := tx.CreateBucket([]byte("widgets"))
  484. if err != nil {
  485. t.Fatal(err)
  486. }
  487. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  488. t.Fatal(err)
  489. }
  490. if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
  491. t.Fatal(err)
  492. }
  493. return nil
  494. }); err != nil {
  495. t.Fatal(err)
  496. }
  497. if err := db.View(func(tx *bolt.Tx) error {
  498. return tx.CopyFile(path, 0600)
  499. }); err != nil {
  500. t.Fatal(err)
  501. }
  502. db2, err := bolt.Open(path, 0600, nil)
  503. if err != nil {
  504. t.Fatal(err)
  505. }
  506. if err := db2.View(func(tx *bolt.Tx) error {
  507. if v := tx.Bucket([]byte("widgets")).Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) {
  508. t.Fatalf("unexpected value: %v", v)
  509. }
  510. if v := tx.Bucket([]byte("widgets")).Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
  511. t.Fatalf("unexpected value: %v", v)
  512. }
  513. return nil
  514. }); err != nil {
  515. t.Fatal(err)
  516. }
  517. if err := db2.Close(); err != nil {
  518. t.Fatal(err)
  519. }
  520. }
  521. type failWriterError struct{}
  522. func (failWriterError) Error() string {
  523. return "error injected for tests"
  524. }
  525. type failWriter struct {
  526. // fail after this many bytes
  527. After int
  528. }
  529. func (f *failWriter) Write(p []byte) (n int, err error) {
  530. n = len(p)
  531. if n > f.After {
  532. n = f.After
  533. err = failWriterError{}
  534. }
  535. f.After -= n
  536. return n, err
  537. }
  538. // Ensure that Copy handles write errors right.
  539. func TestTx_CopyFile_Error_Meta(t *testing.T) {
  540. db := MustOpenDB()
  541. defer db.MustClose()
  542. if err := db.Update(func(tx *bolt.Tx) error {
  543. b, err := tx.CreateBucket([]byte("widgets"))
  544. if err != nil {
  545. t.Fatal(err)
  546. }
  547. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  548. t.Fatal(err)
  549. }
  550. if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
  551. t.Fatal(err)
  552. }
  553. return nil
  554. }); err != nil {
  555. t.Fatal(err)
  556. }
  557. if err := db.View(func(tx *bolt.Tx) error {
  558. return tx.Copy(&failWriter{})
  559. }); err == nil || err.Error() != "meta 0 copy: error injected for tests" {
  560. t.Fatalf("unexpected error: %v", err)
  561. }
  562. }
  563. // Ensure that Copy handles write errors right.
  564. func TestTx_CopyFile_Error_Normal(t *testing.T) {
  565. db := MustOpenDB()
  566. defer db.MustClose()
  567. if err := db.Update(func(tx *bolt.Tx) error {
  568. b, err := tx.CreateBucket([]byte("widgets"))
  569. if err != nil {
  570. t.Fatal(err)
  571. }
  572. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  573. t.Fatal(err)
  574. }
  575. if err := b.Put([]byte("baz"), []byte("bat")); err != nil {
  576. t.Fatal(err)
  577. }
  578. return nil
  579. }); err != nil {
  580. t.Fatal(err)
  581. }
  582. if err := db.View(func(tx *bolt.Tx) error {
  583. return tx.Copy(&failWriter{3 * db.Info().PageSize})
  584. }); err == nil || err.Error() != "error injected for tests" {
  585. t.Fatalf("unexpected error: %v", err)
  586. }
  587. }
  588. // TestTx_releaseRange ensures db.freePages handles page releases
  589. // correctly when there are transaction that are no longer reachable
  590. // via any read/write transactions and are "between" ongoing read
  591. // transactions, which requires they must be freed by
  592. // freelist.releaseRange.
  593. func TestTx_releaseRange(t *testing.T) {
  594. // Set initial mmap size well beyond the limit we will hit in this
  595. // test, since we are testing with long running read transactions
  596. // and will deadlock if db.grow is triggered.
  597. db := MustOpenWithOption(&bolt.Options{InitialMmapSize: os.Getpagesize() * 100})
  598. defer db.MustClose()
  599. bucket := "bucket"
  600. put := func(key, value string) {
  601. if err := db.Update(func(tx *bolt.Tx) error {
  602. b, err := tx.CreateBucketIfNotExists([]byte(bucket))
  603. if err != nil {
  604. t.Fatal(err)
  605. }
  606. return b.Put([]byte(key), []byte(value))
  607. }); err != nil {
  608. t.Fatal(err)
  609. }
  610. }
  611. del := func(key string) {
  612. if err := db.Update(func(tx *bolt.Tx) error {
  613. b, err := tx.CreateBucketIfNotExists([]byte(bucket))
  614. if err != nil {
  615. t.Fatal(err)
  616. }
  617. return b.Delete([]byte(key))
  618. }); err != nil {
  619. t.Fatal(err)
  620. }
  621. }
  622. getWithTxn := func(txn *bolt.Tx, key string) []byte {
  623. return txn.Bucket([]byte(bucket)).Get([]byte(key))
  624. }
  625. openReadTxn := func() *bolt.Tx {
  626. readTx, err := db.Begin(false)
  627. if err != nil {
  628. t.Fatal(err)
  629. }
  630. return readTx
  631. }
  632. checkWithReadTxn := func(txn *bolt.Tx, key string, wantValue []byte) {
  633. value := getWithTxn(txn, key)
  634. if !bytes.Equal(value, wantValue) {
  635. t.Errorf("Wanted value to be %s for key %s, but got %s", wantValue, key, string(value))
  636. }
  637. }
  638. rollback := func(txn *bolt.Tx) {
  639. if err := txn.Rollback(); err != nil {
  640. t.Fatal(err)
  641. }
  642. }
  643. put("k1", "v1")
  644. rtx1 := openReadTxn()
  645. put("k2", "v2")
  646. hold1 := openReadTxn()
  647. put("k3", "v3")
  648. hold2 := openReadTxn()
  649. del("k3")
  650. rtx2 := openReadTxn()
  651. del("k1")
  652. hold3 := openReadTxn()
  653. del("k2")
  654. hold4 := openReadTxn()
  655. put("k4", "v4")
  656. hold5 := openReadTxn()
  657. // Close the read transactions we established to hold a portion of the pages in pending state.
  658. rollback(hold1)
  659. rollback(hold2)
  660. rollback(hold3)
  661. rollback(hold4)
  662. rollback(hold5)
  663. // Execute a write transaction to trigger a releaseRange operation in the db
  664. // that will free multiple ranges between the remaining open read transactions, now that the
  665. // holds have been rolled back.
  666. put("k4", "v4")
  667. // Check that all long running reads still read correct values.
  668. checkWithReadTxn(rtx1, "k1", []byte("v1"))
  669. checkWithReadTxn(rtx2, "k2", []byte("v2"))
  670. rollback(rtx1)
  671. rollback(rtx2)
  672. // Check that the final state is correct.
  673. rtx7 := openReadTxn()
  674. checkWithReadTxn(rtx7, "k1", nil)
  675. checkWithReadTxn(rtx7, "k2", nil)
  676. checkWithReadTxn(rtx7, "k3", nil)
  677. checkWithReadTxn(rtx7, "k4", []byte("v4"))
  678. rollback(rtx7)
  679. }
  680. func ExampleTx_Rollback() {
  681. // Open the database.
  682. db, err := bolt.Open(tempfile(), 0666, nil)
  683. if err != nil {
  684. log.Fatal(err)
  685. }
  686. defer os.Remove(db.Path())
  687. // Create a bucket.
  688. if err := db.Update(func(tx *bolt.Tx) error {
  689. _, err := tx.CreateBucket([]byte("widgets"))
  690. return err
  691. }); err != nil {
  692. log.Fatal(err)
  693. }
  694. // Set a value for a key.
  695. if err := db.Update(func(tx *bolt.Tx) error {
  696. return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
  697. }); err != nil {
  698. log.Fatal(err)
  699. }
  700. // Update the key but rollback the transaction so it never saves.
  701. tx, err := db.Begin(true)
  702. if err != nil {
  703. log.Fatal(err)
  704. }
  705. b := tx.Bucket([]byte("widgets"))
  706. if err := b.Put([]byte("foo"), []byte("baz")); err != nil {
  707. log.Fatal(err)
  708. }
  709. if err := tx.Rollback(); err != nil {
  710. log.Fatal(err)
  711. }
  712. // Ensure that our original value is still set.
  713. if err := db.View(func(tx *bolt.Tx) error {
  714. value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  715. fmt.Printf("The value for 'foo' is still: %s\n", value)
  716. return nil
  717. }); err != nil {
  718. log.Fatal(err)
  719. }
  720. // Close database to release file lock.
  721. if err := db.Close(); err != nil {
  722. log.Fatal(err)
  723. }
  724. // Output:
  725. // The value for 'foo' is still: bar
  726. }
  727. func ExampleTx_CopyFile() {
  728. // Open the database.
  729. db, err := bolt.Open(tempfile(), 0666, nil)
  730. if err != nil {
  731. log.Fatal(err)
  732. }
  733. defer os.Remove(db.Path())
  734. // Create a bucket and a key.
  735. if err := db.Update(func(tx *bolt.Tx) error {
  736. b, err := tx.CreateBucket([]byte("widgets"))
  737. if err != nil {
  738. return err
  739. }
  740. if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  741. return err
  742. }
  743. return nil
  744. }); err != nil {
  745. log.Fatal(err)
  746. }
  747. // Copy the database to another file.
  748. toFile := tempfile()
  749. if err := db.View(func(tx *bolt.Tx) error {
  750. return tx.CopyFile(toFile, 0666)
  751. }); err != nil {
  752. log.Fatal(err)
  753. }
  754. defer os.Remove(toFile)
  755. // Open the cloned database.
  756. db2, err := bolt.Open(toFile, 0666, nil)
  757. if err != nil {
  758. log.Fatal(err)
  759. }
  760. // Ensure that the key exists in the copy.
  761. if err := db2.View(func(tx *bolt.Tx) error {
  762. value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  763. fmt.Printf("The value for 'foo' in the clone is: %s\n", value)
  764. return nil
  765. }); err != nil {
  766. log.Fatal(err)
  767. }
  768. // Close database to release file lock.
  769. if err := db.Close(); err != nil {
  770. log.Fatal(err)
  771. }
  772. if err := db2.Close(); err != nil {
  773. log.Fatal(err)
  774. }
  775. // Output:
  776. // The value for 'foo' in the clone is: bar
  777. }