-
-
Notifications
You must be signed in to change notification settings - Fork 532
perf: Add FilenameCache to cache compute_filename results #2904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,44 +27,24 @@ class Frame < Interface | |
| attr_accessor :abs_path, :context_line, :function, :in_app, :filename, | ||
| :lineno, :module, :pre_context, :post_context, :vars | ||
|
|
||
| def initialize(project_root, line, strip_backtrace_load_path = true) | ||
| def initialize(project_root, line, strip_backtrace_load_path = true, filename_cache: nil) | ||
| @strip_backtrace_load_path = strip_backtrace_load_path | ||
| @filename_cache = filename_cache | ||
|
|
||
| @abs_path = line.file | ||
| @function = line.method if line.method | ||
| @lineno = line.number | ||
| @in_app = line.in_app | ||
| @module = line.module_name if line.module_name | ||
| @filename = compute_filename(project_root, strip_backtrace_load_path) | ||
| @filename = compute_filename | ||
| end | ||
|
|
||
| def to_s | ||
| "#{@filename}:#{@lineno}" | ||
| end | ||
|
|
||
| def compute_filename(project_root, strip_backtrace_load_path) | ||
| return if abs_path.nil? | ||
| return abs_path unless strip_backtrace_load_path | ||
|
|
||
| under_root = project_root && abs_path.start_with?(project_root) | ||
| prefix = | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Frame silently produces nil filename without cacheMedium Severity
Additional Locations (1) |
||
| if under_root && in_app | ||
| project_root | ||
| elsif under_root | ||
| longest_load_path || project_root | ||
| else | ||
| longest_load_path | ||
| end | ||
|
|
||
| if prefix | ||
| prefix_str = prefix.to_s | ||
| offset = if prefix_str.end_with?(File::SEPARATOR) | ||
| prefix_str.bytesize | ||
| else | ||
| prefix_str.bytesize + 1 | ||
| end | ||
| abs_path.byteslice(offset, abs_path.bytesize - offset) | ||
| else | ||
| abs_path | ||
| end | ||
| def compute_filename | ||
| @filename_cache&.compute_filename(abs_path, in_app, @strip_backtrace_load_path) | ||
| end | ||
|
|
||
| def set_context(linecache, context_lines) | ||
|
|
@@ -84,10 +64,6 @@ def to_h(*args) | |
| end | ||
|
|
||
| private | ||
|
|
||
| def longest_load_path | ||
| $LOAD_PATH.select { |path| abs_path.start_with?(path.to_s) }.max_by(&:size) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Sentry | ||
| class FilenameCache | ||
| def initialize(project_root) | ||
| @project_root = project_root | ||
| @load_paths = $LOAD_PATH.map(&:to_s).sort_by(&:size).reverse.freeze | ||
| @cache = {} | ||
| end | ||
|
|
||
| def compute_filename(abs_path, in_app, strip_backtrace_load_path) | ||
| return unless abs_path | ||
| return abs_path unless strip_backtrace_load_path | ||
|
|
||
| @cache.fetch(abs_path) do | ||
| under_root = @project_root && abs_path.start_with?(@project_root) | ||
| prefix = | ||
| if under_root && in_app | ||
| @project_root | ||
| elsif under_root | ||
| longest_load_path(abs_path) || @project_root | ||
| else | ||
| longest_load_path(abs_path) | ||
| end | ||
|
|
||
| @cache[abs_path] = if prefix | ||
| offset = if prefix.end_with?(File::SEPARATOR) | ||
| prefix.bytesize | ||
| else | ||
| prefix.bytesize + 1 | ||
| end | ||
| abs_path.byteslice(offset, abs_path.bytesize - offset) | ||
| else | ||
| abs_path | ||
| end | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def longest_load_path(abs_path) | ||
| @load_paths.find { |path| abs_path.start_with?(path) } | ||
| end | ||
| end | ||
| end |


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead
project_rootparameter in Frame constructorLow Severity
The
project_rootpositional parameter inFrame.initializeis accepted but never stored or referenced. All filename computation now delegates to@filename_cache, which carries its ownproject_root. This dead parameter is misleading — callers passing different values forproject_rootand the cache'sproject_rootwould get silent inconsistencies.