static int endElement_GRID(void *data, const char *el) { xmldata_t *xmldata = (xmldata_t *) data; /* In non-scalable mode, we ignore GRIDs. */ if (!gmetad_config.scalable_mode) return 0; xmldata->grid_depth--; debug_msg("Found a </GRID>, depth is now %d", xmldata->grid_depth); datum_t hashkey, hashval; datum_t *rdatum; hash_t *summary; Source_t *source; /* Only keep info on sources we are an authority on. */ if (authority_mode(xmldata)) { source = &xmldata->source; /* Swap the metric_summary and metric_summary_pending over */ pthread_mutex_lock(source->sum_finished); { summary = xmldata->source.metric_summary_pending; xmldata->source.metric_summary_pending = xmldata->source.metric_summary; xmldata->source.metric_summary = summary; } pthread_mutex_unlock(source->sum_finished); hashkey.data = (void*) xmldata->sourcename; hashkey.size = strlen(xmldata->sourcename) + 1; hashval.data = source; /* Trim structure to the correct length. */ hashval.size = sizeof(*source) - GMETAD_FRAMESIZE + source->stringslen; /* We insert here to get an accurate hosts up/down value. */ rdatum = hash_insert( &hashkey, &hashval, xmldata->root); if (!rdatum) { err_msg("Could not insert source %s", xmldata->sourcename); return 1; } /* Write the metric summaries to the RRD. */ hash_foreach(summary, finish_processing_source, data); } return 0; }
static int endElement_CLUSTER(void *data, const char *el) { xmldata_t *xmldata = (xmldata_t *) data; datum_t hashkey, hashval; datum_t *rdatum; hash_t *summary; Source_t *source; /* Only keep info on sources we are an authority on. */ if (authority_mode(xmldata)) { source = &xmldata->source; summary = xmldata->source.metric_summary; /* Release the partial sum mutex */ pthread_mutex_unlock(source->sum_finished); hashkey.data = (void*) xmldata->sourcename; hashkey.size = strlen(xmldata->sourcename) + 1; hashval.data = source; /* Trim structure to the correct length. */ hashval.size = sizeof(*source) - GMETAD_FRAMESIZE + source->stringslen; /* We insert here to get an accurate hosts up/down value. */ rdatum = hash_insert( &hashkey, &hashval, xmldata->root); if (!rdatum) { err_msg("Could not insert source %s", xmldata->sourcename); return 1; } /* Write the metric summaries to the RRD. */ hash_foreach(summary, finish_processing_source, data); } return 0; }
/* XXX - There is an issue which will cause a failure if there are more than 16 EXTRA_ELEMENTs. This is a problem with the size of the data structure that is used to hold the metric information. */ static int startElement_EXTRA_ELEMENT (void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; int edge; struct xml_tag *xt; int i, name_off, value_off; Metric_t metric; char *name = getfield(xmldata->metric.strings, xmldata->metric.name); datum_t *rdatum; datum_t hashkey, hashval; datum_t *hash_datum = NULL; if (!xmldata->host_alive) return 0; /* Only keep extra element details if we are the authority on this cluster. */ if (!authority_mode(xmldata)) return 0; hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; hash_datum = hash_lookup (&hashkey, xmldata->host.metrics); if (!hash_datum) return 0; memcpy(&metric, hash_datum->data, hash_datum->size); datum_free(hash_datum); /* Check to make sure that we don't try to add more extra elements than the array can handle. */ if (metric.ednameslen >= MAX_EXTRA_ELEMENTS) { debug_msg("Can not add more extra elements for [%s]. Capacity of %d reached[%s].", name, MAX_EXTRA_ELEMENTS); return 0; } edge = metric.stringslen; name_off = value_off = -1; for(i = 0; attr[i]; i+=2) { xt = in_xml_list(attr[i], strlen(attr[i])); if (!xt) continue; switch (xt->tag) { case NAME_TAG: name_off = i; break; case VAL_TAG: value_off = i; break; default: break; } } if ((name_off >= 0) && (value_off >= 0)) { const char *new_name = attr[name_off+1]; const char *new_value = attr[value_off+1]; metric.ednames[metric.ednameslen++] = addstring(metric.strings, &edge, new_name); metric.edvalues[metric.edvalueslen++] = addstring(metric.strings, &edge, new_value); metric.stringslen = edge; hashkey.data = (void*)name; hashkey.size = strlen(name) + 1; /* Trim metric structure to the correct length. */ hashval.size = sizeof(metric) - GMETAD_FRAMESIZE + metric.stringslen; hashval.data = (void*) &metric; /* Update full metric in cluster host table. */ rdatum = hash_insert(&hashkey, &hashval, xmldata->host.metrics); if (!rdatum) { err_msg("Could not insert %s metric", name); } else { hash_t *summary = xmldata->source.metric_summary; Metric_t sum_metric; /* do not add every SPOOF_HOST element to the summary table. if the same metric is SPOOF'd on more than ~MAX_EXTRA_ELEMENTS hosts then its summary table is destroyed. */ if ( strlen(new_name) == 10 && !strcasecmp(new_name, SPOOF_HOST) ) return 0; /* only update summary if metric is in hash */ hash_datum = hash_lookup(&hashkey, summary); if (hash_datum) { int found = FALSE; memcpy(&sum_metric, hash_datum->data, hash_datum->size); datum_free(hash_datum); for (i = 0; i < sum_metric.ednameslen; i++) { char *chk_name = getfield(sum_metric.strings, sum_metric.ednames[i]); char *chk_value = getfield(sum_metric.strings, sum_metric.edvalues[i]); /* If the name and value already exists, skip adding the strings. */ if (!strcasecmp(chk_name, new_name) && !strcasecmp(chk_value, new_value)) { found = TRUE; break; } } if (!found) { edge = sum_metric.stringslen; sum_metric.ednames[sum_metric.ednameslen++] = addstring(sum_metric.strings, &edge, new_name); sum_metric.edvalues[sum_metric.edvalueslen++] = addstring(sum_metric.strings, &edge, new_value); sum_metric.stringslen = edge; } /* Trim graph display sum_metric at (352, 208) now or when in startElement_EXTRA_ELEMENT metric structure to the correct length. Tricky. */ hashval.size = sizeof(sum_metric) - GMETAD_FRAMESIZE + sum_metric.stringslen; hashval.data = (void*) &sum_metric; /* Update metric in summary table. */ rdatum = hash_insert(&hashkey, &hashval, summary); if (!rdatum) err_msg("Could not insert summary %s metric", name); } } } return 0; }
static int startElement_METRIC(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; ganglia_slope_t slope = GANGLIA_SLOPE_UNSPECIFIED; struct xml_tag *xt; struct type_tag *tt; datum_t *hash_datum = NULL; datum_t *rdatum; datum_t hashkey, hashval; const char *name = NULL; const char *metricval = NULL; const char *type = NULL; int do_summary; int i, edge, carbon_ret; hash_t *summary; Metric_t *metric; if (!xmldata->host_alive ) return 0; /* Get name for hash key, and val/type for summaries. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list(attr[i], strlen(attr[i])); if (!xt) continue; switch (xt->tag) { case NAME_TAG: name = attr[i+1]; hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; break; case VAL_TAG: metricval = attr[i+1]; break; case TYPE_TAG: type = attr[i+1]; break; case SLOPE_TAG: slope = cstr_to_slope(attr[i+1]); default: break; } } metric = &(xmldata->metric); memset((void*) metric, 0, sizeof(*metric)); /* Summarize all numeric metrics */ do_summary = 0; tt = in_type_list(type, strlen(type)); if (!tt) return 0; if (tt->type==INT || tt->type==UINT || tt->type==FLOAT) do_summary = 1; /* Only keep metric details if we are the authority on this cluster. */ if (authority_mode(xmldata)) { /* Save the data to a round robin database if the data source is alive */ fillmetric(attr, metric, type); if (metric->dmax && metric->tn > metric->dmax) return 0; if (do_summary && !xmldata->ds->dead && !xmldata->rval) { debug_msg("Updating host %s, metric %s", xmldata->hostname, name); if ( gmetad_config.write_rrds == 1 ) xmldata->rval = write_data_to_rrd(xmldata->sourcename, xmldata->hostname, name, metricval, NULL, xmldata->ds->step, xmldata->source.localtime, slope); if (gmetad_config.carbon_server) // if the user has specified a carbon server, send the metric to carbon as well carbon_ret=write_data_to_carbon(xmldata->sourcename, xmldata->hostname, name, metricval,xmldata->source.localtime); } metric->id = METRIC_NODE; metric->report_start = metric_report_start; metric->report_end = metric_report_end; edge = metric->stringslen; metric->name = addstring(metric->strings, &edge, name); metric->stringslen = edge; /* Set local idea of T0. */ metric->t0 = xmldata->now; metric->t0.tv_sec -= metric->tn; /* Trim metric structure to the correct length. */ hashval.size = sizeof(*metric) - GMETAD_FRAMESIZE + metric->stringslen; hashval.data = (void*) metric; /* Update full metric in cluster host table. */ rdatum = hash_insert(&hashkey, &hashval, xmldata->host.metrics); if (!rdatum) { err_msg("Could not insert %s metric", name); } } /* Always update summary for numeric metrics. */ if (do_summary) { summary = xmldata->source.metric_summary; hash_datum = hash_lookup(&hashkey, summary); if (!hash_datum) { if (!authority_mode(xmldata)) { metric = &(xmldata->metric); memset((void*) metric, 0, sizeof(*metric)); fillmetric(attr, metric, type); } /* else we have already filled in the metric above. */ } else { memcpy(&xmldata->metric, hash_datum->data, hash_datum->size); datum_free(hash_datum); metric = &(xmldata->metric); switch (tt->type) { case INT: case UINT: case FLOAT: metric->val.d += (double) strtod(metricval, (char**) NULL); break; default: break; } } metric->num++; metric->t0 = xmldata->now; /* tell cleanup thread we are using this */ /* Trim metric structure to the correct length. Tricky. */ hashval.size = sizeof(*metric) - GMETAD_FRAMESIZE + metric->stringslen; hashval.data = (void*) metric; /* Update metric in summary table. */ rdatum = hash_insert(&hashkey, &hashval, summary); if (!rdatum) err_msg("Could not insert %s metric", name); } return 0; }
static int startElement_HOST(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; datum_t *hash_datum = NULL; datum_t *rdatum; datum_t hashkey, hashval; struct xml_tag *xt; uint32_t tn=0; uint32_t tmax=0; uint32_t reported=0; const char *name = NULL; int edge; int i; Host_t *host; hash_t *hosts; /* Check if the host is up. */ for (i = 0; attr[i]; i+=2) { xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; if (xt->tag == REPORTED_TAG) reported = strtoul(attr[i+1], (char **)NULL, 10); else if (xt->tag == TN_TAG) tn = atoi(attr[i+1]); else if (xt->tag == TMAX_TAG) tmax = atoi(attr[i+1]); else if (xt->tag == NAME_TAG) name = attr[i+1]; } /* Is this host alive? For pre-2.5.0, we use the 60-second * method, otherwise we use the host's TN and TMAX attrs. */ xmldata->host_alive = (xmldata->old || !tmax) ? abs(xmldata->source.localtime - reported) < 60 : tn < tmax * 4; if (xmldata->host_alive) xmldata->source.hosts_up++; else xmldata->source.hosts_down++; /* Only keep host details if we are the authority on this cluster. */ if (!authority_mode(xmldata)) return 0; host = &(xmldata->host); /* Use node Name for hash key (Query processing * requires a name key). */ xmldata->hostname = realloc(xmldata->hostname, strlen(name)+1); strcpy(xmldata->hostname, name); /* Convert name to lower case - host names can't be * case sensitive */ /*for(i = 0; name[i] != 0; i++) xmldata->hostname[i] = tolower(name[i]); xmldata->hostname[i] = 0; */ hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; hosts = xmldata->source.authority; hash_datum = hash_lookup (&hashkey, hosts); if (!hash_datum) { memset((void*) host, 0, sizeof(*host)); host->id = HOST_NODE; host->report_start = host_report_start; host->report_end = host_report_end; /* Only create one hash table for the host's metrics. Not user/builtin * like gmond. */ host->metrics = hash_create(DEFAULT_METRICSIZE); if (!host->metrics) { err_msg("Could not create metric hash for host %s", name); return 1; } } else { /* Copy the stored host data into our Host buffer in xmldata. */ memcpy(host, hash_datum->data, hash_datum->size); datum_free(hash_datum); } /* Edge has the same invariant as in fillmetric(). */ edge = 0; host->location = -1; host->tags = -1; host->reported = reported; host->tn = tn; host->tmax = tmax; /* sacerdoti: Host TN tracks what gmond sees. TN=0 when gmond received last * heartbeat from node. Works because clocks move at same speed, and TN is * a relative timespan. */ host->t0 = xmldata->now; host->t0.tv_sec -= host->tn; /* We will store this host in the cluster's authority table. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; switch( xt->tag ) { case IP_TAG: host->ip = addstring(host->strings, &edge, attr[i+1]); break; case DMAX_TAG: host->dmax = strtoul(attr[i+1], (char **)NULL, 10); break; case LOCATION_TAG: host->location = addstring(host->strings, &edge, attr[i+1]); break; case TAGS_TAG: host->tags = addstring(host->strings, &edge, attr[i+1]); break; case STARTED_TAG: host->started = strtoul(attr[i+1], (char **)NULL, 10); break; default: break; } } host->stringslen = edge; /* Trim structure to the correct length. */ hashval.size = sizeof(*host) - GMETAD_FRAMESIZE + host->stringslen; hashval.data = host; /* We dont care if this is an insert or an update. */ rdatum = hash_insert(&hashkey, &hashval, hosts); if (!rdatum) { err_msg("Could not insert host %s", name); return 1; } return 0; }
static int startElement_CLUSTER(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; struct xml_tag *xt; datum_t *hash_datum = NULL; datum_t hashkey; const char *name = NULL; int edge; int i; Source_t *source; /* Get name for hash key */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; if (xt->tag == NAME_TAG) name = attr[i+1]; } /* Only keep cluster details if we are the authority on this cluster. */ if (!authority_mode(xmldata)) return 0; source = &(xmldata->source); xmldata->sourcename = realloc(xmldata->sourcename, strlen(name)+1); strcpy(xmldata->sourcename, name); hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; hash_datum = hash_lookup(&hashkey, xmldata->root); if (!hash_datum) { memset((void*) source, 0, sizeof(*source)); /* Set the identity of this host. */ source->id = CLUSTER_NODE; source->report_start = source_report_start; source->report_end = source_report_end; source->authority = hash_create(DEFAULT_CLUSTERSIZE); if (!source->authority) { err_msg("Could not create hash table for cluster %s", name); return 1; } if(gmetad_config.case_sensitive_hostnames == 0) hash_set_flags(source->authority, HASH_FLAG_IGNORE_CASE); source->metric_summary = hash_create(DEFAULT_METRICSIZE); if (!source->metric_summary) { err_msg("Could not create summary hash for cluster %s", name); return 1; } source->ds = xmldata->ds; /* Initialize the partial sum lock */ source->sum_finished = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(source->sum_finished, NULL); /* Grab the "partial sum" mutex until we are finished summarizing. */ pthread_mutex_lock(source->sum_finished); } else { memcpy(source, hash_datum->data, hash_datum->size); datum_free(hash_datum); /* We need this lock before zeroing metric sums. */ pthread_mutex_lock(source->sum_finished); source->hosts_up = 0; source->hosts_down = 0; hash_foreach(source->metric_summary, zero_out_summary, NULL); } /* Edge has the same invariant as in fillmetric(). */ edge = 0; source->owner = -1; source->latlong = -1; source->url = -1; /* Fill in cluster attributes. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; switch( xt->tag ) { case OWNER_TAG: source->owner = addstring(source->strings, &edge, attr[i+1]); break; case LATLONG_TAG: source->latlong = addstring(source->strings, &edge, attr[i+1]); break; case URL_TAG: source->url = addstring(source->strings, &edge, attr[i+1]); break; case LOCALTIME_TAG: source->localtime = strtoul(attr[i+1], (char **) NULL, 10); break; default: break; } } source->stringslen = edge; return 0; }
static int startElement_GRID(void *data, const char *el, const char **attr) { xmldata_t *xmldata = (xmldata_t *)data; struct xml_tag *xt; datum_t *hash_datum = NULL; datum_t hashkey; const char *name = NULL; int edge; int i; Source_t *source; /* In non-scalable mode, we ignore GRIDs. */ if (!gmetad_config.scalable_mode) return 0; /* We do not keep info on nested grids. */ if (authority_mode(xmldata)) { /* Get name for hash key */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list (attr[i], strlen(attr[i])); if (!xt) continue; if (xt->tag == NAME_TAG) { name = attr[i+1]; xmldata->sourcename = realloc(xmldata->sourcename, strlen(name)+1); strcpy(xmldata->sourcename, name); hashkey.data = (void*) name; hashkey.size = strlen(name) + 1; } } source = &(xmldata->source); /* Query the hash table for this cluster */ hash_datum = hash_lookup(&hashkey, xmldata->root); if (!hash_datum) { /* New Cluster */ memset((void*) source, 0, sizeof(*source)); source->id = GRID_NODE; source->report_start = source_report_start; source->report_end = source_report_end; source->metric_summary = hash_create(DEFAULT_METRICSIZE); if (!source->metric_summary) { err_msg("Could not create summary hash for cluster %s", name); return 1; } source->ds = xmldata->ds; /* Initialize the partial sum lock */ source->sum_finished = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); pthread_mutex_init(source->sum_finished, NULL); /* Grab the "partial sum" mutex until we are finished * summarizing. */ pthread_mutex_lock(source->sum_finished); } else { /* Found Cluster. Put into our Source buffer in xmldata. */ memcpy(source, hash_datum->data, hash_datum->size); datum_free(hash_datum); /* Grab the "partial sum" mutex until we are finished * summarizing. Needs to be done asap.*/ pthread_mutex_lock(source->sum_finished); source->hosts_up = 0; source->hosts_down = 0; hash_foreach(source->metric_summary, zero_out_summary, NULL); } /* Edge has the same invariant as in fillmetric(). */ edge = 0; /* Fill in grid attributes. */ for(i = 0; attr[i]; i+=2) { xt = in_xml_list(attr[i], strlen(attr[i])); if (!xt) continue; switch( xt->tag ) { case AUTHORITY_TAG: source->authority_ptr = addstring(source->strings, &edge, attr[i+1]); break; case LOCALTIME_TAG: source->localtime = strtoul(attr[i+1], (char **) NULL, 10); break; default: break; } } source->stringslen = edge; } /* Must happen after all processing of this tag. */ xmldata->grid_depth++; debug_msg("Found a <GRID>, depth is now %d", xmldata->grid_depth); return 0; }