Class: Hyperion::ResponseWriter::ChunkedCoalescer

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperion/response_writer.rb

Overview

Per-response coalescing buffer. Holds <512 B chunks until either the 4 KiB threshold is hit, the 1 ms writer-fiber tick elapses, or an explicit flush / end-of-body fires. One instance per response; not shared across the connection (state lifecycle = response lifecycle, matches the Stepable-style “per-call object” pattern).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io) ⇒ ChunkedCoalescer

Returns a new instance of ChunkedCoalescer.



449
450
451
452
453
454
455
456
457
# File 'lib/hyperion/response_writer.rb', line 449

def initialize(io)
  @io                     = io
  @buffer                 = String.new(capacity: ResponseWriter::COALESCE_FLUSH_BYTES,
                                       encoding: Encoding::ASCII_8BIT)
  @bytes_written          = 0
  @total_write_count      = 0
  @coalesced_write_count  = 0
  @last_drain_at          = monotonic_now
end

Instance Attribute Details

#bytes_writtenObject (readonly)

Returns the value of attribute bytes_written.



447
448
449
# File 'lib/hyperion/response_writer.rb', line 447

def bytes_written
  @bytes_written
end

#coalesced_write_countObject (readonly)

Returns the value of attribute coalesced_write_count.



447
448
449
# File 'lib/hyperion/response_writer.rb', line 447

def coalesced_write_count
  @coalesced_write_count
end

#total_write_countObject (readonly)

Returns the value of attribute total_write_count.



447
448
449
# File 'lib/hyperion/response_writer.rb', line 447

def total_write_count
  @total_write_count
end

Instance Method Details

#flush_and_terminate!Object

End-of-body. Drain any buffered bytes AND emit the chunked terminator in a single syscall — this preserves the “terminator follows the last chunk atomically” invariant on the wire (otherwise a peer could see a half-flushed response if the writer fiber were preempted between our flush + terminator writes).



489
490
491
492
493
494
495
496
# File 'lib/hyperion/response_writer.rb', line 489

def flush_and_terminate!
  if @buffer.empty?
    do_write(ResponseWriter::CHUNKED_TERMINATOR)
  else
    @buffer << ResponseWriter::CHUNKED_TERMINATOR
    drain_buffer!
  end
end

#force_flush!Object

External flush (body responded to flush, or yielded the flush sentinel). Drains the buffer; safe to call when the buffer is empty.



480
481
482
# File 'lib/hyperion/response_writer.rb', line 480

def force_flush!
  drain_buffer!
end

#write_chunk(payload) ⇒ Object

Append a chunk into the wire stream. Small chunks coalesce into the buffer; large chunks drain the buffer first then write directly. Returns the number of body-bytes consumed (used by metrics).



462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/hyperion/response_writer.rb', line 462

def write_chunk(payload)
  framed = frame_chunk(payload)
  if payload.bytesize < ResponseWriter::COALESCE_SMALL_CHUNK_BYTES
    append_to_buffer(framed)
    maybe_tick_flush
  else
    # Big chunk: drain anything we've accumulated first so that
    # bytes hit the wire in body-yield order, then write the big
    # chunk in its own syscall (no point coalescing — it's already
    # past the threshold).
    drain_buffer!
    do_write(framed)
  end
  payload.bytesize
end