dalli 2.7.11 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dalli might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +5 -10
- data/History.md +51 -0
- data/README.md +26 -91
- data/lib/dalli/cas/client.rb +1 -59
- data/lib/dalli/client.rb +167 -103
- data/lib/dalli/compressor.rb +4 -3
- data/lib/dalli/options.rb +3 -4
- data/lib/dalli/protocol/binary.rb +737 -0
- data/lib/dalli/protocol/value_compressor.rb +85 -0
- data/lib/dalli/protocol.rb +9 -0
- data/lib/dalli/ring.rb +12 -63
- data/lib/dalli/server.rb +2 -748
- data/lib/dalli/socket.rb +62 -128
- data/lib/dalli/version.rb +2 -1
- data/lib/dalli.rb +15 -16
- data/lib/rack/session/dalli.rb +21 -40
- metadata +35 -8
- data/lib/action_dispatch/middleware/session/dalli_store.rb +0 -82
- data/lib/active_support/cache/dalli_store.rb +0 -441
- data/lib/dalli/railtie.rb +0 -8
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
module Dalli
|
6
|
+
module Protocol
|
7
|
+
##
|
8
|
+
# Dalli::Protocol::ValueCompressor compartmentalizes the logic for managing
|
9
|
+
# compression and decompression of stored values. It manages interpreting
|
10
|
+
# relevant options from both client and request, determining whether to
|
11
|
+
# compress/decompress on store/retrieve, and processes bitflags as necessary.
|
12
|
+
##
|
13
|
+
class ValueCompressor
|
14
|
+
DEFAULTS = {
|
15
|
+
compress: true,
|
16
|
+
compressor: ::Dalli::Compressor,
|
17
|
+
# min byte size to attempt compression
|
18
|
+
compression_min_size: 4 * 1024 # 4K
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
OPTIONS = DEFAULTS.keys.freeze
|
22
|
+
|
23
|
+
# https://www.hjp.at/zettel/m/memcached_flags.rxml
|
24
|
+
# Looks like most clients use bit 1 to indicate gzip compression.
|
25
|
+
FLAG_COMPRESSED = 0x2
|
26
|
+
|
27
|
+
def initialize(client_options)
|
28
|
+
# Support the deprecated compression option, but don't allow it to override
|
29
|
+
# an explicit compress
|
30
|
+
# Remove this with 4.0
|
31
|
+
if client_options.key?(:compression) && !client_options.key?(:compress)
|
32
|
+
Dalli.logger.warn "DEPRECATED: Dalli's :compression option is now just 'compress: true'. " \
|
33
|
+
'Please update your configuration.'
|
34
|
+
client_options[:compress] = client_options.delete(:compression)
|
35
|
+
end
|
36
|
+
|
37
|
+
@compression_options =
|
38
|
+
DEFAULTS.merge(client_options.select { |k, _| OPTIONS.include?(k) })
|
39
|
+
end
|
40
|
+
|
41
|
+
def store(value, req_options, bitflags)
|
42
|
+
do_compress = compress_value?(value, req_options)
|
43
|
+
store_value = do_compress ? compressor.compress(value) : value
|
44
|
+
bitflags |= FLAG_COMPRESSED if do_compress
|
45
|
+
|
46
|
+
[store_value, bitflags]
|
47
|
+
end
|
48
|
+
|
49
|
+
def retrieve(value, bitflags)
|
50
|
+
compressed = (bitflags & FLAG_COMPRESSED) != 0
|
51
|
+
compressed ? compressor.decompress(value) : value
|
52
|
+
|
53
|
+
# TODO: We likely want to move this rescue into the Dalli::Compressor / Dalli::GzipCompressor
|
54
|
+
# itself, since not all compressors necessarily use Zlib. For now keep it here, so the behavior
|
55
|
+
# of custom compressors doesn't change.
|
56
|
+
rescue Zlib::Error
|
57
|
+
raise UnmarshalError, "Unable to uncompress value: #{$ERROR_INFO.message}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def compress_by_default?
|
61
|
+
@compression_options[:compress]
|
62
|
+
end
|
63
|
+
|
64
|
+
def compressor
|
65
|
+
@compression_options[:compressor]
|
66
|
+
end
|
67
|
+
|
68
|
+
def compression_min_size
|
69
|
+
@compression_options[:compression_min_size]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Checks whether we should apply compression when serializing a value
|
73
|
+
# based on the specified options. Returns false unless the value
|
74
|
+
# is greater than the minimum compression size. Otherwise returns
|
75
|
+
# based on a method-level option if specified, falling back to the
|
76
|
+
# server default.
|
77
|
+
def compress_value?(value, req_options)
|
78
|
+
return false unless value.bytesize >= compression_min_size
|
79
|
+
return compress_by_default? unless req_options && !req_options[:compress].nil?
|
80
|
+
|
81
|
+
req_options[:compress]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/dalli/ring.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
2
|
+
|
3
|
+
require "digest/sha1"
|
4
|
+
require "zlib"
|
4
5
|
|
5
6
|
module Dalli
|
6
7
|
class Ring
|
@@ -32,7 +33,13 @@ module Dalli
|
|
32
33
|
if @continuum
|
33
34
|
hkey = hash_for(key)
|
34
35
|
20.times do |try|
|
35
|
-
|
36
|
+
# Find the closest index in the Ring with value <= the given value
|
37
|
+
entryidx = @continuum.bsearch_index { |entry| entry.value > hkey }
|
38
|
+
if entryidx.nil?
|
39
|
+
entryidx = @continuum.size - 1
|
40
|
+
else
|
41
|
+
entryidx -= 1
|
42
|
+
end
|
36
43
|
server = @continuum[entryidx].server
|
37
44
|
return server if server.alive?
|
38
45
|
break unless @failover
|
@@ -40,7 +47,7 @@ module Dalli
|
|
40
47
|
end
|
41
48
|
else
|
42
49
|
server = @servers.first
|
43
|
-
return server if server
|
50
|
+
return server if server&.alive?
|
44
51
|
end
|
45
52
|
|
46
53
|
raise Dalli::RingError, "No server available"
|
@@ -49,7 +56,7 @@ module Dalli
|
|
49
56
|
def lock
|
50
57
|
@servers.each(&:lock!)
|
51
58
|
begin
|
52
|
-
|
59
|
+
yield
|
53
60
|
ensure
|
54
61
|
@servers.each(&:unlock!)
|
55
62
|
end
|
@@ -71,63 +78,6 @@ module Dalli
|
|
71
78
|
((total_servers * POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
|
72
79
|
end
|
73
80
|
|
74
|
-
# Native extension to perform the binary search within the continuum
|
75
|
-
# space. Fallback to a pure Ruby version if the compilation doesn't work.
|
76
|
-
# optional for performance and only necessary if you are using multiple
|
77
|
-
# memcached servers.
|
78
|
-
begin
|
79
|
-
require 'inline'
|
80
|
-
inline do |builder|
|
81
|
-
builder.c <<-EOM
|
82
|
-
int binary_search(VALUE ary, unsigned int r) {
|
83
|
-
long upper = RARRAY_LEN(ary) - 1;
|
84
|
-
long lower = 0;
|
85
|
-
long idx = 0;
|
86
|
-
ID value = rb_intern("value");
|
87
|
-
VALUE continuumValue;
|
88
|
-
unsigned int l;
|
89
|
-
|
90
|
-
while (lower <= upper) {
|
91
|
-
idx = (lower + upper) / 2;
|
92
|
-
|
93
|
-
continuumValue = rb_funcall(RARRAY_PTR(ary)[idx], value, 0);
|
94
|
-
l = NUM2UINT(continuumValue);
|
95
|
-
if (l == r) {
|
96
|
-
return idx;
|
97
|
-
}
|
98
|
-
else if (l > r) {
|
99
|
-
upper = idx - 1;
|
100
|
-
}
|
101
|
-
else {
|
102
|
-
lower = idx + 1;
|
103
|
-
}
|
104
|
-
}
|
105
|
-
return upper;
|
106
|
-
}
|
107
|
-
EOM
|
108
|
-
end
|
109
|
-
rescue LoadError
|
110
|
-
# Find the closest index in the Ring with value <= the given value
|
111
|
-
def binary_search(ary, value)
|
112
|
-
upper = ary.size - 1
|
113
|
-
lower = 0
|
114
|
-
|
115
|
-
while (lower <= upper) do
|
116
|
-
idx = (lower + upper) / 2
|
117
|
-
comp = ary[idx].value <=> value
|
118
|
-
|
119
|
-
if comp == 0
|
120
|
-
return idx
|
121
|
-
elsif comp > 0
|
122
|
-
upper = idx - 1
|
123
|
-
else
|
124
|
-
lower = idx + 1
|
125
|
-
end
|
126
|
-
end
|
127
|
-
upper
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
81
|
class Entry
|
132
82
|
attr_reader :value
|
133
83
|
attr_reader :server
|
@@ -137,6 +87,5 @@ module Dalli
|
|
137
87
|
@server = srv
|
138
88
|
end
|
139
89
|
end
|
140
|
-
|
141
90
|
end
|
142
91
|
end
|