コード例 #1
0
/*
 * parser_allocate_string_buffer () - creates memory for a given parser
 *   return: allocated memory pointer
 *   parser(in):
 *   length(in):
 *   align(in):
 *
 * Note :
 * First it tries to find length + 1 bytes in the parser's free strings list.
 * If there is no room, it adds a new block of strings to the free
 * strings list, at least large enough to hold new length plus
 * 1 (for a null character). Thus, one can call it by
 * 	copy_of_foo = pt_create_string(parser, strlen(foo));
 */
void *
parser_allocate_string_buffer (const PARSER_CONTEXT * parser,
			       const int length, const int align)
{
  int idhash;
  PARSER_STRING_BLOCK *block;
#if defined(SERVER_MODE)
  int rv;
#endif /* SERVER_MODE */


  /* find free string list for for this id */
  idhash = parser->id % HASH_NUMBER;
#if defined(SERVER_MODE)
  MUTEX_LOCK (rv, parser_memory_lock);
#endif /* SERVER_MODE */
  block = parser_String_blocks[idhash];
  while (block != NULL
	 && (block->parser_id != parser->id
	     || ((block->block_end - block->last_string_end) <
		 (length + (align - 1) + 1))))
    {
      block = block->next;
    }
#if defined(SERVER_MODE)
  MUTEX_UNLOCK (parser_memory_lock);
#endif /* SERVER_MODE */

  if (block == NULL)
    {
      if ((block = parser_create_string_block
	   (parser, length + (align - 1) + 1)) == NULL)
	return NULL;
    }

  /* set start to the aligned length */
  block->last_string_start =
    CAST_BUFLEN ((block->last_string_end + (align - 1) + 1) & ~(align - 1));
  block->last_string_end = CAST_BUFLEN (block->last_string_start + length);
  block->u.chars[block->last_string_start] = 0;

  return &block->u.chars[block->last_string_start];
}
コード例 #2
0
/*
 * overflow_get_nbytes () - GET A PORTION OF THE CONTENT OF AN OVERFLOW RECORD
 *   return: scan status
 *   ovf_vpid(in): Overflow address
 *   recdes(in): Record descriptor
 *   start_offset(in): Start offset of portion to copy
 *   max_nbytes(in): Maximum number of bytes to retrieve
 *   remaining_length(in): The number of remaining bytes to read
 *
 * Note: A portion of the content of the overflow record associated with the
 *       given overflow address(ovf_pid) is placed into the area pointed to by
 *       the record descriptor. If the content of the object does not fit in
 *       such an area (i.e., recdes->area_size), an error is returned and a
 *       hint of the number of bytes needed is returned as a negative value in
 *       recdes->length. The length of the retrieved number of bytes is *set
 *       in the the record descriptor (i.e., recdes->length).
 */
SCAN_CODE
overflow_get_nbytes (THREAD_ENTRY * thread_p, const VPID * ovf_vpid,
		     RECDES * recdes, int start_offset, int max_nbytes,
		     int *remaining_length)
{
  OVERFLOW_FIRST_PART *first_part;
  OVERFLOW_REST_PART *rest_parts;
  PAGE_PTR pgptr = NULL;
  char *copyfrom;
  VPID next_vpid;
  int copy_length;
  char *data;

  /*
   * We don't need to lock the overflow pages since these pages are not
   * shared among several pieces of overflow data. The overflow pages are
   * know by accessing the relocation-overflow record with the appropiate lock
   */

  next_vpid = *ovf_vpid;

  pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ,
		     PGBUF_UNCONDITIONAL_LATCH);
  if (pgptr == NULL)
    {
      return S_ERROR;
    }

  first_part = (OVERFLOW_FIRST_PART *) pgptr;
  *remaining_length = first_part->length;

  if (max_nbytes < 0)
    {
      /* The rest of the overflow record starting at start_offset */
      max_nbytes = *remaining_length - start_offset;
    }
  else
    {
      /* Don't give more than what we have */
      if (max_nbytes > (*remaining_length - start_offset))
	{
	  max_nbytes = *remaining_length - start_offset;
	}
    }

  if (max_nbytes < 0)
    {
      /* Likely the offset was beyond the size of the overflow record */
      max_nbytes = 0;
      *remaining_length = 0;
    }
  else
    {
      *remaining_length -= max_nbytes;
    }

  /* Make sure that there is enough space to copy the desired length object */
  if (max_nbytes > recdes->area_size)
    {
      pgbuf_unfix_and_init (thread_p, pgptr);

      /* Give a hint to the user of the needed length. Hint is given as a
         negative value */
      recdes->length = -max_nbytes;
      return S_DOESNT_FIT;
    }
  else if (max_nbytes == 0)
    {
      pgbuf_unfix_and_init (thread_p, pgptr);

      recdes->length = 0;
      return S_SUCCESS;
    }

  recdes->length = max_nbytes;

  /* Start copying the object */
  data = recdes->data;
  copyfrom = (char *) first_part->data;
  next_vpid = first_part->next_vpid;

  while (max_nbytes > 0)
    {
      /* Continue seeking until the starting offset is reached (passed) */
      if (start_offset > 0)
	{
	  /* Advance .. seek as much as you can */
	  copy_length =
	    (int) ((copyfrom + start_offset) > ((char *) pgptr + DB_PAGESIZE)
		   ? DB_PAGESIZE - (copyfrom -
				    (char *) pgptr) : start_offset);
	  start_offset -= copy_length;
	  copyfrom += copy_length;
	}

      /*
       * Copy as much as you can when you do not need to continue seeking,
       * and there is something to copy in current page (i.e., not at end
       * of the page) and we are not located at the end of the overflow record.
       */
      if (start_offset == 0)
	{
	  if (copyfrom + max_nbytes > (char *) pgptr + DB_PAGESIZE)
	    {
	      copy_length =
		DB_PAGESIZE - CAST_BUFLEN (copyfrom - (char *) pgptr);
	    }
	  else
	    {
	      copy_length = max_nbytes;
	    }

	  /* If we were not at the end of the page, perform the copy */
	  if (copy_length > 0)
	    {
	      memcpy (data, copyfrom, copy_length);
	      data += copy_length;
	      max_nbytes -= copy_length;
	    }
	}

      pgbuf_unfix_and_init (thread_p, pgptr);
      if (max_nbytes > 0)
	{
	  if (VPID_ISNULL (&next_vpid))
	    {
	      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE,
		      ER_HEAP_OVFADDRESS_CORRUPTED, 3, ovf_vpid->volid,
		      ovf_vpid->pageid, NULL_SLOTID);
	      return S_ERROR;
	    }

	  pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ,
			     PGBUF_UNCONDITIONAL_LATCH);
	  if (pgptr == NULL)
	    {
	      recdes->length = 0;
	      return S_ERROR;
	    }
	  rest_parts = (OVERFLOW_REST_PART *) pgptr;
	  copyfrom = (char *) rest_parts->data;
	  next_vpid = rest_parts->next_vpid;
	}
    }

  return S_SUCCESS;
}
コード例 #3
0
/*
 * overflow_insert () - Insert a multipage data in overflow
 *   return: ovf_vpid on success or NULL on failure
 *   ovf_vfid(in): File where the overflow data is going to be stored
 *   ovf_vpid(out): Overflow address
 *   recdes(in): Record descriptor
 *
 * Note: Data in overflow is composed of several pages. Pages in the overflow
 *       area are not shared among other pieces of overflow data.
 *
 *       --------------------------------         ------------------------
 *       |Next_vpid |Length|... data ...| ... --> |Next_vpid|... data ...|
 *       --------------------------------         ------------------------
 *
 *       Single link list of pages.
 *       The length of the multipage data is stored on its first overflow page
 *
 *       Overflow pages are not locked in any mode since they are not shared
 *       by other pieces of data and its address is only know by accessing the
 *       relocation overflow record data which has been appropriately locked.
 */
VPID *
overflow_insert (THREAD_ENTRY * thread_p, const VFID * ovf_vfid,
		 VPID * ovf_vpid, RECDES * recdes)
{
  PAGE_PTR vfid_fhdr_pgptr = NULL;
  OVERFLOW_FIRST_PART *first_part;
  OVERFLOW_REST_PART *rest_parts;
  OVERFLOW_RECV_LINKS undo_recv;
  char *copyto;
  int length, copy_length;
  INT32 npages = 0;
  char *data;
  int alloc_nth;
  LOG_DATA_ADDR addr;
  LOG_DATA_ADDR logical_undoaddr;
  int i;
  VPID *vpids, fhdr_vpid;
  VPID vpids_buffer[OVERFLOW_ALLOCVPID_ARRAY_SIZE + 1];
  FILE_ALLOC_VPIDS alloc_vpids;

  /*
   * We don't need to lock the overflow pages since these pages are not
   * shared among several pieces of overflow data. The overflow pages are
   * know by accessing the relocation-overflow record with the appropiate lock
   */

  addr.vfid = ovf_vfid;
  addr.offset = 0;

  logical_undoaddr.vfid = ovf_vfid;
  logical_undoaddr.offset = 0;
  logical_undoaddr.pgptr = NULL;

  undo_recv.ovf_vfid = *ovf_vfid;

  /*
   * Temporary:
   *   Lock the file header, so I am the only one changing the file table
   *   of allocated pages. This is needed since this function is using
   *   file_find_nthpages, which could give me not the expected page, if someone
   *   else remove pages, after the initial allocation.
   */

  fhdr_vpid.volid = ovf_vfid->volid;
  fhdr_vpid.pageid = ovf_vfid->fileid;

  vfid_fhdr_pgptr = pgbuf_fix (thread_p, &fhdr_vpid, OLD_PAGE,
			       PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
  if (vfid_fhdr_pgptr == NULL)
    {
      return NULL;
    }

  /*
   * Guess the number of pages. The total number of pages is found by
   * dividing length by pagesize - the smallest header. Then, we make sure
   * that this estimate is correct.
   */
  length = recdes->length - (DB_PAGESIZE -
			     (int) offsetof (OVERFLOW_FIRST_PART, data));
  if (length > 0)
    {
      i = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data);
      npages = 1 + CEIL_PTVDIV (length, i);
    }
  else
    {
      npages = 1;
    }

  if (npages > OVERFLOW_ALLOCVPID_ARRAY_SIZE)
    {
      vpids = (VPID *) malloc ((npages + 1) * sizeof (VPID));
      if (vpids == NULL)
	{
	  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY,
		  1, (npages + 1) * sizeof (VPID));
	  pgbuf_unfix (thread_p, vfid_fhdr_pgptr);
	  return NULL;
	}
    }
  else
    {
      vpids = vpids_buffer;
    }

#if !defined(NDEBUG)
  for (i = 0; i < npages; i++)
    {
      VPID_SET_NULL (&vpids[i]);
    }
#endif

  VPID_SET_NULL (&vpids[npages]);

  alloc_vpids.vpids = vpids;
  alloc_vpids.index = 0;

  /*
   * We do not initialize the pages during allocation since they are not
   * pointed by anyone until we return from this function, at that point
   * they are initialized.
   */
  if (file_alloc_pages_as_noncontiguous (thread_p, ovf_vfid, vpids,
					 &alloc_nth, npages, NULL, NULL,
					 NULL, &alloc_vpids) == NULL)
    {
      if (vpids != vpids_buffer)
	{
	  free_and_init (vpids);
	}

      pgbuf_unfix (thread_p, vfid_fhdr_pgptr);
      return NULL;
    }

  assert (alloc_vpids.index == npages);

#if !defined(NDEBUG)
  for (i = 0; i < npages; i++)
    {
      assert (!VPID_ISNULL (&vpids[i]));
    }
#endif

  *ovf_vpid = vpids[0];

  /* Copy the content of the data */

  data = recdes->data;
  length = recdes->length;

  for (i = 0; i < npages; i++)
    {
      addr.pgptr = pgbuf_fix (thread_p, &vpids[i], NEW_PAGE,
			      PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
      if (addr.pgptr == NULL)
	{
	  goto exit_on_error;
	}

      /* Is this the first page ? */
      if (i == 0)
	{
	  /* This is the first part */
	  first_part = (OVERFLOW_FIRST_PART *) addr.pgptr;

	  first_part->next_vpid = vpids[i + 1];
	  first_part->length = length;
	  copyto = (char *) first_part->data;

	  copy_length = DB_PAGESIZE - offsetof (OVERFLOW_FIRST_PART, data);
	  if (length < copy_length)
	    {
	      copy_length = length;
	    }

	  /* notify the first part of overflow recdes */
	  log_append_empty_record (thread_p, LOG_DUMMY_OVF_RECORD);
	}
      else
	{
	  rest_parts = (OVERFLOW_REST_PART *) addr.pgptr;

	  rest_parts->next_vpid = vpids[i + 1];
	  copyto = (char *) rest_parts->data;

	  copy_length = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data);
	  if (length < copy_length)
	    {
	      copy_length = length;
	    }
	}

      memcpy (copyto, data, copy_length);
      data += copy_length;
      length -= copy_length;

      pgbuf_get_vpid (addr.pgptr, &undo_recv.new_vpid);
      if (file_is_new_file (thread_p, ovf_vfid) == FILE_OLD_FILE)
	{
	  /* we don't do undo logging for new files */
	  log_append_undo_data (thread_p, RVOVF_NEWPAGE_LOGICAL_UNDO,
				&logical_undoaddr, sizeof (undo_recv),
				&undo_recv);
	}

      log_append_redo_data (thread_p, RVOVF_NEWPAGE_INSERT, &addr,
			    copy_length +
			    CAST_BUFLEN (copyto - (char *) addr.pgptr),
			    (char *) addr.pgptr);

      pgbuf_set_dirty (thread_p, addr.pgptr, FREE);
      addr.pgptr = NULL;
    }

  assert (length == 0);
#if defined (CUBRID_DEBUG)
  if (length > 0)
    {
      er_log_debug (ARG_FILE_LINE, "ovf_insert: ** SYSTEM ERROR calculation"
		    " of number of pages needed to store overflow data seems"
		    " incorrect. Need no more than %d pages", npages);
      goto exit_on_error;
    }
#endif

  /*
   * Temporary:
   *   Unlock the file header, so I am the only one changing the file table
   *   of allocated pages. This is needed since curently, I am using
   *   file_find_nthpages, which could give me not the expected page, if someone
   *   else remove pages.
   */

  if (vpids != vpids_buffer)
    {
      free_and_init (vpids);
    }

  pgbuf_unfix (thread_p, vfid_fhdr_pgptr);
  return ovf_vpid;

exit_on_error:

  for (i = 0; i < npages; i++)
    {
      (void) file_dealloc_page (thread_p, ovf_vfid, &vpids[i]);
    }

  if (vpids != vpids_buffer)
    {
      free_and_init (vpids);
    }

  pgbuf_unfix (thread_p, vfid_fhdr_pgptr);
  return NULL;
}
コード例 #4
0
/*
 * parser_create_string_block () - reates a new block of strings, links the block
 * on the hash list for the parser, and returns the block
 *   return:
 *   parser(in):
 *   length(in):
 */
static PARSER_STRING_BLOCK *
parser_create_string_block (const PARSER_CONTEXT * parser, const int length)
{
  int idhash;
  PARSER_STRING_BLOCK *block;
#if defined(SERVER_MODE)
  int rv;
#endif /* SERVER_MODE */

  if (length < (int) STRINGS_PER_BLOCK)
    {
      block = (PARSER_STRING_BLOCK *) malloc (sizeof (PARSER_STRING_BLOCK));
      if (!block)
	{
	  if (parser->jmp_env_active)
	    {
	      /* long jump back to routine that set up the jump env
	       * for clean up and run down.
	       */
	      longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1);
	    }
	  else
	    {
	      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE,
		      ER_OUT_OF_VIRTUAL_MEMORY, 1,
		      sizeof (PARSER_STRING_BLOCK));
	      return NULL;
	    }
	}
      block->block_end = STRINGS_PER_BLOCK - 1;
    }
  else
    {
      /* This is an unusually large string. Allocate a special block
       * for it, with space for one string, plus some space
       * for appending to. */
      block = (PARSER_STRING_BLOCK *)
	malloc (sizeof (PARSER_STRING_BLOCK)
		+ (length + 1001 - STRINGS_PER_BLOCK));
      if (!block)
	{
	  if (parser->jmp_env_active)
	    {
	      /* long jump back to routine that set up the jump env
	       * for clean up and run down.
	       */
	      longjmp (((PARSER_CONTEXT *) parser)->jmp_env, 1);
	    }
	  else
	    {
	      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE,
		      ER_OUT_OF_VIRTUAL_MEMORY, 1,
		      (sizeof (PARSER_STRING_BLOCK) +
		       (length + 1001 - STRINGS_PER_BLOCK)));
	      return NULL;
	    }
	}
      block->block_end = CAST_BUFLEN (length + 1001 - 1);
    }

  /* remember which parser allocated this block */
  block->parser_id = parser->id;
  block->last_string_start = -1;
  block->last_string_end = -1;
  block->u.chars[0] = 0;

  /* link blocks on the hash list for this id */
  idhash = parser->id % HASH_NUMBER;
#if defined(SERVER_MODE)
  MUTEX_LOCK (rv, parser_memory_lock);
#endif /* SERVER_MODE */
  block->next = parser_String_blocks[idhash];
  parser_String_blocks[idhash] = block;
#if defined(SERVER_MODE)
  MUTEX_UNLOCK (parser_memory_lock);
#endif /* SERVER_MODE */

  return block;
}