json/write: add an output buffer
This improves output speed significantly, especially if the write callback is expensive (e.g. issues a syscall or takes a lock). On my test system, jsoncat citylots.json > /dev/null improves from ~2.8s to ~1.7s. citylots.json: https://github.com/zemirco/sf-city-lots-json (~181 MiB) Change-Id: I7d411ce92366712ed87ad5fc6e9b64828541db4d Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
2138676573
commit
a509ddeb24
@ -47,6 +47,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "spdk/likely.h"
|
||||||
#include "spdk/string.h"
|
#include "spdk/string.h"
|
||||||
|
|
||||||
#define SPDK_JSON_MAX_NESTING_DEPTH 64
|
#define SPDK_JSON_MAX_NESTING_DEPTH 64
|
||||||
|
@ -41,8 +41,34 @@ struct spdk_json_write_ctx {
|
|||||||
bool new_indent;
|
bool new_indent;
|
||||||
bool first_value;
|
bool first_value;
|
||||||
bool failed;
|
bool failed;
|
||||||
|
size_t buf_filled;
|
||||||
|
uint8_t buf[4096];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size);
|
||||||
|
|
||||||
|
static int
|
||||||
|
fail(struct spdk_json_write_ctx *w)
|
||||||
|
{
|
||||||
|
w->failed = true;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
flush_buf(struct spdk_json_write_ctx *w)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = w->write_cb(w->cb_ctx, w->buf, w->buf_filled);
|
||||||
|
if (rc != 0) {
|
||||||
|
return fail(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
w->buf_filled = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct spdk_json_write_ctx *
|
struct spdk_json_write_ctx *
|
||||||
spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx, uint32_t flags)
|
spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx, uint32_t flags)
|
||||||
{
|
{
|
||||||
@ -60,6 +86,7 @@ spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx, uint32_t flags)
|
|||||||
w->new_indent = false;
|
w->new_indent = false;
|
||||||
w->first_value = true;
|
w->first_value = true;
|
||||||
w->failed = false;
|
w->failed = false;
|
||||||
|
w->buf_filled = 0;
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
@ -68,6 +95,7 @@ int
|
|||||||
spdk_json_write_end(struct spdk_json_write_ctx *w)
|
spdk_json_write_end(struct spdk_json_write_ctx *w)
|
||||||
{
|
{
|
||||||
bool failed;
|
bool failed;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (w == NULL) {
|
if (w == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -75,28 +103,51 @@ spdk_json_write_end(struct spdk_json_write_ctx *w)
|
|||||||
|
|
||||||
failed = w->failed;
|
failed = w->failed;
|
||||||
|
|
||||||
|
rc = flush_buf(w);
|
||||||
|
if (rc != 0) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
free(w);
|
free(w);
|
||||||
|
|
||||||
return failed ? -1 : 0;
|
return failed ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static inline int
|
||||||
fail(struct spdk_json_write_ctx *w)
|
emit(struct spdk_json_write_ctx *w, const void *data, size_t size)
|
||||||
{
|
{
|
||||||
w->failed = true;
|
size_t buf_remain = sizeof(w->buf) - w->buf_filled;
|
||||||
return -1;
|
|
||||||
|
if (spdk_unlikely(size > buf_remain)) {
|
||||||
|
/* Not enough space in buffer for the new data. */
|
||||||
|
return emit_buf_full(w, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the new data into buf. */
|
||||||
|
memcpy(w->buf + w->buf_filled, data, size);
|
||||||
|
w->buf_filled += size;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emit(struct spdk_json_write_ctx *w, const void *data, size_t size)
|
emit_buf_full(struct spdk_json_write_ctx *w, const void *data, size_t size)
|
||||||
{
|
{
|
||||||
|
size_t buf_remain = sizeof(w->buf) - w->buf_filled;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = w->write_cb(w->cb_ctx, data, size);
|
assert(size > buf_remain);
|
||||||
|
|
||||||
|
/* Copy as much of the new data as possible into the buffer and flush it. */
|
||||||
|
memcpy(w->buf + w->buf_filled, data, buf_remain);
|
||||||
|
w->buf_filled += buf_remain;
|
||||||
|
|
||||||
|
rc = flush_buf(w);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return fail(w);
|
return fail(w);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
/* Recurse to emit the rest of the data. */
|
||||||
|
return emit(w, data + buf_remain, size - buf_remain);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
Loading…
Reference in New Issue
Block a user