Object store

The objects plugin stores binary payloads in the database file and names them in a tree of files and directories. Enable it at open with plugins {objects {}}. It has no settings. See plugin selection for the open options. Calls without it report the unavailable status.

The typed wrappers use plugin_call or plugin_stream with plugin objects. Request members use lowerCamelCase, such as expectedRevision.

Payloads

A payload is an immutable byte sequence. Its digest is the SHA-256 of all its bytes. Write a payload through an upload stream: write appends bytes in order and finish publishes the payload atomically. Equal bytes publish one payload: a second finish of the same bytes reports deduplicated true and stores nothing new. The database splits payloads into content-defined chunks of 256 KiB to 4 MiB, so edits to a large payload share most chunks with earlier versions. manifest lists the chunks, and an open stream reads any byte range: seek moves its position and read copies from it.

Published payloads are never deleted. Removing a file or pointing it at another payload keeps the earlier payload, and history keeps every earlier version of the file. An upload that does not finish publishes nothing. Closing the stream abandons it, and the next open removes what an interrupted upload left behind.

Each upload holds a working buffer of up to 4 MiB from the database memory budget until it finishes or closes. An upload that cannot fit reports out_of_memory. Calls on one stream are serialized; separate streams can run at the same time.

Digests cross the API as 64 hexadecimal digits in either case. Results show them as {#sha256 <hex>} values.

Files and directories

Every node lives under the root directory, entity 0. A directory holds named children; a file names one published payload. Names are non-empty UTF-8 text without / or NUL, and are not . or ... Names are unique within a directory and hold at most 4096 bytes.

A record describes one node:

MemberValue
entityThe node's entity.
parentThe parent directory's entity, 0 for the root.
nameThe node's name in its parent.
kindfile or directory.
revisionThe transaction that last changed the node.
sizeA file's payload size in bytes.
digestA file's payload digest.

create creates up to 4096 nodes in one commit. A node names its parent by entity, or with under by the position of an earlier directory in the same request:

TRON219 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
044C 6E616D65txt "name"
095C 6E6F746573txt "notes"
0F0F 0A 04000000 0900 0000map leaf, size 10: @4 → @9
197C 23736861323536txt "#sha256"
2114 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
630F 0A 19000000 2100 0000map leaf, size 10: @19 → @21
6D5C 756E646572txt "under"
7302 01000000000000 00i64 1
7C0F 0A 6D000000 7300 0000map leaf, size 10: @6D → @73
866C 646967657374txt "digest"
8D0F 0A 86000000 6300 0000map leaf, size 10: @86 → @63
974C 6E616D65txt "name"
9C9C 68656C6C6F2E74 7874txt "hello.txt"
A60F 0A 97000000 9C00 0000map leaf, size 10: @97 → @9C
B007 12 04820000 7C00 0000 8D000000 A600 0000map branch, size 18, depth 0 (root), slots 2, 9, 15: @7C → @8D → @A6
C20E 11 00 0300 020000 00 0F000000 B00000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @F → @B0

A file can name only a published payload. A merge patch can also write stardust/object/digest on an entity; the commit then needs a published payload too.

Revisions

Each write commits atomically through the commit queue. A refused write changes nothing. update, move and remove take an expected revision. Pass the revision of a record you read to refuse the write when another writer changed the node since: the call reports conflict. Pass 0 to skip the check. An update to the current payload, or a move to the current name and parent, changes nothing and keeps the revision.

With replace true, a move can replace a destination node of the same kind. A file replaces a file. A directory replaces only an empty directory. Remove deletes a file or an empty directory.

Reads

Every tree read uses one snapshot of the database. Concurrent writes do not change a read in progress. children lists a directory in name order. path returns the names from the root to a node. files finds the files that hold a payload. A stream read verifies every chunk it reads against its digest and reports evaluation_failed when stored bytes do not match.

Without the plugin

On a database that does not enable objects, a write that sets stardust/object/digest fails with the unavailable status and the code plugin_required. Payloads and files that the plugin stored stay in the database file and return when the plugin is enabled again.

Operations

OperationReturnsSummary
Objects::getdocumentobjects.get(entity) returns the owned record document of an object file or directory.
Objects::lookupdocumentobjects.lookup(parent, name) returns the owned record document of a directory's child.
Objects::childrendocumentobjects.children(parent) returns an owned array document of a directory's child records in name order.
Objects::pathdocumentobjects.path(entity) returns an owned array document of the names from the root to an object node.
Objects::filesdocumentobjects.files(digest) returns an owned ascending array document of the file entities that hold a payload.
Objects::manifestdocumentobjects.manifest(digest) returns a published payload's owned manifest document.
Objects::createdocumentobjects.create(nodes) creates files and directories in one commit and returns an owned array document of their records.
Objects::updatedocumentobjects.update(entity, digest, expected_revision) points a file at another published payload and returns its owned record document.
Objects::movedocumentobjects.move(entity, parent, name, expected_revision, replace) renames or moves a node and returns its owned record document.
Objects::removenoneobjects.remove(entity, expected_revision) removes a file or an empty directory.
Objects::uploadplugin_streamobjects.upload() opens an owned plugin stream that uploads one payload.
Objects::openplugin_streamobjects.open(digest) opens an owned plugin stream that reads a published payload.

Objects::get

rust50 B
pub fn get(&self, entity: i64) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
entityi64ValueRequiredThe node's entity.

Errors

StatusWhen
Status::INVALID_ARGUMENTentity is not a user entity
Status::NOT_FOUNDno object node has the entity
Status::EVALUATION_FAILEDstored tree metadata or the manifest of a named payload is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

Read the record of a file

rust326 B
let mut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();
let nodes = stardust::parse(r#"[{name hello.txt digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#, Format::DUST)?;
db.objects().create(&nodes)?;
let result = db.objects().get(1)?;
TRON316 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0047C 23736861323536txt "#sha256"
00C14 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
04E0F 0A 04000000 0C00 0000map leaf, size 10: @4 → @C
0586C 656E74697479txt "entity"
05F02 01000000000000 00i64 1
0680F 0A 58000000 5F00 0000map leaf, size 10: @58 → @5F
0724C 6B696E64txt "kind"
0774C 66696C65txt "file"
07C0F 0A 72000000 7700 0000map leaf, size 10: @72 → @77
0864C 73697A65txt "size"
08B02 0E000000000000 00i64 14
0940F 0A 86000000 8B00 0000map leaf, size 10: @86 → @8B
09E8C 7265766973696F 6Etxt "revision"
0A702 02000000000000 00i64 2
0B00F 0A 9E000000 A700 0000map leaf, size 10: @9E → @A7
0BA6C 706172656E74txt "parent"
0C102 00000000000000 00i64 0
0CA0F 0A BA000000 C100 0000map leaf, size 10: @BA → @C1
0D407 0E 00120000 B000 0000 CA000000map branch, size 14, depth 2, slots 9, 12: @B0 → @CA
0E207 0E 04010000 9400 0000 D4000000map branch, size 14, depth 1, slots 2, 8: @94 → @D4
0F06C 646967657374txt "digest"
0F70F 0A F0000000 4E00 0000map leaf, size 10: @F0 → @4E
1014C 6E616D65txt "name"
1069C 68656C6C6F2E74 7874txt "hello.txt"
1100F 0A 01010000 0601 0000map leaf, size 10: @101 → @106
11A07 1A 30830000 6800 0000 7C000000 E200 0000 F7000000 1001 0000map branch, size 26, depth 0 (root), slots 4, 5, 8, 9, 15: @68 → @7C → @E2 → @F7 → @110

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::lookup

rust65 B
pub fn lookup(&self, parent: i64, name: &str) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
parenti64ValueRequiredThe directory's entity. 0 selects the root.
name&strValueRequiredThe child's name.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe parent or the name is invalid, or the parent is a file
Status::NOT_FOUNDthe parent has no child with the name, or the parent does not exist
Status::EVALUATION_FAILEDstored tree metadata or the manifest of a named payload is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

Find a child of the root by name

rust154 B
db.objects().create(&stardust::parse("[{name notes}]", Format::DUST)?)?;
// Entity 0 is the root directory.
let result = db.objects().lookup(0, "notes")?;
TRON184 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
046C 656E74697479txt "entity"
0B02 01000000000000 00i64 1
140F 0A 04000000 0B00 0000map leaf, size 10: @4 → @B
1E4C 6B696E64txt "kind"
239C 6469726563746F 7279txt "directory"
2D0F 0A 1E000000 2300 0000map leaf, size 10: @1E → @23
378C 7265766973696F 6Etxt "revision"
4002 02000000000000 00i64 2
490F 0A 37000000 4000 0000map leaf, size 10: @37 → @40
536C 706172656E74txt "parent"
5A02 00000000000000 00i64 0
630F 0A 53000000 5A00 0000map leaf, size 10: @53 → @5A
6D07 0E 00120000 4900 0000 63000000map branch, size 14, depth 2, slots 9, 12: @49 → @63
7B07 0A 00010000 6D00 0000map branch, size 10, depth 1, slots 8: @6D
854C 6E616D65txt "name"
8A5C 6E6F746573txt "notes"
900F 0A 85000000 8A00 0000map leaf, size 10: @85 → @8A
9A07 16 30810000 1400 0000 2D000000 7B00 0000 90000000map branch, size 22, depth 0 (root), slots 4, 5, 8, 15: @14 → @2D → @7B → @90

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::children

rust55 B
pub fn children(&self, parent: i64) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
parenti64ValueRequiredThe directory's entity. 0 selects the root.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe parent is invalid or is a file
Status::NOT_FOUNDthe parent does not exist
Status::EVALUATION_FAILEDstored tree metadata or the manifest of a named payload is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

List the root directory

rust126 B
db.objects().create(&stardust::parse("[{name notes} {name drafts}]", Format::DUST)?)?;
let result = db.objects().children(0)?;
TRON374 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0046C 656E74697479txt "entity"
00B02 02000000000000 00i64 2
0140F 0A 04000000 0B00 0000map leaf, size 10: @4 → @B
01E4C 6B696E64txt "kind"
0239C 6469726563746F 7279txt "directory"
02D0F 0A 1E000000 2300 0000map leaf, size 10: @1E → @23
0378C 7265766973696F 6Etxt "revision"
04002 03000000000000 00i64 3
0490F 0A 37000000 4000 0000map leaf, size 10: @37 → @40
0536C 706172656E74txt "parent"
05A02 00000000000000 00i64 0
0630F 0A 53000000 5A00 0000map leaf, size 10: @53 → @5A
06D07 0E 00120000 4900 0000 63000000map branch, size 14, depth 2, slots 9, 12: @49 → @63
07B07 0A 00010000 6D00 0000map branch, size 10, depth 1, slots 8: @6D
0854C 6E616D65txt "name"
08A6C 647261667473txt "drafts"
0910F 0A 85000000 8A00 0000map leaf, size 10: @85 → @8A
09B07 16 30810000 1400 0000 2D000000 7B00 0000 91000000map branch, size 22, depth 0 (root), slots 4, 5, 8, 15: @14 → @2D → @7B → @91
0B16C 656E74697479txt "entity"
0B802 01000000000000 00i64 1
0C10F 0A B1000000 B800 0000map leaf, size 10: @B1 → @B8
0CB4C 6B696E64txt "kind"
0D09C 6469726563746F 7279txt "directory"
0DA0F 0A CB000000 D000 0000map leaf, size 10: @CB → @D0
0E48C 7265766973696F 6Etxt "revision"
0ED02 03000000000000 00i64 3
0F60F 0A E4000000 ED00 0000map leaf, size 10: @E4 → @ED
1006C 706172656E74txt "parent"
10702 00000000000000 00i64 0
1100F 0A 00010000 0701 0000map leaf, size 10: @100 → @107
11A07 0E 00120000 F600 0000 10010000map branch, size 14, depth 2, slots 9, 12: @F6 → @110
12807 0A 00010000 1A01 0000map branch, size 10, depth 1, slots 8: @11A
1324C 6E616D65txt "name"
1375C 6E6F746573txt "notes"
13D0F 0A 32010000 3701 0000map leaf, size 10: @132 → @137
14707 16 30810000 C100 0000 DA000000 2801 0000 3D010000map branch, size 22, depth 0 (root), slots 4, 5, 8, 15: @C1 → @DA → @128 → @13D
15D0E 11 00 0300 020000 00 9B000000 470100 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @9B → @147

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::path

rust51 B
pub fn path(&self, entity: i64) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
entityi64ValueRequiredThe node's entity. 0 selects the root, whose path is empty.

Errors

StatusWhen
Status::INVALID_ARGUMENTentity is not a user entity
Status::NOT_FOUNDthe node or one of its ancestors does not exist
Status::EVALUATION_FAILEDstored tree metadata or the manifest of a named payload is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

Read the path of a nested directory

rust130 B
db.objects().create(&stardust::parse("[{name notes} {name drafts under 1}]", Format::DUST)?)?;
let result = db.objects().path(2)?;
TRON42 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
045C 6E6F746573txt "notes"
0A6C 647261667473txt "drafts"
110E 11 00 0300 020000 00 04000000 0A0000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @4 → @A

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::files

rust53 B
pub fn files(&self, digest: &str) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
digest&strValueRequiredThe payload's SHA-256 digest as 64 hexadecimal digits.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe digest is not 64 hexadecimal digits
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

Find the files that hold a payload

rust497 B
let mut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();
let nodes = stardust::parse(
    r#"[{name a.txt digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}} {name b.txt digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#,
    Format::DUST,
)?;
db.objects().create(&nodes)?;
let result = db.objects().files("95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb")?;
TRON47 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
0402 01000000000000 00i64 1
0D02 02000000000000 00i64 2
160E 11 00 0300 020000 00 04000000 0D0000 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @4 → @D

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::manifest

rust56 B
pub fn manifest(&self, digest: &str) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
digest&strValueRequiredThe payload's SHA-256 digest as 64 hexadecimal digits.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe digest is not 64 hexadecimal digits
Status::NOT_FOUNDno payload with the digest is published
Status::EVALUATION_FAILEDthe stored manifest is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

The manifest is {digest size chunks}. chunks lists {digest size} in byte order and is omitted for an empty payload.

Examples

Read the manifest of a published payload

rust213 B
let mut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();
let result = db.objects().manifest("95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb")?;
TRON324 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0047C 23736861323536txt "#sha256"
00C14 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
04E0F 0A 04000000 0C00 0000map leaf, size 10: @4 → @C
0587C 23736861323536txt "#sha256"
06014 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
0A20F 0A 58000000 6000 0000map leaf, size 10: @58 → @60
0AC4C 73697A65txt "size"
0B102 0E000000000000 00i64 14
0BA0F 0A AC000000 B100 0000map leaf, size 10: @AC → @B1
0C46C 646967657374txt "digest"
0CB0F 0A C4000000 A200 0000map leaf, size 10: @C4 → @A2
0D507 0E 00030000 BA00 0000 CB000000map branch, size 14, depth 0 (root), slots 8, 9: @BA → @CB
0E30E 0D 00 0100 010000 00 D5000000array leaf, size 13, shift 0, bitmap 0001, count 1 (root): @D5
0F04C 73697A65txt "size"
0F502 0E000000000000 00i64 14
0FE0F 0A F0000000 F500 0000map leaf, size 10: @F0 → @F5
1086C 646967657374txt "digest"
10F0F 0A 08010000 4E00 0000map leaf, size 10: @108 → @4E
1196C 6368756E6B73txt "chunks"
1200F 0A 19010000 E300 0000map leaf, size 10: @119 → @E3
12A07 12 00070000 FE00 0000 0F010000 2001 0000map branch, size 18, depth 0 (root), slots 8, 9, 10: @FE → @10F → @120

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::create

rust58 B
pub fn create(&self, nodes: &Document) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
nodes&DocumentBorrowed for the callRequiredA borrowed array of at most 4096 nodes. Each has name, and parent (entity, default 0) or under (one-based position of an earlier directory). A file also has digest {#sha256 hex}. Without digest, the node is a directory.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe array is empty or malformed, a name is invalid, or a parent is a file
Status::NOT_FOUNDa parent does not exist or a digest is not published
Status::CONFLICTa name is already taken in its parent or appears twice, or the database holds writes
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

Nodes are created in order. A node names its parent by entity, or by the one-based position of an earlier directory in the same array with under.

Examples

Create a directory and a file in one commit

rust387 B
let mut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();
// under 1 places hello.txt in the first node of the request.
let nodes = stardust::parse(r#"[{name notes} {name hello.txt under 1 digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#, Format::DUST)?;
let result = db.objects().create(&nodes)?;
TRON505 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0046C 656E74697479txt "entity"
00B02 01000000000000 00i64 1
0140F 0A 04000000 0B00 0000map leaf, size 10: @4 → @B
01E4C 6B696E64txt "kind"
0239C 6469726563746F 7279txt "directory"
02D0F 0A 1E000000 2300 0000map leaf, size 10: @1E → @23
0378C 7265766973696F 6Etxt "revision"
04002 03000000000000 00i64 3
0490F 0A 37000000 4000 0000map leaf, size 10: @37 → @40
0536C 706172656E74txt "parent"
05A02 00000000000000 00i64 0
0630F 0A 53000000 5A00 0000map leaf, size 10: @53 → @5A
06D07 0E 00120000 4900 0000 63000000map branch, size 14, depth 2, slots 9, 12: @49 → @63
07B07 0A 00010000 6D00 0000map branch, size 10, depth 1, slots 8: @6D
0854C 6E616D65txt "name"
08A5C 6E6F746573txt "notes"
0900F 0A 85000000 8A00 0000map leaf, size 10: @85 → @8A
09A07 16 30810000 1400 0000 2D000000 7B00 0000 90000000map branch, size 22, depth 0 (root), slots 4, 5, 8, 15: @14 → @2D → @7B → @90
0B07C 23736861323536txt "#sha256"
0B814 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
0FA0F 0A B0000000 B800 0000map leaf, size 10: @B0 → @B8
1046C 656E74697479txt "entity"
10B02 02000000000000 00i64 2
1140F 0A 04010000 0B01 0000map leaf, size 10: @104 → @10B
11E4C 6B696E64txt "kind"
1234C 66696C65txt "file"
1280F 0A 1E010000 2301 0000map leaf, size 10: @11E → @123
1324C 73697A65txt "size"
13702 0E000000000000 00i64 14
1400F 0A 32010000 3701 0000map leaf, size 10: @132 → @137
14A8C 7265766973696F 6Etxt "revision"
15302 03000000000000 00i64 3
15C0F 0A 4A010000 5301 0000map leaf, size 10: @14A → @153
1666C 706172656E74txt "parent"
16D02 01000000000000 00i64 1
1760F 0A 66010000 6D01 0000map leaf, size 10: @166 → @16D
18007 0E 00120000 5C01 0000 76010000map branch, size 14, depth 2, slots 9, 12: @15C → @176
18E07 0E 04010000 4001 0000 80010000map branch, size 14, depth 1, slots 2, 8: @140 → @180
19C6C 646967657374txt "digest"
1A30F 0A 9C010000 FA00 0000map leaf, size 10: @19C → @FA
1AD4C 6E616D65txt "name"
1B29C 68656C6C6F2E74 7874txt "hello.txt"
1BC0F 0A AD010000 B201 0000map leaf, size 10: @1AD → @1B2
1C607 1A 30830000 1401 0000 28010000 8E01 0000 A3010000 BC01 0000map branch, size 26, depth 0 (root), slots 4, 5, 8, 9, 15: @114 → @128 → @18E → @1A3 → @1BC
1E00E 11 00 0300 020000 00 9A000000 C60100 00array leaf, size 17, shift 0, bitmap 0003, count 2 (root): @9A → @1C6

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::update

rust91 B
pub fn update(&self, entity: i64, digest: &str, expected_revision: i64) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
entityi64ValueRequiredThe file's entity.
digest&strValueRequiredThe payload's SHA-256 digest as 64 hexadecimal digits.
expected_revisioni64ValueRequiredThe transaction that last touched the node, from its record. 0 skips the check.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe entity is a directory or invalid, the digest is malformed, or expected_revision is negative
Status::NOT_FOUNDthe file does not exist or the digest is not published
Status::CONFLICTexpected_revision is stale, or the database holds writes
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Examples

Point a file at a new payload

rust528 B
for text in [&b"Hello, objects"[..], &b"Revised notes"[..]] {
    let mut upload = db.objects().upload()?;
    upload.write(text)?;
    upload.finish()?;
}
let nodes = stardust::parse(r#"[{name hello.txt digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#, Format::DUST)?;
db.objects().create(&nodes)?;
// 0 skips the revision check; pass a record's revision to refuse a stale write.
let result = db.objects().update(1, "2b6d3a4299dac5900171112d4fd569b48e54711d8937f6ff5ca00528d47afad2", 0)?;
TRON316 B
Offset (hex)Bytes (hex)Meaning
00054 52 4F 4Emagic TRON
0047C 23736861323536txt "#sha256"
00C14 40 326236643361 3432393964616335 3930303137313131 3264346664353639 6234386535343731 3164383933376636 6666356361303035 3238643437616661 6432txt "2b6d3a4299dac5900171112d…"
04E0F 0A 04000000 0C00 0000map leaf, size 10: @4 → @C
0586C 656E74697479txt "entity"
05F02 01000000000000 00i64 1
0680F 0A 58000000 5F00 0000map leaf, size 10: @58 → @5F
0724C 6B696E64txt "kind"
0774C 66696C65txt "file"
07C0F 0A 72000000 7700 0000map leaf, size 10: @72 → @77
0864C 73697A65txt "size"
08B02 0D000000000000 00i64 13
0940F 0A 86000000 8B00 0000map leaf, size 10: @86 → @8B
09E8C 7265766973696F 6Etxt "revision"
0A702 03000000000000 00i64 3
0B00F 0A 9E000000 A700 0000map leaf, size 10: @9E → @A7
0BA6C 706172656E74txt "parent"
0C102 00000000000000 00i64 0
0CA0F 0A BA000000 C100 0000map leaf, size 10: @BA → @C1
0D407 0E 00120000 B000 0000 CA000000map branch, size 14, depth 2, slots 9, 12: @B0 → @CA
0E207 0E 04010000 9400 0000 D4000000map branch, size 14, depth 1, slots 2, 8: @94 → @D4
0F06C 646967657374txt "digest"
0F70F 0A F0000000 4E00 0000map leaf, size 10: @F0 → @4E
1014C 6E616D65txt "name"
1069C 68656C6C6F2E74 7874txt "hello.txt"
1100F 0A 01010000 0601 0000map leaf, size 10: @101 → @106
11A07 1A 30830000 6800 0000 7C000000 E200 0000 F7000000 1001 0000map branch, size 26, depth 0 (root), slots 4, 5, 8, 9, 15: @68 → @7C → @E2 → @F7 → @110

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::move

rust117 B
pub fn r#move(&self, entity: i64, parent: i64, name: &str, expected_revision: i64, replace: bool) -> Result<Document>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
entityi64ValueRequiredThe node to move.
parenti64ValueRequiredThe destination directory. 0 selects the root.
name&strValueRequiredThe node's new name.
expected_revisioni64ValueRequiredThe transaction that last touched the node, from its record. 0 skips the check.
replaceboolValueRequiredReplace an existing node of the same kind at the destination. False reports conflict for an occupied name.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe request is malformed, the destination is a file or inside the node, the kinds differ, or a replaced directory is not empty
Status::NOT_FOUNDthe node or the destination does not exist
Status::CONFLICTthe name is occupied without replace, expected_revision is stale, or the database holds writes
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

With replace, a node of the same kind at the destination is replaced; a directory only when it is empty. A move into the node's own subtree is invalid.

Examples

Move a directory into another

rust210 B
db.objects().create(&stardust::parse("[{name notes} {name drafts}]", Format::DUST)?)?;
// false refuses to replace a node that already has the name.
let result = db.objects().r#move(2, 1, "archive", 0, false)?;
TRON186 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
046C 656E74697479txt "entity"
0B02 02000000000000 00i64 2
140F 0A 04000000 0B00 0000map leaf, size 10: @4 → @B
1E4C 6B696E64txt "kind"
239C 6469726563746F 7279txt "directory"
2D0F 0A 1E000000 2300 0000map leaf, size 10: @1E → @23
378C 7265766973696F 6Etxt "revision"
4002 04000000000000 00i64 4
490F 0A 37000000 4000 0000map leaf, size 10: @37 → @40
536C 706172656E74txt "parent"
5A02 01000000000000 00i64 1
630F 0A 53000000 5A00 0000map leaf, size 10: @53 → @5A
6D07 0E 00120000 4900 0000 63000000map branch, size 14, depth 2, slots 9, 12: @49 → @63
7B07 0A 00010000 6D00 0000map branch, size 10, depth 1, slots 8: @6D
854C 6E616D65txt "name"
8A7C 61726368697665txt "archive"
920F 0A 85000000 8A00 0000map leaf, size 10: @85 → @8A
9C07 16 30810000 1400 0000 2D000000 7B00 0000 92000000map branch, size 22, depth 0 (root), slots 4, 5, 8, 15: @14 → @2D → @7B → @92

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::remove

rust71 B
pub fn remove(&self, entity: i64, expected_revision: i64) -> Result<()>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
entityi64ValueRequiredThe node to remove.
expected_revisioni64ValueRequiredThe transaction that last touched the node, from its record. 0 skips the check.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe entity is invalid, the directory is not empty, or expected_revision is negative
Status::NOT_FOUNDthe node does not exist
Status::CONFLICTexpected_revision is stale, or the database holds writes
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

The payload stays published.

Examples

Remove an empty directory

rust101 B
db.objects().create(&stardust::parse("[{name drafts}]", Format::DUST)?)?;
db.objects().remove(1, 0)?;

C exports: stardust_db_plugin_call, stardust_result_take_document, stardust_result_error, stardust_result_release

Objects::upload

rust44 B
pub fn upload(&self) -> Result<PluginStream>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.

Errors

StatusWhen
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CONFLICTthe database holds writes
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

The stream holds a working buffer of up to 4 MiB from the database memory budget until it finishes or closes. Write appends bytes; finish publishes the payload and returns {digest size deduplicated}.

Examples

Upload a payload and publish it

rust269 B
// Dropping the upload abandons it unless it finished.
let mut upload = db.objects().upload()?;
// The upload stream implements std::io::Write, so std::io::copy can stream into it.
std::io::copy(&mut &b"Hello, objects"[..], &mut upload)?;
let result = upload.finish()?;
TRON189 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
047C 23736861323536txt "#sha256"
0C14 40 393565383464 6133386362656664 6633663966366566 3032323031303734 6337333132346637 6366323032356433 6531643639653539 3161343130383536 6662txt "95e84da38cbefdf3f9f6ef02…"
4E0F 0A 04000000 0C00 0000map leaf, size 10: @4 → @C
584C 73697A65txt "size"
5D02 0E000000000000 00i64 14
660F 0A 58000000 5D00 0000map leaf, size 10: @58 → @5D
706C 646967657374txt "digest"
770F 0A 70000000 4E00 0000map leaf, size 10: @70 → @4E
81CC 64656475706C69 6361746564txt "deduplicated"
8E01bit false
8F0F 0A 81000000 8E00 0000map leaf, size 10: @81 → @8E
9907 0E 00440000 7700 0000 8F000000map branch, size 14, depth 1, slots 10, 14: @77 → @8F
A707 0E 00030000 6600 0000 99000000map branch, size 14, depth 0 (root), slots 8, 9: @66 → @99

C exports: stardust_db_plugin_stream_open, stardust_result_error, stardust_result_release

Objects::open

rust56 B
pub fn open(&self, digest: &str) -> Result<PluginStream>

Parameters

ParameterTypeOwnershipDefaultMeaning
self&SelfBorrowed for the callRequiredThe objects owner for this operation. Keep it alive during the call.
digest&strValueRequiredThe payload's SHA-256 digest as 64 hexadecimal digits.

Errors

StatusWhen
Status::INVALID_ARGUMENTthe digest is not 64 hexadecimal digits
Status::NOT_FOUNDno payload with the digest is published
Status::EVALUATION_FAILEDthe stored manifest is corrupted
Status::UNAVAILABLEthe database does not enable the objects plugin
Status::CLOSEDthe database is closed
Status::OUT_OF_MEMORYnative memory is exhausted

Notes

Read copies bytes from the position and verifies each chunk it touches; seek moves the position, from the end with the payload size. The reader charges its state to the database memory budget until it is released or the database closes.

Examples

Read a range of a payload

rust409 B
let mut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();
let mut reader = db.objects().open("95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb")?;
// The reader also implements std::io::Read and std::io::Seek.
reader.seek(7, 0)?;
let mut data = [0u8; 7];
let read = reader.read(&mut data)?;
// data holds b"objects".
let result = read as i64;
TRON21 B
Offset (hex)Bytes (hex)Meaning
0054 52 4F 4Emagic TRON
0402 07000000000000 00i64 7

C exports: stardust_db_plugin_stream_open, stardust_result_error, stardust_result_release