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.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /****************/
  /* Module Setup */
  /****************/
  
  #define H5O_FRIEND      /*suppress error about including H5Opkg	  */
  #include "H5SMmodule.h" /* This source code file is part of the H5SM module */
  
  /***********/
  /* Headers */
  /***********/
  #include "H5private.h"   /* Generic Functions			*/
  #include "H5Eprivate.h"  /* Error handling		  	*/
  #include "H5MMprivate.h" /* Memory management			*/
  #include "H5Opkg.h"      /* Object Headers                       */
  #include "H5SMpkg.h"     /* Shared object header messages        */
  
  /****************/
  /* Local Macros */
  /****************/
  
  /******************/
  /* Local Typedefs */
  /******************/
  
  /* Udata struct for calls to H5SM__compare_cb and H5SM__compare_iter_op*/
  typedef struct H5SM_compare_udata_t {
      const H5SM_mesg_key_t *key; /* Key; compare this against stored message */
      H5O_msg_crt_idx_t      idx; /* Index of the message in the OH, if applicable */
      herr_t                 ret; /* Return value; set this to result of memcmp */
  } H5SM_compare_udata_t;
  
  /********************/
  /* Local Prototypes */
  /********************/
  static herr_t H5SM__compare_cb(const void *obj, size_t obj_len, void *udata);
  static herr_t H5SM__compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg, unsigned sequence, unsigned *oh_modified,
                                      void *udata);
  
  /*********************/
  /* Package Variables */
  /*********************/
  
  /*****************************/
  /* Library Private Variables */
  /*****************************/
  
  /*******************/
  /* Local Variables */
  /*******************/
  
  /*-------------------------------------------------------------------------
   * Function:	H5SM__compare_cb
   *
   * Purpose:	Callback for H5HF_op, used in H5SM__message_compare below.
   *              Determines whether the search key passed in in _UDATA is
   *              equal to OBJ or not.
   *
   *              Passes back the result in _UDATA->RET
   *
   * Return:	Negative on error, non-negative on success
   *
   * Programmer:	James Laird
   *              Monday, January 8, 2007
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5SM__compare_cb(const void *obj, size_t obj_len, void *_udata)
  {
      H5SM_compare_udata_t *udata = (H5SM_compare_udata_t *)_udata;
  
      FUNC_ENTER_STATIC_NOERR
  
      /* If the encoding sizes are different, it's not the same object */
      if (udata->key->encoding_size > obj_len)
          udata->ret = 1;
      else if (udata->key->encoding_size < obj_len)
          udata->ret = -1;
      else
          /* Sizes are the same.  Return result of memcmp */
          udata->ret = HDmemcmp(udata->key->encoding, obj, obj_len);
  
      FUNC_LEAVE_NOAPI(SUCCEED)
  } /* end H5SM__compare_cb() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5SM__compare_iter_op
   *
   * Purpose:	OH iteration callback to compare a key against a message in
   *              an OH
   *
   * Return:	0 if this is not the message we're searching for
   *              1 if this is the message we're searching for (with memcmp
   *                      result returned in udata)
   *              negative on error
   *
   * Programmer:	James Laird
   *              Wednesday, February 7, 2007
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5SM__compare_iter_op(H5O_t *oh, H5O_mesg_t *mesg /*in,out*/, unsigned sequence,
                        unsigned H5_ATTR_UNUSED *oh_modified, void *_udata /*in,out*/)
  {
      H5SM_compare_udata_t *udata     = (H5SM_compare_udata_t *)_udata;
      herr_t                ret_value = H5_ITER_CONT;
  
      FUNC_ENTER_STATIC
  
      /*
       * Check arguments.
       */
      HDassert(oh);
      HDassert(mesg);
      HDassert(udata && udata->key);
  
      /* Check the creation index for this message */
      if (sequence == udata->idx) {
          size_t aligned_encoded_size = H5O_ALIGN_OH(oh, udata->key->encoding_size);
  
          /* Sanity check the message's length */
          HDassert(mesg->raw_size > 0);
  
          if (aligned_encoded_size > mesg->raw_size)
              udata->ret = 1;
          else if (aligned_encoded_size < mesg->raw_size)
              udata->ret = -1;
          else {
              /* Check if the message is dirty & flush it to the object header if so */
              if (mesg->dirty)
                  if (H5O_msg_flush(udata->key->file, oh, mesg) < 0)
                      HGOTO_ERROR(H5E_SOHM, H5E_CANTENCODE, H5_ITER_ERROR,
                                  "unable to encode object header message")
  
              HDassert(udata->key->encoding_size <= mesg->raw_size);
              udata->ret = HDmemcmp(udata->key->encoding, mesg->raw, udata->key->encoding_size);
          } /* end else */
  
          /* Indicate that we found the message we were looking for */
          ret_value = H5_ITER_STOP;
      } /* end if */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5SM__compare_iter_op() */
  
  /*-------------------------------------------------------------------------
   * Function:	H5SM__message_compare
   *
   * Purpose:	Determine whether the search key rec1 represents a shared
   *              message that is equal to rec2 or not, and if not, whether
   *              rec1 is "greater than" or "less than" rec2.
   *
   * Return:	0 if rec1 == rec2
   *              Negative if rec1 < rec2
   *              Positive if rec1 > rec2
   *
   * Programmer:	James Laird
   *              Monday, November 6, 2006
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5SM__message_compare(const void *rec1, const void *rec2, int *result)
  {
      const H5SM_mesg_key_t *key       = (const H5SM_mesg_key_t *)rec1;
      const H5SM_sohm_t *    mesg      = (const H5SM_sohm_t *)rec2;
      herr_t                 ret_value = SUCCEED;
  
      FUNC_ENTER_PACKAGE
  
      /* If the key has an fheap ID, we're looking for a message that's
       * already in the index; if the fheap ID matches, we've found the message
       * and can stop immediately.
       * Likewise, if the message has an OH location that is matched by the
       * message in the index, we've found the message.
       */
      if (mesg->location == H5SM_IN_HEAP && key->message.location == H5SM_IN_HEAP) {
          if (key->message.u.heap_loc.fheap_id.val == mesg->u.heap_loc.fheap_id.val) {
              *result = 0;
              HGOTO_DONE(SUCCEED);
          }
      } /* end if */
      else if (mesg->location == H5SM_IN_OH && key->message.location == H5SM_IN_OH) {
          if (key->message.u.mesg_loc.oh_addr == mesg->u.mesg_loc.oh_addr &&
              key->message.u.mesg_loc.index == mesg->u.mesg_loc.index &&
              key->message.msg_type_id == mesg->msg_type_id) {
              *result = 0;
              HGOTO_DONE(SUCCEED);
          }
      } /* end if */
  
      /* Compare hash values */
      if (key->message.hash > mesg->hash)
          *result = 1;
      else if (key->message.hash < mesg->hash)
          *result = -1;
      /* If the hash values match, make sure the messages are really the same */
      else {
          /* Hash values match; compare the encoded message with the one in
           * the index.
           */
          H5SM_compare_udata_t udata;
  
          HDassert(key->message.hash == mesg->hash);
          HDassert(key->encoding_size > 0 && key->encoding);
  
          /* Set up user data for callback */
          udata.key = key;
  
          /* Compare the encoded message with either the message in the heap or
           * the message in an object header.
           */
          if (mesg->location == H5SM_IN_HEAP) {
              /* Call heap op routine with comparison callback */
              if (H5HF_op(key->fheap, &(mesg->u.heap_loc.fheap_id), H5SM__compare_cb, &udata) < 0)
                  HGOTO_ERROR(H5E_HEAP, H5E_CANTCOMPARE, FAIL, "can't compare btree2 records")
          } /* end if */
          else {
              H5O_loc_t           oloc; /* Object owning the message */
              H5O_mesg_operator_t op;   /* Message operator */
  
              /* Sanity checks */
              HDassert(key->file);
              HDassert(mesg->location == H5SM_IN_OH);
  
              /* Reset the object location */
              if (H5O_loc_reset(&oloc) < 0)
                  HGOTO_ERROR(H5E_SYM, H5E_CANTRESET, FAIL, "unable to initialize target location")
  
              /* Set up object location */
              oloc.file = key->file;
              oloc.addr = mesg->u.mesg_loc.oh_addr;
  
              /* Finish setting up user data for iterator */
              udata.idx = mesg->u.mesg_loc.index;
  
              /* Locate the right message and compare with it */
              op.op_type  = H5O_MESG_OP_LIB;
              op.u.lib_op = H5SM__compare_iter_op;
              if (H5O_msg_iterate(&oloc, mesg->msg_type_id, &op, &udata) < 0)
                  HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "error iterating over links")
          } /* end else */
  
          *result = udata.ret;
      } /* end if */
  
  done:
      FUNC_LEAVE_NOAPI(ret_value)
  } /* end H5SM__message_compare */
  
  /*-------------------------------------------------------------------------
   * Function:	H5SM__message_encode
   *
   * Purpose:	Serialize a H5SM_sohm_t struct into a buffer RAW.
   *
   * Return:	Non-negative on success
   *              Negative on failure
   *
   * Programmer:	James Laird
   *              Monday, November 6, 2006
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5SM__message_encode(uint8_t *raw, const void *_nrecord, void *_ctx)
  {
      H5SM_bt2_ctx_t *   ctx     = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
      const H5SM_sohm_t *message = (const H5SM_sohm_t *)_nrecord;
  
      FUNC_ENTER_PACKAGE_NOERR
  
      /* Sanity check */
      HDassert(ctx);
  
      *raw++ = (uint8_t)message->location;
      UINT32ENCODE(raw, message->hash);
  
      if (message->location == H5SM_IN_HEAP) {
          UINT32ENCODE(raw, message->u.heap_loc.ref_count);
          H5MM_memcpy(raw, message->u.heap_loc.fheap_id.id, (size_t)H5O_FHEAP_ID_LEN);
      } /* end if */
      else {
          HDassert(message->location == H5SM_IN_OH);
  
          *raw++ = 0; /* reserved (possible flags byte) */
          *raw++ = (uint8_t)message->msg_type_id;
          UINT16ENCODE(raw, message->u.mesg_loc.index);
          H5F_addr_encode_len((size_t)ctx->sizeof_addr, &raw, message->u.mesg_loc.oh_addr);
      } /* end else */
  
      FUNC_LEAVE_NOAPI(SUCCEED)
  } /* end H5SM__message_encode */
  
  /*-------------------------------------------------------------------------
   * Function:	H5SM__message_decode
   *
   * Purpose:	Read an encoded SOHM message from RAW into an H5SM_sohm_t struct.
   *
   * Return:	Non-negative on success
   *              Negative on failure
   *
   * Programmer:	James Laird
   *              Monday, November 6, 2006
   *
   *-------------------------------------------------------------------------
   */
  herr_t
  H5SM__message_decode(const uint8_t *raw, void *_nrecord, void *_ctx)
  {
      H5SM_bt2_ctx_t *ctx     = (H5SM_bt2_ctx_t *)_ctx; /* Callback context structure */
      H5SM_sohm_t *   message = (H5SM_sohm_t *)_nrecord;
  
      FUNC_ENTER_PACKAGE_NOERR
  
      message->location = (H5SM_storage_loc_t)*raw++;
      UINT32DECODE(raw, message->hash);
  
      if (message->location == H5SM_IN_HEAP) {
          UINT32DECODE(raw, message->u.heap_loc.ref_count);
          H5MM_memcpy(message->u.heap_loc.fheap_id.id, raw, (size_t)H5O_FHEAP_ID_LEN);
      } /* end if */
      else {
          HDassert(message->location == H5SM_IN_OH);
  
          raw++; /* reserved */
          message->msg_type_id = *raw++;
          UINT16DECODE(raw, message->u.mesg_loc.index);
          H5F_addr_decode_len((size_t)ctx->sizeof_addr, &raw, &message->u.mesg_loc.oh_addr);
      } /* end else */
  
      FUNC_LEAVE_NOAPI(SUCCEED)
  } /* end H5SM__message_decode */
  