text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * Copyright by the Board of Trustees of the University of Illinois.         *
   * All rights reserved.                                                      *
   *                                                                           *
   * This file is part of HDF5.  The full HDF5 copyright notice, including     *
   * terms governing use, modification, and redistribution, is contained in    *
   * the COPYING file, which can be found at the root of the source code       *
   * distribution tree, or in https://www.hdfgroup.org/licenses.               *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /*-------------------------------------------------------------------------
   *
   * Created:		H5Ochunk.c
   *			Jul 13 2008
   *			Quincey Koziol
   *
   * Purpose:		Object header chunk routines.
   *
   *-------------------------------------------------------------------------
   */
  
  /****************/
  /* Module Setup */
  /****************/
  
  #include "H5Omodule.h" /* This source code file is part of the H5O module */
  
  /***********/
  /* Headers */
  /***********/
  #include "H5private.h"  /* Generic Functions			*/
  #include "H5Eprivate.h" /* Error handling		  	*/
  #include "H5Opkg.h"     /* Object headers			*/
  
  /****************/
  /* Local Macros */
  /****************/
  
  /******************/
  /* Local Typedefs */
  /******************/
  
  /********************/
  /* Package Typedefs */
  /********************/
  
  /********************/
  /* Local Prototypes */
  /********************/
  
  /*********************/
  /* Package Variables */
  /*********************/
  
  /* Declare the free list for H5O_chunk_proxy_t's */
  H5FL_DEFINE(H5O_chunk_proxy_t);
  
  /*****************************/
  /* Library Private Variables */
  /*****************************/
  
  /*******************/
  /* Local Variables */
  /*******************/
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_add
   *
   * Purpose:     Add new chunk for object header to metadata cache
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		Jul 13 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_add(H5F_t *f, H5O_t *oh, unsigned idx, unsigned cont_chunkno)
  {
      H5O_chunk_proxy_t *chk_proxy = NULL; /* Proxy for chunk, to mark it dirty in the cache */
      H5O_chunk_proxy_t *cont_chk_proxy =
          NULL; /* Proxy for chunk containing continuation message that points to this chunk, if not chunk 0 */
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE_TAG(oh->cache_info.addr)
  
      /* check args */
      HDassert(f);
      HDassert(oh);
      HDassert(idx < oh->nchunks);
      HDassert(idx > 0);
  
      /* Allocate space for the object header data structure */
      if (NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
          HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
  
      /* Increment reference count on object header */
      if (H5O__inc_rc(oh) < 0)
          HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "can't increment reference count on object header")
  
      /* Set the values in the chunk proxy */
      chk_proxy->f       = f;
      chk_proxy->oh      = oh;
      chk_proxy->chunkno = idx;
  
      /* Determine the parent of the chunk */
      if (cont_chunkno != 0) {
          if (NULL == (cont_chk_proxy = H5O__chunk_protect(f, oh, cont_chunkno)))
              HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
          chk_proxy->fd_parent = cont_chk_proxy;
      } /* end else */
  
      /* Insert the chunk proxy into the cache */
      if (H5AC_insert_entry(f, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__NO_FLAGS_SET) < 0)
          HGOTO_ERROR(H5E_OHDR, H5E_CANTINSERT, FAIL, "unable to cache object header chunk")
  
      chk_proxy = NULL;
  
  done:
      /* Cleanup on failure */
      if (ret_value < 0)
          if (chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
              HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk")
  
      /* Release resources */
      if (cont_chk_proxy)
          if (H5O__chunk_unprotect(f, cont_chk_proxy, FALSE) < 0)
              HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to unprotect object header chunk")
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5O__chunk_add() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_protect
   *
   * Purpose:     Protect an object header chunk for modifications
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		Jul 17 2008
   *
   *-------------------------------------------------------------------------
   */
  H5O_chunk_proxy_t *
  H5O__chunk_protect(H5F_t *f, H5O_t *oh, unsigned idx)
  {
      H5O_chunk_proxy_t *chk_proxy = NULL; /* Proxy for protected chunk */
      H5O_chunk_proxy_t *ret_value = NULL; /* Return value */
  
      FUNC_ENTER_PACKAGE_TAG(oh->cache_info.addr)
  
      /* check args */
      HDassert(f);
      HDassert(oh);
      HDassert(idx < oh->nchunks);
  
      /* Check for protecting first chunk */
      if (0 == idx) {
          /* Create new "fake" chunk proxy for first chunk */
          /* (since the first chunk is already handled by the H5O_t object) */
          if (NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
              HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
  
          /* Increment reference count on object header */
          if (H5O__inc_rc(oh) < 0)
              HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
  
          /* Set chunk proxy fields */
          chk_proxy->f       = f;
          chk_proxy->oh      = oh;
          chk_proxy->chunkno = idx;
      } /* end if */
      else {
          H5O_chk_cache_ud_t chk_udata; /* User data for loading chunk */
  
          /* Construct the user data for protecting chunk proxy */
          /* (and _not_ decoding it) */
          HDmemset(&chk_udata, 0, sizeof(chk_udata));
          chk_udata.oh      = oh;
          chk_udata.chunkno = idx;
          chk_udata.size    = oh->chunk[idx].size;
  
          /* Get the chunk proxy */
          if (NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, H5AC_OHDR_CHK, oh->chunk[idx].addr,
                                                                     &chk_udata, H5AC__NO_FLAGS_SET)))
              HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk")
  
          /* Sanity check */
          HDassert(chk_proxy->oh == oh);
          HDassert(chk_proxy->chunkno == idx);
      } /* end else */
  
      /* Set return value */
      ret_value = chk_proxy;
  
  done:
      /* Cleanup on error */
      if (!ret_value)
          if (0 == idx && chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
              HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk")
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5O__chunk_protect() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_unprotect
   *
   * Purpose:     Unprotect an object header chunk after modifications
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		Jul 17 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_unprotect(H5F_t *f, H5O_chunk_proxy_t *chk_proxy, hbool_t dirtied)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* check args */
      HDassert(f);
      HDassert(chk_proxy);
  
      /* Check for releasing first chunk */
      if (0 == chk_proxy->chunkno) {
          /* Check for dirtying the first chunk */
          if (dirtied) {
              /* Mark object header as dirty in cache */
              if (H5AC_mark_entry_dirty(chk_proxy->oh) < 0)
                  HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, FAIL, "unable to mark object header as dirty")
          } /* end else/if */
  
          /* Decrement reference count of object header */
          if (H5O__dec_rc(chk_proxy->oh) < 0)
              HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header")
  
          /* Free fake chunk proxy */
          chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy);
      } /* end if */
      else {
          /* Release the chunk proxy from the cache, possibly marking it dirty */
          if (H5AC_unprotect(f, H5AC_OHDR_CHK, chk_proxy->oh->chunk[chk_proxy->chunkno].addr, chk_proxy,
                             (dirtied ? H5AC__DIRTIED_FLAG : H5AC__NO_FLAGS_SET)) < 0)
              HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5O__chunk_unprotect() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_resize
   *
   * Purpose:     Resize an object header chunk
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		May  6 2010
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_resize(H5O_t *oh, H5O_chunk_proxy_t *chk_proxy)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* check args */
      HDassert(oh);
      HDassert(chk_proxy);
  
      /* Check for resizing first chunk */
      if (0 == chk_proxy->chunkno) {
          /* Resize object header in cache */
          if (H5AC_resize_entry(oh, oh->chunk[0].size) < 0)
              HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize chunk in cache")
      } /* end if */
      else {
          /* Resize chunk in cache */
          if (H5AC_resize_entry(chk_proxy, oh->chunk[chk_proxy->chunkno].size) < 0)
              HGOTO_ERROR(H5E_OHDR, H5E_CANTRESIZE, FAIL, "unable to resize chunk in cache")
      } /* end else */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5O__chunk_resize() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_update_idx
   *
   * Purpose:     Update the chunk index for a chunk proxy
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		Jul 13 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_update_idx(H5F_t *f, H5O_t *oh, unsigned idx)
  {
      H5O_chunk_proxy_t *chk_proxy = NULL;    /* Proxy for chunk, to mark it dirty in the cache */
      H5O_chk_cache_ud_t chk_udata;           /* User data for loading chunk */
      herr_t             ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE_TAG(oh->cache_info.addr)
  
      /* check args */
      HDassert(f);
      HDassert(oh);
      HDassert(idx < oh->nchunks);
      HDassert(idx > 0);
  
      /* Construct the user data for protecting chunk proxy */
      /* (and _not_ decoding it) */
      HDmemset(&chk_udata, 0, sizeof(chk_udata));
      chk_udata.oh      = oh;
      chk_udata.chunkno = idx;
      chk_udata.size    = oh->chunk[idx].size;
  
      /* Get the chunk proxy */
      if (NULL == (chk_proxy = (H5O_chunk_proxy_t *)H5AC_protect(f, H5AC_OHDR_CHK, oh->chunk[idx].addr,
                                                                 &chk_udata, H5AC__NO_FLAGS_SET)))
          HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
  
      /* Update index for chunk proxy in cache */
      chk_proxy->chunkno = idx;
  
      /* Release the chunk proxy from the cache, marking it deleted */
      if (H5AC_unprotect(f, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, H5AC__DIRTIED_FLAG) < 0)
          HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
  
  done:
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5O__chunk_update_idx() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_delete
   *
   * Purpose:     Notify metadata cache that a chunk has been deleted
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *		Jul 13 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_delete(H5F_t *f, H5O_t *oh, unsigned idx)
  {
      H5O_chunk_proxy_t *chk_proxy   = NULL;               /* Proxy for chunk, to mark it dirty in the cache */
      unsigned           cache_flags = H5AC__DELETED_FLAG; /* Flags for unprotecting proxy */
      herr_t             ret_value   = SUCCEED;            /* Return value */
  
      FUNC_ENTER_PACKAGE_TAG(oh->cache_info.addr)
  
      /* check args */
      HDassert(f);
      HDassert(oh);
      HDassert(idx < oh->nchunks);
      HDassert(idx > 0);
  
      /* Get the chunk proxy */
      if (NULL == (chk_proxy = H5O__chunk_protect(f, oh, idx)))
          HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, FAIL, "unable to load object header chunk")
  
      /* Only free file space if not doing SWMR writes */
      if (!oh->swmr_write)
          cache_flags |= H5AC__DIRTIED_FLAG | H5AC__FREE_FILE_SPACE_FLAG;
  
  done:
      /* Release the chunk proxy from the cache, marking it deleted */
      if (chk_proxy && H5AC_unprotect(f, H5AC_OHDR_CHK, oh->chunk[idx].addr, chk_proxy, cache_flags) < 0)
          HDONE_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, FAIL, "unable to release object header chunk")
  
      FUNC_LEAVE_NOAPI_TAG(ret_value)
  } /* end H5O__chunk_delete() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5O__chunk_dest
   *
   * Purpose:     Destroy a chunk proxy object
   *
   * Return:      SUCCEED/FAIL
   *
   * Programmer:	Quincey Koziol
   *              July 13, 2008
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5O__chunk_dest(H5O_chunk_proxy_t *chk_proxy)
  {
      herr_t ret_value = SUCCEED; /* Return value */
  
      FUNC_ENTER_PACKAGE
  
      /* Check arguments */
      HDassert(chk_proxy);
  
      /* Decrement reference count of object header */
      if (chk_proxy->oh && H5O__dec_rc(chk_proxy->oh) < 0)
          HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "can't decrement reference count on object header")
  
      /* Release the chunk proxy object */
      chk_proxy = H5FL_FREE(H5O_chunk_proxy_t, chk_proxy);
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* H5O__chunk_dest() */
  