Class: Kafka::FFI::Opaque
- Inherits:
-
Object
- Object
- Kafka::FFI::Opaque
- Extended by:
- FFI::DataConverter
- Defined in:
- lib/kafka/ffi/opaque.rb
Overview
Opaque provides a safe mechanism for providing Ruby objects as opaque pointers.
Opaque pointers are used heavily in librdkafka to allow for passing references to application state into callbacks, configs, and other contexts. Ruby's garbage collector cannot check for references held in external FFI memory and will garbage collect objects that are otherwise not referenced leading to a segmentation fault.
Opaque solves this by allocated a memory address which is used as a hash key to look up the Ruby object when needed. This keeps a reference to the object in Ruby so it is not garbage collected. This method allows for Ruby objects to be moved in memory during compaction (in Ruby 2.7+) compared to storing a referece to a Ruby object.
Instance Attribute Summary collapse
-
#pointer ⇒ Object
readonly
Returns the value of attribute pointer.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Class Method Summary collapse
- .from_native(value, _ctx) ⇒ Object
-
.register(opaque) ⇒ Object
Register the Opaque the registry, keeping a reference to it to avoid it being garbage collected.
-
.remove(opaque) ⇒ Object
Remove the Opaque from the registry, putting it back in contention for garbage collection.
- .to_native(value, _ctx) ⇒ Object
Instance Method Summary collapse
-
#free ⇒ Object
Free releases the pointer back to the system and removes the Opaque from the registry.
-
#initialize(value) ⇒ Opaque
constructor
A new instance of Opaque.
Constructor Details
#initialize(value) ⇒ Opaque
Returns a new instance of Opaque.
62 63 64 65 66 67 |
# File 'lib/kafka/ffi/opaque.rb', line 62 def initialize(value) @value = value @pointer = ::FFI::MemoryPointer.new(:int8) Opaque.register(self) end |
Instance Attribute Details
#pointer ⇒ Object (readonly)
Returns the value of attribute pointer.
60 61 62 |
# File 'lib/kafka/ffi/opaque.rb', line 60 def pointer @pointer end |
#value ⇒ Object (readonly)
Returns the value of attribute value.
59 60 61 |
# File 'lib/kafka/ffi/opaque.rb', line 59 def value @value end |
Class Method Details
.from_native(value, _ctx) ⇒ Object
50 51 52 53 54 55 56 |
# File 'lib/kafka/ffi/opaque.rb', line 50 def from_native(value, _ctx) if value.null? return nil end @registry.fetch(value.address, nil) end |
.register(opaque) ⇒ Object
Register the Opaque the registry, keeping a reference to it to avoid it being garbage collected. This will replace any existing Opaque with the same address.
32 33 34 |
# File 'lib/kafka/ffi/opaque.rb', line 32 def register(opaque) @registry[opaque.pointer.address] = opaque end |
.remove(opaque) ⇒ Object
Remove the Opaque from the registry, putting it back in contention for garbage collection.
40 41 42 |
# File 'lib/kafka/ffi/opaque.rb', line 40 def remove(opaque) @registry.delete(opaque.pointer.address) end |
.to_native(value, _ctx) ⇒ Object
45 46 47 |
# File 'lib/kafka/ffi/opaque.rb', line 45 def to_native(value, _ctx) value.pointer end |
Instance Method Details
#free ⇒ Object
Free releases the pointer back to the system and removes the Opaque from the registry. free should only be called when the Opaque is no longer stored in librdkafka as it frees the backing pointer which could cause a segfault if still referenced.
73 74 75 76 77 78 79 |
# File 'lib/kafka/ffi/opaque.rb', line 73 def free Opaque.remove(self) @pointer.free @value = nil @pointer = nil end |