Skip to content

Commit b92c275

Browse files
author
Ruben Bridgewater
committed
chore(jsparser): Refactor bulk string chunk handling
This gives a tiny performance improvement (a few %) in case of chunked bulk data. It will also minimize the memory usage a tiny bit.
1 parent b3aea39 commit b92c275

File tree

2 files changed

+79
-64
lines changed

2 files changed

+79
-64
lines changed

lib/parser.js

Lines changed: 74 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -385,36 +385,6 @@ JavascriptRedisParser.prototype.setStringNumbers = function (stringNumbers) {
385385
this.optionStringNumbers = stringNumbers
386386
}
387387

388-
/**
389-
* Concat a bulk string containing multiple chunks
390-
*
391-
* Notes:
392-
* 1) The first chunk might contain the whole bulk string including the \r
393-
* 2) We are only safe to fully add up elements that are neither the first nor any of the last two elements
394-
*
395-
* @param parser
396-
* @param buffer
397-
* @returns {String}
398-
*/
399-
function concatBulkString (parser) {
400-
var list = parser.bufferCache
401-
var chunks = list.length
402-
var offset = parser.bigStrSize - parser.totalChunkSize
403-
parser.offset = offset
404-
if (offset === 1) {
405-
if (chunks === 2) {
406-
return list[0].toString('utf8', parser.bigOffset, list[0].length - 1)
407-
}
408-
chunks--
409-
}
410-
var res = decoder.write(list[0].slice(parser.bigOffset))
411-
for (var i = 1; i < chunks - 1; i++) {
412-
res += decoder.write(list[i])
413-
}
414-
res += decoder.end(list[i].slice(0, offset - 2))
415-
return res
416-
}
417-
418388
/**
419389
* Decrease the bufferPool size over time
420390
* @returns {undefined}
@@ -444,37 +414,86 @@ function decreaseBufferPool () {
444414
}
445415

446416
/**
447-
* Concat the collected chunks from parser.bufferCache.
448-
*
449-
* Increases the bufferPool size beforehand if necessary.
417+
* Check if the requested size fits in the current bufferPool.
418+
* If it does not, reset and increase the bufferPool accordingly.
450419
*
451-
* @param parser
452420
* @param length
453-
* @returns {Buffer}
421+
* @returns {undefined}
454422
*/
455-
function concatBuffer (parser, length) {
456-
var list = parser.bufferCache
457-
var pos = bufferOffset
458-
length -= parser.offset
423+
function resizeBuffer (length) {
459424
if (bufferPool.length < length + bufferOffset) {
460425
var multiplier = length > 1024 * 1024 * 75 ? 2 : 3
461-
if (bufferOffset > 1024 * 1024 * 120) {
426+
if (bufferOffset > 1024 * 1024 * 111) {
462427
bufferOffset = 1024 * 1024 * 50
463428
}
464429
bufferPool = new Buffer(length * multiplier + bufferOffset)
465430
bufferOffset = 0
466431
counter++
467-
pos = 0
468432
if (interval === null) {
469433
interval = setInterval(decreaseBufferPool, 50)
470434
}
471435
}
472-
list[0].copy(bufferPool, pos, parser.offset, list[0].length)
473-
pos += list[0].length - parser.offset
474-
for (var i = 1; i < list.length; i++) {
436+
}
437+
438+
/**
439+
* Concat a bulk string containing multiple chunks
440+
*
441+
* Notes:
442+
* 1) The first chunk might contain the whole bulk string including the \r
443+
* 2) We are only safe to fully add up elements that are neither the first nor any of the last two elements
444+
*
445+
* @param parser
446+
* @returns {String}
447+
*/
448+
function concatBulkString (parser) {
449+
var list = parser.bufferCache
450+
var chunks = list.length
451+
var offset = parser.bigStrSize - parser.totalChunkSize
452+
parser.offset = offset
453+
if (offset === 1) {
454+
if (chunks === 2) {
455+
return list[0].toString('utf8', parser.bigOffset, list[0].length - 1)
456+
}
457+
chunks--
458+
}
459+
var res = decoder.write(list[0].slice(parser.bigOffset))
460+
for (var i = 1; i < chunks - 1; i++) {
461+
res += decoder.write(list[i])
462+
}
463+
res += decoder.end(list[i].slice(0, offset - 2))
464+
return res
465+
}
466+
467+
/**
468+
* Concat the collected chunks from parser.bufferCache.
469+
*
470+
* Increases the bufferPool size beforehand if necessary.
471+
*
472+
* @param parser
473+
* @returns {Buffer}
474+
*/
475+
function concatBulkBuffer (parser) {
476+
var list = parser.bufferCache
477+
var chunks = list.length
478+
var length = parser.bigStrSize - parser.bigOffset - 2
479+
var offset = parser.bigStrSize - parser.totalChunkSize
480+
parser.offset = offset
481+
if (offset === 1) {
482+
if (chunks === 2) {
483+
return list[0].slice(parser.bigOffset, list[0].length - 1)
484+
}
485+
chunks--
486+
offset = list[list.length - 1].length + 1
487+
}
488+
resizeBuffer(length)
489+
var pos = bufferOffset
490+
list[0].copy(bufferPool, pos, parser.bigOffset, list[0].length)
491+
pos += list[0].length - parser.bigOffset
492+
for (var i = 1; i < list.length - 1; i++) {
475493
list[i].copy(bufferPool, pos)
476494
pos += list[i].length
477495
}
496+
list[i].copy(bufferPool, pos, 0, offset - 2)
478497
var buffer = bufferPool.slice(bufferOffset, length + bufferOffset)
479498
bufferOffset += length
480499
return buffer
@@ -486,7 +505,6 @@ function concatBuffer (parser, length) {
486505
* @returns {undefined}
487506
*/
488507
JavascriptRedisParser.prototype.execute = function execute (buffer) {
489-
var arr
490508
if (this.buffer === null) {
491509
this.buffer = buffer
492510
this.offset = 0
@@ -499,32 +517,26 @@ JavascriptRedisParser.prototype.execute = function execute (buffer) {
499517
this.buffer = newBuffer
500518
this.offset = 0
501519
if (this.arrayCache.length) {
502-
arr = parseArrayChunks(this)
520+
var arr = parseArrayChunks(this)
503521
if (!arr) {
504522
return
505523
}
506524
this.returnReply(arr)
507525
}
508526
} else if (this.totalChunkSize + buffer.length >= this.bigStrSize) {
509527
this.bufferCache.push(buffer)
510-
if (this.optionReturnBuffers === false && !this.arrayCache.length) {
511-
this.returnReply(concatBulkString(this))
512-
this.buffer = buffer
513-
} else {
514-
this.buffer = concatBuffer(this, this.totalChunkSize + buffer.length)
515-
this.offset = 0
516-
if (this.arrayCache.length) {
517-
arr = parseArrayChunks(this)
518-
if (!arr) {
519-
this.bigStrSize = 0
520-
this.bufferCache = []
521-
return
522-
}
523-
this.returnReply(arr)
524-
}
525-
}
528+
var tmp = this.optionReturnBuffers ? concatBulkBuffer(this) : concatBulkString(this)
526529
this.bigStrSize = 0
527530
this.bufferCache = []
531+
this.buffer = buffer
532+
if (this.arrayCache.length) {
533+
this.arrayCache[0][this.arrayPos[0]++] = tmp
534+
tmp = parseArrayChunks(this)
535+
if (!tmp) {
536+
return
537+
}
538+
}
539+
this.returnReply(tmp)
528540
} else {
529541
this.bufferCache.push(buffer)
530542
this.totalChunkSize += buffer.length

test/parsers.spec.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,12 @@ describe('parsers', function () {
613613

614614
parser.execute(new Buffer('+test\r\n'))
615615
assert.strictEqual(replyCount, 1)
616-
parser.execute(new Buffer('$4\r\ntest\r\n'))
616+
parser.execute(new Buffer('$4\r\ntest\r'))
617+
parser.execute(new Buffer('\n'))
617618
assert.strictEqual(replyCount, 2)
618-
parser.execute(new Buffer('*1\r\n$4\r\ntest\r\n'))
619+
parser.execute(new Buffer('*1\r\n$4\r\nte'))
620+
parser.execute(new Buffer('st\r'))
621+
parser.execute(new Buffer('\n'))
619622
assert.strictEqual(replyCount, 3)
620623
})
621624

0 commit comments

Comments
 (0)