Skip to content

Commit

Permalink
Optimize for exact-match target name lookups
Browse files Browse the repository at this point in the history
Performing wildcard target name resolution is fairly costly,
having to search through all group names, target names, and
target aliases, calling File.fnmatch on each one in order to
find matches.

In the case of the targets being non-wildcard strings much
faster exact matching can be performed resulting in a
significant performance improvement.

!feature

* **Optimize get_targets performance for exact-match cases**

  Attempt exact target name matches for strings passed to
  get_targets and only attempt the slower wildcard match if
  the string contains a valid glob wildcard character.
  • Loading branch information
seanmil committed Apr 3, 2024
1 parent 9c9646e commit 627c000
Showing 1 changed file with 17 additions and 8 deletions.
25 changes: 17 additions & 8 deletions lib/bolt/inventory/inventory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class Inventory
EXTENDED_TARGET_REGEX = /[[:space:],]+(?=[^\]}]*(?:[\[{]|$))/.freeze
TARGET_REGEX = /[[:space:],]+/.freeze

# Pattern which looks for indicators that glob-based target name matching
# should be used.
GLOB_MATCH_REGEX = /[*?\[\]{}]/.freeze

class WildcardError < Bolt::Error
def initialize(target)
super("Found 0 targets matching wildcard pattern #{target}", 'bolt.inventory/wildcard-error')
Expand Down Expand Up @@ -125,12 +129,18 @@ def match_wildcard?(wildcard, target_name, ext_glob: false)

# If target is a group name, expand it to the members of that group.
# Else match against groups and targets in inventory by name or alias.
# If a wildcard string, error if no matches are found.
# Attempt exact matches for groups, targets, and aliases first for speed.
# If no exact match and the string contains wildcard characters, then try
# for a wildcard match and error if no matches are found.
# Else fall back to [target] if no matches are found.
def resolve_name(target, ext_glob: false)
if (group = group_lookup[target])
group.all_targets.to_a
else
elsif @targets.key?(target)
[target]
elsif (real_target = groups.target_aliases[target])
[real_target]
elsif GLOB_MATCH_REGEX.match?(target)
targets = []

# Find groups that match the glob
Expand All @@ -147,12 +157,11 @@ def resolve_name(target, ext_glob: false)
.select { |tgt_alias, _| match_wildcard?(target, tgt_alias, ext_glob: ext_glob) }
.values

if targets.empty?
raise(WildcardError, target) if target.include?('*')
[target]
else
targets.uniq
end
raise(WildcardError, target) if targets.empty?

targets.uniq
else # rubocop:disable Lint/DuplicateBranch
[target]
end
end
private :resolve_name
Expand Down

0 comments on commit 627c000

Please sign in to comment.