]> git.evergreen-ils.org Git - OpenSRF.git/commit
2 Patches from Scott McKellar, with slight modification:
authorerickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Tue, 18 Nov 2008 22:23:29 +0000 (22:23 +0000)
committererickson <erickson@9efc2488-bf62-4759-914b-345cdb29e865>
Tue, 18 Nov 2008 22:23:29 +0000 (22:23 +0000)
commit4a02ad9f39356a92105fdd1491a95e98634e5ea3
treeb51049d0d2eaac7e2a219a2ad83bd0c453733b38
parentc5904a8e5afdcc24dd9d400c970ddb6db626bbfe
2 Patches from Scott McKellar, with slight modification:

This patch adds a new function buffer_append_uescape(), a streamlined
replacement for uescape().  The optimizations are as follows:

1. As described in an earlier post, the new function appends the uescaped
text to an existing growing_buffer, rather than into an internal one that
it must create and destroy.  It thereby saves two mallocs and two frees.
In addition, the calling code doesn't have to do a buffer_add().

2. Because it doesn't create an internal growing_buffer, it doesn't need
to do a strlen() to determine how big a buffer to allocate.

3. Since the new version doesn't have a boolean parameter, it doesn't have
to test the boolean.

4. For characters < 128 (i.e. ASCII characters), I rearranged the order of
the tests so that non-control characters are recognized immediately.  In
uescape() we first go through a switch/case looking for several specific
control characters like '\b' and '\n'.  In practice most characters are
not control characters, so this rearrangement saves a few CPU cycles.

5. For control characters, uescape() uses buffer_fadd() to format the
character into hex.  Now, buffer_fadd is slow because it uses vsnprintf()
twice, once to determine a buffer size and once to do the formatting.  In
turn vsnprintf() is slow because it has to parse the format string.  In
this case we don't need vsnprintf() because we already know exactly how
big the buffer needs to be, and the formatting is simple.  I eliminated
buffer_fadd() and formatted the hex manually with a little bit-twiddling.

Some of these optimizations could be applied to uescape(), but I haven't
bothered, partly because I wanted a clean comparison for benchmarking
purposes and partly because I expect uescape() to disappear from use
(though I am leaving it available).

=====

This patch is a rewrite of the jsonObjectToJSON and jsonObjectToJSONRaw functions.  It is dependent on my previous patch to utils.c and utils.h,
adding the new buffer_append_uescape function.

One purpose is to replace a call to the uescape function with a call to
the faster buffer_append_uescape function.  The other purpose is to
introduce a faster way to translate a jsonObject into a string.

(Also in one spot I broke up a very long string literal into several
smaller pieces so that it wouldn't wrap around in the editor.)

In the existing jsonObjectToJSON function, we receive a pointer to a
jsonObject and return a string of JSON.  However we don't translate the
original jsonObject directly.  Instead, we create a modified clone of the
original, inserting an additional JSON_HASH node wherever we find a
classname.  Then we translate the clone, and finally destroy it.

It always struck me as an egregious waste to create and destroy a whole
parallel object just so that we could turn it into a string.  So I looked
for a way to eliminate the cloning.

The result is a modification of add_json_to_buffer(), a local function
that recursively traverses and translates the jsonObject.  When it sees a
classname (and it has been asked to expand classnames), the new version
inserts additional gibberish into the output text and then continues the
traversal, without modifying or copying the original jsonObject at all.

In my benchmark, this new approach was faster than the original by a
factor of about 5.  When I combined this change with the use of the new
buffer_append_uencode function, it was faster by a factor of about 7.2.
The benchmark used a moderately complex jsonObject about 5 or 6 levels
deep, with both hashes and arrays, with classnames at several levels.
The performance gain will no doubt depend on the contents of the
jsonObject,but I haven't tried to isolate the variables.

The new version is a bit trickier and harder to read than the old.  In my
opinion the speedup is worth the obscurity, because a lot of places in
Evergreen will benefit.

git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1498 9efc2488-bf62-4759-914b-345cdb29e865
src/libopensrf/osrf_json_object.c
src/libopensrf/utils.c