summaryrefslogtreecommitdiffstats
path: root/server/parser
diff options
context:
space:
mode:
authorClark Williams <williams@redhat.com>2012-01-12 10:09:19 -0600
committerClark Williams <williams@redhat.com>2012-01-12 10:09:19 -0600
commitfa1758387eff03d47c9049d8efcd5eabef622f55 (patch)
tree78cc5743722f50db6b88fc30f1fdb9323a060496 /server/parser
parentc9c862c407a27946931ca8f60f9a3a733f364d74 (diff)
parent53f19edb5795cbb31263f00a01d443f222deb970 (diff)
downloadrteval-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.c65
-rw-r--r--server/parser/xmlparser.c91
-rw-r--r--server/parser/xmlparser.h11
-rw-r--r--server/parser/xmlparser.xsl25
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>