~ubuntu-branches/ubuntu/trusty/ntop/trusty

« back to all changes in this revision

Viewing changes to myrrd/rrd_update.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2008-06-15 14:38:28 UTC
  • mfrom: (2.1.11 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080615143828-oalh84nda2hje4do
Tags: 3:3.3-11
Correction of Polish translation encoding, closes: #479490. Thanks
to Christian Perrier <bubulle@debian.org> for the help.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 * RRDtool 1.0.49  Copyright Tobias Oetiker, 1997 - 2000
3
 
 *****************************************************************************
4
 
 * rrd_update.c  RRD Update Function
5
 
 *****************************************************************************
6
 
 * $Id: rrd_update.c,v 1.4 2004/09/06 10:20:05 deri Exp $
7
 
 * $Log: rrd_update.c,v $
8
 
 * Revision 1.4  2004/09/06 10:20:05  deri
9
 
 * Updated to RRDtool 1.0.49
10
 
 *
11
 
 * Revision 1.1.1.1  2002/02/26 10:21:38  oetiker
12
 
 * Intial Import
13
 
 *
14
 
 *****************************************************************************/
15
 
 
16
 
#include "rrd_tool.h"
17
 
#include <sys/types.h>
18
 
#include <fcntl.h>
19
 
 
20
 
#ifdef WIN32
21
 
 #include <sys/locking.h>
22
 
 #include <sys/stat.h>
23
 
 #include <io.h>
24
 
#endif
25
 
 
26
 
 
27
 
/* Prototypes */
28
 
int LockRRD(FILE *rrd_file);
29
 
 
30
 
/*#define DEBUG */
31
 
 
32
 
 
33
 
#ifdef STANDALONE
34
 
int 
35
 
main(int argc, char **argv){
36
 
        rrd_update(argc,argv);
37
 
        if (rrd_test_error()) {
38
 
                printf("RRDtool 1.0.49  Copyright 1997-2000 by Tobias Oetiker <tobi@oetiker.ch>\n\n"
39
 
                        "Usage: rrdupdate filename\n"
40
 
                        "\t\t\t[--template|-t ds-name:ds-name:...]\n"
41
 
                        "\t\t\ttime|N:value[:value...]\n\n"
42
 
                        "\t\t\t[ time:value[:value...] ..]\n\n");
43
 
                                   
44
 
                printf("ERROR: %s\n",rrd_get_error());
45
 
                rrd_clear_error();                                                            
46
 
                return 1;
47
 
        }
48
 
        return 0;
49
 
}
50
 
#endif
51
 
 
52
 
int
53
 
rrd_update(int argc, char **argv)
54
 
{
55
 
 
56
 
    int              arg_i = 2;
57
 
    long             i,ii,iii;
58
 
 
59
 
    unsigned long    rra_begin;          /* byte pointer to the rra
60
 
                                          * area in the rrd file.  this
61
 
                                          * pointer never changes value */
62
 
    unsigned long    rra_start;          /* byte pointer to the rra
63
 
                                          * area in the rrd file.  this
64
 
                                          * pointer changes as each rrd is
65
 
                                          * processed. */
66
 
    unsigned long    rra_current;        /* byte pointer to the current write
67
 
                                          * spot in the rrd file. */
68
 
    unsigned long    rra_pos_tmp;        /* temporary byte pointer. */
69
 
    unsigned long    interval,
70
 
        pre_int,post_int;                /* interval between this and
71
 
                                          * the last run */
72
 
    unsigned long    proc_pdp_st;        /* which pdp_st was the last
73
 
                                          * to be processed */
74
 
    unsigned long    occu_pdp_st;        /* when was the pdp_st
75
 
                                          * before the last update
76
 
                                          * time */
77
 
    unsigned long    proc_pdp_age;       /* how old was the data in
78
 
                                          * the pdp prep area when it
79
 
                                          * was last updated */
80
 
    unsigned long    occu_pdp_age;       /* how long ago was the last
81
 
                                          * pdp_step time */
82
 
    unsigned long    pdp_st;             /* helper for cdp_prep 
83
 
                                          * processing */
84
 
    rrd_value_t      *pdp_new;           /* prepare the incoming data
85
 
                                          * to be added the the
86
 
                                          * existing entry */
87
 
    rrd_value_t      *pdp_temp;          /* prepare the pdp values 
88
 
                                          * to be added the the
89
 
                                          * cdp values */
90
 
 
91
 
    long             *tmpl_idx;          /* index representing the settings
92
 
                                            transported by the template index */
93
 
    long             tmpl_cnt = 2;       /* time and data */
94
 
 
95
 
    FILE             *rrd_file;
96
 
    rrd_t            rrd;
97
 
    time_t           current_time = time(NULL);
98
 
    char             **updvals;
99
 
    int              wrote_to_file = 0;
100
 
    char             *template = NULL;          
101
 
    char             *endptr; /* used in the conversion */
102
 
 
103
 
 
104
 
    while (1) {
105
 
        static struct option long_options[] =
106
 
        {
107
 
            {"template",      required_argument, 0, 't'},
108
 
            {0,0,0,0}
109
 
        };
110
 
        int option_index = 0;
111
 
        int opt;
112
 
        opt = getopt_long(argc, argv, "t:", 
113
 
                          long_options, &option_index);
114
 
        
115
 
        if (opt == EOF)
116
 
          break;
117
 
        
118
 
        switch(opt) {
119
 
        case 't':
120
 
            template = optarg;
121
 
            break;
122
 
 
123
 
        case '?':
124
 
            rrd_set_error("unknown option '%s'",argv[optind-1]);
125
 
            return(-1);
126
 
        }
127
 
    }
128
 
 
129
 
    /* need at least 2 arguments: filename, data. */
130
 
    if (argc-optind < 2) {
131
 
        rrd_set_error("Not enough arguments");
132
 
        return -1;
133
 
    }
134
 
 
135
 
    if(rrd_open(argv[optind],&rrd_file,&rrd, RRD_READWRITE)==-1){
136
 
        return -1;
137
 
    }
138
 
    rra_current = rra_start = rra_begin = ftell(rrd_file);
139
 
    /* This is defined in the ANSI C standard, section 7.9.5.3:
140
 
 
141
 
        When a file is opened with udpate mode ('+' as the second
142
 
        or third character in the ... list of mode argument
143
 
        variables), both input and output may be performed on the
144
 
        associated stream.  However, ...  input may not be directly
145
 
        followed by output without an intervening call to a file
146
 
        positioning function, unless the input operation encounters
147
 
        end-of-file. */
148
 
    fseek(rrd_file, 0, SEEK_CUR);
149
 
 
150
 
    
151
 
    /* get exclusive lock to whole file.
152
 
     * lock gets removed when we close the file.
153
 
     */
154
 
    if (LockRRD(rrd_file) != 0) {
155
 
      rrd_set_error("could not lock RRD");
156
 
      rrd_free(&rrd);
157
 
      fclose(rrd_file);
158
 
      return(-1);   
159
 
    }
160
 
 
161
 
    if((updvals = malloc( sizeof(char*) * (rrd.stat_head->ds_cnt+1)))==NULL){
162
 
        rrd_set_error("allocating updvals pointer array");
163
 
        rrd_free(&rrd);
164
 
        fclose(rrd_file);
165
 
        return(-1);
166
 
    }
167
 
 
168
 
    if ((pdp_temp = malloc(sizeof(rrd_value_t)
169
 
                           *rrd.stat_head->ds_cnt))==NULL){
170
 
        rrd_set_error("allocating pdp_temp ...");
171
 
        free(updvals);
172
 
        rrd_free(&rrd);
173
 
        fclose(rrd_file);
174
 
        return(-1);
175
 
    }
176
 
 
177
 
    if ((tmpl_idx = malloc(sizeof(unsigned long)
178
 
                           *(rrd.stat_head->ds_cnt+1)))==NULL){
179
 
        rrd_set_error("allocating tmpl_idx ...");
180
 
        free(pdp_temp);
181
 
        free(updvals);
182
 
        rrd_free(&rrd);
183
 
        fclose(rrd_file);
184
 
        return(-1);
185
 
    }
186
 
    /* initialize template redirector */
187
 
    /* default config
188
 
       tmpl_idx[0] -> 0; (time)
189
 
       tmpl_idx[1] -> 1; (DS 0)
190
 
       tmpl_idx[2] -> 2; (DS 1)
191
 
       tmpl_idx[3] -> 3; (DS 2)
192
 
       ... */
193
 
    for (i=0;i<=rrd.stat_head->ds_cnt;i++) tmpl_idx[i]=i;
194
 
    tmpl_cnt=rrd.stat_head->ds_cnt+1;
195
 
    if (template) {
196
 
        char *dsname;
197
 
        int tmpl_len;
198
 
        dsname = template;
199
 
        tmpl_cnt = 1; /* the first entry is the time */
200
 
        tmpl_len = strlen(template);
201
 
        for(i=0;i<=tmpl_len ;i++) {
202
 
            if (template[i] == ':' || template[i] == '\0') {
203
 
                template[i] = '\0';
204
 
                if (tmpl_cnt>rrd.stat_head->ds_cnt){
205
 
                    rrd_set_error("Template contains more DS definitions than RRD");
206
 
                    free(updvals); free(pdp_temp);
207
 
                    free(tmpl_idx); rrd_free(&rrd);
208
 
                    fclose(rrd_file); return(-1);
209
 
                }
210
 
                if ((tmpl_idx[tmpl_cnt++] = ds_match(&rrd,dsname)) == -1){
211
 
                    rrd_set_error("unknown DS name '%s'",dsname);
212
 
                    free(updvals); free(pdp_temp);
213
 
                    free(tmpl_idx); rrd_free(&rrd);
214
 
                    fclose(rrd_file); return(-1);
215
 
                } else {
216
 
                  /* the first element is always the time */
217
 
                  tmpl_idx[tmpl_cnt-1]++; 
218
 
                  /* go to the next entry on the template */
219
 
                  dsname = &template[i+1];
220
 
                  /* fix the damage we did before */
221
 
                  if (i<tmpl_len) {
222
 
                     template[i]=':';
223
 
                  } 
224
 
 
225
 
                }
226
 
            }       
227
 
        }
228
 
    }
229
 
    if ((pdp_new = malloc(sizeof(rrd_value_t)
230
 
                          *rrd.stat_head->ds_cnt))==NULL){
231
 
        rrd_set_error("allocating pdp_new ...");
232
 
        free(updvals);
233
 
        free(pdp_temp);
234
 
        free(tmpl_idx);
235
 
        rrd_free(&rrd);
236
 
        fclose(rrd_file);
237
 
        return(-1);
238
 
    }
239
 
 
240
 
    /* loop through the arguments. */
241
 
    for(arg_i=optind+1; arg_i<argc;arg_i++) {
242
 
        char *stepper = malloc((strlen(argv[arg_i])+1)*sizeof(char));
243
 
        char *step_start = stepper;
244
 
        if (stepper == NULL){
245
 
                rrd_set_error("failed duplication argv entry");
246
 
                free(updvals);
247
 
                free(pdp_temp);  
248
 
                free(tmpl_idx);
249
 
                rrd_free(&rrd);
250
 
                fclose(rrd_file);
251
 
                return(-1);
252
 
         }
253
 
        /* initialize all ds input to unknown except the first one
254
 
           which has always got to be set */
255
 
        for(ii=1;ii<=rrd.stat_head->ds_cnt;ii++) updvals[ii] = "U";
256
 
        ii=0;
257
 
        strcpy(stepper,argv[arg_i]);
258
 
        updvals[0]=stepper;
259
 
        while (*stepper) {
260
 
            if (*stepper == ':') {
261
 
                *stepper = '\0';
262
 
                ii++;
263
 
                if (ii<tmpl_cnt){                   
264
 
                    updvals[tmpl_idx[ii]] = stepper+1;
265
 
                }
266
 
            }
267
 
            stepper++;
268
 
        }
269
 
 
270
 
        if (ii != tmpl_cnt-1) {
271
 
            rrd_set_error("expected %lu data source readings (got %lu) from %s:...",
272
 
                          tmpl_cnt-1, ii, argv[arg_i]);
273
 
            free(step_start);
274
 
            break;
275
 
        }
276
 
        
277
 
        /* get the time from the reading ... handle N */
278
 
        if (strcmp(updvals[0],"N")==0){
279
 
            current_time = time(NULL);
280
 
        } else {
281
 
            errno = 0;
282
 
            current_time = strtol(updvals[0],&endptr,10);
283
 
            if (errno > 0){
284
 
                rrd_set_error("converting  '%s' to long: %s",updvals[0],strerror(errno));
285
 
                free(step_start);
286
 
                break;
287
 
            };
288
 
            if (endptr[0] != '\0'){
289
 
                rrd_set_error("conversion of '%s' to long not complete: tail '%s'",updvals[0],endptr);
290
 
                free(step_start);
291
 
                break;
292
 
            }
293
 
        }
294
 
        
295
 
        if(current_time <= rrd.live_head->last_up){
296
 
            rrd_set_error("illegal attempt to update using time %ld when "
297
 
                          "last update time is %ld (minimum one second step)",
298
 
                          current_time, rrd.live_head->last_up);
299
 
            free(step_start);
300
 
            break;
301
 
        }
302
 
        
303
 
        
304
 
        /* seek to the beginning of the rrd's */
305
 
        if (rra_current != rra_begin) {
306
 
            if(fseek(rrd_file, rra_begin, SEEK_SET) != 0) {
307
 
                rrd_set_error("seek error in rrd");
308
 
                free(step_start);
309
 
                break;
310
 
            }
311
 
            rra_current = rra_begin;
312
 
        }
313
 
        rra_start = rra_begin;
314
 
 
315
 
        /* when was the current pdp started */
316
 
        proc_pdp_age = rrd.live_head->last_up % rrd.stat_head->pdp_step;
317
 
        proc_pdp_st = rrd.live_head->last_up - proc_pdp_age;
318
 
 
319
 
        /* when did the last pdp_st occur */
320
 
        occu_pdp_age = current_time % rrd.stat_head->pdp_step;
321
 
        occu_pdp_st = current_time - occu_pdp_age;
322
 
        interval = current_time - rrd.live_head->last_up;
323
 
    
324
 
        if (occu_pdp_st > proc_pdp_st){
325
 
            /* OK we passed the pdp_st moment*/
326
 
            pre_int =  occu_pdp_st - rrd.live_head->last_up; /* how much of the input data
327
 
                                                              * occurred before the latest
328
 
                                                              * pdp_st moment*/
329
 
            post_int = occu_pdp_age;                         /* how much after it */
330
 
        } else {
331
 
            pre_int = interval;
332
 
            post_int = 0;
333
 
        }
334
 
 
335
 
#ifdef DEBUG
336
 
        printf(
337
 
               "proc_pdp_age %lu\t"
338
 
               "proc_pdp_st %lu\t" 
339
 
               "occu_pfp_age %lu\t" 
340
 
               "occu_pdp_st %lu\t"
341
 
               "int %lu\t"
342
 
               "pre_int %lu\t"
343
 
               "post_int %lu\n", proc_pdp_age, proc_pdp_st, 
344
 
                occu_pdp_age, occu_pdp_st,
345
 
               interval, pre_int, post_int);
346
 
#endif
347
 
    
348
 
        /* process the data sources and update the pdp_prep 
349
 
         * area accordingly */
350
 
        for(i=0;i<rrd.stat_head->ds_cnt;i++){
351
 
            enum dst_en dst_idx;
352
 
            dst_idx= dst_conv(rrd.ds_def[i].dst);
353
 
            if((updvals[i+1][0] != 'U') &&
354
 
               rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt >= interval) {
355
 
               double rate = DNAN;
356
 
               /* the data source type defines how to process the data */
357
 
                /* pdp_temp contains rate * time ... e.g. the bytes
358
 
                 * transferred during the interval. Doing it this way saves
359
 
                 * a lot of math operations */
360
 
                
361
 
 
362
 
                switch(dst_idx){
363
 
                case DST_COUNTER:
364
 
                case DST_DERIVE:
365
 
                    if(rrd.pdp_prep[i].last_ds[0] != 'U'){
366
 
                       for(ii=0;updvals[i+1][ii] != '\0';ii++){
367
 
                            if(updvals[i+1][ii] < '0' || updvals[i+1][ii] > '9' || (ii==0 && updvals[i+1][ii] == '-')){
368
 
                                 rrd_set_error("not a simple integer: '%s'",updvals[i+1]);
369
 
                                 break;
370
 
                            }
371
 
                       }
372
 
                       if (rrd_test_error()){
373
 
                            break;
374
 
                       }
375
 
                       pdp_new[i]= rrd_diff(updvals[i+1],rrd.pdp_prep[i].last_ds);
376
 
                       if(dst_idx == DST_COUNTER) {
377
 
                          /* simple overflow catcher suggested by andres Kroonmaa */
378
 
                          /* this will fail terribly for non 32 or 64 bit counters ... */
379
 
                          /* are there any others in SNMP land ? */
380
 
                          if (pdp_new[i] < (double)0.0 ) 
381
 
                            pdp_new[i] += (double)4294967296.0 ;  /* 2^32 */
382
 
                          if (pdp_new[i] < (double)0.0 ) 
383
 
                            pdp_new[i] += (double)18446744069414584320.0; /* 2^64-2^32 */;
384
 
                       }
385
 
                       rate = pdp_new[i] / interval;
386
 
                    }
387
 
                   else {
388
 
                     pdp_new[i]= DNAN;          
389
 
                   }
390
 
                   break;
391
 
                case DST_ABSOLUTE:
392
 
                    errno = 0;
393
 
                    pdp_new[i] = strtod(updvals[i+1],&endptr);
394
 
                    if (errno > 0){
395
 
                        rrd_set_error("converting  '%s' to float: %s",updvals[i+1],strerror(errno));
396
 
                        break;
397
 
                    };
398
 
                    if (endptr[0] != '\0'){
399
 
                        rrd_set_error("conversion of '%s' to float not complete: tail '%s'",updvals[i+1],endptr);
400
 
                        break;
401
 
                    }
402
 
                    rate = pdp_new[i] / interval;                 
403
 
                    break;
404
 
                case DST_GAUGE:
405
 
                    errno = 0;
406
 
                    pdp_new[i] = strtod(updvals[i+1],&endptr) * interval;
407
 
                    if (errno > 0){
408
 
                        rrd_set_error("converting  '%s' to float: %s",updvals[i+1],strerror(errno));
409
 
                        break;
410
 
                    };
411
 
                    if (endptr[0] != '\0'){
412
 
                        rrd_set_error("conversion of '%s' to float not complete: tail '%s'",updvals[i+1],endptr);
413
 
                        break;
414
 
                    }
415
 
                    rate = pdp_new[i] / interval;                  
416
 
                    break;
417
 
                default:
418
 
                    rrd_set_error("rrd contains unknown DS type : '%s'",
419
 
                                  rrd.ds_def[i].dst);
420
 
                    break;
421
 
                }
422
 
                /* break out of this for loop if the error string is set */
423
 
                if (rrd_test_error()){
424
 
                    break;
425
 
                }
426
 
               /* make sure pdp_temp is neither too large or too small
427
 
                * if any of these occur it becomes unknown ...
428
 
                * sorry folks ... */
429
 
               if ( ! isnan(rate) && 
430
 
                    (( ! isnan(rrd.ds_def[i].par[DS_max_val].u_val) &&
431
 
                         rate > rrd.ds_def[i].par[DS_max_val].u_val ) ||     
432
 
                    ( ! isnan(rrd.ds_def[i].par[DS_min_val].u_val) &&
433
 
                        rate < rrd.ds_def[i].par[DS_min_val].u_val ))){
434
 
                  pdp_new[i] = DNAN;
435
 
               }               
436
 
            } else {
437
 
                /* no news is news all the same */
438
 
                pdp_new[i] = DNAN;
439
 
            }
440
 
            
441
 
            /* make a copy of the command line argument for the next run */
442
 
#ifdef DEBUG
443
 
            fprintf(stderr,
444
 
                    "prep ds[%lu]\t"
445
 
                    "last_arg '%s'\t"
446
 
                    "this_arg '%s'\t"
447
 
                    "pdp_new %10.2f\n",
448
 
                    i,
449
 
                    rrd.pdp_prep[i].last_ds,
450
 
                    updvals[i+1], pdp_new[i]);
451
 
#endif
452
 
            if(dst_idx == DST_COUNTER || dst_idx == DST_DERIVE){
453
 
                strncpy(rrd.pdp_prep[i].last_ds,
454
 
                        updvals[i+1],LAST_DS_LEN-1);
455
 
                rrd.pdp_prep[i].last_ds[LAST_DS_LEN-1]='\0';
456
 
            }
457
 
        }
458
 
        /* break out of the argument parsing loop if the error_string is set */
459
 
        if (rrd_test_error()){
460
 
            free(step_start);
461
 
            break;
462
 
        }
463
 
        /* has a pdp_st moment occurred since the last run ? */
464
 
 
465
 
        if (proc_pdp_st == occu_pdp_st){
466
 
            /* no we have not passed a pdp_st moment. therefore update is simple */
467
 
 
468
 
            for(i=0;i<rrd.stat_head->ds_cnt;i++){
469
 
                if(isnan(pdp_new[i]))
470
 
                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += interval;
471
 
                else
472
 
                    rrd.pdp_prep[i].scratch[PDP_val].u_val+= pdp_new[i];
473
 
#ifdef DEBUG
474
 
                fprintf(stderr,
475
 
                        "NO PDP  ds[%lu]\t"
476
 
                        "value %10.2f\t"
477
 
                        "unkn_sec %5lu\n",
478
 
                        i,
479
 
                        rrd.pdp_prep[i].scratch[PDP_val].u_val,
480
 
                        rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
481
 
#endif
482
 
            }   
483
 
        } else {
484
 
            /* an pdp_st has occurred. */
485
 
 
486
 
            /* in pdp_prep[].scratch[PDP_val].u_val we have collected rate*seconds which 
487
 
             * occurred up to the last run.        
488
 
            pdp_new[] contains rate*seconds from the latest run.
489
 
            pdp_temp[] will contain the rate for cdp */
490
 
 
491
 
 
492
 
            for(i=0;i<rrd.stat_head->ds_cnt;i++){
493
 
                /* update pdp_prep to the current pdp_st */
494
 
                if(isnan(pdp_new[i]))
495
 
                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt += pre_int;
496
 
                else
497
 
                    rrd.pdp_prep[i].scratch[PDP_val].u_val += 
498
 
                        pdp_new[i]/(double)interval*(double)pre_int;
499
 
 
500
 
                /* if too much of the pdp_prep is unknown we dump it */
501
 
                if ((rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt 
502
 
                     > rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt) ||
503
 
                    (occu_pdp_st-proc_pdp_st <= 
504
 
                     rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt)) {
505
 
                    pdp_temp[i] = DNAN;
506
 
                } else {
507
 
                    pdp_temp[i] = rrd.pdp_prep[i].scratch[PDP_val].u_val
508
 
                        / (double)( occu_pdp_st
509
 
                                   - proc_pdp_st
510
 
                                   - rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
511
 
                }
512
 
                /* make pdp_prep ready for the next run */
513
 
                if(isnan(pdp_new[i])){
514
 
                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = post_int;
515
 
                    rrd.pdp_prep[i].scratch[PDP_val].u_val = 0.0;
516
 
                } else {
517
 
                    rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt = 0;
518
 
                    rrd.pdp_prep[i].scratch[PDP_val].u_val = 
519
 
                        pdp_new[i]/(double)interval*(double)post_int;
520
 
                }
521
 
 
522
 
#ifdef DEBUG
523
 
                fprintf(stderr,
524
 
                        "PDP UPD ds[%lu]\t"
525
 
                        "pdp_temp %10.2f\t"
526
 
                        "new_prep %10.2f\t"
527
 
                        "new_unkn_sec %5lu\n",
528
 
                        i, pdp_temp[i],
529
 
                        rrd.pdp_prep[i].scratch[PDP_val].u_val,
530
 
                        rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
531
 
#endif
532
 
            }
533
 
 
534
 
 
535
 
            /* now we have to integrate this data into the cdp_prep areas */
536
 
            /* going through the round robin archives */
537
 
            for(i = 0;
538
 
                i < rrd.stat_head->rra_cnt;
539
 
                i++){
540
 
                enum cf_en current_cf = cf_conv(rrd.rra_def[i].cf_nam);
541
 
                /* going through all pdp_st moments which have occurred 
542
 
                 * since the last run */
543
 
                for(pdp_st  = proc_pdp_st+rrd.stat_head->pdp_step; 
544
 
                    pdp_st <= occu_pdp_st; 
545
 
                    pdp_st += rrd.stat_head->pdp_step){
546
 
 
547
 
#ifdef DEBUG
548
 
                    fprintf(stderr,"RRA %lu STEP %lu\n",i,pdp_st);
549
 
#endif
550
 
 
551
 
                    if((pdp_st %
552
 
                        (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) == 0){
553
 
 
554
 
                        /* later on the cdp_prep values will be transferred to
555
 
                         * the rra.  we want to be in the right place. */
556
 
                        rrd.rra_ptr[i].cur_row++;
557
 
                        if (rrd.rra_ptr[i].cur_row >= rrd.rra_def[i].row_cnt)
558
 
                            /* oops ... we have to wrap the beast ... */
559
 
                            rrd.rra_ptr[i].cur_row=0;                   
560
 
#ifdef DEBUG
561
 
                        fprintf(stderr,"  -- RRA Preseek %ld\n",ftell(rrd_file));
562
 
#endif
563
 
                        /* determine if a seek is even needed. */
564
 
                        rra_pos_tmp = rra_start +
565
 
                                rrd.stat_head->ds_cnt*rrd.rra_ptr[i].cur_row*sizeof(rrd_value_t);
566
 
                        if(rra_pos_tmp != rra_current) {
567
 
                            if(fseek(rrd_file, rra_pos_tmp, SEEK_SET) != 0){
568
 
                                rrd_set_error("seek error in rrd");
569
 
                                break;
570
 
                            }
571
 
                            rra_current = rra_pos_tmp;
572
 
                        }
573
 
#ifdef DEBUG
574
 
                        fprintf(stderr,"  -- RRA Postseek %ld\n",ftell(rrd_file));
575
 
#endif
576
 
                    }
577
 
 
578
 
                    for(ii = 0;
579
 
                        ii < rrd.stat_head->ds_cnt;
580
 
                        ii++){
581
 
                        iii=i*rrd.stat_head->ds_cnt+ii;
582
 
                    
583
 
                        /* the contents of cdp_prep[].scratch[CDP_val].u_val depends
584
 
                         * on the consolidation function ! */
585
 
                    
586
 
                        if (isnan(pdp_temp[ii])){    /* pdp is unknown */
587
 
                            rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt++;
588
 
#ifdef DEBUG
589
 
                            fprintf(stderr,"  ** UNKNOWN ADD %lu\n",
590
 
                                    rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt);
591
 
#endif
592
 
                        } else {
593
 
                            if (isnan(rrd.cdp_prep[iii].scratch[CDP_val].u_val)){
594
 
                                /* cdp_prep is unknown when it does not
595
 
                                 * yet contain data. It can not be zero for
596
 
                                 * things like mim and max consolidation
597
 
                                 * functions */
598
 
#ifdef DEBUG
599
 
                                fprintf(stderr,"  ** INIT CDP %e\n", pdp_temp[ii]);
600
 
#endif
601
 
                                rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
602
 
                            }
603
 
                            else {
604
 
                                switch (current_cf){
605
 
                                    case CF_AVERAGE:                            
606
 
                                        rrd.cdp_prep[iii].scratch[CDP_val].u_val+=pdp_temp[ii];
607
 
#ifdef DEBUG
608
 
                                        fprintf(stderr,"  ** AVERAGE %e\n", 
609
 
                                                rrd.cdp_prep[iii].scratch[CDP_val].u_val);
610
 
#endif
611
 
                                        break;    
612
 
                                    case CF_MINIMUM:
613
 
                                        if (pdp_temp[ii] < rrd.cdp_prep[iii].scratch[CDP_val].u_val)
614
 
                                            rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
615
 
#ifdef DEBUG
616
 
                                        fprintf(stderr,"  ** MINIMUM %e\n", 
617
 
                                                rrd.cdp_prep[iii].scratch[CDP_val].u_val);
618
 
#endif
619
 
                                        break;
620
 
                                    case CF_MAXIMUM:
621
 
                                        if (pdp_temp[ii] > rrd.cdp_prep[iii].scratch[CDP_val].u_val)
622
 
                                            rrd.cdp_prep[iii].scratch[CDP_val].u_val = pdp_temp[ii];
623
 
#ifdef DEBUG
624
 
                                        fprintf(stderr,"  ** MAXIMUM %e\n", 
625
 
                                                rrd.cdp_prep[iii].scratch[CDP_val].u_val);
626
 
#endif
627
 
                                        break;
628
 
                                    case CF_LAST:
629
 
                                        rrd.cdp_prep[iii].scratch[CDP_val].u_val=pdp_temp[ii];
630
 
#ifdef DEBUG
631
 
                                        fprintf(stderr,"  ** LAST %e\n", 
632
 
                                                rrd.cdp_prep[iii].scratch[CDP_val].u_val);
633
 
#endif
634
 
                                        break;    
635
 
                                    default:
636
 
                                        rrd_set_error("Unknown cf %s",
637
 
                                                      rrd.rra_def[i].cf_nam);
638
 
                                        break;
639
 
                                }
640
 
                            }
641
 
                        }
642
 
 
643
 
 
644
 
                        /* is the data in the cdp_prep ready to go into
645
 
                         * its rra ? */
646
 
                        if((pdp_st % 
647
 
                            (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) == 0){
648
 
 
649
 
                            /* prepare cdp_pref for its transition to the rra. */
650
 
                            if (rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt 
651
 
                                > rrd.rra_def[i].pdp_cnt*
652
 
                                rrd.rra_def[i].par[RRA_cdp_xff_val].u_val)
653
 
                                /* to much of the cdp_prep is unknown ... */
654
 
                                rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
655
 
                            else if (current_cf == CF_AVERAGE){
656
 
                                /* for a real average we have to divide
657
 
                                 * the sum we built earlier on. While ignoring
658
 
                                 * the unknown pdps */
659
 
                                rrd.cdp_prep[iii].scratch[CDP_val].u_val 
660
 
                                        /= (rrd.rra_def[i].pdp_cnt
661
 
                                            -rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt);
662
 
                            }
663
 
                            /* we can write straight away, because we are
664
 
                             * already in the right place ... */
665
 
 
666
 
#ifdef DEBUG
667
 
                            fprintf(stderr,"  -- RRA WRITE VALUE %e, at %ld\n",
668
 
                                    rrd.cdp_prep[iii].scratch[CDP_val].u_val,ftell(rrd_file));
669
 
#endif
670
 
 
671
 
                            if(fwrite(&(rrd.cdp_prep[iii].scratch[CDP_val].u_val),
672
 
                                      sizeof(rrd_value_t),1,rrd_file) != 1){
673
 
                                rrd_set_error("writing rrd");
674
 
                                break;
675
 
                            }
676
 
                            rra_current += sizeof(rrd_value_t);
677
 
                            wrote_to_file = 1;
678
 
 
679
 
#ifdef DEBUG
680
 
                            fprintf(stderr,"  -- RRA WROTE new at %ld\n",ftell(rrd_file));
681
 
#endif
682
 
 
683
 
                            /* make cdp_prep ready for the next run */
684
 
                            rrd.cdp_prep[iii].scratch[CDP_val].u_val = DNAN;
685
 
                            rrd.cdp_prep[iii].scratch[CDP_unkn_pdp_cnt].u_cnt = 0;
686
 
                        }
687
 
                    }
688
 
                    /* break out of this loop if error_string has been set */
689
 
                    if (rrd_test_error())
690
 
                        break;
691
 
                }
692
 
                /* break out of this loop if error_string has been set */
693
 
                if (rrd_test_error())
694
 
                    break;
695
 
                /* to be able to position correctly in the next rra w move
696
 
                 * the rra_start pointer on to the next rra */
697
 
                rra_start += rrd.rra_def[i].row_cnt
698
 
                        *rrd.stat_head->ds_cnt*sizeof(rrd_value_t);
699
 
 
700
 
            }
701
 
            /* break out of the argument parsing loop if error_string is set */
702
 
            if (rrd_test_error()){
703
 
                free(step_start);
704
 
                break;
705
 
            }
706
 
        }
707
 
        rrd.live_head->last_up = current_time;
708
 
        free(step_start);
709
 
    }
710
 
 
711
 
 
712
 
    /* if we got here and if there is an error and if the file has not been
713
 
     * written to, then close things up and return. */
714
 
    if (rrd_test_error()) {
715
 
        free(updvals);
716
 
        free(tmpl_idx);
717
 
        rrd_free(&rrd);
718
 
        free(pdp_temp);
719
 
        free(pdp_new);
720
 
        fclose(rrd_file);
721
 
        return(-1);
722
 
    }
723
 
 
724
 
    /* aargh ... that was tough ... so many loops ... anyway, its done.
725
 
     * we just need to write back the live header portion now*/
726
 
 
727
 
    if (fseek(rrd_file, (sizeof(stat_head_t)
728
 
                         + sizeof(ds_def_t)*rrd.stat_head->ds_cnt 
729
 
                         + sizeof(rra_def_t)*rrd.stat_head->rra_cnt),
730
 
              SEEK_SET) != 0) {
731
 
        rrd_set_error("seek rrd for live header writeback");
732
 
        free(updvals);
733
 
        free(tmpl_idx);
734
 
        rrd_free(&rrd);
735
 
        free(pdp_temp);
736
 
        free(pdp_new);
737
 
        fclose(rrd_file);
738
 
        return(-1);
739
 
    }
740
 
 
741
 
    if(fwrite( rrd.live_head,
742
 
               sizeof(live_head_t), 1, rrd_file) != 1){
743
 
        rrd_set_error("fwrite live_head to rrd");
744
 
        free(updvals);
745
 
        rrd_free(&rrd);
746
 
        free(tmpl_idx);
747
 
        free(pdp_temp);
748
 
        free(pdp_new);
749
 
        fclose(rrd_file);
750
 
        return(-1);
751
 
    }
752
 
 
753
 
    if(fwrite( rrd.pdp_prep,
754
 
               sizeof(pdp_prep_t),
755
 
               rrd.stat_head->ds_cnt, rrd_file) != rrd.stat_head->ds_cnt){
756
 
        rrd_set_error("ftwrite pdp_prep to rrd");
757
 
        free(updvals);
758
 
        rrd_free(&rrd);
759
 
        free(tmpl_idx);
760
 
        free(pdp_temp);
761
 
        free(pdp_new);
762
 
        fclose(rrd_file);
763
 
        return(-1);
764
 
    }
765
 
 
766
 
    if(fwrite( rrd.cdp_prep,
767
 
               sizeof(cdp_prep_t),
768
 
               rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt, rrd_file) 
769
 
       != rrd.stat_head->rra_cnt *rrd.stat_head->ds_cnt){
770
 
 
771
 
        rrd_set_error("ftwrite cdp_prep to rrd");
772
 
        free(updvals);
773
 
        free(tmpl_idx);
774
 
        rrd_free(&rrd);
775
 
        free(pdp_temp);
776
 
        free(pdp_new);
777
 
        fclose(rrd_file);
778
 
        return(-1);
779
 
    }
780
 
 
781
 
    if(fwrite( rrd.rra_ptr,
782
 
               sizeof(rra_ptr_t), 
783
 
               rrd.stat_head->rra_cnt,rrd_file) != rrd.stat_head->rra_cnt){
784
 
        rrd_set_error("fwrite rra_ptr to rrd");
785
 
        free(updvals);
786
 
        free(tmpl_idx);
787
 
        rrd_free(&rrd);
788
 
        free(pdp_temp);
789
 
        free(pdp_new);
790
 
        fclose(rrd_file);
791
 
        return(-1);
792
 
    }
793
 
 
794
 
    /* OK now close the files and free the memory */
795
 
    if(fclose(rrd_file) != 0){
796
 
        rrd_set_error("closing rrd");
797
 
        free(updvals);
798
 
        free(tmpl_idx);
799
 
        rrd_free(&rrd);
800
 
        free(pdp_temp);
801
 
        free(pdp_new);
802
 
        return(-1);
803
 
    }
804
 
 
805
 
    rrd_free(&rrd);
806
 
    free(updvals);
807
 
    free(tmpl_idx);
808
 
    free(pdp_new);
809
 
    free(pdp_temp);
810
 
    return(0);
811
 
}
812
 
 
813
 
/*
814
 
 * get exclusive lock to whole file.
815
 
 * lock gets removed when we close the file
816
 
 *
817
 
 * returns 0 on success
818
 
 */
819
 
int
820
 
LockRRD(FILE *rrdfile)
821
 
{
822
 
    int rrd_fd;         /* File descriptor for RRD */
823
 
    int                 stat;
824
 
 
825
 
    rrd_fd = fileno(rrdfile);
826
 
 
827
 
        {
828
 
#ifndef WIN32    
829
 
                struct flock    lock;
830
 
    lock.l_type = F_WRLCK;    /* exclusive write lock */
831
 
    lock.l_len = 0;           /* whole file */
832
 
    lock.l_start = 0;         /* start of file */
833
 
    lock.l_whence = SEEK_SET;   /* end of file */
834
 
 
835
 
    stat = fcntl(rrd_fd, F_SETLK, &lock);
836
 
#else
837
 
                struct _stat st;
838
 
 
839
 
                if ( _fstat( rrd_fd, &st ) == 0 ) {
840
 
                        stat = _locking ( rrd_fd, _LK_NBLCK, st.st_size );
841
 
                } else {
842
 
                        stat = -1;
843
 
                }
844
 
#endif
845
 
        }
846
 
 
847
 
    return(stat);
848
 
}