Skip to content

Commit dfdd8f1

Browse files
committed
example adding support for arbitrary meta flags and for getting them back as part of the response
1 parent 06be66d commit dfdd8f1

File tree

6 files changed

+71
-5
lines changed

6 files changed

+71
-5
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ profile.html
2525
## Environment normalisation:
2626
/.bundle/
2727
/lib/bundler/man/
28+
dev.yml
2829

2930
# for a library or gem, you might want to ignore these files since the code is
3031
# intended to run in multiple environments; otherwise, check them in:

lib/dalli/protocol/base.rb

+6
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ def ensure_connected!
197197
connected?
198198
end
199199

200+
def meta_flag_options(opts)
201+
return nil unless opts.is_a?(Hash)
202+
203+
opts[:meta_flags]
204+
end
205+
200206
def cache_nils?(opts)
201207
return false unless opts.is_a?(Hash)
202208

lib/dalli/protocol/meta.rb

+12-4
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ def response_processor
2525
# Retrieval Commands
2626
def get(key, options = nil)
2727
encoded_key, base64 = KeyRegularizer.encode(key)
28-
req = RequestFormatter.meta_get(key: encoded_key, base64: base64)
28+
req = RequestFormatter.meta_get(key: encoded_key, base64: base64, meta_flags: meta_flag_options(options))
2929
write(req)
30-
response_processor.meta_get_with_value(cache_nils: cache_nils?(options))
30+
if meta_flag_options(options)
31+
response_processor.meta_get_with_value_and_meta_flags(cache_nils: cache_nils?(options))
32+
else
33+
response_processor.meta_get_with_value(cache_nils: cache_nils?(options))
34+
end
3135
end
3236

3337
def quiet_get_request(key)
@@ -38,9 +42,13 @@ def quiet_get_request(key)
3842
def gat(key, ttl, options = nil)
3943
ttl = TtlSanitizer.sanitize(ttl)
4044
encoded_key, base64 = KeyRegularizer.encode(key)
41-
req = RequestFormatter.meta_get(key: encoded_key, ttl: ttl, base64: base64)
45+
req = RequestFormatter.meta_get(key: encoded_key, ttl: ttl, base64: base64, meta_flags: meta_flag_options(options))
4246
write(req)
43-
response_processor.meta_get_with_value(cache_nils: cache_nils?(options))
47+
if meta_flag_options(options)
48+
response_processor.meta_get_with_value_and_meta_flags(cache_nils: cache_nils?(options))
49+
else
50+
response_processor.meta_get_with_value(cache_nils: cache_nils?(options))
51+
end
4452
end
4553

4654
def touch(key, ttl)

lib/dalli/protocol/meta/request_formatter.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ class RequestFormatter
1616
# rubocop:disable Metrics/MethodLength
1717
# rubocop:disable Metrics/ParameterLists
1818
# rubocop:disable Metrics/PerceivedComplexity
19-
def self.meta_get(key:, value: true, return_cas: false, ttl: nil, base64: false, quiet: false)
19+
def self.meta_get(key:, value: true, return_cas: false, ttl: nil, base64: false, quiet: false, meta_flags: nil)
2020
cmd = "mg #{key}"
2121
cmd << ' v f' if value
2222
cmd << ' c' if return_cas
2323
cmd << ' b' if base64
2424
cmd << " T#{ttl}" if ttl
25+
cmd << " #{meta_flags.join(' ')}" if meta_flags
2526
cmd << ' k q s' if quiet # Return the key in the response if quiet
2627
cmd + TERMINATOR
2728
end

lib/dalli/protocol/meta/response_processor.rb

+29
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,23 @@ def meta_get_with_value_and_cas
4545
[@value_marshaller.retrieve(read_data(tokens[1].to_i), bitflags_from_tokens(tokens)), cas]
4646
end
4747

48+
def meta_get_with_value_and_meta_flags(cache_nils: false)
49+
tokens = error_on_unexpected!([VA, EN, HD])
50+
return [(cache_nils ? ::Dalli::NOT_FOUND : nil), {}] if tokens.first == EN
51+
52+
meta_flags = {
53+
c: cas_from_tokens(tokens),
54+
h: hit_from_tokens(tokens),
55+
l: last_accessed_from_tokens(tokens),
56+
t: ttl_remaining_from_tokens(tokens),
57+
}
58+
return [(cache_nils ? ::Dalli::NOT_FOUND : nil), meta_flags] unless tokens.first == VA
59+
60+
value, bitflag = @value_marshaller.retrieve(read_data(tokens[1].to_i), bitflags_from_tokens(tokens))
61+
meta_flags[:bitflag] = bitflag
62+
[value, meta_flags]
63+
end
64+
4865
def meta_get_without_value
4966
tokens = error_on_unexpected!([EN, HD])
5067
tokens.first == EN ? nil : true
@@ -180,6 +197,18 @@ def cas_from_tokens(tokens)
180197
value_from_tokens(tokens, 'c')&.to_i
181198
end
182199

200+
def hit_from_tokens(tokens)
201+
value_from_tokens(tokens, 'h')&.to_i != 0
202+
end
203+
204+
def last_accessed_from_tokens(tokens)
205+
value_from_tokens(tokens, 'l')&.to_i
206+
end
207+
208+
def ttl_remaining_from_tokens(tokens)
209+
value_from_tokens(tokens, 't')&.to_i
210+
end
211+
183212
def key_from_tokens(tokens)
184213
encoded_key = value_from_tokens(tokens, 'k')
185214
base64_encoded = tokens.any?('b')

test/integration/test_operations.rb

+21
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,27 @@
3838
end
3939
end
4040

41+
it 'return the value and the meta flags' do
42+
memcached_persistent(p) do |dc|
43+
skip 'not supported' if p == :binary
44+
dc.flush
45+
46+
val1 = "meta"
47+
dc.set('meta_key', val1)
48+
response = dc.get('meta_key', meta_flags: [:l, :h, :t])
49+
# ensure hit true and last accessed 0
50+
response = dc.get('meta_key', meta_flags: [:l, :h, :t])
51+
val2 = response.first
52+
meta_flags = response.last
53+
54+
assert_equal val1, val2
55+
assert_equal meta_flags, {c: 0, l: 0, h: true, t: -1, bitflag: nil}
56+
57+
assert op_addset_succeeds(dc.set('a', nil))
58+
assert_nil dc.get('a')
59+
end
60+
end
61+
4162
it 'returns nil on a miss' do
4263
memcached_persistent(p) do |dc|
4364
assert_nil dc.get('notexist')

0 commit comments

Comments
 (0)