<commit_before>class BackupJob < ActiveRecord::Base
  belongs_to :server
  belongs_to :backup_server
  has_many :commands, :dependent => :destroy
  
  named_scope :running, :conditions => {:finished => false}, :order => 'updated_at DESC', :include => [:server, :backup_server]
  named_scope :queued, :conditions => {:status => 'queued'}, :order => 'created_at ASC', :include => [:server, :backup_server]
  named_scope :latest_problems, :conditions => "status NOT IN ('OK','running','queued')", :order => 'updated_at DESC', :limit => 20, :include => [:server, :backup_server]
  
  def fs
    self.backup_server.zpool + '/' + self.server.hostname
  end
  
  def prepare_fs
     run_command("/sbin/zfs list #{self.fs}", "fs_exists")
  end
  
  def finish
    self.finished = true
    save
  end
  
  def run
    self.status = 'running'
    self.finished = false
    save
    prepare_fs
  end
  
  def ssh_command
    "ssh -c arcfour -p #{self.server.ssh_port}"
  end
  
  def main_rsync
    "/usr/bin/pfexec rsync --stats -aHRW --timeout=600 --delete-excluded --exclude=.zfs -e '#{ssh_command}' " +
    server.rsync_protects + " " + server.rsync_includes + " " + 
    server.rsync_split_excludes + " " + server.rsync_excludes +
    " --log-file=/tmp/#{self.server}_debug root@#{self.server.connect_address}:#{self.server.startdir} /#{fs}/"
  end
  
  def rsync_template
    "/usr/bin/pfexec rsync --stats -aHRW --timeout=600 --delete-excluded --exclude=.zfs -e '#{ssh_command}' " +
    server.rsync_protects + " " + server.rsync_includes + " " + 
    server.rsync_excludes +
    " --log-file=/tmp/#{self.server}_debug root@#{self.server.connect_address}:DIR /#{fs}/"
  end
  
  def rsyncs
    if stored_rsyncs.blank? and !@last
      populate_rsyncs
    end
    self.stored_rsyncs.split('!RSYNC!')
  end
  
  def populate_rsyncs
    syncs = get_rsyncs
    self.stored_rsyncs=syncs
    save
  end
  
  def get_rsyncs
    self.server.splits.map do | split |
      arr = []
      split_dir = self.server.startdir + split.to_s
      arr.concat(('a'..'z').to_a)
      arr.concat(('A'..'Z').to_a)
      arr.concat((0..9).to_a)
      arr.map do | letter |
        rsync_template.sub('DIR', split_dir + "/#{letter}*")
      end
    end.flatten.join('!RSYNC!')
  end
  
  def code_to_success(num)
    return "OK" if [0,24].include?(num)
    return "PARTIAL"
  end
  
  def run_command(command, label)
    command += ' 2>&1'
    commands.create!(:command => command, :label => label, :user => backup_server.user)
  end
  
  def wakeup
    last = commands.last
    if last.exitstatus
      run_callback(last)
    end
  end
  
  def run_callback(command)
    args = command.label.split(/ /)
    method = args.delete_at(0)
    send('after_' + method, command, *args)
  end
  
  def after_fs_exists(command)
    if command.exitstatus == 0
      start_rsyncs
    else
      run_command("/bin/pfexec /sbin/zfs create #{self.fs}", "create_fs")
    end
  end
  
  def after_create_fs(command)
    if command.exitstatus == 0
      run_command("/sbin/zfs list #{self.fs}", "fs_exists_confirm")
    else
      self.status = 'Unable to create filesystem'
      self.finished = true
      save
    end
  end
  
  def after_fs_exists_confirm(command)
    if command.exitstatus == 0
      start_rsyncs
    else
      self.status = 'Unable to create filesystem'
      self.finished = true
      save
    end
  end
  
  def start_rsyncs
    run_command(self.main_rsync, "main_rsync")
  end
  
  def after_main_rsync(command)
    self.status = code_to_success(command.exitstatus)
    save
    run_split_rsyncs
  end
  
  def run_split_rsyncs
    if rsync = get_first_rsync
      run_command(rsync, "split_rsync")
    else
      do_snapshot
    end
  end
  
  def get_first_rsync
    stored = rsyncs
    @last = true if stored.size == 1
    command = rsyncs.first
    stored.delete_at 0
    self.stored_rsyncs = stored.join('!RSYNC!')
    save
    command
  end
  
  def do_snapshot
    run_command("/bin/pfexec /sbin/zfs snapshot #{self.fs}@#{self.updated_at.to_i}", "snapshot")
  end
  
  def after_snapshot(command)
    cleanup
  end
  
  def after_split_rsync(command)
    run_split_rsyncs
  end
  
  def cleanup
    server.cleanup_old_jobs
    remove_old_snapshots
  end
  
  def remove_old_snapshots
    snaps = server.current_snapshots
    if snaps.size > server.keep_snapshots
      snap = snaps.delete_at(0)
      run_command("/bin/pfexec /sbin/zfs destroy #{self.fs}@#{snap}", "remove_snapshot #{snap}")<commit_msg>Don't initialize stored_rsyncs again<commit_after>class BackupJob < ActiveRecord::Base
  belongs_to :server
  belongs_to :backup_server
  has_many :commands, :dependent => :destroy
  
  named_scope :running, :conditions => {:finished => false}, :order => 'updated_at DESC', :include => [:server, :backup_server]
  named_scope :queued, :conditions => {:status => 'queued'}, :order => 'created_at ASC', :include => [:server, :backup_server]
  named_scope :latest_problems, :conditions => "status NOT IN ('OK','running','queued')", :order => 'updated_at DESC', :limit => 20, :include => [:server, :backup_server]
  
  def fs
    self.backup_server.zpool + '/' + self.server.hostname
  end
  
  def prepare_fs
     run_command("/sbin/zfs list #{self.fs}", "fs_exists")
  end
  
  def finish
    self.finished = true
    save
  end
  
  def run
    self.status = 'running'
    self.finished = false
    save
    prepare_fs
  end
  
  def ssh_command
    "ssh -c arcfour -p #{self.server.ssh_port}"
  end
  
  def main_rsync
    "/usr/bin/pfexec rsync --stats -aHRW --timeout=600 --delete-excluded --exclude=.zfs -e '#{ssh_command}' " +
    server.rsync_protects + " " + server.rsync_includes + " " + 
    server.rsync_split_excludes + " " + server.rsync_excludes +
    " --log-file=/tmp/#{self.server}_debug root@#{self.server.connect_address}:#{self.server.startdir} /#{fs}/"
  end
  
  def rsync_template
    "/usr/bin/pfexec rsync --stats -aHRW --timeout=600 --delete-excluded --exclude=.zfs -e '#{ssh_command}' " +
    server.rsync_protects + " " + server.rsync_includes + " " + 
    server.rsync_excludes +
    " --log-file=/tmp/#{self.server}_debug root@#{self.server.connect_address}:DIR /#{fs}/"
  end
  
  def rsyncs
    if stored_rsyncs.blank? and !@last
      populate_rsyncs
    end
    self.stored_rsyncs.split('!RSYNC!')
  end
  
  def populate_rsyncs
    syncs = get_rsyncs
    self.stored_rsyncs=syncs
    save
  end
  
  def get_rsyncs
    self.server.splits.map do | split |
      arr = []
      split_dir = self.server.startdir + split.to_s
      arr.concat(('a'..'z').to_a)
      arr.concat(('A'..'Z').to_a)
      arr.concat((0..9).to_a)
      arr.map do | letter |
        rsync_template.sub('DIR', split_dir + "/#{letter}*")
      end
    end.flatten.join('!RSYNC!')
  end
  
  def code_to_success(num)
    return "OK" if [0,24].include?(num)
    return "PARTIAL"
  end
  
  def run_command(command, label)
    command += ' 2>&1'
    commands.create!(:command => command, :label => label, :user => backup_server.user)
  end
  
  def wakeup
    last = commands.last
    if last.exitstatus
      run_callback(last)
    end
  end
  
  def run_callback(command)
    args = command.label.split(/ /)
    method = args.delete_at(0)
    send('after_' + method, command, *args)
  end
  
  def after_fs_exists(command)
    if command.exitstatus == 0
      start_rsyncs
    else
      run_command("/bin/pfexec /sbin/zfs create #{self.fs}", "create_fs")
    end
  end
  
  def after_create_fs(command)
    if command.exitstatus == 0
      run_command("/sbin/zfs list #{self.fs}", "fs_exists_confirm")
    else
      self.status = 'Unable to create filesystem'
      self.finished = true
      save
    end
  end
  
  def after_fs_exists_confirm(command)
    if command.exitstatus == 0
      start_rsyncs
    else
      self.status = 'Unable to create filesystem'
      self.finished = true
      save
    end
  end
  
  def start_rsyncs
    run_command(self.main_rsync, "main_rsync")
  end
  
  def after_main_rsync(command)
    self.status = code_to_success(command.exitstatus)
    save
    run_split_rsyncs
  end
  
  def run_split_rsyncs
    if rsync = get_first_rsync
      run_command(rsync, "split_rsync")
    else
      do_snapshot
    end
  end
  
  def get_first_rsync
    stored = rsyncs
    @last = true if stored.size == 1
    command = stored.first
    stored.delete_at 0
    self.stored_rsyncs = stored.join('!RSYNC!')
    save
    command
  end
  
  def do_snapshot
    run_command("/bin/pfexec /sbin/zfs snapshot #{self.fs}@#{self.updated_at.to_i}", "snapshot")
  end
  
  def after_snapshot(command)
    cleanup
  end
  
  def after_split_rsync(command)
    run_split_rsyncs
  end
  
  def cleanup
    server.cleanup_old_jobs
    remove_old_snapshots
  end
  
  def remove_old_snapshots
    snaps = server.current_snapshots
    if snaps.size > server.keep_snapshots
      snap = snaps.delete_at(0)
      run_command("/bin/pfexec /sbin/zfs destroy #{self.fs}@#{snap}", "remove_snapshot #{snap}")
{'fraction_non_alphanumeric': 0.12687312687312688, 'fraction_numerical': 0.004884004884004884, 'mean_word_length': 2.8570205479452055, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1039309', 'n_tokens_mistral': 3304, 'n_tokens_neox': 3284, 'n_words': 656}