/* Utility for printing the record info */ void QIO_print_record_info(QIO_RecordInfo *record_info){ printf("Record header: datatype %s recordtype %d \n", QIO_get_datatype(record_info), QIO_get_recordtype(record_info)); printf("precision %s colors %d spins %d count %d\n", QIO_get_precision(record_info), QIO_get_colors(record_info), QIO_get_spins(record_info), QIO_get_datacount(record_info)); if(QIO_get_recordtype(record_info) == QIO_HYPER){ int i; int n = QIO_get_hyper_spacetime(record_info); int *lower = QIO_get_hyperlower(record_info); int *upper = QIO_get_hyperupper(record_info); printf("Hypercube lower"); for(i = 0; i < n; i++){ printf(" %d",lower[i]); } printf("\n"); printf("Hypercube upper"); for(i = 0; i < n; i++){ printf(" %d",upper[i]); } printf("\n"); } }
void QIO_encode_record_info(QIO_String *record_string, QIO_RecordInfo *record_info){ char *buf; int remainder,n; char recordinfo_tags[QIO_MAXVALUESTRING]; QIO_RecordInfoWrapper wrapper = QIO_RECORD_INFO_WRAPPER; /* Start by creating string of inner tags */ buf = recordinfo_tags; remainder = QIO_MAXVALUESTRING; /* Build inner tag string by appending tags */ *buf = '\0'; buf = QIO_encode_as_string(buf,&record_info->version, &remainder); buf = QIO_encode_as_string(buf,&record_info->date, &remainder); buf = QIO_encode_as_int (buf,&record_info->recordtype, &remainder); if(QIO_get_recordtype(record_info) == QIO_HYPER){ buf = QIO_encode_as_int (buf,&record_info->spacetime, &remainder); n = record_info->spacetime.value; buf = QIO_encode_as_intlist(buf,&record_info->hyperlower, n, &remainder); buf = QIO_encode_as_intlist(buf,&record_info->hyperupper, n, &remainder); } buf = QIO_encode_as_string(buf,&record_info->datatype, &remainder); buf = QIO_encode_as_string(buf,&record_info->precision, &remainder); buf = QIO_encode_as_int (buf,&record_info->colors, &remainder); buf = QIO_encode_as_int (buf,&record_info->spins, &remainder); buf = QIO_encode_as_int (buf,&record_info->typesize, &remainder); buf = QIO_encode_as_int (buf,&record_info->datacount, &remainder); /* Insert inner tag string into file wrapper structure */ QIO_insert_record_tag_string(&wrapper, recordinfo_tags); /* Now build final XML string */ QIO_string_realloc(record_string, QIO_STRINGALLOC); buf = QIO_string_ptr(record_string); remainder = QIO_string_length(record_string); /* Begin with xml info stuff */ strncpy(buf,QIO_XMLINFO,remainder); buf[remainder-1] = '\0'; n = strlen(buf); remainder -= n; buf += n; if(remainder < 0){ printf("QIO_encode_record_info: record_string overflow\n"); } else{ /* Conclude by appending the wrapped tag string */ buf = QIO_encode_as_string (buf,&wrapper.recordinfo_tags, &remainder); } }
int QIO_generic_read_record_data(QIO_Reader *in, void (*put)(char *buf, size_t index, int count, void *arg), size_t datum_size, int word_size, void *arg, DML_Checksum *checksum, uint64_t *nbytes) { char myname[] = "QIO_generic_read_record_data"; int count; LRL_RecordReader *lrl_record_in; size_t datum_size_info; DML_Layout *layout = in->layout; int this_node = layout->this_node; int status; int recordtype; int latdim; QIO_RecordInfo *record_info = &in->record_info; /* List of acceptable binary data LIME types */ int ntypes = 2; /* Avoid a compiler bug */ LIME_type lime_type0 = QIO_LIMETYPE_BINARY_DATA; LIME_type lime_type1 = QIO_LIMETYPE_ILDG_BINARY_DATA; LIME_type lime_type_list[2] = {lime_type0, lime_type1}; // LIME_type lime_type_list[2] = { // QIO_LIMETYPE_BINARY_DATA, // QIO_LIMETYPE_ILDG_BINARY_DATA // }; LIME_type lime_type; /* It is an error to call for the data before reading the info in a given record */ if(in->read_state != QIO_RECORD_DATA_NEXT){ printf("%s(%d): Bad read state %d\n",myname,this_node,in->read_state); return QIO_ERR_INFO_MISSED; } /* Add record type and subset data to layout structure */ recordtype = QIO_get_recordtype(record_info); layout->recordtype = recordtype; status = DML_insert_subset_data(layout, QIO_get_hyperlower(record_info), QIO_get_hyperupper(record_info), QIO_get_hyper_spacetime(record_info)); if(status != 0) return QIO_ERR_BAD_SUBSET; /* Require consistency between the byte count obtained from the private record metadata and the datum_size and count parameters (per site for field or hypercube data or total for global data) */ count = QIO_get_datacount(record_info); if(datum_size != QIO_get_typesize(record_info) * count) { printf("%s(%d): requested byte count %lu disagrees with the record %d * %d\n", myname,this_node,(unsigned long)datum_size, QIO_get_typesize(record_info), count); if(this_node == layout->master_io_node) QIO_print_record_info(record_info); return QIO_ERR_BAD_READ_BYTES; } /* Verify byte count per site (for field or hypercube) or total (for global) */ datum_size_info = QIO_get_typesize(record_info) * count; if(datum_size != datum_size_info){ printf("%s(%d): byte count mismatch request %lu != actual %lu\n", myname, this_node, (unsigned long)datum_size, (unsigned long)datum_size_info); return QIO_ERR_BAD_READ_BYTES; } if(QIO_verbosity() >= QIO_VERB_DEBUG){ printf("%s(%d): Calling QIO_open_read_field\n",myname,this_node);fflush(stdout); } /* Nodes read the field */ /* Scan ahead and open the record with one of the listed LIME types */ lrl_record_in = QIO_open_read_field(in, recordtype, datum_size, lime_type_list, ntypes, &lime_type, &status); if(status != QIO_SUCCESS)return status; if(QIO_verbosity() >= QIO_VERB_DEBUG){ printf("%s(%d): Calling QIO_read_field_data\n", myname,this_node);fflush(stdout); } /* Then read the data and close the record */ status = QIO_read_field_data(in, lrl_record_in, recordtype, put, count, datum_size, word_size, arg, checksum, nbytes); if(status != QIO_SUCCESS){ printf("%s(%d): Error reading field data\n",myname,this_node); return status; } if(QIO_verbosity() >= QIO_VERB_DEBUG){ printf("%s(%d): done reading field\n",myname,this_node);fflush(stdout); } /* Copy most recent node checksum into reader */ memcpy(&(in->last_checksum), checksum, sizeof(DML_Checksum)); if(this_node == layout->master_io_node){ if(QIO_verbosity() >= QIO_VERB_REG){ printf("%s(%d): Read field\n",myname,this_node); QIO_print_record_info(record_info); } } in->read_state = QIO_RECORD_CHECKSUM_NEXT; return QIO_SUCCESS; }
int QIO_read_record_data(QIO_Reader *in, void (*put)(char *buf, size_t index, int count, void *arg), size_t datum_size, int word_size, void *arg){ char myname[] = "QIO_read_record_data"; DML_Checksum checksum; uint64_t nbytes, expect_bytes; QIO_ChecksumInfo *checksum_info_expect; size_t buf_size; size_t volume; int this_node = in->layout->this_node; int status; int recordtype = QIO_get_recordtype(&(in->record_info)); if(QIO_verbosity() >= QIO_VERB_DEBUG){ printf("%s(%d): Calling QIO_generic_read_record_data\n", myname,this_node);fflush(stdout); } status = QIO_generic_read_record_data(in, put, datum_size, word_size, arg, &checksum, &nbytes); if(status != QIO_SUCCESS)return status; /* Total number of sites in this record */ volume = in->layout->subsetvolume; /* Compute the number of bytes read by all nodes */ DML_sum_uint64_t(&nbytes); /* Check that the record size matches the expected size of the data */ if(recordtype == QIO_GLOBAL){ buf_size = datum_size; /* Global data */ expect_bytes = buf_size; } else { /* Field data */ expect_bytes = ((uint64_t)volume) * datum_size; } if(nbytes != expect_bytes){ printf("%s(%d): bytes read %lu != expected rec_size %lu\n", myname, in->layout->this_node, (unsigned long)nbytes, (unsigned long)expect_bytes); return QIO_ERR_BAD_READ_BYTES; } /* Combine checksums over all nodes */ DML_checksum_combine(&checksum); /* Copy most recent combined checksum into reader */ memcpy(&(in->last_checksum), &checksum, sizeof(DML_Checksum)); /* Everyone calls this. It changes the state machine */ checksum_info_expect = QIO_read_checksum(in); if(this_node == in->layout->master_io_node) { if(in->format == QIO_SCIDAC_NATIVE){ if(checksum_info_expect == NULL)return QIO_ERR_CHECKSUM_INFO; status = QIO_compare_checksum(this_node, checksum_info_expect, &checksum); if(status != QIO_SUCCESS)return status; } } /* Checksum info expect may be NULL on non master node. This is not an error. Freeing it is */ if( checksum_info_expect != NULL ) { QIO_destroy_checksum_info(checksum_info_expect); } if(QIO_verbosity() >= QIO_VERB_DEBUG){ printf("%s(%d): done with QIO_read_record_data\n", myname,in->layout->this_node);fflush(stdout); } return QIO_SUCCESS; }
/* Compare only fields that occur in the expected record info */ int QIO_compare_record_info(QIO_RecordInfo *found, QIO_RecordInfo *expect){ char myname[] = "QIO_compare_record_info"; if(QIO_defined_recordtype(expect)) if(!QIO_defined_recordtype(found) && QIO_get_recordtype(found) != QIO_get_recordtype(expect)) { printf("%s:Recordtype flag mismatch expected %d found %d \n",myname, QIO_get_recordtype(expect),QIO_get_recordtype(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_datatype(expect)) if(!QIO_defined_datatype(found) && strncmp(QIO_get_datatype(found),QIO_get_datatype(expect), QIO_MAXVALUESTRING)) { printf("%s:Datatype mismatch expected %s found %s \n",myname, QIO_get_datatype(expect),QIO_get_datatype(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_precision(expect)) if(!QIO_defined_precision(found) && strncmp(QIO_get_precision(found),QIO_get_precision(expect), QIO_MAXVALUESTRING)) { printf("%s:Precision mismatch expected %s found %s \n",myname, QIO_get_precision(expect),QIO_get_precision(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_colors(expect)) if(!QIO_defined_colors(found) && QIO_get_colors(found) != QIO_get_colors(expect)) { printf("%s:Colors mismatch expected %d found %d \n",myname, QIO_get_colors(expect),QIO_get_colors(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_spins(expect)) if(!QIO_defined_spins(found) && QIO_get_spins(found) != QIO_get_spins(expect)) { printf("%s:Spins mismatch expected %d found %d \n",myname, QIO_get_spins(expect),QIO_get_spins(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_typesize(expect)) if(!QIO_defined_typesize(found) && QIO_get_typesize(found) != QIO_get_typesize(expect)) { printf("%s:Typesize mismatch expected %d found %d \n",myname, QIO_get_typesize(expect),QIO_get_typesize(found)); return QIO_ERR_REC_INFO; } if(QIO_defined_datacount(expect)) if(!QIO_defined_datacount(found) && QIO_get_datacount(found) != QIO_get_datacount(expect)) { printf("%s:Datacount mismatch expected %d found %d \n",myname, QIO_get_datacount(expect),QIO_get_datacount(found)); return QIO_ERR_REC_INFO; } return QIO_SUCCESS; }
int QIO_decode_record_info(QIO_RecordInfo *record_info, QIO_String *record_string){ char *parse_pt = QIO_string_ptr(record_string); char *tmp_pt; char tag[QIO_MAXTAG]; char tags_string[QIO_MAXVALUESTRING]; char value_string[QIO_MAXVALUESTRING]; int errors = 0; QIO_RecordInfoWrapper wrapper = QIO_RECORD_INFO_WRAPPER; QIO_RecordInfo templ = QIO_RECORD_INFO_TEMPLATE; char *left_angle; /* Compatibility */ QIO_RecordInfo_v1p0 record_info_v1p0 = QIO_RECORD_INFO_TEMPLATE_v1p0; /* Initialize record info structure from a template */ memcpy(record_info, &templ, sizeof(QIO_RecordInfo)); /* Start parsing record_string */ /* Check leading tag, which is probably the info phrase "<?xml ...?>" */ /* We ignore it if it is there */ tmp_pt = QIO_next_tag(parse_pt, tag, &left_angle); if(strcmp(tag,QIO_QUESTXML)==0){ /* Found ?xml, so resume parsing after the closing ">", ignoring the field. Otherwise, leave the parse_pt at its initial value */ parse_pt = tmp_pt; } /* Open top-level tag (wrapper) and extract string containing tags */ parse_pt = QIO_get_tag_value(parse_pt, tag, tags_string); QIO_decode_as_string (tag, tags_string, &wrapper.recordinfo_tags); /* If outer wrapper has bad tag, exit with error status */ if(QIO_check_string_occur(&wrapper.recordinfo_tags)) return QIO_BAD_XML; /* Otherwise start parsing the string of tags */ parse_pt = QIO_get_record_info_tag_string(&wrapper); /* Scan string until null character is reached */ while(*parse_pt){ parse_pt = QIO_get_tag_value(parse_pt, tag, value_string); QIO_decode_as_string (tag,value_string,&record_info->version); QIO_decode_as_string (tag,value_string,&record_info->date); QIO_decode_as_int (tag,value_string,&record_info->recordtype); QIO_decode_as_int (tag,value_string,&record_info->spacetime); QIO_decode_as_intlist(tag,value_string,&record_info->hyperlower); QIO_decode_as_intlist(tag,value_string,&record_info->hyperupper); QIO_decode_as_string (tag,value_string,&record_info->datatype); QIO_decode_as_string (tag,value_string,&record_info->precision); QIO_decode_as_int (tag,value_string,&record_info->colors); QIO_decode_as_int (tag,value_string,&record_info->spins); QIO_decode_as_int (tag,value_string,&record_info->typesize); QIO_decode_as_int (tag,value_string,&record_info->datacount); /* compatibility */ QIO_decode_as_int (tag,value_string,&record_info_v1p0.globaldata); } /* Backward compatibility */ /* Convert version 1.0 record_info structure to version 1.1 */ if(strcmp("1.0",QIO_get_record_info_version(record_info)) == 0){ /* Version 1.1 added a new record type: hypercube subset and requires a list of lower and upper coordinate bounds to specify the hypercube. These parameters are ignored with the QIO_GLOBAL and QIO_FIELD record types, the only ones used in version 1, so we don't need to set default values. */ /* An earlier defective version (also labeled 1.0) was missing the "globaldata" parameter altogether. */ /* If the old globaldata tag is missing, insert a default value */ if(QIO_check_int_occur(&record_info_v1p0.globaldata) != 0){ record_info_v1p0.globaldata.occur = 1; /* Default is "field" record type */ record_info_v1p0.globaldata.value = QIO_FIELD; } /* Also the "globaldata" member was renamed "recordtype". So just copy the old parameter value. */ record_info->recordtype.occur = 1; record_info->recordtype.value = QIO_get_globaldata(&record_info_v1p0); } /* Check for completeness */ errors += QIO_check_string_occur(&record_info->version); errors += QIO_check_int_occur (&record_info->recordtype); errors += QIO_check_string_occur(&record_info->datatype); errors += QIO_check_string_occur(&record_info->precision); errors += QIO_check_int_occur (&record_info->typesize); errors += QIO_check_int_occur (&record_info->datacount); /* Requirements for hypercube record type */ if(QIO_get_recordtype(record_info) == QIO_HYPER){ errors += QIO_check_int_occur (&record_info->spacetime); errors += QIO_check_intarray_occur (&record_info->hyperlower); errors += QIO_check_intarray_occur (&record_info->hyperupper); } return errors; }