From: oetiker Date: Mon, 25 May 2009 22:23:06 +0000 (+0000) Subject: While restoring, rrd_restore uses between 30 and 40 times as much memory as X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=9e0553265a0b0d700d1b75891b97dc5cf1031680;p=rrdtool.git While restoring, rrd_restore uses between 30 and 40 times as much memory as the size of the rrd file to be restored. This is due to the use of libxml2 for parsing the the whole file prior to turning it into rrd structs. This patch switches rrd_restore to using the xmlTextReader interface for incremental consumtion of xml files. This reduces the memory requirements to about twice the size of the rrd file which should be quite manageable for most cases. The parsing is about 25% less efficient than with the original libxml2 version of rrd_restore. This could be in part due to the more liberal use of malloced memory. Optimizing this is for another day though. --tobi git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1811 a5681a0c-68f1-0310-ab6d-d61299d08faa --- diff --git a/src/rrd_restore.c b/src/rrd_restore.c index 369f7bd..6a28e34 100644 --- a/src/rrd_restore.c +++ b/src/rrd_restore.c @@ -1,36 +1,17 @@ /***************************************************************************** - * RRDtool 1.3.2 Copyright by Tobi Oetiker, 1997-2008 - * This file: Copyright 2008 Florian octo Forster - * Distributed under the GPL + * RRDtool 1.3.2 Copyright by Tobi Oetiker, 1997-2009 ***************************************************************************** - * rrd_restore.c Contains logic to parse XML input and create an RRD file + * rrd_restore.c Contains logic to parse XML input and create an RRD file + * initial libxml2 version of rrd_restore (c) by Florian octo Forster ***************************************************************************** * $Id$ *************************************************************************** */ -/* - * This program is free software; you can redistribute it and / or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (t your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110 - 1301 USA - * - * Authors: - * Florian octo Forster - **/ - -#include #include +#include #include -#include +#include +#include #ifndef WIN32 @@ -46,152 +27,259 @@ # define open _open # define close _close #endif -#include + #include "rrd_tool.h" #include "rrd_rpncalc.h" + #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0])) + static int opt_range_check = 0; static int opt_force_overwrite = 0; /* - * Auxiliary functions + * Helpers */ -static int get_string_from_node( - xmlDoc * doc, - xmlNode * node, - char *buffer, - size_t buffer_size) -{ - xmlChar *temp0; - char *begin_ptr; - char *end_ptr; - temp0 = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - if (temp0 == NULL) { - rrd_set_error("get_string_from_node: xmlNodeListGetString failed."); - return (-1); +/* skip all but tags. complain if we do not get the right tag */ +/* dept -1 causes depth to be ignored */ +static xmlChar* get_xml_element ( + xmlTextReaderPtr reader + ) +{ + while(xmlTextReaderRead(reader)){ + int type; + xmlChar *name; + type = xmlTextReaderNodeType(reader); + if (type == XML_READER_TYPE_TEXT){ + xmlChar *value; + value = xmlTextReaderValue(reader); + rrd_set_error("line %d: expected element but found text '%s'", + xmlTextReaderGetParserLineNumber(reader),value); + xmlFree(value); + return NULL; + } + /* skip all other non-elements */ + if (type != XML_READER_TYPE_ELEMENT && type != XML_READER_TYPE_END_ELEMENT) + continue; + + name = xmlTextReaderName(reader); + if (type == XML_READER_TYPE_END_ELEMENT){ + xmlChar *temp; + xmlChar *temp2; + temp = (xmlChar*)sprintf_alloc("/%s",name); + temp2 = xmlStrdup(temp); + free(temp); + xmlFree(name); + return temp2; + } + /* all seems well, return the happy news */ + return name; } - - begin_ptr = (char *) temp0; - while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0]))) - begin_ptr++; - - if (begin_ptr[0] == 0) { - xmlFree(temp0); - buffer[0] = 0; - return (0); + rrd_set_error("the xml ended while we were looking for an element"); + return NULL; +} /* get_xml_element */ + +static void local_rrd_free (rrd_t *rrd) +{ + free(rrd->live_head); + free(rrd->stat_head); + free(rrd->ds_def); + free(rrd->rra_def); + free(rrd->rra_ptr); + free(rrd->pdp_prep); + free(rrd->cdp_prep); + free(rrd->rrd_value); + free(rrd); +} + + +static int expect_element ( + xmlTextReaderPtr reader, + char *exp_name) +{ + xmlChar *name; + name = get_xml_element(reader); + if (!name) + return -1; + if (xmlStrcasecmp(name,(xmlChar *)exp_name) != 0){ + rrd_set_error("line %d: expected <%s> element but found <%s>", + xmlTextReaderGetParserLineNumber(reader),name,exp_name); + xmlFree(name); + return -1; } + xmlFree(name); + return 0; +} /* expect_element */ - end_ptr = begin_ptr; - while ((end_ptr[0] != 0) && (!isspace(end_ptr[0]))) - end_ptr++; - end_ptr[0] = 0; - - strncpy(buffer, begin_ptr, buffer_size); - buffer[buffer_size - 1] = 0; - - xmlFree(temp0); - - return (0); -} /* int get_string_from_node */ - -static int get_long_from_node( - xmlDoc * doc, - xmlNode * node, - long *value) +static int expect_element_end ( + xmlTextReaderPtr reader, + char *exp_name) { - long temp; - char *str_ptr; - char *end_ptr; - - str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - if (str_ptr == NULL) { - rrd_set_error("get_long_from_node: xmlNodeListGetString failed."); - return (-1); + xmlChar *name; + name = get_xml_element(reader); + if (name == NULL) + return -1; + if (xmlStrcasecmp(name+1,(xmlChar *)exp_name) != 0 || name[0] != '/'){ + rrd_set_error("line %d: expected end element but found <%s>", + xmlTextReaderGetParserLineNumber(reader),exp_name,name); + xmlFree(name); + return -1; } + xmlFree(name); + return 0; +} /* expect_element_end */ - end_ptr = NULL; - temp = strtol(str_ptr, &end_ptr, 0); - xmlFree(str_ptr); - if (str_ptr == end_ptr) { - rrd_set_error("get_long_from_node: Cannot parse buffer as long: %s", - str_ptr); - return (-1); +static xmlChar* get_xml_text ( + xmlTextReaderPtr reader + ) +{ + while(xmlTextReaderRead(reader)){ + xmlChar *ret; + xmlChar *text; + xmlChar *begin_ptr; + xmlChar *end_ptr; + int type; + type = xmlTextReaderNodeType(reader); + if (type == XML_READER_TYPE_ELEMENT){ + xmlChar *name; + name = xmlTextReaderName(reader); + rrd_set_error("line %d: expected a value but found an <%s> element", + xmlTextReaderGetParserLineNumber(reader), + name); + xmlFree(name); + return NULL; + } + /* skip all other non-text */ + if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT) + continue; + + text = xmlTextReaderValue(reader); + + begin_ptr = text; + while ((begin_ptr[0] != 0) && (isspace(begin_ptr[0]))) + begin_ptr++; + if (begin_ptr[0] == 0) { + xmlFree(text); + return xmlStrdup(BAD_CAST ""); + } + end_ptr = begin_ptr; + while ((end_ptr[0] != 0) && (!isspace(end_ptr[0]))) + end_ptr++; + end_ptr[0] = 0; + + ret = xmlStrdup(begin_ptr); + xmlFree(text); + return ret; } + rrd_set_error("file ended while looking for text"); + return NULL; +} /* get_xml_text */ - *value = temp; - return (0); -} /* int get_long_from_node */ - -static int get_ulong_from_node( - xmlDoc * doc, - xmlNode * node, - unsigned long *value) +static int get_xml_string( + xmlTextReaderPtr reader, + char *value, + int max_len) { - unsigned long temp; - char *str_ptr; - char *end_ptr; - - str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - if (str_ptr == NULL) { - rrd_set_error("get_ulong_from_node: xmlNodeListGetString failed."); - return (-1); + xmlChar *str; + str = get_xml_text(reader); + if (str != NULL){ + strncpy(value,(char *)str,max_len); + xmlFree(str); + return 0; } + else + return -1; +} - end_ptr = NULL; - temp = strtoul(str_ptr, &end_ptr, 0); - xmlFree(str_ptr); - - if (str_ptr == end_ptr) { - rrd_set_error("get_ulong_from_node: Cannot parse buffer as unsigned long: %s", - str_ptr); - return (-1); + +static int get_xml_long( + xmlTextReaderPtr reader, + long *value) +{ + xmlChar *text; + long temp; + if ((text = get_xml_text(reader)) != NULL){ + errno = 0; + temp = strtol((char *)text,NULL, 0); + if (errno>0){ + rrd_set_error("ling %d: get_xml_long from '%s' %s", + xmlTextReaderGetParserLineNumber(reader), + text,rrd_strerror(errno)); + xmlFree(text); + return -1; + } + xmlFree(text); + *value = temp; + return 0; } + return -1; +} /* get_xml_long */ - *value = temp; - - return (0); -} /* int get_ulong_from_node */ - -static int get_double_from_node( - xmlDoc * doc, - xmlNode * node, - double *value) +static int get_xml_ulong( + xmlTextReaderPtr reader, + ulong *value) { - double temp; - char *str_ptr; - char *end_ptr; - - str_ptr = (char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - if (str_ptr == NULL) { - rrd_set_error("get_double_from_node: xmlNodeListGetString failed."); - return (-1); - } - - if (strstr(str_ptr, "NaN") != NULL) - { - *value = DNAN; - xmlFree(str_ptr); + + xmlChar *text; + ulong temp; + if ((text = get_xml_text(reader)) != NULL){ + errno = 0; + temp = strtoul((char *)text,NULL, 0); + if (errno>0){ + rrd_set_error("ling %d: get_xml_ulong from '%s' %s", + xmlTextReaderGetParserLineNumber(reader), + text,rrd_strerror(errno)); + xmlFree(text); + return -1; + } + xmlFree(text); + *value = temp; return 0; } + return -1; +} /* get_xml_ulong */ - end_ptr = NULL; - temp = strtod(str_ptr, &end_ptr); - xmlFree(str_ptr); - - if (str_ptr == end_ptr) { - rrd_set_error - ("get_double_from_node: Cannot parse buffer as double: %s", - str_ptr); - return (-1); +static int get_xml_double( + xmlTextReaderPtr reader, + double *value) +{ + + char *text; + double temp; + if ((text = (char *)get_xml_text(reader))!= NULL){ + if (strcasestr(text,"nan")){ + *value = DNAN; + xmlFree(text); + return 0; + } + else if (strcasestr(text,"-inf")){ + *value = -DINF; + xmlFree(text); + return 0; + } + else if (strcasestr(text,"+inf") + || strcasestr(text,"inf")){ + *value = DINF; + xmlFree(text); + return 0; + } + errno = 0; + temp = strtod((char *)text,NULL); + xmlFree(text); + if (errno>0){ + rrd_set_error("ling %d: get_xml_double from '%s' %s", + xmlTextReaderGetParserLineNumber(reader), + text,rrd_strerror(errno)); + return -1; + } + *value = temp; + return 0; } + return -1; +} /* get_xml_double */ - *value = temp; - - return (0); -} /* int get_double_from_node */ static int value_check_range( rrd_value_t *rrd_value, @@ -211,67 +299,47 @@ static int value_check_range( *rrd_value = DNAN; return (0); -} /* int value_check_range */ +} /* int value_check_range */ /* * Parse the block within an RRA definition */ + static int parse_tag_rra_database_row( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd, rrd_value_t *rrd_value) { unsigned int values_count = 0; - xmlNode *child; int status; - + status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "v") == 0) { - if (values_count < rrd->stat_head->ds_cnt) { - status = - get_double_from_node(doc, child, - rrd_value + values_count); - if (status == 0) - value_check_range(rrd_value + values_count, - rrd->ds_def + values_count); - } - - values_count++; - } else { - rrd_set_error("parse_tag_rra_database_row: Unknown tag: %s", - child->name); - status = -1; + for (values_count = 0;values_count < rrd->stat_head->ds_cnt;values_count++){ + if (expect_element(reader,"v") == 0){ + status = get_xml_double(reader,rrd_value + values_count); + if (status == 0) + value_check_range(rrd_value + values_count, + rrd->ds_def + values_count); + else + break; + } else + return -1; + if (expect_element(reader,"/v") == -1){ + return -1; } - - if (status != 0) - break; - } /* for (child = node->xmlChildrenNode) */ - - if (values_count != rrd->stat_head->ds_cnt) { - rrd_set_error("parse_tag_rra_database_row: Row has %u values " - "and RRD has %lu data sources.", - values_count, rrd->stat_head->ds_cnt); - status = -1; } - - return (status); + return status; } /* int parse_tag_rra_database_row */ static int parse_tag_rra_database( - xmlDoc * doc, - xmlNode * node, - rrd_t *rrd) + xmlTextReaderPtr reader, + rrd_t *rrd ) { rra_def_t *cur_rra_def; unsigned int total_row_cnt; - xmlNode *child; int status; int i; + xmlChar *element; total_row_cnt = 0; for (i = 0; i < (((int) rrd->stat_head->rra_cnt) - 1); i++) @@ -280,15 +348,12 @@ static int parse_tag_rra_database( cur_rra_def = rrd->rra_def + i; status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "row") == 0) { - rrd_value_t *temp; - rrd_value_t *cur_rrd_value; - unsigned int total_values_count = rrd->stat_head->ds_cnt - * (total_row_cnt + 1); + while ((element = get_xml_element(reader)) != NULL){ + if (xmlStrcasecmp(element,(const xmlChar *)"row") == 0){ + rrd_value_t *temp; + rrd_value_t *cur_rrd_value; + unsigned int total_values_count = rrd->stat_head->ds_cnt + * (total_row_cnt + 1); /* Allocate space for the new values.. */ temp = (rrd_value_t *) realloc(rrd->rrd_value, @@ -297,7 +362,7 @@ static int parse_tag_rra_database( if (temp == NULL) { rrd_set_error("parse_tag_rra_database: realloc failed."); status = -1; - break; + break; } rrd->rrd_value = temp; cur_rrd_value = rrd->rrd_value @@ -308,18 +373,25 @@ static int parse_tag_rra_database( cur_rra_def->row_cnt++; status = - parse_tag_rra_database_row(doc, child, rrd, cur_rrd_value); - } /* if (xmlStrcmp (child->name, (const xmlChar *) "row") == 0) */ + parse_tag_rra_database_row(reader, rrd, cur_rrd_value); + if (status == 0) + status = expect_element(reader,"/row"); + } /* if (xmlStrcasecmp(element,"row")) */ else { - rrd_set_error("parse_tag_rra_database: Unknown tag: %s", - child->name); - status = -1; + if ( xmlStrcasecmp(element,(const xmlChar *)"/database") == 0){ + xmlFree(element); + break; + } + else { + rrd_set_error("line %d: found unexpected tag: %s", + xmlTextReaderGetParserLineNumber(reader),element); + status = -1; + } } - + xmlFree(element); if (status != 0) - break; - } /* for (child = node->xmlChildrenNode) */ - + break; + } return (status); } /* int parse_tag_rra_database */ @@ -327,167 +399,146 @@ static int parse_tag_rra_database( * Parse the block within an RRA definition */ static int parse_tag_rra_cdp_prep_ds_history( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, cdp_prep_t *cdp_prep) { /* Make `history_buffer' the same size as the scratch area, plus the * terminating NULL byte. */ - char history_buffer[sizeof(((cdp_prep_t *)0)->scratch) + 1]; + xmlChar *history; char *history_ptr; - int status; int i; - - status = get_string_from_node(doc, node, - history_buffer, sizeof(history_buffer)); - if (status != 0) - return (-1); - - history_ptr = (char *) (&cdp_prep->scratch[0]); - for (i = 0; history_buffer[i] != '\0'; i++) - history_ptr[i] = (history_buffer[i] == '1') ? 1 : 0; - - return (0); -} /* int parse_tag_rra_cdp_prep_ds_history */ + if ((history = get_xml_text(reader)) != NULL){ + history_ptr = (char *) (&cdp_prep->scratch[0]); + for (i = 0; history[i] != '\0'; i++) + history_ptr[i] = (history[i] == '1') ? 1 : 0; + xmlFree(history); + return 0; + } + return -1; +} /* int parse_tag_rra_cdp_prep_ds_history */ static int parse_tag_rra_cdp_prep_ds( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd, cdp_prep_t *cdp_prep) { - xmlNode *child; int status; - + xmlChar *element; memset(cdp_prep, '\0', sizeof(cdp_prep_t)); - status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if (atoi(rrd->stat_head->version) == 1) { - cdp_prep->scratch[CDP_primary_val].u_val = 0.0; - cdp_prep->scratch[CDP_secondary_val].u_val = 0.0; - } - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "primary_value") == - 0) + status = -1; + + if (atoi(rrd->stat_head->version) == 1) { + cdp_prep->scratch[CDP_primary_val].u_val = 0.0; + cdp_prep->scratch[CDP_secondary_val].u_val = 0.0; + } + + while ((element = get_xml_element(reader)) != NULL){ + if (xmlStrcasecmp(element, (const xmlChar *) "primary_value") == 0) status = - get_double_from_node(doc, child, - &cdp_prep->scratch[CDP_primary_val]. - u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "secondary_value") - == 0) + get_xml_double(reader,&cdp_prep->scratch[CDP_primary_val].u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "secondary_value") == 0) status = - get_double_from_node(doc, child, - &cdp_prep->scratch[CDP_secondary_val]. - u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "intercept") == 0) - status = get_double_from_node(doc, child, + get_xml_double(reader,&cdp_prep->scratch[CDP_secondary_val].u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "intercept") == 0) + status = get_xml_double(reader, &cdp_prep-> scratch[CDP_hw_intercept].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "last_intercept") == + else if (xmlStrcasecmp(element, (const xmlChar *) "last_intercept") == 0) status = - get_double_from_node(doc, child, + get_xml_double(reader, &cdp_prep-> scratch[CDP_hw_last_intercept].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "slope") == 0) - status = get_double_from_node(doc, child, - &cdp_prep->scratch[CDP_hw_slope]. - u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "last_slope") == 0) - status = get_double_from_node(doc, child, - &cdp_prep-> - scratch[CDP_hw_last_slope].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "nan_count") == 0) - status = get_ulong_from_node(doc, child, - &cdp_prep-> - scratch[CDP_null_count].u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "last_nan_count") == + else if (xmlStrcasecmp(element, (const xmlChar *) "slope") == 0) + status = get_xml_double(reader, + &cdp_prep->scratch[CDP_hw_slope]. + u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "last_slope") == 0) + status = get_xml_double(reader, + &cdp_prep-> + scratch[CDP_hw_last_slope].u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "nan_count") == 0) + status = get_xml_ulong(reader, + &cdp_prep-> + scratch[CDP_null_count].u_cnt); + else if (xmlStrcasecmp(element, (const xmlChar *) "last_nan_count") == 0) status = - get_ulong_from_node(doc, child, - &cdp_prep-> - scratch[CDP_last_null_count].u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal") == 0) - status = get_double_from_node(doc, child, - &cdp_prep->scratch[CDP_hw_seasonal]. - u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "last_seasonal") == + get_xml_ulong(reader, + &cdp_prep-> + scratch[CDP_last_null_count].u_cnt); + else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal") == 0) + status = get_xml_double(reader, + &cdp_prep->scratch[CDP_hw_seasonal]. + u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "last_seasonal") == 0) status = - get_double_from_node(doc, child, + get_xml_double(reader, &cdp_prep->scratch[CDP_hw_last_seasonal]. u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "init_flag") == 0) - status = get_ulong_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "init_flag") == 0) + status = get_xml_ulong(reader, &cdp_prep-> scratch[CDP_init_seasonal].u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "history") == 0) - status = parse_tag_rra_cdp_prep_ds_history(doc, child, cdp_prep); - else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) - status = get_double_from_node(doc, child, - &cdp_prep->scratch[CDP_val].u_val); - else if (xmlStrcmp(child->name, + else if (xmlStrcasecmp(element, (const xmlChar *) "history") == 0) + status = parse_tag_rra_cdp_prep_ds_history(reader, cdp_prep); + else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0) + status = get_xml_double(reader, + &cdp_prep->scratch[CDP_val].u_val); + else if (xmlStrcasecmp(element, (const xmlChar *) "unknown_datapoints") == 0) - status = get_ulong_from_node(doc, child, + status = get_xml_ulong(reader, &cdp_prep-> scratch[CDP_unkn_pdp_cnt].u_cnt); + else if (xmlStrcasecmp(element, + (const xmlChar *) "/ds") == 0){ + xmlFree(element); + break; + } else { rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s", - child->name); + element); status = -1; + xmlFree(element); + break; } - + if (status != 0){ + xmlFree(element); + break; + } + status = expect_element_end(reader,(char *)element); + xmlFree(element); if (status != 0) break; - } - + } return (status); } /* int parse_tag_rra_cdp_prep_ds */ static int parse_tag_rra_cdp_prep( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd, cdp_prep_t *cdp_prep) { - xmlNode *child; int status; - unsigned int ds_count = 0; + unsigned int ds_count; status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) { - if (ds_count >= rrd->stat_head->ds_cnt) - status = -1; - else { - status = parse_tag_rra_cdp_prep_ds(doc, child, rrd, - cdp_prep + ds_count); - ds_count++; - } + for ( ds_count = 0; ds_count < rrd->stat_head->ds_cnt;ds_count++){ + if (expect_element(reader,"ds") == 0) { + status = parse_tag_rra_cdp_prep_ds(reader, rrd, + cdp_prep + ds_count); + if (status != 0) + break; } else { - rrd_set_error("parse_tag_rra_cdp_prep: Unknown tag: %s", - child->name); - status = -1; - } - - if (status != 0) + status = -1; break; + } } - - if (ds_count != rrd->stat_head->ds_cnt) { - rrd_set_error("parse_tag_rra_cdp_prep: There are %i data sources in " - "the RRD file, but %i in this cdp_prep block!", - (int) rrd->stat_head->ds_cnt, ds_count); - status = -1; - } - + if (status == 0) + status = expect_element(reader,"/cdp_prep"); return (status); } /* int parse_tag_rra_cdp_prep */ @@ -495,50 +546,46 @@ static int parse_tag_rra_cdp_prep( * Parse the block within an RRA definition */ static int parse_tag_rra_params( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rra_def_t *rra_def) { - xmlNode *child; + xmlChar *element; int status; - status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; + status = -1; + while ((element = get_xml_element(reader)) != NULL){ /* * Parameters for CF_HWPREDICT */ - else if (xmlStrcmp(child->name, (const xmlChar *) "hw_alpha") == 0) - status = get_double_from_node(doc, child, + if (xmlStrcasecmp(element, (const xmlChar *) "hw_alpha") == 0) + status = get_xml_double(reader, &rra_def->par[RRA_hw_alpha].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "hw_beta") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "hw_beta") == 0) + status = get_xml_double(reader, &rra_def->par[RRA_hw_beta].u_val); - else if (xmlStrcmp(child->name, + else if (xmlStrcasecmp(element, (const xmlChar *) "dependent_rra_idx") == 0) - status = get_ulong_from_node(doc, child, + status = get_xml_ulong(reader, &rra_def-> par[RRA_dependent_rra_idx].u_cnt); /* * Parameters for CF_SEASONAL and CF_DEVSEASONAL */ - else if (xmlStrcmp(child->name, (const xmlChar *) "seasonal_gamma") == + else if (xmlStrcasecmp(element, (const xmlChar *) "seasonal_gamma") == 0) status = - get_double_from_node(doc, child, + get_xml_double(reader, &rra_def->par[RRA_seasonal_gamma].u_val); - else if (xmlStrcmp - (child->name, (const xmlChar *) "seasonal_smooth_idx") == 0) + else if (xmlStrcasecmp + (element, (const xmlChar *) "seasonal_smooth_idx") == 0) status = - get_ulong_from_node(doc, child, + get_xml_ulong(reader, &rra_def-> par[RRA_seasonal_smooth_idx].u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "smoothing_window") + else if (xmlStrcasecmp(element, (const xmlChar *) "smoothing_window") == 0) status = - get_double_from_node(doc, child, + get_xml_double(reader, &rra_def-> par[RRA_seasonal_smoothing_window]. u_val); @@ -546,75 +593,73 @@ static int parse_tag_rra_params( /* * Parameters for CF_FAILURES */ - else if (xmlStrcmp(child->name, (const xmlChar *) "delta_pos") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "delta_pos") == 0) + status = get_xml_double(reader, &rra_def->par[RRA_delta_pos].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "delta_neg") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "delta_neg") == 0) + status = get_xml_double(reader, &rra_def->par[RRA_delta_neg].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "window_len") == 0) - status = get_ulong_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "window_len") == 0) + status = get_xml_ulong(reader, &rra_def->par[RRA_window_len]. u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "failure_threshold") + else if (xmlStrcasecmp(element, (const xmlChar *) "failure_threshold") == 0) status = - get_ulong_from_node(doc, child, + get_xml_ulong(reader, &rra_def-> par[RRA_failure_threshold].u_cnt); /* * Parameters for CF_AVERAGE, CF_MAXIMUM, CF_MINIMUM, and CF_LAST */ - else if (xmlStrcmp(child->name, (const xmlChar *) "xff") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "xff") == 0) + status = get_xml_double(reader, &rra_def->par[RRA_cdp_xff_val]. u_val); /* * Compatibility code for 1.0.49 */ - else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) { /* {{{ */ + else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0) { /* {{{ */ unsigned int i = 0; - while (42) { - if (i >= ARRAY_LENGTH(rra_def->par)) { - status = -1; - break; - } - + for (i=0;ipar);i++){ if ((i == RRA_dependent_rra_idx) || (i == RRA_seasonal_smooth_idx) || (i == RRA_failure_threshold)) - status = get_ulong_from_node(doc, child, + status = get_xml_ulong(reader, &rra_def->par[i]. u_cnt); else - status = get_double_from_node(doc, child, + status = get_xml_double(reader, &rra_def->par[i].u_val); if (status != 0) break; - - /* When this loops exits (sucessfully) `child' points to the last - * `value' tag in the list. */ - if ((child->next == NULL) - || (xmlStrcmp(child->name, (const xmlChar *) "value") != - 0)) - break; - - child = child->next; - i++; + if ( i-1 < ARRAY_LENGTH(rra_def->par)){ + status = expect_element(reader,"/value"); + if (status == 0){ + status = expect_element(reader,"value"); + } + } + if (status != 0){ + break; + } } - } /* }}} */ + } /* }}} */ + else if (xmlStrcasecmp(element,(const xmlChar *) "/params") == 0){ + xmlFree(element); + return status; + } /* }}} */ else { - rrd_set_error("parse_tag_rra_params: Unknown tag: %s", - child->name); + rrd_set_error("line %d: parse_tag_rra_params: Unknown tag: %s", + xmlTextReaderGetParserLineNumber(reader),element); status = -1; } - + status = expect_element_end(reader,(char *)element); + xmlFree(element); if (status != 0) break; } - return (status); } /* int parse_tag_rra_params */ @@ -622,35 +667,33 @@ static int parse_tag_rra_params( * Parse an RRA definition */ static int parse_tag_rra_cf( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rra_def_t *rra_def) { int status; - status = get_string_from_node(doc, node, + status = get_xml_string(reader, rra_def->cf_nam, sizeof(rra_def->cf_nam)); if (status != 0) - return (-1); + return status; status = cf_conv(rra_def->cf_nam); if (status == -1) { rrd_set_error("parse_tag_rra_cf: Unknown consolidation function: %s", rra_def->cf_nam); - return (-1); + return -1; } - return (0); + return 0; } /* int parse_tag_rra_cf */ static int parse_tag_rra( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd) { - xmlNode *child; int status; - + xmlChar *element; + rra_def_t *cur_rra_def; cdp_prep_t *cur_cdp_prep; rra_ptr_t *cur_rra_ptr; @@ -709,36 +752,61 @@ static int parse_tag_rra( rrd->stat_head->rra_cnt++; status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "cf") == 0) - status = parse_tag_rra_cf(doc, child, cur_rra_def); - else if (xmlStrcmp(child->name, (const xmlChar *) "pdp_per_row") == 0) - status = get_ulong_from_node(doc, child, + while ((element = get_xml_element(reader)) != NULL){ + if (xmlStrcasecmp(element, (const xmlChar *) "cf") == 0) + status = parse_tag_rra_cf(reader, cur_rra_def); + else if (xmlStrcasecmp(element, (const xmlChar *) "pdp_per_row") == 0) + status = get_xml_ulong(reader, &cur_rra_def->pdp_cnt); else if (atoi(rrd->stat_head->version) == 1 - && xmlStrcmp(child->name, (const xmlChar *) "xff") == 0) - status = get_double_from_node(doc, child, + && xmlStrcasecmp(element, (const xmlChar *) "xff") == 0) + status = get_xml_double(reader, (double *) &cur_rra_def-> par[RRA_cdp_xff_val].u_val); else if (atoi(rrd->stat_head->version) >= 2 - && xmlStrcmp(child->name, (const xmlChar *) "params") == 0) - status = parse_tag_rra_params(doc, child, cur_rra_def); - else if (xmlStrcmp(child->name, (const xmlChar *) "cdp_prep") == 0) - status = parse_tag_rra_cdp_prep(doc, child, rrd, cur_cdp_prep); - else if (xmlStrcmp(child->name, (const xmlChar *) "database") == 0) - status = parse_tag_rra_database(doc, child, rrd); - else { - rrd_set_error("parse_tag_rra: Unknown tag: %s", child->name); - status = -1; + && xmlStrcasecmp(element, (const xmlChar *) "params") == 0){ + xmlFree(element); + status = parse_tag_rra_params(reader, cur_rra_def); + if (status == 0) + continue; + else + return status; } - - if (status != 0) - break; - } - + else if (xmlStrcasecmp(element, (const xmlChar *) "cdp_prep") == 0){ + xmlFree(element); + status = parse_tag_rra_cdp_prep(reader, rrd, cur_cdp_prep); + if (status == 0) + continue; + else + return status; + } + else if (xmlStrcasecmp(element, (const xmlChar *) "database") == 0){ + xmlFree(element); + status = parse_tag_rra_database(reader, rrd); + if (status == 0) + continue; + else + return status; + } + else if (xmlStrcasecmp(element,(const xmlChar *) "/rra") == 0){ + xmlFree(element); + return status; + } /* }}} */ + else { + rrd_set_error("line %d: parse_tag_rra: Unknown tag: %s", + xmlTextReaderGetParserLineNumber(reader), element); + status = -1; + } + if (status != 0) { + xmlFree(element); + return status; + } + status = expect_element_end(reader,(char *)element); + xmlFree(element); + if (status != 0) { + return status; + } + } /* Set the RRA pointer to a random location */ cur_rra_ptr->cur_row = rrd_random() % cur_rra_def->row_cnt; @@ -749,54 +817,54 @@ static int parse_tag_rra( * Parse a DS definition */ static int parse_tag_ds_cdef( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd) { - char buffer[1024]; - int status; - - status = get_string_from_node(doc, node, buffer, sizeof(buffer)); - if (status != 0) - return (-1); - - /* We're always working on the last DS that has been added to the structure - * when we get here */ - parseCDEF_DS(buffer, rrd, rrd->stat_head->ds_cnt - 1); - - return (0); + xmlChar *cdef; + + cdef = get_xml_text(reader); + if (cdef != NULL){ + /* We're always working on the last DS that has been added to the structure + * when we get here */ + parseCDEF_DS((char *)cdef, rrd, rrd->stat_head->ds_cnt - 1); + xmlFree(cdef); + if (rrd_test_error()) + return -1; + else + return 0; + } + return -1; } /* int parse_tag_ds_cdef */ static int parse_tag_ds_type( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, ds_def_t *ds_def) { - int status; - - status = get_string_from_node(doc, node, - ds_def->dst, sizeof(ds_def->dst)); - if (status != 0) - return (-1); - - status = dst_conv(ds_def->dst); - if (status == -1) { - rrd_set_error("parse_tag_ds_type: Unknown data source type: %s", - ds_def->dst); - return (-1); + char *dst; + dst = (char *)get_xml_text(reader); + if (dst != NULL){ + int status; + status = dst_conv(dst); + if (status == -1) { + rrd_set_error("parse_tag_ds_type: Unknown data source type: %s", + dst); + return -1; + } + strncpy(ds_def->dst,dst,sizeof(ds_def->dst)-1); + ds_def->dst[sizeof(ds_def->dst)-1] = '\0'; + xmlFree(dst); + return 0; } - - return (0); + return -1; } /* int parse_tag_ds_type */ static int parse_tag_ds( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd) { - xmlNode *child; int status; - + xmlChar *element; + ds_def_t *cur_ds_def; pdp_prep_t *cur_pdp_prep; @@ -847,50 +915,55 @@ static int parse_tag_ds( rrd->stat_head->ds_cnt++; status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "name") == 0) - status = get_string_from_node(doc, child, - cur_ds_def->ds_nam, - sizeof(cur_ds_def->ds_nam)); - else if (xmlStrcmp(child->name, (const xmlChar *) "type") == 0) - status = parse_tag_ds_type(doc, child, cur_ds_def); - else if (xmlStrcmp(child->name, + while ((element = get_xml_element(reader)) != NULL){ + if (xmlStrcasecmp(element, (const xmlChar *) "name") == 0){ + status = get_xml_string(reader,cur_ds_def->ds_nam,sizeof(cur_ds_def->ds_nam)); + } + else if (xmlStrcasecmp(element, (const xmlChar *) "type") == 0) + status = parse_tag_ds_type(reader, cur_ds_def); + else if (xmlStrcasecmp(element, (const xmlChar *) "minimal_heartbeat") == 0) - status = get_ulong_from_node(doc, child, + status = get_xml_ulong(reader, &cur_ds_def->par[DS_mrhb_cnt]. u_cnt); - else if (xmlStrcmp(child->name, (const xmlChar *) "min") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "min") == 0) + status = get_xml_double(reader, &cur_ds_def->par[DS_min_val].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "max") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "max") == 0) + status = get_xml_double(reader, &cur_ds_def->par[DS_max_val].u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "cdef") == 0) - status = parse_tag_ds_cdef(doc, child, rrd); - else if (xmlStrcmp(child->name, (const xmlChar *) "last_ds") == 0) - status = get_string_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "cdef") == 0) + status = parse_tag_ds_cdef(reader, rrd); + else if (xmlStrcasecmp(element, (const xmlChar *) "last_ds") == 0) + status = get_xml_string(reader, cur_pdp_prep->last_ds, sizeof(cur_pdp_prep->last_ds)); - else if (xmlStrcmp(child->name, (const xmlChar *) "value") == 0) - status = get_double_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "value") == 0) + status = get_xml_double(reader, &cur_pdp_prep->scratch[PDP_val]. u_val); - else if (xmlStrcmp(child->name, (const xmlChar *) "unknown_sec") == 0) - status = get_ulong_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "unknown_sec") == 0) + status = get_xml_ulong(reader, &cur_pdp_prep-> scratch[PDP_unkn_sec_cnt].u_cnt); + else if (xmlStrcasecmp(element, (const xmlChar *) "/ds") == 0) { + xmlFree(element); + break; + } else { - rrd_set_error("parse_tag_ds: Unknown tag: %s", child->name); + rrd_set_error("parse_tag_ds: Unknown tag: %s", element); status = -1; + } + if (status != 0) { + xmlFree(element); + break; } - + status = expect_element_end(reader,(char *)element); + xmlFree(element); if (status != 0) - break; + break; } - + return (status); } /* int parse_tag_ds */ @@ -898,77 +971,85 @@ static int parse_tag_ds( * Parse root nodes */ static int parse_tag_rrd( - xmlDoc * doc, - xmlNode * node, + xmlTextReaderPtr reader, rrd_t *rrd) { - xmlNode *child; int status; - + xmlChar *element; + status = 0; - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { - if ((xmlStrcmp(child->name, (const xmlChar *) "comment") == 0) - || (xmlStrcmp(child->name, (const xmlChar *) "text") == 0)) - /* ignore */ ; - else if (xmlStrcmp(child->name, (const xmlChar *) "version") == 0) - status = get_string_from_node(doc, child, + while ((element = get_xml_element(reader)) != NULL ){ + if (xmlStrcasecmp(element, (const xmlChar *) "version") == 0) + status = get_xml_string(reader, rrd->stat_head->version, sizeof(rrd->stat_head->version)); - else if (xmlStrcmp(child->name, (const xmlChar *) "step") == 0) - status = get_ulong_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "step") == 0) + status = get_xml_ulong(reader, &rrd->stat_head->pdp_step); - else if (xmlStrcmp(child->name, (const xmlChar *) "lastupdate") == 0) - status = get_long_from_node(doc, child, + else if (xmlStrcasecmp(element, (const xmlChar *) "lastupdate") == 0) + status = get_xml_long(reader, &rrd->live_head->last_up); - else if (xmlStrcmp(child->name, (const xmlChar *) "ds") == 0) - status = parse_tag_ds(doc, child, rrd); - else if (xmlStrcmp(child->name, (const xmlChar *) "rra") == 0) - status = parse_tag_rra(doc, child, rrd); + else if (xmlStrcasecmp(element, (const xmlChar *) "ds") == 0){ + xmlFree(element); + status = parse_tag_ds(reader, rrd); + /* as we come back the tag is already gone */ + if (status == 0) + continue; + else + return status; + } + else if (xmlStrcasecmp(element, (const xmlChar *) "rra") == 0){ + xmlFree(element); + status = parse_tag_rra(reader, rrd); + if (status == 0) + continue; + else + return status; + } + else if (xmlStrcasecmp(element, (const xmlChar *) "/rrd") == 0) { + xmlFree(element); + return status; + } else { - rrd_set_error("parse_tag_rrd: Unknown tag: %s", child->name); + rrd_set_error("parse_tag_rrd: Unknown tag: %s", element); status = -1; } - if (status != 0) + if (status != 0){ + xmlFree(element); break; + } + status = expect_element_end(reader,(char *)element); + xmlFree(element); + if (status != 0) + break; } - return (status); } /* int parse_tag_rrd */ static rrd_t *parse_file( const char *filename) { - xmlDoc *doc; - xmlNode *cur; + xmlTextReaderPtr reader; int status; rrd_t *rrd; - doc = xmlParseFile(filename); - if (doc == NULL) { - rrd_set_error("Document not parsed successfully."); + reader = xmlNewTextReaderFilename(filename); + if (reader == NULL) { + rrd_set_error("Could not create xml reader for: %s",filename); return (NULL); } - cur = xmlDocGetRootElement(doc); - if (cur == NULL) { - rrd_set_error("Document is empty."); - xmlFreeDoc(doc); - return (NULL); - } - - if (xmlStrcmp(cur->name, (const xmlChar *) "rrd") != 0) { - rrd_set_error - ("Document of the wrong type, root node is not \"rrd\"."); - xmlFreeDoc(doc); + if (expect_element(reader,"rrd") != 0) { + xmlFreeTextReader(reader); return (NULL); } rrd = (rrd_t *) malloc(sizeof(rrd_t)); if (rrd == NULL) { rrd_set_error("parse_file: malloc failed."); - xmlFreeDoc(doc); + xmlFreeTextReader(reader); return (NULL); } memset(rrd, '\0', sizeof(rrd_t)); @@ -976,7 +1057,7 @@ static rrd_t *parse_file( rrd->stat_head = (stat_head_t *) malloc(sizeof(stat_head_t)); if (rrd->stat_head == NULL) { rrd_set_error("parse_tag_rrd: malloc failed."); - xmlFreeDoc(doc); + xmlFreeTextReader(reader); free(rrd); return (NULL); } @@ -988,18 +1069,19 @@ static rrd_t *parse_file( rrd->live_head = (live_head_t *) malloc(sizeof(live_head_t)); if (rrd->live_head == NULL) { rrd_set_error("parse_tag_rrd: malloc failed."); - xmlFreeDoc(doc); + xmlFreeTextReader(reader); free(rrd->stat_head); free(rrd); return (NULL); } memset(rrd->live_head, '\0', sizeof(live_head_t)); - status = parse_tag_rrd(doc, cur, rrd); + status = parse_tag_rrd(reader, rrd); + + xmlFreeTextReader(reader); - xmlFreeDoc(doc); if (status != 0) { - rrd_free(rrd); + local_rrd_free(rrd); rrd = NULL; } @@ -1132,13 +1214,14 @@ int rrd_restore( rrd = parse_file(argv[optind]); if (rrd == NULL) return (-1); - + if (write_file(argv[optind + 1], rrd) != 0) { - rrd_free(rrd); + local_rrd_free(rrd); return (-1); } + local_rrd_free(rrd); + - rrd_free(rrd); return (0); } /* int rrd_restore */