Class: Hyperion::Http2Handler::WriterContext

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

Overview

Holds the per-connection outbound coordination state (queue, notifications, byte counters, shutdown flag) plus the encode mutex that protects HPACK state and per-stream frame ordering.

Single instance per connection, lives for the lifetime of ‘serve`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_pending_bytes: MAX_PER_CONN_PENDING_BYTES) ⇒ WriterContext

Returns a new instance of WriterContext.



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/hyperion/http2_handler.rb', line 143

def initialize(max_pending_bytes: MAX_PER_CONN_PENDING_BYTES)
  @queue              = ::Thread::Queue.new
  @send_notify        = ::Async::Notification.new
  @drained_notify     = ::Async::Notification.new
  @encode_mutex       = ::Mutex.new
  @pending_bytes      = 0
  @pending_bytes_lock = ::Mutex.new
  @max_pending_bytes  = max_pending_bytes
  @writer_done        = false
  # 2.10-G timing slots, all initially nil so capture is a single
  # `||=` write under the encode mutex / writer fiber.
  @t0_serve_entry  = nil
  @t1_preface_done = nil
  @t2_first_encode = nil
  @t2_first_wire   = nil
end

Instance Attribute Details

#encode_mutexObject (readonly)

Returns the value of attribute encode_mutex.



136
137
138
# File 'lib/hyperion/http2_handler.rb', line 136

def encode_mutex
  @encode_mutex
end

#t0_serve_entryObject

2.10-G — connection-lifecycle timing slots used by the optional h2 latency-instrumentation path (gated by ‘HYPERION_H2_TIMING=1`). Each slot is a single CLOCK_MONOTONIC timestamp captured at most once per connection. nil = unset, set on first observation.



141
142
143
# File 'lib/hyperion/http2_handler.rb', line 141

def t0_serve_entry
  @t0_serve_entry
end

#t1_preface_doneObject

2.10-G — connection-lifecycle timing slots used by the optional h2 latency-instrumentation path (gated by ‘HYPERION_H2_TIMING=1`). Each slot is a single CLOCK_MONOTONIC timestamp captured at most once per connection. nil = unset, set on first observation.



141
142
143
# File 'lib/hyperion/http2_handler.rb', line 141

def t1_preface_done
  @t1_preface_done
end

#t2_first_encodeObject

2.10-G — connection-lifecycle timing slots used by the optional h2 latency-instrumentation path (gated by ‘HYPERION_H2_TIMING=1`). Each slot is a single CLOCK_MONOTONIC timestamp captured at most once per connection. nil = unset, set on first observation.



141
142
143
# File 'lib/hyperion/http2_handler.rb', line 141

def t2_first_encode
  @t2_first_encode
end

#t2_first_wireObject

2.10-G — connection-lifecycle timing slots used by the optional h2 latency-instrumentation path (gated by ‘HYPERION_H2_TIMING=1`). Each slot is a single CLOCK_MONOTONIC timestamp captured at most once per connection. nil = unset, set on first observation.



141
142
143
# File 'lib/hyperion/http2_handler.rb', line 141

def t2_first_wire
  @t2_first_wire
end

Instance Method Details

#enqueue(bytes) ⇒ Object

Called by SendQueueIO#write on the calling (encoder) fiber. Enforces the per-connection backpressure cap before enqueuing.



162
163
164
165
166
167
# File 'lib/hyperion/http2_handler.rb', line 162

def enqueue(bytes)
  wait_for_drain_if_full(bytes.bytesize)
  @pending_bytes_lock.synchronize { @pending_bytes += bytes.bytesize }
  @queue << bytes
  @send_notify.signal
end

#note_drained(bytesize) ⇒ Object

Called by the writer fiber after each successful drain to release any encoders blocked on the cap.



178
179
180
181
182
183
184
# File 'lib/hyperion/http2_handler.rb', line 178

def note_drained(bytesize)
  @pending_bytes_lock.synchronize do
    @pending_bytes -= bytesize
    @pending_bytes = 0 if @pending_bytes.negative? # paranoia
  end
  @drained_notify.signal
end

#pending_bytesObject



205
206
207
# File 'lib/hyperion/http2_handler.rb', line 205

def pending_bytes
  @pending_bytes_lock.synchronize { @pending_bytes }
end

#queue_empty?Boolean

Returns:

  • (Boolean)


201
202
203
# File 'lib/hyperion/http2_handler.rb', line 201

def queue_empty?
  @queue.empty?
end

#shutdown!Object



190
191
192
193
194
195
# File 'lib/hyperion/http2_handler.rb', line 190

def shutdown!
  @writer_done = true
  # Wake the writer if it's parked, and any encoder waiting on drain.
  @send_notify.signal
  @drained_notify.signal
end

#try_popObject

Pops a single chunk; returns nil if the queue is empty (non-blocking).



170
171
172
173
174
# File 'lib/hyperion/http2_handler.rb', line 170

def try_pop
  @queue.pop(true)
rescue ::ThreadError
  nil
end

#wait_for_signalObject



186
187
188
# File 'lib/hyperion/http2_handler.rb', line 186

def wait_for_signal
  @send_notify.wait
end

#writer_done?Boolean

Returns:

  • (Boolean)


197
198
199
# File 'lib/hyperion/http2_handler.rb', line 197

def writer_done?
  @writer_done
end