#!/usr/bin/perl
#
#  $Id $
# -----------------------------------------------------------------------------
#  SM_UNLOADER - Unload volume
# -----------------------------------------------------------------------------
#  Author: Alex Titov
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
#
# for REQ see: Rally S623:Storage Manager TA926: Space Keeper
# notes:
#   1. Should have own log (get_logger etc)
#
#   1. get volume for "unloading" as argument
#   2. reads all device/days/hours directory and sort by days+hour
#   3. starting from latest day unload one directory at the time to the ONLINE volume
#   4. switch ONLINE volumes after unloading each directory
#   5. skip DEGRADED volumes
#   6. Re-read volume statuses every iterration
#   7. Exit if volume status is changed from "UNLOAD" or all data is unloaded
#   8. Any "foreging" files in va-<VER> & va-<VER>/<DEVICE> &v a-<VER>/<DEVICE>
#      will be moved to va-<VER>/TO-BE-REMOVED
#  10. Can conflict with wipe for directory
#  11. If find that exected directory disapears then re-read dir list 
#  
# ATTN: the consistancy of storage statistics will be compromized (TBD: stat recalc)
#



use warnings;
use strict;
use Data::Dumper;
use File::Basename qw(dirname);
use lib dirname(__FILE__).'/../lib';              # find  SM::Config here
use SM::Config ':all';
use NextCAM::Conf;

die("consistancy of storage statistics will be compromized");

# CONS ------------------------------------------------------------------------
my $UNLOADER =(split(/\//,$0))[-1];	          #the actual name of the prog
my $APL      =$ENV{APL};
my $MNT      ='/vasm'; 
my $VER      =SM_VER;
my $RSYNC    ='rsync -r --bwlimit 4096';
# ARGS ------------------------------------------------------------------------
my $uuid=$ARGV[0];
# VARS ------------------------------------------------------------------------

# SUBS ------------------------------------------------------------------------


#--------------------------------------------------------------------------
#  get_list  retrun the list of dev/date/hour directories
# ex:
#  100525:05.0000-01:106=/vasm/ceb03df6-f163-4d6b-b8ba-8eaaa441fed1/va-2.6.3/106/100525/05.0000-01
#  100525:04.0000-01:143=/vasm/ceb03df6-f163-4d6b-b8ba-8eaaa441fed1/va-2.6.3/143/100525/04.0000-01

#--------------------------------------------------------------------------
sub get_list{
  my $id=shift; 
  print "$id\n";
  my %devs = GetCfgs();
  open(FIND, "find $MNT/$id -type d -mindepth 4 -maxdepth 4 2>/dev/null|")
                                     || die "cannot do find for $MNT/$id";
  my @dirs = sort {$b cmp $a} grep {/\S+:\S+:(a?\d+)/ and exists $devs{$1} } 
      map { "$2:$3:$1=$_" if m|(a?\d+)/(\d{6})/(\d\d(\.\d{4})-\d{2})$| } <FIND>;
  close FIND;
  #print @dirs;
  #exit 0;
  my @list;
  foreach (@dirs) {
    chomp;
    next if not m|=(/.+/(((a?\d+)/((\d{2})(\d{2})(\d{2}))/(\d{2}))(\.\d{4})-(\d{2})))$|;
    my %item=(dir=>$1,path=>$2,spath=>$3,dev=>$4,devday=>"$4/$5",uuid=>$id);
    push @list,\%item;
  }
  \@list;
}

sub unload_hour {
  my ($src,$dst)=@_;
  my $dst_dir="$MNT/$dst/$VER/$src->{path}";
  my $store  ="$MNT/store/$VER";
  #print (Dumper $src);
  #print "dst: $dst\n";
  #	print "$RSYNC $src->{dir}/ $dst_dir.rsync\n";
  #	print "mv $dst_dir.rsync $dst_dir\n";
  #	print "rm -rf $src->{dir}\n";
  #	print "rm -f $store/$src->{path} $store/$src->{spath}-01\n";
  #	print "ln -s $dst_dir $store/$src->{path}\n";
  my $start=time;
  `mkdir -p $MNT/$dst/$VER/$src->{devday}`;
  `mkdir -p $MNT/store/$VER/$src->{devday}`;
  `rm -rf $dst_dir.rsync`;
  `$RSYNC $src->{dir}/ $dst_dir.rsync`;
  if($?==0) {
     my $spent=time-$start;
     SM_LOG->info("SUCCESS: spent=$spent sec  $src->{dir} is moved to $dst_dir");
     SM_info($src->{uuid}, "SUCCESS: spent=$spent sec $src->{dir} is moved to $dst_dir");
     `mv $dst_dir.rsync $dst_dir && rm -rf $src->{dir}`;
     `rm -f $store/$src->{path} $store/$src->{spath}-01`;
     `ln -s $dst_dir $store/$src->{path}`;
  }else {
     SM_LOG->warn("is not moved: $src->{dir} to $dst_dir");
     SM_warn($src->{uuid},"is not moved: $src->{dir} to $dst_dir");
  }
}


sub unload {
  my $id=shift;
  my $list=get_list($id); # pre-load the list  
#  print Dumper($list);
  my $vols=SM_Wheels();      # initial implementation, TBD: re-read in cycle
  my @vols=grep { $_ ne $id and $vols->{$_}->{ost}=~/^(Online|Degraded)$/ } keys %$vols;
  my $voln=0;
  if (! @vols ) {
      SM_LOG->error("$uuid, cannot find Online volume for unloading");
      SM_error($uuid,"cannot find Online volume for unloading");
      print("cannot find Online volume for unloading\n");
      exit 1; 
  }
 
  #print Dumper \@vols;
  for(;;) {
    #my $vols=SM_Wheels(); # 
    if($vols->{$uuid}->{ost} ne 'Unload') {
       SM_LOG->error("$uuid status is chenged to $vols->{$uuid}->{ost} but  'Unload' is expected. Terminating..");
       SM_error($uuid,"status is chenged to $vols->{$uuid}->{ost} but  'Unload' is expected. Terminating..");
       print "$uuid status is chenged to $vols->{$uuid}->{ost} but  'Unload' is expected. Terminating..\n";
       exit -2;
    }
    exit if not @$list;     # exit when list is emtpy
    my $hour=shift @$list;
    if(not -e $hour->{dir}) { 
       SM_LOG->warn("expected hour $hour->{dir} does not exist, may be wiped. Re-reading the list");
       SM_warn($uuid,"expected hour $hour->{dir} does not exist, may be wiped. Re-reading the list");
       print "expected hour $hour->{dir} does not exist, may be wiped. Re-reading the list\n";
       $list=get_list($id);
       next;
    }
    #print Dumper $hour;
    unload_hour($hour,$vols[$voln++]); 
    $voln = 0 if $voln == scalar @vols;
  }
}



# MAIN =========================================================================
SM_WritePid($UNLOADER);                 # write pid for a first time
if(!$uuid) {
  print "\n\nUsage:\n\t$UNLOADER <uuid>\n";
  exit 1;
}
my $vols=SM_Wheels();
if(not exists $vols->{$uuid}) {
  SM_LOG->error("$uuid does not belong to the wheels");
  SM_error($uuid,"does not belong to the wheels");
  print "$uuid does not belong to the wheels\n";
  exit 1;
}
if($vols->{$uuid}->{ost} ne 'Unload') {
  SM_LOG->error("$uuid expected to be in 'Unload' state");
  SM_error($uuid,"expected to be in 'Unload' state");
  print "$uuid expected to be in 'Unload' state\n";
  exit 1;
}

unload($uuid);



