Class Transaction
- Namespace
- RocksDbNet
- Assembly
- RocksDb.Net.dll
A transaction on a TransactionDb. Maps to
rocksdb_transaction_t.
public sealed class Transaction : RocksDbHandle, IDisposable
- Inheritance
-
Transaction
- Implements
- Inherited Members
Remarks
Reads see the transaction's own pending writes as well as the committed database. Writes are buffered until Commit(), and discarded by Rollback().
This is not repeatable read. A plain Get(ReadOnlySpan<byte>, ReadOptions?) takes no lock and is not tracked, so a key can change underneath a transaction between reading it and committing, and nothing reports that. Conflict detection happens when a key is locked, by GetForUpdate(ReadOnlySpan<byte>, bool, ReadOptions?) or by a write, and not at Commit(). A transaction whose correctness depends on what it read has to read for update.
Always dispose it. Neither Commit() nor Rollback() releases the transaction; they only decide what happens to its writes. A transaction that is never disposed keeps its locks.
It must be released before the database. That ordering is enforced rather than merely documented: a transaction keeps its database reachable, and skips its native release once the database has closed. RocksDb's own destructor unlocks keys and unregisters the transaction through the database pointer, so releasing after the close would use freed memory.
Methods
Commit()
Applies the transaction's writes to the database.
public void Commit()
Remarks
Conflicts are not detected here. A pessimistic transaction, which is what TransactionDb gives you, takes a lock and checks for a conflicting change when the key is written or read for update, so a conflict has already thrown from Put(ReadOnlySpan<byte>, ReadOnlySpan<byte>) or GetForUpdate(ReadOnlySpan<byte>, bool, ReadOptions?) long before this is called. That is the ordinary outcome to retry.
A key read with a plain Get(ReadOnlySpan<byte>, ReadOptions?)
is not tracked and never causes a conflict, whether or not
SetSnapshot was used. Measured: a
transaction that read a key, watched another transaction change and
commit it, and then committed its own unrelated write, committed
successfully. Use GetForUpdate for reads a decision depends on.
This does not release the transaction. Dispose it as well.
Delete(ReadOnlySpan<byte>)
Queues a delete of key, taking a lock on it.
public void Delete(ReadOnlySpan<byte> key)
Parameters
keyReadOnlySpan<byte>
Delete(ReadOnlySpan<byte>, ColumnFamilyHandle)
Queues a delete of key, taking a lock on it.
public void Delete(ReadOnlySpan<byte> key, ColumnFamilyHandle cf)
Parameters
keyReadOnlySpan<byte>cfColumnFamilyHandle
Delete(string)
Queues a delete of key, taking a lock on it.
public void Delete(string key)
Parameters
keystring
DisposeHandle()
Releases the native handle. Called during disposal.
protected override void DisposeHandle()
Remarks
Protected rather than public: it destroys the native object without marking this instance disposed or clearing the handle, so calling it from outside and then disposing normally would free the same pointer twice. It was the most Dispose-looking member on the type. Callers want Dispose().
DisposeUnmanagedResources()
Releases unmanaged resources used by the current instance.
protected override void DisposeUnmanagedResources()
Remarks
Protected for the same reason as DisposeHandle().
Get(ReadOnlySpan<byte>, ColumnFamilyHandle, ReadOptions?)
Reads a key, seeing this transaction's pending writes, or returns null if it is absent.
public byte[]? Get(ReadOnlySpan<byte> key, ColumnFamilyHandle cf, ReadOptions? options = null)
Parameters
keyReadOnlySpan<byte>cfColumnFamilyHandleoptionsReadOptions
Returns
- byte[]
Remarks
This takes no lock. Use GetForUpdate(ReadOnlySpan<byte>, bool, ReadOptions?) for a read that a later write in the same transaction depends on.
Get(ReadOnlySpan<byte>, ReadOptions?)
Reads a key, seeing this transaction's pending writes, or returns null if it is absent.
public byte[]? Get(ReadOnlySpan<byte> key, ReadOptions? options = null)
Parameters
keyReadOnlySpan<byte>optionsReadOptions
Returns
- byte[]
Remarks
This takes no lock. Use GetForUpdate(ReadOnlySpan<byte>, bool, ReadOptions?) for a read that a later write in the same transaction depends on.
GetForUpdate(ReadOnlySpan<byte>, ColumnFamilyHandle, bool, ReadOptions?)
Reads a key and locks it, so that no other transaction can change it before this one finishes.
public byte[]? GetForUpdate(ReadOnlySpan<byte> key, ColumnFamilyHandle cf, bool exclusive = true, ReadOptions? options = null)
Parameters
keyReadOnlySpan<byte>The key to read and lock.
cfColumnFamilyHandleexclusivebooltrue, the default, takes a write lock. Passing false takes a shared lock, which several transactions may hold at once, so it guards against writers but not against another reader also intending to write.
optionsReadOptionsRead options, or null for the defaults.
Returns
- byte[]
Remarks
This is the read half of a read-modify-write, and the reason to use a transaction at all. Reading with Get(ReadOnlySpan<byte>, ReadOptions?) and then writing leaves a window in which another transaction can change the value.
Throws if the lock cannot be taken within the timeout, or if SetSnapshot was set and the key has changed since the transaction began. Both are ordinary outcomes to retry, not bugs.
GetForUpdate(ReadOnlySpan<byte>, bool, ReadOptions?)
Reads a key and locks it, so that no other transaction can change it before this one finishes.
public byte[]? GetForUpdate(ReadOnlySpan<byte> key, bool exclusive = true, ReadOptions? options = null)
Parameters
keyReadOnlySpan<byte>The key to read and lock.
exclusivebooltrue, the default, takes a write lock. Passing false takes a shared lock, which several transactions may hold at once, so it guards against writers but not against another reader also intending to write.
optionsReadOptionsRead options, or null for the defaults.
Returns
- byte[]
Remarks
This is the read half of a read-modify-write, and the reason to use a transaction at all. Reading with Get(ReadOnlySpan<byte>, ReadOptions?) and then writing leaves a window in which another transaction can change the value.
Throws if the lock cannot be taken within the timeout, or if SetSnapshot was set and the key has changed since the transaction began. Both are ordinary outcomes to retry, not bugs.
GetString(string, ColumnFamilyHandle, ReadOptions?)
Reads a UTF-8 key as a string, or null if absent.
public string? GetString(string key, ColumnFamilyHandle cf, ReadOptions? options = null)
Parameters
keystringcfColumnFamilyHandleoptionsReadOptions
Returns
GetString(string, ReadOptions?)
Reads a UTF-8 key as a string, or null if absent.
public string? GetString(string key, ReadOptions? options = null)
Parameters
keystringoptionsReadOptions
Returns
GetStringForUpdate(string, bool, ReadOptions?)
Reads and locks a UTF-8 key.
public string? GetStringForUpdate(string key, bool exclusive = true, ReadOptions? options = null)
Parameters
keystringexclusivebooloptionsReadOptions
Returns
Merge(ReadOnlySpan<byte>, ReadOnlySpan<byte>)
Queues a merge operation on key.
public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value)
Parameters
keyReadOnlySpan<byte>valueReadOnlySpan<byte>
Merge(ReadOnlySpan<byte>, ReadOnlySpan<byte>, ColumnFamilyHandle)
Queues a merge operation on key.
public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, ColumnFamilyHandle cf)
Parameters
keyReadOnlySpan<byte>valueReadOnlySpan<byte>cfColumnFamilyHandle
NewIterator(ColumnFamilyHandle, ReadOptions?)
Creates an iterator over the database plus this transaction's pending writes.
public Iterator NewIterator(ColumnFamilyHandle cf, ReadOptions? options = null)
Parameters
cfColumnFamilyHandleoptionsReadOptions
Returns
Remarks
The iterator is invalidated by Commit(), Rollback() and RollbackToSavePoint(). Those dispose any iterator still open, so using one afterwards throws ObjectDisposedException rather than reading freed memory.
NewIterator(ReadOptions?)
Creates an iterator over the database plus this transaction's pending writes.
public Iterator NewIterator(ReadOptions? options = null)
Parameters
optionsReadOptions
Returns
Remarks
The iterator is invalidated by Commit(), Rollback() and RollbackToSavePoint(). Those dispose any iterator still open, so using one afterwards throws ObjectDisposedException rather than reading freed memory.
Put(ReadOnlySpan<byte>, ReadOnlySpan<byte>)
Queues a write of key, taking a lock on it.
public void Put(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value)
Parameters
keyReadOnlySpan<byte>valueReadOnlySpan<byte>
Put(ReadOnlySpan<byte>, ReadOnlySpan<byte>, ColumnFamilyHandle)
Queues a write of key, taking a lock on it.
public void Put(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, ColumnFamilyHandle cf)
Parameters
keyReadOnlySpan<byte>valueReadOnlySpan<byte>cfColumnFamilyHandle
Put(string, string)
Queues a write of a UTF-8 key and value.
public void Put(string key, string value)
Parameters
Put(string, string, ColumnFamilyHandle)
Queues a write of a UTF-8 key and value.
public void Put(string key, string value, ColumnFamilyHandle cf)
Parameters
keystringvaluestringcfColumnFamilyHandle
Rollback()
Discards the transaction's writes and releases its locks.
public void Rollback()
Remarks
This does not release the transaction. Dispose it as well.
RollbackToSavePoint()
Discards everything queued since the last SetSavePoint().
public void RollbackToSavePoint()
Remarks
Invalidates any open iterator, so those are disposed first.
SetSavePoint()
Marks a point that RollbackToSavePoint() can return to.
public void SetSavePoint()