diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2004-06-05 19:10:41 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2004-06-05 19:10:41 (GMT) |
commit | 1437b0bde7528fd6603769580394f9fcb5a47301 (patch) | |
tree | cb2686042b74094ea80e352c63618c1415f5318b /src/H5Fistore.c | |
parent | 28404e2813b982ea7374a8cd0513f9cf17a07c35 (diff) | |
download | hdf5-1437b0bde7528fd6603769580394f9fcb5a47301.zip hdf5-1437b0bde7528fd6603769580394f9fcb5a47301.tar.gz hdf5-1437b0bde7528fd6603769580394f9fcb5a47301.tar.bz2 |
[svn-r8616] Purpose:
Rename these files
Description:
Since these files contain functions that are part of the dataset information
now, rename them to H5D<foo>.c
Diffstat (limited to 'src/H5Fistore.c')
-rw-r--r-- | src/H5Fistore.c | 3141 |
1 files changed, 0 insertions, 3141 deletions
diff --git a/src/H5Fistore.c b/src/H5Fistore.c deleted file mode 100644 index 032a776..0000000 --- a/src/H5Fistore.c +++ /dev/null @@ -1,3141 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * 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 files COPYING and Copyright.html. COPYING can be found at the root * - * of the source code distribution tree; Copyright.html can be found at the * - * root level of an installed copy of the electronic HDF5 document set and * - * is linked from the top-level documents page. It can also be found at * - * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * - * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* Programmer: Robb Matzke <matzke@llnl.gov> - * Wednesday, October 8, 1997 - * - * Purpose: Indexed (chunked) I/O functions. The logical - * multi-dimensional data space is regularly partitioned into - * same-sized "chunks", the first of which is aligned with the - * logical origin. The chunks are given a multi-dimensional - * index which is used as a lookup key in a B-tree that maps - * chunk index to disk address. Each chunk can be compressed - * independently and the chunks may move around in the file as - * their storage requirements change. - * - * Cache: Disk I/O is performed in units of chunks and H5MF_alloc() - * contains code to optionally align chunks on disk block - * boundaries for performance. - * - * The chunk cache is an extendible hash indexed by a function - * of storage B-tree address and chunk N-dimensional offset - * within the dataset. Collisions are not resolved -- one of - * the two chunks competing for the hash slot must be preempted - * from the cache. All entries in the hash also participate in - * a doubly-linked list and entries are penalized by moving them - * toward the front of the list. When a new chunk is about to - * be added to the cache the heap is pruned by preempting - * entries near the front of the list to make room for the new - * entry which is added to the end of the list. - */ - -#define H5B_PACKAGE /*suppress error about including H5Bpkg */ -#define H5D_PACKAGE /*suppress error about including H5Dpkg */ - -/* Pablo information */ -/* (Put before include files to avoid problems with inline functions) */ -#define PABLO_MASK H5Distore_mask - -#include "H5private.h" /* Generic Functions */ -#include "H5Bpkg.h" /* B-link trees */ -#include "H5Dpkg.h" /* Datasets */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5Fprivate.h" /* Files */ -#include "H5FDprivate.h" /* File drivers */ -#include "H5FLprivate.h" /* Free Lists */ -#include "H5Iprivate.h" /* IDs */ -#include "H5MFprivate.h" /* File space management */ -#include "H5MMprivate.h" /* Memory management */ -#include "H5Oprivate.h" /* Object headers */ -#include "H5Pprivate.h" /* Property lists */ -#include "H5Sprivate.h" /* Dataspaces */ -#include "H5Vprivate.h" /* Vector and array functions */ - -/* - * Feature: If this constant is defined then every cache preemption and load - * causes a character to be printed on the standard error stream: - * - * `.': Entry was preempted because it has been completely read or - * completely written but not partially read and not partially - * written. This is often a good reason for preemption because such - * a chunk will be unlikely to be referenced in the near future. - * - * `:': Entry was preempted because it hasn't been used recently. - * - * `#': Entry was preempted because another chunk collided with it. This - * is usually a relatively bad thing. If there are too many of - * these then the number of entries in the cache can be increased. - * - * c: Entry was preempted because the file is closing. - * - * w: A chunk read operation was eliminated because the library is - * about to write new values to the entire chunk. This is a good - * thing, especially on files where the chunk size is the same as - * the disk block size, chunks are aligned on disk block boundaries, - * and the operating system can also eliminate a read operation. - */ - -/*#define H5D_ISTORE_DEBUG */ - -/* Interface initialization */ -static int interface_initialize_g = 0; -#define INTERFACE_INIT NULL - -/* - * Given a B-tree node return the dimensionality of the chunks pointed to by - * that node. - */ -#define H5D_ISTORE_NDIMS(X) ((int)(((X)->sizeof_rkey-8)/8)) - -/* Raw data chunks are cached. Each entry in the cache is: */ -typedef struct H5D_rdcc_ent_t { - hbool_t locked; /*entry is locked in cache */ - hbool_t dirty; /*needs to be written to disk? */ - hssize_t offset[H5O_LAYOUT_NDIMS]; /*chunk name */ - size_t rd_count; /*bytes remaining to be read */ - size_t wr_count; /*bytes remaining to be written */ - size_t chunk_size; /*size of a chunk */ - size_t alloc_size; /*amount allocated for the chunk */ - uint8_t *chunk; /*the unfiltered chunk data */ - unsigned idx; /*index in hash table */ - struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */ - struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */ -} H5D_rdcc_ent_t; -typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */ - -/* - * B-tree key. A key contains the minimum logical N-dimensional address and - * the logical size of the chunk to which this key refers. The - * fastest-varying dimension is assumed to reference individual bytes of the - * array, so a 100-element 1-d array of 4-byte integers would really be a 2-d - * array with the slow varying dimension of size 100 and the fast varying - * dimension of size 4 (the storage dimensionality has very little to do with - * the real dimensionality). - * - * Only the first few values of the OFFSET and SIZE fields are actually - * stored on disk, depending on the dimensionality. - * - * The chunk's file address is part of the B-tree and not part of the key. - */ -typedef struct H5D_istore_key_t { - size_t nbytes; /*size of stored data */ - hssize_t offset[H5O_LAYOUT_NDIMS]; /*logical offset to start*/ - unsigned filter_mask; /*excluded filters */ -} H5D_istore_key_t; - -typedef struct H5D_istore_ud1_t { - H5D_istore_key_t key; /*key values */ - haddr_t addr; /*file address of chunk */ - H5O_layout_t mesg; /*layout message */ - hsize_t total_storage; /*output from iterator */ - FILE *stream; /*debug output stream */ - hsize_t *dims; /*dataset dimensions */ -} H5D_istore_ud1_t; - -#define H5D_HASH(D,ADDR) H5F_addr_hash(ADDR,(D)->cache.chunk.nslots) - -/* Private prototypes */ -static haddr_t H5D_istore_get_addr(H5F_t *f, hid_t dxpl_id, const H5O_layout_t *layout, - const hssize_t offset[], H5D_istore_ud1_t *_udata); -static void *H5D_istore_chunk_alloc(size_t size, const H5O_pline_t *pline); -static void *H5D_istore_chunk_xfree(void *chk, const H5O_pline_t *pline); - -/* B-tree iterator callbacks */ -static int H5D_istore_iter_allocated(H5F_t *f, hid_t dxpl_id, void *left_key, haddr_t addr, - void *right_key, void *_udata); -static int H5D_istore_iter_dump(H5F_t *f, hid_t dxpl_id, void *left_key, haddr_t addr, - void *right_key, void *_udata); -static int H5D_istore_prune_extent(H5F_t *f, hid_t dxpl_id, void *_lt_key, haddr_t addr, - void *_rt_key, void *_udata); - -/* B-tree callbacks */ -static size_t H5D_istore_sizeof_rkey(H5F_t *f, const void *_udata); -static herr_t H5D_istore_new_node(H5F_t *f, hid_t dxpl_id, H5B_ins_t, void *_lt_key, - void *_udata, void *_rt_key, - haddr_t *addr_p /*out*/); -static int H5D_istore_cmp2(H5F_t *f, hid_t dxpl_id, void *_lt_key, void *_udata, - void *_rt_key); -static int H5D_istore_cmp3(H5F_t *f, hid_t dxpl_id, void *_lt_key, void *_udata, - void *_rt_key); -static herr_t H5D_istore_found(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void *_lt_key, - void *_udata, const void *_rt_key); -static H5B_ins_t H5D_istore_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key, - hbool_t *lt_key_changed, void *_md_key, - void *_udata, void *_rt_key, - hbool_t *rt_key_changed, - haddr_t *new_node/*out*/); -static H5B_ins_t H5D_istore_remove( H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key, - hbool_t *lt_key_changed, void *_udata, void *_rt_key, - hbool_t *rt_key_changed); -static herr_t H5D_istore_decode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, - void *_key); -static herr_t H5D_istore_encode_key(H5F_t *f, H5B_t *bt, uint8_t *raw, - void *_key); -static herr_t H5D_istore_debug_key(FILE *stream, H5F_t *f, hid_t dxpl_id, - int indent, int fwidth, const void *key, - const void *udata); - -/* inherits B-tree like properties from H5B */ -H5B_class_t H5B_ISTORE[1] = {{ - H5B_ISTORE_ID, /*id */ - sizeof(H5D_istore_key_t), /*sizeof_nkey */ - H5D_istore_sizeof_rkey, /*get_sizeof_rkey */ - H5D_istore_new_node, /*new */ - H5D_istore_cmp2, /*cmp2 */ - H5D_istore_cmp3, /*cmp3 */ - H5D_istore_found, /*found */ - H5D_istore_insert, /*insert */ - FALSE, /*follow min branch? */ - FALSE, /*follow max branch? */ - H5D_istore_remove, /*remove */ - H5D_istore_decode_key, /*decode */ - H5D_istore_encode_key, /*encode */ - H5D_istore_debug_key, /*debug */ -}}; - -/* Declare a free list to manage H5F_rdcc_ent_t objects */ -H5FL_DEFINE_STATIC(H5D_rdcc_ent_t); - -/* Declare a free list to manage the H5F_rdcc_ent_ptr_t sequence information */ -H5FL_SEQ_DEFINE_STATIC(H5D_rdcc_ent_ptr_t); - -/* Declare a free list to manage the chunk sequence information */ -H5FL_BLK_DEFINE_STATIC(chunk); - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_sizeof_rkey - * - * Purpose: Returns the size of a raw key for the specified UDATA. The - * size of the key is dependent on the number of dimensions for - * the object to which this B-tree points. The dimensionality - * of the UDATA is the only portion that's referenced here. - * - * Return: Success: Size of raw key in bytes. - * - * Failure: abort() - * - * Programmer: Robb Matzke - * Wednesday, October 8, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static size_t -H5D_istore_sizeof_rkey(H5F_t UNUSED *f, const void *_udata) -{ - const H5D_istore_ud1_t *udata = (const H5D_istore_ud1_t *) _udata; - size_t nbytes; - - /* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_sizeof_rkey); - - assert(udata); - assert(udata->mesg.u.chunk.ndims > 0 && udata->mesg.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - - nbytes = 4 + /*storage size */ - 4 + /*filter mask */ - udata->mesg.u.chunk.ndims*8; /*dimension indices */ - - FUNC_LEAVE_NOAPI(nbytes); -} /* end H5D_istore_sizeof_rkey() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_decode_key - * - * Purpose: Decodes a raw key into a native key for the B-tree - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Friday, October 10, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_decode_key(H5F_t UNUSED *f, H5B_t *bt, uint8_t *raw, void *_key) -{ - H5D_istore_key_t *key = (H5D_istore_key_t *) _key; - int i; - int ndims = H5D_ISTORE_NDIMS(bt); - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_decode_key, FAIL); - - /* check args */ - assert(f); - assert(bt); - assert(raw); - assert(key); - assert(ndims>0 && ndims<=H5O_LAYOUT_NDIMS); - - /* decode */ - UINT32DECODE(raw, key->nbytes); - UINT32DECODE(raw, key->filter_mask); - for (i=0; i<ndims; i++) - UINT64DECODE(raw, key->offset[i]); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_decode_key() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_encode_key - * - * Purpose: Encode a key from native format to raw format. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Friday, October 10, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_encode_key(H5F_t UNUSED *f, H5B_t *bt, uint8_t *raw, void *_key) -{ - H5D_istore_key_t *key = (H5D_istore_key_t *) _key; - int ndims = H5D_ISTORE_NDIMS(bt); - int i; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_encode_key, FAIL); - - /* check args */ - assert(f); - assert(bt); - assert(raw); - assert(key); - assert(ndims>0 && ndims<=H5O_LAYOUT_NDIMS); - - /* encode */ - UINT32ENCODE(raw, key->nbytes); - UINT32ENCODE(raw, key->filter_mask); - for (i=0; i<ndims; i++) - UINT64ENCODE(raw, key->offset[i]); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_encode_key() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_debug_key - * - * Purpose: Prints a key. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, April 16, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_debug_key (FILE *stream, H5F_t UNUSED *f, hid_t UNUSED dxpl_id, int indent, int fwidth, - const void *_key, const void *_udata) -{ - const H5D_istore_key_t *key = (const H5D_istore_key_t *)_key; - const H5D_istore_ud1_t *udata = (const H5D_istore_ud1_t *)_udata; - unsigned u; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_debug_key, FAIL); - - assert (key); - - HDfprintf(stream, "%*s%-*s %Zd bytes\n", indent, "", fwidth, - "Chunk size:", key->nbytes); - HDfprintf(stream, "%*s%-*s 0x%08x\n", indent, "", fwidth, - "Filter mask:", key->filter_mask); - HDfprintf(stream, "%*s%-*s {", indent, "", fwidth, - "Logical offset:"); - for (u=0; u<udata->mesg.u.chunk.ndims; u++) - HDfprintf (stream, "%s%Hd", u?", ":"", key->offset[u]); - HDfputs ("}\n", stream); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_debug_key() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_cmp2 - * - * Purpose: Compares two keys sort of like strcmp(). The UDATA pointer - * is only to supply extra information not carried in the keys - * (in this case, the dimensionality) and is not compared - * against the keys. - * - * Return: Success: -1 if LT_KEY is less than RT_KEY; - * 1 if LT_KEY is greater than RT_KEY; - * 0 if LT_KEY and RT_KEY are equal. - * - * Failure: FAIL (same as LT_KEY<RT_KEY) - * - * Programmer: Robb Matzke - * Thursday, November 6, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static int -H5D_istore_cmp2(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, void *_lt_key, void *_udata, - void *_rt_key) -{ - H5D_istore_key_t *lt_key = (H5D_istore_key_t *) _lt_key; - H5D_istore_key_t *rt_key = (H5D_istore_key_t *) _rt_key; - H5D_istore_ud1_t *udata = (H5D_istore_ud1_t *) _udata; - int ret_value; - - FUNC_ENTER_NOAPI(H5D_istore_cmp2, FAIL); - - assert(lt_key); - assert(rt_key); - assert(udata); - assert(udata->mesg.u.chunk.ndims > 0 && udata->mesg.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - - /* Compare the offsets but ignore the other fields */ - ret_value = H5V_vector_cmp_s(udata->mesg.u.chunk.ndims, lt_key->offset, rt_key->offset); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_cmp2() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_cmp3 - * - * Purpose: Compare the requested datum UDATA with the left and right - * keys of the B-tree. - * - * Return: Success: negative if the min_corner of UDATA is less - * than the min_corner of LT_KEY. - * - * positive if the min_corner of UDATA is - * greater than or equal the min_corner of - * RT_KEY. - * - * zero otherwise. The min_corner of UDATA is - * not necessarily contained within the address - * space represented by LT_KEY, but a key that - * would describe the UDATA min_corner address - * would fall lexicographically between LT_KEY - * and RT_KEY. - * - * Failure: FAIL (same as UDATA < LT_KEY) - * - * Programmer: Robb Matzke - * Wednesday, October 8, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static int -H5D_istore_cmp3(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, void *_lt_key, void *_udata, - void *_rt_key) -{ - H5D_istore_key_t *lt_key = (H5D_istore_key_t *) _lt_key; - H5D_istore_key_t *rt_key = (H5D_istore_key_t *) _rt_key; - H5D_istore_ud1_t *udata = (H5D_istore_ud1_t *) _udata; - int ret_value = 0; - - FUNC_ENTER_NOAPI(H5D_istore_cmp3, FAIL); - - assert(lt_key); - assert(rt_key); - assert(udata); - assert(udata->mesg.u.chunk.ndims > 0 && udata->mesg.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - - if (H5V_vector_lt_s(udata->mesg.u.chunk.ndims, udata->key.offset, - lt_key->offset)) { - ret_value = -1; - } else if (H5V_vector_ge_s(udata->mesg.u.chunk.ndims, udata->key.offset, - rt_key->offset)) { - ret_value = 1; - } - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_cmp3() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_new_node - * - * Purpose: Adds a new entry to an i-storage B-tree. We can assume that - * the domain represented by UDATA doesn't intersect the domain - * already represented by the B-tree. - * - * Return: Success: Non-negative. The address of leaf is returned - * through the ADDR argument. It is also added - * to the UDATA. - * - * Failure: Negative - * - * Programmer: Robb Matzke - * Tuesday, October 14, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_new_node(H5F_t *f, hid_t dxpl_id, H5B_ins_t op, - void *_lt_key, void *_udata, void *_rt_key, - haddr_t *addr_p/*out*/) -{ - H5D_istore_key_t *lt_key = (H5D_istore_key_t *) _lt_key; - H5D_istore_key_t *rt_key = (H5D_istore_key_t *) _rt_key; - H5D_istore_ud1_t *udata = (H5D_istore_ud1_t *) _udata; - unsigned u; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_new_node, FAIL); - - /* check args */ - assert(f); - assert(lt_key); - assert(rt_key); - assert(udata); - assert(udata->mesg.u.chunk.ndims > 0 && udata->mesg.u.chunk.ndims < H5O_LAYOUT_NDIMS); - assert(addr_p); - - /* Allocate new storage */ - assert (udata->key.nbytes > 0); - H5_CHECK_OVERFLOW( udata->key.nbytes ,size_t, hsize_t); - if (HADDR_UNDEF==(*addr_p=H5MF_alloc(f, H5FD_MEM_DRAW, dxpl_id, (hsize_t)udata->key.nbytes))) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "couldn't allocate new file storage"); - udata->addr = *addr_p; - - /* - * The left key describes the storage of the UDATA chunk being - * inserted into the tree. - */ - lt_key->nbytes = udata->key.nbytes; - lt_key->filter_mask = udata->key.filter_mask; - for (u=0; u<udata->mesg.u.chunk.ndims; u++) - lt_key->offset[u] = udata->key.offset[u]; - - /* - * The right key might already be present. If not, then add a zero-width - * chunk. - */ - if (H5B_INS_LEFT != op) { - rt_key->nbytes = 0; - rt_key->filter_mask = 0; - for (u=0; u<udata->mesg.u.chunk.ndims; u++) { - assert (udata->key.offset[u]+(hssize_t)(udata->mesg.u.chunk.dim[u]) > - udata->key.offset[u]); - rt_key->offset[u] = udata->key.offset[u] + - (hssize_t)(udata->mesg.u.chunk.dim[u]); - } - } - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_new_node() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_found - * - * Purpose: This function is called when the B-tree search engine has - * found the leaf entry that points to a chunk of storage that - * contains the beginning of the logical address space - * represented by UDATA. The LT_KEY is the left key (the one - * that describes the chunk) and RT_KEY is the right key (the - * one that describes the next or last chunk). - * - * Note: It's possible that the chunk isn't really found. For - * instance, in a sparse dataset the requested chunk might fall - * between two stored chunks in which case this function is - * called with the maximum stored chunk indices less than the - * requested chunk indices. - * - * Return: Non-negative on success with information about the chunk - * returned through the UDATA argument. Negative on failure. - * - * Programmer: Robb Matzke - * Thursday, October 9, 1997 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_found(H5F_t UNUSED *f, hid_t UNUSED dxpl_id, haddr_t addr, const void *_lt_key, - void *_udata, const void UNUSED *_rt_key) -{ - H5D_istore_ud1_t *udata = (H5D_istore_ud1_t *) _udata; - const H5D_istore_key_t *lt_key = (const H5D_istore_key_t *) _lt_key; - unsigned u; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_found, FAIL); - - /* Check arguments */ - assert(f); - assert(H5F_addr_defined(addr)); - assert(udata); - assert(lt_key); - - /* Is this *really* the requested chunk? */ - for (u=0; u<udata->mesg.u.chunk.ndims; u++) { - if (udata->key.offset[u] >= lt_key->offset[u]+(hssize_t)(udata->mesg.u.chunk.dim[u])) - HGOTO_DONE(FAIL); - } - - /* Initialize return values */ - udata->addr = addr; - udata->key.nbytes = lt_key->nbytes; - udata->key.filter_mask = lt_key->filter_mask; - assert (lt_key->nbytes>0); - for (u = 0; u < udata->mesg.u.chunk.ndims; u++) - udata->key.offset[u] = lt_key->offset[u]; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_found() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_insert - * - * Purpose: This function is called when the B-tree insert engine finds - * the node to use to insert new data. The UDATA argument - * points to a struct that describes the logical addresses being - * added to the file. This function allocates space for the - * data and returns information through UDATA describing a - * file chunk to receive (part of) the data. - * - * The LT_KEY is always the key describing the chunk of file - * memory at address ADDR. On entry, UDATA describes the logical - * addresses for which storage is being requested (through the - * `offset' and `size' fields). On return, UDATA describes the - * logical addresses contained in a chunk on disk. - * - * Return: Success: An insertion command for the caller, one of - * the H5B_INS_* constants. The address of the - * new chunk is returned through the NEW_NODE - * argument. - * - * Failure: H5B_INS_ERROR - * - * Programmer: Robb Matzke - * Thursday, October 9, 1997 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. The NEW_NODE argument - * is renamed NEW_NODE_P. - *------------------------------------------------------------------------- - */ -static H5B_ins_t -H5D_istore_insert(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key, - hbool_t UNUSED *lt_key_changed, - void *_md_key, void *_udata, void *_rt_key, - hbool_t UNUSED *rt_key_changed, - haddr_t *new_node_p/*out*/) -{ - H5D_istore_key_t *lt_key = (H5D_istore_key_t *) _lt_key; - H5D_istore_key_t *md_key = (H5D_istore_key_t *) _md_key; - H5D_istore_key_t *rt_key = (H5D_istore_key_t *) _rt_key; - H5D_istore_ud1_t *udata = (H5D_istore_ud1_t *) _udata; - int cmp; - unsigned u; - H5B_ins_t ret_value; - - FUNC_ENTER_NOAPI(H5D_istore_insert, H5B_INS_ERROR); - - /* check args */ - assert(f); - assert(H5F_addr_defined(addr)); - assert(lt_key); - assert(lt_key_changed); - assert(md_key); - assert(udata); - assert(rt_key); - assert(rt_key_changed); - assert(new_node_p); - - cmp = H5D_istore_cmp3(f, dxpl_id, lt_key, udata, rt_key); - assert(cmp <= 0); - - if (cmp < 0) { - /* Negative indices not supported yet */ - assert("HDF5 INTERNAL ERROR -- see rpm" && 0); - HGOTO_ERROR(H5E_STORAGE, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error"); - - } else if (H5V_vector_eq_s (udata->mesg.u.chunk.ndims, - udata->key.offset, lt_key->offset) && - lt_key->nbytes>0) { - /* - * Already exists. If the new size is not the same as the old size - * then we should reallocate storage. - */ - if (lt_key->nbytes != udata->key.nbytes) { -/* Currently, the old chunk data is "thrown away" after the space is reallocated, - * so avoid data copy in H5MF_realloc() call by just free'ing the space and - * allocating new space. - * - * This should keep the file smaller also, by freeing the space and then - * allocating new space, instead of vice versa (in H5MF_realloc). - * - * QAK - 11/19/2002 - */ -#ifdef OLD_WAY - if (HADDR_UNDEF==(*new_node_p=H5MF_realloc(f, H5FD_MEM_DRAW, addr, - (hsize_t)lt_key->nbytes, (hsize_t)udata->key.nbytes))) - HGOTO_ERROR (H5E_STORAGE, H5E_NOSPACE, H5B_INS_ERROR, "unable to reallocate chunk storage"); -#else /* OLD_WAY */ - H5_CHECK_OVERFLOW( lt_key->nbytes ,size_t, hsize_t); - if (H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes)<0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTFREE, H5B_INS_ERROR, "unable to free chunk"); - H5_CHECK_OVERFLOW( udata->key.nbytes ,size_t, hsize_t); - if (HADDR_UNDEF==(*new_node_p=H5MF_alloc(f, H5FD_MEM_DRAW, dxpl_id, (hsize_t)udata->key.nbytes))) - HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, H5B_INS_ERROR, "unable to reallocate chunk"); -#endif /* OLD_WAY */ - lt_key->nbytes = udata->key.nbytes; - lt_key->filter_mask = udata->key.filter_mask; - *lt_key_changed = TRUE; - udata->addr = *new_node_p; - ret_value = H5B_INS_CHANGE; - } else { - udata->addr = addr; - ret_value = H5B_INS_NOOP; - } - - } else if (H5V_hyper_disjointp(udata->mesg.u.chunk.ndims, - lt_key->offset, udata->mesg.u.chunk.dim, - udata->key.offset, udata->mesg.u.chunk.dim)) { - assert(H5V_hyper_disjointp(udata->mesg.u.chunk.ndims, - rt_key->offset, udata->mesg.u.chunk.dim, - udata->key.offset, udata->mesg.u.chunk.dim)); - /* - * Split this node, inserting the new new node to the right of the - * current node. The MD_KEY is where the split occurs. - */ - md_key->nbytes = udata->key.nbytes; - md_key->filter_mask = udata->key.filter_mask; - for (u=0; u<udata->mesg.u.chunk.ndims; u++) { - assert(0 == udata->key.offset[u] % udata->mesg.u.chunk.dim[u]); - md_key->offset[u] = udata->key.offset[u]; - } - - /* - * Allocate storage for the new chunk - */ - H5_CHECK_OVERFLOW( udata->key.nbytes ,size_t, hsize_t); - if (HADDR_UNDEF==(*new_node_p=H5MF_alloc(f, H5FD_MEM_DRAW, dxpl_id, (hsize_t)udata->key.nbytes))) - HGOTO_ERROR(H5E_STORAGE, H5E_NOSPACE, H5B_INS_ERROR, "file allocation failed"); - udata->addr = *new_node_p; - ret_value = H5B_INS_RIGHT; - - } else { - assert("HDF5 INTERNAL ERROR -- see rpm" && 0); - HGOTO_ERROR(H5E_IO, H5E_UNSUPPORTED, H5B_INS_ERROR, "internal error"); - } - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_insert() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_iter_allocated - * - * Purpose: Simply counts the number of chunks for a dataset. - * - * Return: Success: Non-negative - * - * Failure: Negative - * - * Programmer: Robb Matzke - * Wednesday, April 21, 1999 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - * - * Quincey Koziol, 2002-04-22 - * Changed to callback from H5B_iterate - *------------------------------------------------------------------------- - */ -static int -H5D_istore_iter_allocated (H5F_t UNUSED *f, hid_t UNUSED dxpl_id, void *_lt_key, haddr_t UNUSED addr, - void UNUSED *_rt_key, void *_udata) -{ - H5D_istore_ud1_t *bt_udata = (H5D_istore_ud1_t *)_udata; - H5D_istore_key_t *lt_key = (H5D_istore_key_t *)_lt_key; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_iter_allocated); - - bt_udata->total_storage += lt_key->nbytes; - - FUNC_LEAVE_NOAPI(H5B_ITER_CONT); -} /* H5D_istore_iter_allocated() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_iter_dump - * - * Purpose: If the UDATA.STREAM member is non-null then debugging - * information is written to that stream. - * - * Return: Success: Non-negative - * - * Failure: Negative - * - * Programmer: Robb Matzke - * Wednesday, April 21, 1999 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - * - * Quincey Koziol, 2002-04-22 - * Changed to callback from H5B_iterate - *------------------------------------------------------------------------- - */ -static int -H5D_istore_iter_dump (H5F_t UNUSED *f, hid_t UNUSED dxpl_id, void *_lt_key, haddr_t UNUSED addr, - void UNUSED *_rt_key, void *_udata) -{ - H5D_istore_ud1_t *bt_udata = (H5D_istore_ud1_t *)_udata; - H5D_istore_key_t *lt_key = (H5D_istore_key_t *)_lt_key; - unsigned u; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_iter_dump); - - if (bt_udata->stream) { - if (0==bt_udata->total_storage) { - fprintf(bt_udata->stream, - " Flags Bytes Address Logical Offset\n"); - fprintf(bt_udata->stream, - " ========== ======== ========== " - "==============================\n"); - } - HDfprintf(bt_udata->stream, " 0x%08x %8Zu %10a [", - lt_key->filter_mask, lt_key->nbytes, addr); - for (u=0; u<bt_udata->mesg.u.chunk.ndims; u++) - HDfprintf(bt_udata->stream, "%s%Hd", u?", ":"", lt_key->offset[u]); - HDfputs("]\n", bt_udata->stream); - - /* Use "total storage" information as flag for printing headers */ - bt_udata->total_storage++; - } - - FUNC_LEAVE_NOAPI(H5B_ITER_CONT); -} /* H5D_istore_iter_dump() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_init - * - * Purpose: Initialize the raw data chunk cache for a dataset. This is - * called when the dataset is initialized. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Monday, May 18, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_init (H5F_t *f, H5D_t *dset) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_init, FAIL); - - HDmemset (rdcc, 0, sizeof(H5D_rdcc_t)); - if (H5F_RDCC_NBYTES(f)>0 && H5F_RDCC_NELMTS(f)>0) { - rdcc->nbytes=H5F_RDCC_NBYTES(f); - rdcc->nslots = H5F_RDCC_NELMTS(f); - rdcc->slot = H5FL_SEQ_CALLOC (H5D_rdcc_ent_ptr_t,rdcc->nslots); - if (NULL==rdcc->slot) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_init() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_flush_entry - * - * Purpose: Writes a chunk to disk. If RESET is non-zero then the - * entry is cleared -- it's slightly faster to flush a chunk if - * the RESET flag is turned on because it results in one fewer - * memory copy. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_flush_entry(H5F_t *f, const H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t reset) -{ - herr_t ret_value=SUCCEED; /*return value */ - unsigned u; /*counters */ - void *buf=NULL; /*temporary buffer */ - size_t alloc; /*bytes allocated for BUF */ - hbool_t point_of_no_return = FALSE; - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_flush_entry); - - assert(f); - assert(ent); - assert(!ent->locked); - - buf = ent->chunk; - if (ent->dirty) { - H5D_istore_ud1_t udata; /*pass through B-tree */ - - udata.mesg = dset->layout; - udata.key.filter_mask = 0; - udata.addr = HADDR_UNDEF; - udata.key.nbytes = ent->chunk_size; - for (u=0; u<dset->layout.u.chunk.ndims; u++) - udata.key.offset[u] = ent->offset[u]; - alloc = ent->alloc_size; - - /* Should the chunk be filtered before writing it to disk? */ - if (dset->dcpl_cache.pline.nused) { - if (!reset) { - /* - * Copy the chunk to a new buffer before running it through - * the pipeline because we'll want to save the original buffer - * for later. - */ - alloc = ent->chunk_size; - if (NULL==(buf = H5MM_malloc(alloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline"); - HDmemcpy(buf, ent->chunk, ent->chunk_size); - } else { - /* - * If we are reseting and something goes wrong after this - * point then it's too late to recover because we may have - * destroyed the original data by calling H5Z_pipeline(). - * The only safe option is to continue with the reset - * even if we can't write the data to disk. - */ - point_of_no_return = TRUE; - ent->chunk = NULL; - } - if (H5Z_pipeline(&(dset->dcpl_cache.pline), 0, &(udata.key.filter_mask), dxpl_cache->err_detect, - dxpl_cache->filter_cb, &(udata.key.nbytes), &alloc, &buf)<0) - HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed") - } - - /* - * Create the chunk it if it doesn't exist, or reallocate the chunk if - * its size changed. Then write the data into the file. - */ - if (H5B_insert(f, dxpl_id, H5B_ISTORE, dset->layout.u.chunk.addr, &udata)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to allocate chunk"); - if (H5F_block_write(f, H5FD_MEM_DRAW, udata.addr, udata.key.nbytes, dxpl_id, buf)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file"); - - /* Mark cache entry as clean */ - ent->dirty = FALSE; - dset->cache.chunk.nflushes++; - } /* end if */ - - /* Reset, but do not free or removed from list */ - if (reset) { - point_of_no_return = FALSE; - if(buf==ent->chunk) - buf = NULL; - if(ent->chunk!=NULL) - ent->chunk = H5D_istore_chunk_xfree(ent->chunk,&(dset->dcpl_cache.pline)); - } /* end if */ - -done: - /* Free the temp buffer only if it's different than the entry chunk */ - if (buf!=ent->chunk) - H5MM_xfree(buf); - - /* - * If we reached the point of no return then we have no choice but to - * reset the entry. This can only happen if RESET is true but the - * output pipeline failed. Do not free the entry or remove it from the - * list. - */ - if (ret_value<0 && point_of_no_return) { - if(ent->chunk) - ent->chunk = H5D_istore_chunk_xfree(ent->chunk,&(dset->dcpl_cache.pline)); - } /* end if */ - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_flush_entry() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_preempt - * - * Purpose: Preempts the specified entry from the cache, flushing it to - * disk if necessary. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Pedro Vicente, March 28, 2002 - * Added flush parameter that switches the call to H5F_istore_flush_entry - * The call with FALSE is used by the H5F_istore_prune_by_extent function - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_preempt(H5F_t *f, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - H5D_t *dset, H5D_rdcc_ent_t * ent, hbool_t flush) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_preempt); - - assert(f); - assert(ent); - assert(!ent->locked); - assert(ent->idx < rdcc->nslots); - - if(flush) { - /* Flush */ - if(H5D_istore_flush_entry(f, dxpl_cache, dxpl_id, dset, ent, TRUE) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "cannot flush indexed storage buffer"); - } - else { - /* Don't flush, just free chunk */ - if(ent->chunk != NULL) - ent->chunk = H5D_istore_chunk_xfree(ent->chunk,&(dset->dcpl_cache.pline)); - } - - /* Unlink from list */ - if(ent->prev) - ent->prev->next = ent->next; - else - rdcc->head = ent->next; - if(ent->next) - ent->next->prev = ent->prev; - else - rdcc->tail = ent->prev; - ent->prev = ent->next = NULL; - - /* Remove from cache */ - rdcc->slot[ent->idx] = NULL; - ent->idx = UINT_MAX; - rdcc->nbytes -= ent->chunk_size; - --rdcc->nused; - - /* Free */ - H5FL_FREE(H5D_rdcc_ent_t, ent); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_preempt() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_flush - * - * Purpose: Writes all dirty chunks to disk and optionally preempts them - * from the cache. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Pedro Vicente, March 28, 2002 - * Added TRUE parameter to the call to H5F_istore_preempt - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_flush (H5F_t *f, hid_t dxpl_id, H5D_t *dset, unsigned flags) -{ - H5D_dxpl_cache_t dxpl_cache; /* Cached data transfer properties */ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - int nerrors=0; - H5D_rdcc_ent_t *ent=NULL, *next=NULL; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_flush, FAIL); - - /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") - - for (ent=rdcc->head; ent; ent=next) { - next = ent->next; - if ((flags&H5F_FLUSH_CLEAR_ONLY)) { - /* Just mark cache entry as clean */ - ent->dirty = FALSE; - } /* end if */ - else if ((flags&H5F_FLUSH_INVALIDATE)) { - if (H5D_istore_preempt(f, &dxpl_cache, dxpl_id, dset, ent, TRUE )<0) - nerrors++; - } else { - if (H5D_istore_flush_entry(f, &dxpl_cache, dxpl_id, dset, ent, FALSE)<0) - nerrors++; - } - } /* end for */ - - if (nerrors) - HGOTO_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks"); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_flush() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_dest - * - * Purpose: Destroy the entire chunk cache by flushing dirty entries, - * preempting all entries, and freeing the cache itself. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Pedro Vicente, March 28, 2002 - * Added TRUE parameter to the call to H5F_istore_preempt - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_dest (H5F_t *f, hid_t dxpl_id, H5D_t *dset) -{ - H5D_dxpl_cache_t dxpl_cache; /* Cached data transfer properties */ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - int nerrors=0; - H5D_rdcc_ent_t *ent=NULL, *next=NULL; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_dest, FAIL); - - /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") - - for (ent=rdcc->head; ent; ent=next) { -#ifdef H5D_ISTORE_DEBUG - HDfputc('c', stderr); - HDfflush(stderr); -#endif - next = ent->next; - if (H5D_istore_preempt(f, &dxpl_cache, dxpl_id, dset, ent, TRUE )<0) - nerrors++; - } - if (nerrors) - HGOTO_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks"); - - H5FL_SEQ_FREE (H5D_rdcc_ent_ptr_t,rdcc->slot); - HDmemset (rdcc, 0, sizeof(H5D_rdcc_t)); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_dest() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_prune - * - * Purpose: Prune the cache by preempting some things until the cache has - * room for something which is SIZE bytes. Only unlocked - * entries are considered for preemption. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Pedro Vicente, March 28, 2002 - * TRUE parameter to the call to H5F_istore_preempt - * - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_prune (H5F_t *f, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, H5D_t *dset, - size_t size) -{ - int i, j, nerrors=0; - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - size_t total = rdcc->nbytes; - const int nmeth=2; /*number of methods */ - int w[1]; /*weighting as an interval */ - H5D_rdcc_ent_t *p[2], *cur; /*list pointers */ - H5D_rdcc_ent_t *n[2]; /*list next pointers */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_prune); - - /* - * Preemption is accomplished by having multiple pointers (currently two) - * slide down the list beginning at the head. Pointer p(N+1) will start - * traversing the list when pointer pN reaches wN percent of the original - * list. In other words, preemption method N gets to consider entries in - * approximate least recently used order w0 percent before method N+1 - * where 100% means tha method N will run to completion before method N+1 - * begins. The pointers participating in the list traversal are each - * given a chance at preemption before any of the pointers are advanced. - */ - w[0] = (int)(rdcc->nused * H5F_RDCC_W0(f)); - p[0] = rdcc->head; - p[1] = NULL; - - while ((p[0] || p[1]) && rdcc->nbytes+size>total) { - - /* Introduce new pointers */ - for (i=0; i<nmeth-1; i++) - if (0==w[i]) - p[i+1] = rdcc->head; - - /* Compute next value for each pointer */ - for (i=0; i<nmeth; i++) - n[i] = p[i] ? p[i]->next : NULL; - - /* Give each method a chance */ - for (i=0; i<nmeth && rdcc->nbytes+size>total; i++) { - if (0==i && p[0] && !p[0]->locked && - ((0==p[0]->rd_count && 0==p[0]->wr_count) || - (0==p[0]->rd_count && p[0]->chunk_size==p[0]->wr_count) || - (p[0]->chunk_size==p[0]->rd_count && 0==p[0]->wr_count))) { - /* - * Method 0: Preempt entries that have been completely written - * and/or completely read but not entries that are partially - * written or partially read. - */ - cur = p[0]; -#ifdef H5D_ISTORE_DEBUG - HDputc('.', stderr); - HDfflush(stderr); -#endif - - } else if (1==i && p[1] && !p[1]->locked) { - /* - * Method 1: Preempt the entry without regard to - * considerations other than being locked. This is the last - * resort preemption. - */ - cur = p[1]; -#ifdef H5D_ISTORE_DEBUG - HDputc(':', stderr); - HDfflush(stderr); -#endif - - } else { - /* Nothing to preempt at this point */ - cur= NULL; - } - - if (cur) { - for (j=0; j<nmeth; j++) { - if (p[j]==cur) - p[j] = NULL; - if (n[j]==cur) - n[j] = cur->next; - } - if (H5D_istore_preempt(f, dxpl_cache, dxpl_id, dset, cur, TRUE)<0) - nerrors++; - } - } - - /* Advance pointers */ - for (i=0; i<nmeth; i++) - p[i] = n[i]; - for (i=0; i<nmeth-1; i++) - w[i] -= 1; - } - - if (nerrors) - HGOTO_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, "unable to preempt one or more raw data cache entry"); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_prune() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_lock - * - * Purpose: Return a pointer to a dataset chunk. The pointer points - * directly into the chunk cache and should not be freed - * by the caller but will be valid until it is unlocked. The - * input value IDX_HINT is used to speed up cache lookups and - * it's output value should be given to H5F_istore_unlock(). - * IDX_HINT is ignored if it is out of range, and if it points - * to the wrong entry then we fall back to the normal search - * method. - * - * If RELAX is non-zero and the chunk isn't in the cache then - * don't try to read it from the file, but just allocate an - * uninitialized buffer to hold the result. This is intended - * for output functions that are about to overwrite the entire - * chunk. - * - * Return: Success: Ptr to a file chunk. - * - * Failure: NULL - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Robb Matzke, 1999-08-02 - * The split ratios are passed in as part of the data transfer - * property list. - * - * Pedro Vicente, March 28, 2002 - * TRUE parameter to the call to H5F_istore_preempt - *------------------------------------------------------------------------- - */ -static void * -H5D_istore_lock(H5F_t *f, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - H5D_t *dset, const H5D_storage_t *store, - H5D_istore_ud1_t *udata, hbool_t relax, unsigned *idx_hint/*in,out*/) -{ - unsigned idx=0; /*hash index number */ - hbool_t found = FALSE; /*already in cache? */ - const H5O_pline_t *pline=&(dset->dcpl_cache.pline); /* I/O pipeline info */ - const H5O_layout_t *layout=&(dset->layout); /* Dataset layout */ - const H5O_fill_t *fill=&(dset->dcpl_cache.fill); /* Fill value info */ - H5D_fill_time_t fill_time=dset->dcpl_cache.fill_time; /* Fill time */ - H5D_rdcc_t *rdcc = &(dset->cache.chunk);/*raw data chunk cache*/ - H5D_rdcc_ent_t *ent = NULL; /*cache entry */ - unsigned u; /*counters */ - size_t chunk_size=0; /*size of a chunk */ - void *chunk=NULL; /*the file chunk */ - void *ret_value; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_lock); - - assert(f); - assert(dset); - assert(store); - assert(dxpl_cache); - assert(TRUE==H5P_isa_class(dxpl_id,H5P_DATASET_XFER)); - - /* Get the chunk's size */ - assert(layout->u.chunk.size>0); - H5_ASSIGN_OVERFLOW(chunk_size,layout->u.chunk.size,hsize_t,size_t); - - /* Search for the chunk in the cache */ - if (rdcc->nslots>0) { - idx=H5D_HASH(dset,store->chunk.index); - ent = rdcc->slot[idx]; - - if (ent) { - for (u=0, found=TRUE; u<dset->layout.u.chunk.ndims; u++) { - if (store->chunk.offset[u]!=ent->offset[u]) { - found = FALSE; - break; - } /* end if */ - } /* end for */ - } /* end if */ - } /* end if */ - - if (found) { - /* - * Already in the cache. Count a hit. - */ - rdcc->nhits++; - - } else if (!found && relax) { - /* - * Not in the cache, but we're about to overwrite the whole thing - * anyway, so just allocate a buffer for it but don't initialize that - * buffer with the file contents. Count this as a hit instead of a - * miss because we saved ourselves lots of work. - */ -#ifdef H5D_ISTORE_DEBUG - HDputc('w', stderr); - HDfflush(stderr); -#endif - rdcc->nhits++; - if (NULL==(chunk=H5D_istore_chunk_alloc (chunk_size,pline))) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk"); - - } else { - H5D_istore_ud1_t tmp_udata; /*B-tree pass-through */ - haddr_t chunk_addr; /* Address of chunk on disk */ - - if(udata!=NULL) - chunk_addr=udata->addr; - else { - /* Point at temporary storage for B-tree pass through */ - udata=&tmp_udata; - - /* - * Not in the cache. Read it from the file and count this as a miss - * if it's in the file or an init if it isn't. - */ - chunk_addr = H5D_istore_get_addr(f, dxpl_id, layout, store->chunk.offset, udata); - } /* end else */ - - if (H5F_addr_defined(chunk_addr)) { - size_t chunk_alloc=0; /*allocated chunk size */ - - /* - * The chunk exists on disk. - */ - /* Chunk size on disk isn't [likely] the same size as the final chunk - * size in memory, so allocate memory big enough. */ - chunk_alloc = udata->key.nbytes; - if (NULL==(chunk = H5D_istore_chunk_alloc (chunk_alloc,pline))) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk"); - if (H5F_block_read(f, H5FD_MEM_DRAW, chunk_addr, udata->key.nbytes, dxpl_id, chunk)<0) - HGOTO_ERROR (H5E_IO, H5E_READERROR, NULL, "unable to read raw data chunk"); - - if (pline->nused) - if (H5Z_pipeline(pline, H5Z_FLAG_REVERSE, &(udata->key.filter_mask), dxpl_cache->err_detect, - dxpl_cache->filter_cb, &(udata->key.nbytes), &chunk_alloc, &chunk)<0) { - HGOTO_ERROR(H5E_PLINE, H5E_READERROR, NULL, "data pipeline read failed"); - } - rdcc->nmisses++; - } else { - H5D_fill_value_t fill_status; - - /* Clear the error stack from not finding the chunk on disk */ - H5E_clear(NULL); - - /* Chunk size on disk isn't [likely] the same size as the final chunk - * size in memory, so allocate memory big enough. */ - if (NULL==(chunk = H5D_istore_chunk_alloc (chunk_size,pline))) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed for raw data chunk"); - - if (H5P_is_fill_value_defined(fill, &fill_status) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't tell if fill value defined"); - - if(fill_time==H5D_FILL_TIME_ALLOC || - (fill_time==H5D_FILL_TIME_IFSET && fill_status==H5D_FILL_VALUE_USER_DEFINED)) { - if (fill && fill->buf) { - /* - * The chunk doesn't exist in the file. Replicate the fill - * value throughout the chunk. - */ - assert(0==chunk_size % fill->size); - H5V_array_fill(chunk, fill->buf, fill->size, chunk_size/fill->size); - } else { - /* - * The chunk doesn't exist in the file and no fill value was - * specified. Assume all zeros. - */ - HDmemset (chunk, 0, chunk_size); - } /* end else */ - } /* end if */ - rdcc->ninits++; - } /* end else */ - } - assert (found || chunk_size>0); - - if (!found && rdcc->nslots>0 && chunk_size<=dset->cache.chunk.nbytes && - (!ent || !ent->locked)) { - /* - * Add the chunk to the cache only if the slot is not already locked. - * Preempt enough things from the cache to make room. - */ - if (ent) { -#ifdef H5D_ISTORE_DEBUG - HDputc('#', stderr); - HDfflush(stderr); -#endif - if (H5D_istore_preempt(f, dxpl_cache, dxpl_id, dset, ent, TRUE)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk from cache"); - } - if (H5D_istore_prune(f, dxpl_cache, dxpl_id, dset, chunk_size)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, NULL, "unable to preempt chunk(s) from cache"); - - /* Create a new entry */ - ent = H5FL_MALLOC(H5D_rdcc_ent_t); - ent->locked = 0; - ent->dirty = FALSE; - ent->chunk_size = chunk_size; - ent->alloc_size = chunk_size; - for (u=0; u<layout->u.chunk.ndims; u++) - ent->offset[u] = store->chunk.offset[u]; - ent->rd_count = chunk_size; - ent->wr_count = chunk_size; - ent->chunk = chunk; - - /* Add it to the cache */ - assert(NULL==rdcc->slot[idx]); - rdcc->slot[idx] = ent; - ent->idx = idx; - rdcc->nbytes += chunk_size; - rdcc->nused++; - - /* Add it to the linked list */ - ent->next = NULL; - if (rdcc->tail) { - rdcc->tail->next = ent; - ent->prev = rdcc->tail; - rdcc->tail = ent; - } else { - rdcc->head = rdcc->tail = ent; - ent->prev = NULL; - } - found = TRUE; - } else if (!found) { - /* - * The chunk is larger than the entire cache so we don't cache it. - * This is the reason all those arguments have to be repeated for the - * unlock function. - */ - ent = NULL; - idx = UINT_MAX; - - } else if (found) { - /* - * The chunk is not at the beginning of the cache; move it backward - * by one slot. This is how we implement the LRU preemption - * algorithm. - */ - if (ent->next) { - if (ent->next->next) - ent->next->next->prev = ent; - else - rdcc->tail = ent; - ent->next->prev = ent->prev; - if (ent->prev) - ent->prev->next = ent->next; - else - rdcc->head = ent->next; - ent->prev = ent->next; - ent->next = ent->next->next; - ent->prev->next = ent; - } - } - - /* Lock the chunk into the cache */ - if (ent) { - assert (!ent->locked); - ent->locked = TRUE; - chunk = ent->chunk; - } - - if (idx_hint) - *idx_hint = idx; - - /* Set return value */ - ret_value = chunk; - -done: - if (!ret_value) - if(chunk) - H5D_istore_chunk_xfree (chunk,pline); - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_lock() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_unlock - * - * Purpose: Unlocks a previously locked chunk. The LAYOUT, COMP, and - * OFFSET arguments should be the same as for H5F_rdcc_lock(). - * The DIRTY argument should be set to non-zero if the chunk has - * been modified since it was locked. The IDX_HINT argument is - * the returned index hint from the lock operation and BUF is - * the return value from the lock. - * - * The NACCESSED argument should be the number of bytes accessed - * for reading or writing (depending on the value of DIRTY). - * It's only purpose is to provide additional information to the - * preemption policy. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * Robb Matzke, 1999-08-02 - * The split_ratios are passed as part of the data transfer - * property list. - *------------------------------------------------------------------------- - */ -static herr_t -H5D_istore_unlock(H5F_t *f, const H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - H5D_t *dset, const H5D_storage_t *store, - hbool_t dirty, unsigned idx_hint, uint8_t *chunk, size_t naccessed) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - H5D_rdcc_ent_t *ent = NULL; - int found = -1; - unsigned u; - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_unlock); - - if (UINT_MAX==idx_hint) { - /*not in cache*/ - } else { - assert(idx_hint<rdcc->nslots); - assert(rdcc->slot[idx_hint]); - assert(rdcc->slot[idx_hint]->chunk==chunk); - found = idx_hint; - } - - if (found<0) { - /* - * It's not in the cache, probably because it's too big. If it's - * dirty then flush it to disk. In any case, free the chunk. - * Note: we have to copy the layout and filter messages so we - * don't discard the `const' qualifier. - */ - if (dirty) { - H5D_rdcc_ent_t x; - - HDmemset (&x, 0, sizeof x); - x.dirty = TRUE; - for (u=0; u<dset->layout.u.chunk.ndims; u++) - x.offset[u] = store->chunk.offset[u]; - assert(dset->layout.u.chunk.size>0); - H5_ASSIGN_OVERFLOW(x.chunk_size,dset->layout.u.chunk.size,hsize_t,size_t); - x.alloc_size = x.chunk_size; - x.chunk = chunk; - - H5D_istore_flush_entry (f, dxpl_cache, dxpl_id, dset, &x, TRUE); - } else { - if(chunk) - H5D_istore_chunk_xfree (chunk,&(dset->dcpl_cache.pline)); - } - } else { - /* - * It's in the cache so unlock it. - */ - ent = rdcc->slot[found]; - assert (ent->locked); - if (dirty) { - ent->dirty = TRUE; - ent->wr_count -= MIN (ent->wr_count, naccessed); - } else { - ent->rd_count -= MIN (ent->rd_count, naccessed); - } - ent->locked = FALSE; - } - - FUNC_LEAVE_NOAPI(SUCCEED); -} /* end H5D_istore_unlock() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_readvv - * - * Purpose: Reads a multi-dimensional buffer from (part of) an indexed raw - * storage array. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Wednesday, May 7, 2003 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -ssize_t -H5D_istore_readvv(H5F_t *f, const struct H5D_dxpl_cache_t *dxpl_cache, hid_t dxpl_id, - H5D_t *dset, const H5D_storage_t *store, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - void *buf) -{ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - haddr_t chunk_addr; /* Chunk address on disk */ - size_t u; /* Local index variables */ - ssize_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_readvv, FAIL); - - /* Check args */ - assert(f); - assert(dxpl_cache); - assert(dset && H5D_CHUNKED==dset->layout.type); - assert(dset->layout.u.chunk.ndims>0 && dset->layout.u.chunk.ndims<=H5O_LAYOUT_NDIMS); - assert(store); - assert(chunk_len_arr); - assert(chunk_offset_arr); - assert(mem_len_arr); - assert(mem_offset_arr); - assert(buf); - -#ifndef NDEBUG - for (u=0; u<dset->layout.u.chunk.ndims; u++) - assert(store->chunk.offset[u]>=0); /*negative coordinates not supported (yet) */ -#endif - - /* Get the address of this chunk on disk */ -#ifdef QAK -HDfprintf(stderr,"%s: chunk_coords={",FUNC); -for(u=0; u<dset->layout.u.chunk.ndims; u++) - HDfprintf(stderr,"%Hd%s",chunk_coords[u],(u<(dset->layout.u.chunk.ndims-1) ? ", " : "}\n")); -#endif /* QAK */ - chunk_addr=H5D_istore_get_addr(f, dxpl_id, &(dset->layout), store->chunk.offset, &udata); -#ifdef QAK -HDfprintf(stderr,"%s: chunk_addr=%a, chunk_size=%Hu\n",FUNC,chunk_addr,dset->layout.u.chunk.size); -HDfprintf(stderr,"%s: chunk_len_arr[%Zu]=%Zu\n",FUNC,*chunk_curr_seq,chunk_len_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: chunk_offset_arr[%Zu]=%Hu\n",FUNC,*chunk_curr_seq,chunk_offset_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: mem_len_arr[%Zu]=%Zu\n",FUNC,*mem_curr_seq,mem_len_arr[*mem_curr_seq]); -HDfprintf(stderr,"%s: mem_offset_arr[%Zu]=%Hu\n",FUNC,*mem_curr_seq,mem_offset_arr[*mem_curr_seq]); -#endif /* QAK */ - - /* - * If the chunk is too large to load into the cache and it has no - * filters in the pipeline (i.e. not compressed) and if the address - * for the chunk has been defined, then don't load the chunk into the - * cache, just write the data to it directly. - */ - if (dset->layout.u.chunk.size>dset->cache.chunk.nbytes && dset->dcpl_cache.pline.nused==0 && - chunk_addr!=HADDR_UNDEF) { - if ((ret_value=H5D_contig_readvv(f, dxpl_id, dset, chunk_addr, (hsize_t)dset->layout.u.chunk.size, chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_offset_arr, mem_max_nseq, mem_curr_seq, mem_len_arr, mem_offset_arr, buf))<0) - HGOTO_ERROR (H5E_IO, H5E_READERROR, FAIL, "unable to read raw data to file"); - } /* end if */ - else { - uint8_t *chunk; /* Pointer to cached chunk in memory */ - unsigned idx_hint=0; /* Cache index hint */ - ssize_t naccessed; /* Number of bytes accessed in chunk */ - - /* - * Lock the chunk, copy from application to chunk, then unlock the - * chunk. - */ - if (NULL==(chunk=H5D_istore_lock(f, dxpl_cache, dxpl_id, dset, store, - &udata, FALSE, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read raw data chunk"); - - /* Use the vectorized memory copy routine to do actual work */ - if((naccessed=H5V_memcpyvv(buf,mem_max_nseq,mem_curr_seq,mem_len_arr,mem_offset_arr,chunk,chunk_max_nseq,chunk_curr_seq,chunk_len_arr,chunk_offset_arr))<0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "vectorized memcpy failed"); - - H5_CHECK_OVERFLOW(naccessed,ssize_t,size_t); - if (H5D_istore_unlock(f, dxpl_cache, dxpl_id, dset, store, - FALSE, idx_hint, chunk, (size_t)naccessed)<0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to unlock raw data chunk"); - - /* Set return value */ - ret_value=naccessed; - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_istore_readvv() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_writevv - * - * Purpose: Writes a multi-dimensional buffer to (part of) an indexed raw - * storage array. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Friday, May 2, 2003 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -ssize_t -H5D_istore_writevv(H5F_t *f, const struct H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, H5D_t *dset, const H5D_storage_t *store, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[], - const void *buf) -{ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - haddr_t chunk_addr; /* Chunk address on disk */ - size_t u; /* Local index variables */ - ssize_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_writevv, FAIL); - - /* Check args */ - assert(f); - assert(dxpl_cache); - assert(dset && H5D_CHUNKED==dset->layout.type); - assert(dset->layout.u.chunk.ndims>0 && dset->layout.u.chunk.ndims<=H5O_LAYOUT_NDIMS); - assert(store); - assert(chunk_len_arr); - assert(chunk_offset_arr); - assert(mem_len_arr); - assert(mem_offset_arr); - assert(buf); - -#ifndef NDEBUG - for (u=0; u<dset->layout.u.chunk.ndims; u++) - assert(store->chunk.offset[u]>=0); /*negative coordinates not supported (yet) */ -#endif - - /* Get the address of this chunk on disk */ -#ifdef QAK -HDfprintf(stderr,"%s: chunk_coords={",FUNC); -for(u=0; u<dset->layout.u.chunk.ndims; u++) - HDfprintf(stderr,"%Hd%s",chunk_coords[u],(u<(dset->layout.u.chunk.ndims-1) ? ", " : "}\n")); -#endif /* QAK */ - chunk_addr=H5D_istore_get_addr(f, dxpl_id, &(dset->layout), store->chunk.offset, &udata); -#ifdef QAK -HDfprintf(stderr,"%s: chunk_addr=%a, chunk_size=%Hu\n",FUNC,chunk_addr,dset->layout.u.chunk.size); -HDfprintf(stderr,"%s: chunk_len_arr[%Zu]=%Zu\n",FUNC,*chunk_curr_seq,chunk_len_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: chunk_offset_arr[%Zu]=%Hu\n",FUNC,*chunk_curr_seq,chunk_offset_arr[*chunk_curr_seq]); -HDfprintf(stderr,"%s: mem_len_arr[%Zu]=%Zu\n",FUNC,*mem_curr_seq,mem_len_arr[*mem_curr_seq]); -HDfprintf(stderr,"%s: mem_offset_arr[%Zu]=%Hu\n",FUNC,*mem_curr_seq,mem_offset_arr[*mem_curr_seq]); -#endif /* QAK */ - - /* - * If the chunk is too large to load into the cache and it has no - * filters in the pipeline (i.e. not compressed) and if the address - * for the chunk has been defined, then don't load the chunk into the - * cache, just write the data to it directly. - * - * If MPI based VFD is used, must bypass the - * chunk-cache scheme because other MPI processes could be - * writing to other elements in the same chunk. Do a direct - * write-through of only the elements requested. - */ - if ((dset->layout.u.chunk.size>dset->cache.chunk.nbytes && dset->dcpl_cache.pline.nused==0 && chunk_addr!=HADDR_UNDEF) - || (IS_H5FD_MPI(f) && (H5F_ACC_RDWR & H5F_get_intent(f)))) { -#ifdef H5_HAVE_PARALLEL - /* Additional sanity check when operating in parallel */ - if (chunk_addr==HADDR_UNDEF || dset->dcpl_cache.pline.nused>0) - HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "unable to locate raw data chunk"); -#endif /* H5_HAVE_PARALLEL */ - if ((ret_value=H5D_contig_writevv(f, dxpl_id, dset, chunk_addr, (hsize_t)dset->layout.u.chunk.size, chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_offset_arr, mem_max_nseq, mem_curr_seq, mem_len_arr, mem_offset_arr, buf))<0) - HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file"); - } /* end if */ - else { - uint8_t *chunk; /* Pointer to cached chunk in memory */ - unsigned idx_hint=0; /* Cache index hint */ - ssize_t naccessed; /* Number of bytes accessed in chunk */ - hbool_t relax; /* Whether whole chunk is selected */ - - /* - * Lock the chunk, copy from application to chunk, then unlock the - * chunk. - */ - if(chunk_max_nseq==1 && chunk_len_arr[0] == dset->layout.u.chunk.size) - relax = TRUE; - else - relax = FALSE; - - if (NULL==(chunk=H5D_istore_lock(f, dxpl_cache, dxpl_id, dset, store, - &udata, relax, &idx_hint))) - HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "unable to read raw data chunk"); - - /* Use the vectorized memory copy routine to do actual work */ - if((naccessed=H5V_memcpyvv(chunk,chunk_max_nseq,chunk_curr_seq,chunk_len_arr,chunk_offset_arr,buf,mem_max_nseq,mem_curr_seq,mem_len_arr,mem_offset_arr))<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "vectorized memcpy failed"); - - H5_CHECK_OVERFLOW(naccessed,ssize_t,size_t); - if (H5D_istore_unlock(f, dxpl_cache, dxpl_id, dset, store, - TRUE, idx_hint, chunk, (size_t)naccessed)<0) - HGOTO_ERROR (H5E_IO, H5E_WRITEERROR, FAIL, "uanble to unlock raw data chunk"); - - /* Set return value */ - ret_value=naccessed; - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_istore_writevv() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_create - * - * Purpose: Creates a new indexed-storage B-tree and initializes the - * istore struct with information about the storage. The - * struct should be immediately written to the object header. - * - * This function must be called before passing ISTORE to any of - * the other indexed storage functions! - * - * Return: Non-negative on success (with the ISTORE argument initialized - * and ready to write to an object header). Negative on failure. - * - * Programmer: Robb Matzke - * Tuesday, October 21, 1997 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_create(H5F_t *f, hid_t dxpl_id, H5O_layout_t *layout /*out */ ) -{ - H5D_istore_ud1_t udata; -#ifndef NDEBUG - unsigned u; -#endif - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_create, FAIL); - - /* Check args */ - assert(f); - assert(layout && H5D_CHUNKED == layout->type); - assert(layout->u.chunk.ndims > 0 && layout->u.chunk.ndims <= H5O_LAYOUT_NDIMS); -#ifndef NDEBUG - for (u = 0; u < layout->u.chunk.ndims; u++) - assert(layout->u.chunk.dim[u] > 0); -#endif - - udata.mesg.u.chunk.ndims = layout->u.chunk.ndims; - if (H5B_create(f, dxpl_id, H5B_ISTORE, &udata, &(layout->u.chunk.addr)/*out*/) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "can't create B-tree"); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_create() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_allocated - * - * Purpose: Return the number of bytes allocated in the file for storage - * of raw data under the specified B-tree (ADDR is the address - * of the B-tree). - * - * Return: Success: Number of bytes stored in all chunks. - * - * Failure: 0 - * - * Programmer: Robb Matzke - * Wednesday, April 21, 1999 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - *------------------------------------------------------------------------- - */ -hsize_t -H5D_istore_allocated(H5F_t *f, hid_t dxpl_id, H5D_t *dset) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); /*raw data chunk cache */ - H5D_rdcc_ent_t *ent; /*cache entry */ - H5D_dxpl_cache_t dxpl_cache; /* Cached data transfer properties */ - H5D_istore_ud1_t udata; - hsize_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_allocated, 0); - - /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't fill dxpl cache") - - /* Search for cached chunks that haven't been written out */ - for(ent = rdcc->head; ent; ent = ent->next) { - /* Flush the chunk out to disk, to make certain the size is correct later */ - if (H5D_istore_flush_entry(f, &dxpl_cache, dxpl_id, dset, ent, FALSE)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, 0, "cannot flush indexed storage buffer"); - } /* end for */ - - HDmemset(&udata, 0, sizeof udata); - udata.mesg.u.chunk.ndims = dset->layout.u.chunk.ndims; - if (H5B_iterate(f, dxpl_id, H5B_ISTORE, H5D_istore_iter_allocated, dset->layout.u.chunk.addr, &udata)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, 0, "unable to iterate over chunk B-tree"); - - /* Set return value */ - ret_value=udata.total_storage; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_allocated() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_get_addr - * - * Purpose: Get the file address of a chunk if file space has been - * assigned. Save the retrieved information in the udata - * supplied. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Albert Cheng - * June 27, 1998 - * - * Modifications: - * Modified to return the address instead of returning it through - * a parameter - QAK, 1/30/02 - * - *------------------------------------------------------------------------- - */ -static haddr_t -H5D_istore_get_addr(H5F_t *f, hid_t dxpl_id, const H5O_layout_t *layout, - const hssize_t offset[], H5D_istore_ud1_t *_udata) -{ - H5D_istore_ud1_t tmp_udata; /* Information about a chunk */ - H5D_istore_ud1_t *udata; /* Pointer to information about a chunk */ - unsigned u; - haddr_t ret_value; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_get_addr); - - assert(f); - assert(layout && (layout->u.chunk.ndims > 0)); - assert(offset); - - /* Check for udata struct to return */ - udata = (_udata!=NULL ? _udata : &tmp_udata); - - /* Initialize the information about the chunk we are looking for */ - for (u=0; u<layout->u.chunk.ndims; u++) - udata->key.offset[u] = offset[u]; - udata->mesg = *layout; - udata->addr = HADDR_UNDEF; - - /* Go get the chunk information */ - if (H5B_find (f, dxpl_id, H5B_ISTORE, layout->u.chunk.addr, udata)<0) { - H5E_clear(NULL); - - HGOTO_ERROR(H5E_BTREE,H5E_NOTFOUND,HADDR_UNDEF,"Can't locate chunk info"); - } /* end if */ - - /* Success! Set the return value */ - ret_value=udata->addr; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_istore_get_addr() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_chunk_alloc - * - * Purpose: Allocate space for a chunk in memory. This routine allocates - * memory space for non-filtered chunks from a block free list - * and uses malloc()/free() for filtered chunks. - * - * Return: Pointer to memory for chunk on success/NULL on failure - * - * Programmer: Quincey Koziol - * April 22, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static void * -H5D_istore_chunk_alloc(size_t size, const H5O_pline_t *pline) -{ - void *ret_value=NULL; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_chunk_alloc); - - assert(size); - assert(pline); - - if(pline->nused>0) - ret_value=H5MM_malloc(size); - else - ret_value=H5FL_BLK_MALLOC(chunk,size); - - FUNC_LEAVE_NOAPI(ret_value); -} /* H5D_istore_chunk_alloc() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_chunk_xfree - * - * Purpose: Free space for a chunk in memory. This routine allocates - * memory space for non-filtered chunks from a block free list - * and uses malloc()/free() for filtered chunks. - * - * Return: NULL (never fails) - * - * Programmer: Quincey Koziol - * April 22, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static void * -H5D_istore_chunk_xfree(void *chk, const H5O_pline_t *pline) -{ - FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5D_istore_chunk_xfree); - - assert(pline); - - if(chk) { - if(pline->nused>0) - H5MM_xfree(chk); - else - H5FL_BLK_FREE(chunk,chk); - } /* end if */ - - FUNC_LEAVE_NOAPI(NULL); -} /* H5D_istore_chunk_xfree() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_allocate - * - * Purpose: Allocate file space for all chunks that are not allocated yet. - * Return SUCCEED if all needed allocation succeed, otherwise - * FAIL. - * - * Return: Non-negative on success/Negative on failure - * - * Note: Current implementation relies on cache_size being 0, - * thus no chunk is cashed and written to disk immediately - * when a chunk is unlocked (via H5F_istore_unlock) - * This should be changed to do a direct flush independent - * of the cache value. - * - * This routine might be called before the dcpl_cache is set up - * correctly, so don't use those values. - * - * Programmer: Albert Cheng - * June 26, 1998 - * - * Modifications: - * rky, 1998-09-23 - * Added barrier to preclude racing with data writes. - * - * rky, 1998-12-07 - * Added Wait-Signal wrapper around unlock-lock critical region - * to prevent race condition (unlock reads, lock writes the - * chunk). - * - * Robb Matzke, 1999-08-02 - * The split_ratios are passed in as part of the data transfer - * property list. - * - * Quincey Koziol, 2002-05-16 - * Rewrote algorithm to allocate & write blocks without using - * lock/unlock code. - * - * Quincey Koziol, 2002-05-17 - * Added feature to avoid writing fill-values if user has indicated - * that they should never be written. - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_allocate(H5F_t *f, hid_t dxpl_id, const H5D_t *dset, - hbool_t full_overwrite) -{ - hssize_t chunk_offset[H5O_LAYOUT_NDIMS]; /* Offset of current chunk */ - hsize_t chunk_size; /* Size of chunk in bytes */ - H5O_pline_t pline; /* I/O pipeline information */ - H5O_fill_t fill; /* Fill value information */ - H5D_fill_time_t fill_time; /* When to write fill values */ - H5D_fill_value_t fill_status; /* The fill value status */ - unsigned should_fill=0; /* Whether fill values should be written */ - H5D_istore_ud1_t udata; /* B-tree pass-through for creating chunk */ - void *chunk=NULL; /* Chunk buffer for writing fill values */ - H5P_genplist_t *dx_plist; /* Data xfer property list */ -#ifdef H5_HAVE_PARALLEL - MPI_Comm mpi_comm=MPI_COMM_NULL; /* MPI communicator for file */ - int mpi_rank=(-1); /* This process's rank */ - int mpi_code; /* MPI return code */ - unsigned blocks_written=0; /* Flag to indicate that chunk was actually written */ - unsigned using_mpi=0; /* Flag to indicate that the file is being accessed with an MPI-capable file driver */ -#endif /* H5_HAVE_PARALLEL */ - int carry; /* Flag to indicate that chunk increment carrys to higher dimension (sorta) */ - unsigned chunk_exists; /* Flag to indicate whether a chunk exists already */ - int i; /* Local index variable */ - unsigned u; /* Local index variable */ - H5Z_EDC_t edc; /* Decide whether to enable EDC for read */ - H5Z_cb_t cb_struct; - H5P_genplist_t *dc_plist; /* Property list */ - int space_ndims; /* Dataset's space rank */ - hsize_t space_dim[H5O_LAYOUT_NDIMS]; /* Dataset's dataspace dimensions */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_allocate, FAIL); - - /* Check args */ - assert(f); - assert(TRUE==H5P_isa_class(dxpl_id,H5P_DATASET_XFER)); - assert(dset && H5D_CHUNKED==dset->layout.type); - assert(dset->layout.u.chunk.ndims>0 && dset->layout.u.chunk.ndims<=H5O_LAYOUT_NDIMS); - assert(H5F_addr_defined(dset->layout.u.chunk.addr)); - - /* Get dataset's creation property list */ - if (NULL == (dc_plist = H5I_object(dset->dcpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list") - - /* We only handle simple data spaces so far */ - if ((space_ndims=H5S_get_simple_extent_dims(dset->space, space_dim, NULL))<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to get simple data space info") - space_dim[space_ndims] = dset->layout.u.chunk.dim[space_ndims]; - - /* Get necessary properties from dataset creation property list */ - if(H5P_get(dc_plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "can't get fill value"); - if(H5P_get(dc_plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0) - HGOTO_ERROR(H5E_STORAGE, H5E_CANTGET, FAIL, "can't get data pipeline"); - if(H5P_get(dc_plist, H5D_CRT_FILL_TIME_NAME, &fill_time) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve fill time"); - - /* Get necessary properties from dataset transfer property list */ - if (NULL == (dx_plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list"); - if(H5P_get(dx_plist,H5D_XFER_EDC_NAME,&edc)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get edc information"); - if(H5P_get(dx_plist,H5D_XFER_FILTER_CB_NAME,&cb_struct)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get filter callback struct"); - -#ifdef H5_HAVE_PARALLEL - /* Retrieve MPI parameters */ - if(IS_H5FD_MPI(f)) { - /* Get the MPI communicator */ - if (MPI_COMM_NULL == (mpi_comm=H5F_mpi_get_comm(f))) - HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI communicator"); - - /* Get the MPI rank */ - if ((mpi_rank=H5F_mpi_get_rank(f))<0) - HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, FAIL, "Can't retrieve MPI rank"); - - /* Set the MPI-capable file driver flag */ - using_mpi=1; - } /* end if */ -#endif /* H5_HAVE_PARALLEL */ - - /* - * Setup indice to go through all chunks. (Future improvement - * should allocate only chunks that have no file space assigned yet. - */ - for (u=0; u<dset->layout.u.chunk.ndims; u++) - chunk_offset[u] = 0; - chunk_size = dset->layout.u.chunk.size; - - /* Check the dataset's fill-value status */ - if (H5P_is_fill_value_defined(&fill, &fill_status) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't tell if fill value defined"); - - /* If we are filling the dataset on allocation or "if set" and - * the fill value _is_ set, _and_ we are not overwriting the new blocks, - * set the "should fill" flag - */ - if(!full_overwrite && (fill_time==H5D_FILL_TIME_ALLOC || - (fill_time==H5D_FILL_TIME_IFSET && fill_status==H5D_FILL_VALUE_USER_DEFINED))) - should_fill=1; - - /* Check if fill values should be written to blocks */ - if(should_fill) { - /* Allocate chunk buffer for processes to use when writing fill values */ - H5_CHECK_OVERFLOW(chunk_size,hsize_t,size_t); - if (NULL==(chunk = H5D_istore_chunk_alloc((size_t)chunk_size,&pline))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for chunk"); - - /* Fill the chunk with the proper values */ - if(fill.buf) { - /* - * Replicate the fill value throughout the chunk. - */ - assert(0==chunk_size % fill.size); - H5V_array_fill(chunk, fill.buf, fill.size, (size_t)chunk_size/fill.size); - } else { - /* - * No fill value was specified, assume all zeros. - */ - HDmemset (chunk, 0, (size_t)chunk_size); - } /* end else */ - - /* Check if there are filters which need to be applied to the chunk */ - if (pline.nused>0) { - unsigned filter_mask=0; - size_t buf_size=(size_t)chunk_size; - size_t nbytes=(size_t)chunk_size; - - /* Push the chunk through the filters */ - if (H5Z_pipeline(&pline, 0, &filter_mask, edc, cb_struct, &nbytes, &buf_size, &chunk)<0) - HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "output pipeline failed"); - - /* Keep the number of bytes the chunk turned in to */ - chunk_size=nbytes; - } /* end if */ - } /* end if */ - - /* Loop over all chunks */ - carry=0; - while (carry==0) { - /* Check if the chunk exists yet on disk */ - chunk_exists=1; - if(H5D_istore_get_addr(f,dxpl_id,&(dset->layout),chunk_offset, NULL)==HADDR_UNDEF) { - const H5D_rdcc_t *rdcc = &(dset->cache.chunk); /*raw data chunk cache */ - H5D_rdcc_ent_t *ent = NULL; /*cache entry */ - - /* Didn't find the chunk on disk */ - chunk_exists = 0; - - /* Look for chunk in cache */ - for(ent = rdcc->head; ent && !chunk_exists; ent = ent->next) { - /* Assume a match */ - chunk_exists = 1; - for(u = 0; u < dset->layout.u.chunk.ndims && chunk_exists; u++) { - if(ent->offset[u] != chunk_offset[u]) - chunk_exists = 0; /* Reset if no match */ - } /* end for */ - } /* end for */ - } /* end if */ - - if(!chunk_exists) { - /* Initialize the chunk information */ - udata.mesg = dset->layout; - udata.key.filter_mask = 0; - udata.addr = HADDR_UNDEF; - H5_CHECK_OVERFLOW(chunk_size,hsize_t,size_t); - udata.key.nbytes = (size_t)chunk_size; - for (u=0; u<dset->layout.u.chunk.ndims; u++) - udata.key.offset[u] = chunk_offset[u]; - - /* Allocate the chunk with all processes */ - if (H5B_insert(f, dxpl_id, H5B_ISTORE, dset->layout.u.chunk.addr, &udata)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to allocate chunk"); - - /* Check if fill values should be written to blocks */ - if(should_fill) { -#ifdef H5_HAVE_PARALLEL - /* Check if this file is accessed with an MPI-capable file driver */ - if(using_mpi) { - /* Write the chunks out from only one process */ - /* !! Use the internal "independent" DXPL!! -QAK */ - if(H5_PAR_META_WRITE==mpi_rank) { - if (H5F_block_write(f, H5FD_MEM_DRAW, udata.addr, udata.key.nbytes, H5AC_ind_dxpl_id, chunk)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file"); - } /* end if */ - - /* Indicate that blocks are being written */ - blocks_written=1; - } /* end if */ - else { -#endif /* H5_HAVE_PARALLEL */ - if (H5F_block_write(f, H5FD_MEM_DRAW, udata.addr, udata.key.nbytes, dxpl_id, chunk)<0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write raw data to file"); -#ifdef H5_HAVE_PARALLEL - } /* end else */ -#endif /* H5_HAVE_PARALLEL */ - } /* end if */ - } /* end if */ - - /* Increment indices */ - for (i=dset->layout.u.chunk.ndims-1, carry=1; i>=0 && carry; --i) { - chunk_offset[i] += dset->layout.u.chunk.dim[i]; - if (chunk_offset[i] >= (hssize_t)(space_dim[i])) - chunk_offset[i] = 0; - else - carry = 0; - } /* end for */ - } /* end while */ - -#ifdef H5_HAVE_PARALLEL - /* Only need to block at the barrier if we actually allocated a chunk */ - /* And if we are using an MPI-capable file driver */ - if(using_mpi && blocks_written) { - /* Wait at barrier to avoid race conditions where some processes are - * still writing out chunks and other processes race ahead to read - * them in, getting bogus data. - */ - if (MPI_SUCCESS != (mpi_code=MPI_Barrier(mpi_comm))) - HMPI_GOTO_ERROR(FAIL, "MPI_Barrier failed", mpi_code); - } /* end if */ -#endif /* H5_HAVE_PARALLEL */ - -done: - /* Free the chunk for fill values */ - if(chunk!=NULL) - H5D_istore_chunk_xfree(chunk,&pline); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_allocate() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_prune_by_extent - * - * Purpose: This function searches for chunks that are no longer necessary both in the - * raw data cache and in the B-tree. - * - * Return: Success: 0, Failure: -1 - * - * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu - * Algorithm: Robb Matzke - * - * Date: March 27, 2002 - * - * The algorithm is: - * - * For chunks that are no longer necessary: - * - * 1. Search in the raw data cache for each chunk - * 2. If found then preempt it from the cache - * 3. Search in the B-tree for each chunk - * 4. If found then remove it from the B-tree and deallocate file storage for the chunk - * - * This example shows a 2d dataset of 90x90 with a chunk size of 20x20. - * - * - * 0 20 40 60 80 90 100 - * 0 +---------+---------+---------+---------+-----+...+ - * |:::::X:::::::::::::: : : | : - * |:::::::X:::::::::::: : : | : Key - * |::::::::::X::::::::: : : | : -------- - * |::::::::::::X::::::: : : | : +-+ Dataset - * 20+::::::::::::::::::::.........:.........:.....+...: | | Extent - * | :::::X::::: : : | : +-+ - * | ::::::::::: : : | : - * | ::::::::::: : : | : ... Chunk - * | :::::::X::: : : | : : : Boundary - * 40+.........:::::::::::.........:.........:.....+...: :.: - * | : : : : | : - * | : : : : | : ... Allocated - * | : : : : | : ::: & Filled - * | : : : : | : ::: Chunk - * 60+.........:.........:.........:.........:.....+...: - * | : :::::::X::: : | : X Element - * | : ::::::::::: : | : Written - * | : ::::::::::: : | : - * | : ::::::::::: : | : - * 80+.........:.........:::::::::::.........:.....+...: O Fill Val - * | : : ::::::::::: | : Explicitly - * | : : ::::::X:::: | : Written - * 90+---------+---------+---------+---------+-----+ : - * : : : ::::::::::: : - * 100:.........:.........:.........:::::::::::.........: - * - * - * We have 25 total chunks for this dataset, 5 of which have space - * allocated in the file because they were written to one or more - * elements. These five chunks (and only these five) also have entries in - * the storage B-tree for this dataset. - * - * Now lets say we want to shrink the dataset down to 70x70: - * - * - * 0 20 40 60 70 80 90 100 - * 0 +---------+---------+---------+----+----+-----+...+ - * |:::::X:::::::::::::: : | : | : - * |:::::::X:::::::::::: : | : | : Key - * |::::::::::X::::::::: : | : | : -------- - * |::::::::::::X::::::: : | : | : +-+ Dataset - * 20+::::::::::::::::::::.........:....+....:.....|...: | | Extent - * | :::::X::::: : | : | : +-+ - * | ::::::::::: : | : | : - * | ::::::::::: : | : | : ... Chunk - * | :::::::X::: : | : | : : : Boundary - * 40+.........:::::::::::.........:....+....:.....|...: :.: - * | : : : | : | : - * | : : : | : | : ... Allocated - * | : : : | : | : ::: & Filled - * | : : : | : | : ::: Chunk - * 60+.........:.........:.........:....+....:.....|...: - * | : :::::::X::: | : | : X Element - * | : ::::::::::: | : | : Written - * +---------+---------+---------+----+ : | : - * | : ::::::::::: : | : - * 80+.........:.........:::::::::X:.........:.....|...: O Fill Val - * | : : ::::::::::: | : Explicitly - * | : : ::::::X:::: | : Written - * 90+---------+---------+---------+---------+-----+ : - * : : : ::::::::::: : - * 100:.........:.........:.........:::::::::::.........: - * - * - * That means that the nine chunks along the bottom and right side should - * no longer exist. Of those nine chunks, (0,80), (20,80), (40,80), - * (60,80), (80,80), (80,60), (80,40), (80,20), and (80,0), one is actually allocated - * that needs to be released. - * To release the chunks, we traverse the B-tree to obtain a list of unused - * allocated chunks, and then call H5B_remove() for each chunk. - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_prune_by_extent(H5F_t *f, const struct H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, H5D_t *dset) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); /*raw data chunk cache */ - H5D_rdcc_ent_t *ent = NULL, *next = NULL; /*cache entry */ - unsigned u; /*counters */ - int found; /*remove this entry */ - H5D_istore_ud1_t udata; /*B-tree pass-through */ - hsize_t curr_dims[H5O_LAYOUT_NDIMS]; /*current dataspace dimensions */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_prune_by_extent, FAIL); - - /* Check args */ - assert(f); - assert(dxpl_cache); - assert(dset && H5D_CHUNKED == dset->layout.type); - assert(dset->layout.u.chunk.ndims > 0 && dset->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - assert(H5F_addr_defined(dset->layout.u.chunk.addr)); - - /* Go get the rank & dimensions */ - if(H5S_get_simple_extent_dims(dset->space, curr_dims, NULL) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions"); - - /*------------------------------------------------------------------------- - * Figure out what chunks are no longer in use for the specified extent - * and release them from the linked list raw data cache - *------------------------------------------------------------------------- - */ - found = 0; - for(ent = rdcc->head; ent; ent = next) { - next = ent->next; - - for(u = 0; u < dset->layout.u.chunk.ndims - 1; u++) { - if((hsize_t)ent->offset[u] > curr_dims[u]) { - found = 1; - break; - } /* end if */ - } /* end for */ - - if(found) { -#ifdef H5D_ISTORE_DEBUG - HDfputs("cache:remove:[", stderr); - for(u = 0; u < dset->layout.u.chunk.ndims - 1; u++) - HDfprintf(stderr, "%s%Hd", u ? ", " : "", ent->offset[u]); - HDfputs("]\n", stderr); -#endif - - /* Preempt the entry from the cache, but do not flush it to disk */ - if(H5D_istore_preempt(f, dxpl_cache, dxpl_id, dset, ent, FALSE) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, 0, "unable to preempt chunk"); - - found=0; - } - } - -/*------------------------------------------------------------------------- - * Check if there are any chunks on the B-tree - *------------------------------------------------------------------------- - */ - - HDmemset(&udata, 0, sizeof udata); - udata.stream = stdout; - udata.mesg.u.chunk.addr = dset->layout.u.chunk.addr; - udata.mesg.u.chunk.ndims = dset->layout.u.chunk.ndims; - for(u = 0; u < dset->layout.u.chunk.ndims; u++) - udata.mesg.u.chunk.dim[u] = dset->layout.u.chunk.dim[u]; - udata.dims = curr_dims; - - if(H5B_iterate(f, dxpl_id, H5B_ISTORE, H5D_istore_prune_extent, dset->layout.u.chunk.addr, &udata) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, 0, "unable to iterate over B-tree"); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_prune_by_extent() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_prune_extent - * - * Purpose: Search for chunks that are no longer necessary in the B-tree. - * - * Return: Success: 0, Failure: -1 - * - * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu - * - * Date: March 26, 2002 - * - * Comments: Called by H5D_prune_by_extent - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static int -H5D_istore_prune_extent(H5F_t *f, hid_t dxpl_id, void *_lt_key, haddr_t UNUSED addr, - void UNUSED *_rt_key, void *_udata) -{ - H5D_istore_ud1_t *bt_udata = (H5D_istore_ud1_t *)_udata; - H5D_istore_key_t *lt_key = (H5D_istore_key_t *)_lt_key; - unsigned u; - H5D_istore_ud1_t udata; - int ret_value=H5B_ITER_CONT; /* Return value */ - - /* The LT_KEY is the left key (the one that describes the chunk). It points to a chunk of - * storage that contains the beginning of the logical address space represented by UDATA. - */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_istore_prune_extent); - - /* Figure out what chunks are no longer in use for the specified extent and release them */ - for(u = 0; u < bt_udata->mesg.u.chunk.ndims - 1; u++) - if((hsize_t)lt_key->offset[u] > bt_udata->dims[u]) { -#ifdef H5D_ISTORE_DEBUG - HDfputs("b-tree:remove:[", bt_udata->stream); - for(u = 0; u < bt_udata->mesg.u.chunk.ndims - 1; u++) - HDfprintf(bt_udata->stream, "%s%Hd", u ? ", " : "", lt_key->offset[u]); - HDfputs("]\n", bt_udata->stream); -#endif - - HDmemset(&udata, 0, sizeof udata); - udata.key = *lt_key; - udata.mesg = bt_udata->mesg; - - /* Remove */ - if(H5B_remove(f, dxpl_id, H5B_ISTORE, bt_udata->mesg.u.chunk.addr, &udata) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_ITER_ERROR, "unable to remove entry"); - break; - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_prune_extent() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_remove - * - * Purpose: Removes chunks that are no longer necessary in the B-tree. - * - * Return: Success: 0, Failure: -1 - * - * Programmer: Robb Matzke - * Pedro Vicente, pvn@ncsa.uiuc.edu - * - * Date: March 28, 2002 - * - * Comments: Part of H5B_ISTORE - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static H5B_ins_t -H5D_istore_remove(H5F_t *f, hid_t dxpl_id, haddr_t addr, void *_lt_key /*in,out */ , - hbool_t *lt_key_changed /*out */ , - void UNUSED * _udata /*in,out */ , - void UNUSED * _rt_key /*in,out */ , - hbool_t *rt_key_changed /*out */ ) -{ - H5D_istore_key_t *lt_key = (H5D_istore_key_t *)_lt_key; - H5B_ins_t ret_value=H5B_INS_REMOVE; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_remove,H5B_INS_ERROR); - - /* Remove raw data chunk from file */ - H5MF_xfree(f, H5FD_MEM_DRAW, dxpl_id, addr, (hsize_t)lt_key->nbytes); - - /* Mark keys as unchanged */ - *lt_key_changed = FALSE; - *rt_key_changed = FALSE; - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_remove() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_initialize_by_extent - * - * Purpose: This function searches for chunks that have to be initialized with the fill - * value both in the raw data cache and in the B-tree. - * - * Return: Success: 0, Failure: -1 - * - * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu - * - * Date: April 4, 2002 - * - * Comments: - * - * (See the example of H5D_istore_prune_by_extent) - * Next, there are seven chunks where the database extent boundary is - * within the chunk. We find those seven just like we did with the previous nine. - * Fot the ones that are allocated we initialize the part that lies outside the boundary - * with the fill value. - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_initialize_by_extent(H5F_t *f, const struct H5D_dxpl_cache_t *dxpl_cache, - hid_t dxpl_id, H5D_t *dset) -{ - uint8_t *chunk = NULL; /*the file chunk */ - unsigned idx_hint = 0; /*input value for H5F_istore_lock */ - hssize_t chunk_offset[H5O_LAYOUT_NDIMS]; /*logical location of the chunks */ - hsize_t idx_cur[H5O_LAYOUT_NDIMS]; /*multi-dimensional counters */ - hsize_t idx_max[H5O_LAYOUT_NDIMS]; - hsize_t sub_size[H5O_LAYOUT_NDIMS]; - hsize_t naccessed; /*bytes accessed in chunk */ - hsize_t end_chunk; /*chunk position counter */ - hssize_t start[H5O_LAYOUT_NDIMS]; /*starting location of hyperslab */ - hsize_t count[H5O_LAYOUT_NDIMS]; /*element count of hyperslab */ - hsize_t size[H5O_LAYOUT_NDIMS]; /*current size of dimensions */ - H5S_t *space_chunk = NULL; /*dataspace for a chunk */ - hsize_t chunk_dims[H5O_LAYOUT_NDIMS]; /*current chunk dimensions */ - hsize_t curr_dims[H5O_LAYOUT_NDIMS]; /*current dataspace dimensions */ - hsize_t chunks[H5O_LAYOUT_NDIMS]; /*current number of chunks in each dimension */ - hsize_t down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of elements in each dimension */ - int srank; /*current # of dimensions (signed) */ - unsigned rank; /*current # of dimensions */ - int i, carry; /*counters */ - unsigned u; - int found = 0; /*initialize this entry */ - H5P_genplist_t *dc_plist; /* Property list */ - H5O_pline_t pline; /* I/O pipeline information */ - H5O_fill_t fill; /* Fill value information */ - H5D_fill_time_t fill_time; /* Fill time information */ - H5D_storage_t store; /* Dataset storage information */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_initialize_by_extent, FAIL); - - /* Check args */ - assert(f); - assert(dxpl_cache); - assert(dset && H5D_CHUNKED == dset->layout.type); - assert(dset->layout.u.chunk.ndims > 0 && dset->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - assert(H5F_addr_defined(dset->layout.u.chunk.addr)); - - /* Get dataset's creation property list */ - if (NULL == (dc_plist = H5I_object(dset->dcpl_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list") - - /* Get necessary properties from property list */ - if(H5P_get(dc_plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fill value"); - if(H5P_get(dc_plist, H5D_CRT_FILL_TIME_NAME, &fill_time) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get fill time"); - if(H5P_get(dc_plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data pipeline"); - - /* Reset start & count arrays */ - HDmemset(start, 0, sizeof(start)); - HDmemset(count, 0, sizeof(count)); - - /* Go get the rank & dimensions */ - if((srank = H5S_get_simple_extent_dims(dset->space, curr_dims, NULL)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions"); - H5_ASSIGN_OVERFLOW(rank,srank,int,unsigned); - - /* Copy current dimensions */ - for(u = 0; u < rank; u++) { - size[u] = curr_dims[u]; - - /* Round up to the next integer # of chunks, to accomodate partial chunks */ - chunks[u] = ((curr_dims[u]+dset->layout.u.chunk.dim[u])-1) / dset->layout.u.chunk.dim[u]; - } /* end for */ - size[u] = dset->layout.u.chunk.dim[u]; - - /* Get the "down" sizes for each dimension */ - if(H5V_array_down(rank,chunks,down_chunks)<0) - HGOTO_ERROR (H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute 'down' sizes") - - /* Create a data space for a chunk & set the extent */ - for(u = 0; u < rank; u++) - chunk_dims[u] = dset->layout.u.chunk.dim[u]; - if(NULL == (space_chunk = H5S_create_simple(rank,chunk_dims,NULL))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace"); - -/* - * Set up multi-dimensional counters (idx_max, and idx_cur) and - * loop through the chunks copying each chunk from the application to the - * chunk cache. - */ - for(u = 0; u < dset->layout.u.chunk.ndims; u++) { - idx_max[u] = (size[u] - 1) / dset->layout.u.chunk.dim[u] + 1; - idx_cur[u] = 0; - } /* end for */ - - /* Loop over all chunks */ - carry=0; - while(carry==0) { - for(u = 0, naccessed = 1; u < dset->layout.u.chunk.ndims; u++) { - /* The location and size of the chunk being accessed */ - chunk_offset[u] = idx_cur[u] * (hssize_t)(dset->layout.u.chunk.dim[u]); - sub_size[u] = MIN((idx_cur[u] + 1) * dset->layout.u.chunk.dim[u], - size[u]) - chunk_offset[u]; - naccessed *= sub_size[u]; - } /* end for */ - - /* - * Figure out what chunks have to be initialized. These are the chunks where the dataspace - * extent boundary is within the chunk - */ - for(u = 0, found = 0; u < dset->layout.u.chunk.ndims - 1; u++) { - end_chunk = chunk_offset[u] + dset->layout.u.chunk.dim[u]; - if(end_chunk > size[u]) { - found = 1; - break; - } - } /* end for */ - - if(found) { - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(rank,chunk_offset,dset->layout.u.chunk.dim,down_chunks,&store.chunk.index)<0) - HGOTO_ERROR (H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - store.chunk.offset=chunk_offset; - if(NULL == (chunk = H5D_istore_lock(f, dxpl_cache, dxpl_id, dset, - &store, NULL, FALSE, &idx_hint))) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to read raw data chunk"); - - if(H5S_select_all(space_chunk,1) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to select space"); - - for(u = 0; u < rank; u++) - count[u] = MIN((idx_cur[u] + 1) * dset->layout.u.chunk.dim[u], size[u] - chunk_offset[u]); - -#ifdef H5D_ISTORE_DEBUG - HDfputs("cache:initialize:offset:[", stdout); - for(u = 0; u < dset->layout.u.chunk.ndims - 1; u++) - HDfprintf(stdout, "%s%Hd", u ? ", " : "", chunk_offset[u]); - HDfputs("]", stdout); - HDfputs(":count:[", stdout); - for(u = 0; u < dset->layout.u.chunk.ndims - 1; u++) - HDfprintf(stdout, "%s%Hd", u ? ", " : "", count[u]); - HDfputs("]\n", stdout); -#endif - - if(H5S_select_hyperslab(space_chunk, H5S_SELECT_NOTB, start, NULL, - count, NULL) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to select hyperslab"); - - /* Fill the selection in the memory buffer */ - /* Use the size of the elements in the chunk directly instead of */ - /* relying on the fill.size, which might be set to 0 if there is */ - /* no fill-value defined for the dataset -QAK */ - H5_CHECK_OVERFLOW(size[rank],hsize_t,size_t); - if(H5S_select_fill(fill.buf, (size_t)size[rank], space_chunk, chunk) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "filling selection failed"); - - if(H5D_istore_unlock(f, dxpl_cache, dxpl_id, dset, &store, - TRUE, idx_hint, chunk, (size_t)naccessed) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to unlock raw data chunk"); - } /*found */ - - /* Increment indices */ - for(i = dset->layout.u.chunk.ndims - 1, carry = 1; i >= 0 && carry; --i) { - if(++idx_cur[i] >= idx_max[i]) - idx_cur[i] = 0; - else - carry = 0; - } /* end for */ - } /* end while */ - -done: - if(space_chunk) - H5S_close(space_chunk); - - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_initialize_by_extent() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_delete - * - * Purpose: Delete raw data storage for entire dataset (i.e. all chunks) - * - * Return: Success: Non-negative - * Failure: negative - * - * Programmer: Quincey Koziol - * Thursday, March 20, 2003 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_delete(H5F_t *f, hid_t dxpl_id, const struct H5O_layout_t *layout) -{ - H5D_istore_ud1_t udata; /* User data for B-tree iterator call */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_delete, FAIL); - - /* Check if the B-tree has been created in the file */ - if(H5F_addr_defined(layout->u.chunk.addr)) { - /* Set up user data for B-tree deletion */ - HDmemset(&udata, 0, sizeof udata); - udata.mesg = *layout; - - /* Delete entire B-tree */ - if(H5B_delete(f, dxpl_id, H5B_ISTORE, layout->u.chunk.addr, &udata)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTDELETE, 0, "unable to delete chunk B-tree"); - } /* end if */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_delete() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_update_cache - * - * Purpose: Update any cached chunks index values after the dataspace - * size has changed - * - * Return: Success: Non-negative - * Failure: negative - * - * Programmer: Quincey Koziol - * Saturday, May 29, 2004 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_update_cache(H5F_t *f, hid_t dxpl_id, H5D_t *dset) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); /*raw data chunk cache */ - H5D_rdcc_ent_t *ent, *next; /*cache entry */ - H5D_rdcc_ent_t *old_ent; /* Old cache entry */ - H5D_dxpl_cache_t dxpl_cache; /* Cached data transfer properties */ - int srank; /*current # of dimensions (signed) */ - unsigned rank; /*current # of dimensions */ - hsize_t curr_dims[H5O_LAYOUT_NDIMS]; /*current dataspace dimensions */ - hsize_t chunks[H5O_LAYOUT_NDIMS]; /*current number of chunks in each dimension */ - hsize_t down_chunks[H5O_LAYOUT_NDIMS]; /* "down" size of number of elements in each dimension */ - hsize_t idx; /* Chunk index */ - unsigned old_idx; /* Previous index number */ - unsigned u; /*counters */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_update_cache, FAIL); - - /* Check args */ - assert(f); - assert(dset && H5D_CHUNKED == dset->layout.type); - assert(dset->layout.u.chunk.ndims > 0 && dset->layout.u.chunk.ndims <= H5O_LAYOUT_NDIMS); - - /* Go get the rank & dimensions */ - if((srank = H5S_get_simple_extent_dims(dset->space, curr_dims, NULL)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get dataset dimensions"); - H5_ASSIGN_OVERFLOW(rank,srank,int,unsigned); - - /* Round up to the next integer # of chunks, to accomodate partial chunks */ - for(u = 0; u < rank; u++) - chunks[u] = ((curr_dims[u]+dset->layout.u.chunk.dim[u])-1) / dset->layout.u.chunk.dim[u]; - - /* Get the "down" sizes for each dimension */ - if(H5V_array_down(rank,chunks,down_chunks)<0) - HGOTO_ERROR (H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute 'down' sizes") - - /* Fill the DXPL cache values for later use */ - if (H5D_get_dxpl_cache(dxpl_id,&dxpl_cache)<0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") - - /* Recompute the index for each cached chunk that is in a dataset */ - for(ent = rdcc->head; ent; ent = next) { - next=ent->next; - - /* Calculate the index of this chunk */ - if(H5V_chunk_index(rank,ent->offset,dset->layout.u.chunk.dim,down_chunks,&idx)<0) - HGOTO_ERROR (H5E_DATASPACE, H5E_BADRANGE, FAIL, "can't get chunk index") - - /* Compute the index for the chunk entry */ - old_idx=ent->idx; /* Save for later */ - ent->idx=H5D_HASH(dset,idx); - - if(old_idx!=ent->idx) { - /* Check if there is already a chunk at this chunk's new location */ - old_ent = rdcc->slot[ent->idx]; - if(old_ent!=NULL) { - assert(old_ent->locked==0); - - /* Check if we are removing the entry we would walk to next */ - if(old_ent==next) - next=old_ent->next; - - /* Remove the old entry from the cache */ - if (H5D_istore_preempt(f, &dxpl_cache, dxpl_id, dset, old_ent, TRUE )<0) - HGOTO_ERROR (H5E_IO, H5E_CANTFLUSH, FAIL, "unable to flush one or more raw data chunks"); - } /* end if */ - - /* Insert this chunk into correct location in hash table */ - rdcc->slot[ent->idx]=ent; - - /* Null out previous location */ - rdcc->slot[old_idx]=NULL; - } /* end if */ - } /* end for */ - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5F_istore_update_cache() */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_dump_btree - * - * Purpose: Prints information about the storage B-tree to the specified - * stream. - * - * Return: Success: Non-negative - * - * Failure: negative - * - * Programmer: Robb Matzke - * Wednesday, April 28, 1999 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_dump_btree(H5F_t *f, hid_t dxpl_id, FILE *stream, unsigned ndims, haddr_t addr) -{ - H5D_istore_ud1_t udata; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_dump_btree, FAIL); - - HDmemset(&udata, 0, sizeof udata); - udata.mesg.u.chunk.ndims = ndims; - udata.stream = stream; - if(stream) - HDfprintf(stream, " Address: %a\n",addr); - if(H5B_iterate(f, dxpl_id, H5B_ISTORE, H5D_istore_iter_dump, addr, &udata)<0) - HGOTO_ERROR(H5E_IO, H5E_CANTINIT, 0, "unable to iterate over chunk B-tree"); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_dump_btree() */ - -#ifdef H5D_ISTORE_DEBUG - -/*------------------------------------------------------------------------- - * Function: H5D_istore_stats - * - * Purpose: Print raw data cache statistics to the debug stream. If - * HEADERS is non-zero then print table column headers, - * otherwise assume that the H5AC layer has already printed them. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, May 21, 1998 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_stats (H5D_t *dset, hbool_t headers) -{ - H5D_rdcc_t *rdcc = &(dset->cache.chunk); - double miss_rate; - char ascii[32]; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_stats, FAIL); - - if (!H5DEBUG(AC)) - HGOTO_DONE(SUCCEED); - - if (headers) { - fprintf(H5DEBUG(AC), "H5D: raw data cache statistics\n"); - fprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s+%-8s\n", - "Layer", "Hits", "Misses", "MissRate", "Inits", "Flushes"); - fprintf(H5DEBUG(AC), " %-18s %8s %8s %8s %8s-%-8s\n", - "-----", "----", "------", "--------", "-----", "-------"); - } - -#ifdef H5AC_DEBUG - if (H5DEBUG(AC)) headers = TRUE; -#endif - - if (headers) { - if (rdcc->nhits>0 || rdcc->nmisses>0) { - miss_rate = 100.0 * rdcc->nmisses / - (rdcc->nhits + rdcc->nmisses); - } else { - miss_rate = 0.0; - } - if (miss_rate > 100) { - sprintf(ascii, "%7d%%", (int) (miss_rate + 0.5)); - } else { - sprintf(ascii, "%7.2f%%", miss_rate); - } - - fprintf(H5DEBUG(AC), " %-18s %8u %8u %7s %8d+%-9ld\n", - "raw data chunks", rdcc->nhits, rdcc->nmisses, ascii, - rdcc->ninits, (long)(rdcc->nflushes)-(long)(rdcc->ninits)); - } - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_stats() */ -#endif /* H5D_ISTORE_DEBUG */ - - -/*------------------------------------------------------------------------- - * Function: H5D_istore_debug - * - * Purpose: Debugs a B-tree node for indexed raw data storage. - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Robb Matzke - * Thursday, April 16, 1998 - * - * Modifications: - * Robb Matzke, 1999-07-28 - * The ADDR argument is passed by value. - *------------------------------------------------------------------------- - */ -herr_t -H5D_istore_debug(H5F_t *f, hid_t dxpl_id, haddr_t addr, FILE * stream, int indent, - int fwidth, int ndims) -{ - H5D_istore_ud1_t udata; - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(H5D_istore_debug, FAIL); - - HDmemset (&udata, 0, sizeof udata); - udata.mesg.u.chunk.ndims = ndims; - - H5B_debug (f, dxpl_id, addr, stream, indent, fwidth, H5B_ISTORE, &udata); - -done: - FUNC_LEAVE_NOAPI(ret_value); -} /* end H5D_istore_debug() */ |