diff --git a/attributes/maestro-schema.c b/attributes/maestro-schema.c index c03d39143b9aad55bf85339cf91dac1287caaf29..5232a0b3a588224ff777640425a6efa9b684b9c2 100644 --- a/attributes/maestro-schema.c +++ b/attributes/maestro-schema.c @@ -996,12 +996,14 @@ mstro_schema_lookup_attribute(mstro_schema schema, /** attribute entry in dictionary (hashable by key) */ struct mstro_attribute_entry_ { - UT_hash_handle hh; /** hashable by key */ - mstro_symbol key; /** the key (interned attribute name) */ - void *val; /** a value, to be interpreted by looking up the - * expected type of the attribute in the - * appropriate schema */ - size_t valsize; /** allocated space for val */ + UT_hash_handle hh; /**< hashable by key */ + mstro_symbol key; /**< the key (interned attribute name) */ + void *val; /**< a value, to be interpreted by looking up the + * expected type of the attribute in the + * appropriate schema */ + size_t valsize; /**< allocated space for val */ + bool user_owned_val; /**< whether the val allocation is owned by the + * user (if not we must free it eventually) */ /* FIXME: this is the place where serialized versions of the entry * should be cached if needed */ /* these may be unset -- this can be checked by comparing the string @@ -1247,7 +1249,76 @@ BAILOUT: return s; } + +static inline +mstro_status +mstro_attribute_entry_create(mstro_symbol sym, struct mstro_attribute_entry_ **result) +{ + if(sym==NULL) + return MSTRO_INVARG; + if(result==NULL) + return MSTRO_INVOUT; + *result = malloc(sizeof(struct mstro_attribute_entry_)); + if(*result==NULL) { + ERR("Failed to allocate attribute entry\n"); + return MSTRO_NOMEM; + } + (*result)->key = sym; + (*result)->val = NULL; + (*result)->valsize = 0; + (*result)->user_owned_val = false; + (*result)->serialized_yaml = NULL; + mstro__pool__aval__init(& ((*result)->serialized_pb)); + return MSTRO_OK; +} + +static inline +mstro_status +mstro_attribute_entry_dispose(struct mstro_attribute_entry_ *entry) +{ + if(entry==NULL) + return MSTRO_INVARG; + mstro_status status=MSTRO_OK; + if(! entry->user_owned_val) { + free(entry->val); + } + if(entry->serialized_yaml) + free(entry->serialized_yaml); + + switch(entry->serialized_pb.val_case) { + case MSTRO__POOL__AVAL__VAL_STRING: + free(entry->serialized_pb.string); + break; + case MSTRO__POOL__AVAL__VAL_BYTES: + if(entry->serialized_pb.bytes.len) + free(entry->serialized_pb.bytes.data); + break; + case MSTRO__POOL__AVAL__VAL_TIMESTAMP: + mstro__pool__timestamp__free_unpacked( + entry->serialized_pb.timestamp, NULL); + break; + case MSTRO__POOL__AVAL__VAL__NOT_SET: + case MSTRO__POOL__AVAL__VAL_BOOL: + case MSTRO__POOL__AVAL__VAL_INT32: + case MSTRO__POOL__AVAL__VAL_INT64: + case MSTRO__POOL__AVAL__VAL_UINT32: + case MSTRO__POOL__AVAL__VAL_UINT64: + case MSTRO__POOL__AVAL__VAL_FLOAT: + case MSTRO__POOL__AVAL__VAL_DOUBLE: + /* These are inlined, no need to free them */ + break; + default: + ERR("Unhandled protobuf AVAL type: %d\n", + entry->serialized_pb.val_case); + status=MSTRO_FAIL; + } + free(entry); + + return status; +} + + static inline mstro_status mstro_attributes__parse_helper(yaml_parser_t parser, @@ -1255,6 +1326,7 @@ mstro_attributes__parse_helper(yaml_parser_t parser, mstro_attribute_dict *result) { mstro_status status = MSTRO_UNIMPL; + bool result_allocated_here=false; struct partial_key *keystack =NULL; if(schema==NULL) { ERR("Can't parse without schema\n"); @@ -1264,13 +1336,16 @@ mstro_attributes__parse_helper(yaml_parser_t parser, ERR("NULL attribute dict\n"); return MSTRO_INVOUT; } - *result = malloc(sizeof(struct mstro_attribute_dict_)); if(*result==NULL) { - ERR("Failed to allocate attribute dict\n"); - return MSTRO_NOMEM; + *result = malloc(sizeof(struct mstro_attribute_dict_)); + if(*result==NULL) { + ERR("Failed to allocate attribute dict\n"); + return MSTRO_NOMEM; + } + (*result)->dict=NULL; + (*result)->schema=schema; /* for now, will be added when successful */ + result_allocated_here = true; } - (*result)->dict=NULL; - (*result)->schema=NULL; /* for now, will be added when successful */ yaml_event_t event; @@ -1396,28 +1471,38 @@ mstro_attributes__parse_helper(yaml_parser_t parser, } } /* it's a valid attribute */ - struct mstro_attribute_entry_ *entry = malloc(sizeof(struct mstro_attribute_entry_)); - if(entry==NULL) { - ERR("Failed to allocate attribute entry\n"); - status=MSTRO_NOMEM; - goto BAILOUT; + mstro_attribute_entry entry=NULL; + bool new_entry=false; + + DEBUG("looking up sym %p in dict\n", decl->key_symbol); + HASH_FIND(hh, (*result)->dict, &(decl->key_symbol), sizeof(mstro_symbol), entry); + if(entry) { + DEBUG("Replacing value of previously set attribute |%s|\n", keystack->fqkey); + if(! entry->user_owned_val) { + free(entry->val); + entry->val=NULL; + } + } else { + new_entry=true; + status = mstro_attribute_entry_create(decl->key_symbol, &entry); + if(status!=MSTRO_OK) + goto BAILOUT; } - entry->key = decl->key_symbol; - entry->serialized_yaml = NULL; - entry->serialized_pb.val_case = MSTRO__POOL__AVAL__VAL__NOT_SET; status = mstro_attributes_parse_val(schema, decl, val, val_len, entry); if(status!=MSTRO_OK) { ERR("Failed to parse |%s| as value for attribute |%s|\n", val, mstro_symbol_name(decl->key_symbol)); + if(new_entry) + mstro_attribute_entry_dispose(entry); goto BAILOUT; } else { DEBUG("Parsed |%s| as valid value for attribute |%s|\n", val, mstro_symbol_name(decl->key_symbol)); /* FIXME: describe_entry function call here */ } - - HASH_ADD(hh, (*result)->dict, key, sizeof(mstro_symbol), entry); + if(new_entry) + HASH_ADD(hh, (*result)->dict, key, sizeof(mstro_symbol), entry); DEBUG("Handled entry for %s, cleaning keystack\n", keystack->fqkey); free(keystack->fqkey); @@ -1550,7 +1635,11 @@ mstro_attributes__parse_helper(yaml_parser_t parser, /* depth); */ /* } */ -BAILOUT: +BAILOUT: + if(status!=MSTRO_OK && result_allocated_here) { + free(*result); + } + return status; } @@ -1570,8 +1659,7 @@ mstro_attributes_parse(mstro_schema schema, goto BAILOUT; } if(yaml_fragment==NULL) { - *result=NULL; - s=MSTRO_OK; + s=MSTRO_INVARG; goto BAILOUT; } @@ -1592,7 +1680,7 @@ mstro_attributes_parse(mstro_schema schema, if(s!=MSTRO_OK) { ERR("Failed to parse attribute yaml string |%s|\n", yaml_fragment); } else { - INFO("Parsed yaml attribute string, %zu entries\n", HASH_COUNT((*result)->dict)); + INFO("Parsed yaml attribute string, now %zu entries in dictionary\n", HASH_COUNT((*result)->dict)); (*result)->schema = schema; } @@ -1600,13 +1688,58 @@ BAILOUT: return s; } +mstro_status +mstro_attribute_dict_get_schema(mstro_attribute_dict dict, mstro_schema *schema_p) +{ + if(dict==NULL) + return MSTRO_INVARG; + if(schema_p==NULL) + return MSTRO_INVOUT; + *schema_p=dict->schema; + return MSTRO_OK; +} + +mstro_status +mstro_attribute_dict_set_defaults(mstro_schema schema, + bool override, + mstro_attribute_dict *result) +{ + if(schema==NULL) + return MSTRO_INVARG; + if(result==NULL) + return MSTRO_INVOUT; + if(*result==NULL) { + *result = malloc(sizeof(struct mstro_attribute_dict_)); + if(*result==NULL) + return MSTRO_NOMEM; + (*result)->schema = schema; + (*result)->dict = NULL; + } + + WARN("Not filling in default values in dictionary\n"); + return MSTRO_OK; +} + + mstro_status -mstro_attributes_default(mstro_schema schema, - bool override, - mstro_attribute_dict *result) +mstro_attribute_dict_dispose(mstro_attribute_dict dict) { - return MSTRO_UNIMPL; + if(dict==NULL) + return MSTRO_INVARG; + /* schema will be refcounted one day ...*/ + mstro_status status = MSTRO_OK; + + struct mstro_attribute_entry_ *el,*tmp; + HASH_ITER(hh,dict->dict,el,tmp) { + DEBUG("Deleting attribute %s from dict %p\n", + mstro_symbol_name(el->key), dict->dict); + HASH_DELETE(hh,dict->dict,el); + status = status | mstro_attribute_entry_dispose(el); + } + + free(dict); + return status; } mstro_status @@ -1820,15 +1953,9 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, } /* create fresh entry */ - entry = malloc(sizeof(struct mstro_attribute_entry_)); - if(entry==NULL) { - ERR("Failed to allocate attribute entry\n"); - status=MSTRO_NOMEM; + status = mstro_attribute_entry_create(decl->key_symbol, &entry); + if(status!=MSTRO_OK) goto BAILOUT; - } - entry->key = decl->key_symbol; - entry->serialized_yaml = NULL; - entry->serialized_pb.val_case = MSTRO__POOL__AVAL__VAL__NOT_SET; /* FIXME: setting the val size should be part of the default init for entry */ /* FIXME: entry should have the tdecl->parsed_type-> kind as a slot in it. */ @@ -1946,6 +2073,7 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key, } WARN("Not checking type restrictions\n"); entry->val = val; + entry->user_owned_val = true; status=MSTRO_OK; diff --git a/attributes/maestro-schema.h b/attributes/maestro-schema.h index 94044c27eb503660865e8e4890f3870ab0a29b42..fc74f5dad86bf39489e5dd24433c75b238c0274e 100644 --- a/attributes/maestro-schema.h +++ b/attributes/maestro-schema.h @@ -123,9 +123,11 @@ typedef struct mstro_attribute_dict_ * mstro_attribute_dict; ** specified for a CDO. The input will be parsed as though it were ** normalized to a depth-1 sequence of 'key: value' entries. Keys ** will be looked up as attribute keys in the @arg schema, and values - ** will be parsed accordingly. The result is a sequence of entries - ** suitable for merging into the attribute dictionary of a CDO, or - ** serializing for pool messages. + ** will be parsed accordingly. + ** + ** If *result == NULL a fresh dictionay will be allocated. + ** If *result != NULL the parsed values will be stored in the dictionary, replacing + ** any previously set values for the same keys. ** ** Example: ** maestro.core.cdo: @@ -137,6 +139,7 @@ typedef struct mstro_attribute_dict_ * mstro_attribute_dict; ** maestro.core.cdo.persist.cdo.persist: "on" ** maestro.core.cdo.scope.size: 1024 ** + ** @arg yaml_fragment may not be NULL. **/ mstro_status @@ -146,13 +149,26 @@ mstro_attributes_parse(mstro_schema schema, /** Inject default values from schema into attribute dictionary. + ** + ** If *result==NULL, allocate a fresh, default-filled, attribute + ** dictionary. Otherwise just (re-)set the default values from the + ** schema. ** ** When @arg override is true, overrides existing entries, otherwise only fills in missing ones. **/ mstro_status -mstro_attributes_default(mstro_schema schema, - bool override, - mstro_attribute_dict *result); +mstro_attribute_dict_set_defaults(mstro_schema schema, + bool override, + mstro_attribute_dict *result); + +/** Deallocate a dictionary. + * + */ +mstro_status +mstro_attribute_dict_dispose(mstro_attribute_dict dict); + +mstro_status +mstro_attribute_dict_get_schema(mstro_attribute_dict dict, mstro_schema *schema_p); /** Look up maestro attribute in dictionary. diff --git a/include/maestro/attributes.h b/include/maestro/attributes.h index ba282d8f33398c15747b851fcdb7a2a34f0df05a..ed2d3e64c904ac45579b6dfdf5c19d660d8c937f 100644 --- a/include/maestro/attributes.h +++ b/include/maestro/attributes.h @@ -56,11 +56,11 @@ extern "C" { ** This is the Attribute API, as developed for D3.2 **/ -/** Default attribute value specifier for a CDO */ -#define MSTRO_ATTR_DEFAULT NULL +/* /\** a structure holding a set of attributes *\/ */ +typedef struct mstro_attribute_dict_* mstro_cdo_attributes; -/** a structure holding a set of attributes */ -typedef struct mstro_cdo_decl_attr_ *mstro_cdo_decl_attr; +/** Default attribute value specifier for a CDO */ +#define MSTRO_ATTR_DEFAULT ((mstro_cdo_attributes)NULL) /**@defgroup MSTRO_Attr_builtin Maestro Core Predefined Attributes @@ -242,6 +242,31 @@ enum mstro_cdo_attr_value_type { MSTRO_CDO_ATTR_VALUE__MAX }; + + // All data types have an implicit length, so we need a wrapper +/** A data type to hold blobs. + ** + ** This provides a wrapper around the user memory region so that we can know the size of it. + **/ +typedef struct { + size_t len; /**< the length of the data at @ref mstro_blob.data */ + void *data; /**< an opaque memory region of size @ref mstro_blob.len */ +} mstro_blob; + +/** convenience function to wrap a blob and its size into a mstro_blob object. + * + * (You can also use stack-allocated mstro_blob structures, or allocate them yourself.) + * + * If you create a blob with this function you need to free it using mstro_blob_dispose() + */ +mstro_status +mstro_blob_create(size_t len, void *data, mstro_blob **result_p); + +/** convenience function to dispose a blob allocated with mstro_blob_create() + */ +mstro_status +mstro_blob_dispose(mstro_blob *b); + /** Opaque CDO handle. */ typedef struct mstro_cdo_ *mstro_cdo; diff --git a/include/maestro/cdo.h b/include/maestro/cdo.h index 82eb3cde416c9fe1862673d88ca9914b24495f28..5ae0f24e90aca2f05c24009b82394a4ce82eeacb 100644 --- a/include/maestro/cdo.h +++ b/include/maestro/cdo.h @@ -90,7 +90,7 @@ mstro_cdo_name(mstro_cdo cdo); **/ mstro_status mstro_cdo_declare(const char *name, - mstro_cdo_decl_attr attributes, + mstro_cdo_attributes attributes, mstro_cdo *result); diff --git a/include/maestro/i_cdo.h b/include/maestro/i_cdo.h index 9977f0b0274d807217fba6ccdc2c498ee149ee4e..b125087c5aeb0afe8aa953dffbf9d9f7b9ea5450 100644 --- a/include/maestro/i_cdo.h +++ b/include/maestro/i_cdo.h @@ -287,9 +287,8 @@ struct mstro_cdo_ { struct mstro_cdo_id gid; /**< the globally unique ID */ /* all other attributes and name and id are stored in the following table */ - struct mstro_cdo_attr_table_* attributes; - char* attributes_yaml; /**< attributes in yaml to be parsed once at seal time (cyaml limitations) */ - char* attributes_namespace; /**< namespace string; default: ".maestro.core.cdo" */ + mstro_cdo_attributes attributes; /**< attribute and schema information */ + char* current_namespace; /**< namespace string; default: ".maestro.core.cdo" */ }; /* cdo.h has typedef struct mstro_cdo_ * mstro_cdo; */ diff --git a/include/maestro/i_globals.h b/include/maestro/i_globals.h index 9455fa962c80aef74fd84093c7d1148b08dcbc26..c475db59b07782dec8e00de14ae3fc75e8353551 100644 --- a/include/maestro/i_globals.h +++ b/include/maestro/i_globals.h @@ -39,6 +39,7 @@ #include "maestro.h" #include "maestro/i_state.h" #include "protocols/mstro_pool.pb-c.h" +#include "attributes/maestro-schema.h" #include <stdbool.h> #include <stdatomic.h> #include <pthread.h> @@ -103,4 +104,7 @@ extern Mstro__Pool__Apptoken g_pool_apptoken; /** the app ID (packed version of @ref g_pool_app_id) used in communicating with the pool manager. */ extern Mstro__Pool__Appid g_pool_appid; +/** the fundamental built-in attribute schema. Filled early in mstro_core_init(), then constant */ +extern mstro_schema g_mstro_core_schema_instance; + #endif /* MAESTRO_I_GLOBALS_H_ */ diff --git a/maestro/attributes.c b/maestro/attributes.c index caf509ea379a75f677dd60785e302aea17cf21e3..575062d0c9f55c6790593f08fc32aef5ea34ed43 100644 --- a/maestro/attributes.c +++ b/maestro/attributes.c @@ -29,6 +29,7 @@ #include "maestro/attributes.h" #include "maestro/i_attributes.h" #include "maestro/logging.h" +#include "attributes/maestro-schema.h" #include "c-timestamp/timestamp.h" @@ -98,75 +99,33 @@ mstro_cdo_attribute_set(mstro_cdo cdo, const char* key, void* val) ERR("Invalid key: not a cstring\n"); return MSTRO_INVARG; } - /* FIXME Absolute path supported only for default namespace yet */ - if ( strncmp (key,MSTRO_CDO_ATTR_NAMESPACE_DEFAULT, strlen(MSTRO_CDO_ATTR_NAMESPACE_DEFAULT)) - && !strncmp (key,MSTRO_CDO_ATTR_NAMESPACE_DEFAULT, 1)) { - ERR("set attribute on CDO \"%s\" failed because absolute path supported only for default namespace yet\n", cdo->name); - return MSTRO_INVARG; - } + if(mstro_cdo_state_check(cdo, MSTRO_CDO_STATE_SEALED)) { ERR("cannot set attributes on sealed CDO\n"); return MSTRO_FAIL; } - /* Search key by pointer FIXME: do for all other attributes*/ - if (key == MSTRO_ATTR_CORE_CDO_RAW_PTR) { - cdo->raw_ptr = val; - goto SUCCESS; - } - if (key == MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY) { - cdo->mamba_array = val; - goto SUCCESS; - } - - if (key == MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE) { - cdo->attributes->scope.local_size = *(uint64_t*)val; - - /* we rely on being able to overwrite all data at SEAL time with the YAML-parse result, so need to store this setting */ - char scope_string[128]; - snprintf(scope_string, 128, - "scope:\n" - " local_size: %" PRIu64 , *(uint64_t*)val); - if (! (MSTRO_OK == mstro_cdo_attribute_set_yaml(cdo, scope_string))) { - ERR("Couldn't set attribute yaml for CDO %s\n", cdo->name); - return MSTRO_FAIL; - } - - DEBUG("Set local-size (interned key) to %"PRIu64"\n", cdo->attributes->scope.local_size); - goto SUCCESS; - } - - /* If not found, search by string FIXME: do for all other attributes*/ - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_RAW_PTR)) { - cdo->raw_ptr = val; - goto SUCCESS; - } - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_RAW_PTR)) { - cdo->mamba_array = val; - goto SUCCESS; - } - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE)) { - cdo->attributes->scope.local_size = *(uint64_t*)val; - char scope_string[128]; - snprintf(scope_string, 128, - "scope:\n" - " local_size: %" PRIu64, *(uint64_t*)val); - if (! (MSTRO_OK == mstro_cdo_attribute_set_yaml(cdo, scope_string))) { - ERR("Couldn't set attribute yaml for CDO %s\n", cdo->name); - return MSTRO_FAIL; - } - cdo->attributes->scope.local_size = *(uint64_t*)val; - DEBUG("Set local-size (string key) to %"PRIu64"\n", - cdo->attributes->scope.local_size); - goto SUCCESS; + char *tmpfqkey=NULL; + const char *fqkey=NULL; + if(key[0]!='.') { + /* qualify it */ + tmpfqkey = malloc(strlen(key)+strlen(cdo->current_namespace)); + if(tmpfqkey==NULL) { + ERR("Cannot allocate for fully-qualified key\n"); + return MSTRO_NOMEM; + } + fqkey = tmpfqkey; + } else { + fqkey=key; } - /* No match */ - WARN("No match for attribute \"%s\"\n", key); - return MSTRO_INVARG; - -SUCCESS: - return MSTRO_OK; + mstro_status status + = mstro_attribute_dict_set(cdo->attributes, fqkey, + MSTRO_CDO_ATTR_VALUE_INVALID, /* we dont help in checking */ + val); + if(tmpfqkey) + free(tmpfqkey); + return status; } mstro_status @@ -202,18 +161,16 @@ mstro_cdo_attribute_set_default(mstro_cdo cdo) { if (cdo == NULL) return MSTRO_INVARG; - if (cdo->attributes == NULL) - return MSTRO_INVARG; + /* we can rely on the dict being non-NULL (at least the core schema is loaded) */ - char tmp_attributes_yaml [] = - #include "cdo-attributes-default.txt" - ; - cdo->attributes_yaml = malloc(sizeof(char) * sizeof(tmp_attributes_yaml)); - if(cdo->attributes_yaml == NULL) - return MSTRO_NOMEM; - strcpy(cdo->attributes_yaml, tmp_attributes_yaml); - - return MSTRO_OK; + mstro_schema schema; + mstro_status s= mstro_attribute_dict_get_schema(cdo->attributes, &schema); + if(s!=MSTRO_OK) + return s; + + return mstro_attribute_dict_set_defaults(schema, + true, + &(cdo->attributes)); } mstro_status @@ -221,24 +178,20 @@ mstro_cdo_attribute_set_yaml(mstro_cdo cdo, const char* keyval_in_yaml) { if(cdo==NULL || keyval_in_yaml==NULL) return MSTRO_INVARG; - if (cdo->attributes_yaml == NULL) - return MSTRO_INVARG; - if(mstro_cdo_state_check(cdo, MSTRO_CDO_STATE_SEALED)) + if(mstro_cdo_state_check(cdo, MSTRO_CDO_STATE_SEALED)) { + ERR("Cannot add yaml attributes on SEALED CDO\n"); return MSTRO_FAIL; + } - char *tmp = realloc(cdo->attributes_yaml, - strlen(cdo->attributes_yaml) + strlen(keyval_in_yaml) - + BYTE_ASCII_LF + BYTE_ASCII_NUL); // Not pretty, 1 additional byte for '\n' we cat right after and 1 byte for '\0' not accounted for by strlen - if(tmp==NULL) - return MSTRO_NOMEM; - else - cdo->attributes_yaml = tmp; - - strcat(cdo->attributes_yaml, keyval_in_yaml); - strcat(cdo->attributes_yaml, "\n"); - - return MSTRO_OK; + mstro_schema schema; + mstro_status s= mstro_attribute_dict_get_schema(cdo->attributes, &schema); + if(s!=MSTRO_OK) + return s; + + return mstro_attributes_parse(schema, + keyval_in_yaml, + &cdo->attributes); } mstro_status @@ -325,3 +278,26 @@ mstro_timestamp_to_tm_local(const mstro_timestamp *tsp, struct tm *tmp) +mstro_status +mstro_blob_create(size_t len, void *data, mstro_blob **result_p) +{ + if(result_p==NULL) + return MSTRO_INVOUT; + *result_p = malloc(sizeof(mstro_blob)); + if(!*result_p) + return MSTRO_NOMEM; + (*result_p)->len = len; + (*result_p)->data = data; + return MSTRO_OK; +} + +/** convenience function to dispose a blob allocated with mstro_blob_create() + */ +mstro_status +mstro_blob_dispose(mstro_blob *b) +{ + if(b==NULL) + return MSTRO_INVARG; + free(b); + return MSTRO_OK; +} diff --git a/maestro/cdo.c b/maestro/cdo.c index 3ee65835953a8d1cc94cd61eacb173c2a756efd4..9ddebf5ae363fb355db69bc3b6d19f405a7f5d66 100644 --- a/maestro/cdo.c +++ b/maestro/cdo.c @@ -133,7 +133,13 @@ mstro_cdo__alloc(void) /* initialize parts that need special handling */ atomic_init(&(res->state), MSTRO_CDO_STATE_INVALID); /* add attributes space */ - assert(MSTRO_OK==mstro_cdo_attr_table__alloc(&(res->attributes))); + mstro_status s = mstro_attribute_dict_set_defaults(g_mstro_core_schema_instance, + false, + &(res->attributes)); + if(s!=MSTRO_OK) { + ERR("Cannot create CDO, aborting\n"); + abort(); + } return res; } @@ -149,16 +155,14 @@ mstro_cdo__free(mstro_cdo *cdoptr) if((*cdoptr)->name) free((*cdoptr)->name); - status = mstro_cdo_attr_table__destroy((*cdoptr)->attributes); + status = mstro_attribute_dict_dispose((*cdoptr)->attributes); if(status!=MSTRO_OK) { ERR("Failed to destroy CDO attribute table\n"); goto BAILOUT; } - if((*cdoptr)->attributes_yaml) - free((*cdoptr)->attributes_yaml); - if((*cdoptr)->attributes_namespace) - free((*cdoptr)->attributes_namespace); + if((*cdoptr)->current_namespace) + free((*cdoptr)->current_namespace); if((*cdoptr)->mamba_array) { mmbError stat = mmb_array_destroy((*cdoptr)->mamba_array); @@ -240,7 +244,7 @@ mstro_cdo_name(mstro_cdo cdo) mstro_status mstro_cdo_declare(const char *name, - mstro_cdo_decl_attr attributes, + mstro_cdo_attributes attributes, mstro_cdo *result) { if(name==NULL) { @@ -252,6 +256,7 @@ mstro_cdo_declare(const char *name, return MSTRO_INVOUT; } if(attributes!=MSTRO_ATTR_DEFAULT) { + ERR("non-default declaration attributes unsupported, FIXME\n"); return MSTRO_UNIMPL; } @@ -341,14 +346,12 @@ mstro_cdo_declare(const char *name, return s; /* TODO initialize default namespace*/ - (*result)->attributes_namespace = malloc(sizeof(char)*128); - if ((*result)->attributes_namespace == NULL) { - ERR("Cannot allocate for CDO namespace\n"); + (*result)->current_namespace = strdup(MSTRO_CDO_ATTR_NAMESPACE_DEFAULT); + if ((*result)->current_namespace == NULL) { + ERR("Cannot allocate for default CDO namespace\n"); mstro_cdo__free(result); return MSTRO_NOMEM; } - sprintf((*result)->attributes_namespace, "%s", MSTRO_CDO_ATTR_NAMESPACE_DEFAULT); - WITH_CDO_ID_STR(idstr,&(*result)->id, INFO("Declared CDO `%s', (local ID: %s)\n", @@ -379,12 +382,14 @@ mstro_cdo_declaration_seal(mstro_cdo cdo) } - /* Parse once and for all attributes yaml string. */ - status = mstro_cdo_attributes_parse_string(cdo); - if (status != MSTRO_OK) { - ERR("CDO `%s` yaml attribute parse failed\n", cdo->name); - goto BAILOUT; - } + /* /\* Parse once and for all attributes yaml string. *\/ */ + /* status = mstro_cdo_attributes_parse_string(cdo); */ + /* if (status != MSTRO_OK) { */ + /* ERR("CDO `%s` yaml attribute parse failed\n", cdo->name); */ + /* goto BAILOUT; */ + /* } */ + void *raw_ptr; + mmbArray *mamba_array; if(cdo->raw_ptr!=NULL && cdo->mamba_array!=NULL) { ERR("CDO `%s` has both raw_ptr and existing mamba_array, unsupported\n", @@ -473,7 +478,7 @@ mstro_cdo_declaration_seal(mstro_cdo cdo) /* FIXME: this should use the fixed data but a serialized version * of the current attributes */ WARN("Sealing with silly attributes\n"); - attr.yaml_string = cdo->attributes_yaml; + //xx// attr.yaml_string = cdo->attributes_yaml; Mstro__Pool__Seal seal = MSTRO__POOL__SEAL__INIT; seal.cdoid = &cdoid; diff --git a/maestro/cdo_attributes_schema.c b/maestro/cdo_attributes_schema.c index bb83d96b86758c3084023fead12a79926c48c370..207b7b988abdb100ca46076b81bf78235e2be6e1 100644 --- a/maestro/cdo_attributes_schema.c +++ b/maestro/cdo_attributes_schema.c @@ -93,47 +93,7 @@ static const cyaml_config_t config = { .mem_fn = cyaml_mem, /* Use the default memory allocator. */ }; -mstro_status -mstro_cdo_attributes_parse_string(mstro_cdo cdo) -{ - if (cdo == NULL) - return MSTRO_INVARG; - - struct mstro_cdo_attr_table_* good_table; - struct mstro_cdo_attr_table_ _tmp_table; - struct mstro_cdo_attr_table_* tmp_table = &_tmp_table; - good_table = cdo->attributes; - - cyaml_err_t err; -// err = cyaml_load_file("/cray/css/users/chaine/projects/maestro/maestro-core/maestro/cdo-attributes-default.yaml", &config, &top_schema, (cyaml_data_t **)&tmp_table, NULL); // works now - err = cyaml_load_data((const uint8_t*)cdo->attributes_yaml, strlen(cdo->attributes_yaml), &config, &top_schema, (cyaml_data_t**)&tmp_table, NULL); //&seq_count_out); - - if (err != CYAML_OK) { - fprintf(stderr, "cyaml: %s\n", cyaml_strerror(err)); - return MSTRO_FAIL; - } - // XXX Here we need a copy, because cyaml would throw away our attribute allocation/defaults, can't memcpy either because structures don't match - // FIXME can do it slightly less hardcoded with a loop and data_offset's, or maybe partial memcpy's... - good_table->allocate_now = tmp_table->allocate_now; - good_table->maestro_provided_storage = tmp_table->maestro_provided_storage; - good_table->name = (unsigned char*)strdup((const char*)tmp_table->name); - good_table->level = tmp_table->level; - good_table->id = (unsigned char*)strdup((const char*)tmp_table->id); - good_table->lifetime = (unsigned char*)strdup((const char*)tmp_table->lifetime); - good_table->redundancy = (unsigned char*)strdup((const char*)tmp_table->redundancy); - good_table->persist = tmp_table->persist; - good_table->desist = tmp_table->desist; - - good_table->scope.local_size = tmp_table->scope.local_size; -// good_table->scope.layout.regular_1d.element_size = tmp_table->scope.layout.regular_1d.element_size; - good_table->scope.distribution = (unsigned char*)strdup((const char*)tmp_table->scope.distribution); - - // cyaml cleanup - cyaml_free(&config, &top_schema, tmp_table, 0); - - return MSTRO_OK; -} enum mstro_cdo_attr_value_type mstro_cdo_attr__match_type_cyaml(enum cyaml_type t, uint32_t size) @@ -194,100 +154,100 @@ mstro_cdo_attr__match_key_schema(const cyaml_schema_field_t s[], size_t len, con return -1; } -mstro_status -mstro_cdo_attr_table__lookup(mstro_cdo cdo, - const char *key, - enum mstro_cdo_attr_value_type *valtype, - void **value_dst) -{ -// XXX how to navigate through the attribute table levels using the schema table? -// -> I will hardcode this for now - const cyaml_schema_field_t* s; - void* ptr_tab, *ptr_val; - int found_top, found_scope, i; - size_t valsize; - - // Match key param with <WILDCARD>schema[].key - found_top = mstro_cdo_attr__match_key_schema(top_mapping_schema, sizeof(top_mapping_schema)/sizeof(cyaml_schema_field_t)-1, key); - if (found_top > -1) { - s = top_mapping_schema; - ptr_tab = (void*)(cdo->attributes); - i = found_top; - } - else { - found_scope = mstro_cdo_attr__match_key_schema(scope_mapping_schema, sizeof(scope_mapping_schema)/sizeof(cyaml_schema_field_t)-1, key); - if (found_scope > -1) { - s = scope_mapping_schema; - ptr_tab = (void*)&(cdo->attributes->scope); - i = found_scope; - } - } - if (found_top == -1 && found_scope == -1) { - /* Search key by pointer FIXME: do for all other attributes*/ - if (key == MSTRO_ATTR_CORE_CDO_RAW_PTR) { - ERR("%s cannot be queried, use mstro_cdo_access_ptr()\n", - MSTRO_ATTR_CORE_CDO_RAW_PTR); - return MSTRO_INVARG; - } - if (key == MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY) { - ERR("% cannot be queried, use mstro_cdo_access_mamba_array()\n", - MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY); - return MSTRO_INVARG; - } - if (key == MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE) { - *value_dst = (void*)&cdo->attributes->scope.local_size; - goto SUCCESS; - } +/* mstro_status */ +/* mstro_cdo_attr_table__lookup(mstro_cdo cdo, */ +/* const char *key, */ +/* enum mstro_cdo_attr_value_type *valtype, */ +/* void **value_dst) */ +/* { */ +/* // XXX how to navigate through the attribute table levels using the schema table? */ +/* // -> I will hardcode this for now */ +/* const cyaml_schema_field_t* s; */ +/* void* ptr_tab, *ptr_val; */ +/* int found_top, found_scope, i; */ +/* size_t valsize; */ + +/* // Match key param with <WILDCARD>schema[].key */ +/* found_top = mstro_cdo_attr__match_key_schema(top_mapping_schema, sizeof(top_mapping_schema)/sizeof(cyaml_schema_field_t)-1, key); */ +/* if (found_top > -1) { */ +/* s = top_mapping_schema; */ +/* ptr_tab = (void*)(cdo->attributes); */ +/* i = found_top; */ +/* } */ +/* else { */ +/* found_scope = mstro_cdo_attr__match_key_schema(scope_mapping_schema, sizeof(scope_mapping_schema)/sizeof(cyaml_schema_field_t)-1, key); */ +/* if (found_scope > -1) { */ +/* s = scope_mapping_schema; */ +/* ptr_tab = (void*)&(cdo->attributes->scope); */ +/* i = found_scope; */ +/* } */ +/* } */ +/* if (found_top == -1 && found_scope == -1) { */ +/* /\* Search key by pointer FIXME: do for all other attributes*\/ */ +/* if (key == MSTRO_ATTR_CORE_CDO_RAW_PTR) { */ +/* ERR("%s cannot be queried, use mstro_cdo_access_ptr()\n", */ +/* MSTRO_ATTR_CORE_CDO_RAW_PTR); */ +/* return MSTRO_INVARG; */ +/* } */ +/* if (key == MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY) { */ +/* ERR("% cannot be queried, use mstro_cdo_access_mamba_array()\n", */ +/* MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY); */ +/* return MSTRO_INVARG; */ +/* } */ +/* if (key == MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE) { */ +/* *value_dst = (void*)&cdo->attributes->scope.local_size; */ +/* goto SUCCESS; */ +/* } */ - /* If not found, search by string FIXME: do for all other attributes*/ - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_RAW_PTR)) { - ERR("%s cannot be queried, use mstro_cdo_access_ptr()\n", - MSTRO_ATTR_CORE_CDO_RAW_PTR); - return MSTRO_INVARG; - } - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY)) { - ERR("%s cannot be queried, use mstro_cdo_access_mamba_array()\n", - MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY); - return MSTRO_INVARG; - } - if (!strcmp(key, MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE)) { - *value_dst = (void*)&cdo->attributes->scope.local_size; - goto SUCCESS; - } - - /* not found */ - *valtype = MSTRO_CDO_ATTR_VALUE_NA; - *value_dst = NULL; - return MSTRO_INVARG; - } - - // Set valtype param with the right maestro cdo attribute type corresponding to the cyaml_type for <WILDCARD>schema[].key - *valtype = mstro_cdo_attr__match_type_cyaml(s[i].value.type, s[i].value.data_size); - - // Match <WILDCARD>schema[].key with its value in attribute table, using data_offset - ptr_val = (void*)((char*)ptr_tab + s[i].data_offset); - - if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype){ - ptr_val = *(void**)ptr_val; -// valsize = strlen((char*)ptr_val); - } -/* else - valsize = s[i].value.data_size; - - if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype) - *value_dst = malloc(valsize+1); - else - *value_dst = malloc(valsize); - if (*value_dst == NULL) - return MSTRO_NOMEM; - - memcpy(*value_dst, ptr_val, valsize); - if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype) - ((char*)(*value_dst))[valsize] = '\0'; -*/ - *value_dst = ptr_val; - -SUCCESS: - return MSTRO_OK; -} +/* /\* If not found, search by string FIXME: do for all other attributes*\/ */ +/* if (!strcmp(key, MSTRO_ATTR_CORE_CDO_RAW_PTR)) { */ +/* ERR("%s cannot be queried, use mstro_cdo_access_ptr()\n", */ +/* MSTRO_ATTR_CORE_CDO_RAW_PTR); */ +/* return MSTRO_INVARG; */ +/* } */ +/* if (!strcmp(key, MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY)) { */ +/* ERR("%s cannot be queried, use mstro_cdo_access_mamba_array()\n", */ +/* MSTRO_ATTR_CORE_CDO_MAMBA_ARRAY); */ +/* return MSTRO_INVARG; */ +/* } */ +/* if (!strcmp(key, MSTRO_ATTR_CORE_CDO_SCOPE_LOCAL_SIZE)) { */ +/* *value_dst = (void*)&cdo->attributes->scope.local_size; */ +/* goto SUCCESS; */ +/* } */ + +/* /\* not found *\/ */ +/* *valtype = MSTRO_CDO_ATTR_VALUE_NA; */ +/* *value_dst = NULL; */ +/* return MSTRO_INVARG; */ +/* } */ + +/* // Set valtype param with the right maestro cdo attribute type corresponding to the cyaml_type for <WILDCARD>schema[].key */ +/* *valtype = mstro_cdo_attr__match_type_cyaml(s[i].value.type, s[i].value.data_size); */ + +/* // Match <WILDCARD>schema[].key with its value in attribute table, using data_offset */ +/* ptr_val = (void*)((char*)ptr_tab + s[i].data_offset); */ + +/* if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype){ */ +/* ptr_val = *(void**)ptr_val; */ +/* // valsize = strlen((char*)ptr_val); */ +/* } */ +/* /\* else */ +/* valsize = s[i].value.data_size; */ + +/* if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype) */ +/* *value_dst = malloc(valsize+1); */ +/* else */ +/* *value_dst = malloc(valsize); */ +/* if (*value_dst == NULL) */ +/* return MSTRO_NOMEM; */ + +/* memcpy(*value_dst, ptr_val, valsize); */ +/* if (MSTRO_CDO_ATTR_VALUE_cstring == *valtype) */ +/* ((char*)(*value_dst))[valsize] = '\0'; */ +/* *\/ */ +/* *value_dst = ptr_val; */ + +/* SUCCESS: */ +/* return MSTRO_OK; */ +/* } */ diff --git a/maestro/core.c b/maestro/core.c index 5e3480abfdb881f843902d48c79cbc84e41aba1e..d7ad811e3a1ae7de059595cf69a063481cfca2b6 100644 --- a/maestro/core.c +++ b/maestro/core.c @@ -71,6 +71,14 @@ mstro_core_init(const char *workflow_name, return MSTRO_NOMEM; } } + status=mstro_schema_parse(MSTRO_SCHEMA_BUILTIN_YAML_CORE, + MSTRO_SCHEMA_BUILTIN_YAML_CORE_LEN, + &g_mstro_core_schema_instance); + if(status!=MSTRO_OK) { + ERR("Failed to parse built-in core schema\n"); + goto BAILOUT; + } + DEBUG("mstro_core_init: %s/%s/% "PRIi64 " in thread %" PRIxPTR" complete\n", data->workflow_name, data->component_name, data->component_index, (intptr_t)pthread_self()); diff --git a/maestro/globals.c b/maestro/globals.c index cb44ea38502439b9f4e795744ac8a2f256b214a4..02a95be71e6d50afe45f2ceb0496e9563f9b0c86 100644 --- a/maestro/globals.c +++ b/maestro/globals.c @@ -70,3 +70,6 @@ Mstro__Pool__Apptoken g_pool_apptoken = MSTRO__POOL__APPTOKEN__INIT; /** re-usable app id structure */ Mstro__Pool__Appid g_pool_appid = MSTRO__POOL__APPID__INIT; + +/** the fundamental built-in schema. Filled early in mstro_core_init(), then constant */ +mstro_schema g_mstro_core_schema_instance = NULL; diff --git a/protocols/mstro_pool.pb-c.h b/protocols/mstro_pool.pb-c.h index 8816b13f0b21bcb025272f67f797f9512ae0b5f4..2e7f3b0afbb7ced8c95aa68d26ccf9c95a4221b5 100644 --- a/protocols/mstro_pool.pb-c.h +++ b/protocols/mstro_pool.pb-c.h @@ -405,7 +405,7 @@ struct _Mstro__Pool__AVal double double_; char *string; /* - * protobuf limits this to 2^32 + * protobuf limits this to 2^32; this is used for mstro_blob attributes */ ProtobufCBinaryData bytes; Mstro__Pool__Timestamp *timestamp; diff --git a/protocols/mstro_pool.proto b/protocols/mstro_pool.proto index 5320db4d7c5428fb1dab64ea98b35b68fbae50a4..0c3e2c8eadd66f94b3b3684e70a3afee277ca0c3 100644 --- a/protocols/mstro_pool.proto +++ b/protocols/mstro_pool.proto @@ -155,7 +155,7 @@ message AVal { double double = 7; string string = 8; - bytes bytes = 9; /* protobuf limits this to 2^32 */ + bytes bytes = 9; /* protobuf limits this to 2^32; this is used for mstro_blob attributes */ Timestamp timestamp = 10; }; }; diff --git a/tests/check_schema_parse.c b/tests/check_schema_parse.c index 5fbe1a19ecf2c6c2c11a01405001c9a09e5845da..90cb51c368b66fb48176d61b815c439919fe5139 100644 --- a/tests/check_schema_parse.c +++ b/tests/check_schema_parse.c @@ -67,8 +67,8 @@ CHEAT_TEST(core_schema_parse, - mstro_schema s1, s2, s3; - mstro_attribute_dict dict; + mstro_schema s1=NULL, s2=NULL, s3=NULL; + mstro_attribute_dict dict=NULL; mstro_status s=MSTRO_OK; s=mstro_schema_parse_from_file(USER_YAML, &s2); @@ -109,9 +109,9 @@ CHEAT_TEST(core_schema_parse, ) CHEAT_TEST(core_schema_parse_builtin, - mstro_schema s1, s2; + mstro_schema s1=NULL, s2=NULL; - mstro_attribute_dict dict; + mstro_attribute_dict dict=NULL; mstro_status s=MSTRO_OK; cheat_assert(MSTRO_OK==mstro_schema_parse(MSTRO_SCHEMA_BUILTIN_YAML_CORE, @@ -176,10 +176,10 @@ CHEAT_TEST(core_schema_parse_builtin, mstro_attribute_dict_set(dict, ecmwfdate, MSTRO_CDO_ATTR_VALUE_INVALID, &ts)); /* and query the TS */ - void *tsval; + const void *tsval; cheat_assert(MSTRO_OK== mstro_attribute_dict_get(dict, ecmwfdate, &type, &tsval, NULL)); - mstro_timestamp *tsval_cast = (mstro_timestamp*)tsval; + const mstro_timestamp *tsval_cast = (const mstro_timestamp*)tsval; cheat_assert(tsval_cast->sec==ts.sec && tsval_cast->nsec==ts.nsec && tsval_cast->offset==ts.offset);