From e524041013b4c887f8db642d698a7fcbae9ec356 Mon Sep 17 00:00:00 2001 From: Celine Mercier Date: Tue, 7 Feb 2017 17:16:09 +0100 Subject: [PATCH] Views: Files for unfinished views now have the extension '.obiview_unfinished', renamed to '.obiview' when the view is finished. --- python/obitools3/obidms/_obidms.pyx | 2 +- python/obitools3/obidms/capi/obiview.pxd | 8 +- src/obi_align.c | 16 +- src/obiview.c | 533 ++++++++++++++++------- src/obiview.h | 39 +- 5 files changed, 384 insertions(+), 214 deletions(-) diff --git a/python/obitools3/obidms/_obidms.pyx b/python/obitools3/obidms/_obidms.pyx index 943b3e2..51a0d5a 100644 --- a/python/obitools3/obidms/_obidms.pyx +++ b/python/obitools3/obidms/_obidms.pyx @@ -690,7 +690,7 @@ cdef class OBIDMS : cdef int i, j cdef str column_name - view_infos_p = obi_view_map_file(self._pointer, str2bytes(view_name)) + view_infos_p = obi_view_map_file(self._pointer, str2bytes(view_name), True) view_infos_d = {} view_infos_d["name"] = bytes2str(view_infos_p.name) view_infos_d["comments"] = bytes2str(view_infos_p.comments) diff --git a/python/obitools3/obidms/capi/obiview.pxd b/python/obitools3/obidms/capi/obiview.pxd index 34521ca..792441b 100644 --- a/python/obitools3/obidms/capi/obiview.pxd +++ b/python/obitools3/obidms/capi/obiview.pxd @@ -68,7 +68,7 @@ cdef extern from "obiview.h" nogil: Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const_char_p view_name, const_char_p view_to_clone_name, index_t* line_selection, const_char_p comments, bint quality_column) - Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) + Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name, bint finished) int obi_view_unmap_file(OBIDMS_p dms, Obiview_infos_p view_infos) @@ -94,11 +94,7 @@ cdef extern from "obiview.h" nogil: OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const_char_p column_name) - int obi_view_create_column_alias(Obiview_p view, const_char_p current_name, const_char_p alias) - - int obi_save_view(Obiview_p view) - - int obi_close_view(Obiview_p view) + int obi_view_create_column_alias(Obiview_p view, const_char_p current_name, const_char_p alias) int obi_save_and_close_view(Obiview_p view) diff --git a/src/obi_align.c b/src/obi_align.c index 3fa3678..07a389b 100644 --- a/src/obi_align.c +++ b/src/obi_align.c @@ -4,7 +4,7 @@ /** * @file obi_align.c - * @author Celine Mercier + * @author Celine Mercier (celine.mercier@metabarcoding.org) * @date May 4th 2016 * @brief Functions handling LCS sequence alignments. */ @@ -31,10 +31,6 @@ #define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?) -// TODO -// use openMP pragmas - - /************************************************************************** * * D E C L A R A T I O N O F T H E P R I V A T E F U N C T I O N S @@ -618,12 +614,12 @@ int obi_lcs_align_one_column(OBIDMS_p dms, const char* seq_view_name, const char } // Close views - if (obi_close_view(seq_view) < 0) + if (obi_save_and_close_view(seq_view) < 0) { obidebug(1, "\nError closing the input view after aligning"); return -1; } - if (obi_close_view(output_view) < 0) + if (obi_save_and_close_view(output_view) < 0) { obidebug(1, "\nError closing the output view after aligning"); return -1; @@ -963,19 +959,19 @@ int obi_lcs_align_two_columns(OBIDMS_p dms, // Close views if (seq2_view != seq1_view) { - if (obi_close_view(seq2_view) < 0) + if (obi_save_and_close_view(seq2_view) < 0) { obidebug(1, "\nError closing the second input view after aligning"); return -1; } } - if (obi_close_view(seq1_view) < 0) + if (obi_save_and_close_view(seq1_view) < 0) { obidebug(1, "\nError closing the first input view after aligning"); return -1; } - if (obi_close_view(output_view) < 0) + if (obi_save_and_close_view(output_view) < 0) { obidebug(1, "\nError closing the output view after aligning"); return -1; diff --git a/src/obiview.c b/src/obiview.c index a9b0a86..a8f67a2 100644 --- a/src/obiview.c +++ b/src/obiview.c @@ -47,7 +47,7 @@ /** - * Internal function building the file name where the informations about an obiview are stored. + * Internal function building the file name where the informations about a finished, read-only obiview are stored. * * @warning The returned pointer has to be freed by the caller. * @@ -63,7 +63,23 @@ static char* build_obiview_file_name(const char* view_name); /** - * Internal function checking if a view with a given name already exists in a DMS. + * Internal function building the file name where the informations about an unfinished, writable 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. + * + * @since February 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +static char* build_unfinished_obiview_file_name(const char* view_name); + + +/** + * Internal function checking if a view (either finished or unfinished) with a given name already exists in a DMS. * * @param dms The DMS. * @param view_name The name of the view. @@ -73,7 +89,7 @@ static char* build_obiview_file_name(const char* view_name); * @since September 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -bool view_exists(OBIDMS_p dms, const char* view_name); +static bool view_exists(OBIDMS_p dms, const char* view_name); /** @@ -84,7 +100,7 @@ bool view_exists(OBIDMS_p dms, const char* view_name); * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -size_t get_platform_view_file_size(); +static size_t get_platform_view_file_size(); /** @@ -99,7 +115,7 @@ size_t get_platform_view_file_size(); * @since August 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int enlarge_view_file(Obiview_p view, size_t new_size); +static int enlarge_view_file(Obiview_p view, size_t new_size); /** @@ -117,7 +133,7 @@ int enlarge_view_file(Obiview_p view, size_t new_size); * @since August 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int write_comments_to_view_file(Obiview_p view, const char* comments); +static int write_comments_to_view_file(Obiview_p view, const char* comments); /** @@ -134,7 +150,7 @@ int write_comments_to_view_file(Obiview_p view, const char* comments); * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int create_obiview_file(OBIDMS_p dms, const char* view_name); +static int create_obiview_file(OBIDMS_p dms, const char* view_name); /** @@ -156,7 +172,7 @@ int create_obiview_file(OBIDMS_p dms, const char* view_name); * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -void update_column_refs(Obiview_p view); +static void update_column_refs(Obiview_p view); /** @@ -175,7 +191,7 @@ void update_column_refs(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int create_column_dict(Obiview_p view); +static int create_column_dict(Obiview_p view); /** @@ -194,7 +210,7 @@ int create_column_dict(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int update_column_dict(Obiview_p view); +static int update_column_dict(Obiview_p view); /** @@ -219,7 +235,7 @@ int update_column_dict(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int update_column_refs_and_dict(Obiview_p view); +static int update_column_refs_and_dict(Obiview_p view); /** @@ -239,7 +255,7 @@ int update_column_refs_and_dict(Obiview_p view); * @since February 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int update_lines(Obiview_p view, index_t line_count); +static int update_lines(Obiview_p view, index_t line_count); /** @@ -257,7 +273,71 @@ int update_lines(Obiview_p view, index_t line_count); * @since February 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name); +static OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name); + + +/** + * @brief Saves a view, updating its informations in the view file. + * + * @warning The view must be writable. + * + * @param view A pointer on the view. + * + * @returns A value indicating the success of the operation. + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since February 2016 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +static int save_view(Obiview_p view); + + +/** + * @brief Rename a view file once the view is finished, replacing the '*.obiview_unfinished' extension with '*.obiview'. + * + * @param view A pointer on the view. + * + * @returns A value indicating the success of the operation. + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since February 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +static int rename_finished_view(Obiview_p view); + + +/** + * @brief Finishes a view: check the predicates, save all the informations, rename the view file. + * + * @param view A pointer on the view. + * + * @returns A value indicating the success of the operation. + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since February 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +static int finish_view(Obiview_p view); + +/** + * @brief Closes an opened view. + * + * @warning Doesn't save the view. + * + * @param view A pointer on the view. + * + * @returns A value indicating the success of the operation. + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @see obi_save_and_close_view() + * @since February 2016 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +static int close_view(Obiview_p view); /** @@ -276,7 +356,7 @@ OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name); * @since April 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p); +static int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p); /** @@ -294,7 +374,7 @@ int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, i * @since April 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p); +static int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p); /****** PREDICATE FUNCTIONS *******/ @@ -313,7 +393,7 @@ int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_has_nuc_sequence_column(Obiview_p view); +static char* view_has_nuc_sequence_column(Obiview_p view); /** @@ -330,7 +410,7 @@ char* view_has_nuc_sequence_column(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_has_quality_column(Obiview_p view); +static char* view_has_quality_column(Obiview_p view); /** @@ -347,7 +427,7 @@ char* view_has_quality_column(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_has_id_column(Obiview_p view); +static char* view_has_id_column(Obiview_p view); /** @@ -364,7 +444,7 @@ char* view_has_id_column(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_has_definition_column(Obiview_p view); +static char* view_has_definition_column(Obiview_p view); /** @@ -381,7 +461,7 @@ char* view_has_definition_column(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_check_qual_match_seqs(Obiview_p view); +static char* view_check_qual_match_seqs(Obiview_p view); /** @@ -396,7 +476,7 @@ char* view_check_qual_match_seqs(Obiview_p view); * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_check_one_predicate(Obiview_p view, char* (*predicate_function)(Obiview_p view)); +static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function)(Obiview_p view)); /** @@ -410,7 +490,7 @@ char* view_check_one_predicate(Obiview_p view, char* (*predicate_function)(Obivi * @since July 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -char* view_check_all_predicates(Obiview_p view); +static char* view_check_all_predicates(Obiview_p view); /************************************************************************ @@ -443,11 +523,35 @@ static char* build_obiview_file_name(const char* view_name) } -bool view_exists(OBIDMS_p dms, const char* view_name) +static char* build_unfinished_obiview_file_name(const char* view_name) +{ + char* file_name; + + // Build file name + file_name = (char*) malloc((strlen(view_name) + 19 + 1)*sizeof(char)); + if (file_name == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for a view file name"); + return NULL; + } + if (sprintf(file_name, "%s.obiview_unfinished", view_name) < 0) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nProblem building an unfinished obiview file name"); + return NULL; + } + + return file_name; +} + + +static bool view_exists(OBIDMS_p dms, const char* view_name) { struct dirent* dp; char* file_name; + // Check finished views // Create file name file_name = build_obiview_file_name(view_name); if (file_name == NULL) @@ -458,13 +562,38 @@ bool view_exists(OBIDMS_p dms, const char* view_name) if ((dp->d_name)[0] == '.') continue; if (strcmp(dp->d_name, file_name) == 0) + { + free(file_name); return true; + } } + + free(file_name); + + // Check unfinished views + // Create file name + file_name = build_unfinished_obiview_file_name(view_name); + if (file_name == NULL) + return -1; + + while ((dp = readdir(dms->view_directory)) != NULL) + { + if ((dp->d_name)[0] == '.') + continue; + if (strcmp(dp->d_name, file_name) == 0) + { + free(file_name); + return true; + } + } + + free(file_name); + return false; } -size_t get_platform_view_file_size() +static size_t get_platform_view_file_size() { size_t obiview_size; size_t rounded_obiview_size; @@ -480,7 +609,7 @@ size_t get_platform_view_file_size() } -int enlarge_view_file(Obiview_p view, size_t new_size) +static int enlarge_view_file(Obiview_p view, size_t new_size) { int obiview_file_descriptor; double multiple; @@ -488,7 +617,7 @@ int enlarge_view_file(Obiview_p view, size_t new_size) char* file_name; // Create file name - file_name = build_obiview_file_name((view->infos)->name); + file_name = build_unfinished_obiview_file_name((view->infos)->name); if (file_name == NULL) return -1; @@ -556,7 +685,7 @@ int enlarge_view_file(Obiview_p view, size_t new_size) } -int write_comments_to_view_file(Obiview_p view, const char* comments) +static int write_comments_to_view_file(Obiview_p view, const char* comments) { size_t new_size; @@ -580,14 +709,14 @@ int write_comments_to_view_file(Obiview_p view, const char* comments) } -int create_obiview_file(OBIDMS_p dms, const char* view_name) +static int create_obiview_file(OBIDMS_p dms, const char* view_name) { char* file_name; int obiview_file_descriptor; size_t file_size; // Create file name - file_name = build_obiview_file_name(view_name); + file_name = build_unfinished_obiview_file_name(view_name); if (file_name == NULL) return -1; @@ -634,7 +763,7 @@ int create_obiview_file(OBIDMS_p dms, const char* view_name) } -void update_column_refs(Obiview_p view) +static void update_column_refs(Obiview_p view) { int i; @@ -646,7 +775,7 @@ void update_column_refs(Obiview_p view) } -int create_column_dict(Obiview_p view) +static int create_column_dict(Obiview_p view) { int i; @@ -681,7 +810,7 @@ int create_column_dict(Obiview_p view) } -int update_column_dict(Obiview_p view) +static int update_column_dict(Obiview_p view) { // Re-initialize the dictionary to rebuild it from scratch ht_free(view->column_dict); @@ -693,14 +822,14 @@ int update_column_dict(Obiview_p view) } -int update_column_refs_and_dict(Obiview_p view) +static int update_column_refs_and_dict(Obiview_p view) { update_column_refs(view); return update_column_dict(view); } -int update_lines(Obiview_p view, index_t line_count) +static int update_lines(Obiview_p view, index_t line_count) { int i; @@ -739,7 +868,7 @@ int update_lines(Obiview_p view, index_t line_count) } -OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name) +static OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name) { int i; OBIDMS_column_p column = NULL; @@ -799,7 +928,161 @@ OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_name) } -int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p) +static int save_view(Obiview_p view) +{ + // Check that the view is not read-only + if (view->read_only) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError trying to save a read-only view"); + return -1; + } + + // Store reference for the line selection associated with that view if there is one + if (view->line_selection != NULL) // Unnecessary in theory, the line selection references are already saved + { + strcpy(((view->infos)->line_selection).column_name, ((view->line_selection)->header)->name); + ((view->infos)->line_selection).version = ((view->line_selection)->header)->version; + (view->infos)->all_lines = false; + } + else // Necessary because line selection could have been deleted if a column was cloned + { + (((view->infos)->line_selection).column_name)[0] = '\0'; + ((view->infos)->line_selection).version = -1; + (view->infos)->all_lines = true; + } + + update_column_refs(view); + + return 0; +} + + +static int rename_finished_view(Obiview_p view) +{ + char* old_name; + char* new_name; + char* path_old_name; + char* path_new_name; + char* full_path_old_name; + char* full_path_new_name; + + old_name = build_unfinished_obiview_file_name((view->infos)->name); + new_name = build_obiview_file_name((view->infos)->name); + + path_old_name = malloc(MAX_PATH_LEN); + path_new_name = malloc(MAX_PATH_LEN); + + strcpy(path_old_name, "VIEWS/"); + strcat(path_old_name, old_name); + + strcpy(path_new_name, "VIEWS/"); + strcat(path_new_name, new_name); + + full_path_old_name = obi_dms_get_full_path(view->dms, path_old_name); + full_path_new_name = obi_dms_get_full_path(view->dms, path_new_name); + + if (rename(full_path_old_name, full_path_new_name) < 0) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError renaming the file of a finished view: %s", full_path_new_name); + free(old_name); + free(new_name); + return -1; + } + + free(old_name); + free(new_name); + free(path_new_name); + free(path_old_name); + free(full_path_old_name); + free(full_path_new_name); + + return 0; +} + + +static int finish_view(Obiview_p view) +{ + char* predicates; + + // Check that the view is not read-only + if (view->read_only) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError trying to save a read-only view"); + return -1; + } + + // Check predicates + predicates = view_check_all_predicates(view); + if (predicates == NULL) + { + obidebug(1, "\nView predicates not respected"); + return -1; // TODO reverse view (delete files) + } + else + { + write_comments_to_view_file(view, predicates); + free(predicates); + } + + if (save_view(view) < 0) + return -1; + + if (rename_finished_view(view) < 0) + return -1; + + // Flag the view as finished + (view->infos)->finished = true; + + return 0; +} + + +static int close_view(Obiview_p view) +{ + int i; + int ret_value; + + ret_value = 0; + + for (i=0; i < ((view->infos)->column_count); i++) + { + if (obi_close_column((view->columns)[i]) < 0) + { + obidebug(1, "\nError closing a column while closing a view"); + ret_value = -1; + } + } + + // Close line selection if there is one + if (view->line_selection != NULL) + { + if (obi_close_column(view->line_selection) < 0) + { + obidebug(1, "\nError closing a line selection while closing a view"); + ret_value = -1; + } + } + + // Free the column dictionary + ht_free(view->column_dict); + + // Unmap view file + if (obi_view_unmap_file(view->dms, view->infos) < 0) + { + obidebug(1, "\nError unmaping a view file while closing a view"); + ret_value = -1; + } + + free(view); + + return ret_value; +} + + +static int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, index_t* line_nb_p) { int i; char* column_name = NULL; @@ -846,7 +1129,7 @@ int prepare_to_set_value_in_column(Obiview_p view, OBIDMS_column_p* column_pp, i } -int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p) +static int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p) { if (((*line_nb_p)+1) > ((view->infos)->line_count)) { @@ -865,7 +1148,7 @@ int prepare_to_get_value_from_column(Obiview_p view, index_t* line_nb_p) /****** PREDICATE FUNCTIONS *******/ -char* view_has_nuc_sequence_column(Obiview_p view) +static char* view_has_nuc_sequence_column(Obiview_p view) { char* predicate; @@ -889,7 +1172,7 @@ char* view_has_nuc_sequence_column(Obiview_p view) } -char* view_has_quality_column(Obiview_p view) +static char* view_has_quality_column(Obiview_p view) { char* predicate; @@ -913,7 +1196,7 @@ char* view_has_quality_column(Obiview_p view) } -char* view_has_id_column(Obiview_p view) +static char* view_has_id_column(Obiview_p view) { char* predicate; @@ -936,7 +1219,8 @@ char* view_has_id_column(Obiview_p view) } } -char* view_has_definition_column(Obiview_p view) + +static char* view_has_definition_column(Obiview_p view) { char* predicate; @@ -960,7 +1244,7 @@ char* view_has_definition_column(Obiview_p view) } -char* view_check_qual_match_seqs(Obiview_p view) +static char* view_check_qual_match_seqs(Obiview_p view) { index_t i, j, k; index_t nb_elements_per_line; @@ -1053,13 +1337,13 @@ char* view_check_qual_match_seqs(Obiview_p view) } -char* view_check_one_predicate(Obiview_p view, char* (*predicate_function)(Obiview_p view)) +static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function)(Obiview_p view)) { return predicate_function(view); } -char* view_check_all_predicates(Obiview_p view) +static char* view_check_all_predicates(Obiview_p view) { int i, j; size_t size_to_allocate; @@ -1195,7 +1479,7 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl } // Map view file - view->infos = obi_view_map_file(dms, view_name); + view->infos = obi_view_map_file(dms, view_name, false); if (view->infos == NULL) { obidebug(1, "\nError mapping the informations of a new view"); @@ -1305,7 +1589,7 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl if (write_comments_to_view_file(view, clone_comment) < 0) { obidebug(1, "\nError writing comments when creating a view"); - obi_close_view(view); + close_view(view); return NULL; } } @@ -1341,7 +1625,7 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl if (write_comments_to_view_file(view, comments) < 0) { obidebug(1, "\nError writing comments when creating a view"); - obi_close_view(view); + close_view(view); return NULL; } @@ -1360,7 +1644,7 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl // Create the column dictionary (hash table) associating column names (or aliases) to column pointers if (create_column_dict(view) < 0) { - obi_close_view(view); + close_view(view); return NULL; } @@ -1409,7 +1693,7 @@ Obiview_p obi_new_view_cloned_from_name(OBIDMS_p dms, const char* view_name, con return NULL; view = obi_new_view(dms, view_name, view_to_clone, line_selection, comments); - obi_close_view(view_to_clone); + close_view(view_to_clone); return view; } @@ -1511,26 +1795,43 @@ Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const char* view_ return NULL; view = obi_new_view_nuc_seqs(dms, view_name, view_to_clone, line_selection, comments, quality_column); - obi_close_view(view_to_clone); + close_view(view_to_clone); return view; } -Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) +Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name, bool finished) { char* file_name; Obiview_infos_p view_infos; int obiview_file_descriptor; size_t file_size; + int open_flag; + int mmap_flag; // Create file name - file_name = build_obiview_file_name(view_name); + if (finished) + file_name = build_obiview_file_name(view_name); + else + file_name = build_unfinished_obiview_file_name(view_name); if (file_name == NULL) return NULL; + // Set flags (read-only or not) + if (finished) + { + open_flag = O_RDONLY; + mmap_flag = PROT_READ; + } + else + { + open_flag = O_RDWR; + mmap_flag = PROT_READ | PROT_WRITE; + } + // Open view file - obiview_file_descriptor = openat(dms->view_dir_fd, file_name, O_RDWR, 0777); + obiview_file_descriptor = openat(dms->view_dir_fd, file_name, open_flag, 0777); if (obiview_file_descriptor < 0) { if (errno == ENOENT) @@ -1560,7 +1861,7 @@ Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) // Map the view infos structure view_infos = mmap(NULL, file_size, - PROT_READ | PROT_WRITE, + mmap_flag, MAP_SHARED, obiview_file_descriptor, 0 @@ -1585,17 +1886,20 @@ Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name) int obi_view_unmap_file(OBIDMS_p dms, Obiview_infos_p view_infos) { - char* file_name; - int obiview_file_descriptor; - size_t file_size; + char* file_name; + int obiview_file_descriptor; + size_t file_size; // Get file name - file_name = build_obiview_file_name(view_infos->name); + if (view_infos->finished) + file_name = build_obiview_file_name(view_infos->name); + else + file_name = build_unfinished_obiview_file_name(view_infos->name); if (file_name == NULL) return -1; // Open view file - obiview_file_descriptor = openat(dms->view_dir_fd, file_name, O_RDWR, 0777); + obiview_file_descriptor = openat(dms->view_dir_fd, file_name, O_RDONLY, 0777); if (obiview_file_descriptor < 0) { obi_set_errno(OBIVIEW_ERROR); @@ -1661,13 +1965,9 @@ Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name) } // Map view file - view->infos = obi_view_map_file(dms, view_name); - - // Check that the view is finished and can be opened - if ((view->infos)->finished == false) + view->infos = obi_view_map_file(dms, view_name, true); + if ((view->infos) == NULL) { - obidebug(1, "\nError opening a view: the view is not finished"); - obi_view_unmap_file(view->dms, view->infos); free(view); return NULL; } @@ -1697,7 +1997,7 @@ Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name) if (column_pointer == NULL) { obidebug(1, "\nError opening a column for a view: column %d: %s, version %d", i, column_name, column_version); - obi_close_view(view); + close_view(view); return NULL; } (view->columns)[i] = column_pointer; @@ -1713,7 +2013,7 @@ Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name) if (create_column_dict(view) < 0) { obidebug(1, "\nError creating the column dictionary when opening a view"); - obi_close_view(view); + close_view(view); return NULL; } @@ -1963,103 +2263,16 @@ int obi_view_create_column_alias(Obiview_p view, const char* current_name, const } -int obi_save_view(Obiview_p view) -{ - // Check that the view is not read-only - if (view->read_only) - { - obi_set_errno(OBIVIEW_ERROR); - obidebug(1, "\nError trying to save a read-only view"); - return -1; - } - - // Store reference for the line selection associated with that view if there is one - if (view->line_selection != NULL) // Unnecessary in theory, the line selection references are already saved - { - strcpy(((view->infos)->line_selection).column_name, ((view->line_selection)->header)->name); - ((view->infos)->line_selection).version = ((view->line_selection)->header)->version; - (view->infos)->all_lines = false; - } - else // Necessary because line selection could have been deleted if a column was cloned - { - (((view->infos)->line_selection).column_name)[0] = '\0'; - ((view->infos)->line_selection).version = -1; - (view->infos)->all_lines = true; - } - - update_column_refs(view); - - return 0; -} - - -int obi_close_view(Obiview_p view) -{ - int i; - int ret_value; - - ret_value = 0; - - for (i=0; i < ((view->infos)->column_count); i++) - { - if (obi_close_column((view->columns)[i]) < 0) - { - obidebug(1, "\nError closing a column while closing a view"); - ret_value = -1; - } - } - - // Close line selection if there is one - if (view->line_selection != NULL) - { - if (obi_close_column(view->line_selection) < 0) - { - obidebug(1, "\nError closing a line selection while closing a view"); - ret_value = -1; - } - } - - // Flag the view as finished - (view->infos)->finished = true; - - // Free the column dictionary - ht_free(view->column_dict); - - // Unmap view file - if (obi_view_unmap_file(view->dms, view->infos) < 0) - { - obidebug(1, "\nError unmaping a view file while closing a view"); - ret_value = -1; - } - - free(view); - - return ret_value; -} - - int obi_save_and_close_view(Obiview_p view) { - char* predicates; - - if (!(view->read_only)) - { - predicates = view_check_all_predicates(view); - if (predicates == NULL) - { - obidebug(1, "\nView predicates not respected"); - return -1; // TODO reverse view (delete files) - } - else - { - write_comments_to_view_file(view, predicates); - free(predicates); - } - if (obi_save_view(view) < 0) + // Finish and save the view if it is not read-only + if ( ! (view->read_only)) + if (finish_view(view) < 0) return -1; - } - if (obi_close_view(view) < 0) + + if (close_view(view) < 0) return -1; + return 0; } diff --git a/src/obiview.h b/src/obiview.h index 641b856..f2750e9 100644 --- a/src/obiview.h +++ b/src/obiview.h @@ -242,6 +242,7 @@ Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const char* view_ * * @param dms A pointer on the OBIDMS. * @param view_name The unique name identifying the view. + * @param finished Whether the view is finished or not. * * @returns A pointer on the mapped view infos structure. * @retval NULL if an error occurred. @@ -249,7 +250,7 @@ Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const char* view_ * @since June 2016 * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name); +Obiview_infos_p obi_view_map_file(OBIDMS_p dms, const char* view_name, bool finished); /** @@ -444,42 +445,6 @@ int obi_select_line(Obiview_p view, index_t line_nb); int obi_select_lines(Obiview_p view, index_t* line_nbs); -/** - * @brief Saves a view, writing it in the view file. - * - * The view is written at the end of the view file, following the latest written view. - * - * @warning The view must be writable. - * - * @param view A pointer on the view. - * - * @returns A value indicating the success of the operation. - * @retval 0 if the operation was successfully completed. - * @retval -1 if an error occurred. - * - * @since February 2016 - * @author Celine Mercier (celine.mercier@metabarcoding.org) - */ -int obi_save_view(Obiview_p view); - - -/** - * @brief Closes an opened view. - * - * @warning Uses obi_save_and_close_view() to automatically save the view if it's not already saved in the view file. - * - * @param view A pointer on the view. - * - * @returns A value indicating the success of the operation. - * @retval 0 if the operation was successfully completed. - * @retval -1 if an error occurred. - * - * @since February 2016 - * @author Celine Mercier (celine.mercier@metabarcoding.org) - */ -int obi_close_view(Obiview_p view); - - /** * @brief Closes an opened view, and saves it if it is not read-only (meaning it is not already saved in the view file). *