2015-05-22 17:54:34 +02:00
/****************************************************************************
2015-09-30 12:03:46 +02:00
* OBIDMS columns functions *
2015-05-22 17:54:34 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
2015-07-31 18:03:48 +02:00
* @ file obidmscolumn . c
2015-09-30 12:03:46 +02:00
* @ author Celine Mercier ( celine . mercier @ metabarcoding . org )
2015-05-22 17:54:34 +02:00
* @ date 22 May 2015
2015-09-30 12:03:46 +02:00
* @ brief Functions shared by all the OBIDMS columns .
2015-05-22 17:54:34 +02:00
*/
# include <stdlib.h>
2015-06-17 16:51:16 +02:00
# include <stdio.h>
2015-07-31 18:03:48 +02:00
# include <string.h>
2015-06-17 16:51:16 +02:00
# include <sys/types.h>
2015-06-23 18:35:34 +02:00
# include <dirent.h>
2015-06-17 16:51:16 +02:00
# include <unistd.h>
2015-11-03 14:22:00 +01:00
# include <time.h>
2015-05-26 10:38:56 +02:00
# include <fcntl.h>
2015-06-23 18:35:34 +02:00
# include <stdbool.h>
2015-09-21 15:42:29 +02:00
# include <math.h>
2015-09-30 12:03:46 +02:00
# include <sys/mman.h>
2015-05-22 17:54:34 +02:00
2015-06-17 16:51:16 +02:00
# include "obidmscolumn.h"
2015-06-26 17:53:03 +02:00
# include "obidmscolumndir.h"
2015-06-17 16:51:16 +02:00
# include "obidms.h"
# include "obitypes.h"
# include "obierrno.h"
2015-06-26 17:53:03 +02:00
# include "obidebug.h"
2015-06-17 16:51:16 +02:00
# include "obilittlebigman.h"
2015-11-03 14:22:00 +01:00
# include "obiarray.h"
2015-07-20 11:38:43 +02:00
2015-07-31 18:03:48 +02:00
2015-09-30 12:03:46 +02:00
# define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?)
2015-07-31 18:03:48 +02:00
2015-05-22 17:54:34 +02:00
2015-06-23 18:35:34 +02:00
/**************************************************************************
2015-05-26 10:38:56 +02:00
*
2015-06-10 15:19:02 +02:00
* 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
2015-05-26 10:38:56 +02:00
*
2015-06-23 18:35:34 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-05-26 10:38:56 +02:00
/**
* @ brief Internal function building the file name for a column .
*
2015-06-10 15:19:02 +02:00
* The function builds the file name corresponding to a column of an OBIDMS .
2015-05-26 10:38:56 +02:00
*
* @ warning The returned pointer has to be freed by the caller .
*
2015-09-30 12:03:46 +02:00
* @ param column_name The name of the OBIDMS column file .
* @ param version_number The version number of the OBIDMS column file .
2015-05-26 10:38:56 +02:00
*
2015-09-30 12:03:46 +02:00
* @ returns A pointer to the column file name .
* @ retval NULL if an error occurred .
2015-05-26 10:38:56 +02:00
*
* @ since May 2015
* @ author Eric Coissac ( eric . coissac @ metabarcoding . org )
*/
2015-09-30 12:03:46 +02:00
static char * build_column_file_name ( const char * column_name , obiversion_t version_number ) ;
2015-06-10 15:19:02 +02:00
2015-05-26 10:38:56 +02:00
/**
2015-06-17 16:51:16 +02:00
* @ brief Internal function building the file name for a column version file .
2015-05-26 10:38:56 +02:00
*
2015-06-17 16:51:16 +02:00
* The column version file indicates the latest version number for a column .
* This function returns the name of the file storing this information .
2015-05-26 10:38:56 +02:00
*
* @ warning The returned pointer has to be freed by the caller .
*
2015-09-30 12:03:46 +02:00
* @ param column_name The name of the OBIDMS column .
2015-05-26 10:38:56 +02:00
*
2015-09-30 12:03:46 +02:00
* @ returns A pointer to the version file name .
* @ retval NULL if an error occurred .
2015-05-26 10:38:56 +02:00
*
* @ since May 2015
* @ author Eric Coissac ( eric . coissac @ metabarcoding . org )
*/
2015-09-30 12:03:46 +02:00
static char * build_version_file_name ( const char * column_name ) ;
2015-05-26 10:38:56 +02:00
2015-06-10 15:19:02 +02:00
2015-05-26 10:38:56 +02:00
/**
* @ brief Internal function returning a new column version number
2015-09-30 12:03:46 +02:00
* in the OBIDMS database .
2015-05-26 10:38:56 +02:00
*
2015-09-30 12:03:46 +02:00
* @ param column_directory A pointer as returned by obi_create_column_directory ( ) or obi_open_column_directory ( ) .
* @ param block Whether the call is blocking or not :
* - ` true ` the call is blocking
* - ` false ` the call is not blocking .
2015-05-26 10:38:56 +02:00
*
2015-09-30 12:03:46 +02:00
* @ returns The next version number for this column .
* @ retval - 1 if an error occurred .
2015-05-26 10:38:56 +02:00
*
* @ since May 2015
* @ author Eric Coissac ( eric . coissac @ metabarcoding . org )
*/
2015-06-26 17:53:03 +02:00
static obiversion_t obi_get_new_version_number ( OBIDMS_column_directory_p column_directory , bool block ) ;
2015-05-26 10:38:56 +02:00
2015-06-10 15:19:02 +02:00
2015-05-26 10:38:56 +02:00
/**
* @ brief Internal function creating a new column version file
2015-09-30 12:03:46 +02:00
* in the OBIDMS database .
2015-05-26 10:38:56 +02:00
*
* The new file is initialized with the minimum version number ` 0 ` .
*
2015-09-30 12:03:46 +02:00
* @ param column_directory A pointer as returned by obi_create_column_directory ( ) or obi_open_column_directory ( ) .
2015-05-26 10:38:56 +02:00
*
2015-09-30 12:03:46 +02:00
* @ returns The next usable version number for this column : ` 0 ` .
* @ retval - 1 if an error occurred .
2015-05-26 10:38:56 +02:00
*
* @ since May 2015
* @ author Eric Coissac ( eric . coissac @ metabarcoding . org )
*/
2015-09-30 12:03:46 +02:00
static obiversion_t create_version_file ( OBIDMS_column_directory_p column_directory ) ;
2015-05-26 10:38:56 +02:00
2015-06-10 15:19:02 +02:00
2015-07-31 18:03:48 +02:00
/**
* @ brief Internal function setting the elements names of the lines of a
2015-09-30 12:03:46 +02:00
* column in the header of the OBIDMS column structure .
2015-07-31 18:03:48 +02:00
*
2015-09-30 12:03:46 +02:00
* @ param column A pointer as returned by obi_create_column ( ) .
* @ param elements_names The names of the elements with ' ; ' as separator .
2015-07-31 18:03:48 +02:00
*
2015-09-30 12:03:46 +02:00
* @ retval 0 if the operation was successfully completed .
* @ retval - 1 if an error occurred .
2015-07-31 18:03:48 +02:00
*
* @ since July 2015
* @ author Celine Mercier ( celine . mercier @ metabarcoding . org )
*/
2015-09-30 12:03:46 +02:00
static int obi_column_set_elements_names ( OBIDMS_column_p column , const char * elements_names ) ;
2015-07-31 18:03:48 +02:00
2015-09-21 15:42:29 +02:00
/**
2015-09-30 12:03:46 +02:00
* @ brief Internal function computing how many lines of an OBIDMS column
* fit in a memory page .
2015-09-21 15:42:29 +02:00
*
2015-09-30 12:03:46 +02:00
* @ param data_type The data OBIType .
* @ param nb_elements_per_line The number of elements per line .
2015-09-21 15:42:29 +02:00
*
2015-09-30 12:03:46 +02:00
* @ returns The line count for one memory page .
2015-09-21 15:42:29 +02:00
*
* @ since September 2015
* @ author Celine Mercier ( celine . mercier @ metabarcoding . org )
*/
2015-11-06 17:55:15 +01:00
static index_t get_line_count_per_page ( OBIType_t data_type , index_t nb_elements_per_line ) ;
2015-09-21 15:42:29 +02:00
2015-06-10 15:19:02 +02:00
/************************************************************************
2015-05-26 10:38:56 +02:00
*
2015-06-10 15:19:02 +02:00
* 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
2015-05-26 10:38:56 +02:00
*
2015-06-10 15:19:02 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-05-26 10:38:56 +02:00
2015-06-26 17:53:03 +02:00
2015-11-03 14:22:00 +01:00
static char * build_column_file_name ( const char * column_name , obiversion_t version_number )
2015-06-17 16:51:16 +02:00
{
2015-11-03 14:22:00 +01:00
char * file_name ;
2015-05-26 10:38:56 +02:00
2015-11-03 14:22:00 +01:00
// Build the file name
if ( asprintf ( & file_name , " %s@%d.odc " , column_name , version_number ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_MEMORY_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error building a column file name " ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-11-03 14:22:00 +01:00
return file_name ;
2015-05-26 10:38:56 +02:00
}
2015-11-03 14:22:00 +01:00
static char * build_version_file_name ( const char * column_name )
2015-06-17 16:51:16 +02:00
{
2015-11-03 14:22:00 +01:00
char * file_name ;
2015-05-26 10:38:56 +02:00
2015-11-03 14:22:00 +01:00
// Build the file name
if ( asprintf ( & file_name , " %s.odv " , column_name ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_MEMORY_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error building a version file name " ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-11-03 14:22:00 +01:00
return file_name ;
2015-05-26 10:38:56 +02:00
}
2015-06-10 15:19:02 +02:00
2015-06-26 17:53:03 +02:00
static obiversion_t obi_get_new_version_number ( OBIDMS_column_directory_p column_directory , bool block )
2015-06-17 16:51:16 +02:00
{
off_t loc_size ;
obiversion_t new_version_number ;
char * version_file_name ;
int version_file_descriptor ;
int lock_mode ;
2015-05-26 10:38:56 +02:00
2015-06-17 16:51:16 +02:00
new_version_number = 0 ;
2015-11-09 17:50:32 +01:00
loc_size = sizeof ( obiversion_t ) ;
2015-05-26 10:38:56 +02:00
// Select the correct lockf operation according to the blocking mode
if ( block )
2015-06-17 16:51:16 +02:00
lock_mode = F_LOCK ;
2015-05-26 10:38:56 +02:00
else
2015-06-17 16:51:16 +02:00
lock_mode = F_TLOCK ;
2015-05-26 10:38:56 +02:00
2015-06-23 18:35:34 +02:00
// Build the version file name
2015-06-26 17:53:03 +02:00
version_file_name = build_version_file_name ( column_directory - > column_name ) ;
2015-06-17 16:51:16 +02:00
if ( version_file_name = = NULL )
2015-05-26 10:38:56 +02:00
return - 1 ;
2015-06-23 18:35:34 +02:00
// Open the version file
2015-11-09 15:06:02 +01:00
version_file_descriptor = openat ( column_directory - > dir_fd , version_file_name , O_RDWR ) ;
2015-06-17 16:51:16 +02:00
if ( version_file_descriptor < 0 )
{
2015-05-26 10:38:56 +02:00
if ( errno = = ENOENT )
2015-06-26 17:53:03 +02:00
return create_version_file ( column_directory ) ;
2015-05-26 10:38:56 +02:00
else
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-09-30 12:03:46 +02:00
obidebug ( 1 , " \n Error opening a version file " ) ;
free ( version_file_name ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
}
2015-11-09 11:22:51 +01:00
free ( version_file_name ) ;
2015-05-26 10:38:56 +02:00
// Test if the version file size is ok
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_END ) < loc_size )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error testing if a version file size is ok " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Prepare the file for locking
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_SET ) ! = 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error preparing a version file for locking " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
// Lock the file
2015-06-23 18:35:34 +02:00
if ( lockf ( version_file_descriptor , lock_mode , loc_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error locking a version file " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Read the current version number
2015-06-17 16:51:16 +02:00
if ( read ( version_file_descriptor , & new_version_number , sizeof ( obiversion_t ) ) < sizeof ( obiversion_t ) )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error reading a version file " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-17 16:51:16 +02:00
new_version_number + + ;
2015-05-26 10:38:56 +02:00
2015-06-23 18:35:34 +02:00
// Write the new version number
2015-06-17 16:51:16 +02:00
if ( write ( version_file_descriptor , & new_version_number , sizeof ( obiversion_t ) ) < sizeof ( obiversion_t ) )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error writing a new version number in a version file " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Prepare for unlocking
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_SET ) ! = 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error preparing the unlocking of a version file " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Unlock the file
if ( lockf ( version_file_descriptor , F_ULOCK , loc_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error unlocking a version file " ) ;
2015-06-17 16:51:16 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-24 13:53:12 +02:00
close ( version_file_descriptor ) ;
2015-06-23 18:35:34 +02:00
2015-06-17 16:51:16 +02:00
return new_version_number ;
2015-05-26 10:38:56 +02:00
}
2015-06-10 15:19:02 +02:00
2015-09-30 12:03:46 +02:00
static obiversion_t create_version_file ( OBIDMS_column_directory_p column_directory )
2015-06-17 16:51:16 +02:00
{
off_t loc_size ;
obiversion_t version_number ;
char * version_file_name ;
int version_file_descriptor ;
2015-05-26 10:38:56 +02:00
2015-11-09 17:50:32 +01:00
loc_size = sizeof ( obiversion_t ) ;
2015-06-17 16:51:16 +02:00
version_number = 0 ;
2015-05-26 10:38:56 +02:00
2015-06-26 17:53:03 +02:00
version_file_name = build_version_file_name ( column_directory - > column_name ) ;
2015-06-17 16:51:16 +02:00
if ( version_file_name = = NULL )
2015-05-26 10:38:56 +02:00
return - 1 ;
2015-06-23 18:35:34 +02:00
// Get the file descriptor associated to the version file
2015-11-09 15:22:01 +01:00
version_file_descriptor = openat ( column_directory - > dir_fd , version_file_name , O_RDWR | O_CREAT | O_EXCL , 0777 ) ;
2015-06-17 16:51:16 +02:00
if ( version_file_descriptor < 0 )
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening a version file " ) ;
2015-06-17 16:51:16 +02:00
free ( version_file_name ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-11-09 11:22:51 +01:00
free ( version_file_name ) ;
2015-05-26 10:38:56 +02:00
// Lock the file
2015-06-23 18:35:34 +02:00
if ( lockf ( version_file_descriptor , F_LOCK , loc_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error locking a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Truncate the version file to the right size
2015-06-17 16:51:16 +02:00
if ( ftruncate ( version_file_descriptor , loc_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error truncating a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Position offset to 0 to prepare for writing
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_SET ) ! = 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error changing offset of a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Write version number
2015-06-17 16:51:16 +02:00
if ( write ( version_file_descriptor , & version_number , sizeof ( obiversion_t ) ) < sizeof ( obiversion_t ) )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error writing version number in a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Prepare for unlocking
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_SET ) ! = 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error preparing a version file for unlocking " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Unlock the file
if ( lockf ( version_file_descriptor , F_ULOCK , loc_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error unlocking a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-24 13:53:12 +02:00
close ( version_file_descriptor ) ;
2015-06-23 18:35:34 +02:00
2015-06-17 16:51:16 +02:00
return version_number ;
2015-05-26 10:38:56 +02:00
}
2015-06-10 15:19:02 +02:00
2015-07-31 18:03:48 +02:00
int obi_column_set_elements_names ( OBIDMS_column_p column , const char * elements_names )
{
strcpy ( ( column - > header ) - > elements_names , elements_names ) ;
return 0 ;
}
2015-11-06 17:55:15 +01:00
index_t get_line_count_per_page ( OBIType_t data_type , index_t nb_elements_per_line )
2015-09-21 15:42:29 +02:00
{
return getpagesize ( ) / ( obi_sizeof ( data_type ) * nb_elements_per_line ) ;
}
2015-07-31 18:03:48 +02:00
2015-06-17 16:51:16 +02:00
/**********************************************************************
2015-05-26 10:38:56 +02:00
*
2015-06-17 16:51:16 +02:00
* 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
2015-05-26 10:38:56 +02:00
*
2015-06-17 16:51:16 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-06-26 17:53:03 +02:00
obiversion_t obi_get_latest_version_number ( OBIDMS_column_directory_p column_directory )
2015-06-17 16:51:16 +02:00
{
off_t loc_size ;
obiversion_t latest_version_number ;
char * version_file_name ;
int version_file_descriptor ;
2015-11-09 17:50:32 +01:00
loc_size = sizeof ( obiversion_t ) ;
2015-06-17 16:51:16 +02:00
latest_version_number = 0 ;
2015-06-26 17:53:03 +02:00
version_file_name = build_version_file_name ( column_directory - > column_name ) ;
2015-06-17 16:51:16 +02:00
if ( version_file_name = = NULL )
2015-05-26 10:38:56 +02:00
return - 1 ;
2015-06-23 18:35:34 +02:00
// Get the file descriptor associated to the version file
2015-11-09 15:06:02 +01:00
version_file_descriptor = openat ( column_directory - > dir_fd , version_file_name , O_RDONLY ) ;
2015-06-23 18:35:34 +02:00
if ( version_file_descriptor < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening a version file " ) ;
2015-06-17 16:51:16 +02:00
free ( version_file_name ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-11-09 11:22:51 +01:00
free ( version_file_name ) ;
2015-06-23 18:35:34 +02:00
// Check that the version file size is ok
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_END ) < loc_size )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error testing if a version file size is ok " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Set the offset to 0 in the version file
2015-06-17 16:51:16 +02:00
if ( lseek ( version_file_descriptor , 0 , SEEK_SET ) ! = 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error setting the offset of a version file to 0 " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-23 18:35:34 +02:00
// Read the latest version number
2015-06-17 16:51:16 +02:00
if ( read ( version_file_descriptor , & latest_version_number , sizeof ( obiversion_t ) ) < sizeof ( obiversion_t ) )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error reading the latest version number in a version file " ) ;
2015-06-23 18:35:34 +02:00
close ( version_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return - 1 ;
}
2015-06-24 13:53:12 +02:00
close ( version_file_descriptor ) ;
2015-06-23 18:35:34 +02:00
2015-06-17 16:51:16 +02:00
return latest_version_number ;
2015-05-26 10:38:56 +02:00
}
2015-06-10 15:19:02 +02:00
2015-07-31 18:03:48 +02:00
obiversion_t obi_column_get_latest_version_from_name ( OBIDMS_p dms , const char * column_name )
{
OBIDMS_column_directory_p column_directory ;
obiversion_t latest_version ;
// Get the column directory structure associated to the column
column_directory = obi_open_column_directory ( dms , column_name ) ;
if ( column_directory = = NULL )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Problem opening a column directory structure " ) ;
2015-07-31 18:03:48 +02:00
return - 1 ;
}
// Get the latest version number
latest_version = obi_get_latest_version_number ( column_directory ) ;
if ( latest_version < 0 )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Problem getting the latest version number in a column directory " ) ;
2015-07-31 18:03:48 +02:00
return - 1 ;
}
return latest_version ;
}
2015-05-26 10:38:56 +02:00
size_t obi_get_platform_header_size ( )
{
2015-11-10 13:09:30 +01:00
size_t header_size ;
size_t rounded_header_size ;
double multiple ;
header_size = sizeof ( OBIDMS_column_header_t ) ;
multiple = ceil ( ( double ) header_size / ( double ) getpagesize ( ) ) ;
rounded_header_size = multiple * getpagesize ( ) ;
return rounded_header_size ;
2015-05-26 10:38:56 +02:00
}
2015-11-09 15:55:00 +01:00
OBIDMS_column_p obi_create_column ( OBIDMS_p dms ,
2015-09-28 13:52:41 +02:00
const char * column_name ,
2015-11-09 15:55:00 +01:00
OBIType_t data_type ,
index_t nb_lines ,
index_t nb_elements_per_line ,
2015-11-03 14:22:00 +01:00
const char * elements_names ,
2015-11-10 10:56:45 +01:00
const char * array_name ,
const char * comments )
2015-05-26 10:38:56 +02:00
{
2015-10-08 10:36:02 +02:00
OBIDMS_column_p new_column ;
2015-06-26 17:53:03 +02:00
OBIDMS_column_directory_p column_directory ;
2015-10-08 10:36:02 +02:00
OBIDMS_column_header_p header ;
2015-11-03 14:22:00 +01:00
OBIDMS_array_p array ;
2015-10-08 10:36:02 +02:00
size_t file_size ;
obiversion_t version_number ;
char * column_file_name ;
int column_file_descriptor ;
size_t header_size ;
size_t data_size ;
2015-11-06 17:55:15 +01:00
index_t minimum_line_count ;
2015-06-17 16:51:16 +02:00
new_column = NULL ;
2015-09-14 17:04:29 +02:00
// Check that the informations given are not NULL/invalid/greater than the allowed sizes
if ( dms = = NULL )
{
obidebug ( 1 , " \n Can't create column because of invalid DMS " ) ;
return NULL ;
}
if ( column_name = = NULL )
{
obidebug ( 1 , " \n Can't create column because of empty column name " ) ;
return NULL ;
}
2015-11-03 14:22:00 +01:00
if ( ( data_type < 1 ) | | ( data_type > 5 ) )
2015-09-21 15:42:29 +02:00
{
obidebug ( 1 , " \n Can't create column because of invalid data type " ) ;
return NULL ;
}
2015-11-03 14:22:00 +01:00
if ( ( data_type = = 5 ) & & ( array_name = = NULL ) )
{
obidebug ( 1 , " \n Can't create column because of empty array name " ) ;
return NULL ;
}
2015-09-21 15:42:29 +02:00
// The initial line count should be between the minimum (corresponding to the page size) and the maximum allowed
2015-09-28 13:52:41 +02:00
minimum_line_count = get_line_count_per_page ( data_type , nb_elements_per_line ) ;
2015-09-21 15:42:29 +02:00
if ( nb_lines > MAXIMUM_LINE_COUNT )
{
2015-11-03 14:22:00 +01:00
obidebug ( 1 , " \n Can't create column because of line count greater than the maximum allowed (%d) " , MAXIMUM_LINE_COUNT ) ;
2015-09-21 15:42:29 +02:00
return NULL ;
}
else if ( nb_lines < minimum_line_count )
nb_lines = minimum_line_count ;
// The number of elements names should be equal to the number of elements per line
if ( ( elements_names = = NULL ) & & ( nb_elements_per_line > 1 ) )
{
obidebug ( 1 , " \n Can't create column because no elements names were given for a number of elements per line greater than 1 " ) ;
return NULL ;
}
else if ( ( elements_names ! = NULL ) & & ( nb_elements_per_line > 1 ) )
{
char * token ;
2015-11-06 17:55:15 +01:00
index_t n = 0 ;
2015-09-21 15:42:29 +02:00
token = strdup ( elements_names ) ;
token = strtok ( token , " ; " ) ;
while ( token ! = NULL )
{
token = strtok ( NULL , " ; " ) ;
n + + ;
}
if ( n ! = nb_elements_per_line )
{
obidebug ( 1 , " \n Can't create column because the number of elements names given is not equal to the number of elements per line " ) ;
return NULL ;
}
}
else if ( ( nb_elements_per_line = = 1 ) & & ( strcmp ( elements_names , column_name ) ! = 0 ) )
{
obidebug ( 1 , " \n Can't create column because the element name does not match the column name " ) ;
return NULL ;
}
2015-07-31 18:03:48 +02:00
2015-06-26 17:53:03 +02:00
// Get the column directory structure associated to the column
column_directory = obi_column_directory ( dms , column_name ) ;
if ( column_directory = = NULL )
2015-08-03 15:10:39 +02:00
{
obi_set_errno ( OBICOLDIR_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error opening a column directory structure " ) ;
2015-06-23 18:35:34 +02:00
return NULL ;
2015-08-03 15:10:39 +02:00
}
2015-06-23 18:35:34 +02:00
// Calculate the size needed
2015-06-17 16:51:16 +02:00
header_size = obi_get_platform_header_size ( ) ;
2015-09-28 13:52:41 +02:00
data_size = obi_array_sizeof ( data_type , nb_lines , nb_elements_per_line ) ;
2015-06-17 16:51:16 +02:00
file_size = header_size + data_size ;
2015-05-26 10:38:56 +02:00
2015-06-23 18:35:34 +02:00
// Get the latest version number
2015-06-26 17:53:03 +02:00
version_number = obi_get_new_version_number ( column_directory , true ) ;
2015-06-17 16:51:16 +02:00
if ( version_number < 0 )
2015-05-26 10:38:56 +02:00
{
return NULL ;
}
2015-06-23 18:35:34 +02:00
// Get the column file name
2015-06-17 16:51:16 +02:00
column_file_name = build_column_file_name ( column_name , version_number ) ;
2015-06-23 18:35:34 +02:00
if ( column_file_name = = NULL )
{
return NULL ;
}
2015-06-10 15:19:02 +02:00
2015-06-23 18:35:34 +02:00
// Open the column file
2015-11-09 15:22:01 +01:00
column_file_descriptor = openat ( column_directory - > dir_fd , column_file_name , O_RDWR | O_CREAT | O_EXCL , 0777 ) ;
2015-06-23 18:35:34 +02:00
if ( column_file_descriptor < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-09-30 12:03:46 +02:00
obidebug ( 1 , " \n Error opening a column file " ) ;
2015-06-23 18:35:34 +02:00
free ( column_file_name ) ;
return NULL ;
}
2015-05-26 10:38:56 +02:00
2015-11-09 11:22:51 +01:00
free ( column_file_name ) ;
2015-06-23 18:35:34 +02:00
// Truncate the column file to the right size
2015-06-17 16:51:16 +02:00
if ( ftruncate ( column_file_descriptor , file_size ) < 0 )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error truncating a column file to the right size " ) ;
2015-06-17 16:51:16 +02:00
close ( column_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-06-23 18:35:34 +02:00
// Allocate the memory for the column structure
2015-06-17 16:51:16 +02:00
new_column = ( OBIDMS_column_p ) malloc ( sizeof ( OBIDMS_column_t ) ) ;
2015-06-23 18:35:34 +02:00
if ( new_column = = NULL )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error allocating the memory for the column structure " ) ;
2015-06-17 16:51:16 +02:00
close ( column_file_descriptor ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-06-23 18:35:34 +02:00
// Fill the column structure
new_column - > dms = dms ;
2015-07-20 16:08:50 +02:00
new_column - > column_directory = column_directory ;
2015-06-23 18:35:34 +02:00
new_column - > header = mmap ( NULL ,
header_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
column_file_descriptor ,
0
) ;
2015-05-26 10:38:56 +02:00
2015-06-17 16:51:16 +02:00
if ( new_column - > header = = MAP_FAILED )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error mmapping the header of a column " ) ;
2015-06-17 16:51:16 +02:00
close ( column_file_descriptor ) ;
free ( new_column ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-06-23 18:35:34 +02:00
new_column - > data = mmap ( NULL ,
data_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
column_file_descriptor ,
header_size
) ;
2015-05-26 10:38:56 +02:00
2015-06-17 16:51:16 +02:00
if ( new_column - > data = = MAP_FAILED )
2015-05-26 10:38:56 +02:00
{
2015-06-23 18:35:34 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error mmapping the data of a column " ) ;
munmap ( new_column - > header , header_size ) ;
2015-06-17 16:51:16 +02:00
close ( column_file_descriptor ) ;
free ( new_column ) ;
2015-05-26 10:38:56 +02:00
return NULL ;
}
2015-06-23 18:35:34 +02:00
new_column - > writable = true ;
2015-05-26 10:38:56 +02:00
2015-07-20 16:08:50 +02:00
header = new_column - > header ;
header - > header_size = header_size ;
2015-11-09 15:55:00 +01:00
header - > data_size = data_size ;
2015-08-26 10:52:19 +02:00
header - > line_count = nb_lines ;
2015-07-20 16:08:50 +02:00
header - > lines_used = 0 ;
header - > nb_elements_per_line = nb_elements_per_line ;
2015-09-28 13:52:41 +02:00
header - > data_type = data_type ;
2015-07-20 16:08:50 +02:00
header - > creation_date = time ( NULL ) ;
header - > version = version_number ;
2015-08-26 10:29:07 +02:00
header - > cloned_from = - 1 ;
2015-07-20 16:08:50 +02:00
2015-07-31 18:03:48 +02:00
obi_column_set_elements_names ( new_column , elements_names ) ;
2015-07-20 16:08:50 +02:00
2015-09-30 12:03:46 +02:00
strncpy ( header - > name , column_name , OBIDMS_COLUMN_MAX_NAME ) ;
2015-05-26 10:38:56 +02:00
2015-11-10 10:56:45 +01:00
if ( comments ! = NULL )
strncpy ( header - > comments , comments , COMMENTS_MAX_LENGTH ) ;
2015-11-03 14:22:00 +01:00
// If the data type is OBI_IDX, the associated obi_array is opened or created
if ( data_type = = 5 )
{
array = obi_array ( dms , array_name ) ;
if ( array = = NULL )
{
obidebug ( 1 , " \n Error opening or creating the array associated with a column " ) ;
munmap ( new_column - > header , header_size ) ;
close ( column_file_descriptor ) ;
free ( new_column ) ;
return NULL ;
}
new_column - > array = array ;
strncpy ( header - > array_name , array_name , ARRAY_MAX_NAME ) ;
}
2015-08-26 12:00:38 +02:00
// Fill the data with NA values
2015-09-14 17:04:29 +02:00
obi_ini_to_NA_values ( new_column , 0 , nb_lines ) ;
2015-08-26 12:00:38 +02:00
2015-06-24 13:53:12 +02:00
close ( column_file_descriptor ) ;
2015-06-23 18:35:34 +02:00
2015-06-17 16:51:16 +02:00
return new_column ;
2015-05-26 10:38:56 +02:00
}
2015-07-31 18:03:48 +02:00
2015-09-30 12:03:46 +02:00
OBIDMS_column_p obi_open_column ( OBIDMS_p dms ,
const char * column_name ,
obiversion_t version_number )
2015-07-31 18:03:48 +02:00
{
OBIDMS_column_p column ;
OBIDMS_column_directory_p column_directory ;
2015-11-03 14:22:00 +01:00
OBIDMS_array_p array ;
2015-07-31 18:03:48 +02:00
char * column_file_name ;
int column_file_descriptor ;
size_t header_size ;
column = NULL ;
// Get the column directory structure associated to the column
column_directory = obi_open_column_directory ( dms , column_name ) ;
if ( column_directory = = NULL )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening a column directory structure " ) ;
2015-07-31 18:03:48 +02:00
return NULL ;
}
// Get the latest version number if it has the value -1 (not given by user)
if ( version_number = = - 1 )
{
version_number = obi_get_latest_version_number ( column_directory ) ;
if ( version_number < 0 )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error getting the latest version number in a column directory " ) ;
2015-07-31 18:03:48 +02:00
return NULL ;
}
}
// Get the column file name
column_file_name = build_column_file_name ( column_name , version_number ) ;
if ( column_file_name = = NULL )
{
return NULL ;
}
// Open the column file, ALWAYS READ-ONLY
2015-11-09 15:06:02 +01:00
column_file_descriptor = openat ( column_directory - > dir_fd , column_file_name , O_RDONLY ) ;
2015-07-31 18:03:48 +02:00
if ( column_file_descriptor < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening column file " ) ;
2015-07-31 18:03:48 +02:00
free ( column_file_name ) ;
return NULL ;
}
2015-11-09 11:22:51 +01:00
free ( column_file_name ) ;
2015-07-31 18:03:48 +02:00
// Allocate the memory for the column structure
column = ( OBIDMS_column_p ) malloc ( sizeof ( OBIDMS_column_t ) ) ;
if ( column = = NULL )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error allocating the memory for a column structure " ) ;
2015-07-31 18:03:48 +02:00
close ( column_file_descriptor ) ;
return NULL ;
}
2015-11-09 17:50:32 +01:00
// Read the header size
if ( read ( column_file_descriptor , & header_size , sizeof ( size_t ) ) < sizeof ( size_t ) )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error reading the header size to open a column " ) ;
close ( column_file_descriptor ) ;
free ( column ) ;
return NULL ;
}
2015-07-31 18:03:48 +02:00
// Fill the column structure
column - > dms = dms ;
column - > column_directory = column_directory ;
column - > header = mmap ( NULL ,
header_size ,
PROT_READ ,
2015-08-26 10:29:07 +02:00
MAP_PRIVATE ,
2015-07-31 18:03:48 +02:00
column_file_descriptor ,
0
) ;
if ( column - > header = = MAP_FAILED )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error mmapping the header of a column " ) ;
2015-07-31 18:03:48 +02:00
close ( column_file_descriptor ) ;
free ( column ) ;
return NULL ;
}
2015-10-09 10:25:40 +02:00
// Map the data
2015-07-31 18:03:48 +02:00
column - > data = mmap ( NULL ,
2015-11-09 15:55:00 +01:00
( column - > header ) - > data_size ,
2015-07-31 18:03:48 +02:00
PROT_READ ,
2015-08-26 10:29:07 +02:00
MAP_PRIVATE ,
2015-07-31 18:03:48 +02:00
column_file_descriptor ,
header_size
) ;
if ( column - > data = = MAP_FAILED )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error mmapping the data of a column " ) ;
munmap ( column - > header , header_size ) ;
2015-07-31 18:03:48 +02:00
close ( column_file_descriptor ) ;
free ( column ) ;
return NULL ;
}
column - > writable = false ;
2015-11-03 14:22:00 +01:00
// If the data type is OBI_IDX, the associated obi_array is opened or created
if ( ( column - > header ) - > data_type = = 5 )
{
array = obi_array ( dms , ( column - > header ) - > array_name ) ;
if ( array = = NULL )
{
obidebug ( 1 , " \n Error opening the array associated with a column " ) ;
munmap ( column - > header , header_size ) ;
close ( column_file_descriptor ) ;
free ( column ) ;
return NULL ;
}
column - > array = array ;
}
2015-07-31 18:03:48 +02:00
close ( column_file_descriptor ) ;
return column ;
}
2015-11-09 15:55:00 +01:00
OBIDMS_column_p obi_clone_column ( OBIDMS_p dms ,
const char * column_name ,
2015-09-30 12:03:46 +02:00
obiversion_t version_number ,
2015-11-09 15:55:00 +01:00
bool clone_data )
2015-08-26 10:29:07 +02:00
{
OBIDMS_column_p column_to_clone ;
OBIDMS_column_p new_column ;
2015-11-09 11:22:51 +01:00
index_t nb_lines ;
2015-11-06 17:55:15 +01:00
index_t nb_elements_per_line ;
2015-08-26 10:29:07 +02:00
OBIType_t data_type ;
column_to_clone = obi_open_column ( dms , column_name , version_number ) ;
if ( column_to_clone = = NULL )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error opening the column to clone " ) ;
return NULL ;
}
2015-09-21 15:42:29 +02:00
data_type = ( column_to_clone - > header ) - > data_type ;
nb_elements_per_line = ( column_to_clone - > header ) - > nb_elements_per_line ;
2015-08-26 10:29:07 +02:00
if ( clone_data )
nb_lines = ( column_to_clone - > header ) - > line_count ;
else
2015-09-21 15:42:29 +02:00
nb_lines = get_line_count_per_page ( data_type , nb_elements_per_line ) ; // minimum line count corresponding to one memory page
2015-08-26 10:29:07 +02:00
new_column = obi_create_column ( dms ,
column_name ,
data_type ,
nb_lines ,
nb_elements_per_line ,
2015-11-03 14:22:00 +01:00
( column_to_clone - > header ) - > elements_names ,
2015-11-10 10:56:45 +01:00
( column_to_clone - > header ) - > array_name ,
( column_to_clone - > header ) - > comments ) ;
2015-08-26 10:29:07 +02:00
if ( new_column = = NULL )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error creating the new column when cloning a column " ) ;
2015-09-02 13:06:21 +02:00
// The new file is deleted
const char * column_file_name = build_column_file_name ( column_name , version_number ) ;
if ( remove ( column_file_name ) < 0 )
obidebug ( 1 , " \n Error deleting a bad cloned file " ) ;
2015-08-26 10:29:07 +02:00
}
( new_column - > header ) - > cloned_from = version_number ;
if ( clone_data )
2015-08-26 10:38:07 +02:00
{
2015-11-09 15:55:00 +01:00
memcpy ( new_column - > data , column_to_clone - > data , ( column_to_clone - > header ) - > data_size ) ;
2015-09-22 10:27:17 +02:00
( new_column - > header ) - > lines_used = ( column_to_clone - > header ) - > lines_used ;
2015-08-26 10:38:07 +02:00
}
2015-08-26 10:29:07 +02:00
2015-09-02 10:36:00 +02:00
// close column_to_clone
if ( obi_close_column ( column_to_clone ) < 0 )
{
obidebug ( 1 , " \n Error closing a column that has been cloned " ) ;
// TODO return NULL or not?
}
2015-08-26 17:01:54 +02:00
2015-08-26 10:29:07 +02:00
return new_column ;
}
2015-07-31 18:03:48 +02:00
int obi_close_column ( OBIDMS_column_p column )
{
2015-08-26 17:01:54 +02:00
// Munmap data
2015-11-09 15:55:00 +01:00
if ( munmap ( column - > data , ( column - > header ) - > data_size ) < 0 )
2015-08-26 17:01:54 +02:00
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error munmapping column data " ) ;
return - 1 ;
}
// Munmap header
if ( munmap ( column - > header , ( column - > header ) - > header_size ) < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error munmapping a column header " ) ;
return - 1 ;
}
2015-11-09 15:06:02 +01:00
obi_close_column_directory ( column - > column_directory ) ; // TODO or not
2015-10-09 10:25:40 +02:00
2015-07-31 18:03:48 +02:00
free ( column ) ;
2015-08-26 17:01:54 +02:00
return 0 ;
}
2015-09-30 12:03:46 +02:00
int obi_truncate_column_to_lines_used ( OBIDMS_column_p column ) // TODO is it necessary to unmap/remap?
2015-08-26 17:01:54 +02:00
{
2015-11-09 15:06:02 +01:00
size_t file_size ;
size_t data_size ;
2015-11-06 17:55:15 +01:00
index_t new_line_count ;
2015-11-09 15:06:02 +01:00
double multiple ;
int column_file_descriptor ;
char * column_file_name ;
2015-08-26 17:01:54 +02:00
2015-10-08 10:36:02 +02:00
// Compute the new line count = the number of lines used rounded to the nearest greater multiple of page size greater than 0
multiple = ceil ( ( double ) ( ONE_IF_ZERO ( ( column - > header ) - > lines_used ) * ( column - > header ) - > nb_elements_per_line * obi_sizeof ( ( column - > header ) - > data_type ) ) / ( double ) getpagesize ( ) ) ;
2015-10-09 13:49:48 +02:00
new_line_count = floor ( ( ( ( int ) multiple ) * getpagesize ( ) ) / ( ( column - > header ) - > nb_elements_per_line * obi_sizeof ( ( column - > header ) - > data_type ) ) ) ; // TODO is it safe to cast like this?
2015-09-21 15:42:29 +02:00
// Check that it is actually greater than the current number of lines allocated in the file, otherwise no need to truncate
if ( ( column - > header ) - > line_count = = new_line_count )
return 0 ;
2015-08-26 17:01:54 +02:00
// Get the column file name
column_file_name = build_column_file_name ( ( column - > header ) - > name , ( column - > header ) - > version ) ;
if ( column_file_name = = NULL )
{
return - 1 ;
}
// Open the column file
2015-11-09 15:06:02 +01:00
column_file_descriptor = openat ( ( column - > column_directory ) - > dir_fd , column_file_name , O_RDWR ) ;
2015-08-26 17:01:54 +02:00
if ( column_file_descriptor < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-26 17:05:37 +02:00
obidebug ( 1 , " \n Error getting the file descriptor of a column file " ) ;
2015-08-26 17:01:54 +02:00
free ( column_file_name ) ;
return - 1 ;
}
2015-11-09 11:22:51 +01:00
free ( column_file_name ) ;
2015-08-26 17:01:54 +02:00
// Unmap the data before truncating the file
2015-11-09 15:55:00 +01:00
if ( munmap ( column - > data , ( column - > header ) - > data_size ) < 0 )
2015-08-26 17:01:54 +02:00
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error munmapping the data of a column before truncating " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
2015-09-21 15:42:29 +02:00
// Truncate the column file
data_size = obi_array_sizeof ( ( column - > header ) - > data_type , new_line_count , ( column - > header ) - > nb_elements_per_line ) ;
2015-08-26 17:01:54 +02:00
file_size = ( column - > header ) - > header_size + data_size ;
if ( ftruncate ( column_file_descriptor , file_size ) < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error truncating a column file at the number of lines used " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
// Remap the data
2015-11-09 15:06:02 +01:00
column - > data = mmap ( NULL ,
data_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
column_file_descriptor ,
( column - > header ) - > header_size
) ;
2015-08-26 17:01:54 +02:00
if ( column - > data = = MAP_FAILED )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error re-mmapping the data of a column after truncating " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
2015-11-09 15:55:00 +01:00
// Set new line_count and new data size
2015-09-21 15:42:29 +02:00
( column - > header ) - > line_count = new_line_count ;
2015-11-09 15:55:00 +01:00
( column - > header ) - > data_size = data_size ;
2015-08-26 17:01:54 +02:00
close ( column_file_descriptor ) ;
return 0 ;
}
2015-09-01 17:38:08 +02:00
int obi_enlarge_column ( OBIDMS_column_p column )
{
2015-11-09 15:06:02 +01:00
size_t file_size ;
size_t old_data_size ;
size_t new_data_size ;
size_t header_size ;
2015-11-06 17:55:15 +01:00
index_t old_line_count ;
index_t new_line_count ;
2015-11-09 15:06:02 +01:00
int column_file_descriptor ;
char * column_file_name ;
void * new_data ;
2015-09-01 17:38:08 +02:00
// Get the column file name
column_file_name = build_column_file_name ( ( column - > header ) - > name , ( column - > header ) - > version ) ;
if ( column_file_name = = NULL )
{
return - 1 ;
}
// Open the column file
2015-11-09 15:06:02 +01:00
column_file_descriptor = openat ( ( column - > column_directory ) - > dir_fd , column_file_name , O_RDWR ) ;
2015-09-01 17:38:08 +02:00
if ( column_file_descriptor < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error getting the file descriptor of a column file " ) ;
free ( column_file_name ) ;
return - 1 ;
}
2015-11-09 11:22:51 +01:00
free ( column_file_name ) ;
2015-09-01 17:38:08 +02:00
// Calculate the new file size
old_line_count = ( column - > header ) - > line_count ;
2015-11-03 14:22:00 +01:00
new_line_count = old_line_count * COLUMN_GROWTH_FACTOR ;
2015-09-21 15:42:29 +02:00
2015-09-01 17:38:08 +02:00
if ( new_line_count > MAXIMUM_LINE_COUNT )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error enlarging a column file: new line count greater than the maximum allowed " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
2015-11-09 15:55:00 +01:00
old_data_size = ( column - > header ) - > data_size ;
2015-11-03 14:22:00 +01:00
new_data_size = old_data_size * COLUMN_GROWTH_FACTOR ;
2015-09-01 17:38:08 +02:00
header_size = ( column - > header ) - > header_size ;
file_size = header_size + new_data_size ;
2015-09-21 15:42:29 +02:00
// Enlarge the file // TODO isn't it possible that this makes the file "move"?
2015-09-01 17:38:08 +02:00
if ( ftruncate ( column_file_descriptor , file_size ) < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error enlarging a column file " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
2015-09-30 12:03:46 +02:00
// Remap the data: try enlarging mapped region (TODO this actually never works on my mac without the MAP_FIXED flag which overwrites everything)
// TODO : makes separate function even if it's only used here?
2015-09-21 15:42:29 +02:00
//obidebug(2, "\ntry enlarging mapped region: old size = %ld, new size = %ld, size = %ld", old_data_size, new_data_size, new_data_size - old_data_size);
new_data = mmap ( column - > data ,
new_data_size - old_data_size ,
2015-09-01 17:38:08 +02:00
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
column_file_descriptor ,
2015-09-21 15:42:29 +02:00
old_data_size
2015-09-01 17:38:08 +02:00
) ;
2015-09-21 15:42:29 +02:00
if ( new_data = = MAP_FAILED )
2015-09-01 17:38:08 +02:00
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error re-mmapping the data of a column after enlarging the file " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
2015-09-21 15:42:29 +02:00
// If remap failed: Unmap and map the data again
if ( new_data ! = ( column - > data ) ) // TODO check that this works without exception
{
//obidebug(2, "\nEnlarging mapped region failed: Unmap and map the data again, %x != %x", column->data, new_data);
if ( munmap ( column - > data , old_data_size ) < 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error munmapping the data of a column before enlarging " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
column - > data = mmap ( NULL ,
new_data_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
column_file_descriptor ,
header_size
) ;
if ( column - > data = = MAP_FAILED )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error re-mmapping the data of a column after enlarging the file " ) ;
close ( column_file_descriptor ) ;
return - 1 ;
}
}
2015-11-09 15:55:00 +01:00
// Set new line count and new data size
2015-09-01 17:38:08 +02:00
( column - > header ) - > line_count = new_line_count ;
2015-11-09 15:55:00 +01:00
( column - > header ) - > data_size = new_data_size ;
2015-09-01 17:38:08 +02:00
// Initialize new data lines to NA
obi_ini_to_NA_values ( column , old_line_count , new_line_count - old_line_count ) ;
close ( column_file_descriptor ) ;
return 0 ;
}
2015-08-26 17:01:54 +02:00
int obi_truncate_and_close_column ( OBIDMS_column_p column )
{
if ( obi_truncate_column_to_lines_used ( column ) < 0 )
return - 1 ;
if ( obi_close_column ( column ) < 0 )
return - 1 ;
2015-07-31 18:03:48 +02:00
return 0 ;
}
2015-09-30 12:03:46 +02:00
void obi_ini_to_NA_values ( OBIDMS_column_p column ,
2015-11-06 17:55:15 +01:00
index_t first_line_nb ,
index_t nb_lines )
2015-09-01 17:38:08 +02:00
{
2015-11-06 17:55:15 +01:00
index_t i , start , end , nb_elements ;
2015-09-01 17:38:08 +02:00
nb_elements = nb_lines * ( ( column - > header ) - > nb_elements_per_line ) ;
2015-10-12 17:54:36 +02:00
start = first_line_nb * ( ( column - > header ) - > nb_elements_per_line ) ;
2015-09-01 17:38:08 +02:00
end = start + nb_elements ;
switch ( ( column - > header ) - > data_type ) {
case OBI_VOID : // TODO;
break ;
case OBI_INT : for ( i = start ; i < end ; i + + )
{
* ( ( ( obiint_t * ) ( column - > data ) ) + i ) = OBIInt_NA ;
}
break ;
case OBI_FLOAT : for ( i = start ; i < end ; i + + )
{
* ( ( ( obifloat_t * ) ( column - > data ) ) + i ) = OBIFloat_NA ;
}
break ;
case OBI_BOOL : for ( i = start ; i < end ; i + + )
{
* ( ( ( obibool_t * ) ( column - > data ) ) + i ) = OBIBool_NA ;
}
break ;
case OBI_CHAR : for ( i = start ; i < end ; i + + )
{
* ( ( ( obichar_t * ) ( column - > data ) ) + i ) = OBIChar_NA ;
}
break ;
case OBI_IDX : for ( i = start ; i < end ; i + + )
{
2015-11-06 17:55:15 +01:00
* ( ( ( index_t * ) ( column - > data ) ) + i ) = OBIIdx_NA ;
2015-09-01 17:38:08 +02:00
}
break ;
}
}
2015-11-06 17:55:15 +01:00
OBIDMS_column_header_p obi_column_get_header_from_name ( OBIDMS_p dms , const char * column_name ) // TODO ADD VERSION ARGUMENT
2015-07-31 18:03:48 +02:00
{
OBIDMS_column_header_p header ;
OBIDMS_column_directory_p column_directory ;
char * column_file_name ;
int column_file_descriptor ;
size_t header_size ;
obiversion_t version_number ;
// Get the column directory structure associated to the column
column_directory = obi_open_column_directory ( dms , column_name ) ;
if ( column_directory = = NULL )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening a column directory structure " ) ;
2015-10-14 18:05:34 +02:00
return NULL ;
2015-07-31 18:03:48 +02:00
}
// Get the latest version number
version_number = obi_get_latest_version_number ( column_directory ) ;
if ( version_number < 0 )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error getting the latest version number in a column directory " ) ;
2015-10-14 18:05:34 +02:00
return NULL ;
2015-07-31 18:03:48 +02:00
}
// Get the column file name
column_file_name = build_column_file_name ( column_name , version_number ) ;
if ( column_file_name = = NULL )
{
2015-10-14 18:05:34 +02:00
return NULL ;
2015-07-31 18:03:48 +02:00
}
// Open the column file (READ-ONLY)
2015-11-09 15:06:02 +01:00
column_file_descriptor = openat ( column_directory - > dir_fd , column_file_name , O_RDONLY ) ;
2015-07-31 18:03:48 +02:00
if ( column_file_descriptor < 0 )
{
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error opening a column file " ) ;
2015-07-31 18:03:48 +02:00
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
free ( column_file_name ) ;
2015-10-14 18:05:34 +02:00
return NULL ;
2015-07-31 18:03:48 +02:00
}
2015-11-09 11:22:51 +01:00
free ( column_file_name ) ;
2015-11-09 17:50:32 +01:00
// Read the header size
if ( read ( column_file_descriptor , & header_size , sizeof ( size_t ) ) < sizeof ( size_t ) )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
obidebug ( 1 , " \n Error reading the header size to read a header " ) ;
close ( column_file_descriptor ) ;
return NULL ;
}
2015-07-31 18:03:48 +02:00
// Fill the header structure
header = mmap ( NULL ,
header_size ,
PROT_READ ,
MAP_SHARED ,
column_file_descriptor ,
0
) ;
if ( header = = MAP_FAILED )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error mmapping the header of a column " ) ;
2015-07-31 18:03:48 +02:00
close ( column_file_descriptor ) ;
2015-10-14 18:05:34 +02:00
return NULL ;
2015-07-31 18:03:48 +02:00
}
close ( column_file_descriptor ) ;
2015-10-14 18:05:34 +02:00
return header ;
2015-07-31 18:03:48 +02:00
}
2015-10-14 18:05:34 +02:00
int obi_unmap_header ( OBIDMS_column_header_p header )
2015-09-15 17:09:31 +02:00
{
2015-10-14 18:05:34 +02:00
if ( munmap ( header , header - > header_size ) < 0 )
2015-09-15 17:09:31 +02:00
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-10-14 18:05:34 +02:00
obidebug ( 1 , " \n Error munmapping a column header " ) ;
2015-09-15 17:09:31 +02:00
return - 1 ;
}
2015-10-14 18:05:34 +02:00
return 0 ;
2015-09-15 17:09:31 +02:00
}
2015-11-10 10:56:45 +01:00
// TODO to be rewritten in an optimized and safe way if possible
2015-11-06 17:55:15 +01:00
index_t obi_column_get_element_index_from_name ( OBIDMS_column_p column , const char * element_name )
2015-07-31 18:03:48 +02:00
{
2015-11-09 15:06:02 +01:00
char * elements_names ;
char * name ;
2015-11-06 17:55:15 +01:00
index_t element_index ;
2015-07-31 18:03:48 +02:00
elements_names = strdup ( ( column - > header ) - > elements_names ) ;
if ( elements_names = = NULL )
{
obidebug ( 1 , " \n Error strdup-ing the elements names " ) ;
2015-11-06 17:55:15 +01:00
return OBIIdx_NA ;
2015-07-31 18:03:48 +02:00
}
element_index = 0 ;
2015-09-21 15:42:29 +02:00
name = strtok ( elements_names , " ; " ) ; // TODO not thread safe, see strtok_r maybe
2015-07-31 18:03:48 +02:00
if ( strcmp ( element_name , name ) = = 0 )
{
free ( elements_names ) ;
return element_index ;
}
element_index + + ;
while ( name ! = NULL )
{
2015-09-21 15:42:29 +02:00
name = strtok ( NULL , " ; " ) ; // TODO not thread safe, see strtok_r maybe
2015-07-31 18:03:48 +02:00
if ( strcmp ( element_name , name ) = = 0 )
{
free ( elements_names ) ;
return element_index ;
}
element_index + + ;
}
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Can't find an element name " ) ;
2015-07-31 18:03:48 +02:00
free ( elements_names ) ;
2015-11-06 17:55:15 +01:00
return OBIIdx_NA ;
2015-07-31 18:03:48 +02:00
}
2015-10-15 15:12:45 +02:00
char * obi_column_format_date ( time_t date )
2015-10-02 13:47:53 +02:00
{
2015-11-09 15:06:02 +01:00
char * formatted_time ;
struct tm * tmp ;
2015-10-02 13:47:53 +02:00
formatted_time = ( char * ) malloc ( FORMATTED_TIME_LENGTH * sizeof ( char ) ) ;
2015-10-15 15:12:45 +02:00
tmp = localtime ( & date ) ;
2015-10-02 13:47:53 +02:00
if ( tmp = = NULL )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-10-15 15:12:45 +02:00
obidebug ( 1 , " \n Error formatting a date " ) ;
2015-10-02 13:47:53 +02:00
return NULL ;
}
if ( strftime ( formatted_time , FORMATTED_TIME_LENGTH , " %c " , tmp ) = = 0 )
{
obi_set_errno ( OBICOL_UNKNOWN_ERROR ) ;
2015-10-15 15:12:45 +02:00
obidebug ( 1 , " \n Error formatting a date " ) ;
2015-10-02 13:47:53 +02:00
return NULL ;
}
return formatted_time ;
}