mirror of
https://github.com/luxfi/zapdb.git
synced 2026-07-27 06:54:45 +00:00
In the existing implementation of oracle, if you happen to always have at least one write transaction open the memory usage of the transaction oracle is unbounded. It is actually relatively easy to hit when batch importing data. If you have more than one WriteBatch active during the import the transaction oracle will never be cleaned up. This commit fixes it. The core idea is to avoid increasing contention on purely read transactions; so only clean up the transaction oracle when write transactions are committed even if technically we could free memory sooner; Split the big `oracle.commit` map into one map per previously committed transaction; (this allows Go to release memory sooner than when performing deletes on a single map); Take advantage of the fact that we have acquired the oracle lock in oracle.newCommitTs to do the cleanup I am assuming here that the number of committed-but-still-tracked transactions is small, which makes an implementation based on a simple slice reasonable. If that's not the case we will need some form of a sorted data-structure (i.e. a b-tree) here. Co-authored-by: Damien Tournoud <damien@platform.sh>
90 lines
3.0 KiB
Go
90 lines
3.0 KiB
Go
/*
|
|
* Copyright 2017 Dgraph Labs, Inc. and Contributors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package badger
|
|
|
|
// OpenManaged returns a new DB, which allows more control over setting
|
|
// transaction timestamps, aka managed mode.
|
|
//
|
|
// This is only useful for databases built on top of Badger (like Dgraph), and
|
|
// can be ignored by most users.
|
|
func OpenManaged(opts Options) (*DB, error) {
|
|
opts.managedTxns = true
|
|
return Open(opts)
|
|
}
|
|
|
|
// NewTransactionAt follows the same logic as DB.NewTransaction(), but uses the
|
|
// provided read timestamp.
|
|
//
|
|
// This is only useful for databases built on top of Badger (like Dgraph), and
|
|
// can be ignored by most users.
|
|
func (db *DB) NewTransactionAt(readTs uint64, update bool) *Txn {
|
|
if !db.opt.managedTxns {
|
|
panic("Cannot use NewTransactionAt with managedDB=false. Use NewTransaction instead.")
|
|
}
|
|
txn := db.newTransaction(update, true)
|
|
txn.readTs = readTs
|
|
return txn
|
|
}
|
|
|
|
// NewWriteBatchAt is similar to NewWriteBatch but it allows user to set the commit timestamp.
|
|
// NewWriteBatchAt is supposed to be used only in the managed mode.
|
|
func (db *DB) NewWriteBatchAt(commitTs uint64) *WriteBatch {
|
|
if !db.opt.managedTxns {
|
|
panic("cannot use NewWriteBatchAt with managedDB=false. Use NewWriteBatch instead")
|
|
}
|
|
|
|
wb := db.newWriteBatch(true)
|
|
wb.commitTs = commitTs
|
|
wb.txn.commitTs = commitTs
|
|
return wb
|
|
}
|
|
func (db *DB) NewManagedWriteBatch() *WriteBatch {
|
|
if !db.opt.managedTxns {
|
|
panic("cannot use NewManagedWriteBatch with managedDB=false. Use NewWriteBatch instead")
|
|
}
|
|
|
|
wb := db.newWriteBatch(true)
|
|
return wb
|
|
}
|
|
|
|
// CommitAt commits the transaction, following the same logic as Commit(), but
|
|
// at the given commit timestamp. This will panic if not used with managed transactions.
|
|
//
|
|
// This is only useful for databases built on top of Badger (like Dgraph), and
|
|
// can be ignored by most users.
|
|
func (txn *Txn) CommitAt(commitTs uint64, callback func(error)) error {
|
|
if !txn.db.opt.managedTxns {
|
|
panic("Cannot use CommitAt with managedDB=false. Use Commit instead.")
|
|
}
|
|
txn.commitTs = commitTs
|
|
if callback == nil {
|
|
return txn.Commit()
|
|
}
|
|
txn.CommitWith(callback)
|
|
return nil
|
|
}
|
|
|
|
// SetDiscardTs sets a timestamp at or below which, any invalid or deleted
|
|
// versions can be discarded from the LSM tree, and thence from the value log to
|
|
// reclaim disk space. Can only be used with managed transactions.
|
|
func (db *DB) SetDiscardTs(ts uint64) {
|
|
if !db.opt.managedTxns {
|
|
panic("Cannot use SetDiscardTs with managedDB=false.")
|
|
}
|
|
db.orc.setDiscardTs(ts)
|
|
}
|