1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-07 13:22:56 +03:00

Performance improvements and backpressure controls.

Simply and speed up command argument processing logic.
Commands now return the true/false value from the underlying socket write(s).
Implement command_queue high water and low water for more better control of queueing.
This commit is contained in:
Matt Ranney
2011-06-30 14:03:36 -06:00
parent 13914295a6
commit f9e17556d2
7 changed files with 230 additions and 159 deletions

View File

@@ -35,8 +35,6 @@ function small_toString(buf, len) {
// Reset parser to it's original state.
RedisReplyParser.prototype.reset = function () {
this.state = "type";
this.return_buffer = new Buffer(16384); // for holding replies, might grow
this.return_string = "";
this.tmp_string = ""; // for holding size fields
@@ -46,6 +44,22 @@ RedisReplyParser.prototype.reset = function () {
this.multi_bulk_pos = 0;
this.multi_bulk_nested_length = 0;
this.multi_bulk_nested_replies = null;
this.states = {
TYPE: 1,
SINGLE_LINE: 2,
MULTI_BULK_COUNT: 3,
INTEGER_LINE: 4,
BULK_LENGTH: 5,
ERROR_LINE: 6,
BULK_DATA: 7,
UNKNOWN_TYPE: 8,
FINAL_CR: 9,
FINAL_LF: 10,
MULTI_BULK_COUNT_LF: 11
};
this.state = this.states.TYPE;
};
RedisReplyParser.prototype.parser_error = function (message) {
@@ -54,7 +68,7 @@ RedisReplyParser.prototype.parser_error = function (message) {
};
RedisReplyParser.prototype.execute = function (incoming_buf) {
var pos = 0, bd_tmp, bd_str, i, il;
var pos = 0, bd_tmp, bd_str, i, il, states = this.states;
//, state_times = {}, start_execute = new Date(), start_switch, end_switch, old_state;
//start_switch = new Date();
@@ -63,76 +77,76 @@ RedisReplyParser.prototype.execute = function (incoming_buf) {
// console.log("execute: " + this.state + ", " + pos + "/" + incoming_buf.length + ", " + String.fromCharCode(incoming_buf[pos]));
switch (this.state) {
case "type":
case states.TYPE:
this.type = incoming_buf[pos];
pos += 1;
switch (this.type) {
case 43: // +
this.state = "single line";
this.state = states.SINGLE_LINE;
this.return_buffer.end = 0;
this.return_string = "";
break;
case 42: // *
this.state = "multi bulk count";
this.state = states.MULTI_BULK_COUNT;
this.tmp_string = "";
break;
case 58: // :
this.state = "integer line";
this.state = states.INTEGER_LINE;
this.return_buffer.end = 0;
this.return_string = "";
break;
case 36: // $
this.state = "bulk length";
this.state = states.BULK_LENGTH;
this.tmp_string = "";
break;
case 45: // -
this.state = "error line";
this.state = states.ERROR_LINE;
this.return_buffer.end = 0;
this.return_string = "";
break;
default:
this.state = "unknown type";
this.state = states.UNKNOWN_TYPE;
}
break;
case "integer line":
case states.INTEGER_LINE:
if (incoming_buf[pos] === 13) {
this.send_reply(+small_toString(this.return_buffer, this.return_buffer.end));
this.state = "final lf";
this.state = states.FINAL_LF;
} else {
this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
this.return_buffer.end += 1;
}
pos += 1;
break;
case "error line":
case states.ERROR_LINE:
if (incoming_buf[pos] === 13) {
this.send_error(this.return_buffer.toString("ascii", 0, this.return_buffer.end));
this.state = "final lf";
this.state = states.FINAL_LF;
} else {
this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
this.return_buffer.end += 1;
}
pos += 1;
break;
case "single line":
case states.SINGLE_LINE:
if (incoming_buf[pos] === 13) {
this.send_reply(this.return_string);
this.state = "final lf";
this.state = states.FINAL_LF;
} else {
this.return_string += String.fromCharCode(incoming_buf[pos]);
}
pos += 1;
break;
case "multi bulk count":
case states.MULTI_BULK_COUNT:
if (incoming_buf[pos] === 13) { // \r
this.state = "multi bulk count lf";
this.state = states.MULTI_BULK_COUNT_LF;
} else {
this.tmp_string += String.fromCharCode(incoming_buf[pos]);
}
pos += 1;
break;
case "multi bulk count lf":
case states.MULTI_BULK_COUNT_LF:
if (incoming_buf[pos] === 10) { // \n
if (this.multi_bulk_length) { // nested multi-bulk
this.multi_bulk_nested_length = this.multi_bulk_length;
@@ -141,7 +155,7 @@ RedisReplyParser.prototype.execute = function (incoming_buf) {
}
this.multi_bulk_length = +this.tmp_string;
this.multi_bulk_pos = 0;
this.state = "type";
this.state = states.TYPE;
if (this.multi_bulk_length < 0) {
this.send_reply(null);
this.multi_bulk_length = 0;
@@ -158,25 +172,25 @@ RedisReplyParser.prototype.execute = function (incoming_buf) {
}
pos += 1;
break;
case "bulk length":
case states.BULK_LENGTH:
if (incoming_buf[pos] === 13) { // \r
this.state = "bulk lf";
this.state = states.BULK_LF;
} else {
this.tmp_string += String.fromCharCode(incoming_buf[pos]);
}
pos += 1;
break;
case "bulk lf":
case states.BULK_LF:
if (incoming_buf[pos] === 10) { // \n
this.bulk_length = +this.tmp_string;
if (this.bulk_length === -1) {
this.send_reply(null);
this.state = "type";
this.state = states.TYPE;
} else if (this.bulk_length === 0) {
this.send_reply(new Buffer(""));
this.state = "final cr";
this.state = states.FINAL_CR;
} else {
this.state = "bulk data";
this.state = states.BULK_DATA;
if (this.bulk_length > this.return_buffer.length) {
if (exports.debug_mode) {
console.log("Growing return_buffer from " + this.return_buffer.length + " to " + this.bulk_length);
@@ -191,7 +205,7 @@ RedisReplyParser.prototype.execute = function (incoming_buf) {
}
pos += 1;
break;
case "bulk data":
case states.BULK_DATA:
this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
this.return_buffer.end += 1;
pos += 1;
@@ -206,21 +220,21 @@ RedisReplyParser.prototype.execute = function (incoming_buf) {
}
}
this.send_reply(bd_tmp);
this.state = "final cr";
this.state = states.FINAL_CR;
}
break;
case "final cr":
case states.FINAL_CR:
if (incoming_buf[pos] === 13) { // \r
this.state = "final lf";
this.state = states.FINAL_LF;
pos += 1;
} else {
this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final CR"));
return;
}
break;
case "final lf":
case states.FINAL_LF:
if (incoming_buf[pos] === 10) { // \n
this.state = "type";
this.state = states.TYPE;
pos += 1;
} else {
this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final LF"));