You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
1.8 KiB

  1. package nodb
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/lunny/nodb/store"
  6. )
  7. var (
  8. ErrNestTx = errors.New("nest transaction not supported")
  9. ErrTxDone = errors.New("Transaction has already been committed or rolled back")
  10. )
  11. type Tx struct {
  12. *DB
  13. tx *store.Tx
  14. logs [][]byte
  15. }
  16. func (db *DB) IsTransaction() bool {
  17. return db.status == DBInTransaction
  18. }
  19. // Begin a transaction, it will block all other write operations before calling Commit or Rollback.
  20. // You must be very careful to prevent long-time transaction.
  21. func (db *DB) Begin() (*Tx, error) {
  22. if db.IsTransaction() {
  23. return nil, ErrNestTx
  24. }
  25. tx := new(Tx)
  26. tx.DB = new(DB)
  27. tx.DB.l = db.l
  28. tx.l.wLock.Lock()
  29. tx.DB.sdb = db.sdb
  30. var err error
  31. tx.tx, err = db.sdb.Begin()
  32. if err != nil {
  33. tx.l.wLock.Unlock()
  34. return nil, err
  35. }
  36. tx.DB.bucket = tx.tx
  37. tx.DB.status = DBInTransaction
  38. tx.DB.index = db.index
  39. tx.DB.kvBatch = tx.newBatch()
  40. tx.DB.listBatch = tx.newBatch()
  41. tx.DB.hashBatch = tx.newBatch()
  42. tx.DB.zsetBatch = tx.newBatch()
  43. tx.DB.binBatch = tx.newBatch()
  44. tx.DB.setBatch = tx.newBatch()
  45. return tx, nil
  46. }
  47. func (tx *Tx) Commit() error {
  48. if tx.tx == nil {
  49. return ErrTxDone
  50. }
  51. tx.l.commitLock.Lock()
  52. err := tx.tx.Commit()
  53. tx.tx = nil
  54. if len(tx.logs) > 0 {
  55. tx.l.binlog.Log(tx.logs...)
  56. }
  57. tx.l.commitLock.Unlock()
  58. tx.l.wLock.Unlock()
  59. tx.DB.bucket = nil
  60. return err
  61. }
  62. func (tx *Tx) Rollback() error {
  63. if tx.tx == nil {
  64. return ErrTxDone
  65. }
  66. err := tx.tx.Rollback()
  67. tx.tx = nil
  68. tx.l.wLock.Unlock()
  69. tx.DB.bucket = nil
  70. return err
  71. }
  72. func (tx *Tx) newBatch() *batch {
  73. return tx.l.newBatch(tx.tx.NewWriteBatch(), &txBatchLocker{}, tx)
  74. }
  75. func (tx *Tx) Select(index int) error {
  76. if index < 0 || index >= int(MaxDBNumber) {
  77. return fmt.Errorf("invalid db index %d", index)
  78. }
  79. tx.DB.index = uint8(index)
  80. return nil
  81. }