class Berkshelf::API::CacheManager

Constants

SAVE_INTERVAL

Attributes

cache[R]

@return [DependencyCache]

Public Class Methods

cache_file() click to toggle source

@return [String]

# File lib/berkshelf/api/cache_manager.rb, line 5
def cache_file
  File.join(Application.home_path, "cerch")
end
new() click to toggle source
# File lib/berkshelf/api/cache_manager.rb, line 25
def initialize
  log.info "#{self} starting..."
  @cache = DependencyCache.new
  load_save if File.exist?(self.class.cache_file)
  every(SAVE_INTERVAL) { save }
end

Public Instance Methods

add(cookbook, metadata) click to toggle source

@param [RemoteCookbook] cookbook @param [Ridley::Chef::Cookbook::Metadata] metadata

@return [Hash]

# File lib/berkshelf/api/cache_manager.rb, line 36
def add(cookbook, metadata)
  log.debug "#{self} adding (#{cookbook.name}, #{cookbook.version})"
  cache.add(cookbook, metadata)
end
has_cookbook?(name, version) click to toggle source

Check if the cache knows about the given cookbook version

@param [#to_s] name @param [#to_s] version

@return [Boolean]

# File lib/berkshelf/api/cache_manager.rb, line 117
def has_cookbook?(name, version)
  @cache.has_cookbook?(name, version)
end
load_save() click to toggle source
# File lib/berkshelf/api/cache_manager.rb, line 121
def load_save
  log.info "Loading save from #{self.class.cache_file}"
  @cache = DependencyCache.from_file(self.class.cache_file)
  log.info "Cache contains #{@cache.cookbooks.size} items"
end
process_worker(worker) click to toggle source

@param [CacheBuilder::Worker::Base] worker

# File lib/berkshelf/api/cache_manager.rb, line 81
def process_worker(worker)
  log.info "Processing #{worker}"
  remote_cookbooks = worker.cookbooks
  log.info "Found #{remote_cookbooks.size} cookbooks from #{worker}"
  created_cookbooks, deleted_cookbooks = diff(remote_cookbooks, worker.priority)
  log.debug "#{created_cookbooks.size} cookbooks to be added to the cache from #{worker}"
  log.debug "#{deleted_cookbooks.size} cookbooks to be removed from the cache from #{worker}"

  # Process metadata in chunks - Ridley cookbook resource uses a
  # task_class TaskThread, which means each future gets its own
  # thread. If we have many (>2000) cookbooks we can easily
  # exhaust the available threads on the system.
  created_cookbooks_with_metadata = []
  until created_cookbooks.empty?
    work = created_cookbooks.slice!(0,500)
    log.info "Processing metadata for #{work.size} cookbooks with #{created_cookbooks.size} remaining on #{worker}"
    work.map! do |remote|
      [ remote, worker.future(:metadata, remote) ]
    end.map! do |remote, metadata|
      metadata.value ? [remote, metadata.value] : nil
    end

    created_cookbooks_with_metadata += work.compact
  end

  log.info "About to merge cookbooks"
  merge(created_cookbooks_with_metadata, deleted_cookbooks)
  log.info "#{self} cache updated."
end
process_workers(workers) click to toggle source

Loops through a list of workers and merges their cookbook sets into the cache

@param [Array<CacheBuilder::Worker::Base>] workers

The workers for this cache

@return [Boolean]

# File lib/berkshelf/api/cache_manager.rb, line 58
def process_workers(workers)
  # If the cache has been warmed already, we want to spawn
  # workers for all the endpoints concurrently. However, if the
  # cache is cold we want to run sequentially, so higher priority
  # endpoints can work before lower priority, avoiding duplicate
  # downloads.
  # We don't want crashing workers to crash the CacheManager.
  # Crashes are logged so just ignore the exceptions
  if warmed?
    Array(workers).flatten.collect do |worker|
      self.future(:process_worker, worker)
    end.each do |f|
      f.value rescue nil
    end
  else
    Array(workers).flatten.each do |worker|
      process_worker(worker) rescue nil
    end
  end
  self.set_warmed
end
remove(name, version) click to toggle source

Remove the cached item matching the given name and version

@param [#to_s] name @param [#to_s] version

@return [DependencyCache]

# File lib/berkshelf/api/cache_manager.rb, line 47
def remove(name, version)
  log.debug "#{self} removing (#{name}, #{version})"
  cache.remove(name, version)
end
to_s() click to toggle source

@return [String]

# File lib/berkshelf/api/cache_manager.rb, line 128
def to_s
  "Cache manager"
end

Private Instance Methods

diff(cookbooks, worker_priority) click to toggle source

@param [Array<RemoteCookbook>] cookbooks

An array of RemoteCookbooks representing all the cookbooks on the indexed site

@param [Integer] worker_priority

The priority/ID of the endpoint that is running

@return [Array(Array<RemoteCookbook>, Array<RemoteCookbook>)]

A tuple of Arrays of RemoteCookbooks
The first array contains items not in the cache
The second array contains items in the cache, but not in the cookbooks parameter
# File lib/berkshelf/api/cache_manager.rb, line 164
def diff(cookbooks, worker_priority)
  known_cookbooks   = cache.cookbooks.select { |c| c.priority <= worker_priority }
  created_cookbooks = cookbooks - known_cookbooks
  deleted_cookbooks = (known_cookbooks - cookbooks).select { |c| c.priority == worker_priority }
  [ created_cookbooks, deleted_cookbooks ]
end
finalize_callback() click to toggle source
# File lib/berkshelf/api/cache_manager.rb, line 171
def finalize_callback
  log.info "Cache Manager shutting down..."
  save
end
merge(created_cookbooks, deleted_cookbooks) click to toggle source
# File lib/berkshelf/api/cache_manager.rb, line 134
def merge(created_cookbooks, deleted_cookbooks)
  log.info "#{self} adding (#{created_cookbooks.length}) items..."
  created_cookbooks.each do |remote_with_metadata|
    remote, metadata = remote_with_metadata
    add(remote, metadata)
  end

  log.info "#{self} removing (#{deleted_cookbooks.length}) items..."
  deleted_cookbooks.each { |remote| remove(remote.name, remote.version) }

  log.info "#{self} cache updated."
  save
end
save() click to toggle source
# File lib/berkshelf/api/cache_manager.rb, line 148
def save
  if warmed?
    log.info "Saving the cache to: #{self.class.cache_file}"
    cache.save(self.class.cache_file)
    log.info "Cache saved!"
  end
end