Speed up JavaScript parser slightly
This commit is contained in:
parent
e778348fe1
commit
31318c02a2
@ -41,7 +41,7 @@ Connection.prototype.connect = function(port, host) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.stream.on('error', function(error) {
|
this.stream.on('error', function(error) {
|
||||||
//don't raise ECONNRESET errors - they can & should be ignored
|
//don't raise ECONNRESET errors - they can & should be ignored
|
||||||
//during disconnect
|
//during disconnect
|
||||||
if(self._ending && error.code == 'ECONNRESET') {
|
if(self._ending && error.code == 'ECONNRESET') {
|
||||||
return;
|
return;
|
||||||
@ -81,8 +81,10 @@ Connection.prototype.connect = function(port, host) {
|
|||||||
|
|
||||||
Connection.prototype.attachListeners = function(stream) {
|
Connection.prototype.attachListeners = function(stream) {
|
||||||
var self = this;
|
var self = this;
|
||||||
stream.on('data', function(buffer) {
|
stream.on('readable', function() {
|
||||||
self.setBuffer(buffer);
|
var buff = stream.read();
|
||||||
|
if(!buff) return;
|
||||||
|
self.setBuffer(buff);
|
||||||
var msg = self.parseMessage();
|
var msg = self.parseMessage();
|
||||||
while(msg) {
|
while(msg) {
|
||||||
self.emit('message', msg);
|
self.emit('message', msg);
|
||||||
@ -322,8 +324,9 @@ Connection.prototype.parseMessage = function() {
|
|||||||
|
|
||||||
//read message id code
|
//read message id code
|
||||||
var id = this.buffer[this.offset++];
|
var id = this.buffer[this.offset++];
|
||||||
|
var buffer = this.buffer;
|
||||||
//read message length
|
//read message length
|
||||||
var length = this.parseInt32();
|
var length = this.parseInt32(buffer);
|
||||||
|
|
||||||
if(remaining <= length) {
|
if(remaining <= length) {
|
||||||
this.lastBuffer = this.buffer;
|
this.lastBuffer = this.buffer;
|
||||||
@ -340,95 +343,106 @@ Connection.prototype.parseMessage = function() {
|
|||||||
|
|
||||||
case 0x52: //R
|
case 0x52: //R
|
||||||
msg.name = 'authenticationOk';
|
msg.name = 'authenticationOk';
|
||||||
return this.parseR(msg);
|
msg = this.parseR(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x53: //S
|
case 0x53: //S
|
||||||
msg.name = 'parameterStatus';
|
msg.name = 'parameterStatus';
|
||||||
return this.parseS(msg);
|
msg = this.parseS(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x4b: //K
|
case 0x4b: //K
|
||||||
msg.name = 'backendKeyData';
|
msg.name = 'backendKeyData';
|
||||||
return this.parseK(msg);
|
msg = this.parseK(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x43: //C
|
case 0x43: //C
|
||||||
msg.name = 'commandComplete';
|
msg.name = 'commandComplete';
|
||||||
return this.parseC(msg);
|
msg = this.parseC(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x5a: //Z
|
case 0x5a: //Z
|
||||||
msg.name = 'readyForQuery';
|
msg.name = 'readyForQuery';
|
||||||
return this.parseZ(msg);
|
msg = this.parseZ(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x54: //T
|
case 0x54: //T
|
||||||
msg.name = 'rowDescription';
|
msg.name = 'rowDescription';
|
||||||
return this.parseT(msg);
|
msg = this.parseT(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x44: //D
|
case 0x44: //D
|
||||||
msg.name = 'dataRow';
|
msg = this.parseD(buffer, length);
|
||||||
return this.parseD(msg);
|
break;
|
||||||
|
|
||||||
case 0x45: //E
|
case 0x45: //E
|
||||||
msg.name = 'error';
|
msg.name = 'error';
|
||||||
return this.parseE(msg);
|
msg = this.parseE(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x4e: //N
|
case 0x4e: //N
|
||||||
msg.name = 'notice';
|
msg.name = 'notice';
|
||||||
return this.parseN(msg);
|
msg = this.parseN(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x31: //1
|
case 0x31: //1
|
||||||
msg.name = 'parseComplete';
|
msg.name = 'parseComplete';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x32: //2
|
case 0x32: //2
|
||||||
msg.name = 'bindComplete';
|
msg.name = 'bindComplete';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x41: //A
|
case 0x41: //A
|
||||||
msg.name = 'notification';
|
msg.name = 'notification';
|
||||||
return this.parseA(msg);
|
msg = this.parseA(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x6e: //n
|
case 0x6e: //n
|
||||||
msg.name = 'noData';
|
msg.name = 'noData';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x49: //I
|
case 0x49: //I
|
||||||
msg.name = 'emptyQuery';
|
msg.name = 'emptyQuery';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x73: //s
|
case 0x73: //s
|
||||||
msg.name = 'portalSuspended';
|
msg.name = 'portalSuspended';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x47: //G
|
case 0x47: //G
|
||||||
msg.name = 'copyInResponse';
|
msg.name = 'copyInResponse';
|
||||||
return this.parseGH(msg);
|
msg = this.parseGH(msg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x48: //H
|
case 0x48: //H
|
||||||
msg.name = 'copyOutResponse';
|
msg.name = 'copyOutResponse';
|
||||||
return this.parseGH(msg);
|
msg = this.parseGH(msg);
|
||||||
|
break;
|
||||||
case 0x63: //c
|
case 0x63: //c
|
||||||
msg.name = 'copyDone';
|
msg.name = 'copyDone';
|
||||||
return msg;
|
break;
|
||||||
|
|
||||||
case 0x64: //d
|
case 0x64: //d
|
||||||
msg.name = 'copyData';
|
msg.name = 'copyData';
|
||||||
return this.parsed(msg);
|
msg = this.parsed(msg);
|
||||||
|
break;
|
||||||
default:
|
|
||||||
throw new Error("Unrecognized message code " + id);
|
|
||||||
}
|
}
|
||||||
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseR = function(msg) {
|
Connection.prototype.parseR = function(msg) {
|
||||||
var code = 0;
|
var code = 0;
|
||||||
|
var buffer = this.buffer;
|
||||||
if(msg.length === 8) {
|
if(msg.length === 8) {
|
||||||
code = this.parseInt32();
|
code = this.parseInt32(buffer);
|
||||||
if(code === 3) {
|
if(code === 3) {
|
||||||
msg.name = 'authenticationCleartextPassword';
|
msg.name = 'authenticationCleartextPassword';
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
if(msg.length === 12) {
|
if(msg.length === 12) {
|
||||||
code = this.parseInt32();
|
code = this.parseInt32(buffer);
|
||||||
if(code === 5) { //md5 required
|
if(code === 5) { //md5 required
|
||||||
msg.name = 'authenticationMD5Password';
|
msg.name = 'authenticationMD5Password';
|
||||||
msg.salt = new Buffer(4);
|
msg.salt = new Buffer(4);
|
||||||
@ -441,85 +455,103 @@ Connection.prototype.parseR = function(msg) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseS = function(msg) {
|
Connection.prototype.parseS = function(msg) {
|
||||||
msg.parameterName = this.parseCString();
|
var buffer = this.buffer;
|
||||||
msg.parameterValue = this.parseCString();
|
msg.parameterName = this.parseCString(buffer);
|
||||||
|
msg.parameterValue = this.parseCString(buffer);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseK = function(msg) {
|
Connection.prototype.parseK = function(msg) {
|
||||||
msg.processID = this.parseInt32();
|
var buffer = this.buffer;
|
||||||
msg.secretKey = this.parseInt32();
|
msg.processID = this.parseInt32(buffer);
|
||||||
|
msg.secretKey = this.parseInt32(buffer);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseC = function(msg) {
|
Connection.prototype.parseC = function(msg) {
|
||||||
msg.text = this.parseCString();
|
var buffer = this.buffer;
|
||||||
|
msg.text = this.parseCString(buffer);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseZ = function(msg) {
|
Connection.prototype.parseZ = function(msg) {
|
||||||
msg.status = this.readChar();
|
var buffer = this.buffer;
|
||||||
|
msg.status = this.readString(buffer, 1);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseT = function(msg) {
|
Connection.prototype.parseT = function(msg) {
|
||||||
msg.fieldCount = this.parseInt16();
|
var buffer = this.buffer;
|
||||||
|
msg.fieldCount = this.parseInt16(buffer);
|
||||||
var fields = [];
|
var fields = [];
|
||||||
for(var i = 0; i < msg.fieldCount; i++){
|
for(var i = 0; i < msg.fieldCount; i++){
|
||||||
fields.push(this.parseField());
|
fields.push(this.parseField(buffer));
|
||||||
}
|
}
|
||||||
msg.fields = fields;
|
msg.fields = fields;
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseField = function() {
|
Connection.prototype.parseField = function(buffer) {
|
||||||
var field = {
|
var field = {
|
||||||
name: this.parseCString(),
|
name: this.parseCString(buffer),
|
||||||
tableID: this.parseInt32(),
|
tableID: this.parseInt32(buffer),
|
||||||
columnID: this.parseInt16(),
|
columnID: this.parseInt16(buffer),
|
||||||
dataTypeID: this.parseInt32(),
|
dataTypeID: this.parseInt32(buffer),
|
||||||
dataTypeSize: this.parseInt16(),
|
dataTypeSize: this.parseInt16(buffer),
|
||||||
dataTypeModifier: this.parseInt32(),
|
dataTypeModifier: this.parseInt32(buffer),
|
||||||
format: undefined
|
format: undefined
|
||||||
};
|
};
|
||||||
if(this.parseInt16() === TEXT_MODE) {
|
if(this.parseInt16(buffer) === TEXT_MODE) {
|
||||||
this._mode = TEXT_MODE;
|
this._mode = TEXT_MODE;
|
||||||
field.format = 'text';
|
field.format = 'text';
|
||||||
} else {
|
} else {
|
||||||
this._mode = BINARY_MODE;
|
this._mode = BINARY_MODE;
|
||||||
|
this.readField = this.readBytes;
|
||||||
field.format = 'binary';
|
field.format = 'binary';
|
||||||
}
|
}
|
||||||
return field;
|
return field;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseD = function(msg) {
|
var Message = function(name, length) {
|
||||||
var fieldCount = this.parseInt16();
|
this.name = name;
|
||||||
var fields = [];
|
this.length = length;
|
||||||
|
};
|
||||||
|
|
||||||
|
var DataRowMessage = function(name, length, fieldCount) {
|
||||||
|
this.name = name;
|
||||||
|
this.length = length;
|
||||||
|
this.fieldCount = fieldCount;
|
||||||
|
this.fields = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection.prototype.parseD = function(buffer, length) {
|
||||||
|
var fieldCount = this.parseInt16(buffer);
|
||||||
|
var msg = new DataRowMessage('dataRow', length, fieldCount);
|
||||||
for(var i = 0; i < fieldCount; i++) {
|
for(var i = 0; i < fieldCount; i++) {
|
||||||
var length = this.parseInt32();
|
var value = this._readValue(buffer);
|
||||||
var value = null;
|
msg.fields.push(value);
|
||||||
if(length !== -1) {
|
|
||||||
if(this._mode === TEXT_MODE) {
|
|
||||||
value = this.readString(length);
|
|
||||||
} else {
|
|
||||||
value = this.readBytes(length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fields.push(value);
|
|
||||||
}
|
}
|
||||||
msg.fieldCount = fieldCount;
|
|
||||||
msg.fields = fields;
|
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Connection.prototype._readValue = function(buffer) {
|
||||||
|
var length = this.parseInt32(buffer);
|
||||||
|
if(length === -1) return null;
|
||||||
|
if(this._mode === TEXT_MODE) {
|
||||||
|
return this.readString(buffer, length);
|
||||||
|
}
|
||||||
|
return this.readBytes(buffer, length);
|
||||||
|
};
|
||||||
|
|
||||||
//parses error
|
//parses error
|
||||||
Connection.prototype.parseE = function(input) {
|
Connection.prototype.parseE = function(input) {
|
||||||
|
var buffer = this.buffer;
|
||||||
var fields = {};
|
var fields = {};
|
||||||
var msg, item;
|
var msg, item;
|
||||||
var fieldType = this.readString(1);
|
var fieldType = this.readString(buffer, 1);
|
||||||
while(fieldType != '\0') {
|
while(fieldType != '\0') {
|
||||||
fields[fieldType] = this.parseCString();
|
fields[fieldType] = this.parseCString(buffer);
|
||||||
fieldType = this.readString(1);
|
fieldType = this.readString(buffer, 1);
|
||||||
}
|
}
|
||||||
if(input.name === 'error') {
|
if(input.name === 'error') {
|
||||||
// the msg is an Error instance
|
// the msg is an Error instance
|
||||||
@ -553,57 +585,56 @@ Connection.prototype.parseE = function(input) {
|
|||||||
Connection.prototype.parseN = Connection.prototype.parseE;
|
Connection.prototype.parseN = Connection.prototype.parseE;
|
||||||
|
|
||||||
Connection.prototype.parseA = function(msg) {
|
Connection.prototype.parseA = function(msg) {
|
||||||
msg.processId = this.parseInt32();
|
var buffer = this.buffer;
|
||||||
msg.channel = this.parseCString();
|
msg.processId = this.parseInt32(buffer);
|
||||||
msg.payload = this.parseCString();
|
msg.channel = this.parseCString(buffer);
|
||||||
|
msg.payload = this.parseCString(buffer);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseGH = function (msg) {
|
Connection.prototype.parseGH = function (msg) {
|
||||||
|
var buffer = this.buffer;
|
||||||
var isBinary = this.buffer[this.offset] !== 0;
|
var isBinary = this.buffer[this.offset] !== 0;
|
||||||
this.offset++;
|
this.offset++;
|
||||||
msg.binary = isBinary;
|
msg.binary = isBinary;
|
||||||
var columnCount = this.parseInt16();
|
var columnCount = this.parseInt16(buffer);
|
||||||
msg.columnTypes = [];
|
msg.columnTypes = [];
|
||||||
for(var i = 0; i<columnCount; i++) {
|
for(var i = 0; i<columnCount; i++) {
|
||||||
msg.columnTypes.push(this.parseInt16());
|
msg.columnTypes.push(this.parseInt16(buffer));
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.readChar = function() {
|
Connection.prototype.parseInt32 = function(buffer) {
|
||||||
return this.readString(1);
|
var value = buffer.readInt32BE(this.offset, true);
|
||||||
};
|
|
||||||
|
|
||||||
Connection.prototype.parseInt32 = function() {
|
|
||||||
var value = this.buffer.readInt32BE(this.offset, true);
|
|
||||||
this.offset += 4;
|
this.offset += 4;
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseInt16 = function() {
|
Connection.prototype.parseInt16 = function(buffer) {
|
||||||
var value = this.buffer.readInt16BE(this.offset, true);
|
var value = buffer.readInt16BE(this.offset, true);
|
||||||
this.offset += 2;
|
this.offset += 2;
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.readString = function(length) {
|
Connection.prototype.readString = function(buffer, length) {
|
||||||
return this.buffer.toString(this.encoding, this.offset, (this.offset += length));
|
return buffer.toString(this.encoding, this.offset, (this.offset += length));
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.readBytes = function(length) {
|
Connection.prototype.readBytes = function(buffer, length) {
|
||||||
return this.buffer.slice(this.offset, this.offset += length);
|
return buffer.slice(this.offset, this.offset += length);
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseCString = function() {
|
Connection.prototype.parseCString = function(buffer) {
|
||||||
var start = this.offset;
|
var start = this.offset;
|
||||||
while(this.buffer[this.offset++] !== 0) { }
|
while(buffer[this.offset++] !== 0) { }
|
||||||
return this.buffer.toString(this.encoding, start, this.offset - 1);
|
return buffer.toString(this.encoding, start, this.offset - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parsed = function (msg) {
|
Connection.prototype.parsed = function (msg) {
|
||||||
|
this.buffer = buffer;
|
||||||
//exclude length field
|
//exclude length field
|
||||||
msg.chunk = this.readBytes(msg.length - 4);
|
msg.chunk = this.readBytes(buffer, msg.length - 4);
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
//end parsing methods
|
//end parsing methods
|
||||||
|
5
script/setup-bench-data.js
Normal file
5
script/setup-bench-data.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var pg = require('../lib');
|
||||||
|
var
|
||||||
|
pg.connect(function(err, client) {
|
||||||
|
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user