Ejemplo n.º 1
0
/*
 * cursor_fetch_page_having_tuple () - A request is made to the server side to
 *   bring the specified list file page and copy the page to the cursor buffer
 *   area
 *   return: NO_ERROR on all ok, ER status( or ER_FAILED) otherwise
 *   cursor_id(in): Cursor identifier
 *   vpid(in): List File Real Page Identifier
 *   position(in):
 *   offset(in):
 * Note: For performance reasons, this routine checks the cursor identifier
 *       and if the cursor LIST FILE has a hidden OID column (for update)
 *       or has preceding hidden OID columns, vector fetches those referred
 *       objects from the server.
 *
 *       It also positions the tuple pointer to the desired tuple position.
 *       If position = LAST_TPL, then the cursor is positioned to the LAST
 *       tuple on the page.  If position = FIRST_TPL, then the cursor is
 *       positioned to the FIRST tuple on the page.  Otherwise, position is
 *       the tuple position in the fetched page and offset is used as the
 *       byte offset to the tuple.  If positioning to the first or last tuple
 *       on the page, the offset is ignored.
 */
int
cursor_fetch_page_having_tuple (CURSOR_ID * cursor_id_p, VPID * vpid_p,
				int position, int offset)
{
  cursor_initialize_current_tuple_value_position (cursor_id_p);

  if (!VPID_EQ (&(cursor_id_p->current_vpid), vpid_p))
    {
      if (cursor_buffer_last_page (cursor_id_p, vpid_p) != NO_ERROR)
	{
	  return ER_FAILED;
	}
    }

  if (cursor_point_current_tuple (cursor_id_p, position, offset) != NO_ERROR)
    {
      return ER_FAILED;
    }

  if (QFILE_GET_OVERFLOW_PAGE_ID (cursor_id_p->buffer) != NULL_PAGEID)
    {
      if (cursor_construct_tuple_from_overflow_pages (cursor_id_p, vpid_p)
	  != NO_ERROR)
	{
	  return ER_FAILED;
	}
    }
  else
    {
      cursor_id_p->current_tuple_p =
	cursor_id_p->buffer + cursor_id_p->current_tuple_offset;
    }

  /* If there is only one tuple, don't prefetch objects because
   * prefetching a small set of objects is slower than fetching
   * them individually.
   */
  if (cursor_id_p->buffer_tuple_count < 2)
    {
      return NO_ERROR;
    }

  /* vector fetched involved OIDs for performance reasons, if
   * the fetched LIST FILE page contains a hidden OID column or
   * a set of hidden preceding OID columns.
   * NOTE1: this process for oid-cols-included queries are disabled.
   * NOTE2: this process is done only for DB_TYPE_OBJECT colums
   *        not for any other colum types such as DB_TYPE_VOBJ.
   */
  if (cursor_has_first_hidden_oid (cursor_id_p))
    {
      return cursor_prefetch_first_hidden_oid (cursor_id_p);
    }
  else if (cursor_id_p->oid_col_no && cursor_id_p->oid_col_no_cnt)
    {
      return cursor_prefetch_column_oids (cursor_id_p);
    }

  return NO_ERROR;
}
Ejemplo n.º 2
0
static int
cursor_construct_tuple_from_overflow_pages (CURSOR_ID * cursor_id_p,
					    VPID * vpid_p)
{
  VPID overflow_vpid;
  char *buffer_p;
  char *tmp_tuple_p, *tuple_p;
  int tuple_length, offset, tuple_page_size;

  /* get tuple length and allocate space for the tuple */
  tmp_tuple_p = cursor_id_p->buffer + QFILE_PAGE_HEADER_SIZE;
  tuple_length = QFILE_GET_TUPLE_LENGTH (tmp_tuple_p);

  if (cursor_id_p->tuple_record.size < tuple_length)
    {
      if (cursor_allocate_tuple_area (cursor_id_p, tuple_length) != NO_ERROR)
	{
	  return ER_FAILED;
	}
    }

  tuple_p = cursor_id_p->tuple_record.tpl;
  offset = 0;

  do
    {
      buffer_p = cursor_id_p->buffer;

      QFILE_GET_OVERFLOW_VPID (&overflow_vpid, buffer_p);
      tuple_page_size = MIN (tuple_length - offset,
			     QFILE_MAX_TUPLE_SIZE_IN_PAGE);
      memcpy (tuple_p, buffer_p + QFILE_PAGE_HEADER_SIZE, tuple_page_size);
      tuple_p += tuple_page_size;
      offset += tuple_page_size;

      if (overflow_vpid.pageid != NULL_PAGEID)
	{
	  if (cursor_get_list_file_page (cursor_id_p, &overflow_vpid)
	      != NO_ERROR)
	    {
	      return ER_FAILED;
	    }
	  QFILE_COPY_VPID (&cursor_id_p->current_vpid, &overflow_vpid);
	}
    }
  while (overflow_vpid.pageid != NULL_PAGEID);

  /* reset buffer as a head page of overflow page */
  if (!VPID_EQ (vpid_p, &overflow_vpid)
      && cursor_get_list_file_page (cursor_id_p, vpid_p) != NO_ERROR)
    {
      return ER_FAILED;
    }

  cursor_id_p->current_tuple_p = cursor_id_p->tuple_record.tpl;

  return NO_ERROR;
}
Ejemplo n.º 3
0
/*
 * overflow_next_vpid () -
 *   return: ovf_vpid on success or NULL on failure
 *   ovf_vpid(in): Overflow address
 *   vpid(in/out): current/next vpid
 *   pgptr(in): current page
 */
static void
overflow_next_vpid (const VPID * ovf_vpid, VPID * vpid, PAGE_PTR pgptr)
{
  if (VPID_EQ (ovf_vpid, vpid))
    {
      *vpid = ((OVERFLOW_FIRST_PART *) pgptr)->next_vpid;
    }
  else
    {
      *vpid = ((OVERFLOW_REST_PART *) pgptr)->next_vpid;
    }
}
Ejemplo n.º 4
0
static int
cursor_buffer_last_page (CURSOR_ID * cursor_id_p, VPID * vpid_p)
{
  if (cursor_id_p->list_id.last_pgptr
      && VPID_EQ (&(cursor_id_p->list_id.first_vpid), vpid_p))
    {
      memcpy (cursor_id_p->buffer, cursor_id_p->list_id.last_pgptr,
	      CURSOR_BUFFER_SIZE);
    }
  else
    {
      if (cursor_get_list_file_page (cursor_id_p, vpid_p) != NO_ERROR)
	{
	  return ER_FAILED;
	}
    }

  return NO_ERROR;
}
Ejemplo n.º 5
0
/*
 * overflow_update () - Update the content of a multipage data
 *   return: ovf_vpid on success or NULL on failure
 *   ovf_vfid(in): File where the overflow data is stored
 *                 WARNING: MUST BE THE SAME AS IT WAS GIVEN DURING INSERT
 *   ovf_vpid(in): Overflow address
 *   recdes(in): Record descriptor
 *
 * Note: The function may allocate or deallocate several overflow pages if
 *       the multipage data increase/decrease in length.
 *
 *       Overflow pages are not locked in any mode since they are not shared
 *       by other data and its address is know by accessing the relocation
 *       overflow record which has been appropriately locked.
 */
const VPID *
overflow_update (THREAD_ENTRY * thread_p, const VFID * ovf_vfid,
		 const VPID * ovf_vpid, RECDES * recdes)
{
  OVERFLOW_FIRST_PART *first_part = NULL;
  OVERFLOW_REST_PART *rest_parts = NULL;
  char *copyto;
  OVERFLOW_RECV_LINKS recv;
  VPID tmp_vpid;
  int hdr_length;
  int copy_length;
  int old_length = 0;
  int length;
  char *data;
  VPID next_vpid;
  VPID *addr_vpid_ptr;
  LOG_DATA_ADDR addr;
  LOG_DATA_ADDR logical_undoaddr;
  bool isnewpage = false;

  /*
   * 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;

  recv.ovf_vfid = *ovf_vfid;

  next_vpid = *ovf_vpid;

  data = recdes->data;
  length = recdes->length;
  while (length > 0)
    {
      addr.pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE,
			      PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH);
      if (addr.pgptr == NULL)
	{
	  goto exit_on_error;
	}

      addr_vpid_ptr = pgbuf_get_vpid_ptr (addr.pgptr);

      /* Log before and after images */

      /* Is this the first page ? */
      if (VPID_EQ (addr_vpid_ptr, ovf_vpid))
	{
	  /* This is the first part */
	  first_part = (OVERFLOW_FIRST_PART *) addr.pgptr;
	  old_length = first_part->length;

	  copyto = (char *) first_part->data;
	  next_vpid = first_part->next_vpid;

	  hdr_length = offsetof (OVERFLOW_FIRST_PART, data);
	  if ((length + hdr_length) > DB_PAGESIZE)
	    {
	      copy_length = DB_PAGESIZE - hdr_length;
	    }
	  else
	    {
	      copy_length = length;
	    }

	  /* Log before image */
	  if (hdr_length + old_length > DB_PAGESIZE)
	    {
	      log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr,
				    DB_PAGESIZE, addr.pgptr);
	      old_length -= DB_PAGESIZE - hdr_length;
	    }
	  else
	    {
	      log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr,
				    hdr_length + old_length, addr.pgptr);
	      old_length = 0;
	    }

	  /* Modify the new length */
	  first_part->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;
	  copyto = (char *) rest_parts->data;
	  if (isnewpage == true)
	    {
	      VPID_SET_NULL (&next_vpid);
	      rest_parts->next_vpid = next_vpid;
	    }
	  else
	    {
	      next_vpid = rest_parts->next_vpid;
	    }

	  hdr_length = offsetof (OVERFLOW_REST_PART, data);
	  if ((length + hdr_length) > DB_PAGESIZE)
	    {
	      copy_length = DB_PAGESIZE - hdr_length;
	    }
	  else
	    {
	      copy_length = length;
	    }

	  if (old_length > 0)
	    {
	      if (hdr_length + old_length > DB_PAGESIZE)
		{
		  log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr,
					DB_PAGESIZE, addr.pgptr);
		  old_length -= DB_PAGESIZE - hdr_length;
		}
	      else
		{
		  log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr,
					hdr_length + old_length, addr.pgptr);
		  old_length = 0;
		}
	    }
	}

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

      log_append_redo_data (thread_p, RVOVF_PAGE_UPDATE, &addr,
			    copy_length + hdr_length, (char *) addr.pgptr);

      if (length > 0)
	{
	  /* Need more pages... Get next page */
	  if (VPID_ISNULL (&next_vpid))
	    {
	      /* We need to allocate a new page */
	      if (file_alloc_pages (thread_p, ovf_vfid, &next_vpid, 1,
				    addr_vpid_ptr, NULL, NULL) == NULL)
		{
		  pgbuf_set_dirty (thread_p, addr.pgptr, FREE);
		  addr.pgptr = NULL;

		  goto exit_on_error;
		}
	      recv.new_vpid = next_vpid;

	      log_append_undoredo_data (thread_p, RVOVF_NEWPAGE_LINK, &addr,
					sizeof (recv), sizeof (next_vpid),
					&recv, &next_vpid);

	      isnewpage = true;	/* So that its link can be set to NULL */

	      /* This logical undo is to remove the page in case of rollback */
	      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 (recv),
					&recv);
		}

	      if (rest_parts == NULL)
		{
		  /* This is the first part */
		  first_part->next_vpid = next_vpid;
		}
	      else
		{
		  /* This is part of rest part */
		  rest_parts->next_vpid = next_vpid;
		}
	    }
	  pgbuf_set_dirty (thread_p, addr.pgptr, FREE);
	  addr.pgptr = NULL;
	}
      else
	{
	  /* The content of the data has been copied. We don't need more pages.
	     Deallocate any additional pages */
	  VPID_SET_NULL (&tmp_vpid);

	  log_append_undoredo_data (thread_p, RVOVF_CHANGE_LINK, &addr,
				    sizeof (next_vpid), sizeof (next_vpid),
				    &next_vpid, &tmp_vpid);

	  if (rest_parts == NULL)
	    {
	      /* This is the first part */
	      VPID_SET_NULL (&first_part->next_vpid);
	    }
	  else
	    {
	      /* This is part of rest part */
	      VPID_SET_NULL (&rest_parts->next_vpid);
	    }
	  pgbuf_set_dirty (thread_p, addr.pgptr, FREE);
	  addr.pgptr = NULL;

	  while (!(VPID_ISNULL (&next_vpid)))
	    {
	      addr.pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE,
				      PGBUF_LATCH_WRITE,
				      PGBUF_UNCONDITIONAL_LATCH);
	      if (addr.pgptr == NULL)
		{
		  goto exit_on_error;
		}

	      tmp_vpid = next_vpid;
	      rest_parts = (OVERFLOW_REST_PART *) addr.pgptr;
	      next_vpid = rest_parts->next_vpid;

	      if (pgbuf_invalidate (thread_p, addr.pgptr) != NO_ERROR)
		{
		  goto exit_on_error;
		}
	      addr.pgptr = NULL;

	      if (file_dealloc_page (thread_p, ovf_vfid, &tmp_vpid) !=
		  NO_ERROR)
		{
		  goto exit_on_error;
		}
	    }
	  break;
	}
    }

  return ovf_vpid;

exit_on_error:

  return NULL;
}
Ejemplo n.º 6
0
/*
 * cursor_get_list_file_page () -
 *   return:
 *   cursor_id(in/out): Cursor identifier
 *   vpid(in):
 */
static int
cursor_get_list_file_page (CURSOR_ID * cursor_id_p, VPID * vpid_p)
{
  VPID in_vpid;
  int page_size;
  char *page_p;

  /* find page at buffer area */
  if (VPID_EQ (vpid_p, &cursor_id_p->current_vpid))
    {
      /*
       * current_vpid can indicate one of pages in buffer area,
       * so do not assign buffer as head of buffer area
       */
      ;
    }
  else
    {
      cursor_id_p->buffer = NULL;
      if (cursor_id_p->buffer_filled_size > 0)
	{
	  /* it received a page from server */
	  if (VPID_EQ (vpid_p, &cursor_id_p->header_vpid))
	    {
	      /* in case of header vpid in buffer area */
	      cursor_id_p->buffer = cursor_id_p->buffer_area;
	    }
	  else
	    {
	      page_p = cursor_id_p->buffer_area;
	      page_size = 0;

	      while (page_size <
		     (cursor_id_p->buffer_filled_size - CURSOR_BUFFER_SIZE))
		{
		  if (QFILE_GET_OVERFLOW_PAGE_ID (page_p) == NULL_PAGEID)
		    {
		      QFILE_GET_NEXT_VPID (&in_vpid, page_p);
		    }
		  else
		    {
		      QFILE_GET_OVERFLOW_VPID (&in_vpid, page_p);
		    }

		  if (VPID_ISNULL (&in_vpid))
		    {
		      break;
		    }
		  else if (VPID_EQ (vpid_p, &in_vpid))
		    {
		      cursor_id_p->buffer = page_p + CURSOR_BUFFER_SIZE;
		      break;
		    }

		  page_p += CURSOR_BUFFER_SIZE;
		  page_size += CURSOR_BUFFER_SIZE;
		}
	    }
	}
    }

  /* if not found, get the page from server */
  if (cursor_id_p->buffer == NULL)
    {
      if (qfile_get_list_file_page (cursor_id_p->query_id,
				    vpid_p->volid,
				    vpid_p->pageid,
				    cursor_id_p->buffer_area,
				    &cursor_id_p->buffer_filled_size) !=
	  NO_ERROR)
	{
	  return er_errid ();
	}

      cursor_id_p->buffer = cursor_id_p->buffer_area;
      QFILE_COPY_VPID (&cursor_id_p->header_vpid, vpid_p);
    }

  return NO_ERROR;
}