int handle_flush (FILE *fh, char *buffer) { int success = 0; int error = 0; double timeout = 0.0; char **plugins = NULL; size_t plugins_num = 0; char **identifiers = NULL; size_t identifiers_num = 0; #define PRINT_TO_SOCK(fh, ...) \ do { \ if (fprintf (fh, __VA_ARGS__) < 0) { \ char errbuf[1024]; \ WARNING ("handle_flush: failed to write to socket #%i: %s", \ fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \ strarray_free (plugins, plugins_num); \ strarray_free (identifiers, identifiers_num); \ return -1; \ } \ fflush(fh); \ } while (0) if ((fh == NULL) || (buffer == NULL)) return (-1); DEBUG ("utils_cmd_flush: handle_flush (fh = %p, buffer = %s);", (void *) fh, buffer); if (strncasecmp ("FLUSH", buffer, strlen ("FLUSH")) != 0) { PRINT_TO_SOCK (fh, "-1 Cannot parse command.\n"); return (-1); } buffer += strlen ("FLUSH"); while (*buffer != 0) { char *opt_key; char *opt_value; int status; opt_key = NULL; opt_value = NULL; status = parse_option (&buffer, &opt_key, &opt_value); if (status != 0) { PRINT_TO_SOCK (fh, "-1 Parsing options failed.\n"); strarray_free (plugins, plugins_num); strarray_free (identifiers, identifiers_num); return (-1); } if (strcasecmp ("plugin", opt_key) == 0) strarray_add (&plugins, &plugins_num, opt_value); else if (strcasecmp ("identifier", opt_key) == 0) strarray_add (&identifiers, &identifiers_num, opt_value); else if (strcasecmp ("timeout", opt_key) == 0) { char *endptr; errno = 0; endptr = NULL; timeout = strtod (opt_value, &endptr); if ((endptr == opt_value) || (errno != 0) || (!isfinite (timeout))) { PRINT_TO_SOCK (fh, "-1 Invalid value for option `timeout': " "%s\n", opt_value); strarray_free (plugins, plugins_num); strarray_free (identifiers, identifiers_num); return (-1); } else if (timeout < 0.0) { timeout = 0.0; } } else { PRINT_TO_SOCK (fh, "-1 Cannot parse option %s\n", opt_key); strarray_free (plugins, plugins_num); strarray_free (identifiers, identifiers_num); return (-1); } } /* while (*buffer != 0) */ for (size_t i = 0; (i == 0) || (i < plugins_num); i++) { char *plugin = NULL; if (plugins_num != 0) plugin = plugins[i]; for (size_t j = 0; (j == 0) || (j < identifiers_num); j++) { char *identifier = NULL; int status; if (identifiers_num != 0) identifier = identifiers[j]; status = plugin_flush (plugin, DOUBLE_TO_CDTIME_T (timeout), identifier); if (status == 0) success++; else error++; } } PRINT_TO_SOCK (fh, "0 Done: %i successful, %i errors\n", success, error); strarray_free (plugins, plugins_num); strarray_free (identifiers, identifiers_num); return (0); #undef PRINT_TO_SOCK } /* int handle_flush */
static int check_path(const char *hostname, int tm_start, int tm_end, char *buffer, size_t bufferlen) /* {{{ */ { /* Path syntax where timestamp = AABBCCDDDD : * ${toppsdatadir}/${hostname}/AA/AABB/AABBCC0000-X.gz * Checking path means testing that the ${toppsdatadir}/${hostname}/AA/AABB directory exists. * If not, check with tm_margin. * * Start at tm_start. If tm_end < tm_start, search backward. */ gzFile *gzfh=NULL; int offset = 0; int status; short file_found; time_t tm; int n=0; int best_distance; int max_distance; int best_n; int best_tm; int last_seen_n_low,last_seen_n_high; int last_seen_tm_low,last_seen_tm_high; int last_before_flush_n = -1; int last_before_flush_tm = -1; int flush_needed = 0; int flush_already_done = 0; short watchdog; int search_direction; if (toppsdatadir != NULL) { status = ssnprintf (buffer, bufferlen, "%s/", toppsdatadir); if ((status < 1) || (status >= bufferlen )) { ERROR(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "Filename buffer too small (%s:%d)", __FILE__, __LINE__); return (JSONRPC_ERROR_CODE_32603_INTERNAL_ERROR); } offset += status; } DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG toppsdatadir='%s' (%s:%d)", toppsdatadir, __FILE__, __LINE__); DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG offset = %d (%s:%d)", offset, __FILE__, __LINE__); status = ssnprintf (buffer + offset, bufferlen - offset, "%s/", hostname); if ((status < 1) || (status >= bufferlen - offset)) { ERROR(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "Filename buffer too small (%s:%d)", __FILE__, __LINE__); return (JSONRPC_ERROR_CODE_32603_INTERNAL_ERROR); } offset += status; DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG offset = %d (%s:%d)", offset, __FILE__, __LINE__); /* Start search */ max_distance = abs(tm_start - tm_end); /* distance should be < max_distance */ file_found = 0; best_distance = max_distance + 1; best_n = 0; best_tm = 0; last_seen_tm_high = 0; last_seen_tm_low = 0; last_seen_n_high = 0; last_seen_n_low = 0; search_direction = 1; /* positive value to go forward at first time */ DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG WE ARE SEARCHING FOR tm_start = '%d' max_distance = %d (%s:%d)", tm_start, max_distance, __FILE__, __LINE__); n = 0; tm = 10000 * (int)(tm_start / 10000); if(tm_start <= tm_end) tm -= 10000; /* if searching forward, search starts before tm_start. */ // else tm += 10000; /* if searching backward, search starts after tm_start */ #define WATCHDOGMAX 100 /* max number of cycles in this loop. Prevent from infinite loop if something is missing in this complex algo */ for(watchdog = 0; watchdog < WATCHDOGMAX; watchdog++) { /* There are many cases to get out of this loop. See the many 'break' instructions */ int local_err; if((0 == flush_already_done) && (2 == flush_needed)) { /* Back to flush position */ assert(last_before_flush_tm != -1); /* ensure that it was initialized */ assert(last_before_flush_n != -1); /* ensure that it was initialized */ tm = last_before_flush_tm; n = last_before_flush_n; } if(mkpath_by_tm_and_num(buffer + offset, bufferlen - offset,tm, n)) { return (JSONRPC_ERROR_CODE_32603_INTERNAL_ERROR); } /* Try to open the file. * Flush if necessary */ DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG tm = %ld filename = '%s' (%s:%d)", tm, buffer, __FILE__, __LINE__); if(NULL == (gzfh = gzopen(buffer, "r"))) { DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG COULD NOT OPEN = '%s' (%s:%d)", buffer, __FILE__, __LINE__); if((0 == flush_already_done) && (2 == flush_needed)) { /* Open failed. Maybe we should flush ? */ int status; time_t flush_tm; DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG Calling plugin_flush('write_top',10,%s) (%s:%d)", hostname, __FILE__, __LINE__); status = plugin_flush ("write_top", 0, hostname); if (status == 0) { /* Flush done. Try again with older values */ } flush_already_done = 1; flush_tm = time(NULL); while((time(NULL) - flush_tm) < 10) { /* wait no more than 10 seconds for flush */ sleep(1); DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG Trying to open '%s' again... (%s:%d)", buffer, __FILE__, __LINE__); if(NULL != (gzfh = gzopen(buffer, "r"))) break; } } } /* File is supposed to be opened, with or without a flush. * Check that the file was really opened */ if(NULL == gzfh) { /* File could NOT be opened */ if((0 == flush_already_done) && (search_direction > 0)) { if(0 == flush_needed) { last_before_flush_tm = tm; /* save this position */ last_before_flush_n = n; } flush_needed++; } } else { /* File could be opened */ int distance; flush_needed = 0; distance = check_if_file_contains_tm(gzfh, buffer, tm_start,&local_err); gzclose(gzfh); DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG distance = '%d' (%s:%d)", distance, __FILE__, __LINE__); DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG best_distance was = '%d' (%s:%d)", best_distance, __FILE__, __LINE__); if(0 == local_err) { /* ignore this file if something wrong happened */ int adistance = abs(distance); /* Check if file found */ if(0 == distance) { best_distance = distance; best_n = n; best_tm = tm; file_found = 1; break; } /* Check if we found a better file */ if(adistance <= best_distance) { if( ((distance < 0) && (tm_start <= tm_end)) || ((distance > 0) && (tm_start >= tm_end)) ) { best_distance = adistance; best_n = n; best_tm = tm; if(adistance < max_distance) file_found = 1; } } search_direction = distance; } /* 0 == local_err */ DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG best_distance is now = '%d' (file found : %d)(%s:%d)", best_distance, file_found, __FILE__, __LINE__); DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG best_tm/n = '%d/%d' (%s:%d)", best_tm, best_n, __FILE__, __LINE__); } /* NULL != gzfh */ /* Move to next file and check if we should * leave. */ DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG search_direction = '%d' (%s:%d)", search_direction, __FILE__, __LINE__); if(search_direction > 0) { if(NULL == gzfh) { n = 0; tm += 10000; } else { last_seen_tm_low = tm; last_seen_n_low = n; n += 1; } if(last_seen_tm_high) { if((tm >= last_seen_tm_high) && (n >= last_seen_n_high)) { break; /* already been there or after */ } } } else { /* search_direction < 0 */ if(NULL != gzfh) { last_seen_tm_high = tm; last_seen_n_high = n; } n = 0; tm -= 10000; if(last_seen_tm_low) { if((tm <= last_seen_tm_low) && (n <= last_seen_n_low)) { break; /* already been there or before */ } } } DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG fenetre tm/n = '%d/%d','%d/%d' (%s:%d)", last_seen_tm_low,last_seen_n_low,last_seen_tm_high,last_seen_n_high, __FILE__, __LINE__); if(tm_start <= tm_end) { /* When searching forward */ if((tm > tm_end) && ( !((0 == flush_already_done) && (2 == flush_needed)) /* Do not break if flush needed */ )) break; /* There should be no reason to search and limit in the past */ } else { /* When searching backward */ if((tm > (tm_start + 10000)) && ( !((0 == flush_already_done) && (2 == flush_needed)) /* Do not break if flush needed */ )) break; /* Going too far in the future (or recent past) */ if(tm < (tm_end - 86400)) break; /* Going too far in the past */ /* Note : a big old file could contain the data we are * looking for. However, the user should not keep more * than 1 day of data in memory for each hosts. This * is not optimal and is dangerous for the data. */ } } if(watchdog >= WATCHDOGMAX) { ERROR (OUTPUT_PREFIX_JSONRPC_CB_TOPPS "Infinite loop in %s:%d. hostname='%s', tm=%d, tm_end=%d", __FILE__, __LINE__, hostname, tm_start, tm_end); return(JSONRPC_ERROR_CODE_32603_INTERNAL_ERROR); } DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG file_found = '%d' (%s:%d)", file_found, __FILE__, __LINE__); if(file_found) { DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG filename = '%s' (%s:%d)", buffer, __FILE__, __LINE__); if(mkpath_by_tm_and_num(buffer + offset, bufferlen - offset,best_tm, best_n)) { return(JSONRPC_ERROR_CODE_32603_INTERNAL_ERROR); } DEBUG(OUTPUT_PREFIX_JSONRPC_CB_TOPPS "DEBUG filename = '%s' (%s:%d)", buffer, __FILE__, __LINE__); } else { buffer[0] = '\0'; } return(0); } /* }}} check_path */