Add GET /v1/space/mounts/resolve with local mount resolution tests

Add mount-aware v2 federation cursors with remote_space_id support
This commit is contained in:
Carl Niklas Rydberg 2026-01-24 19:50:13 +01:00
parent a870b188e9
commit e54a9009a6
24 changed files with 1147 additions and 175 deletions

View file

@ -82,6 +82,12 @@ string).
Push cursors are separate from pull cursors and live under
`fed/push_cursor/<peer>/head` (space scoped).
To avoid cursor collisions across multiple mounts to the same peer, pass
`remote_space_id=<space_id>` on cursor-aware endpoints. When provided, cursor
heads use `fed/cursor/<peer>/<remote_space_id>/head` and
`fed/push_cursor/<peer>/<remote_space_id>/head`. When omitted, the legacy v1
cursor names remain in effect for backward compatibility.
Read the current cursor for a peer:
```sh
@ -90,6 +96,14 @@ curl --unix-socket amduatd.sock \
-H 'X-Amduat-Space: demo'
```
Scoped to a specific remote space:
```sh
curl --unix-socket amduatd.sock \
'http://localhost/v1/fed/cursor?peer=domain-2&remote_space_id=beta' \
-H 'X-Amduat-Space: demo'
```
Write a cursor update (CAS-safe; include `expected_ref` to enforce; omitting it
only succeeds when the cursor is absent):
@ -119,6 +133,7 @@ curl --unix-socket amduatd.sock \
The plan does not write artifacts, records, or cursors. It is deterministic and
returns only identifiers (logseq/ref), plus the next cursor candidate if the
plan were applied successfully.
Append `&remote_space_id=<space_id>` to use mount-specific cursor keying.
Apply a bounded batch of remote records (advances the cursor only after
success):
@ -131,6 +146,7 @@ curl --unix-socket amduatd.sock -X POST \
`/v1/fed/pull` requires the index backend and will not advance the cursor on
partial failure.
Use `remote_space_id=<space_id>` to scope the cursor to a mount.
### Federation push plan (sender dry run)
@ -145,6 +161,7 @@ curl --unix-socket amduatd.sock \
`/v1/fed/push/plan` requires the index backend and uses a push cursor separate
from the pull cursor.
Append `&remote_space_id=<space_id>` to use mount-specific cursor keying.
### Federation push (sender apply)
@ -159,6 +176,7 @@ curl --unix-socket amduatd.sock -X POST \
`/v1/fed/push` uses `/v1/fed/ingest` on the peer and only advances the push
cursor after the batch completes. It requires the index backend.
Use `remote_space_id=<space_id>` to scope the cursor to a mount.
### Federation sync until caught up
@ -245,6 +263,10 @@ curl --unix-socket amduatd.sock \
-H 'X-Amduat-Space: demo'
```
The response groups cursor status per peer and per remote space id:
`peers:[{peer_key, remotes:[{remote_space_id, pull_cursor, push_cursor}]}]`.
`remote_space_id` is `null` for legacy v1 cursor heads.
## Space manifest
`/v1/space/manifest` returns the space manifest rooted at the deterministic
@ -289,6 +311,8 @@ space manifest mounts with their local pull cursor state. It performs no
network I/O and does not mutate storage. Track mounts indicate intent; syncing
remains a separate concern.
If no manifest head is present, the endpoint returns a 404.
Track mounts report `local_tracking.cursor_namespace` (`v2` when using
`remote_space_id`-keyed cursors).
```sh
curl --unix-socket amduatd.sock \
@ -458,14 +482,18 @@ When the daemon uses the `fs` store backend, index-only checks are reported as
- `GET /v1/contract` → contract bytes (JSON) (+ `X-Amduat-Contract-Ref` header)
- `GET /v1/contract?format=ref``{ref}`
- `GET /v1/space/doctor` → deterministic space health checks
- `GET /v1/space/manifest``{effective_space, manifest_ref, manifest}`
- `PUT /v1/space/manifest``{effective_space, manifest_ref, updated, previous_ref?, manifest}`
- `GET /v1/space/mounts/resolve``{effective_space, manifest_ref, mounts}`
- `GET /v1/space/sync/status``{effective_space, store_backend, federation, peers}`
- `GET /v1/ui` → browser UI for authoring/running programs
- `GET /v1/fed/records?domain_id=...&from_logseq=...&limit=...``{domain_id, snapshot_id, log_prefix, next_logseq, records[]}` (published artifacts + tombstones + PER + TGK edges)
- `GET /v1/fed/cursor?peer=...``{peer_key, space_id, last_logseq, last_record_hash, ref}`
- `POST /v1/fed/cursor?peer=...``{ref}` (CAS update; `expected_ref` in body)
- `GET /v1/fed/pull/plan?peer=...&limit=...` → `{peer, effective_space, cursor, remote_scan, records, next_cursor_candidate, ...}`
- `GET /v1/fed/push/plan?peer=...&limit=...` → `{peer, domain_id, effective_space, cursor, scan, records, required_artifacts, next_cursor_candidate}`
- `POST /v1/fed/pull?peer=...&limit=...` → `{peer, effective_space, cursor_before, plan_summary, applied, cursor_after, errors}`
- `POST /v1/fed/push?peer=...&limit=...` → `{peer, domain_id, effective_space, cursor_before, plan_summary, sent, cursor_after, errors}`
- `GET /v1/fed/cursor?peer=...&remote_space_id=...` → `{peer_key, space_id, last_logseq, last_record_hash, ref}` (`remote_space_id` optional)
- `POST /v1/fed/cursor?peer=...&remote_space_id=...` → `{ref}` (CAS update; `expected_ref` in body; `remote_space_id` optional)
- `GET /v1/fed/pull/plan?peer=...&limit=...&remote_space_id=...` → `{peer, effective_space, cursor, remote_scan, records, next_cursor_candidate, ...}`
- `GET /v1/fed/push/plan?peer=...&limit=...&remote_space_id=...` → `{peer, domain_id, effective_space, cursor, scan, records, required_artifacts, next_cursor_candidate}`
- `POST /v1/fed/pull?peer=...&limit=...&remote_space_id=...` → `{peer, effective_space, cursor_before, plan_summary, applied, cursor_after, errors}`
- `POST /v1/fed/push?peer=...&limit=...&remote_space_id=...` → `{peer, domain_id, effective_space, cursor_before, plan_summary, sent, cursor_after, errors}`
- `GET /v1/fed/artifacts/{ref}` → raw bytes for federation resolve
- `GET /v1/fed/status``{status, domain_id, registry_ref, last_tick_ms}`
- `POST /v1/artifacts`

View file

@ -15,9 +15,16 @@
{"method": "POST", "path": "/v1/capabilities"},
{"method": "GET", "path": "/v1/cap/resolve"},
{"method": "GET", "path": "/v1/fed/records"},
{"method": "GET", "path": "/v1/fed/cursor"},
{"method": "POST", "path": "/v1/fed/cursor"},
{"method": "GET", "path": "/v1/fed/pull/plan"},
{"method": "GET", "path": "/v1/fed/push/plan"},
{"method": "POST", "path": "/v1/fed/pull"},
{"method": "GET", "path": "/v1/fed/artifacts/{ref}"},
{"method": "GET", "path": "/v1/fed/status"},
{"method": "POST", "path": "/v1/fed/ingest"},
{"method": "POST", "path": "/v1/fed/pull/until"},
{"method": "POST", "path": "/v1/fed/push"},
{"method": "POST", "path": "/v1/fed/push/until"},
{"method": "POST", "path": "/v1/concepts"},
{"method": "GET", "path": "/v1/concepts"},
@ -241,13 +248,87 @@
"manifest": {"$ref": "#/schemas/space_manifest"}
}
},
"space_mounts_pull_cursor": {
"type": "object",
"required": ["present"],
"properties": {
"present": {"type": "boolean"},
"last_logseq": {"type": "integer"},
"ref": {"type": "string"}
}
},
"space_mounts_local_tracking": {
"type": "object",
"required": ["cursor_namespace", "cursor_scope", "remote_space_id", "pull_cursor"],
"properties": {
"cursor_namespace": {"type": "string"},
"cursor_scope": {"type": "string"},
"remote_space_id": {"type": "string"},
"pull_cursor": {"$ref": "#/schemas/space_mounts_pull_cursor"}
}
},
"space_mounts_resolved_mount": {
"type": "object",
"required": ["name", "peer_key", "space_id", "mode", "local_tracking"],
"properties": {
"name": {"type": "string"},
"peer_key": {"type": "string"},
"space_id": {"type": "string"},
"mode": {"type": "string"},
"pinned_root_ref": {"type": "string"},
"local_tracking": {"$ref": "#/schemas/space_mounts_local_tracking"}
}
},
"space_mounts_resolve_response": {
"type": "object",
"required": ["effective_space", "manifest_ref", "mounts"],
"properties": {
"effective_space": {"type": "object"},
"manifest_ref": {"type": "string"},
"mounts": {"type": "array"}
"mounts": {"type": "array", "items": {"$ref": "#/schemas/space_mounts_resolved_mount"}}
}
},
"space_sync_status_cursor": {
"type": "object",
"required": ["present"],
"properties": {
"present": {"type": "boolean"},
"last_logseq": {"type": "integer"},
"ref": {"type": "string"}
}
},
"space_sync_status_remote": {
"type": "object",
"required": ["remote_space_id", "pull_cursor", "push_cursor"],
"properties": {
"remote_space_id": {"type": ["string", "null"]},
"pull_cursor": {"$ref": "#/schemas/space_sync_status_cursor"},
"push_cursor": {"$ref": "#/schemas/space_sync_status_cursor"}
}
},
"space_sync_status_peer": {
"type": "object",
"required": ["peer_key", "remotes"],
"properties": {
"peer_key": {"type": "string"},
"remotes": {"type": "array", "items": {"$ref": "#/schemas/space_sync_status_remote"}}
}
},
"space_sync_status_response": {
"type": "object",
"required": ["effective_space", "store_backend", "federation", "peers"],
"properties": {
"effective_space": {"type": "object"},
"store_backend": {"type": "string"},
"federation": {
"type": "object",
"required": ["enabled", "transport"],
"properties": {
"enabled": {"type": "boolean"},
"transport": {"type": "string"}
}
},
"peers": {"type": "array", "items": {"$ref": "#/schemas/space_sync_status_peer"}}
}
}
}

View file

@ -140,13 +140,12 @@ static const char k_amduatd_contract_v1_json[] =
"{\"method\":\"GET\",\"path\":\"/v1/fed/pull/plan\"},"
"{\"method\":\"GET\",\"path\":\"/v1/fed/push/plan\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/pull\"},"
"{\"method\":\"GET\",\"path\":\"/v1/fed/artifacts/{ref}\"},"
"{\"method\":\"GET\",\"path\":\"/v1/fed/status\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/ingest\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/pull/until\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/push\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/push/until\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/pull\"},"
"{\"method\":\"POST\",\"path\":\"/v1/fed/ingest\"},"
"{\"method\":\"GET\",\"path\":\"/v1/fed/artifacts/{ref}\"},"
"{\"method\":\"GET\",\"path\":\"/v1/fed/status\"},"
"{\"method\":\"POST\",\"path\":\"/v1/concepts\"},"
"{\"method\":\"GET\",\"path\":\"/v1/concepts\"},"
"{\"method\":\"GET\",\"path\":\"/v1/concepts/{name}\"},"
@ -335,13 +334,87 @@ static const char k_amduatd_contract_v1_json[] =
"\"manifest\":{\"$ref\":\"#/schemas/space_manifest\"}"
"}"
"},"
"\"space_mounts_pull_cursor\":{"
"\"type\":\"object\","
"\"required\":[\"present\"],"
"\"properties\":{"
"\"present\":{\"type\":\"boolean\"},"
"\"last_logseq\":{\"type\":\"integer\"},"
"\"ref\":{\"type\":\"string\"}"
"}"
"},"
"\"space_mounts_local_tracking\":{"
"\"type\":\"object\","
"\"required\":[\"cursor_namespace\",\"cursor_scope\",\"remote_space_id\",\"pull_cursor\"],"
"\"properties\":{"
"\"cursor_namespace\":{\"type\":\"string\"},"
"\"cursor_scope\":{\"type\":\"string\"},"
"\"remote_space_id\":{\"type\":\"string\"},"
"\"pull_cursor\":{\"$ref\":\"#/schemas/space_mounts_pull_cursor\"}"
"}"
"},"
"\"space_mounts_resolved_mount\":{"
"\"type\":\"object\","
"\"required\":[\"name\",\"peer_key\",\"space_id\",\"mode\",\"local_tracking\"],"
"\"properties\":{"
"\"name\":{\"type\":\"string\"},"
"\"peer_key\":{\"type\":\"string\"},"
"\"space_id\":{\"type\":\"string\"},"
"\"mode\":{\"type\":\"string\"},"
"\"pinned_root_ref\":{\"type\":\"string\"},"
"\"local_tracking\":{\"$ref\":\"#/schemas/space_mounts_local_tracking\"}"
"}"
"},"
"\"space_mounts_resolve_response\":{"
"\"type\":\"object\","
"\"required\":[\"effective_space\",\"manifest_ref\",\"mounts\"],"
"\"properties\":{"
"\"effective_space\":{\"type\":\"object\"},"
"\"manifest_ref\":{\"type\":\"string\"},"
"\"mounts\":{\"type\":\"array\"}"
"\"mounts\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/schemas/space_mounts_resolved_mount\"}}"
"}"
"},"
"\"space_sync_status_cursor\":{"
"\"type\":\"object\","
"\"required\":[\"present\"],"
"\"properties\":{"
"\"present\":{\"type\":\"boolean\"},"
"\"last_logseq\":{\"type\":\"integer\"},"
"\"ref\":{\"type\":\"string\"}"
"}"
"},"
"\"space_sync_status_remote\":{"
"\"type\":\"object\","
"\"required\":[\"remote_space_id\",\"pull_cursor\",\"push_cursor\"],"
"\"properties\":{"
"\"remote_space_id\":{\"type\":[\"string\",\"null\"]},"
"\"pull_cursor\":{\"$ref\":\"#/schemas/space_sync_status_cursor\"},"
"\"push_cursor\":{\"$ref\":\"#/schemas/space_sync_status_cursor\"}"
"}"
"},"
"\"space_sync_status_peer\":{"
"\"type\":\"object\","
"\"required\":[\"peer_key\",\"remotes\"],"
"\"properties\":{"
"\"peer_key\":{\"type\":\"string\"},"
"\"remotes\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/schemas/space_sync_status_remote\"}}"
"}"
"},"
"\"space_sync_status_response\":{"
"\"type\":\"object\","
"\"required\":[\"effective_space\",\"store_backend\",\"federation\",\"peers\"],"
"\"properties\":{"
"\"effective_space\":{\"type\":\"object\"},"
"\"store_backend\":{\"type\":\"string\"},"
"\"federation\":{"
"\"type\":\"object\","
"\"required\":[\"enabled\",\"transport\"],"
"\"properties\":{"
"\"enabled\":{\"type\":\"boolean\"},"
"\"transport\":{\"type\":\"string\"}"
"}"
"},"
"\"peers\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/schemas/space_sync_status_peer\"}}"
"}"
"}"
"}"
@ -743,6 +816,39 @@ static bool amduatd_trim_header_value(const char *value,
return true;
}
static bool amduatd_get_remote_space_id(const amduatd_http_req_t *req,
char *buf,
size_t cap,
const char **out_remote,
const char **out_error) {
const char *remote = NULL;
if (out_remote != NULL) {
*out_remote = NULL;
}
if (out_error != NULL) {
*out_error = NULL;
}
if (req == NULL || buf == NULL || cap == 0u || out_remote == NULL) {
if (out_error != NULL) {
*out_error = "invalid remote_space_id";
}
return false;
}
if (amduatd_query_param(req->path, "remote_space_id", buf, cap) == NULL ||
buf[0] == '\0') {
return true;
}
if (!amduatd_space_space_id_is_valid(buf)) {
if (out_error != NULL) {
*out_error = "invalid remote_space_id";
}
return false;
}
remote = buf;
*out_remote = remote;
return true;
}
static bool amduatd_parse_type_tag_hex(const char *text,
bool *out_has_type_tag,
amduat_type_tag_t *out_type_tag) {
@ -1661,12 +1767,111 @@ manifest_put_cleanup:
return ok;
}
typedef struct {
char *peer_key;
char *remote_space_id;
} amduatd_cursor_pair_t;
static void amduatd_cursor_pair_free(amduatd_cursor_pair_t *pair) {
if (pair == NULL) {
return;
}
free(pair->peer_key);
free(pair->remote_space_id);
pair->peer_key = NULL;
pair->remote_space_id = NULL;
}
static int amduatd_cursor_pair_cmp(const void *a, const void *b) {
const amduatd_cursor_pair_t *lhs = (const amduatd_cursor_pair_t *)a;
const amduatd_cursor_pair_t *rhs = (const amduatd_cursor_pair_t *)b;
const char *lhs_peer = lhs != NULL && lhs->peer_key != NULL ? lhs->peer_key
: "";
const char *rhs_peer = rhs != NULL && rhs->peer_key != NULL ? rhs->peer_key
: "";
const char *lhs_remote =
lhs != NULL && lhs->remote_space_id != NULL ? lhs->remote_space_id : "";
const char *rhs_remote =
rhs != NULL && rhs->remote_space_id != NULL ? rhs->remote_space_id : "";
int cmp = strcmp(lhs_peer, rhs_peer);
if (cmp != 0) {
return cmp;
}
return strcmp(lhs_remote, rhs_remote);
}
static bool amduatd_cursor_pair_add(amduatd_cursor_pair_t **pairs,
size_t *len,
size_t *cap,
const char *peer_key,
const char *remote_space_id) {
size_t next_len;
amduatd_cursor_pair_t *next;
if (pairs == NULL || len == NULL || cap == NULL ||
peer_key == NULL || peer_key[0] == '\0') {
return false;
}
for (size_t i = 0u; i < *len; ++i) {
const char *cur_peer = (*pairs)[i].peer_key;
const char *cur_remote = (*pairs)[i].remote_space_id;
const char *remote = remote_space_id != NULL ? remote_space_id : "";
if (cur_peer != NULL && strcmp(cur_peer, peer_key) == 0) {
if ((cur_remote == NULL || cur_remote[0] == '\0') && remote[0] == '\0') {
return true;
}
if (cur_remote != NULL && strcmp(cur_remote, remote) == 0) {
return true;
}
}
}
if (*len == *cap) {
size_t next_cap = *cap != 0u ? *cap * 2u : 8u;
next = (amduatd_cursor_pair_t *)realloc(*pairs,
next_cap * sizeof(*next));
if (next == NULL) {
return false;
}
*pairs = next;
*cap = next_cap;
}
next_len = *len + 1u;
(*pairs)[*len].peer_key = strdup(peer_key);
if ((*pairs)[*len].peer_key == NULL) {
return false;
}
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
(*pairs)[*len].remote_space_id = strdup(remote_space_id);
if ((*pairs)[*len].remote_space_id == NULL) {
free((*pairs)[*len].peer_key);
(*pairs)[*len].peer_key = NULL;
return false;
}
} else {
(*pairs)[*len].remote_space_id = NULL;
}
*len = next_len;
return true;
}
static void amduatd_cursor_pairs_free(amduatd_cursor_pair_t *pairs,
size_t len) {
if (pairs == NULL) {
return;
}
for (size_t i = 0u; i < len; ++i) {
amduatd_cursor_pair_free(&pairs[i]);
}
free(pairs);
}
static bool amduatd_sync_status_append_cursor(
amduatd_strbuf_t *b,
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
bool push) {
amduatd_fed_cursor_record_t cursor;
amduat_reference_t ref;
@ -1679,18 +1884,20 @@ static bool amduatd_sync_status_append_cursor(
ref = amduat_reference(0u, amduat_octets(NULL, 0u));
status = push
? amduatd_fed_push_cursor_get(store,
pointer_store,
effective_space,
peer_key,
&cursor,
&ref)
: amduatd_fed_cursor_get(store,
pointer_store,
effective_space,
peer_key,
&cursor,
&ref);
? amduatd_fed_push_cursor_get_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
&cursor,
&ref)
: amduatd_fed_cursor_get_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
&cursor,
&ref);
if (status == AMDUATD_FED_CURSOR_OK) {
present = true;
@ -1781,11 +1988,18 @@ static bool amduatd_handle_get_space_sync_status(
const char *root_path,
amduatd_store_backend_t store_backend) {
amduat_asl_pointer_store_t pointer_store;
amduatd_space_roots_list_t peers;
amduatd_space_roots_list_t pull_heads;
amduatd_space_roots_list_t push_heads;
amduatd_strbuf_t b;
amduatd_cursor_pair_t *pairs = NULL;
size_t pair_len = 0u;
size_t pair_cap = 0u;
amduat_octets_t pull_prefix = amduat_octets(NULL, 0u);
amduat_octets_t push_prefix = amduat_octets(NULL, 0u);
bool ok = false;
memset(&peers, 0, sizeof(peers));
memset(&pull_heads, 0, sizeof(pull_heads));
memset(&push_heads, 0, sizeof(push_heads));
memset(&b, 0, sizeof(b));
if (store == NULL || req == NULL || dcfg == NULL || fed_cfg == NULL ||
@ -1810,12 +2024,66 @@ static bool amduatd_handle_get_space_sync_status(
return amduatd_send_json_error(fd, 500, "Internal Server Error",
"pointer store error");
}
if (!amduatd_space_roots_list_cursor_peers(root_path,
req->effective_space,
&peers)) {
if (!amduatd_space_scope_name(req->effective_space,
"fed/cursor",
&pull_prefix) ||
!amduatd_space_scope_name(req->effective_space,
"fed/push_cursor",
&push_prefix)) {
return amduatd_send_json_error(fd, 500, "Internal Server Error",
"cursor scan failed");
}
if (!amduatd_space_roots_list_cursor_heads(root_path,
req->effective_space,
false,
&pull_heads) ||
!amduatd_space_roots_list_cursor_heads(root_path,
req->effective_space,
true,
&push_heads)) {
amduat_octets_free(&pull_prefix);
amduat_octets_free(&push_prefix);
return amduatd_send_json_error(fd, 500, "Internal Server Error",
"cursor scan failed");
}
for (size_t i = 0u; i < pull_heads.len; ++i) {
char *peer = NULL;
char *remote = NULL;
if (amduatd_space_roots_cursor_parse((const char *)pull_prefix.data,
pull_heads.names[i],
&peer,
&remote)) {
if (!amduatd_cursor_pair_add(&pairs, &pair_len, &pair_cap,
peer, remote)) {
free(peer);
free(remote);
goto sync_cleanup;
}
free(peer);
free(remote);
}
}
for (size_t i = 0u; i < push_heads.len; ++i) {
char *peer = NULL;
char *remote = NULL;
if (amduatd_space_roots_cursor_parse((const char *)push_prefix.data,
push_heads.names[i],
&peer,
&remote)) {
if (!amduatd_cursor_pair_add(&pairs, &pair_len, &pair_cap,
peer, remote)) {
free(peer);
free(remote);
goto sync_cleanup;
}
free(peer);
free(remote);
}
}
if (pair_len > 1u) {
qsort(pairs, pair_len, sizeof(*pairs), amduatd_cursor_pair_cmp);
}
if (!amduatd_strbuf_append_cstr(&b, "{\"effective_space\":{")) {
goto sync_cleanup;
@ -1849,39 +2117,91 @@ static bool amduatd_handle_get_space_sync_status(
goto sync_cleanup;
}
for (size_t i = 0u; i < peers.len; ++i) {
const char *peer_key = peers.names[i];
if (i != 0u) {
if (!amduatd_strbuf_append_char(&b, ',')) {
{
const char *current_peer = NULL;
bool first_peer = true;
bool first_remote = true;
for (size_t i = 0u; i < pair_len; ++i) {
const char *peer_key = pairs[i].peer_key;
const char *remote_space_id = pairs[i].remote_space_id;
if (peer_key == NULL || peer_key[0] == '\0') {
continue;
}
if (current_peer == NULL || strcmp(current_peer, peer_key) != 0) {
if (!first_peer) {
if (!amduatd_strbuf_append_cstr(&b, "]}")) {
goto sync_cleanup;
}
}
if (!first_peer) {
if (!amduatd_strbuf_append_char(&b, ',')) {
goto sync_cleanup;
}
}
if (!amduatd_strbuf_append_cstr(&b, "{\"peer_key\":\"") ||
!amduatd_strbuf_append_cstr(&b, peer_key) ||
!amduatd_strbuf_append_cstr(&b, "\",\"remotes\":[")) {
goto sync_cleanup;
}
current_peer = peer_key;
first_peer = false;
first_remote = true;
}
if (!first_remote) {
if (!amduatd_strbuf_append_char(&b, ',')) {
goto sync_cleanup;
}
}
if (!amduatd_strbuf_append_cstr(&b, "{\"remote_space_id\":")) {
goto sync_cleanup;
}
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
if (!amduatd_strbuf_append_cstr(&b, "\"") ||
!amduatd_strbuf_append_cstr(&b, remote_space_id) ||
!amduatd_strbuf_append_cstr(&b, "\"")) {
goto sync_cleanup;
}
} else {
if (!amduatd_strbuf_append_cstr(&b, "null")) {
goto sync_cleanup;
}
}
if (!amduatd_strbuf_append_cstr(&b, ",\"pull_cursor\":")) {
goto sync_cleanup;
}
if (!amduatd_sync_status_append_cursor(&b,
store,
&pointer_store,
req->effective_space,
peer_key,
remote_space_id,
false)) {
goto sync_cleanup;
}
if (!amduatd_strbuf_append_cstr(&b, ",\"push_cursor\":")) {
goto sync_cleanup;
}
if (!amduatd_sync_status_append_cursor(&b,
store,
&pointer_store,
req->effective_space,
peer_key,
remote_space_id,
true)) {
goto sync_cleanup;
}
if (!amduatd_strbuf_append_cstr(&b, "}")) {
goto sync_cleanup;
}
first_remote = false;
}
if (!amduatd_strbuf_append_cstr(&b, "{\"peer_key\":\"") ||
!amduatd_strbuf_append_cstr(&b, peer_key) ||
!amduatd_strbuf_append_cstr(&b, "\",\"pull_cursor\":")) {
goto sync_cleanup;
}
if (!amduatd_sync_status_append_cursor(&b,
store,
&pointer_store,
req->effective_space,
peer_key,
false)) {
goto sync_cleanup;
}
if (!amduatd_strbuf_append_cstr(&b, ",\"push_cursor\":")) {
goto sync_cleanup;
}
if (!amduatd_sync_status_append_cursor(&b,
store,
&pointer_store,
req->effective_space,
peer_key,
true)) {
goto sync_cleanup;
}
if (!amduatd_strbuf_append_cstr(&b, "}")) {
goto sync_cleanup;
if (current_peer != NULL) {
if (!amduatd_strbuf_append_cstr(&b, "]}")) {
goto sync_cleanup;
}
}
}
@ -1895,7 +2215,11 @@ sync_cleanup:
if (!ok) {
ok = amduatd_send_json_error(fd, 500, "Internal Server Error", "error");
}
amduatd_space_roots_list_free(&peers);
amduatd_space_roots_list_free(&pull_heads);
amduatd_space_roots_list_free(&push_heads);
amduatd_cursor_pairs_free(pairs, pair_len);
amduat_octets_free(&pull_prefix);
amduat_octets_free(&push_prefix);
amduatd_strbuf_free(&b);
return ok;
}
@ -2586,6 +2910,9 @@ static bool amduatd_handle_get_fed_cursor(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
amduat_asl_pointer_store_t pointer_store;
amduatd_fed_cursor_record_t cursor;
amduat_reference_t ref;
@ -2627,11 +2954,26 @@ static bool amduatd_handle_get_fed_cursor(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -2644,12 +2986,13 @@ static bool amduatd_handle_get_fed_cursor(int fd,
amduatd_fed_cursor_record_init(&cursor);
memset(&ref, 0, sizeof(ref));
status = amduatd_fed_cursor_get(store,
&pointer_store,
req->effective_space,
peer_buf,
&cursor,
&ref);
status = amduatd_fed_cursor_get_remote(store,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
&cursor,
&ref);
if (status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
return amduatd_send_json_error(fd, 404, "Not Found", "cursor not found");
}
@ -2751,6 +3094,9 @@ static bool amduatd_handle_post_fed_cursor(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
uint8_t *body = NULL;
const char *p = NULL;
const char *end = NULL;
@ -2804,11 +3150,26 @@ static bool amduatd_handle_post_fed_cursor(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -2971,11 +3332,12 @@ fed_cursor_parse_fail:
"pointer store error");
}
status = amduatd_fed_cursor_cas_set(
status = amduatd_fed_cursor_cas_set_remote(
store,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
have_expected_ref ? &expected_ref : NULL,
&cursor,
&new_ref);
@ -3713,6 +4075,9 @@ static bool amduatd_handle_get_fed_pull_plan(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
uint64_t limit = 128u;
uint64_t from_logseq = 0u;
@ -3772,11 +4137,26 @@ static bool amduatd_handle_get_fed_pull_plan(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -3802,12 +4182,13 @@ static bool amduatd_handle_get_fed_pull_plan(int fd,
memset(&cursor_ref, 0, sizeof(cursor_ref));
{
amduatd_fed_cursor_status_t cursor_status;
cursor_status = amduatd_fed_cursor_get(store,
&pointer_store,
req->effective_space,
peer_buf,
&cursor,
&cursor_ref);
cursor_status = amduatd_fed_cursor_get_remote(store,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
&cursor,
&cursor_ref);
if (cursor_status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
cursor_present = false;
} else if (cursor_status == AMDUATD_FED_CURSOR_OK) {
@ -3932,6 +4313,9 @@ static bool amduatd_handle_get_fed_push_plan(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
uint64_t limit = 128u;
uint32_t domain_id = 0u;
@ -3982,11 +4366,26 @@ static bool amduatd_handle_get_fed_push_plan(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_push_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -4017,6 +4416,7 @@ static bool amduatd_handle_get_fed_push_plan(int fd,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
limit,
root_path,
&scan);
@ -5544,6 +5944,9 @@ static bool amduatd_handle_post_fed_pull(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
uint64_t limit = 128u;
amduat_asl_pointer_store_t pointer_store;
@ -5592,11 +5995,26 @@ static bool amduatd_handle_post_fed_pull(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -5642,6 +6060,7 @@ static bool amduatd_handle_post_fed_pull(int fd,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
limit,
fed_cfg,
&pull_transport,
@ -5987,6 +6406,9 @@ static bool amduatd_handle_post_fed_pull_until(
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
char rounds_buf[32];
uint64_t limit = 128u;
@ -6046,11 +6468,26 @@ static bool amduatd_handle_post_fed_pull_until(
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -6104,6 +6541,7 @@ static bool amduatd_handle_post_fed_pull_until(
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
limit,
max_rounds,
fed_cfg,
@ -6255,6 +6693,9 @@ static bool amduatd_handle_post_fed_push(int fd,
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
uint64_t limit = 128u;
uint32_t domain_id = 0u;
@ -6310,11 +6751,26 @@ static bool amduatd_handle_post_fed_push(int fd,
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_push_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -6360,6 +6816,7 @@ static bool amduatd_handle_post_fed_push(int fd,
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
limit,
root_path,
fed_cfg,
@ -6682,6 +7139,9 @@ static bool amduatd_handle_post_fed_push_until(
const amduatd_http_req_t *req,
const char *root_path) {
char peer_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
char remote_buf[AMDUAT_ASL_POINTER_NAME_MAX + 1u];
const char *remote_space_id = NULL;
const char *remote_error = NULL;
char limit_buf[32];
char rounds_buf[32];
uint64_t limit = 128u;
@ -6740,11 +7200,26 @@ static bool amduatd_handle_post_fed_push_until(
return amduatd_send_json_error(fd, 400, "Bad Request",
"missing peer");
}
if (!amduatd_get_remote_space_id(req,
remote_buf,
sizeof(remote_buf),
&remote_space_id,
&remote_error)) {
return amduatd_send_json_error(fd, 400, "Bad Request",
remote_error);
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
if (remote_space_id != NULL) {
if (!amduatd_fed_push_cursor_pointer_name_v2(req->effective_space,
peer_buf,
remote_space_id,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
} else if (!amduatd_fed_push_cursor_pointer_name(req->effective_space,
peer_buf,
&scoped)) {
return amduatd_send_json_error(fd, 400, "Bad Request", "invalid peer");
}
amduat_octets_free(&scoped);
@ -6795,6 +7270,7 @@ static bool amduatd_handle_post_fed_push_until(
&pointer_store,
req->effective_space,
peer_buf,
remote_space_id,
limit,
max_rounds,
root_path,

View file

@ -2,6 +2,7 @@
#include "amduat/asl/record.h"
#include "amduat/enc/asl1_core_codec.h"
#include "amduatd_space.h"
#include <stdlib.h>
#include <string.h>
@ -110,6 +111,11 @@ static bool amduatd_fed_cursor_peer_key_is_valid(const char *peer_key) {
return amduat_asl_pointer_name_is_valid(peer_key);
}
static bool amduatd_fed_cursor_remote_space_id_is_valid(
const char *remote_space_id) {
return amduatd_space_space_id_is_valid(remote_space_id);
}
static bool amduatd_fed_cursor_pointer_name_with_prefix(
const amduatd_space_t *space,
const char *peer_key,
@ -149,6 +155,56 @@ static bool amduatd_fed_cursor_pointer_name_with_prefix(
return ok;
}
static bool amduatd_fed_cursor_pointer_name_with_prefix_v2(
const amduatd_space_t *space,
const char *peer_key,
const char *remote_space_id,
const char *prefix,
amduat_octets_t *out_name) {
const char suffix[] = "/head";
size_t peer_len;
size_t remote_len;
size_t total_len;
size_t prefix_len;
char *base = NULL;
bool ok;
if (out_name != NULL) {
*out_name = amduat_octets(NULL, 0u);
}
if (out_name == NULL || prefix == NULL ||
!amduatd_fed_cursor_peer_key_is_valid(peer_key) ||
!amduatd_fed_cursor_remote_space_id_is_valid(remote_space_id)) {
return false;
}
peer_len = strlen(peer_key);
remote_len = strlen(remote_space_id);
prefix_len = strlen(prefix);
if (peer_len > SIZE_MAX - prefix_len - 1u) {
return false;
}
if (remote_len > SIZE_MAX - prefix_len - peer_len - 1u -
(sizeof(suffix) - 1u)) {
return false;
}
total_len = prefix_len + peer_len + 1u + remote_len + (sizeof(suffix) - 1u);
base = (char *)malloc(total_len + 1u);
if (base == NULL) {
return false;
}
memcpy(base, prefix, prefix_len);
memcpy(base + prefix_len, peer_key, peer_len);
base[prefix_len + peer_len] = '/';
memcpy(base + prefix_len + peer_len + 1u, remote_space_id, remote_len);
memcpy(base + prefix_len + peer_len + 1u + remote_len, suffix,
sizeof(suffix) - 1u);
base[total_len] = '\0';
ok = amduatd_space_scope_name(space, base, out_name);
free(base);
return ok;
}
static bool amduatd_fed_cursor_record_encode(
const amduatd_fed_cursor_record_t *record,
amduat_octets_t *out_payload) {
@ -412,6 +468,28 @@ bool amduatd_fed_push_cursor_pointer_name(const amduatd_space_t *space,
out_name);
}
bool amduatd_fed_cursor_pointer_name_v2(const amduatd_space_t *space,
const char *peer_key,
const char *remote_space_id,
amduat_octets_t *out_name) {
return amduatd_fed_cursor_pointer_name_with_prefix_v2(space,
peer_key,
remote_space_id,
"fed/cursor/",
out_name);
}
bool amduatd_fed_push_cursor_pointer_name_v2(const amduatd_space_t *space,
const char *peer_key,
const char *remote_space_id,
amduat_octets_t *out_name) {
return amduatd_fed_cursor_pointer_name_with_prefix_v2(space,
peer_key,
remote_space_id,
"fed/push_cursor/",
out_name);
}
amduatd_fed_cursor_status_t amduatd_fed_cursor_check_enabled(
const amduatd_fed_cfg_t *cfg) {
if (cfg == NULL) {
@ -428,6 +506,7 @@ static amduatd_fed_cursor_status_t amduatd_fed_cursor_get_with_prefix(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const char *prefix,
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref) {
@ -446,10 +525,18 @@ static amduatd_fed_cursor_status_t amduatd_fed_cursor_get_with_prefix(
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
if (!amduatd_fed_cursor_pointer_name_with_prefix(effective_space,
peer_key,
prefix,
&pointer_name)) {
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
if (!amduatd_fed_cursor_pointer_name_with_prefix_v2(effective_space,
peer_key,
remote_space_id,
prefix,
&pointer_name)) {
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
} else if (!amduatd_fed_cursor_pointer_name_with_prefix(effective_space,
peer_key,
prefix,
&pointer_name)) {
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
@ -529,6 +616,25 @@ amduatd_fed_cursor_status_t amduatd_fed_cursor_get(
pointer_store,
effective_space,
peer_key,
NULL,
"fed/cursor/",
out_cursor,
out_ref);
}
amduatd_fed_cursor_status_t amduatd_fed_cursor_get_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref) {
return amduatd_fed_cursor_get_with_prefix(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
"fed/cursor/",
out_cursor,
out_ref);
@ -545,6 +651,25 @@ amduatd_fed_cursor_status_t amduatd_fed_push_cursor_get(
pointer_store,
effective_space,
peer_key,
NULL,
"fed/push_cursor/",
out_cursor,
out_ref);
}
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_get_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref) {
return amduatd_fed_cursor_get_with_prefix(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
"fed/push_cursor/",
out_cursor,
out_ref);
@ -555,6 +680,7 @@ static amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set_with_prefix(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const char *prefix,
const amduat_reference_t *expected_ref,
const amduatd_fed_cursor_record_t *new_cursor,
@ -591,10 +717,18 @@ static amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set_with_prefix(
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
if (!amduatd_fed_cursor_pointer_name_with_prefix(effective_space,
peer_key,
prefix,
&pointer_name)) {
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
if (!amduatd_fed_cursor_pointer_name_with_prefix_v2(effective_space,
peer_key,
remote_space_id,
prefix,
&pointer_name)) {
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
} else if (!amduatd_fed_cursor_pointer_name_with_prefix(effective_space,
peer_key,
prefix,
&pointer_name)) {
return AMDUATD_FED_CURSOR_ERR_INVALID;
}
@ -653,6 +787,27 @@ amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set(
pointer_store,
effective_space,
peer_key,
NULL,
"fed/cursor/",
expected_ref,
new_cursor,
out_new_ref);
}
amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const amduat_reference_t *expected_ref,
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref) {
return amduatd_fed_cursor_cas_set_with_prefix(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
"fed/cursor/",
expected_ref,
new_cursor,
@ -671,6 +826,27 @@ amduatd_fed_cursor_status_t amduatd_fed_push_cursor_cas_set(
pointer_store,
effective_space,
peer_key,
NULL,
"fed/push_cursor/",
expected_ref,
new_cursor,
out_new_ref);
}
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_cas_set_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const amduat_reference_t *expected_ref,
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref) {
return amduatd_fed_cursor_cas_set_with_prefix(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
"fed/push_cursor/",
expected_ref,
new_cursor,

View file

@ -46,6 +46,16 @@ bool amduatd_fed_push_cursor_pointer_name(const amduatd_space_t *space,
const char *peer_key,
amduat_octets_t *out_name);
bool amduatd_fed_cursor_pointer_name_v2(const amduatd_space_t *space,
const char *peer_key,
const char *remote_space_id,
amduat_octets_t *out_name);
bool amduatd_fed_push_cursor_pointer_name_v2(const amduatd_space_t *space,
const char *peer_key,
const char *remote_space_id,
amduat_octets_t *out_name);
amduatd_fed_cursor_status_t amduatd_fed_cursor_check_enabled(
const amduatd_fed_cfg_t *cfg);
@ -57,6 +67,15 @@ amduatd_fed_cursor_status_t amduatd_fed_cursor_get(
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref);
amduatd_fed_cursor_status_t amduatd_fed_cursor_get_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref);
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_get(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
@ -65,6 +84,15 @@ amduatd_fed_cursor_status_t amduatd_fed_push_cursor_get(
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref);
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_get_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
amduatd_fed_cursor_record_t *out_cursor,
amduat_reference_t *out_ref);
amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
@ -74,6 +102,16 @@ amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set(
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref);
amduatd_fed_cursor_status_t amduatd_fed_cursor_cas_set_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const amduat_reference_t *expected_ref,
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref);
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_cas_set(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
@ -83,6 +121,16 @@ amduatd_fed_cursor_status_t amduatd_fed_push_cursor_cas_set(
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref);
amduatd_fed_cursor_status_t amduatd_fed_push_cursor_cas_set_remote(
amduat_asl_store_t *store,
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
const amduat_reference_t *expected_ref,
const amduatd_fed_cursor_record_t *new_cursor,
amduat_reference_t *out_new_ref);
#ifdef __cplusplus
} /* extern "C" */
#endif

View file

@ -189,6 +189,7 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_apply(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const amduatd_fed_cfg_t *fed_cfg,
const amduatd_fed_pull_transport_t *transport,
@ -234,9 +235,17 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_apply(
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_cursor_pointer_name(effective_space,
peer_key,
&scoped)) {
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
if (!amduatd_fed_cursor_pointer_name_v2(effective_space,
peer_key,
remote_space_id,
&scoped)) {
amduatd_fed_pull_report_error(out_report, "invalid peer");
return AMDUATD_FED_PULL_APPLY_ERR_INVALID;
}
} else if (!amduatd_fed_cursor_pointer_name(effective_space,
peer_key,
&scoped)) {
amduatd_fed_pull_report_error(out_report, "invalid peer");
return AMDUATD_FED_PULL_APPLY_ERR_INVALID;
}
@ -256,12 +265,13 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_apply(
memset(&cursor_ref, 0, sizeof(cursor_ref));
{
amduatd_fed_cursor_status_t cursor_status;
cursor_status = amduatd_fed_cursor_get(store,
pointer_store,
effective_space,
peer_key,
&cursor,
&cursor_ref);
cursor_status = amduatd_fed_cursor_get_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
&cursor,
&cursor_ref);
if (cursor_status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
cursor_present = false;
} else if (cursor_status == AMDUATD_FED_CURSOR_OK) {
@ -471,14 +481,16 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_apply(
memset(&next_ref, 0, sizeof(next_ref));
{
amduatd_fed_cursor_status_t cursor_status;
cursor_status = amduatd_fed_cursor_cas_set(store,
pointer_store,
effective_space,
peer_key,
cursor_present ? &cursor_ref
: NULL,
&next_cursor,
&next_ref);
cursor_status = amduatd_fed_cursor_cas_set_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
cursor_present
? &cursor_ref
: NULL,
&next_cursor,
&next_ref);
if (cursor_status == AMDUATD_FED_CURSOR_ERR_CONFLICT) {
transport->free_records(transport->ctx, records, record_len_total);
amduatd_fed_cursor_record_free(&cursor);

View file

@ -78,6 +78,7 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_apply(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const amduatd_fed_cfg_t *fed_cfg,
const amduatd_fed_pull_transport_t *transport,

View file

@ -95,6 +95,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_apply(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const char *root_path,
const amduatd_fed_cfg_t *fed_cfg,
@ -133,9 +134,17 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_apply(
}
{
amduat_octets_t scoped = amduat_octets(NULL, 0u);
if (!amduatd_fed_push_cursor_pointer_name(effective_space,
peer_key,
&scoped)) {
if (remote_space_id != NULL && remote_space_id[0] != '\0') {
if (!amduatd_fed_push_cursor_pointer_name_v2(effective_space,
peer_key,
remote_space_id,
&scoped)) {
amduatd_fed_push_report_error(out_report, "invalid peer");
return AMDUATD_FED_PUSH_APPLY_ERR_INVALID;
}
} else if (!amduatd_fed_push_cursor_pointer_name(effective_space,
peer_key,
&scoped)) {
amduatd_fed_push_report_error(out_report, "invalid peer");
return AMDUATD_FED_PUSH_APPLY_ERR_INVALID;
}
@ -153,6 +162,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_apply(
pointer_store,
effective_space,
peer_key,
remote_space_id,
limit,
root_path,
&scan) != AMDUATD_FED_PUSH_PLAN_OK) {
@ -303,15 +313,16 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_apply(
memset(&next_ref, 0, sizeof(next_ref));
{
amduatd_fed_cursor_status_t st;
st = amduatd_fed_push_cursor_cas_set(store,
pointer_store,
effective_space,
peer_key,
scan.cursor_present
? &scan.cursor_ref
: NULL,
&next_cursor,
&next_ref);
st = amduatd_fed_push_cursor_cas_set_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
scan.cursor_present
? &scan.cursor_ref
: NULL,
&next_cursor,
&next_ref);
amduatd_fed_cursor_record_free(&next_cursor);
if (st == AMDUATD_FED_CURSOR_ERR_CONFLICT) {
amduatd_fed_push_plan_scan_free(&scan);

View file

@ -76,6 +76,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_apply(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const char *root_path,
const amduatd_fed_cfg_t *fed_cfg,

View file

@ -237,6 +237,7 @@ amduatd_fed_push_plan_status_t amduatd_fed_push_plan_scan(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const char *root_path,
amduatd_fed_push_plan_scan_t *out_scan) {
@ -256,12 +257,13 @@ amduatd_fed_push_plan_status_t amduatd_fed_push_plan_scan(
{
amduatd_fed_cursor_status_t cursor_status;
cursor_status = amduatd_fed_push_cursor_get(store,
pointer_store,
effective_space,
peer_key,
&out_scan->cursor,
&out_scan->cursor_ref);
cursor_status = amduatd_fed_push_cursor_get_remote(store,
pointer_store,
effective_space,
peer_key,
remote_space_id,
&out_scan->cursor,
&out_scan->cursor_ref);
if (cursor_status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
out_scan->cursor_present = false;
} else if (cursor_status == AMDUATD_FED_CURSOR_OK) {

View file

@ -61,6 +61,7 @@ amduatd_fed_push_plan_status_t amduatd_fed_push_plan_scan(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
const char *root_path,
amduatd_fed_push_plan_scan_t *out_scan);

View file

@ -71,6 +71,7 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_until(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
uint64_t max_rounds,
const amduatd_fed_cfg_t *fed_cfg,
@ -100,6 +101,7 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_until(
pointer_store,
effective_space,
peer_key,
remote_space_id,
limit,
fed_cfg,
transport,
@ -154,6 +156,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_until(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
uint64_t max_rounds,
const char *root_path,
@ -185,6 +188,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_until(
pointer_store,
effective_space,
peer_key,
remote_space_id,
limit,
root_path,
fed_cfg,

View file

@ -38,6 +38,7 @@ amduatd_fed_pull_apply_status_t amduatd_fed_pull_until(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
uint64_t max_rounds,
const amduatd_fed_cfg_t *fed_cfg,
@ -49,6 +50,7 @@ amduatd_fed_push_apply_status_t amduatd_fed_push_until(
amduat_asl_pointer_store_t *pointer_store,
const amduatd_space_t *effective_space,
const char *peer_key,
const char *remote_space_id,
uint64_t limit,
uint64_t max_rounds,
const char *root_path,

View file

@ -99,17 +99,19 @@ static amduatd_space_mounts_status_t amduatd_space_mounts_append_tracking(
amduatd_fed_cursor_status_t status;
bool cursor_present = false;
char *cursor_ref_hex = NULL;
const char *cursor_namespace = "none";
amduatd_fed_cursor_record_init(&cursor);
cursor_ref = amduat_reference(0u, amduat_octets(NULL, 0u));
if (mount->mode == AMDUATD_SPACE_MANIFEST_MOUNT_TRACK) {
status = amduatd_fed_cursor_get(store,
pointer_store,
effective_space,
mount->peer_key,
&cursor,
&cursor_ref);
status = amduatd_fed_cursor_get_remote(store,
pointer_store,
effective_space,
mount->peer_key,
mount->space_id,
&cursor,
&cursor_ref);
if (status == AMDUATD_FED_CURSOR_ERR_NOT_FOUND) {
cursor_present = false;
} else if (status == AMDUATD_FED_CURSOR_OK) {
@ -123,12 +125,15 @@ static amduatd_space_mounts_status_t amduatd_space_mounts_append_tracking(
amduat_reference_free(&cursor_ref);
return AMDUATD_SPACE_MOUNTS_ERR_STORE;
}
cursor_namespace = "v2";
}
if (!amduatd_mounts_buf_append_cstr(b, ",\"local_tracking\":{") ||
!amduatd_mounts_buf_append_cstr(b, "\"cursor_namespace\":\"") ||
!amduatd_mounts_buf_append_cstr(b, cursor_namespace) ||
!amduatd_mounts_buf_append_cstr(
b,
"\"cursor_scope\":\"per-peer-per-local-space\","
"\",\"cursor_scope\":\"per-peer-per-local-space\","
"\"remote_space_id\":\"") ||
!amduatd_mounts_buf_append_cstr(b, mount->space_id) ||
!amduatd_mounts_buf_append_cstr(b, "\",\"pull_cursor\":{") ||

View file

@ -312,24 +312,40 @@ static bool amduatd_space_roots_append_cursor_heads(
return ok;
}
static bool amduatd_space_roots_cursor_peer_from_name(
const char *prefix,
const char *pointer_name,
char **out_peer) {
bool amduatd_space_roots_cursor_parse(const char *prefix,
const char *pointer_name,
char **out_peer,
char **out_remote_space_id) {
const char suffix[] = "/head";
size_t prefix_len;
size_t name_len;
size_t name_len_full;
size_t suffix_len = sizeof(suffix) - 1u;
size_t peer_len;
size_t remote_len = 0u;
char *peer;
char *remote = NULL;
const char *segment = NULL;
const char *remote_start = NULL;
const char *name_end = NULL;
if (out_peer != NULL) {
*out_peer = NULL;
}
if (out_remote_space_id != NULL) {
*out_remote_space_id = NULL;
}
if (prefix == NULL || pointer_name == NULL || out_peer == NULL) {
return false;
}
*out_peer = NULL;
prefix_len = strlen(prefix);
name_len = strlen(pointer_name);
if (name_len <= prefix_len + 1u + suffix_len) {
name_len_full = strlen(pointer_name);
name_len = name_len_full;
if (name_len_full >= suffix_len &&
strcmp(pointer_name + name_len_full - suffix_len, suffix) == 0) {
name_len = name_len_full - suffix_len;
}
if (name_len <= prefix_len + 1u) {
return false;
}
if (strncmp(pointer_name, prefix, prefix_len) != 0) {
@ -338,10 +354,18 @@ static bool amduatd_space_roots_cursor_peer_from_name(
if (pointer_name[prefix_len] != '/') {
return false;
}
if (strcmp(pointer_name + name_len - suffix_len, suffix) != 0) {
return false;
segment = pointer_name + prefix_len + 1u;
name_end = pointer_name + name_len;
remote_start = memchr(segment, '/', (size_t)(name_end - segment));
if (remote_start != NULL) {
peer_len = (size_t)(remote_start - segment);
if (remote_start + 1u >= name_end) {
return false;
}
remote_len = (size_t)(name_end - (remote_start + 1u));
} else {
peer_len = (size_t)(name_end - segment);
}
peer_len = name_len - prefix_len - 1u - suffix_len;
if (peer_len == 0u) {
return false;
}
@ -349,8 +373,18 @@ static bool amduatd_space_roots_cursor_peer_from_name(
if (peer == NULL) {
return false;
}
memcpy(peer, pointer_name + prefix_len + 1u, peer_len);
memcpy(peer, segment, peer_len);
peer[peer_len] = '\0';
if (remote_len != 0u && out_remote_space_id != NULL) {
remote = (char *)malloc(remote_len + 1u);
if (remote == NULL) {
free(peer);
return false;
}
memcpy(remote, remote_start + 1u, remote_len);
remote[remote_len] = '\0';
*out_remote_space_id = remote;
}
*out_peer = peer;
return true;
}
@ -552,10 +586,10 @@ bool amduatd_space_roots_list_cursor_peers(
for (size_t i = 0u; i < pull_heads.len; ++i) {
char *peer = NULL;
if (amduatd_space_roots_cursor_peer_from_name(
(const char *)pull_prefix.data,
pull_heads.names[i],
&peer)) {
if (amduatd_space_roots_cursor_parse((const char *)pull_prefix.data,
pull_heads.names[i],
&peer,
NULL)) {
if (!amduatd_space_roots_list_add(out_list, peer)) {
free(peer);
goto cleanup;
@ -565,10 +599,10 @@ bool amduatd_space_roots_list_cursor_peers(
}
for (size_t i = 0u; i < push_heads.len; ++i) {
char *peer = NULL;
if (amduatd_space_roots_cursor_peer_from_name(
(const char *)push_prefix.data,
push_heads.names[i],
&peer)) {
if (amduatd_space_roots_cursor_parse((const char *)push_prefix.data,
push_heads.names[i],
&peer,
NULL)) {
if (!amduatd_space_roots_list_add(out_list, peer)) {
free(peer);
goto cleanup;

View file

@ -35,6 +35,11 @@ bool amduatd_space_roots_list_cursor_peers(
const amduatd_space_t *effective_space,
amduatd_space_roots_list_t *out_list);
bool amduatd_space_roots_cursor_parse(const char *prefix,
const char *pointer_name,
char **out_peer,
char **out_remote_space_id);
void amduatd_space_roots_list_free(amduatd_space_roots_list_t *list);
#ifdef __cplusplus

View file

@ -199,6 +199,42 @@ int main(void) {
amduat_octets_free(&name);
}
{
amduat_octets_t name = amduat_octets(NULL, 0u);
bool ok = amduatd_fed_cursor_pointer_name_v2(&space,
"peer-a",
"beta",
&name);
expect(ok, "v2 cursor pointer name ok");
expect(strcmp((const char *)name.data,
"space/alpha/fed/cursor/peer-a/beta/head") == 0,
"v2 cursor pointer name matches");
amduat_octets_free(&name);
}
{
amduat_octets_t name = amduat_octets(NULL, 0u);
bool ok = amduatd_fed_push_cursor_pointer_name_v2(&space,
"peer-a",
"beta",
&name);
expect(ok, "v2 push cursor pointer name ok");
expect(strcmp((const char *)name.data,
"space/alpha/fed/push_cursor/peer-a/beta/head") == 0,
"v2 push cursor pointer name matches");
amduat_octets_free(&name);
}
{
amduat_octets_t name = amduat_octets(NULL, 0u);
bool ok = amduatd_fed_cursor_pointer_name_v2(&space,
"peer-a",
"bad/space",
&name);
expect(!ok, "remote space validation rejects invalid id");
amduat_octets_free(&name);
}
free(root);
return failures == 0 ? 0 : 1;
}

View file

@ -375,6 +375,7 @@ int main(void) {
&pointer_store,
&space,
"1",
NULL,
2u,
&fed_cfg,
&transport,
@ -478,6 +479,7 @@ int main(void) {
&pointer_store,
&space,
"1",
NULL,
2u,
&fed_cfg,
&transport,
@ -550,6 +552,7 @@ int main(void) {
&pointer_store,
&space,
"1",
NULL,
1u,
&fed_cfg,
&transport,

View file

@ -297,6 +297,7 @@ static int amduatd_test_pull_until_zero(void) {
&pointer_store,
&space,
"1",
NULL,
16u,
3u,
&fed_cfg,
@ -391,6 +392,7 @@ static int amduatd_test_pull_until_multi(void) {
&pointer_store,
&space,
"1",
NULL,
2u,
5u,
&fed_cfg,
@ -483,6 +485,7 @@ static int amduatd_test_pull_until_error(void) {
&pointer_store,
&space,
"1",
NULL,
1u,
4u,
&fed_cfg,

View file

@ -238,6 +238,7 @@ int main(void) {
&pointer_store,
&space,
"2",
NULL,
16u,
root,
&fed_cfg,

View file

@ -210,6 +210,7 @@ static int amduatd_test_push_until_zero(void) {
&pointer_store,
&space,
"2",
NULL,
8u,
3u,
root,
@ -308,6 +309,7 @@ static int amduatd_test_push_until_multi(void) {
&pointer_store,
&space,
"2",
NULL,
1u,
5u,
root,
@ -410,6 +412,7 @@ static int amduatd_test_push_until_error(void) {
&pointer_store,
&space,
"2",
NULL,
1u,
4u,
root,

View file

@ -274,13 +274,15 @@ static int amduatd_test_mounts_resolve(void) {
cursor.has_record_ref = true;
cursor.last_record_ref = cursor_last_ref;
memset(&cursor_ref, 0, sizeof(cursor_ref));
if (amduatd_fed_cursor_cas_set(&store,
&pointer_store,
&space,
"peer-1",
NULL,
&cursor,
&cursor_ref) != AMDUATD_FED_CURSOR_OK) {
if (amduatd_fed_cursor_cas_set_remote(&store,
&pointer_store,
&space,
"peer-1",
"beta",
NULL,
&cursor,
&cursor_ref) !=
AMDUATD_FED_CURSOR_OK) {
fprintf(stderr, "failed to set cursor\n");
amduatd_fed_cursor_record_free(&cursor);
amduat_reference_free(&cursor_ref);
@ -322,6 +324,8 @@ static int amduatd_test_mounts_resolve(void) {
"pinned mode present");
expect(strstr(mounts_json, "\"pinned_root_ref\":\"") != NULL,
"pinned root ref present");
expect(strstr(mounts_json, "\"cursor_namespace\":\"v2\"") != NULL,
"cursor namespace present");
expect(strstr(mounts_json, "\"cursor_scope\":\"per-peer-per-local-space\"") != NULL,
"cursor scope present");
expect(strstr(mounts_json, "\"remote_space_id\":\"beta\"") != NULL,

View file

@ -184,6 +184,8 @@ static int amduatd_test_cursor_roots(void) {
amduat_reference_t none_ref;
amduat_octets_t cursor_name = amduat_octets(NULL, 0u);
amduat_octets_t push_name = amduat_octets(NULL, 0u);
amduat_octets_t cursor_v2 = amduat_octets(NULL, 0u);
amduat_octets_t push_v2 = amduat_octets(NULL, 0u);
amduat_octets_t edges_collection = amduat_octets(NULL, 0u);
amduat_octets_t edges_index_head = amduat_octets(NULL, 0u);
char *collection_head = NULL;
@ -237,7 +239,15 @@ static int amduatd_test_cursor_roots(void) {
amduat_artifact_free(&none_artifact);
if (!amduatd_fed_cursor_pointer_name(&space, "peer-a", &cursor_name) ||
!amduatd_fed_push_cursor_pointer_name(&space, "peer-b", &push_name)) {
!amduatd_fed_push_cursor_pointer_name(&space, "peer-b", &push_name) ||
!amduatd_fed_cursor_pointer_name_v2(&space,
"peer-a",
"beta",
&cursor_v2) ||
!amduatd_fed_push_cursor_pointer_name_v2(&space,
"peer-b",
"beta",
&push_v2)) {
fprintf(stderr, "failed to build cursor names\n");
free(root);
return 1;
@ -254,10 +264,24 @@ static int amduatd_test_cursor_roots(void) {
false,
NULL,
&none_ref,
&swapped) != AMDUAT_ASL_POINTER_OK || !swapped ||
amduat_asl_pointer_cas(&pointer_store,
(const char *)cursor_v2.data,
false,
NULL,
&none_ref,
&swapped) != AMDUAT_ASL_POINTER_OK || !swapped ||
amduat_asl_pointer_cas(&pointer_store,
(const char *)push_v2.data,
false,
NULL,
&none_ref,
&swapped) != AMDUAT_ASL_POINTER_OK || !swapped) {
fprintf(stderr, "failed to seed cursor pointers\n");
amduat_octets_free(&cursor_name);
amduat_octets_free(&push_name);
amduat_octets_free(&cursor_v2);
amduat_octets_free(&push_v2);
free(root);
return 1;
}
@ -266,6 +290,8 @@ static int amduatd_test_cursor_roots(void) {
fprintf(stderr, "roots list failed\n");
amduat_octets_free(&cursor_name);
amduat_octets_free(&push_name);
amduat_octets_free(&cursor_v2);
amduat_octets_free(&push_v2);
free(root);
return 1;
}
@ -284,9 +310,11 @@ static int amduatd_test_cursor_roots(void) {
return 1;
}
if (list.len != 5u ||
if (list.len != 7u ||
!amduatd_list_contains(&list, (const char *)cursor_name.data) ||
!amduatd_list_contains(&list, (const char *)push_name.data) ||
!amduatd_list_contains(&list, (const char *)cursor_v2.data) ||
!amduatd_list_contains(&list, (const char *)push_v2.data) ||
!amduatd_list_contains(&list, (const char *)edges_index_head.data) ||
!amduatd_list_contains(&list, collection_head) ||
!amduatd_list_contains(&list, collection_log_head) ||
@ -294,6 +322,8 @@ static int amduatd_test_cursor_roots(void) {
fprintf(stderr, "unexpected cursor roots list\n");
amduat_octets_free(&cursor_name);
amduat_octets_free(&push_name);
amduat_octets_free(&cursor_v2);
amduat_octets_free(&push_v2);
amduat_octets_free(&edges_collection);
amduat_octets_free(&edges_index_head);
free(collection_head);
@ -305,6 +335,8 @@ static int amduatd_test_cursor_roots(void) {
amduat_octets_free(&cursor_name);
amduat_octets_free(&push_name);
amduat_octets_free(&cursor_v2);
amduat_octets_free(&push_v2);
amduat_octets_free(&edges_collection);
amduat_octets_free(&edges_index_head);
free(collection_head);

View file

@ -203,6 +203,9 @@ static int amduatd_test_peer_discovery(void) {
!amduatd_list_contains(&peers, "2") ||
!amduatd_list_sorted(&peers)) {
fprintf(stderr, "unexpected peers list\n");
for (size_t i = 0u; i < peers.len; ++i) {
fprintf(stderr, " peer[%zu]=%s\n", i, peers.names[i]);
}
amduatd_space_roots_list_free(&peers);
amduat_octets_free(&pull_name);
amduat_octets_free(&push_name);