mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-01-24 16:04:40 +08:00
ccc70d640b
and https://github.com/Unidata/netcdf-c/issues/708 Expand the NC_INMEMORY capabilities to support writing and accessing the final modified memory. Three new functions have been added: nc_open_memio, nc_create_mem, and nc_close_memio. The following new capabilities were added. 1. nc_open_memio() allows the NC_WRITE mode flag so a chunk of memory can be passed in and be modified 2. nc_create_mem() allows the NC_INMEMORY flag to be set to cause the created file to be kept in memory. 3. nc_close_mem() allows the final in-memory contents to be retrieved at the time the file is closed. 4. A special flag, NC_MEMIO_LOCK, is provided to ensure that the provided memory will not be freed or reallocated. Note the following. 1. If nc_open_memio() is called with NC_WRITE, and NC_MEMIO_LOCK is not set, then the netcdf-c library will take control of the incoming memory. This means that the original memory block should not be freed but the block returned by nc_close_mem() must be freed. 2. If nc_open_memio() is called with NC_WRITE, and NC_MEMIO_LOCK is set, then modifications to the original memory may fail if the space available is insufficient. Documentation is provided in the file docs/inmemory.md. A test case is provided: nc_test/tst_inmemory.c driven by nc_test/run_inmemory.sh WARNING: changes were made to the dispatch table for the close entry. From int (*close)(int) to int (*close)(int,void*).
318 lines
9.4 KiB
C
318 lines
9.4 KiB
C
/*********************************************************************
|
|
* Copyright 2018, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
* ********************************************************************/
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "config.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <hdf5.h>
|
|
#include <H5DSpublic.h> /* must be after nc4internal.h */
|
|
#include <H5Fpublic.h>
|
|
#include <H5LTpublic.h>
|
|
|
|
#include "netcdf.h"
|
|
#include "nc4internal.h"
|
|
|
|
#undef DEBUG
|
|
|
|
#ifndef HDrealloc
|
|
#define HDrealloc(M,Z) realloc(M,Z)
|
|
#endif /* HDrealloc */
|
|
|
|
extern int NC4_open_image(NC_HDF5_FILE_INFO_T* h5);
|
|
|
|
#if 0
|
|
/* Forward */
|
|
/* not working */
|
|
static int NC4_set_realloc_callback(NC_HDF5_FILE_INFO_T*, hid_t);
|
|
#endif
|
|
|
|
int
|
|
NC4_open_image_file(NC_HDF5_FILE_INFO_T* h5)
|
|
{
|
|
int stat = NC_NOERR;
|
|
hid_t hdfid;
|
|
|
|
/* check arguments */
|
|
if(h5->mem.memio.memory == NULL || h5->mem.memio.size == 0)
|
|
{stat = NC_EINVAL; goto done;}
|
|
|
|
/* Figure out the flags */
|
|
h5->mem.flags = 0;
|
|
if(h5->mem.locked) {
|
|
h5->mem.flags |= (H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE);
|
|
}
|
|
if(!h5->no_write)
|
|
h5->mem.flags |= H5LT_FILE_IMAGE_OPEN_RW;
|
|
|
|
/* Create the file but using our version of H5LTopen_file_image */
|
|
hdfid = NC4_open_image(h5);
|
|
#if 0
|
|
hdfid = H5LTopen_file_image(h5->mem.memio.memory,h5->mem.memio.size,h5->mem.flags);
|
|
#endif
|
|
if(hdfid < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
#if 0
|
|
/* Override the realloc callback if necessary */
|
|
if(h5->mem.flags & H5LT_FILE_IMAGE_DONT_COPY) {
|
|
if((stat = NC4_set_realloc_callback(h5,hdfid)) != NC_NOERR)
|
|
goto done;
|
|
}
|
|
#endif
|
|
|
|
/* Return file identifier */
|
|
h5->hdfid = hdfid;
|
|
|
|
done:
|
|
return stat;
|
|
}
|
|
|
|
int
|
|
NC4_create_image_file(NC_HDF5_FILE_INFO_T* h5)
|
|
{
|
|
int stat = NC_NOERR;
|
|
NC* nc = h5->controller;
|
|
hid_t fcpl, fapl, file_id; /* HDF5 identifiers */
|
|
size_t alloc_incr; /* Buffer allocation increment */
|
|
size_t min_incr = 65536; /* Minimum buffer increment */
|
|
#if 0
|
|
double buf_prcnt = 0.1f; /* Percentage of buffer size to set
|
|
as increment */
|
|
#endif
|
|
|
|
#if 0
|
|
see if we can get by without creating an initial memory for the core driver
|
|
/* Assume that the default buffer size and memory were set by caller */
|
|
if(h5->mem.memio.memory == NULL || h5->memio.size == 0)
|
|
{stat = NC_EINVAL; goto done;}
|
|
|
|
/* set allocation increment to a percentage of the supplied buffer mem, or
|
|
* a pre-defined minimum increment value, whichever is larger
|
|
*/
|
|
if ((buf_prcnt * h5->memio.size) > min_incr)
|
|
alloc_incr = (size_t)(buf_prcnt * h5->memio.size);
|
|
else
|
|
alloc_incr = min_incr;
|
|
|
|
#else
|
|
alloc_incr = min_incr;
|
|
#endif
|
|
|
|
/* Create FAPL to establish core driver */
|
|
if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
/* Make fcpl be default for now */
|
|
fcpl = H5P_DEFAULT;
|
|
|
|
/* Configure FAPL to use the core file driver with no backing store */
|
|
if (H5Pset_fapl_core(fapl, alloc_incr, 0) < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
#if 0
|
|
/* Assign file image in user buffer to FAPL */
|
|
if(H5Pset_file_image(fapl, h5->memio.memory, h5->memio.size) < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
#endif
|
|
|
|
/* Create the file */
|
|
if((file_id = H5Fcreate(nc->path, H5F_ACC_TRUNC, fcpl, fapl)) < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
/* Return file identifier */
|
|
h5->hdfid = file_id;
|
|
h5->mem.fapl = fapl;
|
|
|
|
done:
|
|
if(stat != NC_NOERR) {
|
|
/* Close FAPL */
|
|
H5Pclose(fapl);
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int
|
|
NC4_extract_file_image(NC_HDF5_FILE_INFO_T* h5)
|
|
{
|
|
int stat = NC_NOERR;
|
|
hid_t fapl;
|
|
herr_t herr;
|
|
NC_memio mem;
|
|
|
|
assert(h5 && h5->hdfid && !h5->no_write);
|
|
|
|
/* Get the file access property list */
|
|
#if 0
|
|
fapl = H5Fget_access_plist(h5->hdfid);
|
|
#else
|
|
fapl = h5->mem.fapl;
|
|
#endif
|
|
if(fapl < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
memset(&mem,0,sizeof(mem));
|
|
herr = H5Pget_file_image(fapl, &mem.memory, &mem.size);
|
|
if(herr < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
h5->mem.memio = mem;
|
|
|
|
/* Close FAPL */
|
|
if (H5Pclose(fapl) < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
h5->mem.fapl = 0;
|
|
|
|
#if 0
|
|
/* Pass 1: get the memory chunk size */
|
|
size = H5Fget_file_image(hdfid, NULL, 0);
|
|
if(size < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
/* Create the space to hold image */
|
|
h5->mem.memio.size = (size_t)size;
|
|
h5->mem.memio.memory = malloc(h5->mem.memio.size);
|
|
if(h5->mem.memio.memory == NULL)
|
|
{stat = NC_ENOMEM; goto done;}
|
|
/* Pass 2: get the memory chunk itself */
|
|
size = H5Fget_file_image(hdfid, h5->mem.memio.memory, h5->mem.memio.size);
|
|
if(size < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
#endif
|
|
|
|
done:
|
|
return stat;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: image_realloc
|
|
*
|
|
* Purpose: Reallocates the shared application image buffer and updates data
|
|
* structures that manage buffer "copying".
|
|
*
|
|
* Return: Address of reallocated buffer, if successful. Otherwise, it returns
|
|
* NULL.
|
|
*
|
|
* Programmer: Christian Chilan
|
|
*
|
|
* Date: October 3, 2011
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
* Modified from code in H5LT.c.
|
|
*/
|
|
|
|
/**
|
|
Type H5LT_file_image_ud_t is taken from H5LT.c.
|
|
*/
|
|
|
|
#if 0
|
|
/* Data structure to pass application data to callbacks. */
|
|
typedef struct {
|
|
void *app_image_ptr; /* Pointer to application buffer */
|
|
size_t app_image_size; /* Size of application buffer */
|
|
void *fapl_image_ptr; /* Pointer to FAPL buffer */
|
|
size_t fapl_image_size; /* Size of FAPL buffer */
|
|
int fapl_ref_count; /* Reference counter for FAPL buffer */
|
|
void *vfd_image_ptr; /* Pointer to VFD buffer */
|
|
size_t vfd_image_size; /* Size of VFD buffer */
|
|
int vfd_ref_count; /* Reference counter for VFD buffer */
|
|
unsigned flags; /* Flags indicate how the file image will */
|
|
/* be open */
|
|
int ref_count; /* Reference counter on udata struct */
|
|
} H5LT_file_image_ud_t;
|
|
|
|
static void *
|
|
local_image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *_udata)
|
|
{
|
|
H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata;
|
|
void * return_value = NULL;
|
|
|
|
/* callback is only used if the application buffer is not actually copied */
|
|
if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY))
|
|
goto out;
|
|
|
|
/* realloc() is not allowed if the image is open in read-only mode */
|
|
if (!(udata->flags & H5LT_FILE_IMAGE_OPEN_RW))
|
|
goto out;
|
|
|
|
if (file_image_op == H5FD_FILE_IMAGE_OP_FILE_RESIZE) {
|
|
if (udata->vfd_image_ptr != ptr)
|
|
goto out;
|
|
|
|
if (udata->vfd_ref_count != 1)
|
|
goto out;
|
|
|
|
/* Modified:
|
|
If H5LT_FILE_IMAGE_DONT_RELEASE flag is set: two cases
|
|
1. If the realloc new size is <= existing size,
|
|
then pretend we did a realloc and return success.
|
|
2. Otherwise, realloc() is not allowed because reallocation
|
|
may change the address of the buffer. The
|
|
new address cannot be communicated to the application
|
|
to release it.
|
|
*/
|
|
if (udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE) {
|
|
if(size > udata->vfd_image_size)
|
|
goto out;
|
|
} else {
|
|
if (NULL == (udata->vfd_image_ptr = HDrealloc(ptr, size)))
|
|
goto out;
|
|
udata->vfd_image_size = size;
|
|
}
|
|
return_value = udata->vfd_image_ptr;
|
|
} /* end if */
|
|
else
|
|
goto out;
|
|
|
|
return(return_value);
|
|
|
|
out:
|
|
return NULL;
|
|
} /* end local_image_realloc() */
|
|
|
|
static int
|
|
NC4_set_realloc_callback(NC_HDF5_FILE_INFO_T* h5, hid_t hdfid)
|
|
{
|
|
int stat = NC_NOERR;
|
|
hid_t fapl;
|
|
herr_t hstat;
|
|
H5FD_file_image_callbacks_t callbacks;
|
|
|
|
/* Get the file access property list */
|
|
fapl = H5Fget_access_plist(hdfid);
|
|
if(fapl < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
/* Now get the callbacks */
|
|
memset(&callbacks,0,sizeof(callbacks));
|
|
/* For some reason, this is not returning the callbacks */
|
|
hstat = H5Pget_file_image_callbacks(fapl, &callbacks);
|
|
if(hstat < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
/* Replace the realloc callback */
|
|
callbacks.image_realloc = local_image_realloc;
|
|
|
|
/* Now reset the callbacks */
|
|
hstat = H5Pset_file_image_callbacks(fapl, &callbacks);
|
|
if(hstat < 0)
|
|
{stat = NC_EHDFERR; goto done;}
|
|
|
|
done:
|
|
return stat;
|
|
}
|
|
#endif
|