114 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
package nodb
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/lunny/nodb/store"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	ErrNestTx = errors.New("nest transaction not supported")
 | 
						|
	ErrTxDone = errors.New("Transaction has already been committed or rolled back")
 | 
						|
)
 | 
						|
 | 
						|
type Tx struct {
 | 
						|
	*DB
 | 
						|
 | 
						|
	tx *store.Tx
 | 
						|
 | 
						|
	logs [][]byte
 | 
						|
}
 | 
						|
 | 
						|
func (db *DB) IsTransaction() bool {
 | 
						|
	return db.status == DBInTransaction
 | 
						|
}
 | 
						|
 | 
						|
// Begin a transaction, it will block all other write operations before calling Commit or Rollback.
 | 
						|
// You must be very careful to prevent long-time transaction.
 | 
						|
func (db *DB) Begin() (*Tx, error) {
 | 
						|
	if db.IsTransaction() {
 | 
						|
		return nil, ErrNestTx
 | 
						|
	}
 | 
						|
 | 
						|
	tx := new(Tx)
 | 
						|
 | 
						|
	tx.DB = new(DB)
 | 
						|
	tx.DB.l = db.l
 | 
						|
 | 
						|
	tx.l.wLock.Lock()
 | 
						|
 | 
						|
	tx.DB.sdb = db.sdb
 | 
						|
 | 
						|
	var err error
 | 
						|
	tx.tx, err = db.sdb.Begin()
 | 
						|
	if err != nil {
 | 
						|
		tx.l.wLock.Unlock()
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	tx.DB.bucket = tx.tx
 | 
						|
 | 
						|
	tx.DB.status = DBInTransaction
 | 
						|
 | 
						|
	tx.DB.index = db.index
 | 
						|
 | 
						|
	tx.DB.kvBatch = tx.newBatch()
 | 
						|
	tx.DB.listBatch = tx.newBatch()
 | 
						|
	tx.DB.hashBatch = tx.newBatch()
 | 
						|
	tx.DB.zsetBatch = tx.newBatch()
 | 
						|
	tx.DB.binBatch = tx.newBatch()
 | 
						|
	tx.DB.setBatch = tx.newBatch()
 | 
						|
 | 
						|
	return tx, nil
 | 
						|
}
 | 
						|
 | 
						|
func (tx *Tx) Commit() error {
 | 
						|
	if tx.tx == nil {
 | 
						|
		return ErrTxDone
 | 
						|
	}
 | 
						|
 | 
						|
	tx.l.commitLock.Lock()
 | 
						|
	err := tx.tx.Commit()
 | 
						|
	tx.tx = nil
 | 
						|
 | 
						|
	if len(tx.logs) > 0 {
 | 
						|
		tx.l.binlog.Log(tx.logs...)
 | 
						|
	}
 | 
						|
 | 
						|
	tx.l.commitLock.Unlock()
 | 
						|
 | 
						|
	tx.l.wLock.Unlock()
 | 
						|
 | 
						|
	tx.DB.bucket = nil
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (tx *Tx) Rollback() error {
 | 
						|
	if tx.tx == nil {
 | 
						|
		return ErrTxDone
 | 
						|
	}
 | 
						|
 | 
						|
	err := tx.tx.Rollback()
 | 
						|
	tx.tx = nil
 | 
						|
 | 
						|
	tx.l.wLock.Unlock()
 | 
						|
	tx.DB.bucket = nil
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (tx *Tx) newBatch() *batch {
 | 
						|
	return tx.l.newBatch(tx.tx.NewWriteBatch(), &txBatchLocker{}, tx)
 | 
						|
}
 | 
						|
 | 
						|
func (tx *Tx) Select(index int) error {
 | 
						|
	if index < 0 || index >= int(MaxDBNumber) {
 | 
						|
		return fmt.Errorf("invalid db index %d", index)
 | 
						|
	}
 | 
						|
 | 
						|
	tx.DB.index = uint8(index)
 | 
						|
	return nil
 | 
						|
}
 |