Table of Contents

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

key ReadOnlySpan<byte>

Delete(ReadOnlySpan<byte>, ColumnFamilyHandle)

Queues a delete of key, taking a lock on it.

public void Delete(ReadOnlySpan<byte> key, ColumnFamilyHandle cf)

Parameters

key ReadOnlySpan<byte>
cf ColumnFamilyHandle

Delete(string)

Queues a delete of key, taking a lock on it.

public void Delete(string key)

Parameters

key string

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

key ReadOnlySpan<byte>
cf ColumnFamilyHandle
options ReadOptions

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

key ReadOnlySpan<byte>
options ReadOptions

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

key ReadOnlySpan<byte>

The key to read and lock.

cf ColumnFamilyHandle
exclusive bool

true, 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.

options ReadOptions

Read 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

key ReadOnlySpan<byte>

The key to read and lock.

exclusive bool

true, 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.

options ReadOptions

Read 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

key string
cf ColumnFamilyHandle
options ReadOptions

Returns

string

GetString(string, ReadOptions?)

Reads a UTF-8 key as a string, or null if absent.

public string? GetString(string key, ReadOptions? options = null)

Parameters

key string
options ReadOptions

Returns

string

GetStringForUpdate(string, bool, ReadOptions?)

Reads and locks a UTF-8 key.

public string? GetStringForUpdate(string key, bool exclusive = true, ReadOptions? options = null)

Parameters

key string
exclusive bool
options ReadOptions

Returns

string

Merge(ReadOnlySpan<byte>, ReadOnlySpan<byte>)

Queues a merge operation on key.

public void Merge(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value)

Parameters

key ReadOnlySpan<byte>
value ReadOnlySpan<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

key ReadOnlySpan<byte>
value ReadOnlySpan<byte>
cf ColumnFamilyHandle

NewIterator(ColumnFamilyHandle, ReadOptions?)

Creates an iterator over the database plus this transaction's pending writes.

public Iterator NewIterator(ColumnFamilyHandle cf, ReadOptions? options = null)

Parameters

cf ColumnFamilyHandle
options ReadOptions

Returns

Iterator

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

options ReadOptions

Returns

Iterator

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

key ReadOnlySpan<byte>
value ReadOnlySpan<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

key ReadOnlySpan<byte>
value ReadOnlySpan<byte>
cf ColumnFamilyHandle

Put(string, string)

Queues a write of a UTF-8 key and value.

public void Put(string key, string value)

Parameters

key string
value string

Put(string, string, ColumnFamilyHandle)

Queues a write of a UTF-8 key and value.

public void Put(string key, string value, ColumnFamilyHandle cf)

Parameters

key string
value string
cf ColumnFamilyHandle

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()