mirror of https://github.com/etcd-io/bbolt.git
Merge pull request #783 from ahrtr/refactor_freelist_20240701
Move method freePages into freelist.gopull/775/head
commit
d537eff505
35
db.go
35
db.go
|
@ -6,7 +6,6 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
@ -797,6 +796,9 @@ func (db *DB) beginTx() (*Tx, error) {
|
|||
// Keep track of transaction until it closes.
|
||||
db.txs = append(db.txs, t)
|
||||
n := len(db.txs)
|
||||
if db.freelist != nil {
|
||||
db.freelist.addReadonlyTXID(t.meta.Txid())
|
||||
}
|
||||
|
||||
// Unlock the meta pages.
|
||||
db.metalock.Unlock()
|
||||
|
@ -841,36 +843,10 @@ func (db *DB) beginRWTx() (*Tx, error) {
|
|||
t := &Tx{writable: true}
|
||||
t.init(db)
|
||||
db.rwtx = t
|
||||
db.freePages()
|
||||
db.freelist.freePages()
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// freePages releases any pages associated with closed read-only transactions.
|
||||
func (db *DB) freePages() {
|
||||
// Free all pending pages prior to earliest open transaction.
|
||||
sort.Sort(txsById(db.txs))
|
||||
minid := common.Txid(0xFFFFFFFFFFFFFFFF)
|
||||
if len(db.txs) > 0 {
|
||||
minid = db.txs[0].meta.Txid()
|
||||
}
|
||||
if minid > 0 {
|
||||
db.freelist.release(minid - 1)
|
||||
}
|
||||
// Release unused txid extents.
|
||||
for _, t := range db.txs {
|
||||
db.freelist.releaseRange(minid, t.meta.Txid()-1)
|
||||
minid = t.meta.Txid() + 1
|
||||
}
|
||||
db.freelist.releaseRange(minid, common.Txid(0xFFFFFFFFFFFFFFFF))
|
||||
// Any page both allocated and freed in an extent is safe to release.
|
||||
}
|
||||
|
||||
type txsById []*Tx
|
||||
|
||||
func (t txsById) Len() int { return len(t) }
|
||||
func (t txsById) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t txsById) Less(i, j int) bool { return t[i].meta.Txid() < t[j].meta.Txid() }
|
||||
|
||||
// removeTx removes a transaction from the database.
|
||||
func (db *DB) removeTx(tx *Tx) {
|
||||
// Release the read lock on the mmap.
|
||||
|
@ -890,6 +866,9 @@ func (db *DB) removeTx(tx *Tx) {
|
|||
}
|
||||
}
|
||||
n := len(db.txs)
|
||||
if db.freelist != nil {
|
||||
db.freelist.removeReadonlyTXID(tx.meta.Txid())
|
||||
}
|
||||
|
||||
// Unlock the meta pages.
|
||||
db.metalock.Unlock()
|
||||
|
|
43
freelist.go
43
freelist.go
|
@ -2,6 +2,7 @@ package bbolt
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
|
@ -24,6 +25,7 @@ type pidSet map[common.Pgid]struct{}
|
|||
type freelist struct {
|
||||
freelistType FreelistType // freelist type
|
||||
ids []common.Pgid // all free and available free page ids.
|
||||
readonlyTXIDs []common.Txid // all readonly transaction IDs.
|
||||
allocs map[common.Pgid]common.Txid // mapping of Txid that allocated a pgid.
|
||||
pending map[common.Txid]*txPending // mapping of soon-to-be free page ids by tx.
|
||||
cache map[common.Pgid]struct{} // fast lookup of all free and pending page ids.
|
||||
|
@ -326,3 +328,44 @@ func (f *freelist) reindex() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *freelist) addReadonlyTXID(tid common.Txid) {
|
||||
f.readonlyTXIDs = append(f.readonlyTXIDs, tid)
|
||||
}
|
||||
|
||||
func (f *freelist) removeReadonlyTXID(tid common.Txid) {
|
||||
for i := range f.readonlyTXIDs {
|
||||
if f.readonlyTXIDs[i] == tid {
|
||||
last := len(f.readonlyTXIDs) - 1
|
||||
f.readonlyTXIDs[i] = f.readonlyTXIDs[last]
|
||||
f.readonlyTXIDs = f.readonlyTXIDs[:last]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type txIDx []common.Txid
|
||||
|
||||
func (t txIDx) Len() int { return len(t) }
|
||||
func (t txIDx) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t txIDx) Less(i, j int) bool { return t[i] < t[j] }
|
||||
|
||||
// freePages releases any pages associated with closed read-only transactions.
|
||||
func (f *freelist) freePages() {
|
||||
// Free all pending pages prior to the earliest open transaction.
|
||||
sort.Sort(txIDx(f.readonlyTXIDs))
|
||||
minid := common.Txid(math.MaxUint64)
|
||||
if len(f.readonlyTXIDs) > 0 {
|
||||
minid = f.readonlyTXIDs[0]
|
||||
}
|
||||
if minid > 0 {
|
||||
f.release(minid - 1)
|
||||
}
|
||||
// Release unused txid extents.
|
||||
for _, tid := range f.readonlyTXIDs {
|
||||
f.releaseRange(minid, tid-1)
|
||||
minid = tid + 1
|
||||
}
|
||||
f.releaseRange(minid, common.Txid(math.MaxUint64))
|
||||
// Any page both allocated and freed in an extent is safe to release.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue