class Dalli::Protocol::Meta::ResponseProcessor
Class that encapsulates logic for processing meta protocol responses from memcached. Includes logic for pulling data from an IO source and parsing into local values. Handles errors on unexpected values.
Constants
- EN
- END_TOKEN
- EX
- HD
- MN
- NF
- NS
- OK
- RESET
- STAT
- VA
- VERSION
Public Class Methods
new(io_source, value_marshaller)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 25 def initialize(io_source, value_marshaller) @io_source = io_source @value_marshaller = value_marshaller end
Public Instance Methods
bitflags_from_tokens(tokens)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 175 def bitflags_from_tokens(tokens) value_from_tokens(tokens, 'f')&.to_i end
body_len_from_tokens(tokens)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 189 def body_len_from_tokens(tokens) value_from_tokens(tokens, 's')&.to_i end
cas_from_tokens(tokens)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 179 def cas_from_tokens(tokens) value_from_tokens(tokens, 'c')&.to_i end
consume_all_responses_until_mn()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 107 def consume_all_responses_until_mn tokens = next_line_to_tokens tokens = next_line_to_tokens while tokens.first != MN true end
contains_header?(buf)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 160 def contains_header?(buf) buf.include?(TERMINATOR) end
decr_incr()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 72 def decr_incr tokens = error_on_unexpected!([VA, NF, NS, EX]) return false if [NS, EX].include?(tokens.first) return nil if tokens.first == NF read_line.to_i end
error_on_unexpected!(expected_codes)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 168 def error_on_unexpected!(expected_codes) tokens = next_line_to_tokens raise Dalli::DalliError, "Response error: #{tokens.first}" unless expected_codes.include?(tokens.first) tokens end
flush()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 90 def flush error_on_unexpected!([OK]) true end
full_response_from_buffer(tokens, body, resp_size)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 122 def full_response_from_buffer(tokens, body, resp_size) value = @value_marshaller.retrieve(body, bitflags_from_tokens(tokens)) [resp_size, tokens.first == VA, cas_from_tokens(tokens), key_from_tokens(tokens), value] end
getk_response_from_buffer(buf)
click to toggle source
This method returns an array of values used in a pipelined getk process. The first value is the number of bytes by which to advance the pointer in the buffer. If the complete response is found in the buffer, this will be the response size. Otherwise it is zero.
The remaining three values in the array are the ResponseHeader, key, and value.
# File lib/dalli/protocol/meta/response_processor.rb, line 137 def getk_response_from_buffer(buf) # There's no header in the buffer, so don't advance return [0, nil, nil, nil, nil] unless contains_header?(buf) tokens, header_len, body_len = tokens_from_header_buffer(buf) # We have a complete response that has no body. # This is either the response to the terminating # noop or, if the status is not MN, an intermediate # error response that needs to be discarded. return [header_len, true, nil, nil, nil] if body_len.zero? resp_size = header_len + body_len + TERMINATOR.length # The header is in the buffer, but the body is not. As we don't have # a complete response, don't advance the buffer return [0, nil, nil, nil, nil] unless buf.bytesize >= resp_size # The full response is in our buffer, so parse it and return # the values body = buf.slice(header_len, body_len) full_response_from_buffer(tokens, body, resp_size) end
header_from_buffer(buf)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 164 def header_from_buffer(buf) buf.split(TERMINATOR, 2).first end
key_from_tokens(tokens)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 183 def key_from_tokens(tokens) encoded_key = value_from_tokens(tokens, 'k') base64_encoded = tokens.any?('b') KeyRegularizer.decode(encoded_key, base64_encoded) end
meta_delete()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 67 def meta_delete tokens = error_on_unexpected!([HD, NF, EX]) tokens.first == HD end
meta_get_with_value(cache_nils: false)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 30 def meta_get_with_value(cache_nils: false) tokens = error_on_unexpected!([VA, EN, HD]) return cache_nils ? ::Dalli::NOT_FOUND : nil if tokens.first == EN return true unless tokens.first == VA @value_marshaller.retrieve(read_line, bitflags_from_tokens(tokens)) end
meta_get_with_value_and_cas()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 38 def meta_get_with_value_and_cas tokens = error_on_unexpected!([VA, EN, HD]) return [nil, 0] if tokens.first == EN cas = cas_from_tokens(tokens) return [nil, cas] unless tokens.first == VA [@value_marshaller.retrieve(read_line, bitflags_from_tokens(tokens)), cas] end
meta_get_without_value()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 48 def meta_get_without_value tokens = error_on_unexpected!([EN, HD]) tokens.first == EN ? nil : true end
meta_set_append_prepend()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 60 def meta_set_append_prepend tokens = error_on_unexpected!([HD, NS, NF, EX]) return false unless tokens.first == HD true end
meta_set_with_cas()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 53 def meta_set_with_cas tokens = error_on_unexpected!([HD, NS, NF, EX]) return false unless tokens.first == HD cas_from_tokens(tokens) end
next_line_to_tokens()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 204 def next_line_to_tokens line = read_line line&.split || [] end
read_line()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 200 def read_line @io_source.read_line&.chomp!(TERMINATOR) end
reset()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 96 def reset error_on_unexpected!([RESET]) true end
stats()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 80 def stats tokens = error_on_unexpected!([END_TOKEN, STAT]) values = {} while tokens.first != END_TOKEN values[tokens[1]] = tokens[2] tokens = next_line_to_tokens end values end
tokens_from_header_buffer(buf)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 114 def tokens_from_header_buffer(buf) header = header_from_buffer(buf) tokens = header.split header_len = header.bytesize + TERMINATOR.length body_len = body_len_from_tokens(tokens) [tokens, header_len, body_len] end
value_from_tokens(tokens, flag)
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 193 def value_from_tokens(tokens, flag) bitflags_token = tokens.find { |t| t.start_with?(flag) } return 0 unless bitflags_token bitflags_token[1..-1] end
version()
click to toggle source
# File lib/dalli/protocol/meta/response_processor.rb, line 102 def version tokens = error_on_unexpected!([VERSION]) tokens.last end