class Bookie::Sender

An object that sends data to the database

Attributes

config[R]

Public Class Methods

new(config) click to toggle source

Creates a new Sender

config should be an instance of Bookie::Config.

# File lib/bookie/sender.rb, line 15
def initialize(config)
  @config = config
  sys_type = config.system_type
  require "bookie/senders/#{sys_type}"
  extend Bookie::Senders.const_get(sys_type.camelize)
end

Public Instance Methods

duplicate(job, system) click to toggle source

Finds the first job that is a duplicate of the provided job

# File lib/bookie/sender.rb, line 127
def duplicate(job, system)
  system.jobs.where({
      :start_time => job.start_time,
      :wall_time => job.wall_time,
      :command_name => job.command_name,
      :cpu_time => job.cpu_time,
      :memory => job.memory,
      :exit_code => job.exit_code
    }).by_user_name(job.user_name).by_group_name(job.group_name).first
end
filtered?(job) click to toggle source

Returns whether a job should be filtered from the results

# File lib/bookie/sender.rb, line 121
def filtered?(job)
  @config.excluded_users.include?job.user_name
end
send_data(filename) click to toggle source

Sends job data from the given file to the database server

# File lib/bookie/sender.rb, line 24
def send_data(filename)
  raise IOError.new("File '#{filename}' does not exist.") unless File.exists?(filename)

  system = nil
  
  known_users = {}
  known_groups = {}
  
  time_min, time_max = nil
  
  #Grab data from the first job:
  each_job(filename) do |job|
    next if filtered?(job)
    system = Bookie::Database::System.find_current(self, job.end_time)
    raise "Jobs already exist in the database for '#{filename}'." if duplicate(job, system)
    time_min = job.start_time
    time_max = job.end_time
    break
  end
  
  #If there are no jobs, return.
  return unless time_min
  
  #Send the job data:
  each_job(filename) do |job|
    next if filtered?(job)
    model = job.to_record
    time_min = (model.start_time < time_min) ? model.start_time : time_min
    time_max = (model.end_time > time_max) ? model.end_time : time_max
    #To consider: handle files that don't have jobs sorted by end time?
    #To consider: this should rarely happen in real life. Remove test?
    #(This situation can only arise if log files from different versions of the system are concatenated before sending.)
    if system.end_time && model.end_time > system.end_time
      system = Database::System.find_current(self, model.end_time)
    end
    user = Bookie::Database::User.find_or_create!(
      job.user_name,
      Bookie::Database::Group.find_or_create!(job.group_name, known_groups),
      known_users
    )
    model.system = system
    model.user = user
    model.save!
  end
  
  #Clear out the summaries that would have been affected by the new data:
  clear_summaries(time_min.to_date, time_max.to_date)
end
system_type() click to toggle source

The name of the Bookie::Database::SystemType that systems using this sender will have

# File lib/bookie/sender.rb, line 114
def system_type
  @system_type ||= Bookie::Database::SystemType.find_or_create!(system_type_name, memory_stat_type)
end
undo_send(filename) click to toggle source

Undoes a previous send operation

# File lib/bookie/sender.rb, line 75
def undo_send(filename)
  raise IOError.new("File '#{filename}' does not exist.") unless File.exists?(filename)
  
  system = nil
  
  time_min, time_max = nil
  
  #Grab data from the first job:
  each_job(filename) do |job|
    next if filtered?(job)
    system = Bookie::Database::System.find_current(self, job.end_time)
    time_min = job.start_time
    time_max = job.end_time
    break
  end
  
  return unless time_min
  
  each_job(filename) do |job|
    next if filtered?(job)
    if system.end_time && job.end_time > system.end_time
      system = Database::System.find_current(self, job.end_time)
    end
    #TODO: optimize this operation?
    #(It should be possible to delete all of the jobs with end times between those of the first and last jobs of the file (exclusive),
    #but jobs with end times matching those of the first/last jobs in the file might be from an earlier or later file, not this one.
    #This assumes that the files all have jobs sorted by end time.
    model = duplicate(job, system)
    break unless model
    time_min = [model.start_time, time_min].min
    time_max = [model.end_time, time_max].max
    model.delete
  end
  
  clear_summaries(time_min.to_date, time_max.to_date)
end

Private Instance Methods

clear_summaries(date_min, date_max) click to toggle source

Used internally by send_data and undo_send

# File lib/bookie/sender.rb, line 139
def clear_summaries(date_min, date_max)
  #Since joins don't mix with DELETE statements, we have to do this the hard way.
  #To consider: prune systems by time?
  system_ids = Database::System.by_name(@config.hostname).pluck(:id)
  Database::JobSummary.where('job_summaries.system_id in (?)', system_ids).where('date >= ? AND date <= ?', date_min, date_max).delete_all
end