X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fgraph_list.c;h=ac4bfac78a3082e76293e98637a497c088142aaa;hb=b578a6b9f331c11ebc70d153494c7b6113990ee7;hp=2112c76faa88dc7b84623df2ee975ee93aaa6259;hpb=99f31aafefdd00b788d9ab2ba74b1cfb70c679e3;p=collection4.git diff --git a/src/graph_list.c b/src/graph_list.c index 2112c76..ac4bfac 100644 --- a/src/graph_list.c +++ b/src/graph_list.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include @@ -232,32 +234,97 @@ static int gl_clear_instances (void) /* {{{ */ static void gl_dump_cb (void *ctx, /* {{{ */ const char *str, unsigned int len) { - FILE *fh = ctx; + int fd = *((int *) ctx); + const char *buffer; + size_t buffer_size; + ssize_t status; + + buffer = str; + buffer_size = (size_t) len; + while (buffer_size > 0) + { + status = write (fd, buffer, buffer_size); + if (status < 0) + { + fprintf (stderr, "write(2) failed with status %i\n", errno); + return; + } - /* FIXME: Has everything been written? */ - fwrite ((void *) str, /* size = */ 1, /* nmemb = */ len, fh); + buffer += status; + buffer_size -= status; + } } /* }}} void gl_dump_cb */ -static int gl_dump (void) /* {{{ */ +static int gl_update_cache (void) /* {{{ */ { - FILE *fh; + int fd; yajl_gen handler; yajl_gen_config handler_config = { /* pretty = */ 1, /* indent = */ " " }; + struct flock lock; + struct stat statbuf; + int status; size_t i; - /* FIXME: Lock the file */ - fh = fopen (CACHE_FILE, "w"); - if (fh == NULL) + memset (&statbuf, 0, sizeof (statbuf)); + status = stat (CACHE_FILE, &statbuf); + if (status == 0) + { + if (statbuf.st_mtime >= gl_last_update) + { + fprintf (stderr, "gl_update_cache: Not writing to cache because it's " + "at least as new as our internal data\n"); + return (0); + } + } + else + { + status = errno; + fprintf (stderr, "gl_update_cache: stat(2) failed with status %i\n", + status); + /* Continue writing the file if possible. */ + } + + fd = open (CACHE_FILE, O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + if (fd < 0) + { + status = errno; + fprintf (stderr, "gl_update_cache: open(2) failed with status %i\n", + status); + return (status); + } + + memset (&lock, 0, sizeof (lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; /* lock everything */ + + while (42) + { + status = fcntl (fd, F_SETLKW, &lock); + if (status == 0) + break; + + if (errno == EINTR) + continue; + + fprintf (stderr, "gl_update_cache: fcntl(2) failed with status %i\n", errno); + close (fd); return (errno); + } handler = yajl_gen_alloc2 (gl_dump_cb, &handler_config, - /* alloc funcs = */ NULL, /* ctx = */ fh); + /* alloc funcs = */ NULL, /* ctx = */ &fd); if (handler == NULL) { - fclose (fh); + close (fd); return (-1); } + fprintf (stderr, "gl_update_cache: Start writing data\n"); + fflush (stderr); + yajl_gen_array_open (handler); for (i = 0; i < gl_active_num; i++) @@ -269,10 +336,13 @@ static int gl_dump (void) /* {{{ */ yajl_gen_array_close (handler); yajl_gen_free (handler); - fclose (fh); + close (fd); + + fprintf (stderr, "gl_update_cache: Finished writing data\n"); + fflush (stderr); return (0); -} /* }}} int gl_dump */ +} /* }}} int gl_update_cache */ /* * JSON parsing functions @@ -347,6 +417,23 @@ static int gl_json_string (void *user_data, /* {{{ */ return (1); } /* }}} int gl_json_string */ +static int gl_json_start_map (void *user_data) /* {{{ */ +{ + gl_json_context_t *ctx = user_data; + + if (((ctx->state & CTX_MASK) == CTX_GRAPH_SELECT) + || ((ctx->state & CTX_MASK) == CTX_INST_SELECT) + || ((ctx->state & CTX_MASK) == CTX_INST_FILE)) + { + assert (ctx->ident == NULL); + ctx->ident = ident_create (ANY_TOKEN, + ANY_TOKEN, ANY_TOKEN, + ANY_TOKEN, ANY_TOKEN); + } + + return (1); +} /* }}} int gl_json_start_map */ + static int gl_json_end_map (void *user_data) /* {{{ */ { gl_json_context_t *ctx = user_data; @@ -482,6 +569,8 @@ static int gl_json_key (void *user_data, /* {{{ */ || ((ctx->state & CTX_MASK) == CTX_INST_SELECT) || ((ctx->state & CTX_MASK) == CTX_INST_FILE)) { + assert (ctx->ident != NULL); + if (strcasecmp ("host", buffer) == 0) set_state (ctx, CTX_IDENT_HOST, CTX_IDENT_MASK); else if (strcasecmp ("plugin", buffer) == 0) @@ -494,7 +583,7 @@ static int gl_json_key (void *user_data, /* {{{ */ set_state (ctx, CTX_IDENT_TYPE_INSTANCE, CTX_IDENT_MASK); } - return (0); + return (1); } /* }}} int gl_json_key */ yajl_callbacks gl_json_callbacks = @@ -505,7 +594,7 @@ yajl_callbacks gl_json_callbacks = /* double = */ NULL, /* number = */ NULL, /* string = */ gl_json_string, - /* start_map = */ NULL, + /* start_map = */ gl_json_start_map, /* map_key = */ gl_json_key, /* end_map = */ gl_json_end_map, /* start_array = */ NULL, @@ -520,8 +609,10 @@ static int gl_read_cache (_Bool block) /* {{{ */ int fd; int cmd; + struct stat statbuf; struct flock lock; int status; + time_t now; fd = open (CACHE_FILE, O_RDONLY); if (fd < 0) @@ -556,12 +647,54 @@ static int gl_read_cache (_Bool block) /* {{{ */ if (errno == EINTR) continue; + status = errno; fprintf (stderr, "gl_read_cache: fcntl(2) failed with status %i\n", - errno); - return (errno); + status); + close (fd); + return (status); + } + + fprintf (stderr, "gl_read_cache: Opening and locking " + "cache file successful\n"); + + memset (&statbuf, 0, sizeof (statbuf)); + status = fstat (fd, &statbuf); + if (status != 0) + { + status = errno; + fprintf (stderr, "gl_read_cache: fstat(2) failed with status %i\n", + status); + close (fd); + return (status); + } + + now = time (NULL); + + if (block) + { + /* Read the file. No excuses. */ + } + else if (statbuf.st_mtime <= gl_last_update) + { + /* Our current data is at least as new as the cache. Return. */ + fprintf (stderr, "gl_read_cache: Not using cache because " + "the internal data is newer\n"); + fflush (stderr); + close (fd); + return (0); + } + else if ((statbuf.st_mtime + UPDATE_INTERVAL) < now) + { + /* We'll scan the directory anyway, so there is no need to parse the cache + * here. */ + fprintf (stderr, "gl_read_cache: Not using cache because it's too old\n"); + fflush (stderr); + close (fd); + return (0); } memset (&context, 0, sizeof (context)); + context.state = CTX_GRAPH; context.cfg = NULL; context.inst = NULL; context.ident = NULL; @@ -571,8 +704,48 @@ static int gl_read_cache (_Bool block) /* {{{ */ /* alloc funcs = */ NULL, &context); + fprintf (stderr, "gl_read_cache: Start parsing data\n"); + fflush (stderr); + + while (42) + { + ssize_t rd_status; + char buffer[1024*1024]; + + rd_status = read (fd, buffer, sizeof (buffer)); + if (rd_status < 0) + { + if ((errno == EINTR) || (errno == EAGAIN)) + continue; + + status = errno; + fprintf (stderr, "gl_read_cache: read(2) failed with status %i\n", + status); + close (fd); + return (status); + } + else if (rd_status == 0) + { + yajl_parse_complete (handle); + break; + } + else + { + yajl_parse (handle, + (unsigned char *) &buffer[0], + (unsigned int) rd_status); + } + } + + yajl_free (handle); + + gl_last_update = statbuf.st_mtime; close (fd); + fprintf (stderr, "gl_read_cache: Finished parsing data\n"); + fflush (stderr); + + return (0); } /* }}} int gl_read_cache */ /* @@ -602,15 +775,34 @@ int gl_config_submit (void) /* {{{ */ return (0); } /* }}} int graph_config_submit */ -int gl_graph_get_all (graph_callback_t callback, /* {{{ */ - void *user_data) +int gl_register_ident (const char *provider, const graph_ident_t *ident) /* {{{ */ +{ + char *ident_str = ident_to_string (ident); + + fprintf (stderr, "gl_register_ident (provider = %s, ident = %s)\n", + provider, ident_str); + + free (ident_str); + return (0); +} /* }}} int gl_register_ident */ + +int gl_register_data_provider (const char *name, data_provider_t *p) /* {{{ */ +{ + fprintf (stderr, "gl_register_data_provider (name = %s, ptr = %p)\n", + name, (void *) p); + + return (0); +} /* }}} int gl_register_data_provider */ + +int gl_graph_get_all (_Bool include_dynamic, /* {{{ */ + graph_callback_t callback, void *user_data) { size_t i; if (callback == NULL) return (EINVAL); - gl_update (); + gl_update (/* request served = */ 0); for (i = 0; i < gl_active_num; i++) { @@ -621,6 +813,9 @@ int gl_graph_get_all (graph_callback_t callback, /* {{{ */ return (status); } + if (!include_dynamic) + return (0); + for (i = 0; i < gl_dynamic_num; i++) { int status; @@ -650,7 +845,7 @@ graph_config_t *gl_graph_get_selected (void) /* {{{ */ ident = ident_create (host, plugin, plugin_instance, type, type_instance); - gl_update (); + gl_update (/* request served = */ 0); for (i = 0; i < gl_active_num; i++) { @@ -711,7 +906,7 @@ int gl_instance_get_all (graph_inst_callback_t callback, /* {{{ */ { size_t i; - gl_update (); + gl_update (/* request served = */ 0); for (i = 0; i < gl_active_num; i++) { @@ -871,20 +1066,24 @@ int gl_foreach_host (int (*callback) (const char *host, void *user_data), /* {{{ return (0); } /* }}} int gl_foreach_host */ -int gl_update (void) /* {{{ */ +int gl_update (_Bool request_served) /* {{{ */ { time_t now; int status; size_t i; - /* - printf ("Content-Type: text/plain\n\n"); - */ + if (!request_served && (gl_last_update > 0)) + return (0); now = time (NULL); if ((gl_last_update + UPDATE_INTERVAL) >= now) + { + /* Write data to cache if appropriate */ + if (request_served) + gl_update_cache (); return (0); + } /* Clear state */ gl_clear_instances (); @@ -893,18 +1092,34 @@ int gl_update (void) /* {{{ */ graph_read_config (); - status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL); + status = gl_read_cache (/* block = */ 1); + /* We have *something* to work with. Even if it's outdated, just get on with + * handling the request and take care of re-reading data later on. */ + if ((status == 0) && !request_served) + return (0); + + if ((status != 0) + || ((gl_last_update + UPDATE_INTERVAL) < now)) + { + /* Clear state */ + gl_clear_instances (); + gl_clear_hosts (); + gl_destroy (&gl_dynamic, &gl_dynamic_num); + + status = fs_scan (/* callback = */ gl_register_file, + /* user data = */ NULL); + gl_last_update = now; + } if (host_list_len > 0) qsort (host_list, host_list_len, sizeof (*host_list), gl_compare_hosts); - gl_last_update = now; - for (i = 0; i < gl_active_num; i++) graph_sort_instances (gl_active[i]); - gl_dump (); + if (request_served) + gl_update_cache (); return (status); } /* }}} int gl_update */