Class: Dalli::Protocol::ValueSerializer

Inherits:
Object
  • Object
show all
Defined in:
lib/dalli/protocol/value_serializer.rb

Overview

Dalli::Protocol::ValueSerializer compartmentalizes the logic for managing serialization and deserialization of stored values. It manages interpreting relevant options from both client and request, determining whether to serialize/deserialize on store/retrieve, and processes bitflags as necessary.

Constant Summary collapse

DEFAULTS =
{
  serializer: Marshal
}.freeze
OPTIONS =
DEFAULTS.keys.freeze
FLAG_SERIALIZED =

www.hjp.at/zettel/m/memcached_flags.rxml Looks like most clients use bit 0 to indicate native language serialization

0x1
TYPE_ERR_REGEXP =

TODO: Some of these error messages need to be validated. It’s not obvious that all of them are actually generated by the invoked code in current systems rubocop:disable Layout/LineLength

%r{needs to have method `_load'|exception class/object expected|instance of IO needed|incompatible marshal file format}.freeze
ARGUMENT_ERR_REGEXP =
/undefined class|marshal data too short/.freeze
NAME_ERR_STR =
'uninitialized constant'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(protocol_options) ⇒ ValueSerializer

Returns a new instance of ValueSerializer.



24
25
26
27
# File 'lib/dalli/protocol/value_serializer.rb', line 24

def initialize(protocol_options)
  @serialization_options =
    DEFAULTS.merge(protocol_options.select { |k, _| OPTIONS.include?(k) })
end

Instance Attribute Details

#serialization_optionsObject

Returns the value of attribute serialization_options.



22
23
24
# File 'lib/dalli/protocol/value_serializer.rb', line 22

def serialization_options
  @serialization_options
end

Instance Method Details

#filter_argument_error(err) ⇒ Object

Raises:



62
63
64
65
66
# File 'lib/dalli/protocol/value_serializer.rb', line 62

def filter_argument_error(err)
  raise err unless ARGUMENT_ERR_REGEXP.match?(err.message)

  raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

#filter_name_error(err) ⇒ Object

Raises:



68
69
70
71
72
# File 'lib/dalli/protocol/value_serializer.rb', line 68

def filter_name_error(err)
  raise err unless err.message.include?(NAME_ERR_STR)

  raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

#filter_type_error(err) ⇒ Object

Raises:



56
57
58
59
60
# File 'lib/dalli/protocol/value_serializer.rb', line 56

def filter_type_error(err)
  raise err unless TYPE_ERR_REGEXP.match?(err.message)

  raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

#retrieve(value, bitflags) ⇒ Object

rubocop:enable Layout/LineLength



45
46
47
48
49
50
51
52
53
54
# File 'lib/dalli/protocol/value_serializer.rb', line 45

def retrieve(value, bitflags)
  serialized = (bitflags & FLAG_SERIALIZED) != 0
  serialized ? serializer.load(value) : value
rescue TypeError => e
  filter_type_error(e)
rescue ArgumentError => e
  filter_argument_error(e)
rescue NameError => e
  filter_name_error(e)
end

#serialize_value(value) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/dalli/protocol/value_serializer.rb', line 78

def serialize_value(value)
  serializer.dump(value)
rescue Timeout::Error => e
  raise e
rescue StandardError => e
  # Serializing can throw several different types of generic Ruby exceptions.
  # Convert to a specific exception so we can special case it higher up the stack.
  exc = Dalli::MarshalError.new(e.message)
  exc.set_backtrace e.backtrace
  raise exc
end

#serializerObject



74
75
76
# File 'lib/dalli/protocol/value_serializer.rb', line 74

def serializer
  @serialization_options[:serializer]
end

#store(value, req_options, bitflags) ⇒ Object



29
30
31
32
33
34
# File 'lib/dalli/protocol/value_serializer.rb', line 29

def store(value, req_options, bitflags)
  do_serialize = !(req_options && req_options[:raw])
  store_value = do_serialize ? serialize_value(value) : value.to_s
  bitflags |= FLAG_SERIALIZED if do_serialize
  [store_value, bitflags]
end