/* * Copyright (C) 1997 NCSA * All rights reserved. * * Programmer: Robb Matzke * Thursday, November 13, 1997 * * Purpose: A driver that splits the meta data and raw data into two * separate files. The high-order bit of the file address * determines whether the address refers to the meta data file * (high order bit is clear) or the raw data file (high order bit * is set). */ #include #include #include #include #include /* Default file name extensions */ #define H5F_SPLIT_META_EXT ".meta" #define H5F_SPLIT_RAW_EXT ".raw" #define PABLO_MASK H5Fsplit_mask static intn interface_initialize_g = 0; #define INTERFACE_INIT NULL static htri_t H5F_split_access(const char *name, const H5F_access_t *access_parms, int mode, H5F_search_t *key/*out*/); static H5F_low_t *H5F_split_open(const char *name, const H5F_access_t *access_parms, uintn flags, H5F_search_t *key/*out*/); static herr_t H5F_split_close(H5F_low_t *lf, const H5F_access_t *access_parms); static herr_t H5F_split_read(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, const haddr_t *addr, size_t size, uint8_t *buf/*out*/); static herr_t H5F_split_write(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, const haddr_t *addr, size_t size, const uint8_t *buf); static herr_t H5F_split_flush(H5F_low_t *lf, const H5F_access_t *access_parms); static herr_t H5F_split_extend(H5F_low_t *lf, const H5F_access_t *access_parms, intn op, hsize_t size, haddr_t *addr/*out*/); static intn H5F_split_alloc (H5F_low_t *lf, intn op, hsize_t alignment, hsize_t threshold, hsize_t size, H5MF_free_t *blk, haddr_t *addr/*out*/); const H5F_low_class_t H5F_LOW_SPLIT_g[1] = {{ H5F_split_access, /*access method */ H5F_split_open, /*open method */ H5F_split_close, /*close method */ H5F_split_read, /*read method */ H5F_split_write, /*write method */ H5F_split_flush, /*flush method */ H5F_split_extend, /*extend method */ H5F_split_alloc, /*alloc method */ }}; /* * This is the bit that determines whether the address is part of the meta * data file or part of the raw data file. Eventually we'll want to pass * this kind of thing down to this function from above... */ #define H5F_SPLIT_MASK 0x80000000 /*------------------------------------------------------------------------- * Function: H5F_split_open * * Purpose: Opens a split meta data/raw data family with the specified * base name. The name of the meta data file will be created by * appending `.h5' while the name of the raw data file will be * created by appending `.raw'. * * Return: Success: Low-level file pointer * * Failure: NULL * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static H5F_low_t * H5F_split_open(const char *name, const H5F_access_t *access_parms, uintn flags, H5F_search_t *key/*out*/) { H5F_low_t *lf = NULL, *ret_value = NULL; char fullname[4096]; const char *ext; /*file name extension*/ const H5F_low_class_t *meta_type = NULL; const H5F_low_class_t *raw_type = NULL; FUNC_ENTER(H5F_split_open, NULL); assert(name && *name); assert (access_parms); assert (H5F_LOW_SPLIT==access_parms->driver); assert (access_parms->u.split.meta_access); assert (access_parms->u.split.raw_access); /* Get member types */ meta_type = H5F_low_class (access_parms->u.split.meta_access->driver); raw_type = H5F_low_class (access_parms->u.split.raw_access->driver); /* Create the file descriptor */ if (NULL==(lf = H5MM_calloc(sizeof(H5F_low_t)))) { HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed"); } lf->u.split.name = H5MM_xstrdup(name); lf->u.split.mask = H5F_SPLIT_MASK; /* Open the meta data file */ ext = access_parms->u.split.meta_ext ? access_parms->u.split.meta_ext : H5F_SPLIT_META_EXT; if (HDstrlen(name)+HDstrlen(ext) >= sizeof fullname) { HGOTO_ERROR (H5E_IO, H5E_CANTINIT, NULL, "file name is too long"); } HDstrcpy(fullname, name); HDstrcat(fullname, ext); lf->u.split.meta = H5F_low_open(meta_type, fullname, access_parms->u.split.meta_access, flags, key/*out*/); if (NULL == lf->u.split.meta) { HGOTO_ERROR(H5E_IO, H5E_CANTOPENFILE, NULL, "can't open meta file"); } /* Open the raw data file */ ext = access_parms->u.split.raw_ext ? access_parms->u.split.raw_ext : H5F_SPLIT_RAW_EXT; if (HDstrlen(name)+HDstrlen(ext) >= sizeof fullname) { HGOTO_ERROR (H5E_IO, H5E_CANTINIT, NULL, "file name is too long"); } HDstrcpy(fullname, name); HDstrcat(fullname, ext); lf->u.split.raw = H5F_low_open(raw_type, fullname, access_parms->u.split.raw_access, flags, NULL); if (NULL == lf->u.split.raw) { HGOTO_ERROR(H5E_IO, H5E_CANTOPENFILE, NULL, "can't open raw file"); } /* Initialize the file size */ H5F_low_size(lf->u.split.raw, &(lf->eof)); lf->eof.offset |= lf->u.split.mask; HRETURN(lf); done: if (!ret_value) { if (lf) { H5F_split_close(lf, access_parms); H5MM_xfree(lf); } } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5F_split_close * * Purpose: Closes a split file. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_split_close(H5F_low_t *lf, const H5F_access_t *access_parms) { FUNC_ENTER(H5F_split_close, FAIL); assert(lf); H5F_low_close(lf->u.split.meta, access_parms->u.split.meta_access); H5F_low_close(lf->u.split.raw, access_parms->u.split.raw_access); H5MM_xfree(lf->u.split.name); FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_split_read * * Purpose: Reads a chunk of contiguous data from a split file. We * assume that the data being read never crosses the meta * data/raw data boundary. Reading past the end of a file * returns zeros instead of failing. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * June 2, 1998 Albert Cheng * Added xfer_mode argument * *------------------------------------------------------------------------- */ static herr_t H5F_split_read(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, const haddr_t *addr, size_t size, uint8_t *buf/*out*/) { haddr_t tmp_addr; H5F_low_t *sub = NULL; herr_t status; const H5F_access_t *sub_parms = NULL; FUNC_ENTER(H5F_split_read, FAIL); assert(lf); assert(addr && H5F_addr_defined(addr)); assert(buf); /* no collective support */ assert(xfer_parms->xfer_mode != H5D_XFER_COLLECTIVE); /* Which file to we actually read from? */ if (addr->offset & lf->u.split.mask) { sub = lf->u.split.raw; sub_parms = access_parms->u.split.raw_access; tmp_addr.offset = addr->offset & (lf->u.split.mask - 1); } else { sub = lf->u.split.meta; sub_parms = access_parms->u.split.meta_access; tmp_addr = *addr; } /* Read the data */ status = H5F_low_read(sub, sub_parms, xfer_parms, &tmp_addr, size, buf/*out*/); FUNC_LEAVE(status); } /*------------------------------------------------------------------------- * Function: H5F_split_write * * Purpose: Writes BUF to either the meta data file or the raw data file. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * June 2, 1998 Albert Cheng * Added xfer_mode argument * *------------------------------------------------------------------------- */ static herr_t H5F_split_write(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, const haddr_t *addr, size_t size, const uint8_t *buf) { haddr_t tmp_addr; H5F_low_t *sub = NULL; herr_t status; const H5F_access_t *sub_parms = NULL; FUNC_ENTER(H5F_split_write, FAIL); assert(lf); assert(addr && H5F_addr_defined(addr)); assert(buf); /* no collective support */ assert(xfer_parms->xfer_mode != H5D_XFER_COLLECTIVE); /* Which file to we actually write to? */ if (addr->offset & lf->u.split.mask) { sub = lf->u.split.raw; sub_parms = access_parms->u.split.raw_access; tmp_addr.offset = addr->offset & (lf->u.split.mask - 1); } else { sub = lf->u.split.meta; sub_parms = access_parms->u.split.meta_access; tmp_addr = *addr; } /* Write the data */ status = H5F_low_write(sub, sub_parms, xfer_parms, &tmp_addr, size, buf); FUNC_LEAVE(status); } /*------------------------------------------------------------------------- * Function: H5F_split_flush * * Purpose: Flushes all data to disk. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_split_flush(H5F_low_t *lf, const H5F_access_t *access_parms) { herr_t ret_value = SUCCEED; FUNC_ENTER(H5F_split_flush, FAIL); assert(lf); ret_value = (H5F_low_flush(lf->u.split.meta, access_parms->u.split.meta_access) >= 0 && H5F_low_flush(lf->u.split.raw, access_parms->u.split.raw_access) >= 0); FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5F_split_access * * Purpose: Determines if both members of the split data file family can * be accessed and returns the key for the first member of the * family. * * Return: Success: TRUE or FALSE * * Failure: FAIL * * Programmer: Robb Matzke * Monday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static htri_t H5F_split_access(const char *name, const H5F_access_t *access_parms, int mode, H5F_search_t *key/*out*/) { char fullname[4096]; htri_t status; const char *ext; /*file extension*/ const H5F_low_class_t *meta_type = NULL; const H5F_low_class_t *raw_type = NULL; FUNC_ENTER(H5F_split_access, FAIL); assert(name && *name); assert (access_parms); assert (H5F_LOW_SPLIT==access_parms->driver); assert (access_parms->u.split.meta_access); assert (access_parms->u.split.raw_access); /* The meta data member */ meta_type = H5F_low_class (access_parms->u.split.meta_access->driver); ext = access_parms->u.split.meta_ext ? access_parms->u.split.meta_ext : H5F_SPLIT_META_EXT; if (HDstrlen(name)+HDstrlen(ext) >= sizeof fullname) { HRETURN_ERROR (H5E_IO, H5E_CANTINIT, FAIL, "file name is too long"); } HDstrcpy(fullname, name); HDstrcat(fullname, ext); status = H5F_low_access(meta_type, fullname, access_parms->u.split.meta_access, mode, key/*out*/); if (status < 0) { HRETURN_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "access call failed for meta data member"); } if (!status) HRETURN(FALSE); /* The raw data member */ raw_type = H5F_low_class (access_parms->u.split.raw_access->driver); ext = access_parms->u.split.raw_ext ? access_parms->u.split.raw_ext : H5F_SPLIT_RAW_EXT; if (HDstrlen(name)+HDstrlen(ext) >= sizeof fullname) { HRETURN_ERROR (H5E_IO, H5E_CANTINIT, FAIL, "file name is too long"); } HDstrcpy(fullname, name); HDstrcat(fullname, ext); status = H5F_low_access(raw_type, fullname, access_parms->u.split.raw_access, mode, NULL/*out*/); if (status < 0) { HRETURN_ERROR(H5E_IO, H5E_CANTINIT, FAIL, "access call failed for raw data member"); } FUNC_LEAVE(status); } /*------------------------------------------------------------------------- * Function: H5F_split_extend * * Purpose: Allocates memory from the end of the meta data file or raw * data file. * * Return: Non-negative on success (with the address of the allocated * memory returned through the ADDR argument.) /Negative * on failure * * Programmer: Robb Matzke * Thursday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_split_extend(H5F_low_t *lf, const H5F_access_t *access_parms, intn op, hsize_t size, haddr_t *addr/*out*/) { FUNC_ENTER(H5F_split_extend, FAIL); assert(lf); assert(H5MF_META == op || H5MF_RAW == op); assert(size > 0); assert(addr); if (H5MF_META == op) { if (H5F_low_extend(lf->u.split.meta, access_parms->u.split.meta_access, op, size, addr/*out*/)<0) { HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "meta data allocation failed"); } if (addr->offset + size > lf->eof.offset) { lf->eof.offset = addr->offset + size; } } else { if (H5F_low_extend(lf->u.split.raw, access_parms->u.split.raw_access, op, size, addr/*out*/)<0) { HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "raw data allocation failed"); } addr->offset |= lf->u.split.mask; lf->eof = lf->u.split.raw->eof; lf->eof.offset |= lf->u.split.mask; } FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_split_alloc * * Purpose: Determines if free block BLK in file LF can be used to * satisfy the request for SIZE bytes. This function is * actually the same as H5F_low_alloc() except it returns * failure if the OP is not compatible with the block address, * insuring that meta data is allocated from one half of the * address space and raw data from the other half. * * Return: Success: Positive if the free block satisfies the * request exactly, zero if the free block * over-satisfies the request. The ADDR will * contain the address within the free block * where the request starts. * * Failure: Negative * * Programmer: Robb Matzke * Tuesday, June 9, 1998 * * Modifications: * *------------------------------------------------------------------------- */ static intn H5F_split_alloc (H5F_low_t *lf, intn op, hsize_t alignment, hsize_t threshold, hsize_t size, H5MF_free_t *blk, haddr_t *addr/*out*/) { intn ret_value = FAIL; hsize_t wasted; FUNC_ENTER (H5F_split_alloc, FAIL); assert (lf); assert (alignment>0); assert (size>0); assert (blk); assert (addr); switch (op) { case H5MF_META: if (blk->addr.offset & lf->u.split.mask) HRETURN(FAIL); break; case H5MF_RAW: if (0==(blk->addr.offset & lf->u.split.mask)) HRETURN(FAIL); break; } if (size>=threshold) { wasted = blk->addr.offset % alignment; } else { wasted = 0; } if (0==wasted && size==blk->size) { /* exact match */ *addr = blk->addr; ret_value = 1; } else if (blk->size>wasted && blk->size-wasted>=size) { /* over-satisfied */ *addr = blk->addr; H5F_addr_inc (addr, wasted); ret_value = 0; } FUNC_LEAVE (ret_value); }