Skip to content

Commit

Permalink
perf: zero copy llhttp buffers (#712)
Browse files Browse the repository at this point in the history
* perf: zero copy llhttp buffers

Fixes: nodejs/llhttp#100
Refs: #711

* fixup

* fixup

* fixup
  • Loading branch information
ronag authored Apr 9, 2021
1 parent 8e44ac0 commit dac0517
Showing 1 changed file with 20 additions and 20 deletions.
40 changes: 20 additions & 20 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,20 +421,26 @@ class Parser {
},
wasm_on_header_field: (p, at, len) => {
assert(this.headers.length % 2 === 0)
return this.onHeader(this.inst.memory.buffer, at, len) || 0
const start = at - this.bufferPtr
const end = start + len
return this.onHeader(this.bufferRef.slice(start, end)) || 0
},
wasm_on_header_value: (p, at, len) => {
assert(this.headers.length % 2 === 1)
return this.onHeader(this.inst.memory.buffer, at, len) || 0
const start = at - this.bufferPtr
const end = start + len
return this.onHeader(this.bufferRef.slice(start, end)) || 0
},
wasm_on_headers_complete: p => {
const statusCode = this.inst.llhttp_get_status_code(p)
const upgrade = Boolean(this.inst.llhttp_get_upgrade(p))
const shouldKeepAlive = Boolean(this.inst.llhttp_should_keep_alive(p))
return this.onHeadersComplete(statusCode, upgrade, shouldKeepAlive)
return this.onHeadersComplete(statusCode, upgrade, shouldKeepAlive) || 0
},
wasm_on_body: (p, at, length) => {
return this.onBody(this.inst.memory.buffer, at, length) || 0
wasm_on_body: (p, at, len) => {
const start = at - this.bufferPtr
const end = start + len
return this.onBody(this.bufferRef.slice(start, end)) || 0
},
wasm_on_message_complete: (p) => {
return this.onMessageComplete() || 0
Expand All @@ -449,6 +455,7 @@ class Parser {
this.ptr = this.inst.llhttp_alloc(constants.TYPE.RESPONSE)
this.bufferSize = 0
this.bufferPtr = null
this.bufferRef = null
this.bufferView = null
this.client = client
this.socket = socket
Expand Down Expand Up @@ -498,13 +505,16 @@ class Parser {
this.bufferView = new Uint8Array(this.inst.memory.buffer, this.bufferPtr, this.bufferSize)
}

// TODO (perf): Can we avoid this copy somehow?
this.bufferView.set(data)

// Call `execute` on the wasm parser.
// We pass the `llhttp_parser` pointer address, the pointer address of buffer view data,
// and finally the length of bytes to parse.
// The return value is an error code or `constants.ERROR.OK`.
this.bufferRef = data
const ret = this.inst.llhttp_execute(this.ptr, this.bufferPtr, data.length)
this.bufferRef = null

if (ret === constants.ERROR.OK) {
return
Expand All @@ -531,15 +541,10 @@ class Parser {
}
}

onHeader (buf, at, len) {
// TODO: we could optimize this further by making this part the responsibility of the user.
// Forcing them to consume the buffer synchronously or copy it otherwise.
const data = Buffer.allocUnsafe(len)
Buffer.from(buf, at, len).copy(data)
onHeader (buf) {
this.headers.push(buf)

this.headers.push(data)

this.headersSize += len
this.headersSize += buf.length
if (this.headersSize >= this.headersMaxSize) {
util.destroy(this.socket, new HeadersOverflowError())
}
Expand Down Expand Up @@ -722,18 +727,13 @@ class Parser {
}
}

onBody (buf, at, len) {
onBody (buf) {
const { client, socket, statusCode, timeout } = this

if (socket.destroyed) {
return -1
}

// TODO: we could optimize this further by making this part responsibility fo the user.
// Forcing them to consume the buffer synchronously or copy it otherwise.
const data = Buffer.allocUnsafe(len)
Buffer.from(buf, at, len).copy(data)

const request = client[kQueue][client[kRunningIdx]]
assert(request)

Expand All @@ -747,7 +747,7 @@ class Parser {
assert(statusCode >= 200)

try {
if (request.onData(data) === false) {
if (request.onData(buf) === false) {
return constants.ERROR.PAUSED
}
} catch (err) {
Expand Down

0 comments on commit dac0517

Please sign in to comment.