Beispiel #1
0
/*
 * cursor_open () -
 *   return: true on all ok, false otherwise
 *   cursor_id(out): Cursor identifier
 *   list_id: List file identifier
 *   updatable: Flag which indicates if cursor is updatable
 *   is_oid_included: Flag which indicates if first column of the list file
 *                 contains hidden object identifiers
 *
 * Note: A cursor is opened to scan through the tuples of the given
 *       list file. The cursor identifier is initialized and memory
 *       buffer for the cursor identifier is allocated. If is_oid_included
 *       flag is set to true, this indicates that the first column
 *       of list file tuples contains the object identifier to be used
 *       for cursor update/delete operations.
 */
bool
cursor_open (CURSOR_ID * cursor_id_p, QFILE_LIST_ID * list_id_p,
	     bool updatable, bool is_oid_included)
{
  static QFILE_LIST_ID empty_list_id;	/* TODO: remove static empty_list_id */

  QFILE_CLEAR_LIST_ID (&empty_list_id);

  cursor_id_p->is_updatable = updatable;
  cursor_id_p->is_oid_included = is_oid_included;
  cursor_id_p->oid_ent_count = 0;
  cursor_id_p->oid_set = NULL;
  cursor_id_p->mop_set = NULL;
  cursor_id_p->position = C_BEFORE;
  cursor_id_p->tuple_no = -1;
  VPID_SET_NULL (&cursor_id_p->current_vpid);
  VPID_SET_NULL (&cursor_id_p->next_vpid);
  VPID_SET_NULL (&cursor_id_p->header_vpid);
  cursor_id_p->tuple_record.size = 0;
  cursor_id_p->tuple_record.tpl = NULL;
  cursor_id_p->on_overflow = false;
  cursor_id_p->buffer_tuple_count = 0;
  cursor_id_p->current_tuple_no = -1;
  cursor_id_p->current_tuple_offset = -1;
  cursor_id_p->current_tuple_p = NULL;
  cursor_id_p->current_tuple_length = -1;
  cursor_id_p->oid_col_no = NULL;
  cursor_id_p->oid_col_no_cnt = 0;
  cursor_id_p->buffer = NULL;
  cursor_id_p->buffer_area = NULL;
  cursor_id_p->buffer_filled_size = 0;
  cursor_id_p->list_id = empty_list_id;
  cursor_id_p->prefetch_lock_mode = DB_FETCH_READ;
  cursor_id_p->is_copy_tuple_value = true;	/* copy */
  cursor_initialize_current_tuple_value_position (cursor_id_p);

  if (cursor_copy_list_id (&cursor_id_p->list_id, list_id_p) != NO_ERROR)
    {
      return false;
    }

  if (cursor_id_p->list_id.type_list.type_cnt)
    {
      cursor_id_p->buffer_area = (char *) malloc (CURSOR_BUFFER_AREA_SIZE);
      cursor_id_p->buffer = cursor_id_p->buffer_area;

      if (cursor_id_p->buffer == NULL)
	{
	  return false;
	}

      if (is_oid_included)
	{
	  cursor_allocate_oid_buffer (cursor_id_p);
	}
    }

  return true;
}
Beispiel #2
0
/*
 * overflow_rv_newpage_link_undo () - Undo allocation of new overflow page and the
 *                               reference to it
 *   return: 0 if no error, or error code
 *   rcv(in): Recovery structure
 */
int
overflow_rv_newpage_link_undo (THREAD_ENTRY * thread_p, LOG_RCV * rcv)
{
  OVERFLOW_REST_PART *rest_parts;

  rest_parts = (OVERFLOW_REST_PART *) rcv->pgptr;
  VPID_SET_NULL (&rest_parts->next_vpid);
  pgbuf_set_dirty (thread_p, rcv->pgptr, DONT_FREE);

  return NO_ERROR;
}
Beispiel #3
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;
}
Beispiel #4
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;
}