diff options
author | Martin Emde <[email protected]> | 2023-12-14 12:42:15 -0800 |
---|---|---|
committer | git <[email protected]> | 2023-12-15 19:36:24 +0000 |
commit | d9b39093e2bac70f121e38f4354a6a58c1b245a3 (patch) | |
tree | 7d26c699971b812effc0d364eac6133810e3be0f /lib | |
parent | 1cfe874ef83cdb7776ecf892c470af634532501c (diff) |
[rubygems/rubygems] Use a mutex around Checksum::Store @store access
Not wrapping to_lock since access to it is single threaded and
read-only at the time of writing the lockfile.
https://github.com/rubygems/rubygems/commit/3b53aa1b12
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bundler/checksum.rb | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb index 742df42a74..25e3ca127d 100644 --- a/lib/bundler/checksum.rb +++ b/lib/bundler/checksum.rb @@ -63,6 +63,10 @@ module Bundler alias_method :eql?, :== + def same_source?(other) + sources.include?(other.sources.first) + end + def match?(other) other.is_a?(self.class) && other.digest == digest && other.algo == algo end @@ -161,6 +165,7 @@ module Bundler def initialize @store = {} + @store_mutex = Mutex.new end def inspect @@ -168,8 +173,9 @@ module Bundler end # Replace when the new checksum is from the same source. - # The primary purpose of this registering checksums from gems where there are + # The primary purpose is registering checksums from gems where there are # duplicates of the same gem (according to full_name) in the index. + # # In particular, this is when 2 gems have two similar platforms, e.g. # "darwin20" and "darwin-20", both of which resolve to darwin-20. # In the Index, the later gem replaces the former, so we do that here. @@ -179,16 +185,14 @@ module Bundler # that contain the same gem with different checksums. def replace(spec, checksum) return unless checksum - lock_name = spec.name_tuple.lock_name - checksums = (store[lock_name] ||= {}) - existing = checksums[checksum.algo] - - # we assume only one source because this is used while building the index - if !existing || existing.sources.first == checksum.sources.first - checksums[checksum.algo] = checksum - else - register_checksum(lock_name, checksum) + @store_mutex.synchronize do + existing = fetch_checksum(lock_name, checksum.algo) + if !existing || existing.same_source?(checksum) + store_checksum(lock_name, checksum) + else + merge_checksum(lock_name, checksum, existing) + end end end @@ -207,7 +211,8 @@ module Bundler def to_lock(spec) lock_name = spec.name_tuple.lock_name - if checksums = store[lock_name] + checksums = @store[lock_name] + if checksums "#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}" else lock_name @@ -217,18 +222,27 @@ module Bundler private def register_checksum(lock_name, checksum) - return unless checksum - checksums = (store[lock_name] ||= {}) - existing = checksums[checksum.algo] - - if !existing - checksums[checksum.algo] = checksum - elsif existing.merge!(checksum) - checksum - else - raise ChecksumMismatchError.new(lock_name, existing, checksum) + @store_mutex.synchronize do + existing = fetch_checksum(lock_name, checksum.algo) + if existing + merge_checksum(lock_name, checksum, existing) + else + store_checksum(lock_name, checksum) + end end end + + def merge_checksum(lock_name, checksum, existing) + existing.merge!(checksum) || raise(ChecksumMismatchError.new(lock_name, existing, checksum)) + end + + def store_checksum(lock_name, checksum) + (@store[lock_name] ||= {})[checksum.algo] = checksum + end + + def fetch_checksum(lock_name, algo) + @store[lock_name]&.fetch(algo, nil) + end end end end |