eccodes/src/grib_filepool.cc

438 lines
11 KiB
C++
Raw Permalink Normal View History

2013-03-25 12:04:10 +00:00
/*
2020-01-28 14:32:34 +00:00
* (C) Copyright 2005- ECMWF.
2013-03-25 12:04:10 +00:00
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#include "grib_api_internal.h"
#define GRIB_MAX_OPENED_FILES 200
#if GRIB_PTHREADS
2020-01-22 13:10:59 +00:00
static pthread_once_t once = PTHREAD_ONCE_INIT;
2013-03-25 12:04:10 +00:00
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
2020-01-22 13:10:59 +00:00
static void init()
{
2013-03-25 12:04:10 +00:00
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
2020-01-22 13:10:59 +00:00
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex1, &attr);
2013-03-25 12:04:10 +00:00
pthread_mutexattr_destroy(&attr);
}
2015-12-30 14:39:02 +00:00
#elif GRIB_OMP_THREADS
static int once = 0;
static omp_nest_lock_t mutex1;
static void init()
{
GRIB_OMP_CRITICAL(lock_grib_filepool_c)
{
2020-01-22 13:10:59 +00:00
if (once == 0) {
2015-12-30 14:39:02 +00:00
omp_init_nest_lock(&mutex1);
once = 1;
}
}
}
2013-03-25 12:04:10 +00:00
#endif
2020-01-22 13:10:59 +00:00
static short next_id = 0;
2013-03-25 12:04:10 +00:00
2023-08-27 16:26:22 +00:00
static grib_file* grib_file_new(grib_context* c, const char* name, int* err);
2017-06-07 12:53:01 +00:00
/* Note: A fast cut-down version of strcmp which does NOT return -1 */
/* 0 means input strings are equal and 1 means not equal */
2020-01-22 13:10:59 +00:00
GRIB_INLINE static int grib_inline_strcmp(const char* a, const char* b)
{
2020-01-22 13:10:59 +00:00
if (*a != *b)
return 1;
while ((*a != 0 && *b != 0) && *(a) == *(b)) {
a++;
b++;
}
return (*a == 0 && *b == 0) ? 0 : 1;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
static grib_file_pool file_pool = {
0, /* grib_context* context;*/
0, /* grib_file* first;*/
0, /* grib_file* current; */
0, /* size_t size;*/
0, /* int number_of_opened_files;*/
GRIB_MAX_OPENED_FILES /* int max_opened_files; */
2013-03-25 12:04:10 +00:00
};
2013-03-25 14:23:07 +00:00
void grib_file_pool_clean()
{
2020-01-22 13:10:59 +00:00
grib_file *file, *next;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if (!file_pool.first)
return;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
file = file_pool.first;
while (file) {
next = file->next;
grib_file_delete(file);
2020-01-22 13:10:59 +00:00
file = next;
}
2013-03-25 12:04:10 +00:00
}
2023-08-27 16:26:22 +00:00
// static void grib_file_pool_change_id()
// {
// grib_file* file;
// if (!file_pool.first)
// return;
// file = file_pool.first;
// while (file) {
// file->id += 1000;
// file = file->next;
// }
// }
// static grib_file* grib_read_file(grib_context* c, FILE* fh, int* err)
// {
// short marker = 0;
// short id = 0;
// grib_file* file;
// *err = grib_read_short(fh, &marker);
// if (!marker)
// return NULL;
// file = (grib_file*)grib_context_malloc_clear(c, sizeof(grib_file));
// file->buffer = 0;
// file->name = grib_read_string(c, fh, err);
// if (*err)
// return NULL;
// *err = grib_read_short(fh, &id);
// file->id = id;
// if (*err)
// return NULL;
// file->next = grib_read_file(c, fh, err);
// if (*err)
// return NULL;
// return file;
// }
// static int grib_write_file(FILE* fh, grib_file* file)
// {
// int err = 0;
// if (!file)
// return grib_write_null_marker(fh);
// err = grib_write_not_null_marker(fh);
// if (err)
// return err;
// err = grib_write_string(fh, file->name);
// if (err)
// return err;
// err = grib_write_short(fh, (short)file->id);
// if (err)
// return err;
// return grib_write_file(fh, file->next);
// }
2013-03-25 12:04:10 +00:00
2024-03-09 19:55:22 +00:00
// grib_file* grib_file_pool_get_files()
// {
// return file_pool.first;
// }
2013-03-25 12:04:10 +00:00
2023-08-27 16:26:22 +00:00
// int grib_file_pool_read(grib_context* c, FILE* fh)
// {
// int err = 0;
// short marker = 0;
// grib_file* file;
// if (!c) c = grib_context_get_default();
// err = grib_read_short(fh, &marker);
// if (!marker) {
// grib_context_log(c, GRIB_LOG_ERROR,
// "Unable to find file information in index file");
// return GRIB_INVALID_FILE;
// }
// grib_file_pool_change_id();
// file = file_pool.first;
// while (file->next)
// file = file->next;
// file->next = grib_read_file(c, fh, &err);
// if (err)
// return err;
// return GRIB_SUCCESS;
// }
// int grib_file_pool_write(FILE* fh)
// {
// int err = 0;
// if (!file_pool.first)
// return grib_write_null_marker(fh);
// err = grib_write_not_null_marker(fh);
// if (err)
// return err;
// return grib_write_file(fh, file_pool.first);
// }
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
grib_file* grib_file_open(const char* filename, const char* mode, int* err)
2013-03-25 14:23:07 +00:00
{
2020-01-22 13:10:59 +00:00
grib_file *file = 0, *prev = 0;
int same_mode = 0;
int is_new = 0;
GRIB_MUTEX_INIT_ONCE(&once, &init);
2020-01-22 13:10:59 +00:00
if (!file_pool.context)
file_pool.context = grib_context_get_default();
2020-01-22 13:10:59 +00:00
if (file_pool.current && !grib_inline_strcmp(filename, file_pool.current->name)) {
file = file_pool.current;
}
else {
GRIB_MUTEX_LOCK(&mutex1);
2020-01-22 13:10:59 +00:00
file = file_pool.first;
while (file) {
2020-01-22 13:10:59 +00:00
if (!grib_inline_strcmp(filename, file->name))
break;
prev = file;
file = file->next;
}
if (!file) {
2020-01-22 13:10:59 +00:00
is_new = 1;
file = grib_file_new(file_pool.context, filename, err);
if (prev)
prev->next = file;
file_pool.current = file;
if (!prev)
file_pool.first = file;
file_pool.size++;
}
GRIB_MUTEX_UNLOCK(&mutex1);
}
2020-01-22 13:10:59 +00:00
if (file->mode)
same_mode = grib_inline_strcmp(mode, file->mode) ? 0 : 1;
if (file->handle && same_mode) {
2020-01-22 13:10:59 +00:00
*err = 0;
return file;
}
GRIB_MUTEX_LOCK(&mutex1);
if (!same_mode && file->handle) {
fclose(file->handle);
}
if (!file->handle) {
if (!is_new && *mode == 'w') {
2020-01-22 13:10:59 +00:00
file->handle = fopen(file->name, "a");
}
else {
file->handle = fopen(file->name, mode);
}
if (!file->handle) {
2023-08-27 16:26:22 +00:00
grib_context_log(file->context, GRIB_LOG_PERROR, "%s: Cannot open file '%s'", __func__, file->name);
2020-01-22 13:10:59 +00:00
*err = GRIB_IO_PROBLEM;
GRIB_MUTEX_UNLOCK(&mutex1);
return NULL;
}
if (file->mode) free(file->mode);
file->mode = strdup(mode);
if (file_pool.context->io_buffer_size) {
2013-03-25 12:04:10 +00:00
#ifdef POSIX_MEMALIGN
2020-01-22 13:10:59 +00:00
if (posix_memalign((void**)&(file->buffer), sysconf(_SC_PAGESIZE), file_pool.context->io_buffer_size)) {
2023-08-27 16:26:22 +00:00
grib_context_log(file->context, GRIB_LOG_FATAL, "posix_memalign unable to allocate io_buffer");
}
2013-03-25 12:04:10 +00:00
#else
2022-05-10 16:47:53 +00:00
file->buffer = (char*)malloc(file_pool.context->io_buffer_size);
if (!file->buffer) {
2020-01-22 13:10:59 +00:00
grib_context_log(file->context, GRIB_LOG_FATAL, "Unable to allocate io_buffer\n");
}
2013-03-25 12:04:10 +00:00
#endif
2020-01-22 13:10:59 +00:00
setvbuf(file->handle, file->buffer, _IOFBF, file_pool.context->io_buffer_size);
}
2013-03-25 12:04:10 +00:00
file_pool.number_of_opened_files++;
}
GRIB_MUTEX_UNLOCK(&mutex1);
return file;
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
void grib_file_pool_delete_file(grib_file* file)
{
grib_file* prev = NULL;
GRIB_MUTEX_INIT_ONCE(&once, &init);
GRIB_MUTEX_LOCK(&mutex1);
2020-01-22 13:10:59 +00:00
if (file == file_pool.first) {
file_pool.first = file->next;
file_pool.current = file->next;
}
else {
prev = file_pool.first;
file_pool.current = file_pool.first;
while (prev) {
2020-01-22 13:10:59 +00:00
if (prev->next == file)
break;
prev = prev->next;
}
2023-06-26 20:21:07 +00:00
DEBUG_ASSERT(prev);
2018-10-26 13:53:29 +00:00
if (prev) {
2020-01-22 13:10:59 +00:00
prev->next = file->next;
2018-10-26 13:53:29 +00:00
}
}
if (file->handle) {
file_pool.number_of_opened_files--;
}
grib_file_delete(file);
GRIB_MUTEX_UNLOCK(&mutex1);
}
void grib_file_close(const char* filename, int force, int* err)
2013-03-25 14:23:07 +00:00
{
2020-01-22 13:10:59 +00:00
grib_file* file = NULL;
grib_context* context = grib_context_get_default();
/* Performance: keep the files open to avoid opening and closing files when writing the output. */
/* So only call fclose() when too many files are open. */
/* Also see ECC-411 */
int do_close = (file_pool.number_of_opened_files > context->file_pool_max_opened_files);
2020-01-22 13:10:59 +00:00
if (force == 1)
do_close = 1; /* Can be overridden with the force argument */
2020-01-22 13:10:59 +00:00
if (do_close) {
/*printf("+++++++++++++ closing file %s (n=%d)\n",filename, file_pool.number_of_opened_files);*/
2020-01-22 13:10:59 +00:00
GRIB_MUTEX_INIT_ONCE(&once, &init);
GRIB_MUTEX_LOCK(&mutex1);
2020-01-22 13:10:59 +00:00
file = grib_get_file(filename, err);
if (file->handle) {
if (fclose(file->handle) != 0) {
2020-01-22 13:10:59 +00:00
*err = GRIB_IO_PROBLEM;
}
if (file->buffer) {
free(file->buffer);
2020-01-22 13:10:59 +00:00
file->buffer = 0;
}
2020-01-22 13:10:59 +00:00
file->handle = NULL;
file_pool.number_of_opened_files--;
}
GRIB_MUTEX_UNLOCK(&mutex1);
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
void grib_file_close_all(int* err)
2013-03-25 12:04:10 +00:00
{
grib_file* file = NULL;
2020-01-22 13:10:59 +00:00
if (!file_pool.first)
return;
2020-01-22 13:10:59 +00:00
GRIB_MUTEX_INIT_ONCE(&once, &init);
GRIB_MUTEX_LOCK(&mutex1);
file = file_pool.first;
while (file) {
if (file->handle) {
if (fclose(file->handle) != 0) {
2020-01-22 13:10:59 +00:00
*err = GRIB_IO_PROBLEM;
}
2020-01-22 13:10:59 +00:00
file->handle = NULL;
}
file = file->next;
}
GRIB_MUTEX_UNLOCK(&mutex1);
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
grib_file* grib_get_file(const char* filename, int* err)
2013-03-25 12:04:10 +00:00
{
2020-01-22 13:10:59 +00:00
grib_file* file = NULL;
2013-03-25 12:04:10 +00:00
2023-12-26 14:52:23 +00:00
if (!file_pool.current) {
*err = GRIB_IO_PROBLEM;
return NULL;
}
2020-01-22 13:10:59 +00:00
if (file_pool.current->name && !grib_inline_strcmp(filename, file_pool.current->name)) {
return file_pool.current;
}
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
file = file_pool.first;
while (file) {
2020-01-22 13:10:59 +00:00
if (!grib_inline_strcmp(filename, file->name))
break;
file = file->next;
}
2020-01-22 13:10:59 +00:00
if (!file)
file = grib_file_new(0, filename, err);
2013-03-25 12:04:10 +00:00
return file;
2013-03-25 12:04:10 +00:00
}
2023-08-27 16:26:22 +00:00
// grib_file* grib_find_file(short id)
// {
// grib_file* file = NULL;
// if (file_pool.current->name && id == file_pool.current->id) {
// return file_pool.current;
// }
// file = file_pool.first;
// while (file) {
// if (id == file->id)
// break;
// file = file->next;
// }
// return file;
// }
static grib_file* grib_file_new(grib_context* c, const char* name, int* err)
2013-03-25 14:23:07 +00:00
{
2023-08-27 16:26:22 +00:00
if (!c) c = grib_context_get_default();
2013-03-25 12:04:10 +00:00
2023-08-27 16:26:22 +00:00
grib_file* file = (grib_file*)grib_context_malloc_clear(c, sizeof(grib_file));
if (!file) {
2023-08-27 16:26:22 +00:00
grib_context_log(c, GRIB_LOG_ERROR, "%s: Unable to allocate memory", __func__);
2020-01-22 13:10:59 +00:00
*err = GRIB_OUT_OF_MEMORY;
return NULL;
}
2020-01-22 13:10:59 +00:00
GRIB_MUTEX_INIT_ONCE(&once, &init);
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
file->name = strdup(name);
file->id = next_id;
2013-03-25 12:04:10 +00:00
GRIB_MUTEX_LOCK(&mutex1);
next_id++;
GRIB_MUTEX_UNLOCK(&mutex1);
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
file->mode = 0;
file->handle = 0;
file->refcount = 0;
file->context = c;
file->next = 0;
file->buffer = 0;
return file;
2013-03-25 12:04:10 +00:00
}
2013-03-25 14:23:07 +00:00
void grib_file_delete(grib_file* file)
{
2023-06-23 18:00:47 +00:00
if (!file) return;
2020-01-22 13:10:59 +00:00
GRIB_MUTEX_INIT_ONCE(&once, &init);
GRIB_MUTEX_LOCK(&mutex1);
/* GRIB-803: cannot call fclose yet! Causes crash */
/* TODO: Set handle to NULL in filepool too */
2023-06-23 18:00:47 +00:00
//if (file->handle) {
// if (fclose(file->handle) != 0) {
// perror(file->name);
// }
//}
2020-01-22 13:10:59 +00:00
if (file->name)
free(file->name);
if (file->mode)
free(file->mode);
if (file->buffer) {
free(file->buffer);
}
2020-01-22 13:10:59 +00:00
grib_context_free(file->context, file);
/* file = NULL; */
GRIB_MUTEX_UNLOCK(&mutex1);
2013-03-25 12:04:10 +00:00
}