Files
obitools3/src/obiview.c

1150 lines
29 KiB
C
Raw Normal View History

2016-02-18 10:38:51 +01:00
/********************************************************************
* Obiview functions *
********************************************************************/
/**
* @file obiview.c
* @author Celine Mercier (celine.mercier@metabarcoding.org)
* @date 16 December 2015
* @brief Obiview functions.
*/
// TODO
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "obidms.h"
#include "obiview.h"
#include "obierrno.h"
#include "obidebug.h"
#include "obidmscolumn.h"
#include "private_at_functions.h"
#include "obilittlebigman.h"
#include "obidmscolumn_idx.h"
#define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?)
/**************************************************************************
*
* 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
*
**************************************************************************/
/**
* Internal function building the file name where obiviews are stored.
*
* @warning The returned pointer has to be freed by the caller.
*
* @returns A pointer to the file name.
* @retval NULL if an error occurred.
*
* @param dms_name The name of the OBIDMS.
*
* @since December 2015
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static char* build_obiview_file_name();
/** TODO public
* Internal function creating the file containing basic informations on the OBIDMS.
*
* This file contains:
* - The endianness of the platform
*
* @warning The returned pointer has to be freed by the caller.
*
* @param dms_file_descriptor The file descriptor for the OBIDMS directory.
* @param dms_name The name of the OBIDMS.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since November 2015
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
int create_obiview_file(int dms_file_descriptor);
/************************************************************************
*
* D E F I N I 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
*
************************************************************************/
static char* build_obiview_file_name()
{
char* file_name;
// Build file name
if (asprintf(&file_name, OBIVIEW_FILE_NAME) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nProblem building an obiview file name");
return NULL;
}
return file_name;
}
size_t get_platform_header_size()
{
size_t header_size;
size_t rounded_header_size;
double multiple;
header_size = sizeof(Obiviews_header_t);
multiple = ceil((double) header_size / (double) getpagesize());
rounded_header_size = multiple * getpagesize();
return rounded_header_size;
}
2016-02-29 16:28:34 +01:00
size_t get_platform_views_size(int nb_of_views)
2016-02-18 10:38:51 +01:00
{
size_t obiview_size;
size_t rounded_obiview_size;
double multiple;
obiview_size = sizeof(Obiview_infos_t);
multiple = ceil((double) (obiview_size*nb_of_views) / (double) getpagesize());
rounded_obiview_size = multiple * getpagesize();
return rounded_obiview_size;
}
int create_obiview_file(int dms_file_descriptor)
{
char* file_name;
int obiview_file_descriptor;
size_t header_size;
// size_t view_size;
size_t file_size;
Obiviews_header_p header;
// Create file name
file_name = build_obiview_file_name();
if (file_name == NULL)
return -1;
// Create file
obiview_file_descriptor = openat(dms_file_descriptor, file_name, O_RDWR | O_CREAT | O_EXCL, 0777);
if (obiview_file_descriptor < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError creating an obiview file");
free(file_name);
return -1;
}
free(file_name);
// Truncate file to the right size
header_size = get_platform_header_size();
//view_size = get_platform_views_size(1);
file_size = header_size; // + view_size;
if (ftruncate(obiview_file_descriptor, file_size) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError truncating an obiview file to the right size");
close(obiview_file_descriptor);
return -1;
}
// Map the header
header = mmap(NULL,
header_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
0
);
if (header == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping an obiview file header");
close(obiview_file_descriptor);
return -1;
}
// Initialize the header
header->header_size = header_size;
header->views_size = 0;
header->view_count = 0;
// Unmap the header
if (munmap(header, header_size) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError munmapping an obiview file header");
close(obiview_file_descriptor);
return -1;
}
close(obiview_file_descriptor);
return 0;
}
/**********************************************************************
*
* D E F I N I T I O N O F T H E P U B L I C F U N C T I O N S
*
**********************************************************************/
2016-02-29 17:56:55 +01:00
Obiview_p obi_new_view_nuc_seqs(OBIDMS_p dms, const char* view_name, Obiview_p view_to_clone, index_t* line_selection, const char* comments)
{
Obiview_p view;
if (view_to_clone != NULL)
{ // TODO check that the view to clone is already a NUC_SEQS view (discuss possibility of transforming type of a view)
if (strcmp(view_to_clone->view_type, VIEW_TYPE_NUC_SEQS))
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "Trying to clone a non-NUC SEQS view to create a NUC SEQS view");
return NULL;
}
}
2016-02-29 17:56:55 +01:00
view = obi_new_view(dms, view_name, view_to_clone, line_selection, comments);
if (view== NULL)
return NULL;
strcpy(view->view_type, VIEW_TYPE_NUC_SEQS);
if (view_to_clone == NULL)
{
// Adding sequence column
if (obi_view_add_column(view, NUC_SEQUENCE_COLUMN, -1, OBI_SEQ, 0, 1, NUC_SEQUENCE_COLUMN, NUC_SEQUENCE_AVL, "Nucleotide sequences", true) < 0)
{
obidebug(1, "Error adding an obligatory column in a nucleotide sequences view");
return NULL;
}
// Adding id column
if (obi_view_add_column(view, ID_COLUMN, -1, OBI_STR, 0, 1, ID_COLUMN, ID_AVL, "Ids", true) < 0)
{
obidebug(1, "Error adding an obligatory column in a nucleotide sequences view");
return NULL;
}
// Adding description column
if (obi_view_add_column(view, DESCRIPTION_COLUMN, -1, OBI_STR, 0, 1, DESCRIPTION_COLUMN, DESCRIPTION_AVL, "Descriptions", true) < 0)
{
obidebug(1, "Error adding an obligatory column in a nucleotide sequences view");
return NULL;
}
}
return view;
}
2016-02-29 17:56:55 +01:00
Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_clone, index_t* line_selection, const char* comments)
2016-02-18 10:38:51 +01:00
{
Obiview_p view;
int i;
index_t line_nb;
Obiviews_infos_all_p views_infos;
// Check uniqueness of name TODO but problem if view not written yet has the same name
views_infos = obi_read_views(dms);
if (views_infos != NULL)
{
for (i=0; i<((views_infos->header)->view_count); i++)
{
if (strcmp(((views_infos->view_infos)+i)->name, view_name) == 0) // TODO discuss what to do
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nView name already exists for a previous view");
obi_unmap_read_views(views_infos);
return NULL;
}
}
obi_unmap_read_views(views_infos);
}
2016-02-18 10:38:51 +01:00
view = (Obiview_p) malloc(sizeof(Obiview_t));
if (view == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError allocating memory for a view");
return NULL;
}
// Clone view to clone if there is one
if (view_to_clone != NULL)
{
if (!(view_to_clone->read_only))
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nA view can not be cloned if it is not read-only");
free(view);
return NULL;
}
2016-02-29 17:56:55 +01:00
view->dms = dms;
2016-02-18 10:38:51 +01:00
view->column_count = view_to_clone->column_count;
if ((view_to_clone->line_selection != NULL) && (line_selection == NULL)) // reorder conditions
{
view->line_selection = obi_open_column(dms, ((view_to_clone->line_selection)->header)->name, ((view_to_clone->line_selection)->header)->version);
if (view->line_selection == NULL)
return NULL;
view->line_count = view_to_clone->line_count;
}
else if (line_selection != NULL)
{
view->line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL);
if ((view->line_selection) == NULL)
{
obidebug(1, "\nError creating a column corresponding to a line selection");
return NULL;
}
view->line_count = 0;
i = 0;
for (i=0; line_selection[i] != -1; i++)
{
line_nb = line_selection[i];
if (line_nb > view_to_clone->line_count)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to select a line for a new view that is beyond the line count of the view to clone");
obi_close_column(view->line_selection);
free(view);
return NULL;
}
if (view_to_clone->line_selection != NULL)
line_nb = obi_column_get_index(view_to_clone->line_selection, line_nb);
if (obi_column_set_index(view->line_selection, ((view->line_selection)->header)->lines_used, line_nb) < 0)
{
obi_close_column(view->line_selection);
free(view);
return NULL;
}
// Update view line count
(view->line_count)++;
}
}
else
{
view->line_selection = NULL;
view->line_count = view_to_clone->line_count;
}
for (i=0; i<(view_to_clone->column_count); i++)
{
(view->columns)[i] = obi_open_column(dms, (((view_to_clone->columns)[i])->header)->name, (((view_to_clone->columns)[i])->header)->version);
if ((view->columns)[i] == NULL)
{
obi_close_column(view->line_selection);
free(view);
return NULL;
}
}
strcpy(view->view_type, view_to_clone->view_type);
2016-02-18 10:38:51 +01:00
strcpy(view->created_from, view_to_clone->name);
view->new_line_selection = NULL;
}
// Else, fill empty view structure
else
{
view->dms = dms;
view->column_count = 0;
view->line_count = 0;
view->line_selection = NULL;
view->new_line_selection = NULL;
(view->created_from)[0] = '\0';
(view->view_type)[0] = '\0';
//view->columns = NULL; TODO
2016-02-18 10:38:51 +01:00
}
strcpy(view->name, view_name);
2016-02-29 17:56:55 +01:00
strcpy(view->comments, comments);
2016-02-18 10:38:51 +01:00
view->read_only = 0;
return view;
}
2016-02-29 17:56:55 +01:00
Obiview_p obi_new_view_cloned_from_name(OBIDMS_p dms, const char* view_name, const char* view_to_clone_name, index_t* line_selection, const char* comments)
2016-02-18 10:38:51 +01:00
{
Obiview_p view;
Obiview_p view_to_clone;
view_to_clone = obi_open_view(dms, view_to_clone_name);
if (view_to_clone == NULL)
return NULL;
2016-02-29 17:56:55 +01:00
view = obi_new_view(dms, view_name, view_to_clone, line_selection, comments);
obi_close_view(view_to_clone);
return view;
}
2016-02-29 17:56:55 +01:00
Obiview_p obi_new_view_nuc_seqs_cloned_from_name(OBIDMS_p dms, const char* view_name, const char* view_to_clone_name, index_t* line_selection, const char* comments)
{
Obiview_p view;
Obiview_p view_to_clone;
view_to_clone = obi_open_view(dms, view_to_clone_name);
if (view_to_clone == NULL)
return NULL;
2016-02-29 17:56:55 +01:00
view = obi_new_view_nuc_seqs(dms, view_name, view_to_clone, line_selection, comments);
obi_close_view(view_to_clone);
2016-02-18 10:38:51 +01:00
return view;
}
Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name)
{
Obiview_p view;
bool first_view;
char* view_file_name;
int obiview_file_descriptor;
size_t header_size;
Obiviews_header_p header;
Obiview_infos_p views;
Obiview_infos_p view_infos;
OBIDMS_column_p column;
int i;
int view_number;
// Check if 1st view : view file doesn't exist
first_view = 0;
view_file_name = build_obiview_file_name();
if (view_file_name == NULL)
return NULL;
// Open view file, read header size and map header and views
obiview_file_descriptor = openat(dms->dir_fd, view_file_name, O_RDWR, 0777);
if (obiview_file_descriptor < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError opening an obiview file");
free(view_file_name);
return NULL;
}
free(view_file_name);
// Read the header size
if (read(obiview_file_descriptor, &header_size, sizeof(size_t)) < ((ssize_t) sizeof(size_t)))
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError reading the header size of an obiview file (trying to open a view when there are none?)");
close(obiview_file_descriptor);
return NULL;
}
// Map the header
header = mmap(NULL,
header_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
0
);
if (header == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping an obiview file header");
close(obiview_file_descriptor);
return NULL;
}
// Map the views
views = mmap(NULL,
header->views_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
header_size
);
if (views == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping the views from an obiview file");
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
// Find and open view that should be read with the line selection associated
view_number = -1;
if (view_name == NULL) // If view name is NULL, open the latest view TODO discuss
view_number = (header->view_count) - 1;
else
{
for (i=0; i<(header->view_count); i++)
{
if (!strcmp((views+i)->name, view_name))
{ // Found the view to open
view_number = i;
}
}
}
if (view_number == -1)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError: the view '%s' to open was not found", view_name);
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
view_infos = views + view_number;
view = (Obiview_p) malloc(sizeof(Obiview_t));
if (view == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError allocating memory for a view");
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
if (view_infos->all_lines)
view->line_selection = NULL;
else
{
view->line_selection = obi_open_column(dms, (view_infos->line_selection).column_name, (view_infos->line_selection).version);
if (view->line_selection == NULL)
{
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
}
view->dms = dms;
view->new_line_selection = NULL;
view->read_only = 1;
view->column_count = 0;
view->line_count = view_infos->line_count;
strcpy(view->created_from, view_infos->created_from);
strcpy(view->name, view_infos->name);
strcpy(view->view_type, view_infos->view_type);
2016-02-29 17:56:55 +01:00
strcpy(view->comments, view_infos->comments);
2016-02-18 10:38:51 +01:00
// Open the columns to read
for (i=0; i<(view_infos->column_count); i++)
{
column = obi_open_column(dms, ((view_infos->column_references)+i)->column_name, ((view_infos->column_references)+i)->version);
if (column == NULL)
{
obidebug(1, "\nError opening a column for a view: column %d: %s, version %d", i, ((view_infos->column_references)+i)->column_name, ((view_infos->column_references)+i)->version);
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
// Store column in the view
(view->columns)[view->column_count] = column;
view->column_count++;
}
// Munmap and close things TODO
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return view;
}
Obiviews_infos_all_p obi_read_views(OBIDMS_p dms)
{
char* view_file_name;
int obiview_file_descriptor;
size_t header_size;
Obiviews_header_p header;
Obiview_infos_p view_infos;
Obiviews_infos_all_p views;
view_file_name = build_obiview_file_name();
if (view_file_name == NULL)
return NULL;
// Open view file, read header size and map header and views
obiview_file_descriptor = openat(dms->dir_fd, view_file_name, O_RDWR, 0777);
if (obiview_file_descriptor < 0)
{ // No views yet
free(view_file_name);
return NULL;
}
free(view_file_name);
// Read the header size
if (read(obiview_file_descriptor, &header_size, sizeof(size_t)) < ((ssize_t) sizeof(size_t)))
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError reading the header size of an obiview file (trying to open a view when there are none?)");
close(obiview_file_descriptor);
return NULL;
}
// Map the header
header = mmap(NULL,
header_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
0
);
if (header == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping an obiview file header");
close(obiview_file_descriptor);
return NULL;
}
// Map the views
view_infos = mmap(NULL,
header->views_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
header_size
);
if (view_infos == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping the views from an obiview file");
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
views = (Obiviews_infos_all_p) malloc(sizeof(Obiviews_infos_all_t));
if (views == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping the views from an obiview file");
munmap(view_infos, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return NULL;
}
views->header = header;
views->view_infos = view_infos;
close(obiview_file_descriptor);
return views;
}
int obi_unmap_read_views(Obiviews_infos_all_p views)
{
if (munmap(views->view_infos, (views->header)->views_size) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError unmapping the views of an obiview file");
free(views);
return -1;
}
if (munmap(views->header, (views->header)->header_size) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError unmapping the header of an obiview file");
free(views);
return -1;
}
free(views);
return 0;
}
2016-02-18 10:38:51 +01:00
int obi_view_add_column(Obiview_p view,
const char* column_name,
obiversion_t version_number,
OBIType_t data_type,
index_t nb_lines,
index_t nb_elements_per_line,
const char* elements_names,
const char* avl_name,
const char* comments,
bool create) // all infos for creation or open
{
OBIDMS_column_p column;
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to add a column in a read-only view");
return -1;
}
if (view->line_count > nb_lines)
nb_lines = view->line_count;
else if (nb_lines > view->line_count)
obi_view_update_lines(view, nb_lines);
// Open or create the column
if (create)
{ // Create column
column = obi_create_column(view->dms, column_name, data_type, nb_lines, nb_elements_per_line, elements_names, avl_name, comments);
}
else
{ // Open column
column = obi_open_column(view->dms, column_name, version_number);
}
if (column == NULL)
{
obidebug(1, "\nError creating or opening a column to add to a view");
return -1;
}
// Store column in the view
(view->columns)[view->column_count] = column;
view->column_count++;
if (view->column_count == 1) // first column in the view
view->line_count = (column->header)->lines_used;
return 0;
}
OBIDMS_column_p obi_view_clone_column(Obiview_p view, const char* column_name)
{
int i;
OBIDMS_column_p current_line_selection = NULL;
OBIDMS_column_p column;
OBIDMS_column_p column_buffer;
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to delete a column in a read-only view");
return NULL;
}
if (view->new_line_selection != NULL) // TODO Probably shouldn't happen
current_line_selection = view->new_line_selection;
else
current_line_selection = view->line_selection;
for (i=0; i<(view->column_count); i++)
{
if ((current_line_selection != NULL) || (!(strcmp((((view->columns)[i])->header)->name, column_name))))
{ // Clone with the right line selection and replace
column_buffer = (view->columns)[i];
(view->columns)[i] = obi_clone_column(view->dms, current_line_selection, (((view->columns)[i])->header)->name, (((view->columns)[i])->header)->version, 1);
if ((view->columns)[i] == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError cloning a column to replace in a view");
return NULL;
}
// Found the column to return
if (!(strcmp((((view->columns)[i])->header)->name, column_name)))
column = (view->columns)[i];
else
obi_truncate_and_close_column(column_buffer); // TODO weird closing after cloning but can't think of cleaner yet
}
}
if (view->line_selection != NULL)
{
obi_truncate_and_close_column(view->line_selection);
view->line_selection = NULL;
}
if (view->new_line_selection != NULL)
{
obi_truncate_and_close_column(view->new_line_selection);
view->new_line_selection = NULL;
}
return column;
}
int obi_view_delete_column(Obiview_p view, const char* column_name)
{
int i;
bool found;
// TODO check that not deleting an obligatory column?
2016-02-18 10:38:51 +01:00
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to delete a column in a read-only view");
return -1;
}
found = 0;
for (i=0; i<(view->column_count); i++)
{
if (!strcmp((((view->columns)[i])->header)->name, column_name))
{
obi_truncate_and_close_column((view->columns)[i]);
found = 1;
}
if (found)
{
if (i != ((view->column_count) - 1)) // not the last one
(view->columns)[i] = (view->columns)[i+1];
else // Last column
(view->columns)[i] = NULL;
}
}
if (!found)
return -1;
(view->column_count)--;
return 0;
}
int obi_select_line(Obiview_p view, index_t line_nb)
{
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to select a line in a read-only view");
return -1;
}
// If column for line selection doesn't already exists, create it and store its informations
if ((view->new_line_selection) == NULL)
{
view->new_line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL);
if ((view->new_line_selection) == NULL)
{
obidebug(1, "\nError creating a column corresponding to a line selection");
return -1;
}
}
// If we are already working on a line selection, get the pointed line number
if (view->line_selection)
line_nb = obi_column_get_index(view->line_selection, line_nb);
if (obi_column_set_index(view->new_line_selection, ((view->new_line_selection)->header)->lines_used, line_nb) < 0)
return -1;
return 0;
}
int obi_select_lines(Obiview_p view, index_t* line_nbs)
{
int i;
index_t line_nb;
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to select a line in a read-only view");
return -1;
}
// If column for line selection doesn't already exists, create it and store its informations
if ((view->new_line_selection) == NULL)
{
view->new_line_selection = obi_create_column(view->dms, LINES_COLUMN_NAME, OBI_IDX, 0, 1, LINES_COLUMN_NAME, NULL, NULL);
if ((view->new_line_selection) == NULL)
{
obidebug(1, "\nError creating a column corresponding to a line selection");
return -1;
}
}
for (i=0; line_nbs[i] != -1; i++)
{
line_nb = line_nbs[i];
// If we are already working on a line selection, get the pointed line number
if (view->line_selection)
line_nb = obi_column_get_index(view->line_selection, line_nb);
if (obi_column_set_index(view->new_line_selection, ((view->new_line_selection)->header)->lines_used, line_nb) < 0)
return -1;
}
return 0;
}
int obi_view_update_lines(Obiview_p view, index_t line_count)
{
int i;
for (i=0; i<(view->column_count); i++)
{
while (line_count > (((view->columns)[i])->header)->line_count)
{
// Enlarge the column
if (obi_enlarge_column((view->columns)[i]) < 0)
return -1;
}
}
view->line_count = line_count;
return 0;
}
OBIDMS_column_p obi_view_get_column(Obiview_p view, const char* column_name)
{
int i;
for (i=0; i<(view->column_count); i++)
{
if (!(strcmp((((view->columns)[i])->header)->name, column_name)))
return (view->columns)[i];
}
return NULL;
}
OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const char* column_name)
{
int i;
for (i=0; i<(view->column_count); i++)
{
if (!(strcmp((((view->columns)[i])->header)->name, column_name)))
return ((view->columns)+i);
}
return NULL;
}
int obi_save_view(Obiview_p view)
{
int i;
struct stat buffer;
char* view_file_name;
char* full_path;
int check_file;
int obiview_file_descriptor;
size_t header_size;
size_t views_size;
size_t file_size;
Obiviews_header_p header;
Obiview_infos_p views;
Obiview_infos_p view_infos;
OBIDMS_column_p current_line_selection;
// 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;
}
view_file_name = build_obiview_file_name();
if (view_file_name == NULL)
return -1;
// Get the full path for the column directory
full_path = get_full_path((view->dms)->dir_fd, view_file_name);
if (full_path == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting the full path of an obiview file");
free(view_file_name);
return -1;
}
check_file = stat(full_path, &buffer);
if (check_file < 0)
{ // 1st view: create view file
if (create_obiview_file((view->dms)->dir_fd) < 0)
return -1;
}
// Open view file, read header size and map header and views
obiview_file_descriptor = openat((view->dms)->dir_fd, view_file_name, O_RDWR, 0777);
if (obiview_file_descriptor < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError opening an obiview file");
free(view_file_name);
return -1;
}
free(view_file_name);
// Read the header size
if (read(obiview_file_descriptor, &header_size, sizeof(size_t)) < ((ssize_t) sizeof(size_t)))
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError reading the header size of an obiview file");
close(obiview_file_descriptor);
return -1;
}
// Map the header
header = mmap(NULL,
header_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
0
);
if (header == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping an obiview file header");
close(obiview_file_descriptor);
return -1;
}
// Truncate file to the right size to add a new view // TODO lock for multithreading
views_size = get_platform_views_size((header->view_count)+1);
file_size = header_size + views_size;
if (ftruncate(obiview_file_descriptor, file_size) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError truncating an obiview file to the right size");
munmap(header, header_size);
close(obiview_file_descriptor);
return -1;
}
header->views_size = views_size;
// Map the views
views = mmap(NULL,
header->views_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
obiview_file_descriptor,
header_size
);
if (views == MAP_FAILED)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError mmapping the views from an obiview file");
munmap(header, header_size);
close(obiview_file_descriptor);
return -1;
}
// Write view infos
view_infos = views + (header->view_count);
view_infos->view_number = (header->view_count);
view_infos->column_count = view->column_count;
view_infos->creation_date = time(NULL);
strcpy(view_infos->created_from, view->created_from);
strcpy(view_infos->name, view->name);
strcpy(view_infos->view_type, view->view_type);
2016-02-29 17:56:55 +01:00
strcpy(view_infos->comments, view->comments);
2016-02-18 10:38:51 +01:00
// Store reference for the line selection associated with that view
if (view->new_line_selection != NULL)
{
view_infos->line_count = ((view->new_line_selection)->header)->lines_used;
current_line_selection = view->new_line_selection;
}
else
{
view_infos->line_count = view->line_count;
current_line_selection = view->line_selection;
}
if (current_line_selection != NULL)
{
view_infos->all_lines = 0;
strcpy((view_infos->line_selection).column_name, (current_line_selection->header)->name);
(view_infos->line_selection).version = (current_line_selection->header)->version;
}
else
{
view_infos->all_lines = 1;
((view_infos->line_selection).column_name)[0] = '\0';
(view_infos->line_selection).version = -1;
}
for (i=0; i<view->column_count; i++)
{
strcpy(((view_infos->column_references)+i)->column_name, (((view->columns)[i])->header)->name);
((view_infos->column_references)+i)->version = (((view->columns)[i])->header)->version;
}
// Increment view count
(header->view_count)++;
// Unmap and close file
munmap(views, header->views_size);
munmap(header, header_size);
close(obiview_file_descriptor);
return 0;
}
int obi_close_view(Obiview_p view)
{
int i;
for (i=0; i < (view->column_count); i++)
{
obi_close_column((view->columns)[i]);
}
free(view);
return 0;
}
int obi_save_and_close_view(Obiview_p view)
{
if (!(view->read_only)) // TODO discuss
{
if (obi_save_view(view) < 0)
return -1;
}
if (obi_close_view(view) < 0)
return -1;
return 0;
}