Skip to content

Commit

Permalink
Get Readers, Writers and Handles ref-counted in C API to compile and …
Browse files Browse the repository at this point in the history
…pass tests
  • Loading branch information
anacrolix committed Jul 11, 2024
1 parent 6888985 commit 543f059
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 151 deletions.
2 changes: 1 addition & 1 deletion go/cpossum/c-possum.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (me Stat) Size() int64 {
return int64(me.size)
}

type Handle = C.Handle
type Handle = C.PossumHandle

func NewHandle(dir string) *Handle {
cDir := C.CString(dir)
Expand Down
44 changes: 22 additions & 22 deletions go/cpossum/possum.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,7 @@ typedef enum {
/**
* Manages uncommitted writes
*/
typedef struct BatchWriter BatchWriter;

/**
* Provides access to a storage directory. Manages manifest access, file cloning, file writers,
* configuration, value eviction etc.
*/
typedef struct Handle Handle;
typedef struct BatchWriter_PossumHandle BatchWriter_PossumHandle;

typedef struct PossumReader PossumReader;

Expand All @@ -31,9 +25,15 @@ typedef struct PossumReader PossumReader;
*/
typedef struct PossumValue PossumValue;

typedef struct Rc_RwLock_Handle Rc_RwLock_Handle;

typedef struct ValueWriter ValueWriter;

typedef BatchWriter PossumWriter;
typedef Rc_RwLock_Handle PossumHandleRc;

typedef PossumHandleRc PossumHandle;

typedef BatchWriter_PossumHandle PossumWriter;

typedef ValueWriter PossumValueWriter;

Expand Down Expand Up @@ -66,13 +66,13 @@ typedef struct {
bool disable_hole_punching;
} PossumLimits;

Handle *possum_new(const char *path);
PossumHandle *possum_new(const char *path);

PossumError possum_start_new_value(PossumWriter *writer, PossumValueWriter **value);

RawFileHandle possum_value_writer_fd(PossumValueWriter *value);

PossumError possum_writer_rename(BatchWriter *writer, const PossumValue *value, PossumBuf new_key);
PossumError possum_writer_rename(PossumWriter *writer, const PossumValue *value, PossumBuf new_key);

PossumError possum_reader_add(PossumReader *reader, PossumBuf key, const PossumValue **value);

Expand All @@ -99,35 +99,35 @@ PossumError possum_writer_commit(PossumWriter *writer);

PossumError possum_writer_stage(PossumWriter *writer, PossumBuf key, PossumValueWriter *value);

void possum_drop(Handle *handle);
void possum_drop(PossumHandle *handle);

PossumError possum_set_instance_limits(Handle *handle, const PossumLimits *limits);
PossumError possum_set_instance_limits(PossumHandle *handle, const PossumLimits *limits);

PossumError possum_cleanup_snapshots(const Handle *handle);
PossumError possum_cleanup_snapshots(const PossumHandle *handle);

size_t possum_single_write_buf(Handle *handle, PossumBuf key, PossumBuf value);
size_t possum_single_write_buf(PossumHandle *handle, PossumBuf key, PossumBuf value);

PossumWriter *possum_new_writer(Handle *handle);
PossumWriter *possum_new_writer(PossumHandle *handle);

bool possum_single_stat(const Handle *handle, PossumBuf key, PossumStat *out_stat);
bool possum_single_stat(const PossumHandle *handle, PossumBuf key, PossumStat *out_stat);

PossumError possum_list_items(const Handle *handle,
PossumError possum_list_items(const PossumHandle *handle,
PossumBuf prefix,
PossumItem **out_list,
size_t *out_list_len);

PossumError possum_single_read_at(const Handle *handle,
PossumError possum_single_read_at(const PossumHandle *handle,
PossumBuf key,
PossumBuf *buf,
uint64_t offset);

/**
* stat is filled if non-null and a delete occurs. NoSuchKey is returned if the key does not exist.
*/
PossumError possum_single_delete(const Handle *handle, PossumBuf key, PossumStat *stat);
PossumError possum_single_delete(const PossumHandle *handle, PossumBuf key, PossumStat *stat);

PossumError possum_reader_new(const Handle *handle, PossumReader **reader);
PossumError possum_reader_new(const PossumHandle *handle, PossumReader **reader);

PossumError possum_handle_move_prefix(Handle *handle, PossumBuf from, PossumBuf to);
PossumError possum_handle_move_prefix(PossumHandle *handle, PossumBuf from, PossumBuf to);

PossumError possum_handle_delete_prefix(Handle *handle, PossumBuf prefix);
PossumError possum_handle_delete_prefix(PossumHandle *handle, PossumBuf prefix);
90 changes: 63 additions & 27 deletions src/c_api/ext_fns/handle.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
use libc::size_t;
use positioned_io::ReadAt;
use rusqlite::TransactionBehavior;

use super::*;
use crate::c_api::PossumError::NoError;
use crate::Handle;

// This drops the Handle Box. Instead, if this is hard to use correctly from C, it could drop a
// top-level reference count for the box. i.e. If this one goes, there's no way to work with the
// Handle, and when all other outstanding operations on the Handle complete, it will drop the Handle
// for real.
// This drops the PossumHandle Box. Instead, if this is hard to use correctly from C, it could drop
// a top-level reference count for the box. i.e. If this one goes, there's no way to work with the
// PossumHandle, and when all other outstanding operations on the PossumHandle complete, it will
// drop the PossumHandle for real.
#[no_mangle]
pub extern "C" fn possum_drop(handle: *mut Handle) {
pub extern "C" fn possum_drop(handle: *mut PossumHandle) {
drop(unsafe { Box::from_raw(handle) })
}

#[no_mangle]
pub extern "C" fn possum_set_instance_limits(
handle: *mut Handle,
handle: *mut PossumHandle,
limits: *const PossumLimits,
) -> PossumError {
let handle = unsafe { &mut *handle };
let limits = unsafe { limits.read() };
with_residual(|| {
handle
.write()
.unwrap()
.set_instance_limits(limits.into())
.map_err(Into::into)
})
}

#[no_mangle]
pub extern "C" fn possum_cleanup_snapshots(handle: *const Handle) -> PossumError {
let handle = unsafe { &*handle };
with_residual(|| handle.cleanup_snapshots())
pub extern "C" fn possum_cleanup_snapshots(handle: *const PossumHandle) -> PossumError {
let handle = unwrap_possum_handle(handle);
with_residual(|| handle.read().unwrap().cleanup_snapshots())
}

#[no_mangle]
pub extern "C" fn possum_single_write_buf(
handle: *mut Handle,
handle: *mut PossumHandle,
key: PossumBuf,
value: PossumBuf,
) -> size_t {
let key_vec = key.as_ref().to_vec();
let value_slice = value.as_ref();
const ERR_SENTINEL: usize = usize::MAX;
let handle = unsafe { &*handle };
match handle.single_write_from(key_vec, value_slice) {
match handle
.read()
.unwrap()
.single_write_from(key_vec, value_slice)
{
Err(_) => ERR_SENTINEL,
Ok((n, _)) => {
let n = n.try_into().unwrap();
Expand All @@ -55,18 +61,21 @@ pub extern "C" fn possum_single_write_buf(
}

#[no_mangle]
pub extern "C" fn possum_new_writer(handle: *mut Handle) -> *mut PossumWriter {
let handle = unsafe { handle.as_ref() }.unwrap();
Box::into_raw(Box::new(handle.new_writer().unwrap()))
pub extern "C" fn possum_new_writer(handle: *mut PossumHandle) -> *mut PossumWriter {
let handle = unwrap_possum_handle(handle);
let writer = BatchWriter::new(handle.clone());
Box::into_raw(Box::new(writer))
}

#[no_mangle]
pub extern "C" fn possum_single_stat(
handle: *const Handle,
handle: *const PossumHandle,
key: PossumBuf,
out_stat: *mut PossumStat,
) -> bool {
match unsafe { handle.as_ref() }
.unwrap()
.read()
.unwrap()
.read_single(key.as_ref())
.unwrap()
Expand All @@ -82,12 +91,14 @@ pub extern "C" fn possum_single_stat(

#[no_mangle]
pub extern "C" fn possum_list_items(
handle: *const Handle,
handle: *const PossumHandle,
prefix: PossumBuf,
out_list: *mut *mut PossumItem,
out_list_len: *mut size_t,
) -> PossumError {
let items = match unsafe { handle.as_ref() }
.unwrap()
.read()
.unwrap()
.list_items(prefix.as_ref())
{
Expand All @@ -100,13 +111,18 @@ pub extern "C" fn possum_list_items(

#[no_mangle]
pub extern "C" fn possum_single_read_at(
handle: *const Handle,
handle: *const PossumHandle,
key: PossumBuf,
buf: *mut PossumBuf,
offset: u64,
) -> PossumError {
let rust_key = key.as_ref();
let value = match unsafe { handle.as_ref() }.unwrap().read_single(rust_key) {
let value = match unsafe { handle.as_ref() }
.unwrap()
.read()
.unwrap()
.read_single(rust_key)
{
Ok(Some(value)) => value,
Ok(None) => return PossumError::NoSuchKey,
Err(err) => return err.into(),
Expand All @@ -124,13 +140,13 @@ pub extern "C" fn possum_single_read_at(
/// stat is filled if non-null and a delete occurs. NoSuchKey is returned if the key does not exist.
#[no_mangle]
pub extern "C" fn possum_single_delete(
handle: *const Handle,
handle: *const PossumHandle,
key: PossumBuf,
stat: *mut PossumStat,
) -> PossumError {
with_residual(|| {
let handle = unsafe { &*handle };
let value = match handle.single_delete(key.as_ref()) {
let value = match handle.read().unwrap().single_delete(key.as_ref()) {
Ok(None) => return Err(crate::Error::NoSuchKey),
Err(err) => return Err(err),
Ok(Some(value)) => value,
Expand All @@ -144,15 +160,27 @@ pub extern "C" fn possum_single_delete(

#[no_mangle]
pub extern "C" fn possum_reader_new(
handle: *const Handle,
handle: *const PossumHandle,
reader: *mut *mut PossumReader,
) -> PossumError {
let handle = unsafe { handle.as_ref() }.unwrap();
let handle = unwrap_possum_handle(handle).clone();
let reader = unsafe { reader.as_mut() }.unwrap();
let rust_reader = match handle.read() {
let owned_tx_res = handle.start_transaction(
// This is copied from Handle::start_writable_transaction_with_behaviour and Handle::read
// until I make proper abstractions.
|conn, handle| {
let rtx = conn.transaction_with_behavior(TransactionBehavior::Deferred)?;
Ok(Transaction::new(rtx, handle))
},
);
let owned_tx = match owned_tx_res {
Ok(ok) => ok,
Err(err) => return err.into(),
};
let rust_reader = Reader {
owned_tx,
reads: Default::default(),
};
*reader = Box::into_raw(Box::new(PossumReader {
rust_reader: Some(rust_reader),
values: Default::default(),
Expand All @@ -162,23 +190,31 @@ pub extern "C" fn possum_reader_new(

#[no_mangle]
pub extern "C" fn possum_handle_move_prefix(
handle: *mut Handle,
handle: *mut PossumHandle,
from: PossumBuf,
to: PossumBuf,
) -> PossumError {
let handle = unsafe { &mut *handle };
with_residual(|| {
handle
.read()
.unwrap()
.move_prefix(from.as_ref(), to.as_ref())
.map_err(Into::into)
})
}

#[no_mangle]
pub extern "C" fn possum_handle_delete_prefix(
handle: *mut Handle,
handle: *mut PossumHandle,
prefix: PossumBuf,
) -> PossumError {
let handle = unsafe { &mut *handle };
with_residual(|| handle.delete_prefix(prefix.as_ref()).map_err(Into::into))
with_residual(|| {
handle
.read()
.unwrap()
.delete_prefix(prefix.as_ref())
.map_err(Into::into)
})
}
9 changes: 6 additions & 3 deletions src/c_api/ext_fns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ mod handle;
use std::ffi::{c_char, CStr};
use std::path::PathBuf;
use std::ptr::null_mut;
use std::rc::Rc;
use std::sync::RwLock;

use libc::size_t;
use positioned_io::ReadAt;
Expand All @@ -13,7 +15,7 @@ use crate::c_api::PossumError::{NoError, NoSuchKey};
use crate::Handle;

#[no_mangle]
pub extern "C" fn possum_new(path: *const c_char) -> *mut Handle {
pub extern "C" fn possum_new(path: *const c_char) -> *mut PossumHandle {
if let Err(err) = env_logger::try_init() {
warn!("error initing env_logger: {}", err);
}
Expand All @@ -33,7 +35,7 @@ pub extern "C" fn possum_new(path: *const c_char) -> *mut Handle {
return null_mut();
}
};
Box::into_raw(Box::new(handle))
Box::into_raw(Box::new(Rc::new(RwLock::new(handle))))
}

#[no_mangle]
Expand Down Expand Up @@ -78,7 +80,8 @@ pub extern "C" fn possum_reader_add(
value: *mut *const PossumValue,
) -> PossumError {
let reader = unsafe { reader.as_mut() }.unwrap();
let rust_value = match reader.rust_reader.as_mut().unwrap().add(key.as_ref()) {
let mut_rust_reader = reader.rust_reader.as_mut().unwrap();
let rust_value = match mut_rust_reader.add(key.as_ref()) {
Ok(None) => return NoSuchKey,
Ok(Some(value)) => value,
Err(err) => return err.into(),
Expand Down
13 changes: 12 additions & 1 deletion src/c_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use std::ffi::c_char;
use std::mem::size_of;
use std::pin::Pin;
use std::ptr::copy_nonoverlapping;
use std::rc::Rc;
use std::slice;
use std::sync::RwLockReadGuard;

use libc::{calloc, malloc, size_t};

Expand All @@ -32,10 +34,15 @@ impl PossumBuf {
struct PossumReader {
// Removed when converted to a snapshot. Specific to the C API so as to not need to expose
// Snapshot, and to convert Values automatically when a snapshot starts.
rust_reader: Option<Reader<OwnedTx<'static>>>,
rust_reader: Option<Reader<PossumReaderOwnedTransaction<'static>>>,
values: Vec<Pin<Box<PossumValue>>>,
}

pub(crate) type PossumReaderOwnedTransaction<'a> = <PossumHandleRc as StartTransaction<
'a,
Transaction<'a, Rc<RwLockReadGuard<'a, Handle>>>,
>>::Owned;

use crate::c_api::PossumError::{AnyhowError, IoError, SqliteError};

impl<V> From<V> for PossumStat
Expand Down Expand Up @@ -142,6 +149,10 @@ fn with_residual(f: impl FnOnce() -> PubResult<()>) -> PossumError {
}
}

fn unwrap_possum_handle<'a>(handle: *const PossumHandle) -> &'a PossumHandle {
unsafe { handle.as_ref() }.unwrap()
}

impl From<PossumLimits> for handle::Limits {
fn from(from: PossumLimits) -> Self {
handle::Limits {
Expand Down
Loading

0 comments on commit 543f059

Please sign in to comment.