Skip to content

Commit 63634b4

Browse files
kohtalagrs
authored andcommitted
Delay concat of read chunks into frame
Buffer.concat is slow on large frames. Collect read chunks into list until full frame has been received.
1 parent 228ad64 commit 63634b4

File tree

6 files changed

+61
-4
lines changed

6 files changed

+61
-4
lines changed

lib/connection.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,15 +547,34 @@ Connection.prototype.input = function (buff) {
547547
try {
548548
if (this.heartbeat_in) clearTimeout(this.heartbeat_in);
549549
log.io('[%s] read %d bytes', this.options.id, buff.length);
550-
if (this.previous_input) {
551-
buffer = Buffer.concat([this.previous_input, buff], this.previous_input.length + buff.length);
550+
if (this.frame_size) {
551+
this.received_bytes += buff.length;
552+
this.chunks.push(buff);
553+
if (this.frame_size <= this.received_bytes) {
554+
buffer = Buffer.concat(this.chunks, this.received_bytes);
555+
this.chunks = null;
556+
this.frame_size = undefined;
557+
} else {
558+
log.io('[%s] pushed %d bytes', this.options.id, buff.length);
559+
return;
560+
}
561+
} else if (this.previous_input) {
562+
buffer = Buffer.concat([this.previous_input, buff]);
552563
this.previous_input = null;
553564
} else {
554565
buffer = buff;
555566
}
556-
var read = this.transport.read(buffer, this);
567+
const read = this.transport.read(buffer, this);
557568
if (read < buffer.length) {
558-
this.previous_input = buffer.slice(read);
569+
const previous_input = buffer.slice(read);
570+
this.frame_size = this.transport.peek_size(previous_input);
571+
if (this.frame_size) {
572+
this.chunks = [previous_input];
573+
this.received_bytes = previous_input.length;
574+
log.io('[%s] waiting frame_size %s', this.options.id, this.frame_size);
575+
} else {
576+
this.previous_input = previous_input;
577+
}
559578
}
560579
if (this.local.open.idle_time_out) this.heartbeat_in = setTimeout(this.idle.bind(this), this.local.open.idle_time_out);
561580
if (this.transport.has_writes_pending()) {

lib/sasl.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,14 @@ SaslServer.prototype.write = function (socket) {
227227
}
228228
};
229229

230+
SaslServer.prototype.peek_size = function (buffer) {
231+
if (this.transport.read_complete) {
232+
return this.next.peek_size(buffer);
233+
} else {
234+
return this.transport.peek_size(buffer);
235+
}
236+
};
237+
230238
SaslServer.prototype.read = function (buffer) {
231239
if (this.transport.read_complete) {
232240
return this.next.read(buffer);
@@ -323,6 +331,14 @@ SaslClient.prototype.write = function (socket) {
323331
}
324332
};
325333

334+
SaslClient.prototype.peek_size = function (buffer) {
335+
if (this.transport.read_complete) {
336+
return this.next.peek_size(buffer);
337+
} else {
338+
return this.transport.peek_size(buffer);
339+
}
340+
};
341+
326342
SaslClient.prototype.read = function (buffer) {
327343
if (this.transport.read_complete) {
328344
return this.next.read(buffer);
@@ -352,6 +368,13 @@ SelectiveServer.prototype.write = function (socket) {
352368
}
353369
};
354370

371+
SelectiveServer.prototype.peek_size = function (buffer) {
372+
if (this.header_received) {
373+
return this.selected.peek_size(buffer);
374+
}
375+
return undefined;
376+
};
377+
355378
SelectiveServer.prototype.read = function (buffer) {
356379
if (!this.header_received) {
357380
if (buffer.length < 8) {

lib/transport.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ Transport.prototype.write = function (socket) {
6464
this.pending = [];
6565
};
6666

67+
Transport.prototype.peek_size = function (buffer) {
68+
log.frames('[%s] peek_size %o, %d', this.identifier, this.header_received, buffer.length);
69+
if (this.header_received && buffer.length >= 4) {
70+
return buffer.readUInt32BE();
71+
}
72+
return undefined;
73+
};
74+
6775
Transport.prototype.read = function (buffer) {
6876
var offset = 0;
6977
if (!this.header_received) {

test/messages.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ describe('message content', function() {
154154
it('sends and receives body of 50k', transfer_test({body:new Array(1024*50+1).join('z')}, function(message: rhea.Message) {
155155
assert.equal(message.body, new Array(1024*50+1).join('z'));
156156
}));
157+
it('sends and receives body of 50M', transfer_test({body:new Array(1024*1024*50+1).join('z')}, function(message: rhea.Message) {
158+
assert.equal(message.body, new Array(1024*1024*50+1).join('z'));
159+
}));
157160
it('sends and receives map body', transfer_test({body:{colour:'green',age:8,happy:true, sad:false}}, function(message: rhea.Message) {
158161
assert.equal(message.body.colour, 'green');
159162
assert.equal(message.body.age, 8);

typings/sasl.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ declare class SaslServer {
6969
on_sasl_response(frame: frames): void;
7070
has_writes_pending(): boolean;
7171
write(socket: Socket): void;
72+
peek_size(buffer: Buffer): number | undefined;
7273
read(buffer: Buffer): number;
7374
}
7475

@@ -87,6 +88,7 @@ declare class SaslClient {
8788
on_sasl_outcome(frame: frames): void;
8889
has_writes_pending(): boolean;
8990
write(socket: Socket): void;
91+
peek_size(buffer: Buffer): number | undefined;
9092
read(buffer: Buffer): number;
9193
}
9294

@@ -100,6 +102,7 @@ declare class SelectiveServer {
100102
constructor(connection: Connection, mechanisms: Mechanisms);
101103
has_writes_pending(): boolean;
102104
write(socket: Socket): void | number;
105+
peek_size(buffer: Buffer): number | undefined;
103106
read(buffer: Buffer): number;
104107
}
105108

typings/transport.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export declare interface Transport {
1616
has_writes_pending(): boolean;
1717
encode(frame: frames): void;
1818
write(socket: Socket): void;
19+
peek_size(buffer: Buffer): number | undefined;
1920
read(buffer: Buffer): number;
2021
}

0 commit comments

Comments
 (0)