Skip to content

Commit

Permalink
WASM ABI: implement row_iter_bsatn_advance & row_iter_bsatn_close (
Browse files Browse the repository at this point in the history
  • Loading branch information
Centril authored Aug 27, 2024
1 parent c88a6ce commit 1dd1e63
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 148 deletions.
9 changes: 7 additions & 2 deletions crates/bindings-csharp/Runtime/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public class BufferTooSmallException : StdbException
public override string Message => "The provided buffer is not large enough to store the data";
}

public class NoSuchIterException : StdbException
{
public override string Message => "The provided row iterator does not exist";
}

public class NoSuchBytesException : StdbException
{
public override string Message => "The provided bytes source or sink does not exist";
Expand All @@ -39,9 +44,9 @@ public class NoSpaceException : StdbException

public class UnknownException : StdbException
{
private readonly FFI.Errno code;
private readonly Errno code;

internal UnknownException(FFI.Errno code) => this.code = code;
internal UnknownException(Errno code) => this.code = code;

public override string Message => $"SpacetimeDB error code {code}";
}
34 changes: 18 additions & 16 deletions crates/bindings-csharp/Runtime/Internal/FFI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ public readonly record struct BytesSource(uint Handle)
[StructLayout(LayoutKind.Sequential)]
public readonly record struct BytesSink(uint Handle) { }

public enum Errno : short
{
EXHAUSTED = -1,
OK = 0,
HOST_CALL_FAILURE = 1,
NO_SUCH_TABLE = 4,
LOOKUP_NOT_FOUND = 2,
NO_SUCH_ITER = 6,
NO_SUCH_BYTES = 8,
NO_SPACE = 9,
BUFFER_TOO_SMALL = 11,
UNIQUE_ALREADY_EXISTS = 12,
}

#pragma warning disable IDE1006 // Naming Styles - Not applicable to FFI stuff.
internal static partial class FFI
{
Expand All @@ -32,18 +46,6 @@ internal static partial class FFI
#endif
;

public enum Errno : ushort
{
OK = 0,
HOST_CALL_FAILURE = 1,
NO_SUCH_TABLE = 4,
LOOKUP_NOT_FOUND = 2,
NO_SUCH_BYTES = 8,
NO_SPACE = 9,
BUFFER_TOO_SMALL = 11,
UNIQUE_ALREADY_EXISTS = 12,
}

[NativeMarshalling(typeof(Marshaller))]
public struct CheckedStatus
{
Expand Down Expand Up @@ -108,7 +110,7 @@ public readonly struct LogLevel(byte log_level)
[StructLayout(LayoutKind.Sequential)]
public readonly record struct RowIter(uint Handle)
{
public static readonly RowIter INVALID = new(uint.MaxValue);
public static readonly RowIter INVALID = new(0);
}

[LibraryImport(StdbNamespace)]
Expand Down Expand Up @@ -159,14 +161,14 @@ out RowIter out_
);

[LibraryImport(StdbNamespace)]
public static partial CheckedStatus _iter_advance(
public static partial Errno _row_iter_bsatn_advance(
RowIter iter_handle,
[MarshalUsing(CountElementName = nameof(buffer_len))] [Out] byte[] buffer,
ref uint buffer_len
);

[LibraryImport(StdbNamespace)]
public static partial void _iter_drop(RowIter iter_handle);
public static partial CheckedStatus _row_iter_bsatn_close(RowIter iter_handle);

[LibraryImport(StdbNamespace)]
public static partial void _volatile_nonatomic_schedule_immediate(
Expand All @@ -189,7 +191,7 @@ uint message_len
);

[LibraryImport(StdbNamespace)]
public static partial short _bytes_source_read(
public static partial Errno _bytes_source_read(
BytesSource source,
Span<byte> buffer,
ref uint buffer_len
Expand Down
44 changes: 33 additions & 11 deletions crates/bindings-csharp/Runtime/Internal/ITable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,53 @@ public class Enumerator(FFI.RowIter handle) : IDisposable

public bool MoveNext()
{
if (handle == FFI.RowIter.INVALID)
{
return false;
}

uint buffer_len;
while (true)
{
buffer_len = (uint)buffer.Length;
try
var ret = FFI._row_iter_bsatn_advance(handle, buffer, ref buffer_len);
if (ret == Errno.EXHAUSTED)
{
FFI._iter_advance(handle, buffer, ref buffer_len);
handle = FFI.RowIter.INVALID;
}
catch (BufferTooSmallException)
// On success, the only way `buffer_len == 0` is for the iterator to be exhausted.
// This happens when the host iterator was empty from the start.
System.Diagnostics.Debug.Assert(!(ret == Errno.OK && buffer_len == 0));
switch (ret)
{
buffer = new byte[buffer_len];
continue;
// Iterator advanced and may also be `EXHAUSTED`.
// When `OK`, we'll need to advance the iterator in the next call to `MoveNext`.
// In both cases, copy over the row data to `Current` from the scratch `buffer`.
case Errno.EXHAUSTED
or Errno.OK:
Current = new byte[buffer_len];
Array.Copy(buffer, 0, Current, 0, buffer_len);
return buffer_len != 0;
// Couldn't find the iterator, error!
case Errno.NO_SUCH_ITER:
throw new NoSuchIterException();
// The scratch `buffer` is too small to fit a row / chunk.
// Grow `buffer` and try again.
// The `buffer_len` will have been updated with the necessary size.
case Errno.BUFFER_TOO_SMALL:
buffer = new byte[buffer_len];
continue;
default:
throw new UnknownException(ret);
}
break;
}
Current = new byte[buffer_len];
Array.Copy(buffer, 0, Current, 0, buffer_len);
return buffer_len != 0;
}

public void Dispose()
{
if (!handle.Equals(FFI.RowIter.INVALID))
if (handle != FFI.RowIter.INVALID)
{
FFI._iter_drop(handle);
FFI._row_iter_bsatn_close(handle);
handle = FFI.RowIter.INVALID;
// Avoid running ~RowIter if Dispose was executed successfully.
GC.SuppressFinalize(this);
Expand Down
16 changes: 8 additions & 8 deletions crates/bindings-csharp/Runtime/Internal/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,24 +238,24 @@ private static byte[] Consume(this BytesSource source)
switch (ret)
{
// Host side source exhausted, we're done.
case -1:
case Errno.EXHAUSTED:
Array.Resize(ref buffer, (int)written);
return buffer;
// Wrote the entire spare capacity.
// Need to reserve more space in the buffer.
case 0 when written == buffer.Length:
case Errno.OK when written == buffer.Length:
Array.Resize(ref buffer, buffer.Length + 1024);
break;
// Host didn't write as much as possible.
// Try to read some more.
// The host will likely not trigger this branch (current host doesn't),
// but a module should be prepared for it.
case 0:
case Errno.OK:
break;
case (short)(ushort)FFI.Errno.NO_SUCH_BYTES:
case Errno.NO_SUCH_BYTES:
throw new NoSuchBytesException();
default:
throw new UnknownException((FFI.Errno)(ushort)ret);
throw new UnknownException(ret);
}
}
}
Expand Down Expand Up @@ -291,7 +291,7 @@ public static void __describe_module__(BytesSink description)
}
}

public static short __call_reducer__(
public static Errno __call_reducer__(
uint id,
ulong sender_0,
ulong sender_1,
Expand Down Expand Up @@ -323,14 +323,14 @@ BytesSink error
{
throw new Exception("Unrecognised extra bytes in the reducer arguments");
}
return 0; /* no exception */
return Errno.OK; /* no exception */
}
catch (Exception e)
{
var error_str = e.ToString();
var error_bytes = System.Text.Encoding.UTF8.GetBytes(error_str);
error.Write(error_bytes);
return (short)(ushort)FFI.Errno.HOST_CALL_FAILURE;
return Errno.HOST_CALL_FAILURE;
}
}
}
8 changes: 4 additions & 4 deletions crates/bindings-csharp/Runtime/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ IMPORT(Status, _iter_start_filtered,
(TableId table_id, const uint8_t* filter, uint32_t filter_len,
RowIter* iter),
(table_id, filter, filter_len, iter));
IMPORT(Status, _iter_advance,
(RowIter iter, uint8_t* buffer, size_t* buffer_len),
(iter, buffer, buffer_len));
IMPORT(void, _iter_drop, (RowIter iter), (iter));
IMPORT(int16_t, _row_iter_bsatn_advance,
(RowIter iter, uint8_t* buffer_ptr, size_t* buffer_len_ptr),
(iter, buffer_ptr, buffer_len_ptr));
IMPORT(uint16_t, _row_iter_bsatn_close, (RowIter iter), (iter));
IMPORT(void, _volatile_nonatomic_schedule_immediate,
(const uint8_t* name, size_t name_len, const uint8_t* args, size_t args_len),
(name, name_len, args, args_len));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
<UnmanagedEntryPointsAssembly Include="SpacetimeDB.Runtime" />
<WasmImport Include="$(SpacetimeNamespace)!_console_log" />
<WasmImport Include="$(SpacetimeNamespace)!_get_table_id" />
<WasmImport Include="$(SpacetimeNamespace)!_create_index" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_by_col_eq" />
<WasmImport Include="$(SpacetimeNamespace)!_insert" />
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_col_eq" />
<WasmImport Include="$(SpacetimeNamespace)!_delete_by_rel" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_start" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_start_filtered" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_next" />
<WasmImport Include="$(SpacetimeNamespace)!_iter_drop" />
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_advance" />
<WasmImport Include="$(SpacetimeNamespace)!_row_iter_bsatn_close" />
<WasmImport Include="$(SpacetimeNamespace)!_bytes_source_read" />
<WasmImport Include="$(SpacetimeNamespace)!_bytes_sink_write" />

Expand Down
Loading

2 comments on commit 1dd1e63

@github-actions
Copy link

@github-actions github-actions bot commented on 1dd1e63 Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarking failed. Please check the workflow run for details.

@github-actions
Copy link

@github-actions github-actions bot commented on 1dd1e63 Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarking failed. Please check the workflow run for details.

Please sign in to comment.