1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-19 02:05:32 +00:00

(trunk, libT) faster JSON parsing for tr_variant. This mostly helps the Qt client, which makes heavy use of the JSON-based RPC calls.

This commit is contained in:
Jordan Lee 2012-12-15 00:01:59 +00:00
parent 1dc8c47059
commit df5b6365bd
7 changed files with 96 additions and 68 deletions

View file

@ -563,7 +563,7 @@ addIdArg (tr_variant * args, const char * id)
if (!isdigit (*pch))
isNum = false;
if (isNum || isList)
tr_rpc_parse_list_str (tr_variantDictAdd (args, "ids"), id, strlen (id));
tr_rpc_parse_list_str (tr_variantDictAdd (args, "ids", 3), id, strlen (id));
else
tr_variantDictAddStr (args, "ids", id); /* it's a torrent sha hash */
}

View file

@ -336,8 +336,8 @@ makeInfoDict (tr_variant * dict,
for (i = 0; i < builder->fileCount; ++i)
{
tr_variant * d = tr_variantListAddDict (list, 2);
tr_variant * length = tr_variantDictAdd (d, "length");
tr_variant * pathVal = tr_variantDictAdd (d, "path");
tr_variant * length = tr_variantDictAdd (d, "length", 6);
tr_variant * pathVal = tr_variantDictAdd (d, "path", 4);
getFileInfo (builder->top, &builder->files[i], length, pathVal);
}
}

View file

@ -66,6 +66,7 @@
#define KEY_PROGRESS_MTIMES "mtimes"
#define KEY_PROGRESS_BITFIELD "bitfield"
#define KEY_PROGRESS_BLOCKS "blocks"
#define KEY_PROGRESS_BLOCKS_STRLEN 6
#define KEY_PROGRESS_HAVE "have"
enum
@ -480,7 +481,7 @@ saveProgress (tr_variant * dict, tr_torrent * tor)
/* add the blocks bitfield */
bitfieldToBenc (&tor->completion.blockBitfield,
tr_variantDictAdd (prog, KEY_PROGRESS_BLOCKS));
tr_variantDictAdd (prog, KEY_PROGRESS_BLOCKS, KEY_PROGRESS_BLOCKS_STRLEN));
}
static uint64_t

View file

@ -630,7 +630,7 @@ addField (tr_torrent * const tor,
else if (tr_streq (key, keylen, "peer-limit"))
tr_variantDictAddInt (d, key, tr_torrentGetPeerLimit (tor));
else if (tr_streq (key, keylen, "peers"))
addPeers (tor, tr_variantDictAdd (d, key));
addPeers (tor, tr_variantDictAdd (d, key, keylen));
else if (tr_streq (key, keylen, "peersConnected"))
tr_variantDictAddInt (d, key, st->peersConnected);
else if (tr_streq (key, keylen, "peersFrom"))
@ -1332,7 +1332,7 @@ addTorrentImpl (struct tr_rpc_idle_data * data, tr_ctor * ctor)
tr_variantListAddStr (&fields, "id");
tr_variantListAddStr (&fields, "name");
tr_variantListAddStr (&fields, "hashString");
addInfo (tor, tr_variantDictAdd (data->args_out, "torrent-added"), &fields);
addInfo (tor, tr_variantDictAdd (data->args_out, "torrent-added", 13), &fields);
notify (data->session, TR_RPC_TORRENT_ADDED, tor);
tr_variantFree (&fields);
}
@ -1970,7 +1970,7 @@ tr_rpc_request_exec_uri (tr_session * session,
char * key = tr_strndup (pch, delim - pch);
int isArg = strcmp (key, "method") && strcmp (key, "tag");
tr_variant * parent = isArg ? args : &top;
tr_rpc_parse_list_str (tr_variantDictAdd (parent, key),
tr_rpc_parse_list_str (tr_variantDictAdd (parent, key, delim-pch),
delim + 1,
next ? (size_t)(
next -

View file

@ -43,7 +43,10 @@ struct json_wrapper_data
int error;
bool has_content;
tr_variant * top;
char * key;
const char * key;
size_t keylen;
struct evbuffer * keybuf;
struct evbuffer * strbuf;
const char * source;
tr_ptrArray stack;
};
@ -69,9 +72,10 @@ get_node (struct jsonsl_st * jsn)
}
else if (tr_variantIsDict (parent) && (data->key!=NULL))
{
node = tr_variantDictAdd (parent, data->key);
tr_free (data->key);
node = tr_variantDictAdd (parent, data->key, data->keylen);
data->key = NULL;
data->keylen = 0;
}
return node;
@ -167,46 +171,35 @@ decode_hex_string (const char * in, unsigned int * setme)
}
static char*
extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len)
extract_escaped_string (const char * in, size_t in_len, size_t * len, struct evbuffer * buf)
{
const char * in_begin;
const char * in_end;
const char * in_it;
size_t out_buflen;
char * out_buf;
char * out_it;
const char * const in_end = in + in_len;
in_begin = jsn->base + state->pos_begin;
if (*in_begin == '"')
in_begin++;
in_end = jsn->base + state->pos_cur;
evbuffer_drain (buf, evbuffer_get_length (buf));
out_buflen = (in_end-in_begin)*3 + 1;
out_buf = tr_new0 (char, out_buflen);
out_it = out_buf;
for (in_it=in_begin; in_it!=in_end;)
while (in < in_end)
{
bool unescaped = false;
if (*in_it=='\\' && in_end-in_it>=2)
if (*in=='\\' && in_end-in>=2)
{
switch (in_it[1])
switch (in[1])
{
case 'b' : *out_it++ = '\b'; in_it+=2; unescaped = true; break;
case 'f' : *out_it++ = '\f'; in_it+=2; unescaped = true; break;
case 'n' : *out_it++ = '\n'; in_it+=2; unescaped = true; break;
case 'r' : *out_it++ = '\r'; in_it+=2; unescaped = true; break;
case 't' : *out_it++ = '\t'; in_it+=2; unescaped = true; break;
case '/' : *out_it++ = '/' ; in_it+=2; unescaped = true; break;
case '"' : *out_it++ = '"' ; in_it+=2; unescaped = true; break;
case '\\': *out_it++ = '\\'; in_it+=2; unescaped = true; break;
case 'b' : evbuffer_add (buf, "\b", 1); in+=2; unescaped = true; break;
case 'f' : evbuffer_add (buf, "\f", 1); in+=2; unescaped = true; break;
case 'n' : evbuffer_add (buf, "\n", 1); in+=2; unescaped = true; break;
case 'r' : evbuffer_add (buf, "\r", 1); in+=2; unescaped = true; break;
case 't' : evbuffer_add (buf, "\t", 1); in+=2; unescaped = true; break;
case '/' : evbuffer_add (buf, "/" , 1); in+=2; unescaped = true; break;
case '"' : evbuffer_add (buf, "\"" , 1); in+=2; unescaped = true; break;
case '\\': evbuffer_add (buf, "\\", 1); in+=2; unescaped = true; break;
case 'u':
{
if (in_end - in_it >= 6)
if (in_end - in >= 6)
{
unsigned int val = 0;
if (decode_hex_string (in_it, &val))
if (decode_hex_string (in, &val))
{
UTF32 str32_buf[2] = { val, 0 };
const UTF32 * str32_walk = str32_buf;
@ -214,16 +207,15 @@ extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len)
UTF8 str8_buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
UTF8 * str8_walk = str8_buf;
UTF8 * str8_end = str8_buf + 8;
if (ConvertUTF32toUTF8 (&str32_walk, str32_end, &str8_walk, str8_end, 0) == 0)
{
const size_t len = str8_walk - str8_buf;
memcpy (out_it, str8_buf, len);
out_it += len;
evbuffer_add (buf, str8_buf, len);
unescaped = true;
}
in_it += 6;
in += 6;
break;
}
}
@ -232,13 +224,43 @@ extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len)
}
if (!unescaped)
*out_it++ = *in_it++;
{
evbuffer_add (buf, in, 1);
++in;
}
}
if (len != NULL)
*len = out_it - out_buf;
*len = evbuffer_get_length (buf);
return (char*) evbuffer_pullup (buf, -1);
}
return out_buf;
static const char*
extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len, struct evbuffer * buf)
{
const char * ret;
const char * in_begin;
const char * in_end;
size_t in_len;
/* figure out where the string is */
in_begin = jsn->base + state->pos_begin;
if (*in_begin == '"')
in_begin++;
in_end = jsn->base + state->pos_cur;
in_len = in_end - in_begin;
if (memchr (in_begin, '\\', in_len) == NULL)
{
/* it's not escaped */
ret = in_begin;
*len = in_len;
}
else
{
ret = extract_escaped_string (in_begin, in_len, len, buf);
}
return ret;
}
static void
@ -251,17 +273,15 @@ action_callback_POP (jsonsl_t jsn,
if (state->type == JSONSL_T_STRING)
{
size_t len = 0;
char * str = extract_string (jsn, state, &len);
size_t len;
const char * str = extract_string (jsn, state, &len, data->strbuf);
tr_variantInitStr (get_node (jsn), str, len);
data->has_content = true;
tr_free (str);
}
else if (state->type == JSONSL_T_HKEY)
{
char * str = extract_string (jsn, state, NULL);
data->has_content = true;
data->key = str;
data->key = extract_string (jsn, state, &data->keylen, data->keybuf);
}
else if ((state->type == JSONSL_T_LIST) || (state->type == JSONSL_T_OBJECT))
{
@ -319,6 +339,8 @@ tr_jsonParse (const char * source,
data.top = setme_benc;
data.stack = TR_PTR_ARRAY_INIT;
data.source = source;
data.keybuf = evbuffer_new ();
data.strbuf = evbuffer_new ();
/* parse it */
jsonsl_feed (jsn, vbuf, len);
@ -333,6 +355,8 @@ tr_jsonParse (const char * source,
/* cleanup */
error = data.error;
evbuffer_free (data.keybuf);
evbuffer_free (data.strbuf);
tr_ptrArrayDestruct (&data.stack, NULL);
jsonsl_destroy (jsn);
return error;

View file

@ -88,17 +88,18 @@ dictIndexOf (const tr_variant * dict, const char * key)
{
if (tr_variantIsDict (dict))
{
size_t i;
const tr_variant * walk;
const tr_variant * const begin = dict->val.l.vals;
const tr_variant * const end = begin + dict->val.l.count;
const size_t len = strlen (key);
for (i=0; (i+1) < dict->val.l.count; i += 2)
{
const tr_variant * child = dict->val.l.vals + i;
if ((child->type == TR_VARIANT_TYPE_STR)
&& (child->val.s.len == len)
&& !memcmp (getStr (child), key, len))
return i;
}
for (walk=begin; walk!=end; walk+=2)
{
assert (walk->type == TR_VARIANT_TYPE_STR);
if ((walk->val.s.len==len) && !memcmp (getStr(walk), key, len))
return walk - begin;
}
}
return -1;
@ -527,7 +528,8 @@ tr_variantListAddDict (tr_variant * list,
tr_variant *
tr_variantDictAdd (tr_variant * dict,
const char * key)
const char * key,
int keylen)
{
tr_variant * child_key;
tr_variant * child_val;
@ -537,7 +539,7 @@ tr_variantDictAdd (tr_variant * dict,
containerReserve (dict, 2);
child_key = dict->val.l.vals + dict->val.l.count++;
tr_variantInitStr (child_key, key, -1);
tr_variantInitStr (child_key, key, keylen);
child_val = dict->val.l.vals + dict->val.l.count++;
tr_variantInit (child_val, TR_VARIANT_TYPE_INT);
@ -561,7 +563,7 @@ dictFindOrAdd (tr_variant * dict, const char * key, int type)
/* if it doesn't exist, create it */
if (child == NULL)
child = tr_variantDictAdd (dict, key);
child = tr_variantDictAdd (dict, key, -1);
return child;
}
@ -614,7 +616,7 @@ dictRecycleOrAdd (tr_variant * dict, const char * key)
/* if it doesn't exist, create it */
if (child == NULL)
child = tr_variantDictAdd (dict, key);
child = tr_variantDictAdd (dict, key, -1);
return child;
}
@ -644,7 +646,7 @@ tr_variantDictAddList (tr_variant * dict,
const char * key,
size_t reserve_count)
{
tr_variant * child = tr_variantDictAdd (dict, key);
tr_variant * child = tr_variantDictAdd (dict, key, -1);
tr_variantInitList (child, reserve_count);
return child;
}
@ -654,7 +656,7 @@ tr_variantDictAddDict (tr_variant * dict,
const char * key,
size_t reserve_count)
{
tr_variant * child = tr_variantDictAdd (dict, key);
tr_variant * child = tr_variantDictAdd (dict, key, -1);
tr_variantInitDict (child, reserve_count);
return child;
}

View file

@ -320,7 +320,8 @@ int tr_variantDictRemove (tr_variant * dict,
const char * key);
tr_variant * tr_variantDictAdd (tr_variant * dict,
const char * key);
const char * key,
int keylen);
tr_variant * tr_variantDictAddReal (tr_variant * dict,
const char * key,