//*-- Author : Jochen Markert
//_HADES_CLASS_DESCRIPTION 
///////////////////////////////////////////////////////////////////////////////
// HldGrepFileSource
//
//  This "data source" reads the HLD data from files on disk.
//  The user provides a directory name and the source will grep
//  the newest files from the disk. If after a given check interval
//  a new file is found, the current one will be closed and the reading
//  continues with the new one. The source will run in an endless loop
//  and wait for new files. The user has to stop the source by calling
//  source->stop().
//-----------------------------------------------------------------------------
//  There are several options to setup the source:
//
//  HldGrepFileSource(TString dir,TString opt,Int_t grepInterval,Int_t refId,Int_t off)
//
//  dir          : directory where the hld files are located
//  opt          : select between the 2 possible modes of the source
//                 1. "Grep" (default) : search for the newest files in intervals
//                    of grepInterval seconds
//                 2. "Date: 02/05/2005 22:00:00" select all files newer than date
//                    and read them sequentional
//                 3. "File: myname.hld" select all files newer than this file and
//                    read them sequentional
//  grepInterval : time interval for checking for new files
//  refId        : -1 (default) reference run for init procedure
//  off          : 5 s (default) selected files have to be older than off seconds
//
///////////////////////////////////////////////////////////////////////////////

#include "hldgrepfilesource.h"
#include "hrecevent.h"
#include "hldfilevt.h"
#include "hades.h"
#include "hruntimedb.h"
#include "TSystem.h"

#include <limits.h>
#include <unistd.h>
#include <sstream>

ClassImp(HldGrepFileSource)

time_t HldGrepFileSource::lastfile     =0;     //! last modification time of last used file
time_t HldGrepFileSource::timelimit    =0;     //! time stamp for the search of new files (files should be newer)
time_t HldGrepFileSource::tcurrent     =0;     //! current time stamp
Int_t  HldGrepFileSource::timeoffset   =0;     //! time offset to current time
TString HldGrepFileSource::fullname    ="";    //! full filename: path/file
TString HldGrepFileSource::fullnamesort="";    //! full filename for sorting: path/modtime_file
TString HldGrepFileSource::path        ="";    //! path to directory used for grep of new hld files

 HldGrepFileSource::HldGrepFileSource(TString dir,TString opt,Int_t grepInterval,Int_t refId,Int_t off)
	: HldFileSourceBase()
{
    //  This "data source" reads the HLD data from files on disk.
    //  The user provides a directory name and the source will grep
    //  the newest files from the disk. If after a given check interval
    //  a new file is found, the current one will be closed and the reading
    //  continues with the new one. The source will run in an endless loop
    //  and wait for new files. The user has to exit the program by himself.
    //
    //  dir          : directory where the hld files are located
    //  opt          : select between the 2 possible modes of the source
    //                 1. "Grep" (default) : search for the newest files in intervals
    //                    of grepInterval seconds
    //                 2. "Date: 02/05/2005 22:00:00" select all files newer than date
    //                    and read them sequentional
    //                 3. "File: myname.hld" select all files newer than this file and
    //                    read them sequential
    //  grepInterval : time interval for checking for new files
    //  refId        : -1 (default) reference run for init procedure
    timeoffset=off;
    referenceId=refId;
    fCurrentFile=0;
    first=0;
    dostop=kFALSE;

    //----------------------------------------
    // check input parameters
    if(grepInterval>0){

	interval=grepInterval;
    }
    else
    {
	Error("HldGrepFileSource()","time interval for directory is <=0 !");
        exit(1);
    }
    checkDir(dir);

    decodeOption(opt);
    //----------------------------------------

    // Default constructor for a Lmd file data source.
    fReadEvent=new HldFilEvt;
    iter=0;
    fCurrentFile=0;
    fEventNr = 0;
    fEventLimit = INT_MAX;

    //----------------------------------------
    // looking for first file on the disk
    // can be endless loop! Not very nice
    // in this place...but lets hope the best.
    loopForNewFile();
    //----------------------------------------
}


 HldGrepFileSource::~HldGrepFileSource(void)
{
    // Destructor for a LMD file data source
    if (fReadEvent)
    {
	delete fReadEvent;
	fReadEvent = 0;
    }
    if (iter)
    {
	delete iter;
	iter = NULL;
    }
}

 Int_t HldGrepFileSource::getRunId(const Text_t *fileName)
{
    // Get the run Id from the file filename
    // In case of failure returns -1
    TString locname=fileName;
    HldFilEvt evt;
    Int_t r=-1;
    if (fCurrentFile && locname.CompareTo(fCurrentFile->GetName())==0) {
	r=fCurrentFile->getRunId();
    } else {
	if (!evt.setFile(fileName)){r=-1;}
	else {
	    evt.read();
	    r=evt.getRunNr();
	}
    }

    return r;
}


 EDsState HldGrepFileSource::getNextEvent(Bool_t doUnpack)
{
    // Tries to read a new event from the LMD file and put
    // the info into the HEvent structure.
    // The set directory is checked in interval seconds
    // for new files. If a new file is available
    // it is opened for reading. If the last event of
    // the current file is reached an endless loop
    // for new files on the disk is performed. The
    // loop ends only in case of success!


    //---------------------------------------------
    // check if reading should be stopped
    if(dostop)
    {
	return kDsEndData;
    }
    //---------------------------------------------

    fEventNr++;

    //---------------------------------------------
    // check if the end of file is reached
    // If so, look for new file on disk
    if ( !((HldFilEvt*)fReadEvent)->execute() )
    {
	//End of current file
	fEventNr = 0;
	loopForNewFile();
    }
    //---------------------------------------------

    //---------------------------------------------
    // if the set time interval has ellapsed, check
    // if a new file is on the disk. This is only
    // in "Grep" mode active.
    if(mode==1)
    {
	timer.Stop();
	if(timer.RealTime()>interval)
	{
	    getNewFile();
	}
	else timer.Continue();
    }
    //---------------------------------------------

    //---------------------------------------------
    // finally do the unpacking of the new event
    if(doUnpack)
    {
	decodeHeader((*fEventAddr)->getHeader());

	iter->Reset();
	HldUnpack *unpacker;
	while ( (unpacker=(HldUnpack *)iter->Next())!=NULL)
	{
	    Int_t ret=unpacker->execute();
	    if(!ret) return kDsError;
	    if(ret==kDsSkip) return kDsSkip;
	}
    }
    //---------------------------------------------

    return kDsOk;
}
 
 Int_t HldGrepFileSource::loopForNewFile()
{
    // check if a new file is on the disk.
    // performs endless loop until succes!
    // A sleep of the set time interval in seconds
    // is performed before next try.

    Int_t found=0;
    while(found==0)
    {
        // found=0 if no success otherwise =1
	found=getNewFile();
	if(found==0)
	{   // in case of no succes sleep
            // a moment before next try
	    sleep(interval);
	}
    }
    return 0;
}


 int HldGrepFileSource::checkDir(TString dir)
{
    // Checks the directory dir. In case of empty
    // strings (default) or not existing directory
    // this function exit the program. No chance
    // to go on for lazy users ...Strategy of breaking
    // as soon as possible. If the directory name does
    // not end with "/" the slash is added

    if(dir.CompareTo("")==0)
    {
	Error("HldGrepFileSource()","String for hld directory is empty!");
	exit(1);
    }
    else
    {
	if(gSystem->AccessPathName(dir))
	{
	    Error("HldGrepFileSource()","Directory : %s does not exist!",dir.Data());
	    exit(1);
	}
        if(!dir.EndsWith("/")) dir+="/";
	path=dir;
    }
    return 0;
}
 Int_t HldGrepFileSource::decodeOption(TString opt)
{
    // Decodes the option string. In case of not known
    // option or wrong format this function exit the program.
    // No chance to go on for lazy users ...Strategy of breaking
    // as soon as possible. Depending on the decoded option
    // the mode (=1 for "Grep", =2 for sequential reading) switch
    // is set.
    //  opt  : select between the 2 possible modes of the source
    //         1. "Grep" (default) : search for the newest files in intervals
    //            of grepInterval seconds
    //         2. "Date: 02/05/2005 22:00:00" select all files newer than date
    //             and read them sequentional
    //         3. "File: myname.hld" select all files newer than this file and
    //            read them sequential

    mode=0;
    if(opt.Contains("Date:"))
    {   // Start of the file list which should be read
	// is selected by a give date/time. If the format
        // of the string is wrong the program exits.
	mode=2;

        TString option=opt;
	option.ReplaceAll("Date:","");
	//-----------handling date/time selection-----------------
	option.ReplaceAll("/"," ");
	option.ReplaceAll(":"," ");

	Int_t var[6]={-1};
	Int_t nVar=0;

	stringstream input;
	input.str("");
        input<<option.Data();

	while(input.good()&&nVar<10)
	{
	    if(nVar<6&&input>>var[nVar])
	    {
		nVar++;
	    }
	    else
	    {
		break;
	    }
	}

	if(nVar!=6)
	{
	    Error("HldGrepFileSource()","wrong number of arguments found ! n "
		  "nVar=%i  => dd/mm/yyyy hh:mm:ss :: %02i/%02i/%i %02i:%02i:%02i  ! n "
		  "input: %s ", nVar,var[0],var[1],var[2],var[3],var[4],var[5],opt.Data());
	    exit(1);
	}
	else {
	    struct tm time_limit;

	    time_limit.tm_mday=var[0];
	    time_limit.tm_mon =var[1]-1;
	    time_limit.tm_year=var[2]-1900;
	    time_limit.tm_hour=var[3];
	    time_limit.tm_min =var[4];
	    time_limit.tm_sec =var[5];

	    timelimit=mktime(&time_limit);
	    lastfile=timelimit;

	    cout<<"HldGrepFileSource(): You selected to start by DATE :"<<ctime(&timelimit)<<endl;
	}
	//--------------------------------------------------------

    }
    else if(opt.Contains("File:"))
    {
	// Start of the file list which should be read
	// is selected by a file name and therefore
	// by the last modification time of the selected
	// file. If the file does not exit the program exits.
	mode=2;
	opt.ReplaceAll("File:","");
	opt.ReplaceAll(" ","");

	if(gSystem->AccessPathName(Form("%s%s",path.Data(),opt.Data())))
	{
	    Error("HldGrepFileSource()","File does not exist!");
	    exit(1);
	}

	//-----------handling file selection----------------------
	struct stat statloc;
	stat(Form("%s%s",path.Data(),opt.Data()),&statloc);
	timelimit=statloc.st_mtime;
	lastfile=timelimit;

	cout<<"HldGrepFileSource(): You selected to start by DATE from File :"<<ctime(&timelimit)<<endl;
	//--------------------------------------------------------

    }
    else if(opt.Contains("Grep"))
    {
	mode=1;
    }
    else
    {
	Error("HldGrepFileSource()","Unknown option:%s!",opt.Data());
	exit(1);
    }
    return 0;
}
 Int_t HldGrepFileSource::selectFiles(const struct dirent *entry)
{
    // This is the select function called with scandir(.....)
    // Selects files going to the list of files for sorting/selection.
    // Returns 1 if a file is selected otherwise 0.
    // Only hld files and files newer or equal than the time stamp
    // lastfile are taken into account. Files smaller 500k are
    // ignored.

    if(entry->d_type==DT_REG ||
       entry->d_type==DT_UNKNOWN)
    {   // only regular files are of interest.
        // Some systems return ONLY unknow!
	TString a=entry->d_name;
	if(!a.EndsWith(".hld")) return 0;

	// only files newer than last read files
        // should go to list. Improves sorting speed!
	struct stat statloc;
	fullname=Form("%s%s",path.Data(),entry->d_name);
	stat(fullname.Data(),&statloc);

	Double_t diff=difftime(tcurrent,statloc.st_mtime);

	if(diff<0)
	{
	    cout<<"HldGrepFileSource::selectFiles(): time difference t_current - t_lastmod < 0 ==> mod time in future!"<<endl;
            return 0;
	}

	if(statloc.st_mtime<lastfile
	   ||statloc.st_size<1024*500
	   ||diff<timeoffset
	  ) return 0;

	return 1;
    }
    else return 0;
}


 Int_t HldGrepFileSource::getNewFile()
{
    // Loops on the set directory for new hld files.
    // the dir is scanned with scandir(). The selected
    // files newer or equal time stamp lastfile goes
    // to the list of candidates. The list will be sorted
    // by last modification of the files.
    // In "Grep" mode (mode=1) the second newest file
    // is opened (preventing from reading a file which is
    // in writing process). The time stamp lastfile is set
    // to the selected files last modification time.
    // In "File/Date" mode (mode=2) the list is sequential
    // read.

    struct dirent **namelist;
    int n;
    struct stat status;

    fullname    ="";
    fullnamesort="";
    
    Int_t newFile=0;

    //----------------------------------------
    // get the current time
    time(&tcurrent);
    //----------------------------------------
    n = scandir(path.Data(), &namelist,selectFiles,alphasort);
    if (n < 0)
    {
	perror("scandir");
    }
    else
    {
	TList mylist;

 	//----------------------------------------
	// loop over the file list provided by
	// scandir() Strings with the format path/modtime_filename
	// are added to TList of files for later sorting
        // by last modification time
	while(n--)
	{
	    fullname=Form("%s%s",path.Data(),namelist[n]->d_name);
	    stat(fullname.Data(),&status);

	    fullnamesort=Form("%s%i_%s",path.Data(),status.st_mtime,namelist[n]->d_name);
	    mylist.AddLast(new TObjString(fullnamesort));

	    free(namelist[n]);
	}
	free(namelist);
	//----------------------------------------

	//----------------------------------------
	// The list will be sort by name of the files
	// As the file name contains the last modificaton time
	// they will be sorted by mod time. The newest file
	// will be the last in the list.
	mylist.Sort();
	//----------------------------------------

	//----------------------------------------
	// in mode=1 take the second newest file
	// to sure that the file is closed!
        // otherwise the first file in list
	Int_t index;
	Int_t lastindex=mylist.LastIndex();
	if(mode==1)                   {index=lastindex-2;} // grep mode
	else if(mode==2&&lastindex>0) {index=1;}           // reading since a give date/time or file
        else                          {index=-1;}          // default
	//----------------------------------------

	if(index>0)
	{
	    cout<<"n----------------------------------------------------------------"<<endl;
	    TString myselect=((TObjString*)(mylist.At(index)))->GetString();

	    //----------------------------------------
	    // removing mod time from name
	    TString temp  =myselect;
	    TString base  =gSystem->BaseName(temp.Data());
	    TString parent=temp.Remove(temp.Length()-base.Length());
  	    Ssiz_t last_  = base.First('_');
	    base.Replace(0,last_+1,"");
            myselect      =parent + base;
	    //----------------------------------------

	    //----------------------------------------
	    // getting mod time of file and current time
	    // for print out
	    stat(myselect.Data(),&status);
	    time_t tfile=status.st_mtime;
	    TString a=ctime(&tfile);
	    TString b=ctime(&tcurrent);
	    a.ReplaceAll("n","");
	    b.ReplaceAll("n","");
	    //----------------------------------------

	    //----------------------------------------
            // print infos about selected file
	    if(mode==2)
	    {
		cout<<mylist.LastIndex()<<" files in list."<<endl;
	    }
            Int_t diff=(Int_t)difftime(tcurrent,tfile);
	    cout<<myselect.Data()<<" last mod time : "<<diff<<" seconds ago." <<endl;
	    cout<<"mod time: "<<a.Data()<<" now: "<<b.Data()<<endl;
 	    //----------------------------------------


	    //----------------------------------------
	    // set the time stamp to the selected files
	    //last modification time
	    lastfile=tfile;
	    first   =1;  // now we know it is not anlylonger the first try to select a file
            newFile =1;  // file selection was succesful
	    //----------------------------------------


	    //----------------------------------------
	    // delete old filew descriptot, generate a new one
            // and open the new file for reading
	    if(fCurrentFile) delete fCurrentFile;
            fCurrentFile=0;
	    Int_t run=getRunId(myselect.Data());
	    fCurrentFile=new HldFileDesc(myselect.Data(),run,referenceId);
	    ((HldFilEvt *)fReadEvent)->setFile(fCurrentFile->GetName());
	    //----------------------------------------

	    cout<<"----------------------------------------------------------------"<<endl;
	}
	else
	{
	    if(first==0)
	    {   // if this is before the first valid file
		// was found. Otherwise it should be quiet!
		cout<<"----------------------------------------------------------------"<<endl;
		cout<<"No new File on Disk! trying again...."<<endl;
		cout<<"----------------------------------------------------------------"<<endl;
	    }
	    else
	    {   // short notification that a scan of the
		// directory has been done with no result!
		cout <<"."<<flush;
	    }
	}

	//----------------------------------------
	// clean the working list from memory
	mylist.Delete();
 	//----------------------------------------

    }
    // time interval is taken after selection to keep
    // the interval independent of the number of files
    // in dir start resets the timer!
    timer.Start(kTRUE); 
    return newFile;
}







ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.