第五节 Rollback()实现

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

  1. 如果当前事务是只读事务,则只需要从db中的txs中找到当前事务,然后移除掉即可。
  2. 如果当前事务是读写事务,则需要将空闲列表中和该事务关联的页释放掉,同时重新从freelist中加载空闲页。
// Rollback closes the transaction and ignores all previous updates. Read-only
// transactions must be rolled back and not committed.
func (tx *Tx) Rollback() error {
    _assert(!tx.managed, "managed tx rollback not allowed")
    if tx.db == nil {
        return ErrTxClosed
    }
    tx.rollback()
    return nil
}

func (tx *Tx) rollback() {
    if tx.db == nil {
        return
    }
    if tx.writable {
        // 移除该事务关联的pages
        tx.db.freelist.rollback(tx.meta.txid)
        // 重新从freelist页中读取构建空闲列表
        tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist))
    }
    tx.close()
}

func (tx *Tx) close() {
    if tx.db == nil {
        return
    }
    if tx.writable {
        // Grab freelist stats.
        var freelistFreeN = tx.db.freelist.free_count()
        var freelistPendingN = tx.db.freelist.pending_count()
        var freelistAlloc = tx.db.freelist.size()

        // Remove transaction ref & writer lock.
        tx.db.rwtx = nil
        tx.db.rwlock.Unlock()

        // Merge statistics.
        tx.db.statlock.Lock()
        tx.db.stats.FreePageN = freelistFreeN
        tx.db.stats.PendingPageN = freelistPendingN
        tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize
        tx.db.stats.FreelistInuse = freelistAlloc
        tx.db.stats.TxStats.add(&tx.stats)
        tx.db.statlock.Unlock()
    } else {
        // 只读事务
        tx.db.removeTx(tx)
    }

    // Clear all references.
    tx.db = nil
    tx.meta = nil
    tx.root = Bucket{tx: tx}
    tx.pages = nil
}

// removeTx removes a transaction from the database.
func (db *DB) removeTx(tx *Tx) {
    // Release the read lock on the mmap.
    db.mmaplock.RUnlock()

    // Use the meta lock to restrict access to the DB object.
    db.metalock.Lock()

    // Remove the transaction.
    for i, t := range db.txs {
        if t == tx {
            last := len(db.txs) - 1
            db.txs[i] = db.txs[last]
            db.txs[last] = nil
            db.txs = db.txs[:last]
            break
        }
    }
    n := len(db.txs)

    // Unlock the meta pages.
    db.metalock.Unlock()

    // Merge statistics.
    db.statlock.Lock()
    db.stats.OpenTxN = n
    db.stats.TxStats.add(&tx.stats)
    db.statlock.Unlock()
}

results matching ""

    No results matching ""