Installation

Plugins add behavior to the embedded library. Install the core library before selecting plugins.

Included plugins

PluginNamePurpose
Adaptive query planneradaptive_query_plannerLearn from query runs and compare alternative plans
ReactorsreactorsRun live mutations after commits
History retentionhistoryPurge history according to retention settings
Object storeobjectsStore binary payloads as named files and directories
BackupsbackupsCopy history and object payloads to local folders and S3-compatible storage, and recover from them
SDK generationsdkGenerate typed language APIs from stored definitions

The library's plugins operation lists the plugins it can use and their requirements. The coming soon list describes prototype features that are not available in this library.

FormPlugin setFilesChange the set
Plugin libraryOne shared library per plugin beside the core libraryThe plugin libraries in lib/<os>_<arch>/Use the plugin libraries from the same release as the core library
Compiled into the coreChosen when the core library is builtNoneRebuild the core library
Static archiveEvery plugin in the release, linked into your programNoneRelink with the static archive of another release

Release packages ship the adaptive planner, Reactors, SDK generation, the object store and backups as plugin libraries. History retention is compiled into the core library. The static archive in the same package contains all these plugins. In all three forms, a database enables plugins when it opens, as described in Enable plugins.

Plugin libraries

A release package keeps each platform's shared core library and plugin libraries together in that platform's directory, lib/<os>_<arch>/:

FileLinuxmacOSWindows
Core librarylibstardust.solibstardust.dylibstardust.dll
Plugin library, one per pluginlibstardust_<name>.solibstardust_<name>.dylibstardust_<name>.dll

Keep these files together, in the directory of the core library, and use them only with the release they came with. The core library looks for plugin libraries only in its own directory, the first time a call needs the plugin list. Opening a database, listing plugins and checking a license can trigger this scan. The bindings need no separate discovery setting.

Verification

The release build records each finished plugin library's SHA-256 in the core library. The core library accepts only the plugin libraries it was built with:

  1. It carries a SHA-256 for the plugin named by the file.
  2. The file's SHA-256 equals that value.
  3. The plugin library is from the same build and exports the plugin entry under its own name.

The core library reads the file once, checks its SHA-256, and loads the bytes that it checked. On Linux it loads the file through its open descriptor. On Windows it keeps the file open without write sharing until it loads. On macOS it keeps the file open and relies on the library's code signature.

Check the release download with minisign, as described in Verify the download. Each binding checks the core library's SHA-256. The core then checks its plugin libraries. See Load the core for the binding check. These checks detect a mismatched, corrupted, or replaced plugin library.

Available and unavailable plugins

A plugin library is available only after it passes every check. Missing libraries and failed checks make the plugin unavailable. Selecting an unavailable plugin causes database open to fail.

The plugins operation lists each available plugin with its name, description, version, requirements, willNotWorkWith, definition types, hooks, index providers, and database hooks. After them, it lists each unavailable plugin library as an object with name, file, and unavailable, which states the reason:

ReasonCause
This core library was not built with the plugin libraryThe file is not part of this release
The plugin library differs from the one this core library was built withThe file changed after the release was built
The plugin library cannot be loadedThe platform loader refused the file
The plugin library has no plugin entryThe file is not a Stardust plugin library
The plugin library is from another buildThe file came with a different release
The plugin library's name differs from its plugin nameThe file was renamed
A plugin with this name is already includedThe core library already contains that plugin
The plugin library's plugin is invalidThe plugin description is not usable

Development builds

Contributors who build the library from source can compile a development core library that loads plugin libraries without checking their SHA-256. This switch exists only at compile time, for development. Release packaging refuses a library built with it. Release libraries always check their plugin libraries.

Plugins compiled into the core

A plugin compiled into the core library is part of that library file. It needs no plugin library file or SHA-256 check, and it is always available to databases. The plugins that a core library contains are chosen when it is built, so changing them requires rebuilding the core library.

Go, Rust, Odin and C programs can link the static archive (libstardust_full.a, or stardust_full.lib on Windows) instead of the shared core library. Linking gives the commands. The archive contains the core and every plugin of its release, compiled in. The plugin set is fixed when you link your program. The backups plugin in the archive carries its own Zstandard copy under stardust_-prefixed symbol names, so your program can also link its own libzstd.

  • Ship only your executable. A static program uses no core library, no plugin libraries and no SHA-256 checks.
  • A static program does not look for plugin libraries. Plugin library files beside the executable have no effect.
  • To use the plugins of another release, link your program again with that release's static archive.
  • Each database still enables plugins when it opens, as described in Enable plugins. The license plugins permission applies as it does for the shared library.

Check the download with minisign before you link the archive, as described in Verify the download. The bindings do not check the SHA-256 of a statically linked core: it is part of your executable.

Enable plugins

Use the plugins database option when opening a database. It works the same way for plugin libraries, plugins compiled into the core, and static links. Selection applies until the database closes. Only named plugins are enabled.

SelectionResult
Omit pluginsEnable no plugins
Empty object, {}Enable no plugins
Object, such as {reactors {}}Enable the named plugins with their load settings
An unknown nameThe open fails with invalid_argument

Each object key is a plugin name. Its value is a settings object. An empty settings object uses the plugin's defaults. Select only available plugins. Include each selected plugin's required dependencies in the object. The willNotWorkWith list names plugins that cannot be enabled together. If either plugin lists the other, opening the database fails with invalid_argument before configuration or storage changes. A plugin in this list can be absent from the library or disabled. Unknown settings and invalid values fail before the database opens. The adaptive planner accepts memoryShare. The history plugin accepts scheduling settings, backups accepts its targets, and SDK generation accepts language output settings. The reactors and objects plugins accept only empty settings. A disabled plugin does not install its database hooks, definition types, or index providers. A write that sets stardust/history reports unavailable when the database does not enable history. A write that sets stardust/object/digest reports unavailable when the database does not enable objects.

Plugin operations

A plugin serves named operations through two calls:

CallInputResult
plugin_callRequest documentResult document
plugin_streamRequest documentByte stream, such as an object upload

Bindings provide typed wrappers for the supported operations. Each wrapper builds a request and calls the same underlying operation. A disabled plugin reports unavailable. An unknown operation reports invalid_argument with code unknown_operation. Plugins name their runtime description status and their wait for committed work sync, when they offer them.

Plugin boundary

All plugins are first-party plugins from the Stardust project. The plugin entry that a plugin library exports is internal to Stardust: it is not part of the C ABI, and the bindings do not call it. There is no interface for third-party plugins.

Operations

OperationReturnsSummary
stardust_db_plugin_callStatus. document through outputdatabase.plugin_call(plugin, operation, request) runs a named operation of an enabled plugin and returns its owned result document.
stardust_db_plugin_stream_openStatus. plugin_stream through outputdatabase.plugin_stream(plugin, operation, request) opens an owned plugin stream of a named stream operation.
stardust_db_plugin_stream_writeStatus. count through outputplugin_stream.write(data) appends bytes to the stream and returns the count accepted.
stardust_db_plugin_stream_readStatus. text through outputplugin_stream.read(length) returns up to length bytes from the stream's position and advances it.
stardust_db_plugin_stream_seekStatus. integer through outputplugin_stream.seek(offset, whence) moves the stream's position and returns it.
stardust_db_plugin_stream_finishStatus. document through outputplugin_stream.finish() ends the stream and returns its owned result document.
stardust_db_plugin_stream_releasevoidRelease the plugin_stream handle, ending an unfinished stream without finishing it.

stardust_db_plugin_call

c164 B
uint32_t stardust_db_plugin_call(stardust_db *db, stardust_bytes plugin_name, stardust_bytes operation, const stardust_document *request, stardust_result **output);
c92 B
uint32_t stardust_result_take_document(stardust_result *result, stardust_document **output);
c96 B
uint32_t stardust_result_error(const stardust_result *result, stardust_diagnostic_view *output);
c54 B
void stardust_result_release(stardust_result *result);

Parameters

stardust_db_plugin_call

ParameterTypeOwnershipDefaultMeaning
dbstardust_db *Borrowed handleRequiredKeep the handle alive until the call returns.
plugin_namestardust_bytesValueRequiredValue passed to the call.
operationstardust_bytesValueRequiredThe plugin's call operation.
requestconst stardust_document *Borrowed handleNULLThe borrowed request document. Its absence reads as an empty object.
outputstardust_result **Owned outputRequiredReceives a library-owned handle. Release it after use.

stardust_result_take_document

ParameterTypeOwnershipDefaultMeaning
resultstardust_result *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_document **Owned outputRequiredReceives a library-owned handle. Release it after use.

stardust_result_error

ParameterTypeOwnershipDefaultMeaning
resultconst stardust_result *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_diagnostic_view *Caller-owned outputRequiredReceives a record. Its pointer fields follow the record's ownership contract.

stardust_result_release

ParameterTypeOwnershipDefaultMeaning
resultstardust_result *Consumed handleNULLEnds ownership. Do not use the handle after this call.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTa name is empty, the plugin has no call operation with the name, or the plugin refuses the request
STARDUST_UNAVAILABLEthe plugin is unknown or the database does not enable it
STARDUST_NOT_FOUNDthe plugin reports that the request names nothing it holds
STARDUST_CONFLICTthe plugin's write lost to a concurrent change, or the database holds writes
STARDUST_EVALUATION_FAILEDthe plugin cannot read its stored state
STARDUST_FAILEDthe plugin's work failed
STARDUST_TIMEOUTthe plugin's wait passed its limit
STARDUST_CLOSEDthe database is closed
STARDUST_OUT_OF_MEMORYnative memory is exhausted

Notes

The plugin decodes the request and builds the result. A result is null when the operation returns nothing. Returned documents omit empty object and array members recursively; empty roots, array elements and scalar values remain. Each plugin documents its operations: object store, reactors and SDK generation.

Examples

Wait for live mutations, then describe them

c1.1 kB
const stardust_bytes reactors = {(const uint8_t *)"reactors", sizeof("reactors") - 1};
const char options_text[] = "{maxWait {#dur PT5S}}";
stardust_document *options = NULL;
stardust_result *synced = NULL;
stardust_result *described = NULL;
uint32_t status = stardust_parse((stardust_bytes){(const uint8_t *)options_text, sizeof(options_text) - 1}, STARDUST_DUST, &options);
// sync returns a null document.
if (status == STARDUST_OK) status = stardust_db_plugin_call(db, reactors, (stardust_bytes){(const uint8_t *)"sync", 4}, options, &synced);
stardust_result_release(synced);
stardust_document_release(options);
// A NULL request reads as an empty object.
if (status == STARDUST_OK) status = stardust_db_plugin_call(db, reactors, (stardust_bytes){(const uint8_t *)"status", 6}, NULL, &described);
if (status != STARDUST_OK) { stardust_result_release(described); return status; }
stardust_document *result = NULL;
status = stardust_result_take_document(described, &result);
stardust_result_release(described);
if (status != STARDUST_OK) return status;
Result / 88 B
{:value {:enabled true
         :cursor  4
         :head    4
         :pending false}}

Also calls: stardust_result_take_document, stardust_result_error, stardust_result_release

stardust_db_plugin_stream_open

c207 B
uint32_t stardust_db_plugin_stream_open(stardust_db *db, stardust_bytes plugin_name, stardust_bytes operation, const stardust_document *request, stardust_db_plugin_stream **stream, stardust_result **output);
c96 B
uint32_t stardust_result_error(const stardust_result *result, stardust_diagnostic_view *output);
c54 B
void stardust_result_release(stardust_result *result);

Parameters

stardust_db_plugin_stream_open

ParameterTypeOwnershipDefaultMeaning
dbstardust_db *Borrowed handleRequiredKeep the handle alive until the call returns.
plugin_namestardust_bytesValueRequiredValue passed to the call.
operationstardust_bytesValueRequiredThe plugin's stream operation.
requestconst stardust_document *Borrowed handleNULLThe borrowed request document. Its absence reads as an empty object.
streamstardust_db_plugin_stream **Owned outputRequiredReceives a library-owned handle. Release it after use.
outputstardust_result **Owned outputRequiredReceives a library-owned handle. Release it after use.

stardust_result_error

ParameterTypeOwnershipDefaultMeaning
resultconst stardust_result *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_diagnostic_view *Caller-owned outputRequiredReceives a record. Its pointer fields follow the record's ownership contract.

stardust_result_release

ParameterTypeOwnershipDefaultMeaning
resultstardust_result *Consumed handleNULLEnds ownership. Do not use the handle after this call.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTa name is empty, the plugin has no stream operation with the name, or the plugin refuses the request
STARDUST_UNAVAILABLEthe plugin is unknown or the database does not enable it
STARDUST_NOT_FOUNDthe plugin reports that the request names nothing it holds
STARDUST_CONFLICTthe database holds writes
STARDUST_EVALUATION_FAILEDthe plugin cannot read its stored state
STARDUST_CLOSEDthe database is closed
STARDUST_OUT_OF_MEMORYnative memory is exhausted

Notes

A stream supports the steps its operation documents. Each plugin documents its stream operations: object store.

Examples

Upload a payload and publish it

c1.2 kB
stardust_db_plugin_stream *upload = NULL;
stardust_result *output = NULL;
const char first[] = "Hello, ";
const char second[] = "objects";
int64_t written = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, (stardust_bytes){(const uint8_t *)"objects", sizeof("objects") - 1}, (stardust_bytes){(const uint8_t *)"upload", sizeof("upload") - 1}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)first, sizeof(first) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)second, sizeof(second) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_finish(upload, &output);
// Release abandons the upload unless it finished.
stardust_db_plugin_stream_release(upload);
stardust_document *result = NULL;
if (status == STARDUST_OK) status = stardust_result_take_document(output, &result);
stardust_result_release(output);
if (status != STARDUST_OK) {stardust_document_release(result); return status;}
Result / 157 B
{:value {:digest       {:#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}
         :size         14
         :deduplicated false}}

Also calls: stardust_result_error, stardust_result_release

stardust_db_plugin_stream_write

c115 B
uint32_t stardust_db_plugin_stream_write(stardust_db_plugin_stream *stream, stardust_bytes data, int64_t *written);

Requires exclusive use of the receiver handle.

Parameters

ParameterTypeOwnershipDefaultMeaning
streamstardust_db_plugin_stream *Borrowed handleRequiredKeep the handle alive until the call returns.
datastardust_bytesValueRequiredThe bytes to append, borrowed for the call.
writtenint64_t *Caller-owned outputRequiredReceives the scalar result.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTthe stream has finished or does not accept writes
STARDUST_CONFLICTthe database holds writes while the plugin stores the bytes
STARDUST_CLOSEDthe parent database is closed

Notes

A failure also reports the count accepted before it, returned together with the error. Those bytes stay part of the stream; continue with the remaining bytes.

Examples

Append bytes to an upload

c760 B
stardust_db_plugin_stream *upload = NULL;
const char payload[] = "Hello, objects";
int64_t result = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, (stardust_bytes){(const uint8_t *)"objects", sizeof("objects") - 1}, (stardust_bytes){(const uint8_t *)"upload", sizeof("upload") - 1}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
// result counts the accepted bytes, also on failure.
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)payload, sizeof(payload) - 1}, &result);
stardust_db_plugin_stream_release(upload);
if (status != STARDUST_OK) return status;
Result / 11 B
{:value 14}

stardust_db_plugin_stream_read

c128 B
uint32_t stardust_db_plugin_stream_read(stardust_db_plugin_stream *stream, uint8_t *buffer, int64_t capacity, int64_t *written);

Requires exclusive use of the receiver handle.

Parameters

ParameterTypeOwnershipDefaultMeaning
streamstardust_db_plugin_stream *Borrowed handleRequiredKeep the handle alive until the call returns.
bufferuint8_t *Caller-owned arrayNULLWrites at most capacity elements and reports their count in written.
capacityint64_tValueRequiredValue passed to the call.
writtenint64_t *Caller-owned outputRequiredReceives the scalar result.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTthe stream does not support reads, or length is negative
STARDUST_EVALUATION_FAILEDstored bytes do not match their digest
STARDUST_CLOSEDthe parent database is closed

Notes

A read is shorter than length only at the end, and empty at or past it.

Examples

Read the start of a payload

c1.7 kB
const stardust_bytes objects = {(const uint8_t *)"objects", sizeof("objects") - 1};
stardust_db_plugin_stream *upload = NULL;
stardust_result *published = NULL;
const char payload[] = "Hello, objects";
int64_t written = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, objects, (stardust_bytes){(const uint8_t *)"upload", 6}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)payload, sizeof(payload) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_finish(upload, &published);
stardust_result_release(published);
stardust_db_plugin_stream_release(upload);
if (status != STARDUST_OK) return status;
const char request_text[] = "{digest \"95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb\"}";
stardust_document *request = NULL;
stardust_db_plugin_stream *reader = NULL;
status = stardust_parse((stardust_bytes){(const uint8_t *)request_text, sizeof(request_text) - 1}, STARDUST_DUST, &request);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_open(db, objects, (stardust_bytes){(const uint8_t *)"open", 4}, request, &reader, &opened);
stardust_result_release(opened);
opened = NULL;
stardust_document_release(request);
uint8_t buffer[5];
int64_t result = 0;
// The call copies straight into the caller's buffer; buffer holds "Hello".
if (status == STARDUST_OK) status = stardust_db_plugin_stream_read(reader, buffer, sizeof(buffer), &result);
stardust_db_plugin_stream_release(reader);
if (status != STARDUST_OK) return status;
Result / 10 B
{:value 5}

stardust_db_plugin_stream_seek

c127 B
uint32_t stardust_db_plugin_stream_seek(stardust_db_plugin_stream *stream, int64_t offset, uint32_t whence, int64_t *position);

Requires exclusive use of the receiver handle.

Parameters

ParameterTypeOwnershipDefaultMeaning
streamstardust_db_plugin_stream *Borrowed handleRequiredKeep the handle alive until the call returns.
offsetint64_tValueRequiredThe distance from whence, negative toward the start.
whenceuint32_tValueRequired0 for the start, 1 for the current position, 2 for the end.
positionint64_t *Caller-owned outputRequiredReceives the scalar result.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTthe stream does not support seeks, whence is unknown, or the position is negative or past the i64 range
STARDUST_CLOSEDthe parent database is closed

Notes

whence 0 counts offset from the start, 1 from the current position and 2 from the end. A refused seek keeps the position.

Examples

Seek from the end of a payload

c1.7 kB
const stardust_bytes objects = {(const uint8_t *)"objects", sizeof("objects") - 1};
stardust_db_plugin_stream *upload = NULL;
stardust_result *published = NULL;
const char payload[] = "Hello, objects";
int64_t written = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, objects, (stardust_bytes){(const uint8_t *)"upload", 6}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)payload, sizeof(payload) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_finish(upload, &published);
stardust_result_release(published);
stardust_db_plugin_stream_release(upload);
if (status != STARDUST_OK) return status;
const char request_text[] = "{digest \"95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb\"}";
stardust_document *request = NULL;
stardust_db_plugin_stream *reader = NULL;
status = stardust_parse((stardust_bytes){(const uint8_t *)request_text, sizeof(request_text) - 1}, STARDUST_DUST, &request);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_open(db, objects, (stardust_bytes){(const uint8_t *)"open", 4}, request, &reader, &opened);
stardust_result_release(opened);
opened = NULL;
stardust_document_release(request);
int64_t position = 0;
// whence 2 counts from the end, so -7 is the start of "objects".
if (status == STARDUST_OK) status = stardust_db_plugin_stream_seek(reader, -7, 2, &position);
stardust_db_plugin_stream_release(reader);
if (status != STARDUST_OK) return status;
int64_t result = position;
Result / 10 B
{:value 7}

stardust_db_plugin_stream_finish

c103 B
uint32_t stardust_db_plugin_stream_finish(stardust_db_plugin_stream *stream, stardust_result **output);
c92 B
uint32_t stardust_result_take_document(stardust_result *result, stardust_document **output);
c96 B
uint32_t stardust_result_error(const stardust_result *result, stardust_diagnostic_view *output);
c54 B
void stardust_result_release(stardust_result *result);

Requires exclusive use of the receiver handle.

Parameters

stardust_db_plugin_stream_finish

ParameterTypeOwnershipDefaultMeaning
streamstardust_db_plugin_stream *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_result **Owned outputRequiredReceives a library-owned handle. Release it after use.

stardust_result_take_document

ParameterTypeOwnershipDefaultMeaning
resultstardust_result *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_document **Owned outputRequiredReceives a library-owned handle. Release it after use.

stardust_result_error

ParameterTypeOwnershipDefaultMeaning
resultconst stardust_result *Borrowed handleRequiredKeep the handle alive until the call returns.
outputstardust_diagnostic_view *Caller-owned outputRequiredReceives a record. Its pointer fields follow the record's ownership contract.

stardust_result_release

ParameterTypeOwnershipDefaultMeaning
resultstardust_result *Consumed handleNULLEnds ownership. Do not use the handle after this call.

Errors

StatusWhen
STARDUST_INVALID_ARGUMENTthe stream has finished or has no finish step
STARDUST_CONFLICTthe database holds writes
STARDUST_CLOSEDthe parent database is closed
STARDUST_OUT_OF_MEMORYnative memory is exhausted

Notes

A failed finish keeps the stream, so finish can be retried. Close the stream separately.

Examples

Publish the same payload twice

c1.8 kB
// The second finish reports deduplicated true and stores nothing new.
stardust_db_plugin_stream *upload = NULL;
stardust_result *published = NULL;
const char payload[] = "Hello, objects";
int64_t written = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, (stardust_bytes){(const uint8_t *)"objects", sizeof("objects") - 1}, (stardust_bytes){(const uint8_t *)"upload", sizeof("upload") - 1}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)payload, sizeof(payload) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_finish(upload, &published);
stardust_result_release(published);
stardust_db_plugin_stream_release(upload);
if (status != STARDUST_OK) return status;
stardust_result *output = NULL;
upload = NULL;
status = stardust_db_plugin_stream_open(db, (stardust_bytes){(const uint8_t *)"objects", sizeof("objects") - 1}, (stardust_bytes){(const uint8_t *)"upload", sizeof("upload") - 1}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)payload, sizeof(payload) - 1}, &written);
if (status == STARDUST_OK) status = stardust_db_plugin_stream_finish(upload, &output);
stardust_db_plugin_stream_release(upload);
stardust_document *result = NULL;
if (status == STARDUST_OK) status = stardust_result_take_document(output, &result);
stardust_result_release(output);
if (status != STARDUST_OK) {stardust_document_release(result); return status;}
Result / 156 B
{:value {:digest       {:#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}
         :size         14
         :deduplicated true}}

Also calls: stardust_result_take_document, stardust_result_error, stardust_result_release

stardust_db_plugin_stream_release

c74 B
void stardust_db_plugin_stream_release(stardust_db_plugin_stream *stream);

Consumes the receiver handle.

Parameters

ParameterTypeOwnershipDefaultMeaning
streamstardust_db_plugin_stream *Consumed handleNULLEnds ownership. Do not use the handle after this call.

Notes

Close waits only for a call already in progress on the stream; start no other call once close begins. It is valid after the database closes. A plugin documents what close abandons; the object store reclaims an upload stage at the next open when close could not abandon it.

Examples

Abandon an unfinished upload

c739 B
stardust_db_plugin_stream *upload = NULL;
const char draft[] = "draft";
int64_t written = 0;
// The open result carries a refusal's diagnostic; release it either way.
stardust_result *opened = NULL;
uint32_t status = stardust_db_plugin_stream_open(db, (stardust_bytes){(const uint8_t *)"objects", sizeof("objects") - 1}, (stardust_bytes){(const uint8_t *)"upload", sizeof("upload") - 1}, NULL, &upload, &opened);
stardust_result_release(opened);
opened = NULL;
if (status == STARDUST_OK) status = stardust_db_plugin_stream_write(upload, (stardust_bytes){(const uint8_t *)draft, sizeof(draft) - 1}, &written);
// Releasing before finish publishes nothing.
stardust_db_plugin_stream_release(upload);
if (status != STARDUST_OK) return status;