diff options
author | Sean Griffin <sean@seantheprogrammer.com> | 2018-11-27 18:51:20 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-27 18:51:20 -0700 |
commit | 9c4d3c341c0f09ea26a7f97a4a0af28f4e998d08 (patch) | |
tree | 06863c2ac038678e33d22bdab604f987f34f5bc4 /activerecord/lib/active_record/integration.rb | |
parent | 129788d6ec68e9e0c14e4048a63688a91b0ee45d (diff) | |
parent | 73f9cd2da452c97061a7b01d3d8e9f480950fe80 (diff) | |
download | rails-9c4d3c341c0f09ea26a7f97a4a0af28f4e998d08.tar.gz rails-9c4d3c341c0f09ea26a7f97a4a0af28f4e998d08.tar.bz2 rails-9c4d3c341c0f09ea26a7f97a4a0af28f4e998d08.zip |
Merge pull request #33835 from schneems/schneems/faster_cache_version
Use raw time string from DB to generate ActiveRecord#cache_version
Diffstat (limited to 'activerecord/lib/active_record/integration.rb')
-rw-r--r-- | activerecord/lib/active_record/integration.rb | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb index 33c4066b89..ec39ece87f 100644 --- a/activerecord/lib/active_record/integration.rb +++ b/activerecord/lib/active_record/integration.rb @@ -96,8 +96,19 @@ module ActiveRecord # Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to # +false+ (which it is by default until Rails 6.0). def cache_version - if cache_versioning && timestamp = try(:updated_at) - timestamp.utc.to_s(:usec) + return unless cache_versioning + + if has_attribute?("updated_at") + timestamp = updated_at_before_type_cast + if can_use_fast_cache_version?(timestamp) + raw_timestamp_to_cache_version(timestamp) + elsif timestamp = updated_at + timestamp.utc.to_s(cache_timestamp_format) + end + else + if self.class.has_attribute?("updated_at") + raise ActiveModel::MissingAttributeError, "missing attribute: updated_at" + end end end @@ -151,5 +162,42 @@ module ActiveRecord end end end + + private + # Detects if the value before type cast + # can be used to generate a cache_version. + # + # The fast cache version only works with a + # string value directly from the database. + # + # We also must check if the timestamp format has been changed + # or if the timezone is not set to UTC then + # we cannot apply our transformations correctly. + def can_use_fast_cache_version?(timestamp) + timestamp.is_a?(String) && + cache_timestamp_format == :usec && + default_timezone == :utc && + !updated_at_came_from_user? + end + + # Converts a raw database string to `:usec` + # format. + # + # Example: + # + # timestamp = "2018-10-15 20:02:15.266505" + # raw_timestamp_to_cache_version(timestamp) + # # => "20181015200215266505" + # + # Postgres truncates trailing zeros, https://bit.ly/2QUlXiZ + # to account for this we pad the output with zeros + def raw_timestamp_to_cache_version(timestamp) + key = timestamp.delete("- :.") + if key.length < 20 + key.ljust(20, "0") + else + key + end + end end end |