Skip to content

Commit d537eff

Browse files
authored
Merge pull request #783 from ahrtr/refactor_freelist_20240701
Move method freePages into freelist.go
2 parents cc78a5a + 263e75d commit d537eff

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

db.go

+7-28
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"io"
77
"os"
88
"runtime"
9-
"sort"
109
"sync"
1110
"time"
1211
"unsafe"
@@ -797,6 +796,9 @@ func (db *DB) beginTx() (*Tx, error) {
797796
// Keep track of transaction until it closes.
798797
db.txs = append(db.txs, t)
799798
n := len(db.txs)
799+
if db.freelist != nil {
800+
db.freelist.addReadonlyTXID(t.meta.Txid())
801+
}
800802

801803
// Unlock the meta pages.
802804
db.metalock.Unlock()
@@ -841,36 +843,10 @@ func (db *DB) beginRWTx() (*Tx, error) {
841843
t := &Tx{writable: true}
842844
t.init(db)
843845
db.rwtx = t
844-
db.freePages()
846+
db.freelist.freePages()
845847
return t, nil
846848
}
847849

848-
// freePages releases any pages associated with closed read-only transactions.
849-
func (db *DB) freePages() {
850-
// Free all pending pages prior to earliest open transaction.
851-
sort.Sort(txsById(db.txs))
852-
minid := common.Txid(0xFFFFFFFFFFFFFFFF)
853-
if len(db.txs) > 0 {
854-
minid = db.txs[0].meta.Txid()
855-
}
856-
if minid > 0 {
857-
db.freelist.release(minid - 1)
858-
}
859-
// Release unused txid extents.
860-
for _, t := range db.txs {
861-
db.freelist.releaseRange(minid, t.meta.Txid()-1)
862-
minid = t.meta.Txid() + 1
863-
}
864-
db.freelist.releaseRange(minid, common.Txid(0xFFFFFFFFFFFFFFFF))
865-
// Any page both allocated and freed in an extent is safe to release.
866-
}
867-
868-
type txsById []*Tx
869-
870-
func (t txsById) Len() int { return len(t) }
871-
func (t txsById) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
872-
func (t txsById) Less(i, j int) bool { return t[i].meta.Txid() < t[j].meta.Txid() }
873-
874850
// removeTx removes a transaction from the database.
875851
func (db *DB) removeTx(tx *Tx) {
876852
// Release the read lock on the mmap.
@@ -890,6 +866,9 @@ func (db *DB) removeTx(tx *Tx) {
890866
}
891867
}
892868
n := len(db.txs)
869+
if db.freelist != nil {
870+
db.freelist.removeReadonlyTXID(tx.meta.Txid())
871+
}
893872

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

freelist.go

+43
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bbolt
22

33
import (
44
"fmt"
5+
"math"
56
"sort"
67
"unsafe"
78

@@ -24,6 +25,7 @@ type pidSet map[common.Pgid]struct{}
2425
type freelist struct {
2526
freelistType FreelistType // freelist type
2627
ids []common.Pgid // all free and available free page ids.
28+
readonlyTXIDs []common.Txid // all readonly transaction IDs.
2729
allocs map[common.Pgid]common.Txid // mapping of Txid that allocated a pgid.
2830
pending map[common.Txid]*txPending // mapping of soon-to-be free page ids by tx.
2931
cache map[common.Pgid]struct{} // fast lookup of all free and pending page ids.
@@ -326,3 +328,44 @@ func (f *freelist) reindex() {
326328
}
327329
}
328330
}
331+
332+
func (f *freelist) addReadonlyTXID(tid common.Txid) {
333+
f.readonlyTXIDs = append(f.readonlyTXIDs, tid)
334+
}
335+
336+
func (f *freelist) removeReadonlyTXID(tid common.Txid) {
337+
for i := range f.readonlyTXIDs {
338+
if f.readonlyTXIDs[i] == tid {
339+
last := len(f.readonlyTXIDs) - 1
340+
f.readonlyTXIDs[i] = f.readonlyTXIDs[last]
341+
f.readonlyTXIDs = f.readonlyTXIDs[:last]
342+
break
343+
}
344+
}
345+
}
346+
347+
type txIDx []common.Txid
348+
349+
func (t txIDx) Len() int { return len(t) }
350+
func (t txIDx) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
351+
func (t txIDx) Less(i, j int) bool { return t[i] < t[j] }
352+
353+
// freePages releases any pages associated with closed read-only transactions.
354+
func (f *freelist) freePages() {
355+
// Free all pending pages prior to the earliest open transaction.
356+
sort.Sort(txIDx(f.readonlyTXIDs))
357+
minid := common.Txid(math.MaxUint64)
358+
if len(f.readonlyTXIDs) > 0 {
359+
minid = f.readonlyTXIDs[0]
360+
}
361+
if minid > 0 {
362+
f.release(minid - 1)
363+
}
364+
// Release unused txid extents.
365+
for _, tid := range f.readonlyTXIDs {
366+
f.releaseRange(minid, tid-1)
367+
minid = tid + 1
368+
}
369+
f.releaseRange(minid, common.Txid(math.MaxUint64))
370+
// Any page both allocated and freed in an extent is safe to release.
371+
}

0 commit comments

Comments
 (0)