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