Select Git revision
Background Jobs.ipynb
-
Jens Henrik Goebbert authoredJens Henrik Goebbert authored
attribute_schema.c 7.50 KiB
/* -*- mode:c -*- */
/** @file
** @brief Maestro Attribute Schema ingest and data structures
**/
/*
* Copyright (C) 2020 Cray Computer GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "maestro/status.h"
#include "maestro/logging.h"
#include "maestro/i_uthash.h"
#include "protocols/mstro_pool.pb-c.h"
#include "yaml.h"
#include <errno.h>
#include <stdlib.h>
/* A single attribute definition */
struct mstro_attribute_entry {
UT_hash_handle *hh; /**< hashable, by key, using magic hash function
* below */
char *key; /**< attribute key, also key in hash table */
/** The type permitted for this attribute */
Mstro__Pool__AVal__ValCase val_type;
};
/* Data structure for (a fragment of) a schema */
struct mstro_attribute_schema {
/** The name of this schema */
char *name;
/** Its version number */
size_t version;
/** the set of declarations in this schema */
struct mstro_attribite_entry *declarations;
};
/* The (merge of) all loaded schemata. This is conceptually read-only
* after mstro_init(), and holds the information on all defined
* attribute keys and value types */
static
struct mstro_attribute_schema *g_mstro_attribute_schema = NULL;
/** Initialize schema module */
mstro_status
mstro_schema_init(void)
{
return MSTRO_OK;
}
/** finalize schema module */
mstro_status
mstro_schema_finalize(void)
{
if(g_mstro_attribute_schema!=NULL) {
WARN("Not deallocating schema tree\n");
}
return MSTRO_OK;
}
static inline
mstro_status
mstro_schema__parse(yaml_parser_t parser,
struct mstro_attribute_schema **result)
{
yaml_token_t token;
char *last_key=NULL;
enum {
INVALID,
KEY, VALUE,
BLOCKSEQ, BLOCKENT, BLOCKMAP
} last_kind = INVALID;
ssize_t depth = -1;
*result = malloc(sizeof(struct mstro_attribute_schema));
if(*result == NULL) {
return MSTRO_NOMEM;
}
/* for now, let's see if token-based scanning is sufficient */
do {
yaml_parser_scan(&parser, &token);
switch(token.type) {
/* Stream start/end */
case YAML_STREAM_START_TOKEN:
DEBUG("STREAM START\n");
depth++;
break;
case YAML_STREAM_END_TOKEN:
DEBUG("STREAM END\n");
depth--;
break;
/* Token types (read before actual token) */
case YAML_KEY_TOKEN:
DEBUG("(Key token) \n");
last_kind = KEY;
break;
case YAML_VALUE_TOKEN:
DEBUG("(Value token) \n");
last_kind = VALUE;
break;
/* Block delimeters */
case YAML_BLOCK_SEQUENCE_START_TOKEN:
DEBUG("Start Block (Sequence)\n");
last_kind = BLOCKSEQ;
depth++;
break;
case YAML_BLOCK_ENTRY_TOKEN:
DEBUG("Start Block (Entry)\n");
last_kind = BLOCKENT;
break;
case YAML_BLOCK_END_TOKEN:
DEBUG("End block\n");
depth--;
break;
/* Data */
case YAML_BLOCK_MAPPING_START_TOKEN:
DEBUG("[Block mapping]\n");
last_kind=BLOCKMAP;
depth++;
break;
case YAML_SCALAR_TOKEN:
DEBUG("scalar %s (for kind %d)\n",
token.data.scalar.value, last_kind);
/* yaml_char_t is signed */
const char *val = (const char*)token.data.scalar.value;
switch(last_kind) {
case KEY:
/* store key for value coming up */
if(last_key!=NULL) {
ERR("two keys in succession: stack %s, here %s\n",
last_key, val);
free(last_key);
}
last_key = strdup(val);
if(last_key==NULL) {
ERR("Failed to allocate key\n");
}
break;
case VALUE:
if(last_key==NULL) {
ERR("No key preceeded this value\n");
} else {
/* This is where the built-in meta-schema is hiding */
if(strcmp(last_key, "schema-name")==0) {
(*result)->name = last_key;
last_key=NULL;
} else if(strcmp(last_key, "schema-version")==0) {
(*result)->version = atol(val);
free(last_key);
} else {
DEBUG("Value |%s| for unknown key |%s|\n", val, last_key);
free(last_key);
}
last_key=NULL;
}
break;
default:
WARN("Unexpected last_kind value\n");
}
break;
/* Others */
default:
WARN("Got token of type %d\n", token.type);
}
if(token.type != YAML_STREAM_END_TOKEN)
yaml_token_delete(&token);
} while(token.type != YAML_STREAM_END_TOKEN);
yaml_token_delete(&token);
if(depth!=-1) {
ERR("YAML stream nesting does not balance, depth %u at end (should be -1)\n",
depth);
}
return MSTRO_UNIMPL;
}
/* merge SCHEMA into global schema tree. Consume argument, even on error */
static inline
mstro_status
mstro_schema__merge(struct mstro_attribute_schema *schema)
{
return MSTRO_UNIMPL;
}
/** Add a file's content to schema tree */
mstro_status
mstro_schema_add_from_file(char *path)
{
mstro_status s;
if(path==NULL) {
s=MSTRO_INVARG;
goto BAILOUT;
}
FILE *f = fopen(path, "r");
if(f==NULL) {
ERR("Failed to open schema file %s: %d (%s)\n",
path, errno, strerror(errno));
s=MSTRO_FAIL;
goto BAILOUT;
}
/* Initialize parser */
yaml_parser_t parser;
if(!yaml_parser_initialize(&parser)) {
ERR("Failed to initialize YAML parser\n");
s= MSTRO_FAIL;
goto BAILOUT_CLOSE;
}
/* Set input file */
yaml_parser_set_input_file(&parser, f);
struct mstro_attribute_schema *schema;
s=mstro_schema__parse(parser, &schema);
yaml_parser_delete(&parser);
if(s!=MSTRO_OK) {
ERR("Failed to parse schema %s\n", path);
} else {
INFO("Parsed schema definition %s\n", schema->name);
/* merge it (consumes argument, even on error) */
s=mstro_schema__merge(schema);
if(s!=MSTRO_OK) {
ERR("Failed to merge schema\n");
}
}
BAILOUT_CLOSE:
fclose(f);
BAILOUT:
return s;
}