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.



136
137
138
139
140
141
142
143
144
145
# File 'lib/hyperion/http2_handler.rb', line 136

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
end

Instance Attribute Details

#encode_mutexObject (readonly)

Returns the value of attribute encode_mutex.



134
135
136
# File 'lib/hyperion/http2_handler.rb', line 134

def encode_mutex
  @encode_mutex
end

Instance Method Details

#enqueue(bytes) ⇒ Object

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



149
150
151
152
153
154
# File 'lib/hyperion/http2_handler.rb', line 149

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.



165
166
167
168
169
170
171
# File 'lib/hyperion/http2_handler.rb', line 165

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



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

def pending_bytes
  @pending_bytes_lock.synchronize { @pending_bytes }
end

#queue_empty?Boolean

Returns:

  • (Boolean)


188
189
190
# File 'lib/hyperion/http2_handler.rb', line 188

def queue_empty?
  @queue.empty?
end

#shutdown!Object



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

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).



157
158
159
160
161
# File 'lib/hyperion/http2_handler.rb', line 157

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

#wait_for_signalObject



173
174
175
# File 'lib/hyperion/http2_handler.rb', line 173

def wait_for_signal
  @send_notify.wait
end

#writer_done?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/hyperion/http2_handler.rb', line 184

def writer_done?
  @writer_done
end