Class: Corosync::CMAP
- Inherits:
-
Object
- Object
- Corosync::CMAP
- Defined in:
- lib/corosync/cmap.rb
Overview
CMAP is used to access the corosync configuration database for the local node. You can list keys, get/set/delete values, and watch for changes.
Many of the methods take or return a ‘type’. The type is a symbol for one of CMAP’s supported types. The symbols are:
-
:int8
-
:uint8
-
:int16
-
:uint16
-
:int32
-
:uint32
-
:int64
-
:uint64
-
:float
-
:double
-
:string
Instance Attribute Summary collapse
-
#fd ⇒ IO
readonly
The IO object containing the file descriptor events and messages come across.
Instance Method Summary collapse
-
#connect ⇒ void
Connect to the CMAP service.
-
#dec(name) ⇒ void
Decrement the specified key.
-
#delete(name) ⇒ void
Delete the specified key.
-
#dispatch(timeout = -1)) ⇒ Boolean
Checks for a single pending event and triggers the appropriate callback if found.
-
#finalize ⇒ void
Disconnect from the CMAP service.
-
#get(name) ⇒ Array<type, value>
Retrieve a key by the specified name.
-
#get_value(name) ⇒ Number, String
Retrieve a key’s value.
-
#inc(name) ⇒ void
Increment the specified key.
-
#initialize(connect = true) ⇒ CMAP
constructor
Starts a new instance of CMAP.
-
#keys(prefix = nil) ⇒ Array<String>
Get a list of keys.
-
#set(name, type, value) ⇒ Number, String
Set a key to the specified type & value.
-
#set_value(name, value) ⇒ Number, String
Set a key to the specified value.
-
#track_add(name, actions, prefix = false, &block) {|action, key, value_new_type, value_new_data, value_old_type, value_old_data| ... } ⇒ Object
Watch keys for changes.
-
#track_delete(track_handle) ⇒ void
Stop watching for changes.
Constructor Details
#initialize(connect = true) ⇒ CMAP
Starts a new instance of CMAP. You can have as many instances as you like, but no real reason for more than one.
38 39 40 41 42 43 44 |
# File 'lib/corosync/cmap.rb', line 38 def initialize(connect = true) @handle = nil @track_handle_callbacks = {} self.connect if connect end |
Instance Attribute Details
#fd ⇒ IO (readonly)
The IO object containing the file descriptor events and messages come across. You can use this to check for activity prior to calling #dispatch, but do not read anything from it.
32 33 34 |
# File 'lib/corosync/cmap.rb', line 32 def fd @fd end |
Instance Method Details
#connect ⇒ void
This method returns an undefined value.
Connect to the CMAP service.
49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/corosync/cmap.rb', line 49 def connect handle_ptr = FFI::MemoryPointer.new(Corosync.find_type(:cmap_handle_t)) Corosync.cs_send(:cmap_initialize, handle_ptr) @handle = handle_ptr.read_uint64 fd_ptr = FFI::MemoryPointer.new(:int) Corosync.cs_send(:cmap_fd_get, @handle, fd_ptr) @fd = IO.new(fd_ptr.read_int) end |
#dec(name) ⇒ void
This method returns an undefined value.
Decrement the specified key.
241 242 243 |
# File 'lib/corosync/cmap.rb', line 241 def dec(name) Corosync.cs_send(:cmap_dec, @handle, name) end |
#delete(name) ⇒ void
This method returns an undefined value.
Delete the specified key.
232 233 234 |
# File 'lib/corosync/cmap.rb', line 232 def delete(name) Corosync.cs_send(:cmap_delete, @handle, name) end |
#dispatch(timeout = -1)) ⇒ Boolean
Checks for a single pending event and triggers the appropriate callback if found.
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/corosync/cmap.rb', line 366 def dispatch(timeout = -1) if !timeout != 0 then timeout = nil if timeout == -1 select([@fd], [], [], timeout) end begin Corosync.cs_send!(:cmap_dispatch, @handle, Corosync::CS_DISPATCH_ONE_NONBLOCKING) rescue Corosync::TryAgainError => e raise e if e.depth > 1 # this exception is from a nested corosync function, not our quorum_dispatch we just called return false end return true end |
#finalize ⇒ void
This method returns an undefined value.
Disconnect from the CMAP service.
64 65 66 67 68 69 70 71 |
# File 'lib/corosync/cmap.rb', line 64 def finalize return if @handle.nil? Corosync.cs_send(:cmap_finalize, @handle) @handle = nil @fd = nil end |
#get(name) ⇒ Array<type, value>
Retrieve a key by the specified name. Will raise NotExistError if the key does not exist.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/corosync/cmap.rb', line 77 def get(name) #TODO? make it just return nil if the key doesn't exist size_ptr = FFI::MemoryPointer.new(:size_t) type_ptr = FFI::MemoryPointer.new(Corosync.find_type(:cmap_value_types_t)) size = 256 begin size_ptr.write_type(:size_t, size) value_ptr = FFI::MemoryPointer.new(size) Corosync.cs_send(:cmap_get, @handle, name, value_ptr, size_ptr, type_ptr) rescue Corosync::InvalidParamError => e # err_invalid_param is supposed to indicate our buffer was too small value_ptr.free size << 1 retry if size < 1024 ** 2 # 1 MB raise e end type = type_ptr.read_type(Corosync.find_type(:cmap_value_types_t)) type = Corosync.enum_type(:cmap_value_types_t)[type] if type == :binary then raise RuntimeError, "Binary, not sure how to handle this. Corosync docs don't clearly indicate what it is" end [type, value_ptr.send("read_#{type}".downcase.to_sym)] end |
#get_value(name) ⇒ Number, String
Retrieve a key’s value. This is just a conveinence wrapper around #get to only get the value if you don’t want the type.
113 114 115 116 |
# File 'lib/corosync/cmap.rb', line 113 def get_value(name) type, value = get(name) value end |
#inc(name) ⇒ void
This method returns an undefined value.
Increment the specified key.
250 251 252 |
# File 'lib/corosync/cmap.rb', line 250 def inc(name) Corosync.cs_send(:cmap_inc, @handle, name) end |
#keys(prefix = nil) ⇒ Array<String>
Get a list of keys.
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/corosync/cmap.rb', line 259 def keys(prefix = nil) cmap_iteration_handle_ptr = FFI::MemoryPointer.new(Corosync.find_type(:cmap_iter_handle_t)) Corosync.cs_send(:cmap_iter_init, @handle, prefix, cmap_iteration_handle_ptr) cmap_iteration_handle = cmap_iteration_handle_ptr.read_type(Corosync.find_type(:cmap_iter_handle_t)) keys = [] key_name_ptr = FFI::MemoryPointer.new(Corosync::CMAP_KEYNAME_MAXLEN) begin begin loop do Corosync.cs_send(:cmap_iter_next, @handle, cmap_iteration_handle, key_name_ptr, nil, nil) # we really don't need to get info on the value. it doesn't help us any #value_size = value_len_ptr.read_type(:size_t) #value_type = value_type_ptr.read_type(Corosync.find_type(:cmap_value_types_t)) #value_type = Corosync.enum_type(:cmap_value_types_t)[value_type] #keys[key_name_ptr.read_string] = Corosync::CMAP::ValueInfo.new(value_size, value_type) keys << key_name_ptr.read_string end rescue Corosync::NoSectionsError # signals end of iteration end ensure Corosync.cs_send(:cmap_iter_finalize, @handle, cmap_iteration_handle) end keys end |
#set(name, type, value) ⇒ Number, String
Set a key to the specified type & value. This will create the key if it doesn’t exist, and will otherwise modify it, including changing the type if it doesn’t match.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/corosync/cmap.rb', line 126 def set(name, type, value) # get byte size if type == :string then size = value.bytesize elsif SIZEMAP.keys.include?(type) then size = SIZEMAP[type].bytes elsif type == :float then size = 4 elsif type == :double then size = 8 elsif type == :binary then size = value.bytesize end value_ptr = FFI::MemoryPointer.new(size) value_ptr.write_type(type, value) Corosync.cs_send(:cmap_set, @handle, name, value_ptr, size, type) value end |
#set_value(name, value) ⇒ Number, String
Set a key to the specified value. A convenience wrapper around #set to automatically determine the type. If the value is numeric, we will use the same type as the existing value (if it already exists). Otherwise we pick the smallest type that will hold the value.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/corosync/cmap.rb', line 168 def set_value(name, value) type = catch :type do # strings are strings throw :type, :string if value.is_a?(String) # try and get existing type begin type_ptr = FFI::MemoryPointer.new(Corosync.find_type(:cmap_value_types_t)) size_ptr = FFI::MemoryPointer.new(:size_t) Corosync.cs_send(:cmap_get, @handle, name, nil, size_ptr, type_ptr) type = type_ptr.read_type(Corosync.find_type(:cmap_value_types_t)) type = Corosync.enum_type(:cmap_value_types_t)[type] if SIZEMAP.keys.include(type) then size = size_ptr.read_type(:size_t) if size <= SIZEMAP[type].bytes then # it fits within the existing type throw :type, type end # it doesnt fit, we need to re-type it end rescue Corosync::NotExistError end # find the type that will fit if value.is_a?(Float) then type = :double elsif value.is_a?(Numeric) then if value.abs <= 2 ** 7 and value < 0 then type = :int8 elsif value <= 2 ** 8 and value >= 0 then type = :uint8 elsif value.abs <= 2 ** 15 and value < 0 then type = :int16 elsif value <= 2 ** 16 and value >= 0 then type = :uint16 elsif value.abs <= 2 ** 31 and value < 0 then type = :int32 elsif value <= 2 ** 32 and value >= 0 then type = :uint32 elsif value.abs <= 2 ** 63 and value < 0 then type = :int64 elsif value < 2 ** 64 and value >= 0 then type = :uint64 else raise ArgumentError, "Corosync cannot handle numbers larger than 64-bit" end throw :type, type end # Unknown type, force it into a string throw :type, :string end value = value.to_s if type == :string and !value.is_a?(String) set(name, type, value) end |
#track_add(name, actions, prefix = false, &block) {|action, key, value_new_type, value_new_data, value_old_type, value_old_data| ... } ⇒ Object
Watch keys for changes. Calls a callback when the watched key(s) are changed.
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/corosync/cmap.rb', line 309 def track_add(name, actions, prefix = false, &block) cs_track_type = 0 cs_track_type |= Corosync::CMAP_TRACK_ADD if actions.include?(:add) cs_track_type |= Corosync::CMAP_TRACK_DELETE if actions.include?(:delete) cs_track_type |= Corosync::CMAP_TRACK_MODIFY if actions.include?(:modify) cs_track_type |= Corosync::CMAP_TRACK_PREFIX if prefix track_handle_ptr = FFI::MemoryPointer.new(Corosync.find_type(:cmap_track_handle_t)) @track_notify_method ||= self.method(:track_notify) # we have to keep it from being garbage collected Corosync.cs_send(:cmap_track_add, @handle, name, cs_track_type, @track_notify_method, nil, track_handle_ptr) track_handle = track_handle_ptr.read_type(Corosync.find_type(:cmap_track_handle_t)) @track_handle_callbacks[track_handle] = block track_handle end |