From 7b780ffb28f382c1db2a8396f110dbfa11dbd2ad Mon Sep 17 00:00:00 2001 From: Celine Mercier Date: Thu, 18 Aug 2016 17:57:03 +0200 Subject: [PATCH] View files now have a dynamic size to allow unlimited comments size --- src/obiview.c | 183 +++++++++++++++++++++++++++++++++++++++++++++----- src/obiview.h | 9 +-- 2 files changed, 173 insertions(+), 19 deletions(-) diff --git a/src/obiview.c b/src/obiview.c index 2cc8f33..615aef0 100644 --- a/src/obiview.c +++ b/src/obiview.c @@ -44,9 +44,9 @@ **************************************************************************/ /** - * Internal function calculating the size of the file where the informations about an obiview are stored. + * Internal function calculating the initial size of the file where the informations about an obiview are stored. * - * @returns The size of the file in bytes. + * @returns The initial size of the file in bytes, rounded to a multiple of page size. * * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) @@ -54,16 +54,49 @@ size_t get_platform_view_file_size(); +/** + * @brief Internal function enlarging a view file. + * + * @param view A pointer on the view. + * @param new_size The new size needed, in bytes (not necessarily rounded to a page size multiple). + * + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since August 2016 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int enlarge_view_file(Obiview_p view, size_t new_size); + + +/** + * @brief Internal function writing new comments in a view file. + * + * The new comments are concatenated to the pre-existing ones. + * The view file is enlarged if necessary. + * + * @param view A pointer on the view. + * @param comments The new comments that should be added. + * + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since August 2016 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int write_comments_to_view_file(Obiview_p view, const char* comments); + + /** * Internal function building the file name where the informations about an obiview are stored. * * @warning The returned pointer has to be freed by the caller. * + * @param view_name The name of the view. + * * @returns A pointer to the file name. * @retval NULL if an error occurred. * - * @param view_name The name of the view. - * * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ @@ -409,6 +442,101 @@ size_t get_platform_view_file_size() } +int enlarge_view_file(Obiview_p view, size_t new_size) +{ + int obiview_file_descriptor; + double multiple; + size_t rounded_new_size; + + // TODO if file name changes +// // Create file name +// file_name = build_obiview_file_name(view_name); +// if (file_name == NULL) +// return -1; + + // Open view file + obiview_file_descriptor = openat((view->dms)->view_dir_fd, (view->infos)->name, O_RDWR, 0777); + if (obiview_file_descriptor < 0) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError opening a view file"); +// free(file_name); + return -1; + } + + //free(file_name); + + // Round new size to a multiple of page size // TODO make function in utils + multiple = ceil((double) new_size / (double) getpagesize()); + rounded_new_size = multiple * getpagesize(); + + + // Enlarge the file + if (ftruncate(obiview_file_descriptor, rounded_new_size) < 0) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError enlarging a view file"); + close(obiview_file_descriptor); + return -1; + } + + // Unmap and remap the file + if (munmap(view->infos, (view->infos)->file_size) < 0) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError munmapping a view file when enlarging"); + close(obiview_file_descriptor); + return -1; + } + + view->infos = mmap(NULL, + rounded_new_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + obiview_file_descriptor, + 0 + ); + if (view->infos == MAP_FAILED) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError re-mmapping a view file after enlarging the file"); + close(obiview_file_descriptor); + return -1; + } + + // Set new size + (view->infos)->file_size = rounded_new_size; + + close(obiview_file_descriptor); + + return 0; +} + + +int write_comments_to_view_file(Obiview_p view, const char* comments) +{ + size_t new_size; + + if (comments == NULL) + return 0; // TODO or error? discuss + + new_size = (view->infos)->used_size + strlen(comments); + + // Check if the file has to be enlarged + if (new_size >= (view->infos)->file_size) + { + if (enlarge_view_file(view, new_size) < 0) + return -1; + } + + strcat((view->infos)->comments, comments); + + (view->infos)->used_size = new_size; + + return 0; +} + + int create_obiview_file(OBIDMS_p dms, const char* view_name) { // char* file_name; @@ -433,7 +561,7 @@ int create_obiview_file(OBIDMS_p dms, const char* view_name) //free(file_name); - // Truncate file to the right size + // Truncate file to the initial size file_size = get_platform_view_file_size(); if (ftruncate(obiview_file_descriptor, file_size) < 0) @@ -444,6 +572,15 @@ int create_obiview_file(OBIDMS_p dms, const char* view_name) return -1; } + // Write file size + if (write(obiview_file_descriptor, &file_size, sizeof(size_t)) < ((ssize_t) sizeof(size_t))) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError writing the file size in an obiview file"); + close(obiview_file_descriptor); + return -1; + } + close(obiview_file_descriptor); return 0; @@ -839,7 +976,7 @@ char* view_check_all_predicates(Obiview_p view) char* all_predicates_string = NULL; char** all_predicates = NULL; - if (view->nb_predicates == 0) + if (view->nb_predicates == 0) // TODO or no error? discuss { obi_set_errno(OBIVIEW_ERROR); obidebug(1, "\nError trying to check predicates of a view with no predicates."); @@ -917,10 +1054,10 @@ char* view_check_all_predicates(Obiview_p view) Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_clone, index_t* line_selection, const char* comments) { - Obiview_p view; - int i; - index_t line_nb; - struct dirent* dp; + Obiview_p view; + int i; + index_t line_nb; + struct dirent* dp; // Check uniqueness of name while ((dp = readdir(dms->view_directory)) != NULL) @@ -963,6 +1100,9 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl return NULL; } + // Write used size in view file for initial structure + (view->infos)->used_size = sizeof(Obiview_infos_t); + // Clone view to clone if there is one if (view_to_clone != NULL) { @@ -1058,11 +1198,17 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl // Fill last informations strcpy((view->infos)->name, view_name); - strcpy((view->infos)->comments, comments); (view->infos)->creation_date = time(NULL); view->nb_predicates = 0; view->predicate_functions = NULL; + if (write_comments_to_view_file(view, comments) < 0) // TODO copy comments if cloning view? + { + obidebug(1, "\nError writing comments when creating a view"); + obi_close_view(view); + return NULL; + } + // Store reference for line selection if (view->line_selection == NULL) { @@ -1251,8 +1397,16 @@ Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) //free(file_name); + // Get file size + if (read(obiview_file_descriptor, &file_size, sizeof(size_t)) < ((ssize_t) sizeof(size_t))) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError reading the file size in an obiview file"); + close(obiview_file_descriptor); + return NULL; + } + // Map the view infos structure - file_size = get_platform_view_file_size(); view_infos = mmap(NULL, file_size, PROT_READ | PROT_WRITE, @@ -1298,7 +1452,7 @@ int obi_view_unmap_file(OBIDMS_p dms, Obiview_infos_p view_infos) //free(file_name); // Unmap the view infos structure - file_size = get_platform_view_file_size(); + file_size = view_infos->file_size; if (munmap(view_infos, file_size) < 0) { obi_set_errno(OBIVIEW_ERROR); @@ -1796,8 +1950,7 @@ int obi_save_and_close_view(Obiview_p view) return -1; // TODO reverse view (delete files) else { - // TODO check size and grow file if needed - strcat((view->infos)->comments, predicates); + write_comments_to_view_file(view, predicates); free(predicates); } } diff --git a/src/obiview.h b/src/obiview.h index 0f5e975..835cd23 100644 --- a/src/obiview.h +++ b/src/obiview.h @@ -30,9 +30,6 @@ #define OBIVIEW_NAME_MAX_LENGTH (1000) /**< The maximum length of an OBIDMS view name. */ -#define OBIVIEW_COMMENTS_MAX_LENGTH (10000) /**< The maximum length of the comments associated - * with a view. - */ #define VIEW_TYPE_MAX_LENGTH (1024) /**< The maximum length of the type name of a view. */ #define LINES_COLUMN_NAME "LINES" /**< The name of the column containing the line selections @@ -73,6 +70,10 @@ typedef struct Alias_column_pair { * Once a view has been written in the view file, it can not be modified and can only be read. */ typedef struct Obiview_infos { + size_t file_size; /**< View file size in bytes. + */ + size_t used_size; /**< Used size in bytes. + */ time_t creation_date; /**< Time at which the view was written in the view file. */ char name[OBIVIEW_NAME_MAX_LENGTH+1]; /**< Name of the view, used to identify it. @@ -92,7 +93,7 @@ typedef struct Obiview_infos { */ Alias_column_pair_t column_references[MAX_NB_OPENED_COLUMNS]; /**< References (name, version and alias) for all the columns in the view. */ - char comments[OBIVIEW_COMMENTS_MAX_LENGTH+1]; /**< Comments, additional informations on the view. + char comments[]; /**< Comments, additional informations on the view. */ } Obiview_infos_t, *Obiview_infos_p;