source: trunk/src/archiving/wave_serverV/serve_trace.c @ 3164

Revision 3164, 82.8 KB checked in by paulf, 12 years ago (diff)

sqlite stuff added

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[15]1
2/*
3 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
4 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
5 *
6 *    $Id$
7 *
8 *    Revision history:
9 *     $Log$
[3164]10 *     Revision 1.15  2007/11/30 18:40:16  paulf
11 *     sqlite stuff added
12 *
[2883]13 *     Revision 1.14  2007/03/28 18:02:34  paulf
14 *     fixed flags for MACOSX and LINUX
15 *
[1903]16 *     Revision 1.13  2005/07/21 21:05:51  friberg
17 *     Added _LINUX ifdef to roundup to prevent macro use
18 *
[1753]19 *     Revision 1.12  2005/03/17 17:30:05  davidk
20 *     Changes to enforce a maximum tanksize of 1GB.
21 *     Non-functional change.
22 *     Added a  Long comment describing the bug in LocateRoughOffset
23 *     that limits WaveServerV tank sizes to 1GB.
24 *
[1493]25 *     Revision 1.11  2004/05/18 22:30:19  lombard
26 *     Modified for location code
27 *
[1176]28 *     Revision 1.10  2003/01/28 00:42:27  alex
29 *     changed logit message around line 2269. Alex
30 *
[1085]31 *     Revision 1.9  2002/10/11 21:44:08  davidk
32 *     Fixed a bulk send fill statement that miscalulated the number
33 *     of fill values.  It sent one too few.  This fixes a fix to the
34 *     same statement, from 08/2001, when the statement was issuing
35 *     one too many fill samples.  The 08/2001 fix removed two(2) samples
36 *     instead of just 1.
37 *
[1084]38 *     Revision 1.8  2002/10/11 21:31:29  davidk
39 *     Checking in change from 08/2001.  Change had never been checked in.
40 *     Checking it in, so that I can fix a bug in it.
41 *
[765]42 *     Revision 1.7  2001/08/11 17:16:45  davidk
43 *     modified GRACE_PERIOD code in locating offsets, so that it now
44 *     accomodates sloppy timestamps, instead of doing whatever it
45 *     did before.  The previous GRACE_PERIOD logic was flawed as it
46 *     was based on misunderstandings about the interpretation of
47 *     trace_buf packets by the GRACE_PERIOD author(me).
48 *
49 *     Modified SendReqDataAscii().  Moved the bulk of the code out
50 *     into a separate function SendReqDataAscii_AndThisTimeWeMeanIt().
51 *     Fixed ascii reply code so that it better handled sloppy timestamps
52 *     and fill values.
53 *     See wave_serverV/README.changes for more detailed info.
54 *
[701]55 *     Revision 1.6  2001/06/29 22:23:59  lucky
56 *     Implemented multi-level debug scheme where the user can specify how detailed
57 *     (and large) the log files should be. If no Debug is specified, only
58 *     errors are reported and logged.
59 *
[371]60 *     Revision 1.5  2001/01/17 21:44:25  davidk
61 *     Added code to report hard(disk) read/write errors via status messages.
62 *
[301]63 *     Revision 1.4  2000/10/02 18:06:48  lombard
64 *     Fixed two places where unnecessary calls to fseek() could cause an
65 *     endless loop if fseek() failed, such as the tank file having been
66 *     closed by the main thread. The fseek() was intended to restore the
67 *     tank file position to that needed by the main thread.
68 *
[162]69 *     Revision 1.3  2000/07/08 19:01:07  lombard
70 *     Numerous bug fies from Chris Wood
71 *
[154]72 *     Revision 1.2  2000/06/28 23:45:27  lombard
73 *     added signal handler for graceful shutdowns; numerous bug fixes
74 *     See README.changes for complete list
75 *
[15]76 *     Revision 1.1  2000/02/14 19:58:27  lucky
77 *     Initial revision
78 *
79 *
80 */
81
82
83/* serve_trace.c: created April 25, 1997 */
84
85#include        <stdio.h>
86#include        <stdlib.h>
87#include        <string.h>
88#include        <earthworm.h>
89#include        <transport.h>           /* needed for wave_serverV.h */
90#include        <trace_buf.h>
91#include        <socket_ew.h>
92#include        "wave_serverV.h"
93#include        "server_thread.h"
[3164]94#include                "tb_packet_db.h"                /* ronb041007 - used to read back out-of-sync packets*/
95   
[15]96
97#define FLAG_L    0
98#define FLAG_R    1
99
100#define D_SIZE_I2 2
101#define D_SIZE_I4 4
102
103#define MAX_TRACE_INT_LEN   16
104#define MAX_TRACE_DBL_LEN  128
105#define MAX_TRACE_HDR_LEN  256
106#define MAX_TRACE_SOC_LEN 8192/*4096*/
107#define DBL_FLOAT_NA      ((double) -1.0)
108#define DBL_FLOAT_EPSILON ((double) 0.00010) /* << 100 samples/sec */
109
110#define SPACE_STR (char *) " "
111#define LN_FD_STR (char *) "\n"
112
113#define NO_NEWLINE 0
114#define YES_NEWLINE 1
115
[765]116/* return codes used in SendReqDataAscii() */
117#define SRDA_ABORT     -1
118#define SRDA_MEM_ABORT -2
119
120
121
122/* MINIMUM_GAP_SIZE is the smallest time gap between samples
123   that can be considered to contain a gap in data.  It is
124   given in terms relative to sample rate.  If it is 1.3, then
125   that means there must be atleast a (1.3/SAMPLERATE) second
126   difference between the last sample and the next before a
127   GAP can be declared.  This is not related to GAPSIZE and
128   wave_serverV indexes.
129   DK 08/09/2001
130*/
131#define MINIMUM_GAP_SIZE (1.0 + ACCEPTABLE_TIMESTAMP_SLOP)
132
133
134
[3164]135extern int bUsePacketSyncDb;    /* config flag to use packet db to sync data. ronb011007*/
136extern int bTankOverSyncDbData; /* config buffer precedence. */
137extern TBDB_STORE* pPacketDb;   /* ref to OutOfSync Packet Db. ronb041007*/
[765]138
[15]139int _writeTraceDataRaw( int, TANK*, CLIENT_MSG* );
140int _writeTraceDataAscii( int, TANK*, CLIENT_MSG* );
141
142static int SendReqDataRaw( int, TANK*, double, double, double, double,
143                           double, double,
144                           char*, long int, char* );
145static int SendReqDataAscii( int, TANK*, double, double, double, double,
146                             double, double, char*,
147                             char*, long int, char* );
148
149static int GetOffsetLeft( TANK*, double, long int*, double* );
150static int GetOffsetRight( TANK*, double, long int*, double* );
151static int LocateExactOffset( TANK*, DATA_CHUNK*, double, int,
152                              long int*, double*, DATA_CHUNK * );
153static int LocateRoughOffset( TANK*, double, double, double,
154                              long int, long int, int, long int*, double* );
155static int LocateStartOfTank( TANK*, long int*, double* );
156static int LocateEndOfTank( TANK*, long int*, double* );
157
158static int CopyReqData( TANK*, long int, long int, char**, long int* );
159static int ReadBlockData( FILE*, long int, long int, char* );
160static int FreeReqData( char* );
161
162static int BulkSendFill( int, char*, long int );
163static int SendHeader( int soc, TANK* t, char* reqid, char* flag, double tS,
164                       double tE, int binSize, int flagNewLine);
165static int SendStrData( int soc, char* str );
[3164]166static int MergeAsyncPackets(
167     TANK* t,
168        char** data,
169        long* datasize,
170        char* AsyncData,
171        long AsyncDataSize,
172        long AsyncPacketCount
173);
[15]174
175
176static int _fDBG = -1;  /* equal to -1 upon first entry to ws_client.c */
177static int _fSUB = 2;
178static int _fALG = 16;
179static int _fPRT = 32;
180
181/* set _fDBG to be non-zero for extended debug logit() */
182static int _fINI = 0;
183static char _pSYSTEM[32] = "ew_debug.ini";
184static char _pMODULE[32] = "serve_trace";
185
186static int ewInitDebugFlag( char* pModule, int* flagp )
187{
188  FILE *fid = NULL;
189  char buf[128] = "";
190
191  *flagp = _fINI;
192  fid = fopen(_pSYSTEM,"r");
193  if (!fid) goto done;
194
195  while (fgets(buf,127,fid))
[154]196  {
197    if (buf[0] == '#') continue;
198    if (!strstr(buf,pModule)) continue;
[15]199    {
[154]200      char *ptr = buf;
201      int flag = 0;
202
203      while (*ptr && (*ptr != '='))
204        ++ptr;
205      if (*ptr == '=') ++ptr;
206      if (!(*ptr) || (sscanf(ptr,"%d",&flag) != 1))
[15]207      {
[154]208        logit("", "ewInitDebugFlag(): sscanf() failed! buf[%s]\n", buf);
209        goto done;
[15]210      }
[154]211      *flagp = flag;
212      break;
[15]213    }
[154]214  }
[15]215
[154]216 done:
[15]217  if (fid) fclose(fid);
218  if (*flagp) logit("e","ewInitDebugFlag(): %s[%d]\n", pModule, *flagp);
219  return 0;
220}
221
[1493]222static int trace_log( TRACE2_HEADER* );
[15]223
224/* function: _writeTraceDataRaw()
225 *    input: int soc, socket descriptor;
226 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
227 *           CLIENT_MSG* msg, which contains the following info:
228 *               double tS, starting time of reqested period;
229 *               double tE, ending time of reqested period;
230 *               char* fill, ascii string that fills sampling gaps
231 *   return: R_SKIP if tE <= tS;
232 *           R_FAIL or R_DONE otherwise
233 *
234 *  purpose: to serve as one of the two entry points from server_thread.c,
235 *           by responding to user requests of raw binary data for a given
236 *           period of time.  In doing so, the following events occur:
237 *           1) tank file is locked,
238 *           2) left and right offsets in tank file are found,
239 *           3) data within this range is copied to memory,
240 *           4) the lock is released,
241 *           5) data is sent to socket with proper header information
242 */
243
244int _writeTraceDataRaw( int soc, TANK* t, CLIENT_MSG* msg )
245{
246  int ret = R_FAIL;
247  long int oS = -1L;          /* starting offset for CopyReqData() */
248  long int oE = -1L;          /* ending offset for CopyReqData() */
249  double tS = 0.0;
250  double tE = 0.0;
251  double acttS = 0.0;         /* actual time stamp at oS */
252  double acttE = 0.0;         /* actual time stamp at oE */
253  long int oL = -1L;          /* starting tank offset for SendReqDataRaw() */
254  long int oR = -1L;          /* ending tank offset for SendReqDataRaw() */
255  double tL = 0.0;            /* time stamp on left edge of the tank */
256  double tR = 0.0;            /* time stamp on right edge of the tank */
257  char* data = (char*) NULL;
258  long int datasize = 0L;
259  int mutexLocked = 0;
260  long int saveOff = 0;      /* saving offset of file */
[3164]261  long AsyncDataSize;
262  long AsyncPacketCount= 0;
263  long AsyncPageSize;
264  char* AsyncData;
265 
[15]266  if ( _fDBG == -1 )
267    ewInitDebugFlag( _pMODULE, &_fDBG );
268
269  if ( !t || !(t->tfp) ) goto abort;
270  if ( !msg ) goto abort;
271  tS = msg->starttime;
272  tE = msg->endtime;
273  if ( tS < 0.0 ) goto abort;
274  if ( tS + DBL_FLOAT_EPSILON >= tE ) goto skip;
275
276  if ( _fDBG & _fSUB )
277    logit( "","\n--------------------------------\n" );
278
279  RequestSpecificMutex(&(t->mutex));
280  mutexLocked = 1;
[162]281  if ( (saveOff = ftell(  t->tfp )) < 0 )
[154]282  {
283    logit( "","_writeTraceDataRaw(): ftell[%ld] failed for tank %s\n",
284           saveOff, t->tankName );
285    goto abort;
286  }
[15]287   
288  /* safe to get delimiters of tank once mutex is locked */
289  if ( LocateStartOfTank( t, &oL, &tL ) )
290    goto abort;
291  if ( LocateEndOfTank( t, &oR, &tR ) )
292    goto abort;
293   
[3164]294   /* Check to see if we have async packets in requested range.*/
295   if(bUsePacketSyncDb) {
296        tbdb_get_all_packets(pPacketDb,t->sta, t->net, 
297                t->chan, t->loc, tS, tE, (void*) &AsyncData, &AsyncDataSize, 
298                &AsyncPageSize, &AsyncPacketCount);
299   }
300 
[15]301  if ( _fDBG & _fSUB )
[154]302  {
303    logit( "","_writeTraceDataRaw(): [tS,tE] [%f,%f]\n",tS,tE );
304    logit( "","                      [tL,tR] [%f,%f]\n",tL,tR );
305    logit( "","                      [oL,oR] [%ld,%ld]\n",oL,oR );
306  }
[15]307   
308  if ( GetOffsetLeft( t, tS, &oS, &acttS ) != R_DONE ) goto abort;
309  if ( GetOffsetRight( t, tE, &oE, &acttE ) != R_DONE ) goto abort;
310
311  /* SendReqDataRaw() will, if necessary, set FL, FR or FG based on
312   * acttS and acttE in comparison with tS and tE,
313   * hence don't goto skip here even if ( acttE <= acttS );
314   *
315   * however, since the wrapping nature of the tank, it is likely
316   * oS > oE, hence CopyReqData() need be guarded by the comparison
317   * of acctS and acctE;
318   *
319   * when [tS,tE] falls entirely in a gap, acttE < tS < tE < acttS,
320   * it is clear that acttE < acttS, and CopyReqData() need not be called
321   *
322   * when [tS,tE] falls entirely in index range, or when there is an
323   * overlap of [tS,tE] and [acttS,acttE], one of following is true:
324   *   1) acttS < tS < tE < acttE,
325   *   2) tS < acttS < acttE < tE,
326   *   3) acttS < tS < acttE < tE,
327   *   4) tS < acttS < tE < acttE,
328   * which is equivalent to ( acttS < tE && tS < acttE );
329   *
330   */
331
332  if ( ( acttS < tE && tS < acttE ) &&
333       ( acttS + DBL_FLOAT_EPSILON > acttE ) )
[154]334  {
335    logit( "","_writeTraceDataRaw(): warning! acttS[%f] acttE[%f] for tank %s\n",
336           acttS,acttE, t->tankName );
337  }
[15]338
339  if ( ( acttS < tE && tS < acttE ) &&
340       ( acttS + DBL_FLOAT_EPSILON <= acttE) )
[154]341  {
[3164]342     if ( (CopyReqData( t, oS, oE, (char**) &data, &datasize ) == R_FAIL) && !AsyncPacketCount )
343       goto abort;
[154]344  }
[15]345   
[3164]346  /* resync packets if we have any*/
347  if(AsyncPacketCount && AsyncData) {
348          MergeAsyncPackets(t, &data, &datasize, AsyncData, AsyncDataSize, AsyncPacketCount);
349          free(AsyncData);
350  }
[15]351  ReleaseSpecificMutex(&(t->mutex));
352  mutexLocked = 0;
353
354  if ( SendReqDataRaw( soc, t, tS, tE, tL, tR, acttS, acttE,
355                       data, datasize, msg->reqId ) != R_DONE)
356    goto abort;
357  ret = R_DONE;
[154]358 skip:
[15]359  if ( ret != R_DONE)
[154]360  {
361    ret = R_SKIP;
362    if ( _fDBG & _fSUB )
363      logit( "","_writeTraceDataRaw(): skips processing\n" );
364  }
365 abort:
[15]366  if ( ret == R_FAIL )
[154]367  {
368    logit( "","_writeTraceDataRaw(): failed\n" );
369  }
[15]370  if ( mutexLocked ) 
[154]371    ReleaseSpecificMutex(&(t->mutex));
[301]372
[15]373  if ( data )
374    FreeReqData( data );
375  return ret;
376}
377
378/* function: _writeTraceDataAscii()
379 *    input: int soc, socket descriptor;
380 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
381 *           CLIENT_MSG* msg, which contains the following info:
382 *               double tS, starting time of reqested period;
383 *               double tE, ending time of reqested period;
384 *               char* fill, ascii string that fills sampling gaps;
385 *           char* reqid, the client's request ID
386 *   return: R_SKIP if tE <= tS;
387 *           R_FAIL or R_DONE otherwise
388 *
389 *  purpose: to serve as one of the two entry points from server_thread.c,
390 *           by responding to user requests of raw ASCII data for a given
391 *           period of time.  In doing so, the following events occur:
392 *           1) tank file is locked,
393 *           2) left and right offsets in tank file are found,
394 *           3) data within this range is copied to memory,
395 *           4) the lock is released,
396 *           5) data is sent to socket with proper header information
397 */
398
399int _writeTraceDataAscii( int soc, TANK* t, CLIENT_MSG* msg )
400{
401  int ret = R_FAIL;
402  long int oS = -1L;          /* starting offset for CopyReqData() */
403  long int oE = -1L;          /* ending offset for CopyReqData() */
404  double tS = 0.0;
405  double tE = 0.0;
406  char* fill = (char*) NULL;
407  double acttS = 0.0;         /* actual time stamp at oS */
408  double acttE = 0.0;         /* actual time stamp at oE */
409  long int oL = -1L;          /* starting tank offset for SendReqDataAscii() */
410  long int oR = -1L;          /* ending tank offset for SendReqDataAscii() */
411  double tL = 0.0;            /* time stamp on left edge of the tank */
412  double tR = 0.0;            /* time stamp on right edge of the tank */
413  char* data = (char*) NULL;
414  long int datasize = 0L;
415  int mutexLocked = 0;
416  long int saveOff = 0;      /* saving offset of file */
[3164]417  long AsyncDataSize;
418  long AsyncPacketCount= 0;
419  long AsyncPageSize;
420  char* AsyncData;
[15]421
422  if ( _fDBG == -1 )
423    ewInitDebugFlag( _pMODULE, &_fDBG );
424
425  if ( !t || !(t->tfp) ) goto abort;
426  if ( !msg ) goto abort;
427  tS = msg->starttime;
428  tE = msg->endtime;
429  fill = msg->fillvalue;
430  if ( tS < 0.0 ) goto abort;
431  if ( tS + DBL_FLOAT_EPSILON >= tE ) goto skip;
432
[3164]433   if ( _fDBG & _fSUB )
[15]434    logit( "","\n================================\n" );
435
436  RequestSpecificMutex(&(t->mutex));
437  mutexLocked = 1;
[162]438  if( (saveOff = ftell( t->tfp )) < 0 )
[154]439  {
440    logit( "","_writeTraceDataAscii(): ftell[%ld] failed for tank %s\n",
441           saveOff, t->tankName );
442    goto abort;
443  }
[15]444   
445  /* safe to get delimiters of tank once mutex is locked */
446  if ( LocateStartOfTank( t, &oL, &tL ) )
447    goto abort;
448  if ( LocateEndOfTank( t, &oR, &tR ) )
449    goto abort;
450   
[3164]451  /* Check to see if we have async packets in requested range.*/
452  if(bUsePacketSyncDb) {
453        tbdb_get_all_packets(pPacketDb,t->sta, t->net, 
454                t->chan, t->loc, tS, tE, (void*) &AsyncData, &AsyncDataSize, 
455                &AsyncPageSize, &AsyncPacketCount);
456  }
457
[15]458  if ( _fDBG & _fSUB )
[154]459  {
460    logit( "","_writeTraceDataAscii(): [tS,tE] [%f,%f]\n",tS,tE );
461    logit( "","                   [tL,tR] [%f,%f]\n",tL,tR );
462    logit( "","                   [oL,oR] [%ld,%ld]\n",oL,oR );
463  }
[15]464   
465  if ( GetOffsetLeft( t, tS, &oS, &acttS ) != R_DONE ) goto abort;
466  if ( GetOffsetRight( t, tE, &oE, &acttE ) != R_DONE ) goto abort;
467
468  /* SendReqDataAscii() will, if necessary, set FL or FR based on
469   * acttS and acttE in comparison with tS and tE,
470   * hence don't goto skip here even if ( acttE <= acttS );
471   *
472   * however, since the wrapping nature of the tank, it is likely
473   * oS > oE, hence CopyReqData() need be guarded by the comparison
474   * of acctS and acctE;
475   *
476   * when [tS,tE] falls entirely in a gap, acttE < tS < tE < acttS,
477   * it is clear that acttE < acttS, and CopyReqData() need not be called
478   *
479   * when [tS,tE] falls entirely in index range, or when there is an
480   * overlap of [tS,tE] and [acttS,acttE], one of following is true:
481   *   1) acttS < tS < tE < acttE,
482   *   2) tS < acttS < acttE < tE,
483   *   3) acttS < tS < acttE < tE,
484   *   4) tS < acttS < tE < acttE,
485   * which is equivalent to ( acttS < tE && tS < acttE );
486   *
487   */
488
489  if ( ( acttS < tE && tS < acttE ) &&
[3164]490       ( acttS + DBL_FLOAT_EPSILON > acttE ) && !AsyncPacketCount)
[154]491  {
492    logit( "","_writeTraceDataAscii(): warning! acttS[%f] acttE[%f], no data available for request in tank %s\n",
493           acttS,acttE,t->tankName );
494  }
[15]495
496  if ( ( acttS < tE && tS < acttE ) &&
497       ( acttS + DBL_FLOAT_EPSILON <= acttE) )
[154]498  {
[3164]499    if ( (CopyReqData( t, oS, oE, (char**) &data, &datasize ) == R_FAIL) && !AsyncPacketCount)
500       goto abort;
[154]501  }
[15]502   
[3164]503
504  /* resync packets if we have any*/
505  if(AsyncPacketCount && AsyncData) {
506          MergeAsyncPackets(t, &data, &datasize, AsyncData, AsyncDataSize, AsyncPacketCount);
507          free(AsyncData);
508  }
509
[15]510  ReleaseSpecificMutex(&(t->mutex));
511  mutexLocked = 0;
512
513  if ( SendReqDataAscii( soc, t, tS, tE, tL, tR, acttS, acttE,
514                         fill, data, datasize, msg->reqId ) != R_DONE)
515    goto abort;
516  ret = R_DONE;
[154]517 skip:
[15]518  if ( ret != R_DONE)
[154]519  {
520    ret = R_SKIP;
521    if ( _fDBG & _fSUB )
522      logit( "","_writeTraceDataAscii(): skips processing\n" );
523  }
524 abort:
[15]525  if ( ret == R_FAIL )
[154]526  {
527    logit( "","_writeTraceDataAscii(): failed\n" );
528  }
[15]529  if ( mutexLocked ) 
[154]530    ReleaseSpecificMutex(&(t->mutex));
[301]531   
[15]532  if ( data )
533    FreeReqData( data );
534  return ret;
535}
536
537
538/* function: GetOffset()
539 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
540 *           double reqtS, starting time of reqested period
541 *   output: long int* offp, the offset that covers reqtS, which is set
542 *               to the start of next index when reqtS falls in a gap;
543 *           double* acttp, actual time that matches *offp;
544 *   return: R_FAIL or R_DONE
545 *
546 *  purpose: to find  offset in tank file (including associated
547 *           time stamp) for the requested time period;
548 *           called  from GetOffsetLeft() and GetOffsetRight();
549 *           Used to illiminate redundancy between Left() and Right()
550 *           Could improve performance by using #defines
551 */
552static int GetOffset( TANK* t, double reqTime,
553                      long int *offp, double *acttp,
554                      int DirectionFlag)
555{
556  int ret = -1;
557  int curr = -1;  /* iterator */
558  int prev = -1;  /* look back */
559  int next = -1;  /* look forward */
560  DATA_CHUNK * pCurr = (DATA_CHUNK *) 0;
561  DATA_CHUNK * pNext = (DATA_CHUNK *) 0;
562  char szFuncName[2][20] = {"GetOffsetLeft", "GetOffsetRight"}; 
563
564  *offp = -1L;
565  *acttp = 0.0;
566
567  if ( !t || !( t->tfp ) || t->samprate < DBL_FLOAT_EPSILON )
[154]568  {
569    logit( "","%s(): bad parameters\n",szFuncName[DirectionFlag] );
570    logit( "","%s(): failed\n",szFuncName[DirectionFlag] );
571    ret=R_FAIL;
572  }
[15]573
574  /* We are not using pointers now, we are using array indexes.  This seems kind
575     of messy, because the list is not encapsulated.  It would probably be a
576     good idea to encapsulate the list, and use GetNextChunk(TANK *,DATA_CHUNK *),
577     but for now, I will just code the index. Cleanup:
[154]578  */
[15]579
580  /* Make sure the tank is not empty */
581  if ( IndexOldest( t )->tEnd == 0.0 )
[154]582  {
583    logit( "","%s(): Empty tank %s\n",szFuncName[DirectionFlag], t->tankName);
584    logit( "","%s(): failed\n",szFuncName[DirectionFlag]);
585    ret=R_FAIL;
586  }
[15]587
588  /* Set curr and next */
[162]589  curr=t->indxStart;
[15]590  if(t->indxStart >= ((unsigned int)t->indxMaxChnks)) /* t->indxStart is an unsigned int and cannot be <0 */
591  {
592    /* t->indxStart is out of whack */
593    logit("et","wave_serverV.GetOffset(): Bad t->indxStart %d, for tank %s\n",
594          t->indxStart, t->tankName );
595  }
596
597  /* Make sure there is a next */
598  if(curr != (int)t->indxFinish)
599  {
600    next=curr+1;
601    if(next == t->indxMaxChnks)
602    {
603      next=0;
604    }
605  }
606
607  while(prev != (int)t->indxFinish && ret != R_DONE  && ret !=R_FAIL)
[154]608  {
609    pCurr=&((t->chunkIndex)[curr]);
[765]610    /* check to see if the current index doesn't contain data that is too young.
611       Remember to allow for timestamp slop. */
612    if( (reqTime < (pCurr->tEnd + GRACE_PERIOD)  && 
613        DirectionFlag == FLAG_L) 
614       ||
615        (reqTime <= (pCurr->tEnd + GRACE_PERIOD) && 
616        DirectionFlag == FLAG_R)
617      )
[15]618    {
[154]619      /* We've found a piece of trace that is not too young */
[765]620      /* check to see if the current index doesn't isn't too old
621         Remember to allow for timestamp slop. */
622      if( (reqTime <= (pCurr->tStart - GRACE_PERIOD) && 
623          DirectionFlag == FLAG_L) 
624         ||
625          (reqTime < (pCurr->tStart - GRACE_PERIOD) && 
626          DirectionFlag == FLAG_R)
627        )
[154]628      { 
629        /* !!oops, either too young, or in the gap just before this junk */
630        /* set the offset to here, and note that it occured in GAP */
[701]631        if (Debug > 1)
632        {
633             logit("t","Found gap, or too young at curr=%d, setting offset %d\n",
634                                                                                                                                curr,pCurr->offset);
635             logit("t","Curr-Start %f,Curr->End %f,reqTime %f!\n",
636                                                                                                        pCurr->tStart,pCurr->tEnd,reqTime);
[154]637             logit("t","Tank %s  ",t->tankName );
638             if(DirectionFlag == FLAG_L) 
[701]639                logit("","Called for start of request.\n***************************\n");
[154]640             else
[701]641                logit("","Called for end of request.\n***************************\n");
642        }
643
[154]644        if(DirectionFlag == FLAG_L)
645        {
646          *offp = pCurr->offset;
647          *acttp = pCurr->tStart;
648        }
649        else
650        {
651          *offp = pCurr->offset;
652          if(prev < 0)
[15]653          {
[154]654            /* DK Cleanup:  logit("t","Wave_serverV.GetOffset():  Requested trace is left of tank.\n");
655             */
656            *acttp = 0.0;
[15]657          }
658          else
659          {
[154]660            *acttp=t->chunkIndex[prev].tEnd;
[15]661          }
[154]662        }
663         
664        if ( _fDBG & _fALG )
665        {
666          if ( prev == -1 )
667            logit( "","  %s(GAP): no prev!\n",szFuncName[DirectionFlag]);
[15]668          else
[154]669            logit("","  %s(GAP): previous tEnd[%f]\n",
670                  szFuncName[DirectionFlag], t->chunkIndex[prev].tEnd);
671          logit( "","                      off[%ld] actt[%f]\n",*offp,*acttp );
672        }
673        ret = R_DONE;
674      }
675      else
676      {
677        /* OK, it's in this chunk somewhere, sick LocateExactOffset on it */
678        if ( _fDBG & _fALG )
679          logit( "","  %s(): tS in   [%f,%f]\n", szFuncName[DirectionFlag],
680                 pCurr->tStart, pCurr->tEnd );
681        /* First, create a pNext */
682        if(curr != (int)t->indxFinish)
683        {
684          next=curr+1;
685          if(next == t->indxMaxChnks)
[15]686          {
[154]687            next=0;
[15]688          }
[154]689          pNext=&(t->chunkIndex[next]);
[15]690        }
691        else
692        {
[154]693          pNext=0;
694        }
695        /* Then call LocateExactOffset */
696        ret = LocateExactOffset( t, pCurr, reqTime, DirectionFlag, offp, acttp,
697                                 pNext );
698        if(ret == R_FAIL)
699        {
700          logit("et","LocateExactOffset failed for tank %s.\n Reqt %f,Start %f, Finish %f,offset %d, InsrtPt %d,FLAG_L %d, GRACE_PERIOD %f\n",
701                t->tankName, reqTime,pCurr->tStart,pCurr->tEnd,pCurr->offset,t->inPtOffset,DirectionFlag==FLAG_L,GRACE_PERIOD);
[15]702        }
703      }
[154]704    }
705    else
706    {
707      /* Not there yet, keep going */
708      prev = curr;
709      curr+=1;
710      if(curr == t->indxMaxChnks)
[15]711      {
[154]712        curr=0;
[15]713      }
[154]714    }
[15]715  }  /* End of while() not finished loop */
716  if(prev == (int)t->indxFinish)
[154]717  {
[15]718    /* Request was too young, crap out, or do something to indicate failure */
719    if ( _fDBG & _fALG )
720      logit( "","  %s(): tS requested too young\n", szFuncName[DirectionFlag]);
721    ret = LocateEndOfTank( t,offp,acttp );
722  }
723  return(ret);
724}
725
726/* function: GetOffsetLeft()
727 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
728 *           double reqtS, starting time of reqested period
729 *   output: long int* offp, the offset that covers reqtS, which is set
730 *               to the start of next index when reqtS falls in a gap;
731 *           double* acttp, actual time that matches *offp;
732 *   return: R_FAIL or R_DONE
733 *
734 *  purpose: to find left offset in tank file (including associated
735 *           time stamp) for the requested time period;
736 *           called only once from _writeTraceDate();
737 *           see also symmetric function GetOffsetRight()
738 */
739static int GetOffsetLeft( TANK* t, double reqtE,
740                          long int *offp, double *acttp )
741{
742  return(GetOffset(t,reqtE,offp,acttp,FLAG_L));
743}
744
745
746/* function: GetOffsetRight()
747 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
748 *           double reqtE, ending time of reqested period;
749 *   output: long int* offp, the offset that covers reqtE, which is set
750 *               to the end of previous index when reqtE falls in a gap;
751 *           double* acttp, actual time that matches *offp;
752 *   return: R_FAIL or R_DONE
753 *
754 *  purpose: to find right offset in tank file (including associated
755 *           time stamp) for the requested time period;
756 *           called only once from _writeTraceDate();
757 *           see also symmetric function GetOffsetLeft()
758 */
759
760static int GetOffsetRight( TANK* t, double reqtE,
761                           long int *offp, double *acttp )
762{
763  return(GetOffset(t,reqtE,offp,acttp,FLAG_R));
764}
765
766/* function: LocateExactOffset()
767 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
768 *           DATA_CHUNK* idx, which meets both conditions listed below:
769 *             1) idx->tStart <= reqt,
770 *             2) idx->tEnd >= reqt;
771 *           double reqt, requested time;
772 *           int flag, either FLAG_L or FLAG_R;
773 *   output: long int* offp, offset located within idx;
774 *           double* acttp, actual time that matches *offp;
775 *   return: R_FAIL or R_DONE
776 *
777 *  purpose: to find exact offset in a given index structure that is
778 *           to the immediate left/right of the requested time;
779 *           could be called no more than once from GetOffsetLeft() or
780 *           GetOffsetRight() respectively (denoted by FLAG_L or FLAG_R)
781 */
782
783static int LocateExactOffset( TANK* t, DATA_CHUNK* idx, double reqt, int flag,
784                              long int* offp, double* acttp, DATA_CHUNK* next )
785{
786  int ret = R_FAIL;
787  long int off = -1L;
788  double actt = 0.0;
789  long int oE = -1L;
790  FILE* tfp = (FILE*) NULL;
[1493]791  TRACE2_HEADER trace_h = { 0 };
[15]792  int rsz = 0;
793  int tsz = 0;
794  int DFIP;
795  int tmp_point;
796  int RoughOff;
797  double RoughActt;
798
[371]799  /* Variables to handle recording of File I/O errors */
800  int iFileOffset, iFileBlockSize;
801  char * szFileTankName;
802  char szFileFunction[15];
803
[15]804  *offp = off;
805  *acttp = actt;
806   
807  if ( !t || !( tfp = t->tfp ) || !( rsz = t->recSize ) || 
808       !( tsz = t->tankSize) || !idx )
[154]809  {
810    logit( "","LocateExactOffset(): t[%0x] tfp[%0x] tsz[%0x] idx[%0x]\n",
811           t, tfp, tsz, idx );
812    goto abort;
813  }
[15]814   
815  if ( _fDBG & _fALG )
[154]816  {
817    logit( "","    LocateExactOffset(%c):  [%f,%f]\n",
818           flag == FLAG_L ? 'L':'R', idx->tStart, idx->tEnd );
819    logit( "","                           [%f]\n", reqt );
820  }
[15]821
822  if ( next )
[154]823  {
824    oE = next->offset;
825  }
[15]826  else
[154]827  {
828    double tE = 0.0;
829    if ( LocateEndOfTank( t, &oE, &tE ) != R_DONE )
830      goto abort;
831  }
[15]832  if ( LocateRoughOffset( t, idx->tStart, idx->tEnd, reqt,
833                          idx->offset, oE, flag, &off, &actt ) != R_DONE )
834  {
835    logit("et","Wave_serverV:LocateRoughOffset failed for tank %s within LocateExactOffset\n",
836          t->tankName );
837    goto abort;
838  }
839   
840  RoughOff=off;
841  RoughActt=actt;
842  /* wrap oE for ease of processing in the following while loop */
843  if ( oE == tsz )
844    oE = 0L;
845
846  /* FLAG_L and FLAG_R are distinguished by LocateRoughOffset();
847   * off and actt both mark the beginning of a record with FLAG_L,
848   * and they mark the end of a record with FLAG_R
849   */
850   
851  /* Calculate the distance from the current offset to the insertion point
852     and then monitor it as to prevent us from crossing it forwards or backwards.
853  */
854  /* First adjust to middle of the current record as opposed to the front or end */
855  if(flag == FLAG_L)
856  {
857    tmp_point=off+(int)(0.5*rsz);
858  }
859  else
860  {
861    tmp_point=off-(int)(0.5*rsz);
862  }
863
864  /* Next Calculate the Distance From Insertion Point */
865  DFIP=t->inPtOffset-tmp_point;
866  while(DFIP < 0)
867  {
868    DFIP+=tsz;
869  }
870  while(DFIP >tsz)
871  {
872    DFIP-=tsz;
873  }
874  /* Now, everytime the offset is moved, adjust the DFIP */
875
876
877  /*  Okay, here's the new plan.  We're gonna overhaul this, so that we start checking
878      time windows for each record, instead of just checking the start or
879      end of the record.
880
881      The logic is:
882      starting with the record that is returned from LocateRoughOffset(), read
883      the start and end times of the current record.  If the reqt is within
884      the record start and endtime (non-inclusive), then we're done, ship the
885      starttime and offset for that record (for FLAG_L, for FLAG_R, ship the
886      endtime and offset+recsz).  If the record does not contain the reqt, then
887      if the reqt < the starttime of the record, throw the search engine in reverse,
888      keeping track of the current offset and starttime or offset and endtime.
889      While the reqt is greater or equal to the endtime of the record, keep going
890      until we hit the index or tank wall(Insertion point).  If we hit the wall,
891      blow up, and goto OHCRAP!!!
892
893      Reverse:
894      Go back the other direction until we pass the reqt going the other way.
895      Then return the previous offset and Start or EndTime depending on L or R
896  */
897
898  /* need search back and forth */
899  if ( flag == FLAG_L )
900  {
[1493]901    if ( ReadBlockData(tfp, off, (long int) sizeof(TRACE2_HEADER),
[15]902                       (char*) &trace_h ) != R_DONE )
[371]903    {
904      strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
905      szFileFunction[sizeof(szFileFunction)]= 0;
906      iFileOffset     = off;
[1493]907      iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]908      szFileTankName  = t->tankName;   /* don't copy just point */
[15]909      goto ReadBlockDataFailed;
[371]910    }
[765]911    /* if reqt is to the right keep going */
912    while ((trace_h.endtime + GRACE_PERIOD) < reqt) 
[15]913    {
914      off += rsz;
915      DFIP-=rsz;
916      if(DFIP <= 0 || DFIP >= tsz)
917      {
918        logit("t","Failed DFIP comparison #1\n");
919        goto OHCRAP;
920      }
921
922      /* for the left boundary, set off = 0 if off == tsz */
923      if ( off >= tsz )
924        off =0;
925
[1493]926      if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
[154]927                          (char*) &trace_h ) != R_DONE )
[371]928      {
929        strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
930        szFileFunction[sizeof(szFileFunction)]= 0;
931        iFileOffset     = off;
[1493]932        iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]933        szFileTankName  = t->tankName;   /* don't copy just point */
[15]934        goto ReadBlockDataFailed;
[371]935      }
[15]936    }  /* End while(acct < reqt) */
937
[765]938    if(trace_h.starttime  - GRACE_PERIOD <= reqt)
[15]939    {
940      /* We've found our spot.  trace_h.starttime <= reqt <= trace_h.endtime.
941         Pack it up and go home */
942      *acttp=trace_h.starttime;
943      *offp=off;
944    }
945    else
946    {
[154]947      /* There was some sort of a minor snaffu.  Throw it in reverse,
948         but keep track of what we've got.
949      */
[15]950      int tempOff=-1;
951      double tempStart=-1.0;
952
953      while (trace_h.starttime - GRACE_PERIOD > reqt )
[765]954        /* Use GRACE_PERIOD to account for sloppy timestamps */
[15]955      {
956        /* Keep going backwards until we hit the wall, or get to a good time */
957        tempOff=off;
958        tempStart=trace_h.starttime;
959        off -= rsz;
960        DFIP += rsz;
961        if(DFIP <= 0 || DFIP >= tsz)
[154]962        {
963          logit("t","Failed DFIP comparison #2\n");
964          goto OHCRAP;
965        }
[15]966        if ( off < 0L )
967          off += tsz;
[1493]968        if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
[154]969                            (char*) &trace_h ) != R_DONE )
[371]970        {
971          strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
972          szFileFunction[sizeof(szFileFunction)]= 0;
973          iFileOffset     = off;
[1493]974          iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]975          szFileTankName  = t->tankName;   /* don't copy just point */
[15]976          goto ReadBlockDataFailed;
[371]977        }
[15]978      }
979      /* OK, we're here, I guess */
[765]980      if(trace_h.starttime - GRACE_PERIOD <= reqt && 
981         reqt <= tempStart - GRACE_PERIOD)
[15]982      {
983        /* OK, we are definitely here now.
984           We just need to figure out where we are.
985        */
[765]986        if(reqt < trace_h.endtime + GRACE_PERIOD )
[15]987        {
988          /* We can get atleast one sample from this rec, so
989             use it.
990          */
991          *offp=off;
992          *acttp=trace_h.starttime;
993        }
994        else
995        {
996          /* We can't get any data out of this sample, so let's
[154]997             go back to the one where we just were.
[15]998          */
999          *offp=tempOff;
1000          *acttp=tempStart;
1001        }
1002      }
1003      else  /* if(trace_h.starttime - GRACE_PERIOD < reqt 
[154]1004               && reqt <= tempStart - GRACE_PERIOD) */
[15]1005      {
1006        /* Anything that lands here would be a bug */
1007        logit("t","Lost in LocateExactOffset for tank %s\n", t->tankName );
1008        logit("t","th.start %f th.end %f off %d tempOff %d tempStart %f reqt %f\n",
1009              trace_h.starttime,trace_h.endtime,off,tempOff,tempStart,reqt);
1010      }
1011    } /* End else from if(trace_h.starttime <= reqt) */
1012  }  /* End   if ( flag == FLAG_L ) */
1013  else  /*  flag == FLAG_R */
1014  {
1015    long int tmp = off-rsz;
1016
1017    if(tmp < 0)
1018      tmp+=tsz;
1019
[1493]1020    if ( ReadBlockData(tfp, tmp, (long int) sizeof(TRACE2_HEADER),
[15]1021                       (char*) &trace_h ) != R_DONE )
[371]1022    {
1023      strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1024      szFileFunction[sizeof(szFileFunction)]= 0;
1025      iFileOffset     = tmp;
[1493]1026      iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]1027      szFileTankName  = t->tankName;   /* don't copy just point */
[15]1028      goto ReadBlockDataFailed;
[371]1029    }
[154]1030    while (trace_h.starttime > reqt)  /* if reqt is to the left keep going */
[15]1031    {
1032      off=tmp;
1033      tmp-=rsz;
1034      DFIP+=rsz;
1035      if(DFIP <= 0 || DFIP >= tsz)
1036      {
1037        logit("t","Failed DFIP comparison #3\n");
1038        goto OHCRAP;
1039      }
1040
1041      /* for the left boundary, set off = 0 if off == tsz */
1042      if ( tmp < 0 )
1043        tmp += tsz;
1044     
[1493]1045      if ( ReadBlockData( tfp, tmp, (long int) sizeof(TRACE2_HEADER),
[154]1046                          (char*) &trace_h ) != R_DONE )
[371]1047      {
1048        strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1049        szFileFunction[sizeof(szFileFunction)]= 0;
1050        iFileOffset     = tmp;
[1493]1051        iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]1052        szFileTankName  = t->tankName;   /* don't copy just point */
[15]1053        goto ReadBlockDataFailed;
[371]1054      }
[15]1055    }  /* End while(acct < reqt) */
1056
1057    if(trace_h.endtime + GRACE_PERIOD >= reqt)
1058    {
1059      /* We've found our spot.  trace_h.starttime < reqt <= trace_h.endtime.
1060         Pack it up and go home */
1061      *acttp=trace_h.endtime;
1062      *offp=off;
1063    }
1064    else
1065    {
[154]1066      /* There was some sort of a minor snaffu.  Throw it in reverse,
1067         but keep track of what we've got.
1068      */
[15]1069      double tempEnd=trace_h.endtime;
1070
1071      while (trace_h.endtime + GRACE_PERIOD < reqt)
[765]1072        /* Use GRACE_PERIOD to account for sloppy timestamps */
[15]1073      {
1074        /* Keep going backwards until we hit the wall, or get to a good time */
1075        tmp=off;
1076        off += rsz;
1077        DFIP -= rsz;
1078        if(DFIP <= 0 || DFIP >= tsz)
[154]1079        {
1080          logit("t","Failed DFIP comparison #4\n");
1081          goto OHCRAP;
1082        }
[15]1083        if ( off >=tsz )
1084          off=0;
1085        tempEnd=trace_h.endtime;
[1493]1086        if ( ReadBlockData( tfp, tmp, (long int) sizeof(TRACE2_HEADER),
[154]1087                            (char*) &trace_h ) != R_DONE )
[371]1088        {
1089          strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1090          szFileFunction[sizeof(szFileFunction)]= 0;
1091          iFileOffset     = tmp;
[1493]1092          iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]1093          szFileTankName  = t->tankName;   /* don't copy just point */
[15]1094          goto ReadBlockDataFailed;
[371]1095        }
[15]1096      }
1097      /* OK, we're here, I guess */
1098      if(tempEnd + GRACE_PERIOD <= reqt && reqt <= trace_h.endtime + GRACE_PERIOD)
1099      {
1100        /* OK, we are definitely here now.
1101           We just need to figure out where we are.
1102        */
1103        if(reqt >= trace_h.starttime + GRACE_PERIOD)
1104        {
1105          /* We can get atleast one sample from this rec, so
1106             use it.
1107          */
1108          *offp=off;
1109          *acttp=trace_h.endtime;
1110        }
1111        else
1112        {
1113          /* We can't get any data out of this record, so let's
1114             go back to the one where we just were.
1115          */
1116          *offp=tmp;
1117          *acttp=tempEnd;
1118        }
1119      }
1120      else  /* if(tempEnd < reqt && reqt < trace_h.endtime + GRACE_PERIOD) */
1121      {
1122        /* Anything that lands here would be a bug */
1123        logit("t","Lost in LocateExactOffset for tank %s\n", t->tankName);
1124        logit("t","th.start %f th.end %f off %d tempOff %d tempEnd %f\n",
1125              trace_h.starttime,trace_h.endtime,off,tmp,tempEnd);
1126      }
1127    } /* End else from if(trace_h.endtime >= reqt) */
1128  }  /* end else from if FLAG_L */
1129
1130  ret = R_DONE;
1131
[154]1132 ReadBlockDataFailed:
[15]1133  if ( ret != R_DONE )
1134  {
[371]1135    IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
[15]1136    goto abort;
1137  }
[154]1138 OHCRAP:
[15]1139  if ( ret != R_DONE )
1140  {
1141    logit("t","Wave_server: LocateExactOffset(): reached the index boundary without reaching reqt.\n reqt %f off %d oE %d inspt %d idxofst %d\n",
[154]1142          reqt,off,oE,t->inPtOffset,idx->offset);
[15]1143    logit("t","Wave_server: LocateExactOffset(): DFIP %d,tsz %d, RoughOff %d, RoughActt %f, Tank %s\n",DFIP,tsz,RoughOff,RoughActt,t->tankName);
1144  }
[154]1145 abort:
[15]1146  if ( ret != R_DONE )
1147    logit( "","LocateExactOffset(): failed\n" );
1148  return ret;
1149}
1150
1151/* function: LocateRoughOffset()
1152 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
1153 *           double tS, starting time denoting beginning of range,
1154 *           double tE, ending time denoting end of range,
1155 *           double reqt, user requested time,
1156 *           long int oS, starting offset corresponding to tS,
1157 *           long int oE, ending offset corresponding to tE;
1158 *           int flag, either FLAG_L or FLAG_R;
1159 *   output: long int* offp, offset located within the range of [oS,oE],
1160 *           double* acttp, actual time that matches *offp;
1161 *   return: R_FAIL or R_DONE
1162 *
1163 *  purpose: to find rough offset in a given index structure that is
1164 *           close to the requested time, so that sequential search
1165 *           in this neighborhood would be inexpensive;
1166 *           called only by GetExactOffset() or GetExactOffset(), and
1167 *           FLAG_L or FLAG_R is passed as flag for differentiation
1168 *
1169 *     note: tanksize is multiple of record size, otherwise disastous
1170 *           alignment of block data read error ensues;
1171 */
1172
[1753]1173/*******************************************************************************
1174*******************************************************************************
1175WARNING!!! BUG IN LocateRoughOffset()
1176
1177 At first glance, there appears to be a bug in wave_serverV that affects tank
1178files over 1,073,741,823 bytes in size.  Code within LocateRoughOffset() in
1179serve_trace.c, does a buffer calculation, that potentially overflows a signed
1180integer value when the tanksize is >= 1 GB.
1181
1182The error affects only data retrieval, and only when the offset of the
1183chronological-start of the tank is near the end of the tank.  Specifically,
1184if  TankSize + oS (offset of chronological-start) >= 2GB, then an error
1185will result, and no data will be returned for the tank.  (Once the offset
1186wraps around to the beginning of the tank again, everything should
1187function normally)
1188
1189Since your tank is just barely over 1 GB, you are seeing the errors only
1190when the chronological-start offset gets near the end of the tank.  If you
1191were using tank sizes ~ 2GB, you would experience the problem
1192constantly.
1193
1194The problem appears to result from a signed integer overflow of tmpoE
1195at Line 1155 of serve_trace.c  (LocateRoughOffset()).
1196An example from your logfile:
1197
1198> LocateRoughOffset(): warning! oE[1029091392] tmpoE[-2145876160] off[2145508992] for tank i:\nano1_MDH1_EP1_NC.tnk
1199>    ==> offset == [-2145877024] < 0
1200
1201
1202oE = the chronological-end of the tank  (once the tank has wrapped, the chronological-end and chronological-start are adjacent.)
1203tmpoE = the chronological-end of the tank + the tanksize
1204tmpoE = 1029091392(oE) + 1,119,999,744 (tanksize) =   0x801883E0 which as an unsigned int = -2145877024
1205which is < 0. This is treated as an error, and an error flag is returned to the client instead of the requested data.
1206
1207
1208This is my analysis based upon 30 minutes of inspection.  Besides the error that I describe here,
1209there may be other issues with tanksizes > 1 GB.  A reliable code fix would require further inspection
1210and thorough testing.  Also, I may have mis-analyzed the code and error, and the problem could
1211potentially be something different.
1212
1213An immediate fix, would be to limit your tank files to < 1 GB.  (This may be impractical for you, if
1214you have a good deal of data in the current tanks that you do not wish to lose, and have no way
1215to transfer it.)
1216
1217Unless someone disagrees with my diagnosis, or wishes to immeidately have the problem investigated
1218further, it would probably be a good idea to send a message out to the EW list, warning against
1219using tanksizes >= 1GB.
1220
1221DK 2005/03/09  (comment from email 2004/01/29)
1222*******************************************************************************
1223*******************************************************************************/
1224
[15]1225static int LocateRoughOffset( TANK* t, double tS, double tE, double reqt,
1226                              long int oS, long int oE, int flag,
1227                              long int* offp, double* acttp )
1228{
1229  int ret = R_FAIL;
1230  long int off = -1L;
1231  double actt = 0.0;
1232  long int tmpoS = oS;
1233  long int tmpoE = oE;
1234  FILE* tfp = (FILE*) NULL;
[1493]1235  TRACE2_HEADER trace_h = { 0 };
[15]1236  long int nRec = 0L;
1237
[371]1238  /* Variables to handle recording of File I/O errors */
1239  int iFileOffset, iFileBlockSize;
1240  char * szFileTankName;
1241  char szFileFunction[15];
1242  int  bIssueIOStatusError = FALSE;
1243
[15]1244  *offp = off;
1245  *acttp = actt;
1246  if ( !t || !( tfp = t->tfp ) || !( t->recSize ) )
[154]1247  {
1248    logit( "","LocateRoughOffset(): t[%0x] tfp[%0x] recSize[%d]\n",
1249           t, t?t->tfp:0, t?t->recSize:0 );
1250    goto abort;
1251  }
[15]1252  if ( tE - tS < DBL_FLOAT_EPSILON )
[154]1253  {
1254    logit( "","LocateRoughOffset(): [tE,tS] range too small for tank %s\n",
1255           t->tankName );
1256    goto abort;
1257  }
[765]1258  if ( ( reqt < tS - GRACE_PERIOD) || ( reqt > tE + GRACE_PERIOD) )
[154]1259  {
[765]1260    logit( "","LocateRoughOffset(): reqt[%f] out of range for tank %s\n",
[154]1261           reqt, t->tankName );
1262    goto abort;
1263  }
[15]1264   
1265  if ( oS == t->tankSize ) tmpoS = 0L;
1266  if ( oE <= oS ) tmpoE += t->tankSize;
1267  nRec = (long int)( ( tmpoE-tmpoS ) / t->recSize * ( reqt-tS ) / ( tE-tS ) );
1268  off = tmpoS + nRec * t->recSize;
1269  if ( off > tmpoE )
[154]1270  {
1271    logit( "","LocateRoughOffset(): warning! oE[%ld] tmpoE[%ld] off[%ld] for tank %s\n",
1272           oE, tmpoE, off, t->tankName );
1273    off = tmpoE - t->recSize;
1274  }
[15]1275  if ( off >= t->tankSize ) off -= t->tankSize;
1276
1277  if ( _fDBG & _fALG ) logit( "","      LocateRoughOffset( ): " );
[1493]1278  if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
[15]1279                      (char*) &trace_h ) != R_DONE )
[371]1280  {
1281    logit( "","LocateRoughOffset(): ERROR ReadBlockData() failed\n" );
1282    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1283    szFileFunction[sizeof(szFileFunction)]= 0;
1284    iFileOffset     = off;
[1493]1285    iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]1286    szFileTankName  = t->tankName;   /* don't copy just point */
1287    bIssueIOStatusError = TRUE;
[15]1288    goto abort;
[371]1289  }
[15]1290  if ( _fDBG & _fALG ) logit( "","                            off[%ld], tS[%f]\n",
1291                              off,trace_h.starttime );
1292
1293  if (flag == FLAG_L)
[154]1294  {
1295    *offp = off;
1296    *acttp = trace_h.starttime;
1297  }
[15]1298  else
[154]1299  {
1300    *offp = off + t->recSize;
1301    *acttp = trace_h.endtime;
1302  }
[15]1303
1304  ret = R_DONE;
[154]1305 abort:
[15]1306  if ( ret != R_DONE )
[371]1307  {
1308    if(bIssueIOStatusError)
1309    {
1310      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1311      bIssueIOStatusError = FALSE;
1312    }
1313
[15]1314    logit( "","LocateRoughOffset(): failed\n" );
[371]1315  }
[15]1316  return ret;
1317}
1318
1319/* function: LocateStartOfTank()
1320 *  purpose: get offset and time stamp at the start of oldest index
1321 *    input: TANK* t
1322 *   output: long int* offp, which is set to t->indxStart->offset;
1323 *           double* acttp, which is set to t->indxStart->tStart
1324 *   return: R_FAIL or R_DONE
1325 *
1326 *  purpose: to find offset and timestamp at beginning of tank
1327 *           called by various functions
1328 */
1329
1330static int LocateStartOfTank( TANK* t, long int* offp, double* acttp )
1331{
1332  int ret = R_FAIL;
1333  DATA_CHUNK* idx = NULL;
1334   
1335  *offp = -1L;
1336  *acttp = 0.0;
1337
1338  if ( !t || !( idx = IndexOldest( t ) ) ) goto abort;
1339
1340  *offp = idx->offset;
1341  *acttp = idx->tStart;
1342
1343  if ( _fDBG & _fPRT )
1344    logit( "","    LocateStartOfTank():    indxS->off[%ld] indxS->sT[%f]\n",
1345           *offp, *acttp );
1346  ret = R_DONE;
[154]1347 abort:
[15]1348  if ( ret != R_DONE )
1349    logit( "","LocateStartOfTank(): failed\n" );
1350  return ret;
1351}
1352
1353/* function: LocateEndOfTank()
1354 *  purpose: get offset and time stamp at the end of youngest index
1355 *    input: TANK* t, with following assumptions:
1356 *               t->tfp opened in "+br" mode;
1357 *               t->inPtOffset is valid insertion point;
1358 *   output: long int* offp, which is set to t->inPtOffset;
1359 *           double* acttp, which is set to t->indxStart->tStart
1360 *   return: R_FAIL or R_DONE
1361 *
1362 *  purpose: to find offset and timestamp at end of tank;
1363 *           called by various functions
1364 */
1365
1366static int LocateEndOfTank( TANK* t, long int* offp, double* acttp )
1367{
1368  int ret = R_FAIL;
1369  FILE* tfp = (FILE*) NULL;
[1493]1370  TRACE2_HEADER trace_h = { 0 };
[15]1371  long int off = -1L;
1372  double actt = 0.0;
[371]1373
1374  /* Variables to handle recording of File I/O errors */
1375  int iFileOffset, iFileBlockSize;
1376  char * szFileTankName;
1377  char szFileFunction[15];
1378  int  bIssueIOStatusError = FALSE;
1379 
[15]1380  *offp = off;
1381  *acttp = actt;
1382
1383  if ( !t || !( tfp = t->tfp ) ) goto abort;
1384
1385  if ( _fDBG & _fPRT )
1386    logit( "","    LocateEndOfTank():      ");
1387  off = t->inPtOffset;
1388  /* in the case off == 0L, the tank has just wrapped to 0L, it is
1389   * convenient to set off = t->tankSize for subsequent processing
1390   */
1391  if ( !off ) off = t->tankSize;
1392  if ( off % t->recSize )
[154]1393  {
[1493]1394    logit( "","LocateEndOfTank(): misaligned TRACE2_HEADER records for tank %s\n",
[154]1395           t->tankName );
1396    goto abort;
1397  }
[15]1398
[1493]1399  if ( ReadBlockData( tfp, off - t->recSize, (long int) sizeof(TRACE2_HEADER),
[15]1400                      (char*) &trace_h ) != R_DONE )
[371]1401  {
1402    logit( "","LocateEndOfTank(): ERROR ReadBlockData() failed\n" );
1403    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1404    szFileFunction[sizeof(szFileFunction)]= 0;
1405    iFileOffset     = off - t->recSize;
[1493]1406    iFileBlockSize  = sizeof(TRACE2_HEADER);
[371]1407    szFileTankName  = t->tankName;   /* don't copy just point */
1408    bIssueIOStatusError = TRUE;
[15]1409    goto abort;
[371]1410  }
[15]1411
1412  *offp = off;
1413  *acttp = trace_h.endtime;
1414  if ( (_fDBG & _fALG) &&
1415       ( trace_h.endtime + DBL_FLOAT_EPSILON < IndexYoungest( t )->tEnd ||
1416         trace_h.endtime - DBL_FLOAT_EPSILON > IndexYoungest( t )->tEnd ) )
[154]1417  {
1418    logit( "","LocateEndOfTank(): warning! young->tEnd[%f] != eT[%f] for tank %s\n", 
1419           IndexOldest( t )->tEnd, *acttp, t->tankName );
1420  }
[15]1421
1422  if ( _fDBG & _fPRT )
1423    logit( "","                            inPt [%ld] endtime[%f]\n",
1424           off, *acttp );
1425  ret = R_DONE;
[371]1426
[154]1427 abort:
[15]1428  if ( ret != R_DONE )
[371]1429  {
1430    if(bIssueIOStatusError)
1431    {
1432      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1433      bIssueIOStatusError = FALSE;
1434    }
1435
[15]1436    logit( "","LocateEndOfTank(): failed\n" );
[371]1437  }
[15]1438  return ret;
1439}
1440
1441/* function: CopyReqData()
1442 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
1443 *           long int oS, starting offset for reqested period;
1444 *           long int oE, ending offset for reqested period,
1445 *             due to the bias flag in GetOffset, oE extends beyond
1446 *             the message with ending time tE in _writeTraceData{Raw|Ascii}(),
1447 *             i.e. even if [tS,tE] is very small, oS != oE,
1448 *             in other words, if tS == tE, the entire tank need be copied;
1449 *   output: char** data, records of t->recSize bytes each;
1450 *   return: R_FAIL or R_DONE
1451 *
1452 *  purpose: to copy data from specified range in tank to memory;
1453 *           called only once from main _writeTraceData{Raw|Ascii}()
1454 */
1455
1456static int CopyReqData( TANK* t, long int oS, long int oE,
1457                        char** datap, long int* sizep )
1458{
1459  int ret = R_FAIL;
1460  long int tsz = 0;          /* tank size */
1461  long int sz1 = 0, sz2 = 0; /* 2 fread()'s needed when oS >= oE */
1462  FILE* tfp = (FILE*) NULL;
1463
[371]1464  /* Variables to handle recording of File I/O errors */
1465  int iFileOffset, iFileBlockSize;
1466  char * szFileTankName;
1467  char szFileFunction[15];
1468  int  bIssueIOStatusError = FALSE;
1469
[15]1470  if ( _fDBG & _fALG )
1471    logit( "","CopyReqData():  offsets[%ld,%ld] for tank %s\n",oS,oE,
1472           t->tankName);
1473
1474  *datap = (char*) NULL;
1475  *sizep = 0;
1476  /* assume tank file already opened in mode "rb+" */
1477  if ( !t || !( tfp = t->tfp ) || !( tsz = t->tankSize ) ) goto abort;
1478  if ( oS < 0 || oE < 0 ) goto abort;
1479  if ( oS > tsz || oE > tsz ) goto abort;
1480   
1481  if ( oS < oE )
[154]1482  {
1483    sz1 = oE - oS;
1484    sz2 = 0;
1485  }
[15]1486  else /* ( oS >= oE ) */
[154]1487  {
1488    sz1 = tsz - oS;
1489    sz2 = oE;
1490  }
[15]1491  if ( !sz1 && !sz2 ) goto mem_abort;
1492  *datap = (char*)malloc( ( sz1 + sz2 ) * sizeof( char ) );
1493  if ( !( *datap ) ) goto mem_abort;
1494
1495  if ( sz1 && ReadBlockData( tfp, oS, sz1, &( (*datap)[0] ) ) != R_DONE )
[154]1496  {
1497    logit( "", "CopyReqData(): read [%ld] bytes failed for tank %s\n",sz1,
1498           t->tankName );
[371]1499    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1500    szFileFunction[sizeof(szFileFunction)]= 0;
1501    iFileOffset     = oS;
1502    iFileBlockSize  = sz1;
1503    szFileTankName  = t->tankName;   /* don't copy just point */
1504    bIssueIOStatusError = TRUE;
[154]1505    goto abort;     
1506  }
[15]1507   
1508  if ( sz2 && ReadBlockData( tfp, 0L, sz2, &( (*datap)[sz1] ) ) != R_DONE )
[154]1509  {
1510    logit( "", "CopyReqData(): read [%ld] bytes failed for tank %s\n",sz1,
1511           t->tankName );
[371]1512    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1513    szFileFunction[sizeof(szFileFunction)]= 0;
1514    iFileOffset     = 0L;
1515    iFileBlockSize  = sz2;
1516    szFileTankName  = t->tankName;   /* don't copy just point */
1517    bIssueIOStatusError = TRUE;
1518    goto abort;     
[154]1519  }
[15]1520
1521  *sizep = sz1 + sz2;
1522  ret = R_DONE;
[154]1523 mem_abort:
[15]1524  if ( ret == R_FAIL )
1525    logit( "","CopyReqData(): failed to malloc [%ld] bytes\n", sz1+sz2 );
[154]1526 abort:
[371]1527  if ( ret != R_DONE ) 
1528  {
1529    if(bIssueIOStatusError)
1530    {
1531      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1532      bIssueIOStatusError = FALSE;
1533    }
1534
[15]1535    if ( *datap )
1536      FreeReqData( *datap );
1537    logit( "","CopyReqData(): failed\n" );
1538  }
1539  return ret;
1540}
1541
1542/* function: ReadBlockData()
1543 *    input: FILE* file, file opened in "br+" mode
1544 *           long int offset, start of block to be read
1545 *           long int length, size of block to be read
1546 *   output: char* data, data read in from file
1547 *   return: R_SKIP, if length == 0,
1548 *           R_FAIL or R_DONE otherwise
1549 *
1550 *  purpose: to read data in specified range in tank to memory;
1551 *           called by various functions
1552 */
1553
1554static int ReadBlockData( FILE* file, long int offset, long int length,
1555                          char* data )
1556{
1557  int ret = R_FAIL;
1558
1559  if ( _fDBG & _fPRT )
1560    logit( "","ReadBlockData(): offset[%ld] length[%ld]\n",
1561           offset,length );
1562  /* assume tank file already opened in mode "rb+" */
1563  if ( !file )
[154]1564  {
1565    logit( "","    ==> filep == NULL\n" );
1566    goto abort;
1567  }
[15]1568  if ( offset < 0 )
[154]1569  {
1570    logit( "","    ==> offset == [%ld] < 0\n",offset );
1571    goto abort;
1572  }
[15]1573  if ( length <= 0 )
[154]1574  {
1575    logit( "","    ==> length == 0\n" );
1576    goto skip;
1577  }
[15]1578  if ( !data )
[154]1579  {
1580    logit( "","    ==> data == NULL\n" );
1581    goto abort;
1582  }
[15]1583
1584  if ( fseek( file, offset, SEEK_SET ) != 0 )
[154]1585  {
1586    logit( "","ReadBlockData(): fseek failed on offset [%ld]\n",offset );
1587    goto abort;
1588  }
[15]1589  if( fread( (char*)data, length, 1, file ) != 1 ) 
[154]1590  {
1591    logit( "", "ReadBlockData(): fread failed on length [%ld]\n",length );
1592    goto abort;
1593  }
[15]1594
1595  ret = R_DONE;
[154]1596 skip:
[15]1597  if ( ret == R_FAIL )
[154]1598  {
1599    logit( "","ReadBlockData(): warning! skips upon 0 length\n" );
1600    ret = R_SKIP;
1601  }
1602 abort:
[15]1603  if ( ret == R_FAIL )
1604    logit( "","ReadBlockData(): failed\n");
1605
1606  return ret;
1607}
1608
1609/* function: FreeReqData()
1610 *    input: char* data, requested data to be freed
1611 *   output: None
1612 *   return: R_SKIP, upon NULL pointer;
1613 *           R_DONE, otherwise
1614 *
1615 *  purpose: to free memory allocated in CopyReqData();
1616 *           called only once from main _writeTraceData{Raw|Ascii}()
1617 */
1618
1619static int FreeReqData( char* data )
1620{
1621  int ret = R_SKIP;
1622  if ( data ) {
1623    free( data );
1624    ret = R_DONE;
1625  }
1626  return ret;
1627}
1628
[765]1629
1630
[2883]1631#if defined(_LINUX) || defined(_MACOSX)
1632#undef roundup
[1903]1633#else
[2883]1634static
[1903]1635#endif
[2883]1636
[1903]1637int roundup(double dIn)
[765]1638{
1639  if(dIn < 0)
1640    return((int)(dIn - 0.5));
1641  else
1642    return((int)(dIn + 0.5));
1643}  /* end roundup() */
1644
1645int SendReqDataAscii_AndThisTimeWeMeanIt(char * data, int iDataByteLen, 
1646                                         double tReqStart, double tReqEnd,
1647                                         double tTankStart, double tTankEnd,
1648                                         int iRecordSize, TANK * t, int soc,
1649                                         char * reqid, char * fill,
1650                                         double acttS, double acttE)
1651{
1652  /* We know we have data, so now we need to process the data.
1653         * First find the start time.
1654  */
1655
1656  double dActStartTime;
1657  double dSampRate;
1658  int    iNumSamplesApart;
1659  int    bFirstBlock;
1660  double tLastSample;
1661  int    iDataSize;
1662  int    iLastSample;
1663  int    iFirstSample;
1664  int    samp_pos;
[1493]1665  int    hsz = sizeof(TRACE2_HEADER);
[765]1666  char*  blk_buf = (char*) NULL;
1667  int    blk_pos = 0L;
1668  int    i;
1669  int    ival = 0;
1670  int    retVal;
[1493]1671  TRACE2_HEADER * pTH;
[765]1672  char * pCurrentRecord;
1673  int    nsamp;
1674
1675
1676
1677  /* Loop through all the trace_buf in the buffer, sending the samples
1678   * requested plus any fill needed in between */
1679  for(pCurrentRecord = data; 
1680      pCurrentRecord < data+iDataByteLen; 
1681      pCurrentRecord += iRecordSize) 
1682  {
1683    if(pCurrentRecord  == data)
1684      bFirstBlock = TRUE;
1685    else
1686      bFirstBlock = FALSE;
1687
[1493]1688    pTH = (TRACE2_HEADER *) pCurrentRecord;
[765]1689
1690
1691    if ( _fDBG & _fPRT ) trace_log( pTH );
1692
1693    if (bFirstBlock) 
1694    {       /* First time through the loop: set values for starttime and
1695             * samplerate for ascii reply header */
1696      dActStartTime = DBL_FLOAT_NA;  /* -1.0 */
1697      dSampRate = pTH->samprate;
1698
1699      /*  THIS CODE ASSUMES THAT THERE WERE NO RECORDS(trace_bufs) BEFORE
1700          THIS ONE WHERE:
1701          pTH->endtime > (tReqStart - MINIMUM_GAP_SIZE/samprate)
1702          GIVEN THIS ASSUMPTION, WE CAN ENFORCE STRICT TIMESTAMPS FOR
1703          DETERMININING IF A FILL SAMPLE SHOULD BE INSERTED BEFORE THE
1704          FIRST SAMPLE IN THE FIRST PACKET
1705          DK 08/10/01
1706       *********************************************************************/
1707
1708     
1709
1710      if ( pTH->samprate < DBL_FLOAT_EPSILON )
1711      {
1712        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): samprate too small for tank %s\n",
1713               t->tankName );
1714        goto abort;
1715      }
1716
1717      /* if the request starts left of the tank */
1718      if ( tReqStart < tTankStart )   
1719        dActStartTime = pTH->starttime;  /* dActStartTime = tank start time */
1720      else
1721      {
1722        /* The requested start time is within the tank */
1723        /* set ActStartTime = [start time of this packet] - (X samples * dSampRate) */
1724        dActStartTime = pTH->starttime;
1725       
1726        iNumSamplesApart = roundup((tReqStart - pTH->starttime) * dSampRate);
1727
1728        dActStartTime += (iNumSamplesApart/dSampRate);
1729      }
1730
1731      tLastSample = dActStartTime;
1732
1733      /* Determine datatype size */
1734      if ( strcmp( pTH->datatype, "i2" ) == 0 ||
1735           strcmp( pTH->datatype, "s2" ) == 0 )
1736      {
1737        iDataSize = D_SIZE_I2;
1738      }
1739      else if ( strcmp( pTH->datatype, "i4" ) == 0 ||
1740                strcmp( pTH->datatype, "s4" ) == 0 )
1741      {
1742        iDataSize = D_SIZE_I4;
1743      }
1744      else
1745      {
1746        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): unexpected data type for tank %s\n",
1747               t->tankName );
1748        goto abort;
1749      }
1750
1751      /* Send the header */
1752      if ( SendHeader( soc, t, reqid, "F", dActStartTime, dSampRate, 0,
1753                       NO_NEWLINE ) != R_DONE )
1754      {
1755        logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): SendHeader #4 failed for tank %s\n",
1756              t->tankName );
1757        goto abort;
1758      }
1759    }  /*end if (bFirstBlock)*/
1760
1761    /* make sure the trace_buf is not unreasonably sized */
1762    if((hsz + pTH->nsamp * iDataSize) > iRecordSize)
1763    {
1764      logit("t","ERROR: SendReqDataAscii_ATWMI(): The following tracebuf exceeded the "
1765                "maximum record size[%d] for this tank! Returning!\n",
1766            iRecordSize);
1767      trace_log( pTH );
1768      goto abort;
1769    }
1770
1771
1772    /* Check for fill, unless this is the first record AND the request is
1773       left of the tank.  So if the first requested sample is in a GAP, we
1774       will issue fill as the first sample. DK 08/09/2001 */
1775    if (bFirstBlock) 
1776    {
1777      if (tLastSample + (1.0/pTH->samprate ) <= 
1778          pTH->starttime ) 
1779      {
1780        if ( fill )
1781        {
1782         nsamp = roundup( pTH->samprate *
1783                           ( pTH->starttime - tLastSample ));
1784          if ( BulkSendFill( soc, fill,nsamp ) != R_DONE )
1785          {
1786            logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #2 failed for tank %s\n",
1787                  t->tankName );
1788            goto abort;
1789          }
1790        }
1791      }
1792    }
1793    else
1794    {
1795      if (tLastSample + ( MINIMUM_GAP_SIZE / pTH->samprate ) <= 
1796          pTH->starttime ) 
1797      {
1798        if ( fill )
1799        {
[1084]1800          /* We need to set nsamp to the number of samples between
1801             the last sampletime and the next sampletime, but remember
1802             to take into account that there should always be a
1803             1/samprate gap between samples.  This fixes a bug
1804             that caused 1 extra fill value to be inserted.
1805             DavidK 08/24/01 */
[1085]1806          /* Removed (-1) from end of statement.  The 08/24/01 fix was
1807             done because we were ending up with one(1) too many samples
1808             of fill when we missed a tracebuf and had to fill it in.
1809             Unfotunately that fix removed 2 samples of fill, instead of
1810             just one(1).  It removed MINIMUM_GAP_SIZE(~1.3) and then removed
1811             one(1) additional at the end of the statement.  The (-1) is now
1812             removed so that we theoretically end up with the correct number
1813             of samples.
1814             This fix was made in response to a complaint by Carol Bryant
1815             about problems with 99.7 Hz data.
1816             DavidK 10/11/02 */
[1084]1817          nsamp = roundup(pTH->samprate *
1818                          (pTH->starttime -
1819                           (tLastSample + ( MINIMUM_GAP_SIZE / pTH->samprate ))
1820                          )
[1085]1821                         );
[765]1822          if ( BulkSendFill( soc, fill,nsamp ) != R_DONE )
1823          {
[1085]1824            logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #4 failed for tank %s\n",
[765]1825                  t->tankName );
1826            goto abort;
1827          }
1828        }
1829      }
1830    }
1831
1832    iFirstSample = 0;
1833
1834    if ( bFirstBlock && tReqStart > pTH->starttime)
1835    {
1836      /* we may need to skip forward when pCurrentRecord is the first record */
1837      /* Round iFirstSample up to next sample as we did for dActStartTime above */
1838      iFirstSample = roundup(pTH->samprate * (tReqStart - pTH->starttime ));
1839      if ( _fDBG & _fPRT ) logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): adj leading iFirstSample to [%ld]\n",iFirstSample );
1840    }
1841
1842    iLastSample = (long int) pTH->nsamp;
1843    /* if the length of this record excedes our databuffer, or
1844       the current record ends after the requested endtime, then
1845       chomp some records off at the end.  */
1846    if ((pCurrentRecord + iRecordSize) > (data + iDataByteLen)) 
1847    {
1848      /* may need cut trailing samples when trace_h is the last record */
1849     iLastSample -= ((pCurrentRecord + iRecordSize) - (data + iDataByteLen) 
1850                + iDataSize - 1)/iDataSize;
1851      if ( _fDBG & _fPRT ) 
1852        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): WARNING!: record goes past end of buffer\n");
1853    }
1854    if (pTH->endtime > tReqEnd) 
1855    {
1856      /* may need cut trailing samples when trace_h is the last record */
1857      iLastSample -= roundup( pTH->samprate * ( pTH->endtime - tReqEnd ));
1858      if ( _fDBG & _fPRT ) 
1859        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): adj trailing nsamp to [%ld]\n",iLastSample );
1860    }
1861    /* update to what we are about to send */
1862    tLastSample = pTH->starttime + (iLastSample - 1)/pTH->samprate;
1863
1864    /* Added by davidk 3/12/98, to prevent a fatal error from occuring, when
1865       SendReqDataAscii_AndThisTimeWeMeanIt() gets a wrong starting record, such that the actual
1866       requested starttime occurs after tEnd for the first record in <data>.
1867    */
1868    if (iFirstSample > iLastSample)
1869    {
1870      int temp_pCurrentRecord;
[1493]1871      TRACE2_HEADER * tempHP;
[765]1872      logit("t","SendReqDataAscii_AndThisTimeWeMeanIt handed premature starting record.  Requested start time is past the end of current record\n");
1873      logit( "","SendReqDataAscii_AndThisTimeWeMeanIt() tank %s\n", t->tankName );
1874      logit( "","               tReqStart[%f]    tReqEnd[%f]\n", tReqStart, tReqEnd );
1875      logit( "","               tTankStart[%f]    tTankEnd[%f]\n", tTankStart, tTankEnd );
1876      logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
1877      logit( "","              len[%ld]\n", iDataByteLen );
1878      logit( "","             fill[%s]\n", fill );
1879      logit(""," thp->nsamp %d,thp->samprate %f, thp->et %f, thp->st %f\n",
1880            pTH->nsamp,pTH->samprate,pTH->endtime,pTH->starttime);
1881      for ( temp_pCurrentRecord = 0; temp_pCurrentRecord < iDataByteLen; temp_pCurrentRecord += iRecordSize )
1882      {
[1493]1883        tempHP=(TRACE2_HEADER *)(data+temp_pCurrentRecord);
[765]1884        logit("","Record # %d :\n",temp_pCurrentRecord/iRecordSize + 1);
1885        logit("","StartTime  %f      EndTime %f\n",tempHP->starttime,tempHP->endtime);
1886        logit("","Samples    %d      SampleRate %f\n",tempHP->nsamp,tempHP->samprate);
1887      }
1888      continue;
1889    }
1890
1891
1892    blk_pos = 0L;
1893    blk_buf = (char*)malloc( (iLastSample - iFirstSample ) * ( MAX_TRACE_INT_LEN ) + 1 );
1894    if ( !blk_buf ) 
1895    {
1896      logit("et","Wave_server:Memory allocation failed in SendReqDataAscii_AndThisTimeWeMeanIt\n");
1897      logit("et","Begin SendReqDataAscii_AndThisTimeWeMeanIt dump from wave_server\n");
1898      logit("et","Nsamp = %d, iFirstSample=%d,MAX_TRACE_INT_LEN=%d\n",
1899           iLastSample,iFirstSample,MAX_TRACE_INT_LEN);
1900      logit( "","SendReqDataAscii_AndThisTimeWeMeanIt() for tank %s\n", t->tankName );
1901      logit( "","               tReqStart[%f]    tReqEnd[%f]\n", tReqStart, tReqEnd );
1902      logit( "","               tTankStart[%f]    tTankEnd[%f]\n", tTankStart, tTankEnd );
1903      logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
1904      logit( "","              len[%ld]\n", iDataByteLen );
1905      logit( "","             fill[%s]\n", fill );
1906      logit(""," thp->nsamp %d,thp->samprate %f, thp->et %f, thp->st %f\n",
1907            pTH->nsamp,pTH->samprate,pTH->endtime,pTH->starttime);
1908      goto mem_abort;
1909    }
1910    /* Finally, we convert the requested samples to ascii */
1911    for (i=iFirstSample; i<iLastSample; i++)
1912    {
1913      samp_pos = hsz + i * iDataSize;
1914      if ( iDataSize == D_SIZE_I2 )
1915        ival = (long int) *((short int*)&pCurrentRecord[samp_pos]);
1916      else /* iDataSize == D_DIZE_I4 */
1917        ival = *((long int*)&pCurrentRecord[samp_pos]);
1918      sprintf( &blk_buf[ blk_pos ], "%d ", ival );
1919      blk_pos = strlen( blk_buf );
1920    }
1921
1922    if ( _fDBG & _fPRT ) 
1923      logit("","Record being transmitted, Start %f End %f, length %d\n",pTH->starttime,pTH->endtime,blk_pos);
1924
1925    if ( (retVal=send_ew( soc, blk_buf, blk_pos, 0, SocketTimeoutLength )) != blk_pos )
1926    {
1927      logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): send_ew was not able to send %d bytes.  send_ew() returned %d. Treated as failure.\n",blk_pos,retVal);
1928      goto abort;         
1929    }
1930    free( blk_buf );
1931    blk_buf = (char*) NULL;
1932
1933    /* Need to fill in gaps at the end of last record,
1934     * but not end of tank */
1935
1936  } /* end of loop though data buffer */
1937  /* Final fill: pulled out of above loop, since it only is used when the
1938   * loop is completed: PNL, 6/25/00 */
1939  if ( (MINIMUM_GAP_SIZE / pTH->samprate ) < tReqEnd - pTH->endtime && tReqEnd < tTankEnd )
1940  {
1941    nsamp = (long) ( pTH->samprate * ( tReqEnd - tLastSample ) ); 
1942    /* sampt replaces pTH->starttime above, to get rid of
1943     * excess fill values: PNL 6/25/00 */
1944    if ( fill )
1945    {
1946      if ( BulkSendFill( soc, fill, nsamp ) != R_DONE )
1947      {
1948        logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #3 failed for tank %s\n",
1949              t->tankName );
1950        goto abort;         
1951      }
1952    }
1953  }
1954  if ( _fDBG & _fPRT ) 
1955    logit("","SRDA: dActStartTime, tLastSample [%.3f - %.3f]\n",
1956          dActStartTime, tLastSample);
1957  return(0);
1958mem_abort:
1959  return(SRDA_MEM_ABORT);
1960abort:
1961  if ( blk_buf )
1962    free( blk_buf );
1963  return(SRDA_ABORT);
1964}  /* end SendReqDataAscii_AndThisTimeWeMeanIt() */
1965
1966
[15]1967/* function: SendReqDataAscii()
1968 *    input: int soc, socket descriptor supplied by caller
1969 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
1970 *           double tS, starting time of reqested period;
1971 *           double tE, ending time of reqested period;
1972 *           double tL, starting time of tank;
1973 *           double tR, ending time of tank;
1974 *           double acttS, starting time of period where data is available;
1975 *           double acttE, ending time of period where data is available;
1976 *           char* fill, fill value for sampling gaps;
1977 *           char* data, records of t->recSize bytes each
1978 *     note: upon entering SendReqDataAscii(), acttS == trace_h.starttime,
1979 *           where trace_h is the header record located at &data[0];
1980 *           upon leaving SendReqDataAscii(), acttE == trace_h.endtime,
1981 *           where trace_h is the header record located at &data[datasize-rsz]
1982 *   output: None
1983 *   return: R_FAIL or R_DONE
1984 *
1985 *  purpose: to send data retrieved in CopyReqData() to socket;
1986 *           called only once from main _writeTraceData{Raw|Ascii}()
1987 */
1988
1989static int SendReqDataAscii( int soc, TANK* t, double tS, double tE,
1990                             double tL, double tR,
1991                             double acttS, double acttE, char* fill,
1992                             char* data, long int datasize, char* reqid )
1993{
1994  int ret = R_FAIL;
1995  long int rsz = 0;
[765]1996  int rc;
1997/* 
[1493]1998  long int hsz = sizeof(TRACE2_HEADER);
[15]1999  long int rec_pos = 0L;
[765]2000  long int nsamp = 0; /* need long int for possibly numerous fill values * /
[15]2001  int dsz = 0;
[765]2002  long int itr = 0;   /* need iterate through nsamp of fill values * /
[15]2003  long int samp_pos = 0L;
[765]2004  double sampt = tS;  /* time stamp when the last sample was sent * /
[15]2005  long int ival = 0;
2006  char* blk_buf = (char*) NULL;
2007  long int blk_pos = 0L;
2008  int BadFirstRecord=0;
2009  int retVal;
[1493]2010  TRACE2_HEADER* trace_hp;
[765]2011*/ 
2012
[15]2013  if ( _fDBG & _fSUB ) 
2014  {
2015    logit( "","SendReqDataAscii()\n" );
2016    logit( "","               tS[%f]    tE[%f]\n", tS, tE );
2017    logit( "","               tL[%f]    tR[%f]\n", tL, tR );
2018    logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
2019    logit( "","              len[%ld]\n", datasize );
2020    logit( "","             fill[%s]\n", fill );
2021  }
2022
[765]2023  if ( _fDBG & _fPRT ) 
2024    logit("","SRDA: tS,tE [%.3f,%.3f], acttS, acctE[%.3f,%.3f]\n",
2025          tS,tE,acttS,acttE);
2026
[15]2027  if ( !t || !( rsz = t->recSize ) )
2028  {
2029    logit("et","SendReqDataAscii(): Tank  or Tank->recSize is NULL.  t=%d, t->recSize=%d\n",t,t->recSize);
2030    goto abort;
2031  }
2032
2033
2034  if ( !data && !datasize )
2035  {
[765]2036    if ( tE <= tL - GRACE_PERIOD )      /* Davidk 3/27/98 added GRACE_PERIOD */
[15]2037    {
2038      /* this is when request falls entirely left of tank range [tL,tR],
[154]2039       * and acttS is the time stamp that marks beginning of tank at tL
2040       */
[15]2041      if ( SendHeader( soc, t, reqid, "FL", acttS, DBL_FLOAT_NA,
2042                       0, YES_NEWLINE ) != R_DONE )
2043      {
2044        logit("et","SendReqDataAscii(): SendHeader #1 failed for tank %s\n",
2045              t->tankName );
2046        goto abort;          /* Line added by WMK  971108 */
2047      }
2048      goto done;
2049    }  /* end if tE < tL */
[765]2050    else if ( tS >= tR + GRACE_PERIOD ) /* Davidk 3/27/98 added GRACE_PERIOD */
[15]2051    {
[154]2052      /* this is when request falls entirely right of tank range [tL,tR],
2053       * and acttE is the time stamp that marks end of tank at tR
2054       */
[15]2055      if ( SendHeader( soc, t, reqid, "FR", DBL_FLOAT_NA, acttE,
2056                       0, YES_NEWLINE ) != R_DONE )
2057      {
2058        logit("et","SendReqDataAscii(): SendHeader #2 failed for tank %s\n",
2059              t->tankName );
2060        goto abort;          /* Line added by WMK  971108 */
2061      }
2062      goto done;
2063    }  /* end else if tS > tR */
2064    else
2065    {
2066      /* this is when the request falls entirely in a gap,
[154]2067       * note the difference between SendReqData{Ascii|Raw()}:
2068       * here in SendReqDataAscii() tS is the 1st double, and
2069       * t->samprate is the 2nd double passed to SendFlgData();
2070       * while in SendReqDataRaw() neither acttS nor acttE is passed
2071       */
[15]2072      double dbl_2 = t->samprate;
2073
2074      if ( _fDBG & _fALG )
2075        logit( "","SendReqDataAscii(): entirely in a gap\n" );
2076      if ( SendHeader( soc, t, reqid, "FG", tS, dbl_2, 0, 
[154]2077                       NO_NEWLINE ) != R_DONE )
[15]2078      {
2079        logit("et","SendReqDataAscii(): SendHeader #3 failed for tank %s\n",
2080              t->tankName );
2081        goto abort;         
2082      }
2083      if ( fill )
[154]2084      {
2085        long int fill_cnt = (long int) (( tE - tS )*( t->samprate ));
[15]2086
[154]2087        if ( BulkSendFill( soc, fill, fill_cnt ) != R_DONE )
[15]2088        {
2089          logit("et","SendReqDataAscii(): BulkSendFill #1 failed for tank %s\n",
2090                t->tankName );
2091          goto abort;         
2092        }
[154]2093      }
2094      goto terminate;
[15]2095    }  /* end else (! tS > tR && ! tE < tL) */
2096  }     /* end if ( !data && !datasize ) */
2097
2098  if ( !data || !datasize || ( datasize % rsz != 0 ) )
[154]2099  {
2100    logit( "","SendReqDataAscii(): data[0x%x] size[%ld]\n", data, datasize );
2101    goto abort;
2102  }
[15]2103   
2104
2105
[765]2106  rc =SendReqDataAscii_AndThisTimeWeMeanIt(data, datasize, 
2107                                           tS, tE, tL, tR,
2108                                           rsz, t, soc, 
2109                                           reqid, fill, acttS, acttE);
[15]2110
[765]2111  if(rc)
2112  {
2113    if(rc == SRDA_ABORT)
[154]2114      goto abort;
[765]2115    else if(rc == SRDA_MEM_ABORT)
[154]2116      goto mem_abort;
[765]2117    else
[154]2118    {
[765]2119      logit("","SendReqDataAscii(): unexpected return code[%d] from %s\n",
2120            rc, "SendReqDataAscii_AndThisTimeWeMeanIt()");
2121      goto abort;
[154]2122    }
2123  }
[15]2124
[154]2125 terminate:
[15]2126  if ( SendStrData( soc, LN_FD_STR ) != R_DONE )
2127  {
2128    logit("et","SendReqDataAscii(): SendStrData failed for tank %s\n", t->tankName );
2129    goto abort;         
2130  }
[154]2131 done:
[15]2132  ret = R_DONE;
[154]2133 mem_abort:
[15]2134  if ( ret != R_DONE )
2135    logit( "","SendReqDataAscii(): out of memory!\n" );
[154]2136 abort:
[15]2137  if ( ret != R_DONE )
2138    logit( "","SendReqDataAscii(): failed\n" );
[765]2139  return(ret);
[15]2140}
2141
2142/* function: SendStrData()
2143 *    input: int soc, socket descriptor supplied by caller,
2144 *           char* str, string value to be sent
2145 *   return: R_FAIL or R_DONE
2146 *
2147 *  purpose: to send string to socket, called from various places
2148 */
2149
2150static int SendStrData( int soc, char* str )
2151{
2152  int ret = R_FAIL;
2153  long int slen = 0L;
2154
2155  if ( !str || !( slen = strlen( str ) ) )
2156    goto abort;
2157  if ( send_ew(soc, str, slen, 0, SocketTimeoutLength) != slen )
2158    goto abort;
2159   
2160  if ( _fDBG & _fPRT ) logit( "","%s",str );
2161
2162  ret = R_DONE;
[154]2163 abort:
[15]2164  if ( ret != R_DONE )
2165    logit( "","SendStrData(): failed\n" );
2166  return ret;
2167}
2168
2169/* function: trace_log()
2170 *    input: int soc, socket descriptor supplied by caller,
2171 *           char* str, string value to be sent
2172 *   return: R_FAIL or R_DONE
2173 *
2174 *  purpose: for debug use only, called only from SendReqData()
2175 */
2176
[1493]2177static int trace_log( TRACE2_HEADER* trace_hp )
[15]2178{
2179  int ret = R_FAIL;
2180
2181  if ( !trace_hp ) goto abort;
2182
2183  logit( "","\n--------------------------------\n" );
2184  logit( "","starttime<%f>\n",trace_hp->starttime );
2185  logit( "","    nsamp<%d>\n",    trace_hp->nsamp );
2186  logit( "","    pinno<%d>\n",    trace_hp->pinno );
2187  logit( "","      sta<%s>\n",      trace_hp->sta );
2188  logit( "","     chan<%s>\n",     trace_hp->chan );
2189  logit( "","      net<%s>\n",      trace_hp->net );
[1493]2190  logit( "","      loc<%s>\n",      trace_hp->loc );
[15]2191  logit( ""," datatype<%s>\n", trace_hp->datatype );
2192  logit( ""," samprate<%f>\n", trace_hp->samprate );
2193  logit( "","\n--------------------------------\n" );
2194  ret = R_DONE;
[154]2195 abort:
[15]2196  return ret;
2197}
2198
2199static const char fakeFillValue[20] = "20";
2200
2201static int BulkSendFill( int soc, char* fill, long int fill_cnt )
2202{
2203  int ret = R_FAIL;
2204  char fill_buf[kFILLVALUE_LEN + 2];
2205  char* blk_buf = (char*)NULL;
2206  long int blk_pos = 0;
2207  long int ii = 0;
2208  int len;
2209 
2210#ifdef FAKE_FILL
2211  fill = fakeFillValue;
2212#endif
2213
2214  if (!strlen(fill))
2215    goto abort;
2216  blk_buf = (char*)malloc( fill_cnt * ( strlen(fill) + 1 ) + 1 );
2217  if ( !blk_buf ) goto abort;
2218  blk_pos = 0L;
2219
2220  strcpy(fill_buf, fill);
2221  strcat(fill_buf, " ");
2222  len = strlen(fill_buf);
2223 
2224  for ( ii = 0; ii < fill_cnt; ii++)
[154]2225  {
2226    memcpy( &blk_buf[blk_pos], fill_buf, len);
2227    blk_pos += len;
2228  }
2229  blk_buf[blk_pos] = '\0';  /* was blk_pos++, but we don't want to send
2230                               the null character to the client: PNL 6/23/00 */
[15]2231 
2232  if ( send_ew( soc, blk_buf, blk_pos, 0, SocketTimeoutLength ) != blk_pos )
2233    goto abort;
2234  ret = R_DONE;
2235 
[154]2236 abort:
[15]2237  if ( blk_buf )
2238    free( blk_buf );
2239  if ( ret != R_DONE )
2240    logit( "","BulkSendFill(): failed\n" );
2241  return ret;
2242}
2243
2244/* function: SendHeader()
2245 *    input: int soc, socket descriptor supplied by caller;
2246 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
2247 *           char* reqid, ascii string from the client;
2248 *           char* flag, "FL"/"FR"/"FG";
2249 *           double tS, starting time, negative DBL_FLOAT_NA when N/A;
2250 *           double tE, ending time, negative DBL_FLOAT_NA when N/A;
2251 *           int binSize, size in bytes for binary header; 0 otherwise;
2252 *           int flagNewLine, 1 to end header with newline; 0 otherwise;
2253 *   output: None
2254 *   return: R_FAIL or R_DONE
2255 *
2256 *  purpose: to send the header preceeding binary and ascii trace data.
2257 *           called from _SendReqData{Raw|Ascii}()
2258 */
2259
2260static int SendHeader( int soc, TANK* t, char* reqid, char* flag, double tS,
2261                       double tE, int binSize, int flagNewLine)
2262{
2263  size_t len;
2264  char buffer[kMAX_CLIENT_MSG_LEN];
2265   
2266  if ( !t || !flag ) return R_FAIL;
2267   
2268  if (sizeof(int) == D_SIZE_I4)
[1493]2269    sprintf( buffer, "%s %ld %s %s %s %s %s %s ", reqid, t->pin, t->sta, t->chan,
2270             t->net, t->loc, flag, t->datatype);
[15]2271  else  /* sizeof(int) == D_SIZE_I2 */
[1493]2272    sprintf( buffer, "%s %d %s %s %s %s %s %s ", reqid, t->pin, t->sta, t->chan,
2273             t->net, t->loc, flag, t->datatype);
[15]2274  if ( tS > DBL_FLOAT_NA + DBL_FLOAT_EPSILON )
2275    sprintf( &buffer[strlen(buffer)], "%f ", tS);
2276  if ( tE > DBL_FLOAT_NA + DBL_FLOAT_EPSILON )
2277    sprintf( &buffer[strlen(buffer)], "%f ", tE);
2278  if (binSize > 0)
2279    sprintf( &buffer[strlen(buffer)], "%d", binSize); /* no space after size */
2280  if (flagNewLine)
2281    strcat(buffer, "\n");
2282 
2283  len = strlen(buffer);
2284  if ( send_ew(soc, buffer, len, 0, SocketTimeoutLength) != (int)len )
[154]2285  {
2286    logit("et", "SendHeader: failed for tank %s\n", t->tankName );
2287    return R_FAIL;
2288  }
[15]2289  return R_DONE;
2290}
2291
2292
2293/* function: SendReqDataRaw()
2294 *    input: int soc, socket descriptor supplied by caller;
2295 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
2296 *           double tS, starting time of reqested period;
2297 *           double tE, ending time of reqested period;
2298 *           double tL, starting time of tank;
2299 *           double tR, ending time of tank;
2300 *           double acttS, starting time of period where data is available;
2301 *           double acttE, ending time of period where data is available;
2302 *           char* data, records of t->recSize bytes each;
2303 *           char* reqid, the client's request ID
2304 *     note: upon entering SendReqDataRaw(), acttS == trace_hp->starttime,
2305 *           where trace_hp is pointer to header record located at &data[0];
2306 *           upon leaving SendReqDataRaw(), acttE == trace_hp->endtime,
2307 *           where trace_hp is pointer to header record located at &data[datasize-rsz]
2308 *   output: None
2309 *   return: R_FAIL or R_DONE
2310 *
2311 *  purpose: to send data retrieved in CopyReqData() to socket;
2312 *           called only once from main _writeTraceDataRaw()
2313 */
2314
2315static int SendReqDataRaw( int soc, TANK* t, double tS, double tE,
2316                           double tL, double tR,
2317                           double acttS, double acttE,
2318                           char* data, long int datasize, char* reqid )
2319{
2320  int ret = R_FAIL;
2321  long int rsz = 0;
[1493]2322  long int hsz = sizeof(TRACE2_HEADER);
[15]2323  long int rec_pos = 0L;
[1493]2324  TRACE2_HEADER* trace_hp;
[15]2325  long int nsamp = 0; /* total count of sample data */
2326  int size;
2327  int dsz = 0;
2328
2329  if ( _fDBG & _fSUB ) {
2330    logit( "","SendReqDataRaw()\n" );
2331    logit( "","               tS[%f]    tE[%f]\n", tS, tE );
2332    logit( "","               tL[%f]    tR[%f]\n", tL, tR );
2333    logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
2334    logit( "","              len[%ld]\n", datasize );
2335  }
2336
2337  if ( !t || !( rsz = t->recSize ) ) goto abort;
2338  if ( !data && !datasize )
[154]2339  {
2340    if ( tE < tL )
[15]2341    {
[154]2342      /* this is when request falls entirely left of tank range [tL,tR],
2343       * and acttS is the time stamp that marks beginning of tank at tL
2344       */
2345      if ( SendHeader( soc, t, reqid, "FL", acttS, DBL_FLOAT_NA, 0,
2346                       YES_NEWLINE) != R_DONE )
2347        goto abort;
[15]2348    }
[154]2349    else if ( tS > tR )
[15]2350    {
[154]2351      /* this is when request entirely right of tank range [tL,tR],
2352       * and acttE is the time stamp that marks end of tank at tR
2353       */
2354      if ( SendHeader( soc, t, reqid, "FR", DBL_FLOAT_NA, acttE, 0,
2355                       YES_NEWLINE ) != R_DONE )
2356        goto abort;
[15]2357    }
[154]2358    else
[15]2359    {
[154]2360      /* this is when the request falls entirely in a gap */
2361      if ( SendHeader( soc, t, reqid, "FG", DBL_FLOAT_NA, DBL_FLOAT_NA,
2362                       0, YES_NEWLINE) !=
2363           R_DONE )
2364        goto abort;
[15]2365    }
[154]2366    goto done;
2367  }
[15]2368
[154]2369  if ( !data || !datasize || ( datasize % rsz != 0 ) )
2370  {
2371    logit( "","SendReqDataRaw(): data[0x%x] size[%ld] for tank %s\n", data,
2372           datasize, t->tankName );
2373    goto abort;
2374  }
2375   
2376  for ( rec_pos = 0; rec_pos < datasize; rec_pos += rsz )
2377  {
[1493]2378    trace_hp = (TRACE2_HEADER* ) &data[rec_pos];
[154]2379    if ( _fDBG & _fPRT ) trace_log( trace_hp );
2380    nsamp += (long int) trace_hp->nsamp;
2381  }
2382
[15]2383  /* since datasize != 0 && datasize % rsz == 0, we know that
2384   * trace_h now is the last record copied from data
2385   */
2386  if ( strcmp( trace_hp->datatype, "i2" ) == 0 ||
2387       strcmp( trace_hp->datatype, "s2" ) == 0 )
2388    dsz = D_SIZE_I2;
2389  else if ( strcmp( trace_hp->datatype, "i4" ) == 0 ||
2390            strcmp( trace_hp->datatype, "s4" ) == 0 )
2391    dsz = D_SIZE_I4;
2392  else
[154]2393  {
[1176]2394    logit( "","SendReqData(): unexpected data type for tank %s[%s] - datasize %d\n", t->tankName, trace_hp->datatype, datasize );
[154]2395    goto abort;
2396  }
[15]2397
2398  if ( SendHeader( soc, t, reqid, "F", acttS, acttE,
2399                   datasize/rsz*hsz+dsz*nsamp, YES_NEWLINE) != R_DONE )
2400    goto abort;
2401
2402  for ( rec_pos = 0; rec_pos < datasize; rec_pos += rsz )
[154]2403  {
[1493]2404    trace_hp = (TRACE2_HEADER *) &data[rec_pos];
[154]2405    size = hsz + dsz * trace_hp->nsamp;
[15]2406         
[154]2407    if ( send_ew( soc, &data[rec_pos], size, 0, SocketTimeoutLength ) !=
2408         size )
2409      goto abort;
2410  }
[15]2411
[154]2412 done:
[15]2413  ret = R_DONE;
[154]2414 abort:
[15]2415  if ( ret != R_DONE )
2416    logit( "","SendReqDataRaw(): failed\n" );
2417  return ret;
2418}
2419
2420int serve_trace_c_init()
2421{
[701]2422  if (Debug > 1)
[1493]2423      logit("t","serve_trace.c:Version 1084816782\n");
[15]2424  return(0);
2425}
[3164]2426/******************************************************
2427  MergeAsyncPackets - used to resync packets written to
2428  db.
2429 
2430*******************************************************/
2431int MergeAsyncPackets(
2432     TANK* t,
2433        char** data,
2434        long* datasize,
2435        char* AsyncData,
2436        long AsyncDataSize,
2437        long AsyncPacketCount
2438 ) {
2439
2440        char* pData;
2441        char* pDataEnd;
2442        char* pLast;
2443        char* pAsync;
2444        char* pAsyncEnd;
2445        char* pMerge;
2446        char* p;
2447        long MergeSize;
2448        TRACE2_HEADER* pTb;
2449        int rc = FALSE;
2450
2451   /* merge async data if any. It would be better to include this
2452   someplace lower for performance reasons but since this should be
2453   a rare event so we'll optimize the merge here so all the other code
2454   that examines the tank data on the way out include the async packets as well.*/
2455   if(AsyncPacketCount) {
2456 
2457          if(*datasize && *data) {
2458 
2459 
2460                  logit( "","MergeAsycPackets(): merging async packet data.\n" );
2461 
2462                  /* reallocate data for combined buffers */
2463                  MergeSize = *datasize + (AsyncPacketCount * t->recSize);
2464                  if(p = pMerge = (char*) malloc(MergeSize)) {
2465 
2466                          /* init buf*/
2467                          memset(pMerge, 0, MergeSize);
2468
2469                          /* walk through tank data*/
2470                          pLast = pData = *data;
2471                          pDataEnd = pData + *datasize;
2472                          pAsync = AsyncData;
2473                          pAsyncEnd = pAsync + AsyncDataSize;
2474                          while(pData < pDataEnd && pAsync < pAsyncEnd) {
2475                                  /**/
2476                                  pTb = (TRACE2_HEADER*) (pAsync + sizeof(long));
2477                                  if(pTb->starttime < ((TRACE2_HEADER*)pData)->starttime) {
2478                                          /*copy any data up to this tank record */
2479                                          if(pData - pLast) {
2480                                                  memcpy(p, pLast, pData - pLast);
2481                                                  p += pData - pLast;
2482                                                  pLast = pData;
2483                                          }
2484                                          /* copy async data */
2485                                          memcpy(p, pTb, *((long*)pAsync));
2486                                          p += t->recSize;
2487                                          pAsync += *((long*)pAsync) + sizeof(long);
2488                                  }
2489                                  pData += t->recSize;
2490                          }
2491                          /* write any leftover. Should only be tankdata because the query shouldn't
2492                          return any records beyond tE drom db.*/
2493                          if(pDataEnd - pLast) {
2494 
2495                                  memcpy(p, pLast, pDataEnd - pLast); 
2496                          }
2497                          /* free old data*/
2498                          FreeReqData(*data);
2499                          /* updata data pointer and size and fall through to old code. */
2500                          *data = pMerge;
2501                          *datasize = MergeSize;
2502                          rc = TRUE;
2503                  } else {
2504                          logit( "e","MergeAsyncPackets(): Error reallocating packet buffer for async packet data.\n" );
2505                  }
2506 
2507          } else {
2508             
2509                 /* just async data. Normalize buffer (make sure packets are recsize.
2510                 this too should be a rare occasion also but seemed possible. */
2511             MergeSize = AsyncPacketCount * t->recSize;
2512                 if(pMerge = (char*) malloc(MergeSize)) {
2513 
2514                         memset(pMerge, 0, MergeSize);
2515                         pAsync = AsyncData;
2516                         pAsyncEnd = pAsync + AsyncDataSize;
2517                         p = pMerge;
2518                         while(pAsync < pAsyncEnd) {
2519                                memcpy(p, pAsync + sizeof(long), *((long*)pAsync));
2520                                pAsync += *((long*)pAsync) + sizeof(long);
2521                                p += t->recSize;
2522                         }
2523                         *data = pMerge;
2524                         *datasize = MergeSize;
2525                         rc = TRUE;
2526                 } else {
2527                          logit( "e","MergeAsyncPackets(): Error allocating packet normalization buffer for async packet data.\n" );
2528                 }
2529 
2530 
2531          }
2532   }
2533   return rc; 
2534 }
Note: See TracBrowser for help on using the repository browser.