Skip to content

Commit 4a0b2a0

Browse files
committed
Memoize key_provider from key or deterministic key_provider if any
The memoization of Scheme#key_provider was removed completely in rails#51019 because it prevented overriding the `key_provider` via `with_encryption_context`. However, this also made our tests for the HEY app about 5 times slower. We traced this down to all attributes where we either provide a key or declare them as deterministic and have to derive a key to instantiate the provider every time we load them. This might happen hundreds of times per test, and ultimately, we call ``` ActiveSupport::KeyGenerator#generate_key ``` and ``` OpenSSL::KDF.pbkdf2_hmac ``` hundreds of times. This adds significant overhead per test. In reality, what's overridden bv `with_encryption_context` is the value used as default provider, that is, `ActiveRecord::Encryption.key_provider`. This is only used in `Scheme#key_provider` if the scheme doesn't already have either a `key_provider` passed directly, or a `key`, or is `deterministic`. The `key_provider` passed directly is already memoized simply by having it stored as is. Let's memoize the other two, in order, so we save all those extra calls to derive the same keys again and again.
1 parent 3efae44 commit 4a0b2a0

File tree

1 file changed

+8
-4
lines changed
  • activerecord/lib/active_record/encryption

1 file changed

+8
-4
lines changed

activerecord/lib/active_record/encryption/scheme.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def fixed?
5050
end
5151

5252
def key_provider
53-
@key_provider_param || build_key_provider || default_key_provider
53+
@key_provider_param || key_provider_from_key || deterministic_key_provider || default_key_provider
5454
end
5555

5656
def merge(other_scheme)
@@ -80,10 +80,14 @@ def validate_config!
8080
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
8181
end
8282

83-
def build_key_provider
84-
return DerivedSecretKeyProvider.new(@key) if @key.present?
83+
def key_provider_from_key
84+
@key_provider_from_key ||= if @key.present?
85+
DerivedSecretKeyProvider.new(@key)
86+
end
87+
end
8588

86-
if @deterministic
89+
def deterministic_key_provider
90+
@deterministic_key_provider ||= if @deterministic
8791
DeterministicKeyProvider.new(ActiveRecord::Encryption.config.deterministic_key)
8892
end
8993
end

0 commit comments

Comments
 (0)