Skip to content

Commit 1dd1e63

Browse files
authored
WASM ABI: implement row_iter_bsatn_advance & row_iter_bsatn_close (#1622)
1 parent c88a6ce commit 1dd1e63

File tree

15 files changed

+291
-148
lines changed

15 files changed

+291
-148
lines changed

crates/bindings-csharp/Runtime/Exceptions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public class BufferTooSmallException : StdbException
2727
public override string Message => "The provided buffer is not large enough to store the data";
2828
}
2929

30+
public class NoSuchIterException : StdbException
31+
{
32+
public override string Message => "The provided row iterator does not exist";
33+
}
34+
3035
public class NoSuchBytesException : StdbException
3136
{
3237
public override string Message => "The provided bytes source or sink does not exist";
@@ -39,9 +44,9 @@ public class NoSpaceException : StdbException
3944

4045
public class UnknownException : StdbException
4146
{
42-
private readonly FFI.Errno code;
47+
private readonly Errno code;
4348

44-
internal UnknownException(FFI.Errno code) => this.code = code;
49+
internal UnknownException(Errno code) => this.code = code;
4550

4651
public override string Message => $"SpacetimeDB error code {code}";
4752
}

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

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ public readonly record struct BytesSource(uint Handle)
1818
[StructLayout(LayoutKind.Sequential)]
1919
public readonly record struct BytesSink(uint Handle) { }
2020

21+
public enum Errno : short
22+
{
23+
EXHAUSTED = -1,
24+
OK = 0,
25+
HOST_CALL_FAILURE = 1,
26+
NO_SUCH_TABLE = 4,
27+
LOOKUP_NOT_FOUND = 2,
28+
NO_SUCH_ITER = 6,
29+
NO_SUCH_BYTES = 8,
30+
NO_SPACE = 9,
31+
BUFFER_TOO_SMALL = 11,
32+
UNIQUE_ALREADY_EXISTS = 12,
33+
}
34+
2135
#pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff.
2236
internal static partial class FFI
2337
{
@@ -32,18 +46,6 @@ internal static partial class FFI
3246
#endif
3347
;
3448

35-
public enum Errno : ushort
36-
{
37-
OK = 0,
38-
HOST_CALL_FAILURE = 1,
39-
NO_SUCH_TABLE = 4,
40-
LOOKUP_NOT_FOUND = 2,
41-
NO_SUCH_BYTES = 8,
42-
NO_SPACE = 9,
43-
BUFFER_TOO_SMALL = 11,
44-
UNIQUE_ALREADY_EXISTS = 12,
45-
}
46-
4749
[NativeMarshalling(typeof(Marshaller))]
4850
public struct CheckedStatus
4951
{
@@ -108,7 +110,7 @@ public readonly struct LogLevel(byte log_level)
108110
[StructLayout(LayoutKind.Sequential)]
109111
public readonly record struct RowIter(uint Handle)
110112
{
111-
public static readonly RowIter INVALID = new(uint.MaxValue);
113+
public static readonly RowIter INVALID = new(0);
112114
}
113115

114116
[LibraryImport(StdbNamespace)]
@@ -159,14 +161,14 @@ out RowIter out_
159161
);
160162

161163
[LibraryImport(StdbNamespace)]
162-
public static partial CheckedStatus _iter_advance(
164+
public static partial Errno _row_iter_bsatn_advance(
163165
RowIter iter_handle,
164166
[MarshalUsing(CountElementName = nameof(buffer_len))] [Out] byte[] buffer,
165167
ref uint buffer_len
166168
);
167169

168170
[LibraryImport(StdbNamespace)]
169-
public static partial void _iter_drop(RowIter iter_handle);
171+
public static partial CheckedStatus _row_iter_bsatn_close(RowIter iter_handle);
170172

171173
[LibraryImport(StdbNamespace)]
172174
public static partial void _volatile_nonatomic_schedule_immediate(
@@ -189,7 +191,7 @@ uint message_len
189191
);
190192

191193
[LibraryImport(StdbNamespace)]
192-
public static partial short _bytes_source_read(
194+
public static partial Errno _bytes_source_read(
193195
BytesSource source,
194196
Span<byte> buffer,
195197
ref uint buffer_len

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

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,53 @@ public class Enumerator(FFI.RowIter handle) : IDisposable
2222

2323
public bool MoveNext()
2424
{
25+
if (handle == FFI.RowIter.INVALID)
26+
{
27+
return false;
28+
}
29+
2530
uint buffer_len;
2631
while (true)
2732
{
2833
buffer_len = (uint)buffer.Length;
29-
try
34+
var ret = FFI._row_iter_bsatn_advance(handle, buffer, ref buffer_len);
35+
if (ret == Errno.EXHAUSTED)
3036
{
31-
FFI._iter_advance(handle, buffer, ref buffer_len);
37+
handle = FFI.RowIter.INVALID;
3238
}
33-
catch (BufferTooSmallException)
39+
// On success, the only way `buffer_len == 0` is for the iterator to be exhausted.
40+
// This happens when the host iterator was empty from the start.
41+
System.Diagnostics.Debug.Assert(!(ret == Errno.OK && buffer_len == 0));
42+
switch (ret)
3443
{
35-
buffer = new byte[buffer_len];
36-
continue;
44+
// Iterator advanced and may also be `EXHAUSTED`.
45+
// When `OK`, we'll need to advance the iterator in the next call to `MoveNext`.
46+
// In both cases, copy over the row data to `Current` from the scratch `buffer`.
47+
case Errno.EXHAUSTED
48+
or Errno.OK:
49+
Current = new byte[buffer_len];
50+
Array.Copy(buffer, 0, Current, 0, buffer_len);
51+
return buffer_len != 0;
52+
// Couldn't find the iterator, error!
53+
case Errno.NO_SUCH_ITER:
54+
throw new NoSuchIterException();
55+
// The scratch `buffer` is too small to fit a row / chunk.
56+
// Grow `buffer` and try again.
57+
// The `buffer_len` will have been updated with the necessary size.
58+
case Errno.BUFFER_TOO_SMALL:
59+
buffer = new byte[buffer_len];
60+
continue;
61+
default:
62+
throw new UnknownException(ret);
3763
}
38-
break;
3964
}
40-
Current = new byte[buffer_len];
41-
Array.Copy(buffer, 0, Current, 0, buffer_len);
42-
return buffer_len != 0;
4365
}
4466

4567
public void Dispose()
4668
{
47-
if (!handle.Equals(FFI.RowIter.INVALID))
69+
if (handle != FFI.RowIter.INVALID)
4870
{
49-
FFI._iter_drop(handle);
71+
FFI._row_iter_bsatn_close(handle);
5072
handle = FFI.RowIter.INVALID;
5173
// Avoid running ~RowIter if Dispose was executed successfully.
5274
GC.SuppressFinalize(this);

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,24 +238,24 @@ private static byte[] Consume(this BytesSource source)
238238
switch (ret)
239239
{
240240
// Host side source exhausted, we're done.
241-
case -1:
241+
case Errno.EXHAUSTED:
242242
Array.Resize(ref buffer, (int)written);
243243
return buffer;
244244
// Wrote the entire spare capacity.
245245
// Need to reserve more space in the buffer.
246-
case 0 when written == buffer.Length:
246+
case Errno.OK when written == buffer.Length:
247247
Array.Resize(ref buffer, buffer.Length + 1024);
248248
break;
249249
// Host didn't write as much as possible.
250250
// Try to read some more.
251251
// The host will likely not trigger this branch (current host doesn't),
252252
// but a module should be prepared for it.
253-
case 0:
253+
case Errno.OK:
254254
break;
255-
case (short)(ushort)FFI.Errno.NO_SUCH_BYTES:
255+
case Errno.NO_SUCH_BYTES:
256256
throw new NoSuchBytesException();
257257
default:
258-
throw new UnknownException((FFI.Errno)(ushort)ret);
258+
throw new UnknownException(ret);
259259
}
260260
}
261261
}
@@ -291,7 +291,7 @@ public static void __describe_module__(BytesSink description)
291291
}
292292
}
293293

294-
public static short __call_reducer__(
294+
public static Errno __call_reducer__(
295295
uint id,
296296
ulong sender_0,
297297
ulong sender_1,
@@ -323,14 +323,14 @@ BytesSink error
323323
{
324324
throw new Exception("Unrecognised extra bytes in the reducer arguments");
325325
}
326-
return 0; /* no exception */
326+
return Errno.OK; /* no exception */
327327
}
328328
catch (Exception e)
329329
{
330330
var error_str = e.ToString();
331331
var error_bytes = System.Text.Encoding.UTF8.GetBytes(error_str);
332332
error.Write(error_bytes);
333-
return (short)(ushort)FFI.Errno.HOST_CALL_FAILURE;
333+
return Errno.HOST_CALL_FAILURE;
334334
}
335335
}
336336
}

crates/bindings-csharp/Runtime/bindings.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ IMPORT(Status, _iter_start_filtered,
6565
(TableId table_id, const uint8_t* filter, uint32_t filter_len,
6666
RowIter* iter),
6767
(table_id, filter, filter_len, iter));
68-
IMPORT(Status, _iter_advance,
69-
(RowIter iter, uint8_t* buffer, size_t* buffer_len),
70-
(iter, buffer, buffer_len));
71-
IMPORT(void, _iter_drop, (RowIter iter), (iter));
68+
IMPORT(int16_t, _row_iter_bsatn_advance,
69+
(RowIter iter, uint8_t* buffer_ptr, size_t* buffer_len_ptr),
70+
(iter, buffer_ptr, buffer_len_ptr));
71+
IMPORT(uint16_t, _row_iter_bsatn_close, (RowIter iter), (iter));
7272
IMPORT(void, _volatile_nonatomic_schedule_immediate,
7373
(const uint8_t* name, size_t name_len, const uint8_t* args, size_t args_len),
7474
(name, name_len, args, args_len));

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
<UnmanagedEntryPointsAssembly Include="SpacetimeDB.Runtime" />
66
<WasmImport Include="$(SpacetimeNamespace)!_console_log" />
77
<WasmImport Include="$(SpacetimeNamespace)!_get_table_id" />
8-
<WasmImport Include="$(SpacetimeNamespace)!_create_index" />
98
<WasmImport Include="$(SpacetimeNamespace)!_iter_by_col_eq" />
109
<WasmImport Include="$(SpacetimeNamespace)!_insert" />
1110
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_col_eq" />
1211
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_rel" />
1312
<WasmImport Include="$(SpacetimeNamespace)!_iter_start" />
1413
<WasmImport Include="$(SpacetimeNamespace)!_iter_start_filtered" />
15-
<WasmImport Include="$(SpacetimeNamespace)!_iter_next" />
16-
<WasmImport Include="$(SpacetimeNamespace)!_iter_drop" />
14+
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_advance" />
15+
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_close" />
1716
<WasmImport Include="$(SpacetimeNamespace)!_bytes_source_read" />
1817
<WasmImport Include="$(SpacetimeNamespace)!_bytes_sink_write" />
1918

0 commit comments

Comments
 (0)