42 lines
1.8 KiB
Diff
42 lines
1.8 KiB
Diff
# UNDF: UNDF-2026-000000253
|
||
Fixes rails-0014: ActiveJob::Arguments#transform_symbol_keys — symbol_keys.include?(key) inside Hash#transform_keys loop O(H×S) per job deserialization.
|
||
|
||
--- a/activejob/lib/active_job/arguments.rb
|
||
+++ b/activejob/lib/active_job/arguments.rb
|
||
|
||
@@ DEFECT rails-0014: lines 150-151, 178-189
|
||
|
||
def deserialize_argument(argument)
|
||
...
|
||
elsif symbol_keys = result.delete(SYMBOL_KEYS_KEY) # symbol_keys is Array<String>
|
||
result = transform_symbol_keys(result, symbol_keys)
|
||
elsif symbol_keys = result.delete(RUBY2_KEYWORDS_KEY)
|
||
result = transform_symbol_keys(result, symbol_keys)
|
||
...
|
||
end
|
||
|
||
def transform_symbol_keys(hash, symbol_keys)
|
||
hash.to_h.transform_keys do |key|
|
||
- if symbol_keys.include?(key) # O(S) Array scan per key
|
||
+ if symbol_keys_set.include?(key) # FIX: O(1) Set lookup
|
||
key.to_sym
|
||
else
|
||
key
|
||
end
|
||
end
|
||
end
|
||
|
||
+ # FIX: convert symbol_keys array to Set before the transform_keys loop
|
||
+ def transform_symbol_keys(hash, symbol_keys)
|
||
+ symbol_keys_set = symbol_keys.is_a?(Set) ? symbol_keys : symbol_keys.to_set
|
||
+ hash.to_h.transform_keys do |key|
|
||
+ symbol_keys_set.include?(key) ? key.to_sym : key
|
||
+ end
|
||
+ end
|
||
|
||
# BEFORE: symbol_keys is an Array<String>; include? is O(S) per key
|
||
# hash has H keys → O(H×S) per deserialization call
|
||
# AFTER: convert to Set before loop: O(1) per key → O(H) per deserialization
|
||
# Severity: MEDIUM — hot path for every ActiveJob with keyword-argument hashes
|
||
# Speedup: ~S× where S = number of symbol keys in the job arguments
|
||
# At H=100 hash keys, S=30 symbol keys: 3,000 → 100 ops per deserialize
|