第五节 Rollback()实现

Rollback()中,主要对不同事务进行不同操作:

  1. 如果当前事务是只读事务,则只需要从db中的txs中找到当前事务,然后移除掉即可。
  2. 如果当前事务是读写事务,则需要将空闲列表中和该事务关联的页释放掉,同时重新从freelist中加载空闲页。
  1. // Rollback closes the transaction and ignores all previous updates. Read-only
  2. // transactions must be rolled back and not committed.
  3. func (tx *Tx) Rollback() error {
  4. _assert(!tx.managed, "managed tx rollback not allowed")
  5. if tx.db == nil {
  6. return ErrTxClosed
  7. }
  8. tx.rollback()
  9. return nil
  10. }
  11. func (tx *Tx) rollback() {
  12. if tx.db == nil {
  13. return
  14. }
  15. if tx.writable {
  16. // 移除该事务关联的pages
  17. tx.db.freelist.rollback(tx.meta.txid)
  18. // 重新从freelist页中读取构建空闲列表
  19. tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist))
  20. }
  21. tx.close()
  22. }
  23. func (tx *Tx) close() {
  24. if tx.db == nil {
  25. return
  26. }
  27. if tx.writable {
  28. // Grab freelist stats.
  29. var freelistFreeN = tx.db.freelist.free_count()
  30. var freelistPendingN = tx.db.freelist.pending_count()
  31. var freelistAlloc = tx.db.freelist.size()
  32. // Remove transaction ref & writer lock.
  33. tx.db.rwtx = nil
  34. tx.db.rwlock.Unlock()
  35. // Merge statistics.
  36. tx.db.statlock.Lock()
  37. tx.db.stats.FreePageN = freelistFreeN
  38. tx.db.stats.PendingPageN = freelistPendingN
  39. tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize
  40. tx.db.stats.FreelistInuse = freelistAlloc
  41. tx.db.stats.TxStats.add(&tx.stats)
  42. tx.db.statlock.Unlock()
  43. } else {
  44. // 只读事务
  45. tx.db.removeTx(tx)
  46. }
  47. // Clear all references.
  48. tx.db = nil
  49. tx.meta = nil
  50. tx.root = Bucket{tx: tx}
  51. tx.pages = nil
  52. }
  53. // removeTx removes a transaction from the database.
  54. func (db *DB) removeTx(tx *Tx) {
  55. // Release the read lock on the mmap.
  56. db.mmaplock.RUnlock()
  57. // Use the meta lock to restrict access to the DB object.
  58. db.metalock.Lock()
  59. // Remove the transaction.
  60. for i, t := range db.txs {
  61. if t == tx {
  62. last := len(db.txs) - 1
  63. db.txs[i] = db.txs[last]
  64. db.txs[last] = nil
  65. db.txs = db.txs[:last]
  66. break
  67. }
  68. }
  69. n := len(db.txs)
  70. // Unlock the meta pages.
  71. db.metalock.Unlock()
  72. // Merge statistics.
  73. db.statlock.Lock()
  74. db.stats.OpenTxN = n
  75. db.stats.TxStats.add(&tx.stats)
  76. db.statlock.Unlock()
  77. }