~ubuntu-branches/ubuntu/natty/ntop/natty

« back to all changes in this revision

Viewing changes to myrrd/rrd_update.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2005-01-30 21:59:13 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050130215913-xc3ke963bw49b3k4
Tags: 2:3.0-5
* Updated README.Debian file so users will understand what to do at
  install, closes: #291794, #287802.
* Updated ntop init script to give better output.
* Also changed log directory from /var/lib/ntop to /var/log/ntop,
  closes: #252352.
* Quoted the interface list to allow whitespace, closes: #267248.
* Added a couple of logcheck ignores, closes: #269321, #269319.

Show diffs side-by-side

added added

removed removed

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