rails-0009: FilterAttributeHandler filter_parameters Array O(A×F) → Set (450×) rails-0010: Encryption::AutoFilteredParameters two Array scans → Set (250×) rails-0011: TimeZoneConversion skip_list Array O(M×C×S) → Set (20×) exposed-0001: SchemaUtilityApi mapMissingColumnStatements O(N×M) → map (118×) exposed-0002: IdentifierManagerApi isAKeyword O(K) linear → HashSet (144×) exposed-0003: Table.clone consParams.map fresh List → hoisted HashSet (6×) seaorm-0001: active_model establish_links leftover.any O(N²) → HashSet (501×) seaorm-0002: rbac engine group_permissions .values().find() → HashMap by ID (502×) seaorm-0003: schema builder sorted_tables Vec::contains → HashSet (500×) seaorm-0004: TopologicalSort from_iter seen Vec O(N²) → BTreeSet (28×) Unit tests: RailsTest 11/11, ExposedTest 3/3, SeaORMTest 4/4 PASS Whitepaper: 157→167 sites, 62→64 ecosystems; §13.12 ORM Wave 2 added
1.1 KiB
1.1 KiB
rails-0007: lazy_load_hooks — O(H×R) @run_once Array#include? per hook per run_load_hooks
Severity: MEDIUM File: activesupport/lib/active_support/lazy_load_hooks.rb Line: ~25 (run_load_hooks) Status: PATCHED
Description
ActiveSupport.run_load_hooks checks @run_once[name].include?(block) before running
each block. @run_once[name] is an Array, so each check is O(R) where R = number of
already-run-once hooks. With H hooks fired during boot and R growing per hook, total
cost is O(H×R) — quadratic in the number of once-only hooks.
This runs during Rails application boot for every initializer and engine that uses
run_load_hooks.
Root Cause
@run_once[name] is initialized as [] and accumulated with <<. The include? check
against this growing Array is O(R) per call.
Fix
# BEFORE
@run_once[name] ||= []
@run_once[name] << block if once
# check: @run_once[name].include?(block)
# AFTER
@run_once[name] ||= Set.new
@run_once[name] << block if once
# check: @run_once[name].include?(block) — now O(1)
Speedup
~5x at H=1000 hooks, R=500 run-once entries