diff options
| author | Clark Williams <williams@redhat.com> | 2012-01-12 10:09:19 -0600 |
|---|---|---|
| committer | Clark Williams <williams@redhat.com> | 2012-01-12 10:09:19 -0600 |
| commit | fa1758387eff03d47c9049d8efcd5eabef622f55 (patch) | |
| tree | 78cc5743722f50db6b88fc30f1fdb9323a060496 /server/parser | |
| parent | c9c862c407a27946931ca8f60f9a3a733f364d74 (diff) | |
| parent | 53f19edb5795cbb31263f00a01d443f222deb970 (diff) | |
| download | rteval-fa1758387eff03d47c9049d8efcd5eabef622f55.tar.gz rteval-fa1758387eff03d47c9049d8efcd5eabef622f55.tar.xz rteval-fa1758387eff03d47c9049d8efcd5eabef622f55.zip | |
Merge remote-tracking branch 'davids/master' into work
Conflicts:
rteval/hackbench.py
rteval/rteval.py
Signed-off-by: Clark Williams <williams@redhat.com>
Diffstat (limited to 'server/parser')
| -rw-r--r-- | server/parser/pgsql.c | 65 | ||||
| -rw-r--r-- | server/parser/xmlparser.c | 91 | ||||
| -rw-r--r-- | server/parser/xmlparser.h | 11 | ||||
| -rw-r--r-- | server/parser/xmlparser.xsl | 25 |
4 files changed, 185 insertions, 7 deletions
diff --git a/server/parser/pgsql.c b/server/parser/pgsql.c index 44032e5..8ea5d08 100644 --- a/server/parser/pgsql.c +++ b/server/parser/pgsql.c @@ -44,6 +44,14 @@ #include <log.h> #include <statuses.h> +/** forward declaration, to be able to setup dbhelper_func pointers */ +static char * pgsql_BuildArray(LogContext *log, xmlNode *sql_n); + +/** Helper functions the xmlparser might beed */ +static dbhelper_func pgsql_helpers = { + .dbh_FormatArray = &(pgsql_BuildArray) +}; + /** * Connect to a database, based on the given configuration * @@ -106,7 +114,7 @@ dbconn *db_connect(eurephiaVALUES *cfg, unsigned int id, LogContext *log) { if( dbr ) { PQclear(dbr); } - + init_xmlparser(&pgsql_helpers); return ret; } @@ -414,6 +422,61 @@ eurephiaVALUES *pgsql_INSERT(dbconn *dbc, xmlDoc *sqldoc) { return res; } +/** + * @copydoc sqldataValueArray() + */ +static char * pgsql_BuildArray(LogContext *log, xmlNode *sql_n) { + char *ret = NULL, *ptr = NULL; + xmlNode *node = NULL; + size_t retlen = 0; + + ret = malloc_nullsafe(log, 2); + if( ret == NULL ) { + writelog(log, LOG_ERR, + "Failed to allocate memory for a new PostgreSQL array"); + return NULL; + } + strncat(ret, "{", 1); + + /* Iterate all ./value/value elements and build up a PostgreSQL specific array */ + foreach_xmlnode(sql_n->children, node) { + if( (node->type != XML_ELEMENT_NODE) + || xmlStrcmp(node->name, (xmlChar *) "value") != 0 ) { + // Skip uninteresting nodes + continue; + } + ptr = sqldataValueHash(log, node); + if( ptr ) { + retlen += strlen(ptr) + 4; + ret = realloc(ret, retlen); + if( ret == NULL ) { + writelog(log, LOG_ERR, + "Failed to allocate memory to expand " + "array to include '%s'", ptr); + free_nullsafe(ret); + free_nullsafe(ptr); + return NULL; + } + /* Newer PostgreSQL servers expects numbers to be without quotes */ + if( isNumber(ptr) == 0 ) { + /* Data is a string */ + strncat(ret, "'", 1); + strncat(ret, ptr, strlen(ptr)); + strncat(ret, "',", 2); + } else { + /* Data is a number */ + strncat(ret, ptr, strlen(ptr)); + strncat(ret, ",", 1); + } + free_nullsafe(ptr); + } + } + /* Replace the last comma with a close-array marker */ + ret[strlen(ret)-1] = '}'; + ret[strlen(ret)] = 0; + return ret; +} + /** * Start an SQL transaction (SQL BEGIN) diff --git a/server/parser/xmlparser.c b/server/parser/xmlparser.c index fb1330a..0ff6e72 100644 --- a/server/parser/xmlparser.c +++ b/server/parser/xmlparser.c @@ -42,6 +42,8 @@ #include <sha1.h> #include <log.h> +static dbhelper_func const * xmlparser_dbhelpers = NULL; + /** * Simple strdup() function which encapsulates the string in single quotes, * which is needed for XSLT parameter values @@ -84,6 +86,33 @@ static char *encapsInt(const unsigned int val) { /** + * Simple function to determine if the given string is a number or not + * + * @param str Pointer to the tring to be checked + * + * @returns Returns 0 if not a number and a non-null value if it is a number + */ +int isNumber(const char * str) +{ + char *ptr = NULL; + + if (str == NULL || *str == '\0' || isspace(*str)) + return 0; + + strtod (str, &ptr); + return *ptr == '\0'; +} + +/** + * Initialise the XML parser, setting some global variables + */ +void init_xmlparser(dbhelper_func const * dbhelpers) +{ + xmlparser_dbhelpers = dbhelpers; +} + + +/** * Parses any XML input document into a sqldata XML format which can be used by pgsql_INSERT(). * The transformation must be defined in the input XSLT template. * @@ -100,6 +129,11 @@ xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d, unsigned int idx = 0, idx_table = 0, idx_submid = 0, idx_syskey = 0, idx_rterid = 0, idx_repfname = 0; + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return NULL; + } + if( params->table == NULL ) { writelog(log, LOG_ERR, "Table is not defined"); return NULL; @@ -170,16 +204,17 @@ xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d, * @return Returns a pointer to a new buffer containing the value on success, otherwise NULL. * This memory buffer must be free'd after usage. */ -static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) { +char * sqldataValueHash(LogContext *log, xmlNode *sql_n) { const char *hash = NULL, *isnull = NULL; SHA1Context shactx; uint8_t shahash[SHA1_HASH_SIZE]; char *ret = NULL, *ptr = NULL; int i; - if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "value") != 0) - || (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") != 0) ) { - return NULL; + if( !(sql_n && (xmlStrcmp(sql_n->name, (xmlChar *) "value") == 0) + && (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") == 0) + || (xmlStrcmp(sql_n->parent->name, (xmlChar *) "value") == 0)) ) { + return NULL; } isnull = xmlGetAttrValue(sql_n->properties, "isnull"); @@ -214,6 +249,27 @@ static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) { /** + * Extract the content of a //sqldata/records/record/value[@type='array']/value node set + * and format it in suitable array format for the database backend. + * + * @param log Log context + * @param sql_n sqldata values node containing the value to extract and format as an array. + * + * @return Returns a pointer to a new memory buffer containing the value as a string. + * On errors, NULL is returned. This memory buffer must be free'd after usage. + */ +static char * sqldataValueArray(LogContext *log, xmlNode *sql_n) +{ + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return NULL; + } + + return xmlparser_dbhelpers->dbh_FormatArray(log, sql_n); +} + + +/** * Extract the content of a '//sqldata/records/record/value' node. It will consider * both the 'hash' and 'type' attributes of the 'value' tag. * @@ -226,6 +282,11 @@ static inline char *sqldataValueHash(LogContext *log, xmlNode *sql_n) { char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) { const char *valtype = xmlGetAttrValue(sql_n->properties, "type"); + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return NULL; + } + if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "value") != 0) || (xmlStrcmp(sql_n->parent->name, (xmlChar *) "record") != 0) ) { return NULL; @@ -239,6 +300,8 @@ char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) { chld_n = chld_n->next; } return xmlNodeToString(log, chld_n); + } else if( valtype && (strcmp(valtype, "array") == 0) ) { + return sqldataValueArray(log, sql_n); } else { return sqldataValueHash(log, sql_n); } @@ -259,6 +322,11 @@ char *sqldataExtractContent(LogContext *log, xmlNode *sql_n) { int sqldataGetFid(LogContext *log, xmlNode *sql_n, const char *fname) { xmlNode *f_n = NULL; + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return -2; + } + if( !sql_n || (xmlStrcmp(sql_n->name, (xmlChar *) "sqldata") != 0) ) { writelog(log, LOG_ERR, "sqldataGetFid: Input XML document is not a valid sqldata document"); @@ -310,6 +378,11 @@ char *sqldataGetValue(LogContext *log, xmlDoc *sqld, const char *fname, int reci xmlNode *r_n = NULL; int fid = -3, rc = 0; + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return NULL; + } + if( recid < 0 ) { writelog(log, LOG_ERR, "sqldataGetValue: Invalid recid"); return NULL; @@ -384,6 +457,11 @@ xmlDoc *sqldataGetHostInfo(LogContext *log, xsltStylesheet *xslt, xmlDoc *summar xmlDoc *hostinfo_d = NULL; parseParams prms; + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return NULL; + } + memset(&prms, 0, sizeof(parseParams)); prms.table = "systems_hostname"; prms.syskey = syskey; @@ -423,6 +501,11 @@ int sqldataGetRequiredSchemaVer(LogContext *log, xmlNode *sqldata_root) char *schver = NULL, *cp = NULL, *ptr = NULL; int majv = 0, minv = 0; + if( xmlparser_dbhelpers == NULL ) { + writelog(log, LOG_ERR, "Programming error: xmlparser is not initialised"); + return -1; + } + if( !sqldata_root || (xmlStrcmp(sqldata_root->name, (xmlChar *) "sqldata") != 0) ) { writelog(log, LOG_ERR, "sqldataGetRequiredSchemaVer: Invalid document node"); return -1; diff --git a/server/parser/xmlparser.h b/server/parser/xmlparser.h index f903037..79c79a1 100644 --- a/server/parser/xmlparser.h +++ b/server/parser/xmlparser.h @@ -39,6 +39,16 @@ typedef struct { unsigned int rterid; /**< References rtevalruns.rterid */ } parseParams; + +/** + * Database specific helper functions + */ +typedef struct { + char *(*dbh_FormatArray)(LogContext *log, xmlNode *sql_n); /** Formats data as arrays */ +} dbhelper_func; + +void init_xmlparser(dbhelper_func const * dbhelpers); +char * sqldataValueHash(LogContext *log, xmlNode *sql_n); xmlDoc *parseToSQLdata(LogContext *log, xsltStylesheet *xslt, xmlDoc *indata_d, parseParams *params); char *sqldataExtractContent(LogContext *log, xmlNode *sql_n); int sqldataGetFid(LogContext *log, xmlNode *sqld, const char *fname); @@ -46,4 +56,5 @@ char *sqldataGetValue(LogContext *log, xmlDoc *sqld, const char *fname, int reci xmlDoc *sqldataGetHostInfo(LogContext *log, xsltStylesheet *xslt, xmlDoc *summaryxml, int syskey, char **hostname, char **ipaddr); int sqldataGetRequiredSchemaVer(LogContext *log, xmlNode *sqldata_root); + #endif diff --git a/server/parser/xmlparser.xsl b/server/parser/xmlparser.xsl index 4330fec..2ee9370 100644 --- a/server/parser/xmlparser.xsl +++ b/server/parser/xmlparser.xsl @@ -23,6 +23,9 @@ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> + <!-- Used for iterating CPU topology information --> + <xsl:key name="pkgkey" match="cpu" use="@physical_package_id"/> + <xsl:template match="/rteval"> <xsl:choose> <!-- TABLE: systems --> @@ -132,13 +135,15 @@ <xsl:text>Invalid 'rterid' parameter value: </xsl:text><xsl:value-of select="$rterid"/> </xsl:message> </xsl:if> - <sqldata schemaver="1.2" table="rtevalruns_details"> + <sqldata schemaver="1.4" table="rtevalruns_details"> <fields> <field fid="0">rterid</field> <field fid="1">numa_nodes</field> <field fid="2">num_cpu_cores</field> <field fid="3">num_cpu_sockets</field> <field fid="4">xmldata</field> + <field fid="5">annotation</field> + <field fid="6">cpu_core_spread</field> </fields> <records> <record> @@ -159,12 +164,20 @@ </value> <value fid="4" type="xmlblob"> <rteval_details> - <xsl:copy-of select="clocksource|services|kthreads|network_config|loads|cyclictest/command_line|run_info/annotate"/> + <xsl:copy-of select="clocksource|services|kthreads|network_config|loads|cyclictest/command_line"/> <hardware> <xsl:copy-of select="hardware/memory_size|hardware/cpu_topology"/> </hardware> </rteval_details> </value> + <value fid="5"><xsl:value-of select="run_info/annotate"/></value> + <value fid="6" type="array"> + <xsl:for-each select="hardware/cpu_topology/cpu[generate-id() = generate-id(key('pkgkey', @physical_package_id)[1])]"> + <xsl:call-template name="count_core_spread"> + <xsl:with-param name="pkgid" select="@physical_package_id"/> + </xsl:call-template> + </xsl:for-each> + </value> </record> </records> </sqldata> @@ -288,4 +301,12 @@ <value fid="3"><xsl:value-of select="@value"/></value> </record> </xsl:template> + + <!-- Helper "function" for generating a core per physical socket spread overview --> + <xsl:template name="count_core_spread"> + <xsl:param name="pkgid"/> + <value> + <xsl:value-of select="count(/rteval/hardware/cpu_topology/cpu[@physical_package_id = $pkgid])"/> + </value> + </xsl:template> </xsl:stylesheet> |
