class Concurrent::Collection::AtomicReferenceMapBackend::Node

Key-value entry. Nodes with a hash field of MOVED are special, and do not contain user keys or values. Otherwise, keys are never nil, and NULL value fields indicate that a node is in the process of being deleted or created. For purposes of read-only access, a key may be read before a value, but can only be used after checking value to be +!= NULL+.

@!visibility private

Constants

HASH_BITS
LOCKED
MOVED

Encodings for special uses of Node hash fields. See above for explanation.

SPIN_LOCK_ATTEMPTS
WAITING

Attributes

key[R]

Public Class Methods

new(hash, key, value, next_node = nil) click to toggle source
Calls superclass method
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 261
def initialize(hash, key, value, next_node = nil)
  super()
  @key = key
  self.lazy_set_hash(hash)
  self.lazy_set_value(value)
  self.next = next_node
end

Private Class Methods

locked_hash?(hash) click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 344
def locked_hash?(hash)
  (hash & LOCKED) != 0
end

Public Instance Methods

key?(key) click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 299
def key?(key)
  @key.eql?(key)
end
locked?() click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 321
def locked?
  self.class.locked_hash?(hash)
end
matches?(key, hash) click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 303
def matches?(key, hash)
  pure_hash == hash && key?(key)
end
pure_hash() click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 307
def pure_hash
  hash & HASH_BITS
end
try_await_lock(table, i) click to toggle source

Spins a while if LOCKED bit set and this node is the first of its bin, and then sets WAITING bits on hash field and blocks (once) if they are still set. It is OK for this method to return even if lock is not available upon exit, which enables these simple single-wait mechanics.

The corresponding signalling operation is performed within callers: Upon detecting that WAITING has been set when unlocking lock (via a failed CAS from non-waiting LOCKED state), unlockers acquire the cheap_synchronize lock and perform a cheap_broadcast.

# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 278
def try_await_lock(table, i)
  if table && i >= 0 && i < table.size # bounds check, TODO: why are we bounds checking?
    spins = SPIN_LOCK_ATTEMPTS
    randomizer = base_randomizer = Concurrent::ThreadSafe::Util::XorShiftRandom.get
    while equal?(table.volatile_get(i)) && self.class.locked_hash?(my_hash = hash)
      if spins >= 0
        if (randomizer = (randomizer >> 1)).even? # spin at random
          if (spins -= 1) == 0
            Thread.pass # yield before blocking
          else
            randomizer = base_randomizer = Concurrent::ThreadSafe::Util::XorShiftRandom.xorshift(base_randomizer) if randomizer.zero?
          end
        end
      elsif cas_hash(my_hash, my_hash | WAITING)
        force_acquire_lock(table, i)
        break
      end
    end
  end
end
try_lock_via_hash(node_hash = hash) { || ... } click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 311
def try_lock_via_hash(node_hash = hash)
  if cas_hash(node_hash, locked_hash = node_hash | LOCKED)
    begin
      yield
    ensure
      unlock_via_hash(locked_hash, node_hash)
    end
  end
end
unlock_via_hash(locked_hash, node_hash) click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 325
def unlock_via_hash(locked_hash, node_hash)
  unless cas_hash(locked_hash, node_hash)
    self.hash = node_hash
    cheap_synchronize { cheap_broadcast }
  end
end

Private Instance Methods

force_acquire_lock(table, i) click to toggle source
# File lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb, line 333
def force_acquire_lock(table, i)
  cheap_synchronize do
    if equal?(table.volatile_get(i)) && (hash & WAITING) == WAITING
      cheap_wait
    else
      cheap_broadcast # possibly won race vs signaller
    end
  end
end