source: XIOS/dev/branch_openmp/extern/src_netcdf4/memio.c @ 1501

Last change on this file since 1501 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 16.0 KB
Line 
1/*
2 *      Copyright 1996, University Corporation for Atmospheric Research
3 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5#if defined (_WIN32) || defined (_WIN64)
6#include <windows.h>
7#include <winbase.h>
8#include <io.h>
9#define lseek64 lseek
10#endif
11
12#include "config.h"
13#include <assert.h>
14#include <stdlib.h>
15#include <errno.h>
16#include <string.h>
17#ifdef _MSC_VER /* Microsoft Compilers */
18#include <io.h>
19#else
20#include <unistd.h>
21#endif
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#endif
25#include "nc.h"
26
27#undef DEBUG
28
29#ifdef DEBUG
30#include <stdio.h>
31#endif
32
33#ifndef HAVE_SSIZE_T
34#define ssize_t int
35#endif
36
37#ifndef SEEK_SET
38#define SEEK_SET 0
39#define SEEK_CUR 1
40#define SEEK_END 2
41#endif
42
43/* Define the mode flags for create: let umask rule */
44#define OPENMODE 0666
45
46#include "ncio.h"
47#include "fbits.h"
48#include "rnd.h"
49
50/* #define INSTRUMENT 1 */
51#if INSTRUMENT /* debugging */
52#undef NDEBUG
53#include <stdio.h>
54/*#include "instr.h"*/
55#endif
56
57#ifndef MEMIO_MAXBLOCKSIZE
58#define MEMIO_MAXBLOCKSIZE 268435456 /* sanity check, about X_SIZE_T_MAX/8 */
59#endif
60
61#undef MIN  /* system may define MIN somewhere and complain */
62#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
63
64#if !defined(NDEBUG) && !defined(X_INT_MAX)
65#define  X_INT_MAX 2147483647
66#endif
67
68#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */
69#define  X_ALIGN 4
70#else
71#undef X_ALIGN
72#endif
73
74/* Private data for memio */
75
76typedef struct NCMEMIO {
77    int locked; /* => we cannot realloc */
78    int persist; /* => save to a file; triggered by NC_WRITE */
79    char* memory;
80    off_t alloc;
81    off_t size;
82    off_t pos;
83} NCMEMIO;
84
85/* Forward */
86static int memio_rel(ncio *const nciop, off_t offset, int rflags);
87static int memio_get(ncio *const nciop, off_t offset, size_t extent, int rflags, void **const vpp);
88static int memio_move(ncio *const nciop, off_t to, off_t from, size_t nbytes, int rflags);
89static int memio_sync(ncio *const nciop);
90static int memio_filesize(ncio* nciop, off_t* filesizep);
91static int memio_pad_length(ncio* nciop, off_t length);
92static int memio_close(ncio* nciop, int);
93
94/* Mnemonic */
95#define DOOPEN 1
96
97static long pagesize = 0;
98
99/* Create a new ncio struct to hold info about the file. */
100static int
101memio_new(const char* path, int ioflags, off_t initialsize, ncio** nciopp, NCMEMIO** memiop)
102{
103    int status = NC_NOERR;
104    ncio* nciop = NULL;
105    NCMEMIO* memio = NULL;
106    int openfd = -1;
107
108    if(pagesize == 0) {
109
110#if defined (_WIN32) || defined(_WIN64)
111      SYSTEM_INFO info;
112      GetSystemInfo (&info);
113      pagesize = info.dwPageSize;
114#elif defined HAVE_SYSCONF
115        pagesize = sysconf(_SC_PAGE_SIZE);
116#elif defined HAVE_GETPAGESIZE
117        pagesize = getpagesize();
118#else
119        pagesize = 4096; /* good guess */
120#endif
121    }
122
123    errno = 0;
124
125    /* Always force the allocated size to be a multiple of pagesize */
126    if(initialsize == 0) initialsize = pagesize;
127    if((initialsize % pagesize) != 0)
128        initialsize += (pagesize - (initialsize % pagesize));
129
130    nciop = (ncio* )calloc(1,sizeof(ncio));
131    if(nciop == NULL) {status = NC_ENOMEM; goto fail;}
132   
133    nciop->ioflags = ioflags;
134    *((int*)&nciop->fd) = -1; /* caller will fix */
135
136    *((char**)&nciop->path) = strdup(path);
137    if(nciop->path == NULL) {status = NC_ENOMEM; goto fail;}
138
139    *((ncio_relfunc**)&nciop->rel) = memio_rel;
140    *((ncio_getfunc**)&nciop->get) = memio_get;
141    *((ncio_movefunc**)&nciop->move) = memio_move;
142    *((ncio_syncfunc**)&nciop->sync) = memio_sync;
143    *((ncio_filesizefunc**)&nciop->filesize) = memio_filesize;
144    *((ncio_pad_lengthfunc**)&nciop->pad_length) = memio_pad_length;
145    *((ncio_closefunc**)&nciop->close) = memio_close;
146
147    memio = (NCMEMIO*)calloc(1,sizeof(NCMEMIO));
148    if(memio == NULL) {status = NC_ENOMEM; goto fail;}
149    *((void* *)&nciop->pvt) = memio;
150
151    memio->alloc = initialsize;
152
153    memio->memory = NULL;
154    memio->size = 0;
155    memio->pos = 0;
156    memio->persist = fIsSet(ioflags,NC_WRITE);
157
158    if(nciopp) *nciopp = nciop;
159    if(memiop) *memiop = memio;
160
161done:
162    if(openfd >= 0) close(openfd);
163    return status;
164
165fail:
166    if(nciop != NULL) {
167        if(nciop->path != NULL) free((char*)nciop->path);
168    }
169    goto done;
170}
171
172/* Create a file, and the ncio struct to go with it. This function is
173   only called from nc__create_mp.
174
175   path - path of file to create.
176   ioflags - flags from nc_create
177   initialsz - From the netcdf man page: "The argument
178   Iinitialsize sets the initial size of the file at creation time."
179   igeto -
180   igetsz -
181   sizehintp - the size of a page of data for buffered reads and writes.
182   nciopp - pointer to a pointer that will get location of newly
183   created and inited ncio struct.
184   mempp - pointer to pointer to the initial memory read.
185*/
186int
187memio_create(const char* path, int ioflags,
188    size_t initialsz,
189    off_t igeto, size_t igetsz, size_t* sizehintp,
190    ncio* *nciopp, void** const mempp)
191{
192    ncio* nciop;
193    int fd;
194    int status;
195    NCMEMIO* memio = NULL;
196    int persist = (ioflags & NC_WRITE?1:0);
197    int oflags;
198
199    if(path == NULL ||* path == 0)
200        return NC_EINVAL;
201
202    /* For diskless open has, the file must be classic version 1 or 2.*/
203    if(fIsSet(ioflags,NC_NETCDF4))
204        return NC_EDISKLESS; /* violates constraints */
205
206    status = memio_new(path, ioflags, initialsz, &nciop, &memio);
207    if(status != NC_NOERR)
208        return status;
209    memio->size = 0;
210
211    if(!persist) {
212        memio->memory = (char*)malloc(memio->alloc);
213        if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
214    } else { /*persist */
215        /* Open the file, but make sure we can write it if needed */
216        oflags = (persist ? O_RDWR : O_RDONLY);   
217#ifdef O_BINARY
218        fSet(oflags, O_BINARY);
219#endif
220        oflags |= (O_CREAT|O_TRUNC);
221        if(fIsSet(ioflags,NC_NOCLOBBER))
222            oflags |= O_EXCL;
223#ifdef vms
224        fd = open(path, oflags, 0, "ctx=stm");
225#else
226        fd  = open(path, oflags, OPENMODE);
227#endif
228        if(fd < 0) {status = errno; goto unwind_open;}
229
230        (void)close(fd); /* will reopen at nc_close */
231        /* malloc memory */
232        memio->memory = (char*)malloc(memio->alloc);
233        if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
234    } /*!persist*/
235
236#ifdef DEBUG
237fprintf(stderr,"memio_create: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
238#endif
239
240    fd = nc__pseudofd();
241    *((int* )&nciop->fd) = fd; 
242
243    fSet(nciop->ioflags, NC_WRITE);
244
245    if(igetsz != 0)
246    {
247        status = nciop->get(nciop,
248                igeto, igetsz,
249                RGN_WRITE,
250                mempp);
251        if(status != NC_NOERR)
252            goto unwind_open;
253    }
254
255    /* Pick a default sizehint */
256    if(sizehintp) *sizehintp = pagesize;
257
258    *nciopp = nciop;
259    return NC_NOERR;
260
261unwind_open:
262    memio_close(nciop,1);
263    return status;
264}
265
266/* This function opens the data file. It is only called from nc.c,
267   from nc__open_mp and nc_delete_mp.
268
269   path - path of data file.
270   ioflags - flags passed into nc_open.
271   igeto - looks like this function can do an initial page get, and
272   igeto is going to be the offset for that. But it appears to be
273   unused
274   igetsz - the size in bytes of initial page get (a.k.a. extent). Not
275   ever used in the library.
276   sizehintp - the size of a page of data for buffered reads and writes.
277   nciopp - pointer to pointer that will get address of newly created
278   and inited ncio struct.
279   mempp - pointer to pointer to the initial memory read.
280*/
281int
282memio_open(const char* path,
283    int ioflags,
284    off_t igeto, size_t igetsz, size_t* sizehintp,
285    ncio* *nciopp, void** const mempp)
286{
287    ncio* nciop;
288    int fd;
289    int status;
290    int persist = (fIsSet(ioflags,NC_WRITE)?1:0);
291    int oflags;
292    NCMEMIO* memio = NULL;
293    size_t sizehint;
294    off_t filesize;
295
296    if(path == NULL ||* path == 0)
297        return EINVAL;
298
299    assert(sizehintp != NULL);
300    sizehint = *sizehintp;
301
302    /* Open the file, but make sure we can write it if needed */
303    oflags = (persist ? O_RDWR : O_RDONLY);   
304#ifdef O_BINARY
305    fSet(oflags, O_BINARY);
306#endif
307    oflags |= O_EXCL;
308#ifdef vms
309    fd = open(path, oflags, 0, "ctx=stm");
310#else
311    fd  = open(path, oflags, OPENMODE);
312#endif
313#ifdef DEBUG
314    if(fd < 0) {
315        fprintf(stderr,"open failed: file=%s err=",path);
316        perror("");
317    }
318#endif
319    if(fd < 0) {status = errno; goto unwind_open;}
320
321    /* get current filesize  = max(|file|,initialize)*/
322    filesize = lseek(fd,0,SEEK_END);
323    if(filesize < 0) {status = errno; goto unwind_open;}
324    /* move pointer back to beginning of file */
325    (void)lseek(fd,0,SEEK_SET);
326    if(filesize < (off_t)sizehint)
327        filesize = (off_t)sizehint;
328
329    status = memio_new(path, ioflags, filesize, &nciop, &memio);
330    if(status != NC_NOERR)
331        return status;
332    memio->size = filesize;
333
334    memio->memory = (char*)malloc(memio->alloc);
335    if(memio->memory == NULL) {status = NC_ENOMEM; goto unwind_open;}
336
337#ifdef DEBUG
338fprintf(stderr,"memio_open: initial memory: %lu/%lu\n",(unsigned long)memio->memory,(unsigned long)memio->alloc);
339#endif
340
341    /* Read the file into the memio memory */
342    /* We need to do multiple reads because there is no
343       guarantee that the amount read will be the full amount */
344    {
345        off_t red = memio->size;
346        char* pos = memio->memory;
347        while(red > 0) {
348            ssize_t count = read(fd, pos, red);
349            if(count < 0)
350                {close(fd); status = errno; goto unwind_open;}
351            if(count == 0)
352                {close(fd); status = NC_ENOTNC; goto unwind_open;}
353            red -= count;
354            pos += count;
355        }
356    }
357    (void)close(fd); /* until memio_close() */
358
359    /* Use half the filesize as the blocksize */
360    sizehint = filesize/2;
361
362    fd = nc__pseudofd();
363    *((int* )&nciop->fd) = fd; 
364
365    if(igetsz != 0)
366    {
367        status = nciop->get(nciop,
368                igeto, igetsz,
369                0,
370                mempp);
371        if(status != NC_NOERR)
372            goto unwind_open;
373    }
374
375    *sizehintp = sizehint;
376    *nciopp = nciop;
377    return NC_NOERR;
378
379unwind_open:
380    memio_close(nciop,0);
381    return status;
382}
383
384
385/*
386 *  Get file size in bytes.
387 */
388static int
389memio_filesize(ncio* nciop, off_t* filesizep)
390{
391    NCMEMIO* memio;
392    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
393    memio = (NCMEMIO*)nciop->pvt;
394    if(filesizep != NULL) *filesizep = memio->size;
395    return NC_NOERR;
396}
397
398/*
399 *  Sync any changes to disk, then truncate or extend file so its size
400 *  is length.  This is only intended to be called before close, if the
401 *  file is open for writing and the actual size does not match the
402 *  calculated size, perhaps as the result of having been previously
403 *  written in NOFILL mode.
404 */
405static int
406memio_pad_length(ncio* nciop, off_t length)
407{
408    NCMEMIO* memio;
409    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
410    memio = (NCMEMIO*)nciop->pvt;
411
412    if(!fIsSet(nciop->ioflags, NC_WRITE))
413        return EPERM; /* attempt to write readonly file*/
414
415    if(memio->locked > 0)
416        return NC_EDISKLESS;
417
418    if(length > memio->alloc) {
419        /* Realloc the allocated memory to a multiple of the pagesize*/
420        off_t newsize = length;
421        void* newmem = NULL;
422        /* Round to a multiple of pagesize */
423        if((newsize % pagesize) != 0)
424            newsize += (pagesize - (newsize % pagesize));
425
426        newmem = (char*)realloc(memio->memory,newsize);
427        if(newmem == NULL) return NC_ENOMEM;
428
429        /* zero out the extra memory */
430        memset((void*)(newmem+memio->alloc),0,(newsize - memio->alloc));
431
432#ifdef DEBUG
433fprintf(stderr,"realloc: %lu/%lu -> %lu/%lu\n",
434(unsigned long)memio->memory,(unsigned long)memio->alloc,
435(unsigned long)newmem,(unsigned long)newsize);
436#endif
437        memio->memory = newmem;
438        memio->alloc = newsize;
439    } 
440    memio->size = length;
441    return NC_NOERR;
442}
443
444/* Write out any dirty buffers to disk and
445   ensure that next read will get data from disk.
446   Sync any changes, then close the open file associated with the ncio
447   struct, and free its memory.
448   nciop - pointer to ncio to close.
449   doUnlink - if true, unlink file
450*/
451
452static int 
453memio_close(ncio* nciop, int doUnlink)
454{
455    int status = NC_NOERR;
456    NCMEMIO* memio;
457    int fd = -1;
458    if(nciop == NULL || nciop->pvt == NULL) return NC_NOERR;
459
460    memio = (NCMEMIO*)nciop->pvt;
461    assert(memio != NULL);
462
463    /* See if the user wants the contents persisted to a file */
464    if(memio->persist) {
465        /* Try to open the file for writing */
466        int oflags = O_WRONLY|O_CREAT|O_TRUNC;
467#ifdef O_BINARY
468        fSet(oflags, O_BINARY);
469#endif
470        fd = open(nciop->path, oflags, OPENMODE);
471        if(fd >= 0) {
472            /* We need to do multiple writes because there is no
473               guarantee that the amount written will be the full amount */
474            off_t written = memio->size;
475            char* pos = memio->memory;
476            while(written > 0) {
477                ssize_t count = write(fd, pos, written);
478                if(count < 0)
479                    {status = errno; goto done;}
480                if(count == 0)
481                    {status = NC_ENOTNC; goto done;}
482                written -= count;
483                pos += count;
484            }
485        } else
486            status = errno;
487        /* Free up things */
488        if(memio->memory != NULL) free(memio->memory);
489     }
490
491done:
492    /* do cleanup  */
493    if(fd >= 0) (void)close(fd);               
494    if(memio != NULL) free(memio);
495    if(nciop->path != NULL) free((char*)nciop->path);
496    free(nciop);
497    return status;
498}
499
500static int
501guarantee(ncio* nciop, off_t endpoint)
502{
503    NCMEMIO* memio = (NCMEMIO*)nciop->pvt;
504    if(endpoint > memio->alloc) {
505        /* extend the allocated memory and size */
506        int status = memio_pad_length(nciop,endpoint);
507        if(status != NC_NOERR) return status;
508    }
509    if(memio->size < endpoint)
510        memio->size = endpoint;
511    return NC_NOERR;
512}
513
514/*
515 * Request that the region (offset, extent)
516 * be made available through *vpp.
517 */
518static int
519memio_get(ncio* const nciop, off_t offset, size_t extent, int rflags, void** const vpp)
520{
521    int status = NC_NOERR;
522    NCMEMIO* memio;
523    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
524    memio = (NCMEMIO*)nciop->pvt;
525    status = guarantee(nciop, offset+extent);
526    memio->locked++;
527    if(status != NC_NOERR) return status;
528    if(vpp) *vpp = memio->memory+offset;
529    return NC_NOERR;
530}
531
532/*
533 * Like memmove(), safely move possibly overlapping data.
534 */
535static int
536memio_move(ncio* const nciop, off_t to, off_t from, size_t nbytes, int ignored)
537{
538    int status = NC_NOERR;
539    NCMEMIO* memio;
540
541    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
542    memio = (NCMEMIO*)nciop->pvt;
543    if(from < to) {
544       /* extend if "to" is not currently allocated */
545       status = guarantee(nciop,to+nbytes);
546       if(status != NC_NOERR) return status;
547    }
548    /* check for overlap */
549    if((to + nbytes) > from || (from + nbytes) > to) {
550        /* Ranges overlap */
551#ifdef HAVE_MEMMOVE
552        memmove((void*)(memio->memory+to),(void*)(memio->memory+from),nbytes);
553#else
554        off_t overlap;
555        off_t nbytes1;
556        if((from + nbytes) > to) {
557            overlap = ((from + nbytes) - to); /* # bytes of overlap */
558            nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */
559            /* move the non-overlapping part */
560            memcpy((void*)(memio->memory+(to+overlap)),
561                   (void*)(memio->memory+(from+overlap)),
562                   nbytes1);
563            /* move the overlapping part */
564            memcpy((void*)(memio->memory+to),
565                   (void*)(memio->memory+from),
566                   overlap);
567        } else { /*((to + nbytes) > from) */
568            overlap = ((to + nbytes) - from); /* # bytes of overlap */
569            nbytes1 = (nbytes - overlap); /* # bytes of non-overlap */
570            /* move the non-overlapping part */
571            memcpy((void*)(memio->memory+to),
572                   (void*)(memio->memory+from),
573                   nbytes1);
574            /* move the overlapping part */
575            memcpy((void*)(memio->memory+(to+nbytes1)),
576                   (void*)(memio->memory+(from+nbytes1)),
577                   overlap);
578        }
579#endif
580    } else {/* no overlap */
581        memcpy((void*)(memio->memory+to),(void*)(memio->memory+from),nbytes);
582    }
583    return status;
584}
585
586static int
587memio_rel(ncio* const nciop, off_t offset, int rflags)
588{
589    NCMEMIO* memio;
590    if(nciop == NULL || nciop->pvt == NULL) return NC_EINVAL;
591    memio = (NCMEMIO*)nciop->pvt;
592    memio->locked--;
593    return NC_NOERR; /* do nothing */
594}
595
596/*
597 * Write out any dirty buffers to disk and
598 * ensure that next read will get data from disk.
599 */
600static int
601memio_sync(ncio* const nciop)
602{
603    return NC_NOERR; /* do nothing */
604}
Note: See TracBrowser for help on using the repository browser.