class Bookie::Database::System

A system on the network

Constants

SystemConflictError

Raised when a system’s specifications are different from those of the active system in the database

Public Class Methods

active() click to toggle source

Finds all systems that are active (i.e. all systems with NULL values for end_time)

# File lib/bookie/database/system.rb, line 20
def self.active
  where('systems.end_time IS NULL')
end
by_name(name) click to toggle source

Filters by name

# File lib/bookie/database/system.rb, line 26
def self.by_name(name)
  where('systems.name = ?', name)
end
by_system_type(sys_type) click to toggle source

Filters by system type

# File lib/bookie/database/system.rb, line 32
def self.by_system_type(sys_type)
  where('systems.system_type_id = ?', sys_type.id)
end
by_time_range(time_range) click to toggle source

Finds all systems whose running intervals overlap the given time range

# File lib/bookie/database/system.rb, line 38
def self.by_time_range(time_range)
  if time_range.empty?
    self.none
  else
    time_range = time_range.exclusive
    where('(? < systems.end_time OR systems.end_time IS NULL) AND systems.start_time < ?', time_range.first, time_range.last)
  end
end
find_current(sender, time = nil) click to toggle source

Finds the current system for a given sender and time

This method also checks that this system’s specifications are the same as those in the database and raises an error if they are different.

This uses Lock#synchronize internally, so it probably should not be called within a transaction block.

# File lib/bookie/database/system.rb, line 53
      def self.find_current(sender, time = nil)
        time ||= Time.now
        config = sender.config
        system = nil
        name = config.hostname
        Lock[:systems].synchronize do
          system = by_name(config.hostname).where('systems.start_time <= :time AND (:time <= systems.end_time OR systems.end_time IS NULL)', :time => time).first
          if system
            mismatch = !(system.cores == config.cores && system.memory == config.memory)
            mismatch ||= sender.system_type != system.system_type
            if mismatch
              raise SystemConflictError.new("The specifications on record for '#{name}' do not match this system's specifications.
Please make sure that all previous systems with this hostname have been marked as decommissioned.")
            end
          else
            raise "There is no system with hostname '#{config.hostname}' that was recorded as active at #{time}."
          end
        end
        system
      end
summary(time_range = nil) click to toggle source

Produces a summary of all the systems for the given time interval

Returns a hash with the following fields:

  • :num_systems

    the number of systems that were active in the given interval

  • :avail_cpu_time

    the total CPU time available for the interval

  • :avail_memory_time

    the total amount of memory-time available (in kilobyte-seconds)

  • :avail_memory_avg

    the average amount of memory available (in kilobytes)

To consider: include the start/end times for the summary (especially if they aren’t provided as arguments)?

# File lib/bookie/database/system.rb, line 84
def self.summary(time_range = nil)
  current_time = Time.now

  num_systems = 0
  avail_cpu_time = 0
  avail_memory_time = 0

  #Find all the systems within the time range.
  systems = System
  if time_range
    time_range = time_range.exclusive.normalized
    systems = systems.by_time_range(time_range)
  end

  systems.find_each do |system|
    start_time = system.start_time
    end_time = system.end_time
    #Is there a time range constraint?
    if time_range
      #If so, trim start_time and end_time to fit within the range.
      start_time = [start_time, time_range.first].max
      if end_time
        end_time = [end_time, time_range.last].min
      else
        end_time ||= time_range.last
      end
    else
      end_time ||= current_time
    end
    wall_time = end_time.to_i - start_time.to_i

    num_systems += 1
    avail_cpu_time += system.cores * wall_time
    avail_memory_time += system.memory * wall_time
  end
  
  time_span = 0
  if time_range
    time_span = time_range.last - time_range.first
  else
    time_min = System.minimum(:start_time)
    #Is there actually a minimum start time?
    #(In other words, are there any systems in the database?)
    if time_min
      if System.active.any?
        time_max = current_time
      else
        time_max = System.maximum(:end_time)
      end
      time_span = time_max - time_min
    end
  end
    
  {
    :num_systems => num_systems,
    :avail_cpu_time => avail_cpu_time,
    :avail_memory_time => avail_memory_time,
    :avail_memory_avg => if time_span == 0 then 0.0 else Float(avail_memory_time) / time_span end,
  }
end

Public Instance Methods

decommission(end_time) click to toggle source

Decommissions the given system, setting its end time to end_time

This should be called any time a system is brought down or its specifications are changed.

# File lib/bookie/database/system.rb, line 149
def decommission(end_time)
  self.end_time = end_time
  self.save!
end