Skip to content

Commit

Permalink
Refactor serialization_modification_detection to increase performance
Browse files Browse the repository at this point in the history
The previous handling was correct, but not performant, as it did
a serialize/deserialize pair both for new objects and after saving.
Change the code to just clear the original values after saving
(which fixes saved objects), and just serialize early for new
objects (which fixes new objects).

To make this either, add a private serialize_deserialized_values
instance method to the serialization plugin, so that the modification
detection plugin can use it.

While here, update the RDoc for the modification detection plugin.
  • Loading branch information
jeremyevans committed Feb 1, 2012
1 parent e16f1d3 commit 1cce888
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 17 deletions.
9 changes: 7 additions & 2 deletions lib/sequel/plugins/serialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ def initialize_set(values)
super
end

# Serialize all deserialized values
# Serialize deserialized values before saving
def before_save
deserialized_values.each{|k,v| @values[k] = serialize_value(k, v)}
serialize_deserialized_values
super
end

Expand All @@ -194,6 +194,11 @@ def deserialize_value(column, v)
end
end

# Serialize all deserialized values
def serialize_deserialized_values
deserialized_values.each{|k,v| @values[k] = serialize_value(k, v)}
end

# Serialize the column value. Called before saving to ensure the serialized value
# is saved in the database.
def serialize_value(column, v)
Expand Down
30 changes: 15 additions & 15 deletions lib/sequel/plugins/serialization_modification_detection.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
module Sequel
module Plugins
# Sequel's built in Serialization plugin doesn't check for modification
# of the serialized objects, because it requires an extra deserialization of a potentially
# very large object. This plugin can detect changes in serialized values by
# checking whether the current deserialized value is the same as the original
# deserialized value. This does require deserializing the value twice, but the
# original deserialized value is cached.
# This plugin extends the serialization plugin and enables it to detect
# changes in serialized values by checking whether the current
# deserialized value is the same as the original deserialized value.
# The serialization plugin does not do such checks by default, as they
# often aren't needed and can hurt performance.
#
# Note that for this plugin to work correctly, the values you are
# serializing must roundtrip correctly (i.e. deserialize(serialize(value))
# should equal value). This is true in most cases, but not in all. For
# example, ruby symbols round trip through yaml, but not json (as they get
# turned into strings in json).
#
# == Example
#
Expand All @@ -29,7 +34,7 @@ module InstanceMethods
# show the column is modified after saving.
def after_save
super
copy_deserialized_values
@original_deserialized_values = {}
end

# Detect which serialized columns have changed.
Expand All @@ -41,16 +46,11 @@ def changed_columns

private

# For new objects, populate the original deserialized value so that we know it hasn't
# changed since initialization.
# For new objects, serialize any existing deserialized values so that changes can
# be detected.
def initialize_set(values)
super
copy_deserialized_values
end

def copy_deserialized_values
@original_deserialized_values = h = {}
@deserialized_values.each{|k, v| h[k] = deserialize_value(k, serialize_value(k, v))}
serialize_deserialized_values
end

# Return the original deserialized value of the column, caching it to improve performance.
Expand Down

0 comments on commit 1cce888

Please sign in to comment.