You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-09 00:22:08 +03:00
Refactor js parser
Fix tests to work with Node.js 0.10 Improve average use case speed by up to 20% Fix some small js parser issues
This commit is contained in:
@@ -9,6 +9,8 @@ function JavascriptReplyParser() {
|
||||
this._big_offset = 0;
|
||||
this._chunks_size = 0;
|
||||
this._buffers = [];
|
||||
this._type = 0;
|
||||
this._protocol_error = false;
|
||||
}
|
||||
|
||||
function IncompleteReadBuffer(message) {
|
||||
@@ -21,87 +23,73 @@ JavascriptReplyParser.prototype._parseResult = function (type) {
|
||||
var start = 0,
|
||||
end = 0,
|
||||
offset = 0,
|
||||
packetHeader = 0;
|
||||
packetHeader = 0,
|
||||
res,
|
||||
reply;
|
||||
|
||||
if (type === 43 || type === 58 || type === 45) { // + or : or -
|
||||
// up to the delimiter
|
||||
// Up to the delimiter
|
||||
end = this._packetEndOffset();
|
||||
start = this._offset;
|
||||
|
||||
// include the delimiter
|
||||
// Include the delimiter
|
||||
this._offset = end + 2;
|
||||
|
||||
if (type === 43) {
|
||||
return this._buffer.slice(start, end);
|
||||
} else if (type === 58) {
|
||||
// return the coerced numeric value
|
||||
// Return the coerced numeric value
|
||||
return +this._buffer.toString('ascii', start, end);
|
||||
}
|
||||
return new Error(this._buffer.toString('utf-8', start, end));
|
||||
} else if (type === 36) { // $
|
||||
packetHeader = this.parseHeader();
|
||||
|
||||
// packets with a size of -1 are considered null
|
||||
// Packets with a size of -1 are considered null
|
||||
if (packetHeader === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
end = this._offset + packetHeader;
|
||||
start = this._offset;
|
||||
|
||||
if (end > this._buffer.length) {
|
||||
if (end + 2 > this._buffer.length) {
|
||||
this._chunks_size = this._buffer.length - this._offset - 2;
|
||||
this._big_offset = packetHeader;
|
||||
throw new IncompleteReadBuffer('Wait for more data.');
|
||||
}
|
||||
|
||||
// set the offset to after the delimiter
|
||||
// Set the offset to after the delimiter
|
||||
this._offset = end + 2;
|
||||
|
||||
return this._buffer.slice(start, end);
|
||||
} else if (type === 42) { // *
|
||||
// set a rewind point, as the packet is larger than the buffer in memory
|
||||
// Set a rewind point, as the packet is larger than the buffer in memory
|
||||
offset = this._offset;
|
||||
packetHeader = this.parseHeader();
|
||||
|
||||
if (packetHeader === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (packetHeader > this._buffer.length - this._offset) {
|
||||
this._offset = offset - 1;
|
||||
throw new IncompleteReadBuffer('Wait for more data.');
|
||||
}
|
||||
|
||||
var reply = [];
|
||||
var ntype, i, res;
|
||||
|
||||
reply = [];
|
||||
offset = this._offset - 1;
|
||||
|
||||
for (i = 0; i < packetHeader; i++) {
|
||||
ntype = this._buffer[this._offset++];
|
||||
|
||||
if (this._offset > this._buffer.length) {
|
||||
for (var i = 0; i < packetHeader; i++) {
|
||||
if (this._offset >= this._buffer.length) {
|
||||
throw new IncompleteReadBuffer('Wait for more data.');
|
||||
}
|
||||
res = this._parseResult(ntype);
|
||||
res = this._parseResult(this._buffer[this._offset++]);
|
||||
reply.push(res);
|
||||
}
|
||||
|
||||
return reply;
|
||||
} else {
|
||||
return null;
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
|
||||
JavascriptReplyParser.prototype.execute = function (buffer) {
|
||||
|
||||
if (this._chunks_size !== 0 && this._big_offset > this._chunks_size + buffer.length) {
|
||||
this._buffers.push(buffer);
|
||||
this._chunks_size += buffer.length;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._buffers.length !== 0) {
|
||||
this._buffers.unshift(this._offset === 0 ? this._buffer : this._buffer.slice(this._offset));
|
||||
this._buffers.push(buffer);
|
||||
@@ -115,44 +103,41 @@ JavascriptReplyParser.prototype.execute = function (buffer) {
|
||||
this._buffer = Buffer.concat([this._buffer.slice(this._offset), buffer]);
|
||||
}
|
||||
this._offset = 0;
|
||||
this._protocol_error = true;
|
||||
this.run();
|
||||
};
|
||||
|
||||
JavascriptReplyParser.prototype.try_parsing = function () {
|
||||
// Set a rewind point. If a failure occurs, wait for the next execute()/append() and try again
|
||||
var offset = this._offset - 1;
|
||||
try {
|
||||
return this._parseResult(this._type);
|
||||
} catch (err) {
|
||||
// Catch the error (not enough data), rewind if it's an array,
|
||||
// and wait for the next packet to appear
|
||||
this._offset = offset;
|
||||
this._protocol_error = false;
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
|
||||
JavascriptReplyParser.prototype.run = function (buffer) {
|
||||
var type, offset = this._offset;
|
||||
this._type = this._buffer[this._offset++];
|
||||
var reply = this.try_parsing();
|
||||
|
||||
while (true) {
|
||||
offset = this._offset;
|
||||
// at least 4 bytes: :1\r\n
|
||||
if (this._buffer.length - this._offset < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
type = this._buffer[this._offset++];
|
||||
|
||||
if (type === 43 || type === 58 || type === 36) { // Strings + // Integers : // Bulk strings $
|
||||
this.send_reply(this._parseResult(type));
|
||||
} else if (type === 45) { // Errors -
|
||||
this.send_error(this._parseResult(type));
|
||||
} else if (type === 42) { // Arrays *
|
||||
// set a rewind point. if a failure occurs,
|
||||
// wait for the next execute()/append() and try again
|
||||
offset = this._offset - 1;
|
||||
|
||||
this.send_reply(this._parseResult(type));
|
||||
} else if (type !== 10 && type !== 13) {
|
||||
// Reset the buffer so the parser can handle following commands properly
|
||||
this._buffer = new Buffer(0);
|
||||
var err = new Error('Protocol error, got "' + String.fromCharCode(type) + '" as reply type byte');
|
||||
this.send_error(err);
|
||||
}
|
||||
} catch (err) {
|
||||
// catch the error (not enough data), rewind, and wait
|
||||
// for the next packet to appear
|
||||
this._offset = offset;
|
||||
break;
|
||||
while (reply !== undefined) {
|
||||
if (this._type === 45) { // Errors -
|
||||
this.send_error(reply);
|
||||
} else {
|
||||
this.send_reply(reply); // Strings + // Integers : // Bulk strings $ // Arrays *
|
||||
}
|
||||
this._type = this._buffer[this._offset++];
|
||||
reply = this.try_parsing();
|
||||
}
|
||||
if (this._type !== undefined && this._protocol_error === true) {
|
||||
// Reset the buffer so the parser can handle following commands properly
|
||||
this._buffer = new Buffer(0);
|
||||
this.send_error(new Error('Protocol error, got "' + String.fromCharCode(this._type) + '" as reply type byte'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,21 +146,20 @@ JavascriptReplyParser.prototype.parseHeader = function () {
|
||||
value = this._buffer.toString('ascii', this._offset, end) | 0;
|
||||
|
||||
this._offset = end + 2;
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
JavascriptReplyParser.prototype._packetEndOffset = function () {
|
||||
var offset = this._offset;
|
||||
var offset = this._offset,
|
||||
len = this._buffer.length - 1;
|
||||
|
||||
while (this._buffer[offset] !== 0x0d && this._buffer[offset + 1] !== 0x0a) {
|
||||
offset++;
|
||||
|
||||
if (offset >= this._buffer.length) {
|
||||
if (offset >= len) {
|
||||
throw new IncompleteReadBuffer('Did not see LF after NL reading multi bulk count (' + offset + ' => ' + this._buffer.length + ', ' + this._offset + ')');
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user