Skip to content

Commit 5e0d684

Browse files
committed
fix: major performance issues with bytea performance brianc#2240
1 parent 89758ce commit 5e0d684

File tree

1 file changed

+63
-22
lines changed

1 file changed

+63
-22
lines changed

packages/pg-protocol/src/parser.ts

+63-22
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ const enum MessageCodes {
7373

7474
export type MessageCallback = (msg: BackendMessage) => void
7575

76+
interface CombinedBuffer {
77+
combinedBuffer: Buffer
78+
combinedBufferOffset: number
79+
combinedBufferLength: number
80+
combinedBufferFullLength: number
81+
reuseRemainingBuffer: boolean
82+
}
83+
7684
export class Parser {
7785
private remainingBuffer: Buffer = emptyBuffer
7886
private remainingBufferLength: number = 0
@@ -88,6 +96,41 @@ export class Parser {
8896
}
8997

9098
public parse(buffer: Buffer, callback: MessageCallback) {
99+
const {
100+
combinedBuffer,
101+
combinedBufferOffset,
102+
combinedBufferLength,
103+
reuseRemainingBuffer,
104+
combinedBufferFullLength,
105+
} = this.mergeBuffer(buffer)
106+
let offset = combinedBufferOffset
107+
while (offset + HEADER_LENGTH <= combinedBufferFullLength) {
108+
// code is 1 byte long - it identifies the message type
109+
const code = combinedBuffer[offset]
110+
111+
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code
112+
const length = combinedBuffer.readUInt32BE(offset + CODE_LENGTH)
113+
114+
const fullMessageLength = CODE_LENGTH + length
115+
116+
if (fullMessageLength + offset <= combinedBufferFullLength) {
117+
const message = this.handlePacket(offset + HEADER_LENGTH, code, length, combinedBuffer)
118+
callback(message)
119+
offset += fullMessageLength
120+
} else {
121+
break
122+
}
123+
}
124+
this.consumeBuffer({
125+
combinedBuffer,
126+
combinedBufferOffset: offset,
127+
combinedBufferLength,
128+
reuseRemainingBuffer,
129+
combinedBufferFullLength,
130+
})
131+
}
132+
133+
private mergeBuffer(buffer: Buffer): CombinedBuffer {
91134
let combinedBuffer = buffer
92135
let combinedBufferLength = buffer.byteLength
93136
let combinedBufferOffset = 0
@@ -125,39 +168,37 @@ export class Parser {
125168
combinedBufferLength = this.remainingBufferLength = newLength
126169
combinedBufferOffset = this.remainingBufferOffset
127170
}
128-
const fullLength = combinedBufferOffset + combinedBufferLength
129-
let offset = combinedBufferOffset
130-
while (offset + HEADER_LENGTH <= fullLength) {
131-
// code is 1 byte long - it identifies the message type
132-
const code = combinedBuffer[offset]
133-
134-
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code
135-
const length = combinedBuffer.readUInt32BE(offset + CODE_LENGTH)
136-
137-
const fullMessageLength = CODE_LENGTH + length
138-
139-
if (fullMessageLength + offset <= fullLength) {
140-
const message = this.handlePacket(offset + HEADER_LENGTH, code, length, combinedBuffer)
141-
callback(message)
142-
offset += fullMessageLength
143-
} else {
144-
break
145-
}
171+
const combinedBufferFullLength = combinedBufferOffset + combinedBufferLength
172+
return {
173+
combinedBuffer,
174+
combinedBufferOffset,
175+
combinedBufferLength,
176+
reuseRemainingBuffer,
177+
combinedBufferFullLength,
146178
}
147-
if (offset === fullLength) {
179+
}
180+
181+
private consumeBuffer({
182+
combinedBufferOffset,
183+
combinedBufferFullLength,
184+
reuseRemainingBuffer,
185+
combinedBuffer,
186+
combinedBufferLength,
187+
}: CombinedBuffer) {
188+
if (combinedBufferOffset === combinedBufferFullLength) {
148189
// No more use for the buffer
149190
this.remainingBuffer = emptyBuffer
150191
this.remainingBufferLength = 0
151192
this.remainingBufferOffset = 0
152193
} else {
153-
this.remainingBufferLength = fullLength - offset
194+
this.remainingBufferLength = combinedBufferFullLength - combinedBufferOffset
154195
if (reuseRemainingBuffer) {
155196
// Adjust the cursors of remainingBuffer
156-
this.remainingBufferOffset = offset
197+
this.remainingBufferOffset = combinedBufferOffset
157198
} else {
158199
// To avoid side effects, copy the remaining part of the new buffer to remainingBuffer with extra space for next buffer
159200
this.remainingBuffer = Buffer.allocUnsafe(combinedBufferLength * 2)
160-
combinedBuffer.copy(this.remainingBuffer, 0, offset)
201+
combinedBuffer.copy(this.remainingBuffer, 0, combinedBufferOffset)
161202
this.remainingBufferOffset = 0
162203
}
163204
}

0 commit comments

Comments
 (0)