Exemplo n.º 1
0
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 */