Skip to content

Commit f7c35b1

Browse files
committed
Fix SerializedObject.append perf issue:
* Replace array.concat(array2) with Array.prototype.push.apply
1 parent f1f0a43 commit f7c35b1

File tree

1 file changed

+37
-26
lines changed

1 file changed

+37
-26
lines changed

src/js/ripple/serializedobject.js

+37-26
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
var _ = require('lodash');
2-
var assert = require('assert');
3-
var extend = require('extend');
1+
'use strict';
2+
3+
var _ = require('lodash');
4+
var assert = require('assert');
5+
var extend = require('extend');
46
var binformat = require('./binformat');
5-
var stypes = require('./serializedtypes');
6-
var Crypt = require('./crypt').Crypt;
7-
var utils = require('./utils');
7+
var stypes = require('./serializedtypes');
8+
var Crypt = require('./crypt').Crypt;
9+
var utils = require('./utils');
810

911
var sjcl = utils.sjcl;
1012

@@ -29,12 +31,14 @@ Object.keys(binformat.ter).forEach(function(key) {
2931
function normalize_sjcl_bn_hex(string) {
3032
var hex = string.slice(2); // remove '0x' prefix
3133
// now strip leading zeros
32-
var i = _.findIndex(hex, function(c) { return c !== '0'; });
34+
var i = _.findIndex(hex, function(c) {
35+
return c !== '0';
36+
});
3337
return i >= 0 ? hex.slice(i) : '0';
3438
}
3539

3640
function SerializedObject(buf) {
37-
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf)) ) {
41+
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf))) {
3842
this.buffer = buf;
3943
} else if (typeof buf === 'string') {
4044
this.buffer = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(buf));
@@ -49,7 +53,7 @@ function SerializedObject(buf) {
4953
SerializedObject.from_json = function(obj) {
5054
// Create a copy of the object so we don't modify it
5155
obj = extend(true, {}, obj);
52-
var so = new SerializedObject();
56+
var so = new SerializedObject();
5357
var typedef;
5458

5559
if (typeof obj.TransactionType === 'number') {
@@ -107,17 +111,17 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
107111
var field = spec[0];
108112
var requirement = spec[1];
109113

110-
if (binformat.REQUIRED === requirement && obj[field] === void(0)) {
114+
if (binformat.REQUIRED === requirement && obj[field] === undefined) {
111115
missing_fields.push(field);
112116
}
113117
}
114118

115119
if (missing_fields.length > 0) {
116120
var object_name;
117121

118-
if (obj.TransactionType !== void(0)) {
122+
if (obj.TransactionType !== undefined) {
119123
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
120-
} else if (obj.LedgerEntryType != null){
124+
} else if (obj.LedgerEntryType !== undefined) {
121125
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
122126
} else {
123127
object_name = 'TransactionMetaData';
@@ -133,7 +137,17 @@ SerializedObject.prototype.append = function(bytes) {
133137
bytes = bytes.buffer;
134138
}
135139

136-
this.buffer = this.buffer.concat(bytes);
140+
// Make sure both buffer and bytes are Array. Either could potentially be a
141+
// Buffer.
142+
if (Array.isArray(this.buffer) && Array.isArray(bytes)) {
143+
// Array::concat is horribly slow where buffer length is 100 kbytes + One
144+
// transaction with 1100 affected nodes took around 23 seconds to convert
145+
// from json to bytes.
146+
Array.prototype.push.apply(this.buffer, bytes);
147+
} else {
148+
this.buffer = this.buffer.concat(bytes);
149+
}
150+
137151
this.pointer += bytes.length;
138152
};
139153

@@ -216,14 +230,17 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
216230
if (typeof structure.to_json === 'function') {
217231
output = structure.to_json();
218232
} else if (structure instanceof sjcl.bn) {
219-
output = ('0000000000000000' + normalize_sjcl_bn_hex(structure.toString()).toUpperCase()).slice(-16);
233+
output = ('0000000000000000' +
234+
normalize_sjcl_bn_hex(structure.toString())
235+
.toUpperCase()
236+
).slice(-16);
220237
} else {
221-
//new Array or Object
238+
// new Array or Object
222239
output = new structure.constructor();
223240

224241
var keys = Object.keys(structure);
225242

226-
for (var i=0, l=keys.length; i<l; i++) {
243+
for (var i = 0, l = keys.length; i < l; i++) {
227244
var key = keys[i];
228245
output[key] = SerializedObject.jsonify_structure(structure[key], key);
229246
}
@@ -256,7 +273,7 @@ SerializedObject.prototype.hash = function(prefix) {
256273
var sign_buffer = new SerializedObject();
257274

258275
// Add hashing prefix
259-
if ('undefined' !== typeof prefix) {
276+
if (typeof prefix !== 'undefined') {
260277
stypes.Int32.serialize(sign_buffer, prefix);
261278
}
262279

@@ -272,17 +289,11 @@ SerializedObject.prototype.hash = function(prefix) {
272289
SerializedObject.prototype.signing_hash = SerializedObject.prototype.hash;
273290

274291
SerializedObject.prototype.serialize_field = function(spec, obj) {
275-
var name = spec[0];
292+
var name = spec[0];
276293
var presence = spec[1];
277-
var field_id = spec[2];
278-
var Type = stypes[spec[3]];
279294

280295
if (typeof obj[name] !== 'undefined') {
281-
// ST: Old serialization code
282-
//this.append(SerializedObject.get_field_header(Type.id, field_id));
283296
try {
284-
// ST: Old serialization code
285-
//Type.serialize(this, obj[name]);
286297
stypes.serialize(this, name, obj[name]);
287298
} catch (e) {
288299
// Add field name to message and rethrow
@@ -295,7 +306,7 @@ SerializedObject.prototype.serialize_field = function(spec, obj) {
295306
};
296307

297308
SerializedObject.get_field_header = function(type_id, field_id) {
298-
var buffer = [ 0 ];
309+
var buffer = [0];
299310

300311
if (type_id > 0xF) {
301312
buffer.push(type_id & 0xFF);
@@ -328,7 +339,7 @@ SerializedObject.lookup_type_tx = function(id) {
328339
return TRANSACTION_TYPES[id];
329340
};
330341

331-
SerializedObject.lookup_type_le = function (id) {
342+
SerializedObject.lookup_type_le = function(id) {
332343
assert(typeof id === 'number');
333344
return LEDGER_ENTRY_TYPES[id];
334345
};

0 commit comments

Comments
 (0)