Skip to content

Commit

Permalink
json: Only start parsing once we're sure we have a message
Browse files Browse the repository at this point in the history
PR ElementsProject#3957 improved performance considerably, however we still look over the
entire message for the message separator. If instead we just look in the
incrementally read data, we remove the quadratic behavior for large messages.

This is safe since we then loop over the messages which would drain any
message separator from the buffer before we attempt the next read.

Changelog-Fixed: bcli: Significant speedups for block synchronization
  • Loading branch information
cdecker authored and rustyrussell committed Sep 2, 2020
1 parent 20cbf4d commit e45b22d
Showing 1 changed file with 27 additions and 15 deletions.
42 changes: 27 additions & 15 deletions lightningd/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,30 +491,42 @@ static struct io_plan *plugin_read_json(struct io_conn *conn,
struct plugin *plugin)
{
bool success;
bool have_full;

log_io(plugin->log, LOG_IO_IN, NULL, "",
plugin->buffer + plugin->used, plugin->len_read);

/* Our JSON parser is pretty good at incremental parsing, but
* `getrawblock` gives a giant 2MB token, which forces it to re-parse
* every time until we have all of it. However, we can't complete a
* JSON object without a '}', so we do a cheaper check here.
*/
have_full = memchr(plugin->buffer + plugin->used, '}',
plugin->len_read);

plugin->used += plugin->len_read;
if (plugin->used == tal_count(plugin->buffer))
tal_resize(&plugin->buffer, plugin->used * 2);

/* Read and process all messages from the connection */
do {
bool destroyed;
const char *err;
err = plugin_read_json_one(plugin, &success, &destroyed);

/* If it's destroyed, conn is already freed! */
if (destroyed)
return io_close(NULL);

if (err) {
plugin_kill(plugin, err);
/* plugin_kill frees plugin */
return io_close(NULL);
}
} while (success);
if (have_full) {
do {
bool destroyed;
const char *err;
err =
plugin_read_json_one(plugin, &success, &destroyed);

/* If it's destroyed, conn is already freed! */
if (destroyed)
return io_close(NULL);

if (err) {
plugin_kill(plugin, err);
/* plugin_kill frees plugin */
return io_close(NULL);
}
} while (success);
}

/* Now read more from the connection */
return io_read_partial(plugin->stdout_conn,
Expand Down

0 comments on commit e45b22d

Please sign in to comment.