Files
orca/src/shared/search-subprocess-lines.ts
T
NeilandOrca c419aadb19 oom(01): A1-shared-readers — reintroduce #10179 subset (#10294)
Files: 18 applied, 0 deleted (from 6eb70d8370)

Co-authored-by: Orca <help@stably.ai>
2026-07-24 20:30:31 -07:00

76 lines
2.2 KiB
TypeScript

export const SEARCH_SUBPROCESS_MAX_LINE_BYTES = 64 * 1024 * 1024
const SEARCH_SUBPROCESS_INITIAL_LINE_BUFFER_BYTES = 4 * 1024
export class SearchSubprocessLineAccumulator {
private buffer: Buffer | null = null
private bytes = 0
constructor(private readonly maxLineBytes = SEARCH_SUBPROCESS_MAX_LINE_BYTES) {
if (!Number.isSafeInteger(maxLineBytes) || maxLineBytes < 0) {
throw new RangeError('Search line limit must be a non-negative safe integer')
}
}
push(rawChunk: Buffer | string, onLine: (line: string) => void): boolean {
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk, 'utf8')
let cursor = 0
while (cursor < chunk.length) {
const newline = chunk.indexOf(0x0a, cursor)
const end = newline === -1 ? chunk.length : newline
const segmentBytes = end - cursor
if (this.bytes + segmentBytes > this.maxLineBytes) {
this.clear()
return false
}
if (newline !== -1 && this.bytes === 0) {
onLine(chunk.toString('utf8', cursor, end))
} else if (segmentBytes > 0) {
this.append(chunk.subarray(cursor, end))
if (newline !== -1) {
onLine(this.takeLine())
}
} else if (newline !== -1) {
onLine(this.takeLine())
}
if (newline === -1) {
return true
}
cursor = newline + 1
}
return true
}
finish(): string | null {
return this.bytes > 0 ? this.takeLine() : null
}
clear(): void {
this.buffer = null
this.bytes = 0
}
private append(segment: Buffer): void {
const requiredBytes = this.bytes + segment.length
if (!this.buffer || this.buffer.length < requiredBytes) {
const doubledCapacity = this.buffer?.length ? this.buffer.length * 2 : 0
const nextCapacity = Math.min(
this.maxLineBytes,
Math.max(SEARCH_SUBPROCESS_INITIAL_LINE_BUFFER_BYTES, doubledCapacity, requiredBytes)
)
const next = Buffer.allocUnsafe(nextCapacity)
this.buffer?.copy(next, 0, 0, this.bytes)
this.buffer = next
}
segment.copy(this.buffer, this.bytes)
this.bytes = requiredBytes
}
private takeLine(): string {
const line = this.buffer?.toString('utf8', 0, this.bytes) ?? ''
this.clear()
return line
}
}