Improve HTTP /restful/rhizome/bundlelist.json token

Now tokens are included in each row instead of a single token in the
enclosing JSON object.  Only puts tokens on the first row, and
thereafter all rows with a rowid higher than for the previous row that
had a token.
This commit is contained in:
Andrew Bettison 2013-11-18 15:10:28 +10:30
parent fb46ae0289
commit f8f7716544
3 changed files with 46 additions and 29 deletions

View File

@ -746,7 +746,8 @@ typedef struct rhizome_http_request
/* For responses that list manifests. /* For responses that list manifests.
*/ */
struct { struct {
enum { LIST_HEADER = 0, LIST_TOKEN, LIST_ROWS, LIST_DONE } phase; enum { LIST_HEADER = 0, LIST_ROWS, LIST_DONE } phase;
uint64_t rowid_highest;
size_t rowcount; size_t rowcount;
struct rhizome_list_cursor cursor; struct rhizome_list_cursor cursor;
} list; } list;

View File

@ -397,6 +397,7 @@ static char *list_token(char *buf, uint64_t rowid)
static int restful_rhizome_bundlelist_json_content_chunk(sqlite_retry_state *retry, struct rhizome_http_request *r, strbuf b) static int restful_rhizome_bundlelist_json_content_chunk(sqlite_retry_state *retry, struct rhizome_http_request *r, strbuf b)
{ {
const char *headers[] = { const char *headers[] = {
".token",
"_id", "_id",
"service", "service",
"id", "id",
@ -420,22 +421,16 @@ static int restful_rhizome_bundlelist_json_content_chunk(sqlite_retry_state *ret
strbuf_putc(b, ','); strbuf_putc(b, ',');
strbuf_json_string(b, headers[i]); strbuf_json_string(b, headers[i]);
} }
strbuf_puts(b, "]"); strbuf_puts(b, "],\n\"rows\":[");
if (!strbuf_overrun(b)) if (!strbuf_overrun(b))
r->u.list.phase = LIST_TOKEN; r->u.list.phase = LIST_ROWS;
return 1; return 1;
case LIST_TOKEN:
case LIST_ROWS: case LIST_ROWS:
{ {
int ret = rhizome_list_next(retry, &r->u.list.cursor); int ret = rhizome_list_next(retry, &r->u.list.cursor);
if (ret == -1) if (ret == -1)
return -1; return -1;
rhizome_manifest *m = r->u.list.cursor.manifest; rhizome_manifest *m = r->u.list.cursor.manifest;
if (r->u.list.phase == LIST_TOKEN) {
strbuf_puts(b, ",\n\"token\":");
strbuf_json_string(b, alloca_list_token(ret ? m->rowid : 0));
strbuf_puts(b, ",\n\"rows\":[");
}
if (ret == 0) { if (ret == 0) {
strbuf_puts(b, "\n]\n}\n"); strbuf_puts(b, "\n]\n}\n");
if (strbuf_overrun(b)) if (strbuf_overrun(b))
@ -445,9 +440,15 @@ static int restful_rhizome_bundlelist_json_content_chunk(sqlite_retry_state *ret
} }
assert(m->filesize != RHIZOME_SIZE_UNSET); assert(m->filesize != RHIZOME_SIZE_UNSET);
rhizome_lookup_author(m); rhizome_lookup_author(m);
if (r->u.list.phase != LIST_TOKEN) if (r->u.list.rowcount != 0)
strbuf_putc(b, ','); strbuf_putc(b, ',');
strbuf_puts(b, "\n["); strbuf_puts(b, "\n[");
if (m->rowid > r->u.list.rowid_highest) {
strbuf_json_string(b, alloca_list_token(m->rowid));
r->u.list.rowid_highest = m->rowid;
} else
strbuf_json_null(b);
strbuf_putc(b, ',');
strbuf_sprintf(b, "%"PRIu64, m->rowid); strbuf_sprintf(b, "%"PRIu64, m->rowid);
strbuf_putc(b, ','); strbuf_putc(b, ',');
strbuf_json_string(b, m->service); strbuf_json_string(b, m->service);

View File

@ -103,6 +103,7 @@ doc_RhizomeList="Fetch small Rhizome bundle list in JSON format"
setup_RhizomeList() { setup_RhizomeList() {
setup setup
NBUNDLES=100 NBUNDLES=100
ROWID_MAX=0
for ((n = 0; n != NBUNDLES; ++n)); do for ((n = 0; n != NBUNDLES; ++n)); do
create_file file$n $((1000 + $n)) create_file file$n $((1000 + $n))
executeOk_servald rhizome add file $SIDA file$n file$n.manifest executeOk_servald rhizome add file $SIDA file$n file$n.manifest
@ -112,7 +113,9 @@ setup_RhizomeList() {
extract_stdout_filehash HASH[$n] extract_stdout_filehash HASH[$n]
extract_stdout_date DATE[$n] extract_stdout_date DATE[$n]
extract_stdout_rowid ROWID[$n] extract_stdout_rowid ROWID[$n]
[ "${ROWID[$n]}" -gt "$ROWID_MAX" ] && ROWID_MAX=${ROWID[$n]}
done done
assert [ "$ROWID_MAX" -ge "$NBUNDLES" ]
} }
test_RhizomeList() { test_RhizomeList() {
executeOk curl \ executeOk curl \
@ -128,24 +131,25 @@ test_RhizomeList() {
# bundlelist.json from the following form (which is optimised for # bundlelist.json from the following form (which is optimised for
# transmission size): # transmission size):
# { # {
# "header":[ "_id", "service", "id", "version","date",".inserttime", # "header":[
# ".token", "_id", "service", "id", "version","date",".inserttime",
# ".author",".fromhere","filesize","filehash","sender","recipient", # ".author",".fromhere","filesize","filehash","sender","recipient",
# "name" # "name"
# ], # ],
# "token":"xxx",
# "rows":[ # "rows":[
# [ rowid1, "service1", bundleid1, version1, .... ], # [ "xx", rowid1, "service1", bundleid1, version1, .... ],
# [ rowid2, "service2", bundleid2, version2, .... ], # [ null, rowid2, "service2", bundleid2, version2, .... ],
# ... # ...
# [ rowidN, "serviceN", bundleidN, versionN, .... ] # [ null, rowidN, "serviceN", bundleidN, versionN, .... ]
# ] # ]
# } # }
# #
# into an array of JSON objects: # into an array of JSON objects:
# { # {
# "token":"xxx",
# "bundles":[ # "bundles":[
# { # {
# "__index": 0,
# ".token": "xx",
# "_id": rowid1, # "_id": rowid1,
# "service": service1, # "service": service1,
# "id": bundleid1, # "id": bundleid1,
@ -153,6 +157,8 @@ test_RhizomeList() {
# ... # ...
# }, # },
# { # {
# "__index": 1,
# ".token": null,
# "_id": rowid2, # "_id": rowid2,
# "service": service2, # "service": service2,
# "id": bundleid2, # "id": bundleid2,
@ -161,6 +167,8 @@ test_RhizomeList() {
# }, # },
# ... # ...
# { # {
# "__index": 2,
# ".token": null,
# "_id": rowidN, # "_id": rowidN,
# "service": serviceN, # "service": serviceN,
# "id": bundleidN, # "id": bundleidN,
@ -170,19 +178,25 @@ test_RhizomeList() {
# ] # ]
# } # }
# which is much easier to test with jq(1) expressions. # which is much easier to test with jq(1) expressions.
jq \ jq '
'[ [
.header as $h | .header as $header |
.rows[] as $d | .rows as $rows |
[ $d | keys | .[] as $i | {key:$h[$i], value:$d[$i]} ] | $rows | keys | .[] as $index |
from_entries [ $rows[$index] as $d | $d | keys | .[] as $i | {key:$header[$i], value:$d[$i]} ] |
] as $bundles | from_entries |
.token as $token | .["__index"] = $index
{ token:$token, bundles:$bundles }' \ ]
bundlelist.json >array_of_objects.json ' bundlelist.json >array_of_objects.json
tfw_preserve array_of_objects.json tfw_preserve array_of_objects.json
for ((n = 0; n != NBUNDLES; ++n)); do for ((n = 0; n != NBUNDLES; ++n)); do
jqscript=".bundles | contains([ if [ "${ROWID[$n]}" -eq "$ROWID_MAX" ]; then
# The first row must contain a non-null token string.
token=',".token":"","__index":0,'
else
token=',".token":null,'
fi
jqscript="contains([
{ name:\"file$n\", { name:\"file$n\",
service:\"file\", service:\"file\",
id:\"${BID[$n]}\", id:\"${BID[$n]}\",
@ -192,10 +206,11 @@ test_RhizomeList() {
date:${DATE[$n]}, date:${DATE[$n]},
_id:${ROWID[$n]}, _id:${ROWID[$n]},
\".fromhere\":1, \".fromhere\":1,
\".author\":\"$SIDA\", \".author\":\"$SIDA\"
$token
} }
])" ])"
assert [ "$(jq "$jqscript" array_of_objects.json)" = true ] assert --message="$jqscript" [ "$(jq "$jqscript" array_of_objects.json)" = true ]
done done
} }