dalli 2.0.1 → 3.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +671 -0
- data/Gemfile +15 -3
- data/LICENSE +1 -1
- data/README.md +33 -148
- data/lib/dalli/cas/client.rb +3 -0
- data/lib/dalli/client.rb +293 -131
- data/lib/dalli/compressor.rb +40 -0
- data/lib/dalli/key_manager.rb +121 -0
- data/lib/dalli/options.rb +22 -4
- data/lib/dalli/pid_cache.rb +40 -0
- data/lib/dalli/pipelined_getter.rb +177 -0
- data/lib/dalli/protocol/base.rb +250 -0
- data/lib/dalli/protocol/binary/request_formatter.rb +117 -0
- data/lib/dalli/protocol/binary/response_header.rb +36 -0
- data/lib/dalli/protocol/binary/response_processor.rb +239 -0
- data/lib/dalli/protocol/binary/sasl_authentication.rb +60 -0
- data/lib/dalli/protocol/binary.rb +173 -0
- data/lib/dalli/protocol/connection_manager.rb +255 -0
- data/lib/dalli/protocol/meta/key_regularizer.rb +31 -0
- data/lib/dalli/protocol/meta/request_formatter.rb +121 -0
- data/lib/dalli/protocol/meta/response_processor.rb +211 -0
- data/lib/dalli/protocol/meta.rb +178 -0
- data/lib/dalli/protocol/response_buffer.rb +54 -0
- data/lib/dalli/protocol/server_config_parser.rb +86 -0
- data/lib/dalli/protocol/ttl_sanitizer.rb +45 -0
- data/lib/dalli/protocol/value_compressor.rb +85 -0
- data/lib/dalli/protocol/value_marshaller.rb +59 -0
- data/lib/dalli/protocol/value_serializer.rb +91 -0
- data/lib/dalli/protocol.rb +19 -0
- data/lib/dalli/ring.rb +98 -50
- data/lib/dalli/server.rb +4 -524
- data/lib/dalli/servers_arg_normalizer.rb +54 -0
- data/lib/dalli/socket.rb +154 -53
- data/lib/dalli/version.rb +5 -1
- data/lib/dalli.rb +49 -13
- data/lib/rack/session/dalli.rb +169 -26
- metadata +53 -88
- data/History.md +0 -262
- data/Performance.md +0 -42
- data/Rakefile +0 -39
- data/dalli.gemspec +0 -28
- data/lib/action_dispatch/middleware/session/dalli_store.rb +0 -76
- data/lib/active_support/cache/dalli_store.rb +0 -203
- data/test/abstract_unit.rb +0 -281
- data/test/benchmark_test.rb +0 -187
- data/test/helper.rb +0 -41
- data/test/memcached_mock.rb +0 -113
- data/test/test_active_support.rb +0 -163
- data/test/test_dalli.rb +0 -461
- data/test/test_encoding.rb +0 -43
- data/test/test_failover.rb +0 -107
- data/test/test_network.rb +0 -54
- data/test/test_ring.rb +0 -85
- data/test/test_sasl.rb +0 -83
- data/test/test_session_store.rb +0 -224
data/lib/dalli/ring.rb
CHANGED
@@ -1,59 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest/sha1'
|
2
4
|
require 'zlib'
|
3
5
|
|
4
6
|
module Dalli
|
7
|
+
##
|
8
|
+
# An implementation of a consistent hash ring, designed to minimize
|
9
|
+
# the cache miss impact of adding or removing servers from the ring.
|
10
|
+
# That is, adding or removing a server from the ring should impact
|
11
|
+
# the key -> server mapping of ~ 1/N of the stored keys where N is the
|
12
|
+
# number of servers in the ring. This is done by creating a large
|
13
|
+
# number of "points" per server, distributed over the space
|
14
|
+
# 0x00000000 - 0xFFFFFFFF. For a given key, we calculate the CRC32
|
15
|
+
# hash, and find the nearest "point" that is less than or equal to the
|
16
|
+
# the key's hash. In this implemetation, each "point" is represented
|
17
|
+
# by a Dalli::Ring::Entry.
|
18
|
+
##
|
5
19
|
class Ring
|
20
|
+
# The number of entries on the continuum created per server
|
21
|
+
# in an equally weighted scenario.
|
6
22
|
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
7
23
|
|
8
24
|
attr_accessor :servers, :continuum
|
9
25
|
|
10
|
-
def initialize(
|
11
|
-
@servers =
|
12
|
-
|
13
|
-
if servers.size > 1
|
14
|
-
total_weight = servers.inject(0) { |memo, srv| memo + srv.weight }
|
15
|
-
continuum = []
|
16
|
-
servers.each do |server|
|
17
|
-
entry_count_for(server, servers.size, total_weight).times do |idx|
|
18
|
-
hash = Digest::SHA1.hexdigest("#{server.hostname}:#{server.port}:#{idx}")
|
19
|
-
value = Integer("0x#{hash[0..7]}")
|
20
|
-
continuum << Dalli::Ring::Entry.new(value, server)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
@continuum = continuum.sort { |a, b| a.value <=> b.value }
|
26
|
+
def initialize(servers_arg, protocol_implementation, options)
|
27
|
+
@servers = servers_arg.map do |s|
|
28
|
+
protocol_implementation.new(s, options)
|
24
29
|
end
|
30
|
+
@continuum = nil
|
31
|
+
@continuum = build_continuum(servers) if servers.size > 1
|
25
32
|
|
26
33
|
threadsafe! unless options[:threadsafe] == false
|
27
34
|
@failover = options[:failover] != false
|
28
35
|
end
|
29
36
|
|
30
37
|
def server_for_key(key)
|
31
|
-
if @continuum
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
server = if @continuum
|
39
|
+
server_from_continuum(key)
|
40
|
+
else
|
41
|
+
@servers.first
|
42
|
+
end
|
43
|
+
|
44
|
+
# Note that the call to alive? has the side effect of initializing
|
45
|
+
# the socket
|
46
|
+
return server if server&.alive?
|
47
|
+
|
48
|
+
raise Dalli::RingError, 'No server available'
|
49
|
+
end
|
50
|
+
|
51
|
+
def server_from_continuum(key)
|
52
|
+
hkey = hash_for(key)
|
53
|
+
20.times do |try|
|
54
|
+
server = server_for_hash_key(hkey)
|
55
|
+
|
56
|
+
# Note that the call to alive? has the side effect of initializing
|
57
|
+
# the socket
|
58
|
+
return server if server.alive?
|
59
|
+
break unless @failover
|
60
|
+
|
61
|
+
hkey = hash_for("#{try}#{key}")
|
43
62
|
end
|
63
|
+
nil
|
64
|
+
end
|
44
65
|
|
45
|
-
|
66
|
+
def keys_grouped_by_server(key_arr)
|
67
|
+
key_arr.group_by do |key|
|
68
|
+
server_for_key(key)
|
69
|
+
rescue Dalli::RingError
|
70
|
+
Dalli.logger.debug { "unable to get key #{key}" }
|
71
|
+
nil
|
72
|
+
end
|
46
73
|
end
|
47
74
|
|
48
75
|
def lock
|
49
|
-
@servers.each
|
76
|
+
@servers.each(&:lock!)
|
50
77
|
begin
|
51
|
-
|
78
|
+
yield
|
52
79
|
ensure
|
53
|
-
@servers.each
|
80
|
+
@servers.each(&:unlock!)
|
54
81
|
end
|
55
82
|
end
|
56
83
|
|
84
|
+
def pipeline_consume_and_ignore_responses
|
85
|
+
@servers.each do |s|
|
86
|
+
s.request(:noop)
|
87
|
+
rescue Dalli::NetworkError
|
88
|
+
# Ignore this error, as it indicates the socket is unavailable
|
89
|
+
# and there's no need to flush
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def socket_timeout
|
94
|
+
@servers.first.socket_timeout
|
95
|
+
end
|
96
|
+
|
97
|
+
def close
|
98
|
+
@servers.each(&:close)
|
99
|
+
end
|
100
|
+
|
57
101
|
private
|
58
102
|
|
59
103
|
def threadsafe!
|
@@ -70,36 +114,40 @@ module Dalli
|
|
70
114
|
((total_servers * POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
|
71
115
|
end
|
72
116
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
117
|
+
def server_for_hash_key(hash_key)
|
118
|
+
# Find the closest index in the Ring with value <= the given value
|
119
|
+
entryidx = @continuum.bsearch_index { |entry| entry.value > hash_key }
|
120
|
+
if entryidx.nil?
|
121
|
+
entryidx = @continuum.size - 1
|
122
|
+
else
|
123
|
+
entryidx -= 1
|
124
|
+
end
|
125
|
+
@continuum[entryidx].server
|
126
|
+
end
|
127
|
+
|
128
|
+
def build_continuum(servers)
|
129
|
+
continuum = []
|
130
|
+
total_weight = servers.inject(0) { |memo, srv| memo + srv.weight }
|
131
|
+
servers.each do |server|
|
132
|
+
entry_count_for(server, servers.size, total_weight).times do |idx|
|
133
|
+
hash = Digest::SHA1.hexdigest("#{server.name}:#{idx}")
|
134
|
+
value = Integer("0x#{hash[0..7]}")
|
135
|
+
continuum << Dalli::Ring::Entry.new(value, server)
|
89
136
|
end
|
90
137
|
end
|
91
|
-
|
138
|
+
continuum.sort_by(&:value)
|
92
139
|
end
|
93
140
|
|
141
|
+
##
|
142
|
+
# Represents a point in the consistent hash ring implementation.
|
143
|
+
##
|
94
144
|
class Entry
|
95
|
-
attr_reader :value
|
96
|
-
attr_reader :server
|
145
|
+
attr_reader :value, :server
|
97
146
|
|
98
147
|
def initialize(val, srv)
|
99
148
|
@value = val
|
100
149
|
@server = srv
|
101
150
|
end
|
102
151
|
end
|
103
|
-
|
104
152
|
end
|
105
153
|
end
|