Skip to content

Expire exists cache when repository is created from bundle

Nikola Milojevic requested to merge 199745-fix-caching-repository-exist into master

Problem

As mentioned in #199745 (closed) while running import with XL data set in import.rake task with RequestStore enabled, I encountered an error:

"undefined method 'lines' for nil:NilClass"

Investigation

Investigation showed that in /app/models/repository.rb we are using exists? method with cache_method_asymmetrically

# /app/models/repository.rb#L533
def exists?
    return false unless full_path

    raw_repository.exists?
  end
  cache_method_asymmetrically :exists?

Note: We are clearing this cache in after_create callback once repository is created.

But during import, repo_restorer creates repository from bundle instead:

  # lib/gitlab/import_export/repo_restorer.rb
  def restore
        return true unless File.exist?(path_to_bundle)

        repository.create_from_bundle(path_to_bundle)
        ...

https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/import_export/repo_restorer.rb#L17

Since create_from_bundle method doesn't exist inside app/models/repository.rb, method missing is triggered, which directly calls repository_service.create_from_bundle

 # app/models/repository.rb#L491
 def method_missing(msg, *args, &block)
      ...
      raw_repository.__send__(msg, *args, &block) # rubocop:disable GitlabSecurity/PublicSend
    end
  end

This call doesn't trigger after_create callback, and doesn't clear expire_exists_cache.

Conclusion

In case when RequestStore is enabled, repository.exists? method will always return false, and actual blob for diff file will never be retrieved from the repository.

This will cause unfolding diff lines to crash.

Fix

We should clear the cache by running expire_exists_cache, once repository is created from bundle

Conformity

Closes #199745 (closed)

Edited by 🤖 GitLab Bot 🤖

Merge request reports