ExtDataRequest.c 10.8 KB
/**
 *  @file ExtDataRequest.c
 *  @version $Id: ExtDataRequest.c,v 1.6 2009/07/07 12:24:23 budnik Exp $
 *=====================================================================
 *                    ExtDataRequest.c
 *                       V.2.6
 *  Functions set to call external script to get more data for 
 *  current database.
 *
 *  Versions:
 * Aug 3, 2007, V.1.0,  Fedorov
 * Sep 20, 2007, V.2.0, Fedorov, New solution for IsTimesLocked()
 * Sep 20, 2007, V.2.1, Fedorov, New solution for IsTimesLocked()
 * Sep 25, 2007, V.2.2, Fedorov, Variable GAP
 * May 21, 2008, V.2.3, Fedorov, skip no data file
 * May 22, 2008, V.2.4, Fedorov, Measuring of elapsed time of Lock
 * Apr 11, 2009, V.2.5, Fedorov, Do not call new file if the data out of general limits
 * Jul 07, 2009, V.2.6, Budnik, Special external call if there is empty times.nc; 
 *                            if(DStop <= DD_Var->GlobalStart) 
 *                            if(DStart >= DD_Var->GlobalStop)       
 *=====================================================================*/

#include <unistd.h>
#include <string.h>
#include "DD.h"
#include "DD_comm.h"

extern int Verbose;

/*=====================================================================
 *               Double2ISOTime()
 * Covert double time to ISO time
 * return pointer to statis string inside function
 *=====================================================================*/
char *Double2ISOTime(double CTime)
{
  static char ISO[25];
  unsigned *UT;
  
  UT = Double2UT(CTime);
  sprintf(ISO,ISOTIMEP,UT[0],UT[1],UT[2],UT[3],UT[4],UT[5],UT[6]);
  return (char *)ISO;
}

/*=====================================================================
 *               DoRequest
 * Read request.
 * return OK, or NOEXEC
 *=====================================================================*/
 int DoRequest(DD_Var_t *DD_Var, double Start, double Stop)
 {
    static char Command[MAXCOMMANDL];  /*Memory for command in system() */
    static char StartISO[25],StopISO[25];
    int err;
    struct timeval tv;
    struct timezone tz;
    
    /*======================================================
     * Lock the VI 
     * Set 1 means that VI is locked by THIS DD_Var and external program did not set LockFile yet
     *=====================================================*/
    DD_Var->VILocked = 1;
    gettimeofday(&tv,&tz);
    memcpy(&(DD_Var->LockStartTime),&(tv.tv_sec),sizeof(time_t));
    
    strcpy(StartISO,Double2ISOTime(Start));
    strcpy(StopISO,Double2ISOTime(Stop));
    sprintf(Command,GETNEWDATACALL,getenv("DDBASEBIN"),DD_Var->BaseName,DD_Var->RemSetID,DD_Var->path,StartISO,StopISO);
    if(Verbose) fprintf(stderr, "DoRequest(): Command = %s\n", Command);
    err = system(Command);
    
    switch(err)
    {
       case 0: return OK; 
       case NOPHP:    return NOEXEC;
       case NOSCRIPT: return NOEXEC;
       default:       return NOEXEC;
    }

    return NOEXEC;
 }

/*======================================================================
 *                ExtDataRequest
 *  Return folowing values:
 *  OK - request is accepted SERVER has to wait when LOCK file is gone
 *  NOEXEC - error in external executable
 *  NODATAATTIME - time corresponds to the NODATA interval
 *  GAPISSMALL - Time is inside too small gap
 *======================================================================*/
 int ExtDataRequest(DD_Var_t *DD_Var, double CTime)
 {
    size_t Rmin,Rmax;
    static size_t start[2] = {0,0};
    static size_t TimeCount[2] = {1,TIMELENGTH};
    char StartTime[TIMELENGTH];
    char StopTime[TIMELENGTH];
    double DStart, DStop;
    int SearchResult, More, status;
    
    if(Verbose) fprintf(stderr,"ExtDataRequest: Rmin,Rmax = %d %d, CTime = %f\n",DD_Var->CurrRmin,DD_Var->CurrRmax, CTime);
    
    /*
     * Search if there is an emtpy space ...
     */
    if(DD_Var->CurrRmin >= 0) Rmin = (size_t)DD_Var->CurrRmin; else Rmin = 0;
    if(DD_Var->CurrRmax >= 0) Rmax = (size_t)DD_Var->CurrRmax; else Rmax = DD_Var->MaxTimeRecNum - 1;     
   
   if(Verbose) fprintf(stderr,"ExtDataRequest:  CTime = %s\n",Double2DD_Time(CTime));
    /*
     * No yet Records in times.nc
    */
    if (Rmax == -1) {

      DStart = CTime - REQTIMEINT;
      DStop = CTime + REQTIMEINT;
      if(DStart > DD_Var->GlobalStop) 
      {
         if(Verbose) fprintf(stderr, "ExtDataRequest: Request exceeds the global stop\n");
         return OUTOFTIME;
      }
      if(DStop < DD_Var->GlobalStart) 
      {
         if(Verbose) fprintf(stderr, "ExtDataRequest: Request is less than global start\n");
         return OUTOFTIME;
      }
        return DoRequest(DD_Var, DStart, DStop);

    }
   
    More = 1;
    while(More)
    {
      start[0] = (Rmin + Rmax)/2;

      status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime);
      DStart = DD_Time2Double(StartTime);

      if(CTime > DStart)
      {
        status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime);
        DStop = DD_Time2Double(StopTime);
        if(DStop >= CTime) /* This is really INSIDE NODATA */
        {
           DD_Var->TimeRecNumber = start[0];
           More = 0;
           return NODATAATTIME;
        }
        else               /* Try interval at the right */
        {
           if(start[0] >= DD_Var->MaxTimeRecNum - 1) /* It was the last record */
           {
             More = 0;
             DD_Var->TimeRecNumber = DD_Var->MaxTimeRecNum - 1;
             SearchResult =  DATAATLEFT;   /* We are on the right of all records */
 
           }
           else
           {
              if(Verbose) fprintf(stderr,"ExtDataRequest: We have to move to %d record, CTime = %s\n", start[0]+1,Double2DD_Time(CTime));
             start[0]++;
             status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime);
             DStart = DD_Time2Double(StartTime);
             if(DStart >= CTime) /* No data interval is at the RIGHT */
             {
               DD_Var->TimeRecNumber = start[0];
               More = 0;
               SearchResult = DATAATRIGHT;
             }
             else
             {
               Rmin = start[0];
                if(Rmax <= Rmin) Rmax = Rmin;
               More = 1;
             }
           } /* else start[0] >= maximal */
         }  /* else of TestTime >= CTime */

     }     /*(CTime > DStart) */
     else   /* StartTime(R) > CTime */
     {
         if(start[0] <= 0) /* CTime is on the left from the first interval */
         {
            More = 0;
            DD_Var->TimeRecNumber = 0;
            SearchResult = DATAATRIGHT;
         }
         else
         {
            start[0]--; /* Try interval at the left */
            status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime);
            DStop = DD_Time2Double(StopTime);
            if(CTime > DStop) /* Correct interval is on the right */
            {
               DD_Var->TimeRecNumber = start[0] + 1;
               More = 0;
               SearchResult = DATAATRIGHT;
            }
            else
            {
               Rmax = start[0];
               More =1;
            }
         }
     }
  } /* while(More) */
  
  /*
   * Probably we at the left or at the right of interval
   */
  if(SearchResult ==  DATAATLEFT) // Data are on the left of requested data
  {
      start[0] = DD_Var->TimeRecNumber;
      status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime);
      DStart = DD_Time2Double(StopTime); //  Left boundary
      if((CTime - DStart) > REQTIMEINT) DStart = CTime - REQTIMEINT;
      DStop = CTime + REQTIMEINT;
      if(DStart >= DD_Var->GlobalStop) 
      {
         if(Verbose) fprintf(stderr, "ExtDataRequest: Request exceeds the global stop\n");
         return OUTOFTIME;
      }
      return DoRequest(DD_Var, DStart, DStop);
  }
  
  if(DD_Var->TimeRecNumber == 0) // All data is on the right 
  { 
      start[0] = DD_Var->TimeRecNumber;
      status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime);
      DStop = DD_Time2Double(StartTime); /* Right boundary */
      if((DStop - CTime) > REQTIMEINT) DStop = CTime + REQTIMEINT;
      DStart = CTime - REQTIMEINT;
      if(DStop <= DD_Var->GlobalStart) 
      {
         if(Verbose) fprintf(stderr, "ExtDataRequest: Request is less than global start\n");
         return OUTOFTIME;
      }
      return DoRequest(DD_Var, DStart, DStop);
  }
      
  /*
   * Now we are between two records
   * We have to check if the gap is big enough
   */
   start[0] = DD_Var->TimeRecNumber;
   status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime);
   DStop = DD_Time2Double(StartTime); /* GAP! */
   
   start[0]--;
   status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime);
   DStart = DD_Time2Double(StopTime); /* GAP! */
   
 
   if((DStop - DStart) < DD_Var->MinGap) return GAPISSMALL;

     
   if((CTime - DStart) > REQTIMEINT) DStart = CTime - REQTIMEINT;
   if((DStop - CTime) > REQTIMEINT) DStop = CTime + REQTIMEINT; 
   /*
   if(Verbose) 
   {
      fprintf(stderr,"DStart-GlobalStart = %f\n",DStart - DD_Var->GlobalStart);
      fprintf(stderr,"DStop-GlobalStop = %f\n",DStop - DD_Var->GlobalStop);
   }
    if((DStop > DD_Var->GlobalStop) || (DStart < DD_Var->GlobalStart)) return OUTOFTIME;
    */
   return DoRequest(DD_Var, DStart, DStop);
 }
 
/*======================================================================
 *                IsTimesLocked
 * Return 1 if there is LOCK in the VI directory or if the corresponding flag in DD_Var is UP
 *======================================================================*/
 int IsTimesLocked(DD_Var_t *DD_VarL)
 {
    int status;
    char FullPath[PATHLENGTH];
    struct timeval tv;
    struct timezone tz;

     
     strcpy(FullPath,DD_VarL->path);
     strcat(FullPath,DIRLOCK);
     status = access(FullPath, F_OK); /* negative if there is no file */
     switch(DD_VarL->VILocked)
     {
       case 0: if(status < 0) return NOLOCK; /* NO LOCK */
               else {DD_VarL->VILocked = 2; return LOCKED;} /* LOCK was made by another server */
               break;
       case 1: if(status < 0) /* LOCK was made by THIS server, PHP is not ready yet OR already removed(!)*/
               {
                  gettimeofday(&tv,&tz);
                  if(difftime(tv.tv_sec,DD_VarL->LockStartTime) > 1.5) 
                    {DD_VarL->VILocked = 0; return LOCKREMOVED;} /* PHP alreadyremoved LOCK */
                  else  return LOCKED;
               }     
               else {DD_VarL->VILocked = 2; return LOCKED;} /* Now even PHP setup LOCK */
               break;
       case 2: if(status < 0) {DD_VarL->VILocked = 0; return LOCKREMOVED;} /* PHP removed LOCK */
               else return LOCKED;                                  /*Keep LOCK condition */
     }
 }
/*=============================================================================================*/