Skip to content

Commit b625694

Browse files
authored
WASM ABI: delete_by_rel -> datastore_delete_all_by_eq_bsatn (#1638)
1 parent 49f366f commit b625694

File tree

10 files changed

+129
-74
lines changed

10 files changed

+129
-74
lines changed

crates/bindings-csharp/Runtime/Exceptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ public class NotInTransactionException : StdbException
1212
public override string Message => "ABI call can only be made while in a transaction";
1313
}
1414

15+
public class BsatnDecodeException : StdbException
16+
{
17+
public override string Message => "Couldn't decode the BSATN to the expected type";
18+
}
19+
1520
public class NoSuchTableException : StdbException
1621
{
1722
public override string Message => "No such table";

crates/bindings-csharp/Runtime/Internal/FFI.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public enum Errno : short
2424
OK = 0,
2525
HOST_CALL_FAILURE = 1,
2626
NOT_IN_TRANSACTION = 2,
27+
BSATN_DECODE_ERROR = 3,
2728
NO_SUCH_TABLE = 4,
2829
NO_SUCH_ITER = 6,
2930
NO_SUCH_BYTES = 8,
@@ -70,11 +71,13 @@ public static CheckedStatus ConvertToManaged(Errno status)
7071
throw status switch
7172
{
7273
Errno.NOT_IN_TRANSACTION => new NotInTransactionException(),
74+
Errno.BSATN_DECODE_ERROR => new BsatnDecodeException(),
7375
Errno.NO_SUCH_TABLE => new NoSuchTableException(),
74-
Errno.UNIQUE_ALREADY_EXISTS => new UniqueAlreadyExistsException(),
75-
Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(),
76+
Errno.NO_SUCH_ITER => new NoSuchIterException(),
7677
Errno.NO_SUCH_BYTES => new NoSuchBytesException(),
7778
Errno.NO_SPACE => new NoSpaceException(),
79+
Errno.BUFFER_TOO_SMALL => new BufferTooSmallException(),
80+
Errno.UNIQUE_ALREADY_EXISTS => new UniqueAlreadyExistsException(),
7881
_ => new UnknownException(status),
7982
};
8083
}
@@ -153,14 +156,6 @@ public static partial CheckedStatus _delete_by_col_eq(
153156
out uint out_
154157
);
155158

156-
[LibraryImport(StdbNamespace)]
157-
public static partial CheckedStatus _delete_by_rel(
158-
TableId table_id,
159-
[In] byte[] relation,
160-
uint relation_len,
161-
out uint out_
162-
);
163-
164159
[LibraryImport(StdbNamespace)]
165160
public static partial CheckedStatus _iter_start_filtered(
166161
TableId table_id,
@@ -179,6 +174,14 @@ ref uint buffer_len
179174
[LibraryImport(StdbNamespace)]
180175
public static partial CheckedStatus _row_iter_bsatn_close(RowIter iter_handle);
181176

177+
[LibraryImport(StdbNamespace)]
178+
public static partial CheckedStatus _datastore_delete_all_by_eq_bsatn(
179+
TableId table_id,
180+
[In] byte[] relation,
181+
uint relation_len,
182+
out uint out_
183+
);
184+
182185
[LibraryImport(StdbNamespace)]
183186
public static partial void _volatile_nonatomic_schedule_immediate(
184187
[In] byte[] name,

crates/bindings-csharp/Runtime/bindings.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ IMPORT(Status, _delete_by_col_eq,
6060
(TableId table_id, ColId col_id, const uint8_t* value,
6161
uint32_t value_len, uint32_t* num_deleted),
6262
(table_id, col_id, value, value_len, num_deleted));
63-
IMPORT(Status, _delete_by_rel,
64-
(TableId table_id, const uint8_t* relation, uint32_t relation_len,
65-
uint32_t* num_deleted),
66-
(table_id, relation, relation_len, num_deleted));
6763
IMPORT(Status, _iter_start_filtered,
6864
(TableId table_id, const uint8_t* filter, uint32_t filter_len,
6965
RowIter* iter),
@@ -72,6 +68,10 @@ IMPORT(int16_t, _row_iter_bsatn_advance,
7268
(RowIter iter, uint8_t* buffer_ptr, size_t* buffer_len_ptr),
7369
(iter, buffer_ptr, buffer_len_ptr));
7470
IMPORT(uint16_t, _row_iter_bsatn_close, (RowIter iter), (iter));
71+
IMPORT(Status, _datastore_delete_all_by_eq_bsatn,
72+
(TableId table_id, const uint8_t* rel_ptr, uint32_t rel_len,
73+
uint32_t* num_deleted),
74+
(table_id, rel_ptr, rel_len, num_deleted));
7575
IMPORT(void, _volatile_nonatomic_schedule_immediate,
7676
(const uint8_t* name, size_t name_len, const uint8_t* args, size_t args_len),
7777
(name, name_len, args, args_len));

crates/bindings-csharp/Runtime/build/SpacetimeDB.Runtime.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
<WasmImport Include="$(SpacetimeNamespace)!_iter_by_col_eq" />
88
<WasmImport Include="$(SpacetimeNamespace)!_insert" />
99
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_col_eq" />
10-
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_rel" />
1110
<WasmImport Include="$(SpacetimeNamespace)!_iter_start_filtered" />
1211
<WasmImport Include="$(SpacetimeNamespace)!_table_id_from_name" />
1312
<WasmImport Include="$(SpacetimeNamespace)!_datastore_table_row_count" />
1413
<WasmImport Include="$(SpacetimeNamespace)!_datastore_table_scan_bsatn" />
1514
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_advance" />
1615
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_close" />
16+
<WasmImport Include="$(SpacetimeNamespace)!_datastore_delete_all_by_eq_bsatn" />
1717
<WasmImport Include="$(SpacetimeNamespace)!_bytes_source_read" />
1818
<WasmImport Include="$(SpacetimeNamespace)!_bytes_sink_write" />
1919

crates/bindings-sys/src/lib.rs

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -138,22 +138,37 @@ pub mod raw {
138138
) -> u16;
139139

140140
/// Deletes those rows, in the table identified by `table_id`,
141-
/// that match any row in `relation`.
141+
/// that match any row in the byte string `rel = rel_ptr[..rel_len]` in WASM memory.
142142
///
143143
/// Matching is defined by first BSATN-decoding
144144
/// the byte string pointed to at by `relation` to a `Vec<ProductValue>`
145145
/// according to the row schema of the table
146146
/// and then using `Ord for AlgebraicValue`.
147+
/// A match happens when `Ordering::Equal` is returned from `fn cmp`.
148+
/// This occurs exactly when the row's BSATN-encoding is equal to the encoding of the `ProductValue`.
147149
///
148150
/// The number of rows deleted is written to the WASM pointer `out`.
149151
///
150-
/// Returns an error if
151-
/// - a table with the provided `table_id` doesn't exist
152-
/// - `(relation, relation_len)` doesn't decode from BSATN to a `Vec<ProductValue>`
153-
/// according to the `ProductValue` that the table's schema specifies for rows.
154-
/// - `relation + relation_len` overflows a 64-bit integer
155-
/// - writing to `out` would overflow a 32-bit integer
156-
pub fn _delete_by_rel(table_id: TableId, relation: *const u8, relation_len: usize, out: *mut u32) -> u16;
152+
/// # Traps
153+
///
154+
/// Traps if:
155+
/// - `rel_ptr` is NULL or `rel` is not in bounds of WASM memory.
156+
/// - `out` is NULL or `out[..size_of::<u32>()]` is not in bounds of WASM memory.
157+
///
158+
/// # Errors
159+
///
160+
/// Returns an error:
161+
///
162+
/// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
163+
/// - `NO_SUCH_TABLE`, when `table_id` is not a known ID of a table.
164+
/// - `BSATN_DECODE_ERROR`, when `rel` cannot be decoded to `Vec<ProductValue>`
165+
/// where each `ProductValue` is typed at the `ProductType` the table's schema specifies.
166+
pub fn _datastore_delete_all_by_eq_bsatn(
167+
table_id: TableId,
168+
rel_ptr: *const u8,
169+
rel_len: usize,
170+
out: *mut u32,
171+
) -> u16;
157172

158173
/// Like [`_datastore_table_scan_bsatn`], start iteration on each row,
159174
/// as bytes, of a table identified by `table_id`.
@@ -200,7 +215,7 @@ pub mod raw {
200215
/// - `BUFFER_TOO_SMALL`, when there are rows left but they cannot fit in `buffer`.
201216
/// When this occurs, `buffer_len` is set to the size of the next item in the iterator.
202217
/// To make progress, the caller should reallocate the buffer to at least that size and try again.
203-
pub fn _row_iter_bsatn_advance(iter: RowIter, buffer: *mut u8, buffer_len: *mut usize) -> i16;
218+
pub fn _row_iter_bsatn_advance(iter: RowIter, buffer_ptr: *mut u8, buffer_len_ptr: *mut usize) -> i16;
204219

205220
/// Destroys the iterator registered under `iter`.
206221
///
@@ -538,17 +553,28 @@ unsafe fn call<T: Copy>(f: impl FnOnce(*mut T) -> u16) -> Result<T, Errno> {
538553
Ok(out.assume_init())
539554
}
540555

541-
/// Queries and returns the `table_id` associated with the given (table) `name`.
556+
/// Queries the `table_id` associated with the given (table) `name`.
557+
///
558+
/// The table id is returned.
559+
///
560+
/// # Errors
542561
///
543-
/// Returns an error if the table does not exist.
562+
/// Returns an error:
563+
///
564+
/// - `NO_SUCH_TABLE`, when `name` is not the name of a table.
544565
#[inline]
545566
pub fn table_id_from_name(name: &str) -> Result<TableId, Errno> {
546567
unsafe { call(|out| raw::_table_id_from_name(name.as_ptr(), name.len(), out)) }
547568
}
548569

549-
/// Queries and returns the number of rows in the table identified by `table_id`.
570+
/// Returns the number of rows currently in table identified by `table_id`.
571+
///
572+
/// # Errors
573+
///
574+
/// Returns an error:
550575
///
551-
/// Returns an error if the table does not exist or if not in a transaction.
576+
/// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
577+
/// - `NO_SUCH_TABLE`, when `table_id` is not a known ID of a table.
552578
#[inline]
553579
pub fn datastore_table_row_count(table_id: TableId) -> Result<u64, Errno> {
554580
unsafe { call(|out| raw::_datastore_table_row_count(table_id, out)) }
@@ -611,31 +637,34 @@ pub fn delete_by_col_eq(table_id: TableId, col_id: ColId, value: &[u8]) -> Resul
611637
}
612638

613639
/// Deletes those rows, in the table identified by `table_id`,
614-
/// that match any row in `relation`.
640+
/// that match any row in the byte string `relation`.
615641
///
616642
/// Matching is defined by first BSATN-decoding
617643
/// the byte string pointed to at by `relation` to a `Vec<ProductValue>`
618644
/// according to the row schema of the table
619645
/// and then using `Ord for AlgebraicValue`.
646+
/// A match happens when `Ordering::Equal` is returned from `fn cmp`.
647+
/// This occurs exactly when the row's BSATN-encoding is equal to the encoding of the `ProductValue`.
620648
///
621-
/// Returns the number of rows deleted.
649+
/// The number of rows deleted is returned.
622650
///
623-
/// Returns an error if
624-
/// - a table with the provided `table_id` doesn't exist
625-
/// - `(relation, relation_len)` doesn't decode from BSATN to a `Vec<ProductValue>`
651+
/// # Errors
652+
///
653+
/// Returns an error:
654+
///
655+
/// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
656+
/// - `NO_SUCH_TABLE`, when `table_id` is not a known ID of a table.
657+
/// - `BSATN_DECODE_ERROR`, when `rel` cannot be decoded to `Vec<ProductValue>`
658+
/// where each `ProductValue` is typed at the `ProductType` the table's schema specifies.
626659
#[inline]
627-
pub fn delete_by_rel(table_id: TableId, relation: &[u8]) -> Result<u32, Errno> {
628-
unsafe { call(|out| raw::_delete_by_rel(table_id, relation.as_ptr(), relation.len(), out)) }
660+
pub fn datastore_delete_all_by_eq_bsatn(table_id: TableId, relation: &[u8]) -> Result<u32, Errno> {
661+
unsafe { call(|out| raw::_datastore_delete_all_by_eq_bsatn(table_id, relation.as_ptr(), relation.len(), out)) }
629662
}
630663

631664
/// Starts iteration on each row, as BSATN-encoded, of a table identified by `table_id`.
632665
/// Returns iterator handle is written to the `out` pointer.
633666
/// This handle can be advanced by [`row_iter_bsatn_advance`].
634667
///
635-
/// # Traps
636-
///
637-
/// This function does not trap.
638-
///
639668
/// # Errors
640669
///
641670
/// Returns an error:

crates/bindings/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,14 @@ pub fn delete_by_col_eq(table_id: TableId, col_id: ColId, value: &impl Serialize
225225
/// Returns an error if
226226
/// - a table with the provided `table_id` doesn't exist
227227
/// - `(relation, relation_len)` doesn't decode from BSATN to a `Vec<ProductValue>`
228+
/// - this is called outside a transaction
228229
///
229230
/// Panics when serialization fails.
230231
pub fn delete_by_rel(table_id: TableId, relation: &[impl Serialize]) -> Result<u32> {
231232
with_row_buf(|bytes| {
232233
// Encode `value` as BSATN into `bytes` and then use that.
233234
bsatn::to_writer(bytes, relation).unwrap();
234-
sys::delete_by_rel(table_id, bytes)
235+
sys::datastore_delete_all_by_eq_bsatn(table_id, bytes)
235236
})
236237
}
237238

crates/core/src/host/instance_env.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,12 @@ impl InstanceEnv {
169169
/// where the rows match one in `relation`
170170
/// which is a bsatn encoding of `Vec<ProductValue>`.
171171
///
172-
/// Returns an error if no rows were deleted.
172+
/// Returns an error if
173+
/// - not in a transaction.
174+
/// - the table didn't exist.
175+
/// - a row couldn't be decoded to the table schema type.
173176
#[tracing::instrument(skip(self, relation))]
174-
pub fn delete_by_rel(&self, table_id: TableId, relation: &[u8]) -> Result<u32, NodesError> {
177+
pub fn datastore_delete_all_by_eq_bsatn(&self, table_id: TableId, relation: &[u8]) -> Result<u32, NodesError> {
175178
let stdb = &*self.dbic.relational_db;
176179
let tx = &mut *self.get_tx()?;
177180

crates/core/src/host/wasm_common.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub(super) type TimingSpanSet = ResourceSlab<TimingSpanIdx>;
320320
pub fn err_to_errno(err: &NodesError) -> Option<NonZeroU16> {
321321
match err {
322322
NodesError::NotInTransaction => Some(errno::NOT_IN_TRANSACTION),
323+
NodesError::DecodeRow(_) => Some(errno::BSATN_DECODE_ERROR),
323324
NodesError::TableNotFound => Some(errno::NO_SUCH_TABLE),
324325
NodesError::AlreadyExists(_) => Some(errno::UNIQUE_ALREADY_EXISTS),
325326
NodesError::Internal(internal) => match **internal {
@@ -351,12 +352,12 @@ macro_rules! abi_funcs {
351352
"spacetime_10.0"::datastore_table_scan_bsatn,
352353
"spacetime_10.0"::row_iter_bsatn_advance,
353354
"spacetime_10.0"::row_iter_bsatn_close,
355+
"spacetime_10.0"::datastore_delete_all_by_eq_bsatn,
354356
"spacetime_10.0"::bytes_source_read,
355357
"spacetime_10.0"::bytes_sink_write,
356358

357359
"spacetime_10.0"::console_log,
358360
"spacetime_10.0"::delete_by_col_eq,
359-
"spacetime_10.0"::delete_by_rel,
360361
"spacetime_10.0"::insert,
361362
"spacetime_10.0"::iter_by_col_eq,
362363
"spacetime_10.0"::iter_start_filtered,

crates/core/src/host/wasmtime/wasm_instance_env.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -417,37 +417,6 @@ impl WasmInstanceEnv {
417417
})
418418
}
419419

420-
/// Deletes those rows, in the table identified by `table_id`,
421-
/// that match any row in `relation`.
422-
///
423-
/// Matching is defined by first BSATN-decoding
424-
/// the byte string pointed to at by `relation` to a `Vec<ProductValue>`
425-
/// according to the row schema of the table
426-
/// and then using `Ord for AlgebraicValue`.
427-
///
428-
/// The number of rows deleted is written to the WASM pointer `out`.
429-
///
430-
/// Returns an error if
431-
/// - a table with the provided `table_id` doesn't exist
432-
/// - `(relation, relation_len)` doesn't decode from BSATN to a `Vec<ProductValue>`
433-
/// according to the `ProductValue` that the table's schema specifies for rows.
434-
/// - `relation + relation_len` overflows a 64-bit integer
435-
/// - writing to `out` would overflow a 32-bit integer
436-
#[tracing::instrument(skip_all)]
437-
pub fn delete_by_rel(
438-
caller: Caller<'_, Self>,
439-
table_id: u32,
440-
relation: WasmPtr<u8>,
441-
relation_len: u32,
442-
out: WasmPtr<u32>,
443-
) -> RtResult<u32> {
444-
Self::cvt_ret(caller, AbiCall::DeleteByRel, out, |caller| {
445-
let (mem, env) = Self::mem_env(caller);
446-
let relation = mem.deref_slice(relation, relation_len)?;
447-
Ok(env.instance_env.delete_by_rel(table_id.into(), relation)?)
448-
})
449-
}
450-
451420
/// Queries the `table_id` associated with the given (table) `name`
452421
/// where `name` is the UTF-8 slice in WASM memory at `name_ptr[..name_len]`.
453422
///
@@ -743,6 +712,49 @@ impl WasmInstanceEnv {
743712
})
744713
}
745714

715+
/// Deletes those rows, in the table identified by `table_id`,
716+
/// that match any row in the byte string `rel = rel_ptr[..rel_len]` in WASM memory.
717+
///
718+
/// Matching is defined by first BSATN-decoding
719+
/// the byte string pointed to at by `relation` to a `Vec<ProductValue>`
720+
/// according to the row schema of the table
721+
/// and then using `Ord for AlgebraicValue`.
722+
/// A match happens when `Ordering::Equal` is returned from `fn cmp`.
723+
/// This occurs exactly when the row's BSATN-encoding is equal to the encoding of the `ProductValue`.
724+
///
725+
/// The number of rows deleted is written to the WASM pointer `out`.
726+
///
727+
/// # Traps
728+
///
729+
/// Traps if:
730+
/// - `rel_ptr` is NULL or `rel` is not in bounds of WASM memory.
731+
/// - `out` is NULL or `out[..size_of::<u32>()]` is not in bounds of WASM memory.
732+
///
733+
/// # Errors
734+
///
735+
/// Returns an error:
736+
///
737+
/// - `NOT_IN_TRANSACTION`, when called outside of a transaction.
738+
/// - `NO_SUCH_TABLE`, when `table_id` is not a known ID of a table.
739+
/// - `BSATN_DECODE_ERROR`, when `rel` cannot be decoded to `Vec<ProductValue>`
740+
/// where each `ProductValue` is typed at the `ProductType` the table's schema specifies.
741+
#[tracing::instrument(skip_all)]
742+
pub fn datastore_delete_all_by_eq_bsatn(
743+
caller: Caller<'_, Self>,
744+
table_id: u32,
745+
rel_ptr: WasmPtr<u8>,
746+
rel_len: u32,
747+
out: WasmPtr<u32>,
748+
) -> RtResult<u32> {
749+
Self::cvt_ret(caller, AbiCall::DeleteByRel, out, |caller| {
750+
let (mem, env) = Self::mem_env(caller);
751+
let relation = mem.deref_slice(rel_ptr, rel_len)?;
752+
Ok(env
753+
.instance_env
754+
.datastore_delete_all_by_eq_bsatn(table_id.into(), relation)?)
755+
})
756+
}
757+
746758
pub fn volatile_nonatomic_schedule_immediate(
747759
mut caller: Caller<'_, Self>,
748760
name: WasmPtr<u8>,

crates/primitives/src/errno.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ macro_rules! errnos {
1010
$mac!(
1111
HOST_CALL_FAILURE(1, "ABI called by host returned an error"),
1212
NOT_IN_TRANSACTION(2, "ABI call can only be made while in a transaction"),
13+
BSATN_DECODE_ERROR(3, "Couldn't decode the BSATN to the expected type"),
1314
NO_SUCH_TABLE(4, "No such table"),
1415
NO_SUCH_ITER(6, "The provided row iterator is not valid"),
1516
NO_SUCH_BYTES(8, "The provided bytes source or sink is not valid"),

0 commit comments

Comments
 (0)