Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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
113 lines
1.8 KiB
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 |
|
}
|
|
|