Class: Shoryuken::Helpers::AtomicHash

Inherits:
Object
  • Object
show all
Defined in:
lib/shoryuken/helpers/atomic_hash.rb

Overview

Note:

This implementation uses mutex synchronization for all operations, ensuring complete thread safety with minimal performance impact.

Note:

All operations are atomic and will never see partial effects from concurrent operations.

A thread-safe hash implementation using Ruby’s Mutex for all operations.

This class provides a hash-like interface with thread-safe operations, serving as a drop-in replacement for Concurrent::Hash without requiring external dependencies. The implementation uses a single mutex to protect both read and write operations, ensuring complete thread safety across all Ruby implementations including JRuby.

Since hash operations (lookup, assignment) are very fast, the mutex overhead is minimal while providing guaranteed safety and simplicity. This approach avoids the complexity of copy-on-write while maintaining excellent performance for typical usage patterns.

Examples:

Basic hash operations

hash = Shoryuken::Helpers::AtomicHash.new
hash['key'] = 'value'
hash['key']           # => 'value'
hash.keys             # => ['key']
hash.clear
hash['key']           # => nil

Worker registry usage

@workers = Shoryuken::Helpers::AtomicHash.new

# Registration (infrequent writes)
@workers['queue_name'] = WorkerClass

# Lookups (frequent reads)
worker_class = @workers['queue_name']
available_queues = @workers.keys
worker_class = @workers.fetch('queue_name', DefaultWorker)

Thread-safe concurrent access

hash = Shoryuken::Helpers::AtomicHash.new

# Multiple threads can safely write
Thread.new { hash['key1'] = 'value1' }
Thread.new { hash['key2'] = 'value2' }

# Multiple threads can safely read concurrently
Thread.new { puts hash['key1'] }
Thread.new { puts hash.keys.size }

Instance Method Summary collapse

Constructor Details

#initializeAtomicHash

Creates a new empty atomic hash.

The hash starts empty and ready to accept key-value pairs through thread-safe operations.

Examples:

Creating an empty hash

hash = Shoryuken::Helpers::AtomicHash.new
hash.keys  # => []


63
64
65
66
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 63

def initialize
  @mutex = Mutex.new
  @hash = {}
end

Instance Method Details

#[](key) ⇒ Object?

Returns the value associated with the given key.

This operation is thread-safe and will return a consistent value even when called concurrently with write operations.

Examples:

Reading values

hash = Shoryuken::Helpers::AtomicHash.new
hash['existing'] = 'value'
hash['existing']    # => 'value'
hash['missing']     # => nil

Works with any key type

hash = Shoryuken::Helpers::AtomicHash.new
hash[:symbol] = 'symbol_value'
hash[42] = 'number_value'
hash[:symbol]  # => 'symbol_value'
hash[42]       # => 'number_value'

Parameters:

  • key (Object)

    The key to look up

Returns:

  • (Object, nil)

    The value associated with the key, or nil if not found



88
89
90
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 88

def [](key)
  @mutex.synchronize { @hash[key] }
end

#[]=(key, value) ⇒ Object

Sets the value for the given key.

This is a thread-safe write operation that ensures data integrity when called concurrently with other read or write operations.

Examples:

Setting values

hash = Shoryuken::Helpers::AtomicHash.new
hash['queue1'] = 'Worker1'
hash['queue2'] = 'Worker2'
hash['queue1']  # => 'Worker1'

Overwriting values

hash = Shoryuken::Helpers::AtomicHash.new
hash['key'] = 'old_value'
hash['key'] = 'new_value'
hash['key']  # => 'new_value'

Parameters:

  • key (Object)

    The key to set

  • value (Object)

    The value to associate with the key

Returns:

  • (Object)

    The assigned value



112
113
114
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 112

def []=(key, value)
  @mutex.synchronize { @hash[key] = value }
end

#clearHash

Removes all key-value pairs from the hash.

This is a thread-safe write operation that ensures atomicity when called concurrently with other operations.

Examples:

Clearing all entries

hash = Shoryuken::Helpers::AtomicHash.new
hash['key1'] = 'value1'
hash['key2'] = 'value2'
hash.keys.size  # => 2
hash.clear
hash.keys.size  # => 0
hash['key1']    # => nil

Returns:

  • (Hash)

    An empty hash (for compatibility with standard Hash#clear)



131
132
133
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 131

def clear
  @mutex.synchronize { @hash.clear }
end

#fetch(key, default = nil) ⇒ Object

Returns the value for the given key, or a default value if the key is not found.

This operation is thread-safe and will return a consistent value even when called concurrently with write operations.

Examples:

Fetching with defaults

hash = Shoryuken::Helpers::AtomicHash.new
hash['existing'] = 'found'
hash.fetch('existing', 'default')  # => 'found'
hash.fetch('missing', 'default')   # => 'default'

Default parameter is optional

hash = Shoryuken::Helpers::AtomicHash.new
hash.fetch('missing')  # => nil

Useful for providing fallback collections

hash = Shoryuken::Helpers::AtomicHash.new
workers = hash.fetch('queue_name', [])  # => [] if not found

Parameters:

  • key (Object)

    The key to look up

  • default (Object) (defaults to: nil)

    The value to return if the key is not found

Returns:

  • (Object)

    The value associated with the key, or the default value



177
178
179
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 177

def fetch(key, default = nil)
  @mutex.synchronize { @hash.fetch(key, default) }
end

#keysArray

Returns an array of all keys in the hash.

This operation is thread-safe and will return a consistent snapshot of keys even when called concurrently with write operations.

Examples:

Getting all keys

hash = Shoryuken::Helpers::AtomicHash.new
hash['queue1'] = 'Worker1'
hash['queue2'] = 'Worker2'
hash.keys  # => ['queue1', 'queue2'] (order not guaranteed)

Empty hash returns empty array

hash = Shoryuken::Helpers::AtomicHash.new
hash.keys  # => []

Returns:

  • (Array)

    An array containing all keys in the hash



151
152
153
# File 'lib/shoryuken/helpers/atomic_hash.rb', line 151

def keys
  @mutex.synchronize { @hash.keys }
end