X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=server%2Fdata.c;h=edfd4c3d388c74d7236469c7cde3db0274c184d1;hb=75b9743b95672218a61811b03433c0ab6e00ec5c;hp=82aadb6577ae844b81310e2fba8e4e0481712f2e;hpb=5ab6641e1e2c28d85440f4cbe4c4091d0c54d1ab;p=matches%2FMCTX3420.git diff --git a/server/data.c b/server/data.c index 82aadb6..edfd4c3 100644 --- a/server/data.c +++ b/server/data.c @@ -1,6 +1,6 @@ /** * @file data.c - * @purpose Implementation of data handling functions; saving, loading, displaying, selecting. + * @brief Implementation of data handling functions; saving, loading, displaying, selecting. */ #include "data.h" @@ -13,9 +13,8 @@ void Data_Init(DataFile * df) { // Everything is NULL - df->filename = NULL; - df->read_file = NULL; - df->write_file = NULL; + memset(df, 0, sizeof(DataFile)); + pthread_mutex_init(&(df->mutex), NULL); } /** @@ -34,26 +33,12 @@ void Data_Open(DataFile * df, const char * filename) // Set number of DataPoints df->num_points = 0; - // Set write FILE* - df->write_file = fopen(filename, "w+"); - if (df->write_file == NULL) - { - Fatal("Error opening DataFile %s - %s", filename, strerror(errno)); - } - - // Set read FILE* - df->read_file = df->write_file; - - //NOTE: Opening the same file in read mode gives funny results; fread generally reads less than expected - // The strerror is: "Transport endpoint is not connected" - /* - fopen(filename, "r"); - if (df->read_file == NULL) + // Set file pointer + df->file = fopen(filename, "wb+"); + if (df->file == NULL) { Fatal("Error opening DataFile %s - %s", filename, strerror(errno)); } - */ - } /** @@ -66,11 +51,10 @@ void Data_Close(DataFile * df) //TODO: Write data to TSV? - // Clear the FILE*s - df->read_file = NULL; - df->write_file = NULL; + fclose(df->file); - fclose(df->write_file); + // Clear the FILE*s + df->file = NULL; // Clear the filename free(df->filename); @@ -85,19 +69,19 @@ void Data_Close(DataFile * df) */ void Data_Save(DataFile * df, DataPoint * buffer, int amount) { - pthread_mutex_unlock(&(df->mutex)); + pthread_mutex_lock(&(df->mutex)); assert(df != NULL); assert(buffer != NULL); assert(amount >= 0); // Go to the end of the file - if (fseek(df->write_file, 0, SEEK_END) < 0) + if (fseek(df->file, 0, SEEK_END) < 0) { Fatal("Error seeking to end of DataFile %s - %s", df->filename, strerror(errno)); } // Attempt to write the DataPoints - int amount_written = fwrite(buffer, sizeof(DataPoint), amount, df->write_file); + int amount_written = fwrite(buffer, sizeof(DataPoint), amount, df->file); // Check if the correct number of points were written if (amount_written != amount) @@ -109,7 +93,6 @@ void Data_Save(DataFile * df, DataPoint * buffer, int amount) df->num_points += amount_written; pthread_mutex_unlock(&(df->mutex)); - } /** @@ -131,21 +114,21 @@ int Data_Read(DataFile * df, DataPoint * buffer, int index, int amount) // If we would read past the end of the file, reduce the amount of points to read - if (index + amount > df->num_points) - { - Log(LOGDEBUG, "Requested %d points but will only read %d to get to EOF (%d)", amount, df->num_points - index, df->num_points); - amount = df->num_points - index; - } + if (index + amount > df->num_points) + { + Log(LOGDEBUG, "Requested %d points but will only read %d to get to EOF (%d)", amount, df->num_points - index, df->num_points); + amount = df->num_points - index; + } // Go to position in file - if (fseek(df->read_file, index*sizeof(DataPoint), SEEK_SET)) + if (fseek(df->file, index*sizeof(DataPoint), SEEK_SET)) { Fatal("Error seeking to position %d in DataFile %s - %s", index, df->filename, strerror(errno)); } // Attempt to read the DataPoints - int amount_read = fread(buffer, sizeof(DataPoint), amount, df->read_file); + int amount_read = fread(buffer, sizeof(DataPoint), amount, df->file); // Check if correct number of points were read if (amount_read != amount) @@ -161,7 +144,7 @@ int Data_Read(DataFile * df, DataPoint * buffer, int index, int amount) * Print data points between two indexes using a given format * @param df - DataFile to print * @param start_index - Index to start at (inclusive) - * @param end_index - Index to end at (inclusive) + * @param end_index - Index to end at (exclusive) * @param format - The format to use */ void Data_PrintByIndexes(DataFile * df, int start_index, int end_index, DataFormat format) @@ -169,53 +152,47 @@ void Data_PrintByIndexes(DataFile * df, int start_index, int end_index, DataForm assert(df != NULL); assert(start_index >= 0); assert(end_index >= 0); - assert(end_index <= df->num_points-1 || df->num_points == 0); + assert(end_index <= df->num_points || df->num_points == 0); const char * fmt_string; // Format for each data point - char seperator; // Character used to seperate successive data points + char separator; // Character used to seperate successive data points - // Determine what format string and seperator character to use + // Determine what format string and separator character to use switch (format) { case JSON: - fmt_string = "[%f,%f]"; - seperator = ','; + fmt_string = "[%.9f,%f]"; + separator = ','; // For JSON we need an opening bracket FCGI_PrintRaw("["); break; case TSV: - fmt_string = "%f\t%f"; - seperator = '\n'; + fmt_string = "%.9f\t%f"; + separator = '\n'; break; } - DataPoint buffer[DATA_BUFSIZ]; // Buffer - // initialise buffer to stop stuff complaining - memset(buffer, 0, sizeof(DataPoint)*DATA_BUFSIZ); - - if (start_index < end_index) + DataPoint buffer[DATA_BUFSIZ] = {{0}}; // Buffer + int index = start_index; + + // Repeat until all DataPoints are printed + while (index < end_index) { + // Fill the buffer from the DataFile + int amount_read = Data_Read(df, buffer, index, DATA_BUFSIZ); - int index = start_index; - // Repeat until all DataPoints are printed - while (index <= end_index) + // Print all points in the buffer + for (int i = 0; i < amount_read && index < end_index; ++i) { - // Fill the buffer from the DataFile - int amount_read = Data_Read(df, buffer, index, DATA_BUFSIZ); - - // Print all points in the buffer - for (int i = 0; i < amount_read && index <= end_index; ++i) - { - // Print individual DataPoint - FCGI_PrintRaw(fmt_string, buffer[i].time_stamp, buffer[i].value); - - // Last seperator is not required - if (index+1 <= end_index) - FCGI_PrintRaw("%c", seperator); - - // Advance the position in the DataFile - ++index; - } + // Print individual DataPoint + FCGI_PrintRaw(fmt_string, buffer[i].time_stamp, buffer[i].value); + + // Last separator is not required + if (index+1 < end_index) + FCGI_PrintRaw("%c", separator); + + // Advance the position in the DataFile + ++index; } } @@ -235,35 +212,25 @@ void Data_PrintByIndexes(DataFile * df, int start_index, int end_index, DataForm * Prints nothing if the time stamp * @param df - DataFile to print * @param start_time - Time to start from (inclusive) - * @param end_time - Time to end at (inclusive) + * @param end_time - Time to end at (exclusive) * @param format - The format to use */ void Data_PrintByTimes(DataFile * df, double start_time, double end_time, DataFormat format) { assert(df != NULL); - assert(start_time >= 0); - assert(end_time >= 0); - assert(end_time >= start_time); - - DataPoint closest; - - // Get starting index - int start_index = Data_FindByTime(df, start_time, &closest); - - // Start time is greater than most recent time stamp - if (start_index >= df->num_points-1) + //Clamp boundaries + if (start_time < 0) + start_time = 0; + if (end_time < 0) + end_time = 0; + + int start_index = 0, end_index = 0; + if (start_time < end_time) { - if (start_index == 0 || closest.time_stamp < start_time) - { - Data_PrintByIndexes(df, 0, 0, format); // Will print "empty" dataset - return; - } + start_index = Data_FindByTime(df, start_time, NULL); + end_index = Data_FindByTime(df, end_time, NULL); } - // Get finishing index - int end_index = Data_FindByTime(df, end_time, &closest); - - // Print data between the indexes Data_PrintByIndexes(df, start_index, end_index, format); } @@ -278,7 +245,7 @@ int Data_FindByTime(DataFile * df, double time_stamp, DataPoint * closest) { assert(df != NULL); assert(time_stamp >= 0); - assert(closest != NULL); + //assert(closest != NULL); DataPoint tmp; // Current DataPoint in binary search @@ -318,3 +285,74 @@ int Data_FindByTime(DataFile * df, double time_stamp, DataPoint * closest) return index; } + +/** + * Helper; handle FCGI response that requires data + * Should be called first. + * @param df - DataFile to access + * @param start - Info about start_time param + * @param end - Info about end_time param + * @param fmt - Info about format param + * @param current_time - Current time + */ +void Data_Handler(DataFile * df, FCGIValue * start, FCGIValue * end, DataFormat format, double current_time) +{ + double start_time = *(double*)(start->value); + double end_time = *(double*)(end->value); + + if (format == JSON) + { + FCGI_JSONKey("data"); + } + + // If a time was specified + if (FCGI_RECEIVED(start->flags) || FCGI_RECEIVED(end->flags)) + { + // Wrap times relative to the current time + if (start_time < 0) + start_time += current_time; + if (end_time < 0) + end_time += current_time; + + // Print points by time range + Data_PrintByTimes(df, start_time, end_time, format); + + } + else // No time was specified; just return a recent set of points + { + pthread_mutex_lock(&(df->mutex)); + int start_index = df->num_points-DATA_BUFSIZ; + int end_index = df->num_points-1; + pthread_mutex_unlock(&(df->mutex)); + + // Bounds check + if (start_index < 0) + start_index = 0; + if (end_index < 0) + end_index = 0; + + // Print points by indexes + Data_PrintByIndexes(df, start_index, end_index, format); + } + +} + +/** + * Helper - Convert human readable format string to DataFormat + * @param fmt - FCGIValue to use + */ +DataFormat Data_GetFormat(FCGIValue * fmt) +{ + const char * fmt_str = *(const char**)(fmt->value); + // Check if format type was specified + if (FCGI_RECEIVED(fmt->flags)) + { + if (strcmp(fmt_str, "json") == 0) + return JSON; + else if (strcmp(fmt_str, "tsv") == 0) + return TSV; + else + Log(LOGERR, "Unknown format type \"%s\"", fmt_str); + } + return JSON; +}