Skip to content
Snippets Groups Projects
Select Git revision
  • 57-sphinx-documentation
  • devel default
  • 107-compilation-error-when-building-maestro-core-on-m1-apple-processors
  • 108-implement-cpu-id-query-for-apple-m1-hardware
  • 58-scripting-interface-to-maestro-core
  • 101-need-ci-test-using-installed-maestro
  • 105-memory-leak-in-pm-message-envelope-handling
  • 104-permit-disabling-memory-pool
  • 103-liberl-installation-issue-on-devel
  • 94-maestro-rdma-transport-ignores-max_msg_size-2
  • main protected
  • 102-possible-race-in-check_pm_redundant_interlock-test
  • 97-check-if-shm-provider-can-be-enabled-after-libfabric-1-14-is-in-our-tree-2
  • 100-include-maestro-attributes-h-cannot-include-mamba-header-from-deps-path
  • 97-check-if-shm-provider-can-be-enabled-after-libfabric-1-14-is-in-our-tree
  • 17-job-failed-282354-needs-update-of-mio-interface-and-build-rules
  • 96-test-libfabric-update-to-1-13-or-1-14
  • feature/stop-telemetry-after-all-left
  • 94-maestro-rdma-transport-ignores-max_msg_size
  • 93-improve-performance-of-mstro_attribute_val_cmp_str
  • v0.3_rc1
  • maestro_d65
  • d65_experiments_20211113
  • v0.2
  • v0.2_rc1
  • d3.3
  • d3.3-review
  • d5.5
  • d5.5-review
  • v0.1
  • d3.2
  • d3.2-draft
  • v0.0
33 results

attribute_schema.c

Blame
  • 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;
    }