Class: Dalli::Ring
- Inherits:
-
Object
- Object
- Dalli::Ring
- Defined in:
- lib/dalli/ring.rb
Overview
An implementation of a consistent hash ring, designed to minimize the cache miss impact of adding or removing servers from the ring. That is, adding or removing a server from the ring should impact the key -> server mapping of ~ 1/N of the stored keys where N is the number of servers in the ring. This is done by creating a large number of “points” per server, distributed over the space 0x00000000 - 0xFFFFFFFF. For a given key, we calculate the CRC32 hash, and find the nearest “point” that is less than or equal to the the key’s hash. In this implemetation, each “point” is represented by a Dalli::Ring::Entry.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- POINTS_PER_SERVER =
The number of entries on the continuum created per server in an equally weighted scenario.
160
Instance Attribute Summary collapse
-
#continuum ⇒ Object
this is the default in libmemcached.
-
#servers ⇒ Object
this is the default in libmemcached.
Instance Method Summary collapse
- #close ⇒ Object
-
#initialize(servers_arg, protocol_implementation, options) ⇒ Ring
constructor
A new instance of Ring.
- #keys_grouped_by_server(key_arr) ⇒ Object
- #lock ⇒ Object
- #pipeline_consume_and_ignore_responses ⇒ Object
- #server_for_key(key) ⇒ Object
- #server_from_continuum(key) ⇒ Object
- #socket_timeout ⇒ Object
Constructor Details
#initialize(servers_arg, protocol_implementation, options) ⇒ Ring
Returns a new instance of Ring.
26 27 28 29 30 31 32 33 34 35 |
# File 'lib/dalli/ring.rb', line 26 def initialize(servers_arg, protocol_implementation, ) @servers = servers_arg.map do |s| protocol_implementation.new(s, ) end @continuum = nil @continuum = build_continuum(servers) if servers.size > 1 threadsafe! unless [:threadsafe] == false @failover = [:failover] != false end |
Instance Attribute Details
#continuum ⇒ Object
this is the default in libmemcached
24 25 26 |
# File 'lib/dalli/ring.rb', line 24 def continuum @continuum end |
#servers ⇒ Object
this is the default in libmemcached
24 25 26 |
# File 'lib/dalli/ring.rb', line 24 def servers @servers end |
Instance Method Details
#close ⇒ Object
97 98 99 |
# File 'lib/dalli/ring.rb', line 97 def close @servers.each(&:close) end |
#keys_grouped_by_server(key_arr) ⇒ Object
66 67 68 69 70 71 72 73 |
# File 'lib/dalli/ring.rb', line 66 def keys_grouped_by_server(key_arr) key_arr.group_by do |key| server_for_key(key) rescue Dalli::RingError Dalli.logger.debug { "unable to get key #{key}" } nil end end |
#lock ⇒ Object
75 76 77 78 79 80 81 82 |
# File 'lib/dalli/ring.rb', line 75 def lock @servers.each(&:lock!) begin yield ensure @servers.each(&:unlock!) end end |
#pipeline_consume_and_ignore_responses ⇒ Object
84 85 86 87 88 89 90 91 |
# File 'lib/dalli/ring.rb', line 84 def pipeline_consume_and_ignore_responses @servers.each do |s| s.request(:noop) rescue Dalli::NetworkError # Ignore this error, as it indicates the socket is unavailable # and there's no need to flush end end |
#server_for_key(key) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/dalli/ring.rb', line 37 def server_for_key(key) server = if @continuum server_from_continuum(key) else @servers.first end # Note that the call to alive? has the side effect of initializing # the socket return server if server&.alive? raise Dalli::RingError, 'No server available' end |
#server_from_continuum(key) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/dalli/ring.rb', line 51 def server_from_continuum(key) hkey = hash_for(key) 20.times do |try| server = server_for_hash_key(hkey) # Note that the call to alive? has the side effect of initializing # the socket return server if server.alive? break unless @failover hkey = hash_for("#{try}#{key}") end nil end |
#socket_timeout ⇒ Object
93 94 95 |
# File 'lib/dalli/ring.rb', line 93 def socket_timeout @servers.first.socket_timeout end |