From 2cd3f7869489bf1fddc7f36749a5d8417dbc87a4 Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Wed, 2 Jul 2025 04:48:18 -0400 Subject: [PATCH 1/2] Library avoids blocking on pending yardoc caches --- lib/solargraph/doc_map.rb | 5 ++-- lib/solargraph/library.rb | 51 +++++++++++++++++++++++++++------------ lib/solargraph/yardoc.rb | 7 ++++++ 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/lib/solargraph/doc_map.rb b/lib/solargraph/doc_map.rb index b3abb5925..fd42e90b4 100644 --- a/lib/solargraph/doc_map.rb +++ b/lib/solargraph/doc_map.rb @@ -21,8 +21,9 @@ class DocMap # @return [Array] def uncached_gemspecs - (uncached_yard_gemspecs + uncached_rbs_collection_gemspecs).sort. - uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" } + uncached_yard_gemspecs.concat(uncached_rbs_collection_gemspecs) + .sort + .uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" } end # @return [Array] diff --git a/lib/solargraph/library.rb b/lib/solargraph/library.rb index 1ed991481..4cd80f2fe 100644 --- a/lib/solargraph/library.rb +++ b/lib/solargraph/library.rb @@ -588,29 +588,50 @@ def cache_errors # @return [void] def cache_next_gemspec return if @cache_progress - spec = (api_map.uncached_yard_gemspecs + api_map.uncached_rbs_collection_gemspecs). - find { |spec| !cache_errors.include?(spec) } + + spec = cacheable_specs.first return end_cache_progress unless spec pending = api_map.uncached_gemspecs.length - cache_errors.length - 1 - logger.info "Caching #{spec.name} #{spec.version}" - Thread.new do - cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s) - report_cache_progress spec.name, pending - Process.wait(cache_pid) - logger.info "Cached #{spec.name} #{spec.version}" - rescue Errno::EINVAL => _e - logger.info "Cached #{spec.name} #{spec.version} with EINVAL" - rescue StandardError => e - cache_errors.add spec - Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}" - ensure - end_cache_progress + + if Yardoc.processing?(spec) + logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)" + queued_gemspec_cache.push(spec) + return if pending < 2 + catalog sync_catalog + else + logger.info "Caching #{spec.name} #{spec.version}" + Thread.new do + cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s) + report_cache_progress spec.name, pending + Process.wait(cache_pid) + logger.info "Cached #{spec.name} #{spec.version}" + rescue Errno::EINVAL => _e + logger.info "Cached #{spec.name} #{spec.version} with EINVAL" + rescue StandardError => e + cache_errors.add spec + Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}" + ensure + end_cache_progress + catalog + sync_catalog + end end end + def cacheable_specs + api_map.uncached_yard_gemspecs + + api_map.uncached_rbs_collection_gemspecs + + queued_gemspec_cache - + cache_errors.to_a + end + + def queued_gemspec_cache + @queued_gemspec_cache ||= [] + end + # @param gem_name [String] # @param pending [Integer] # @return [void] diff --git a/lib/solargraph/yardoc.rb b/lib/solargraph/yardoc.rb index 797413230..59ce428a8 100644 --- a/lib/solargraph/yardoc.rb +++ b/lib/solargraph/yardoc.rb @@ -30,6 +30,13 @@ def cached?(gemspec) File.exist?(yardoc) end + # True if another process is currently building the yardoc cache. + # + def processing?(gemspec) + yardoc = File.join(PinCache.yardoc_path(gemspec), 'processing') + File.exist?(yardoc) + end + # Load a gem's yardoc and return its code objects. # # @note This method modifies the global YARD registry. From cdab31437159160fd6c0cc5bc1b599e7eec58398 Mon Sep 17 00:00:00 2001 From: Fred Snyder Date: Wed, 2 Jul 2025 05:00:21 -0400 Subject: [PATCH 2/2] Avoid syncing if all uncached gemspecs are unqueued --- lib/solargraph/library.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/solargraph/library.rb b/lib/solargraph/library.rb index 4cd80f2fe..8eadeed62 100644 --- a/lib/solargraph/library.rb +++ b/lib/solargraph/library.rb @@ -597,7 +597,7 @@ def cache_next_gemspec if Yardoc.processing?(spec) logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)" queued_gemspec_cache.push(spec) - return if pending < 2 + return if pending - queued_gemspec_cache.length < 1 catalog sync_catalog @@ -622,10 +622,13 @@ def cache_next_gemspec end def cacheable_specs - api_map.uncached_yard_gemspecs + - api_map.uncached_rbs_collection_gemspecs + - queued_gemspec_cache - - cache_errors.to_a + cacheable = api_map.uncached_yard_gemspecs + + api_map.uncached_rbs_collection_gemspecs - + queued_gemspec_cache - + cache_errors.to_a + return cacheable unless cacheable.empty? + + queued_gemspec_cache end def queued_gemspec_cache