Skip to content
Merged
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
80 changes: 60 additions & 20 deletions native/redb-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,17 +349,73 @@ pub extern "C" fn redb_write_tx_delete_table(tx: *mut c_void, name: *const c_cha
};
let str_slice = c_str.to_str().unwrap();

let table = match tx.open_table(TableDefinition::<&[u8], &[u8]>::new(str_slice)) {
Ok(table) => table,
Err(err) => return table_error_code(&err),
match tx.delete_table(TableDefinition::<&[u8], &[u8]>::new(str_slice)) {
Ok(_) => REDB_OK,
Err(err) => table_error_code(&err),
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_write_tx_rename_table(
tx: *mut c_void,
old_name: *const c_char,
new_name: *const c_char,
) -> i32 {
let tx = unsafe {
assert!(!tx.is_null());
&mut *(tx as *mut redb::WriteTransaction)
};

let old_c_str = unsafe {
assert!(!old_name.is_null());
std::ffi::CStr::from_ptr(old_name)
};
let old_str_slice = old_c_str.to_str().unwrap();

let new_c_str = unsafe {
assert!(!new_name.is_null());
std::ffi::CStr::from_ptr(new_name)
};
let new_str_slice = new_c_str.to_str().unwrap();

match tx.delete_table(table) {
match tx.rename_table(
TableDefinition::<&[u8], &[u8]>::new(old_str_slice),
TableDefinition::<&[u8], &[u8]>::new(new_str_slice),
) {
Ok(_) => REDB_OK,
Err(err) => table_error_code(&err),
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_write_tx_abort(tx: *mut c_void) -> i32 {
let tx = unsafe {
assert!(!tx.is_null());
Box::from_raw(tx as *mut redb::WriteTransaction)
};

match tx.abort() {
Ok(_) => REDB_OK,
Err(_) => REDB_ERROR_STORAGE_ERROR,
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_write_tx_commit(tx: *mut c_void) -> i32 {
let tx = unsafe {
assert!(!tx.is_null());
Box::from_raw(tx as *mut redb::WriteTransaction)
};

match tx.commit() {
Ok(_) => REDB_OK,
Err(err) => match err {
redb::CommitError::Storage(_) => REDB_ERROR_STORAGE_ERROR,
_ => todo!(),
},
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_insert(
table: *mut c_void,
Expand Down Expand Up @@ -389,22 +445,6 @@ pub extern "C" fn redb_insert(
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_commit(tx: *mut c_void) -> i32 {
let tx = unsafe {
assert!(!tx.is_null());
Box::from_raw(tx as *mut redb::WriteTransaction)
};

match tx.commit() {
Ok(_) => REDB_OK,
Err(err) => match err {
redb::CommitError::Storage(_) => REDB_ERROR_STORAGE_ERROR,
_ => todo!(),
},
}
}

#[unsafe(no_mangle)]
pub extern "C" fn redb_begin_read(db: *mut c_void, out: *mut *mut c_void) -> i32 {
let db = unsafe {
Expand Down
12 changes: 9 additions & 3 deletions src/Redb/NativeMethods.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,18 @@ internal static unsafe partial class NativeMethods
[DllImport(__DllName, EntryPoint = "redb_write_tx_delete_table", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_write_tx_delete_table(void* tx, byte* name);

[DllImport(__DllName, EntryPoint = "redb_write_tx_rename_table", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_write_tx_rename_table(void* tx, byte* old_name, byte* new_name);

[DllImport(__DllName, EntryPoint = "redb_write_tx_abort", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_write_tx_abort(void* tx);

[DllImport(__DllName, EntryPoint = "redb_write_tx_commit", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_write_tx_commit(void* tx);

[DllImport(__DllName, EntryPoint = "redb_insert", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_insert(void* table, byte* key, nuint key_len, byte* value, nuint value_len);

[DllImport(__DllName, EntryPoint = "redb_commit", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_commit(void* tx);

[DllImport(__DllName, EntryPoint = "redb_begin_read", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
internal static extern int redb_begin_read(void* db, void** @out);

Expand Down
78 changes: 76 additions & 2 deletions src/Redb/WriteTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ public readonly void SetDurability(RedbDurability durability)
}
}

public readonly void SetTwoPhaseCommit(bool enable)
{
var code = NativeMethods.redb_write_tx_set_two_phase_commit(tx, enable);
if (code != 0)
{
throw new RedbDatabaseException("Failed to call set_two_phase_commit()", code);
}
}

public readonly void SetQuickRepair(bool enable)
{
var code = NativeMethods.redb_write_tx_set_quick_repair(tx, enable);
if (code != 0)
{
throw new RedbDatabaseException("Failed to call set_quick_repair()", code);
}
}

public readonly Table OpenTable(ReadOnlySpan<byte> name)
{
using var nameBuffer = new NullTerminatedUtf8String(name);
Expand Down Expand Up @@ -80,21 +98,77 @@ readonly Table<TKey, TValue> OpenTableCore<TKey, TValue>(NullTerminatedUtf8Strin
return new Table<TKey, TValue>(database, table);
}

public readonly void DeleteTable(ReadOnlySpan<byte> utf8Name)
{
using var nameBuffer = new NullTerminatedUtf8String(utf8Name);
DeleteTableCore(nameBuffer);
}

public readonly void DeleteTable(ReadOnlySpan<char> name)
{
using var nameBuffer = new NullTerminatedUtf8String(name);
DeleteTableCore(nameBuffer);
}

readonly void DeleteTableCore(NullTerminatedUtf8String name)
{
fixed (byte* namePtr = name)
{
int code = NativeMethods.redb_write_tx_delete_table(tx, namePtr);
if (code != 0)
{
throw new RedbDatabaseException("Failed to delete table", code);
}
}
}

public readonly void RenameTable(ReadOnlySpan<byte> oldUtf8Name, ReadOnlySpan<byte> newUtf8Name)
{
using var oldNameBuffer = new NullTerminatedUtf8String(oldUtf8Name);
using var newNameBuffer = new NullTerminatedUtf8String(newUtf8Name);
RenameTableCore(oldNameBuffer, newNameBuffer);
}

public readonly void RenameTable(ReadOnlySpan<char> oldName, ReadOnlySpan<char> newName)
{
using var oldNameBuffer = new NullTerminatedUtf8String(oldName);
using var newNameBuffer = new NullTerminatedUtf8String(newName);
RenameTableCore(oldNameBuffer, newNameBuffer);
}

readonly void RenameTableCore(NullTerminatedUtf8String oldName, NullTerminatedUtf8String newName)
{
fixed (byte* oldNamePtr = oldName)
fixed (byte* newNamePtr = newName)
{
int code = NativeMethods.redb_write_tx_rename_table(tx, oldNamePtr, newNamePtr);
if (code != 0)
{
throw new RedbDatabaseException("Failed to rename table", code);
}
}
}

public void Commit()
{
var code = NativeMethods.redb_commit(tx);
var code = NativeMethods.redb_write_tx_commit(tx);
if (code != 0)
{
throw new RedbDatabaseException("Failed to commit transaction", code);
}
tx = null;
}


public void Dispose()
{
if (tx != null)
{
NativeMethods.redb_free_write_transaction(tx);
var code = NativeMethods.redb_write_tx_abort(tx);
if (code != 0)
{
throw new RedbDatabaseException("Failed to abort transaction", code);
}
tx = null;
}
}
Expand Down