Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,14 @@ func (db *DB) Sync() error {
return y.CombineErrors(memtableSyncError, vLogSyncError)
}

// getMemtables returns the current memtables and get references.
func (db *DB) getMemTables() ([]*memTable, func()) {
// getMemTables returns the active set of memtables (mutable + immutables)
// with their refcounts already incremented. Callers MUST release the
// references by calling decrMemTables(tables) — typically via defer.
//
// The two-method shape (instead of returning a cleanup closure) avoids the
// per-call closure allocation that the previous API forced on every iterator
// construction and stream-writer setup.
func (db *DB) getMemTables() []*memTable {
db.lock.RLock()
defer db.lock.RUnlock()

Expand All @@ -730,10 +736,16 @@ func (db *DB) getMemTables() ([]*memTable, func()) {
tables = append(tables, db.imm[last-i])
db.imm[last-i].IncrRef()
}
return tables, func() {
for _, tbl := range tables {
tbl.DecrRef()
}
return tables
}

// decrMemTables releases the refcounts taken by getMemTables. Pair with
// `defer decrMemTables(tables)` after a getMemTables call. Free function
// (no receiver) so the deferred call record doesn't have to capture a
// *DB pointer alongside the slice header.
func decrMemTables(tables []*memTable) {
for _, tbl := range tables {
tbl.DecrRef()
}
}

Expand All @@ -755,8 +767,8 @@ func (db *DB) get(key []byte) (y.ValueStruct, error) {
if db.IsClosed() {
return y.ValueStruct{}, ErrDBClosed
}
tables, decr := db.getMemTables() // Lock should be released.
defer decr()
tables := db.getMemTables() // Lock should be released.
defer decrMemTables(tables)

var maxVs y.ValueStruct
version := y.ParseTs(key)
Expand Down
4 changes: 2 additions & 2 deletions iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ func (txn *Txn) NewIterator(opt IteratorOptions) *Iterator {
txn.numIterators.Add(1)

// TODO: If Prefix is set, only pick those memtables which have keys with the prefix.
tables, decr := txn.db.getMemTables()
defer decr()
tables := txn.db.getMemTables()
defer decrMemTables(tables)
txn.db.vlog.incrIteratorCount()
var iters []y.Iterator
if itr := txn.newPendingWritesIterator(opt.Reverse); itr != nil {
Expand Down
4 changes: 2 additions & 2 deletions stream_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ func (sw *StreamWriter) PrepareIncremental() error {
}
sw.done = func() { once.Do(done) }

mts, decr := sw.db.getMemTables()
defer decr()
mts := sw.db.getMemTables()
defer decrMemTables(mts)
for _, m := range mts {
if !m.sl.Empty() {
return fmt.Errorf("Unable to do incremental writes because MemTable has data")
Expand Down