if (m_page_no == FIL_NULL) {
mtr_t alloc_mtr{m_mtr.trx};
dberr_t err= DB_SUCCESS;
/* We commit redo log for allocation by a separate mtr, becausewedon'tguaranteepagesarecommittedfollowing theallocationorder,andwewillalwaysgenerateredolog
for page allocation, even when creating a new tablespace. */
alloc_mtr.start();
m_index->set_modified(alloc_mtr);
/* Allocate a new page. */
new_block = btr_page_alloc(m_index, 0, FSP_UP, m_level,
&alloc_mtr, &m_mtr, &err);
alloc_mtr.commit(); if (!new_block) {
m_mtr.commit(); return err;
}
/** Set the number of owned records in the uncompressed page of
a ROW_FORMAT=COMPRESSED record without redo-logging. */ staticvoid rec_set_n_owned_zip(rec_t *rec, ulint n_owned)
{
rec_set_bit_field_1(rec, n_owned, REC_NEW_N_OWNED,
REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
}
/** Mark end of insertion to the page. Scan all records to set page dirs, andsetpageheadermembers.
@tparam fmt page format */ template<PageBulk::format fmt> inlinevoid PageBulk::finishPage()
{
ut_ad((m_page_zip != nullptr) == (fmt == COMPRESSED));
ut_ad((fmt != REDUNDANT) == m_is_comp);
/** Mark end of insertion to the page. Scan all records to set page dirs, andsetpageheadermembers.
@tparam compressed whether the page is in ROW_FORMAT=COMPRESSED */ inlinevoid PageBulk::finish()
{
ut_ad(!m_index->is_spatial());
if (!needs_finish()); elseif (UNIV_LIKELY_NULL(m_page_zip))
finishPage<COMPRESSED>(); elseif (m_is_comp)
finishPage<DYNAMIC>(); else
finishPage<REDUNDANT>();
/* In MariaDB 10.2, 10.3, 10.4, we would initialize PAGE_DIRECTION_B,PAGE_N_DIRECTION,PAGE_LAST_INSERT inthesamewayaswewouldduringnormalINSERToperations. StartingwithMariaDBServer10.5,bulkinsertwillnot
touch those fields. */
ut_ad(!m_page[PAGE_HEADER + PAGE_INSTANT]); /* Restore the temporary change of PageBulk::init() that was necessary to
ensure that PageBulk::needs_finish() holds on an empty page. */
m_page[PAGE_HEADER + PAGE_DIRECTION_B]= PAGE_NO_DIRECTION;
do {
offsets = rec_get_offsets(rec, m_index, offsets, n_core,
ULINT_UNDEFINED, &m_heap);
insert(rec, offsets);
rec = page_rec_get_next(rec);
} while (!page_rec_is_supremum(rec));
ut_ad(m_rec_no > 0);
}
/** Remove all records after split rec including itself.
@param[in] rec split rec */ void
PageBulk::copyOut(
rec_t* split_rec)
{ /* Suppose before copyOut, we have 5 records on the page: infimum->r1->r2->r3->r4->r5->supremum,andr3isthesplitrec.
aftercopyOut,wehave2recordsonthepage:
infimum->r1->r2->supremum. slot ajustment is not done. */
/** Set next page
@param[in] next_page_no next page no */ inlinevoid PageBulk::setNext(ulint next_page_no)
{ if (UNIV_LIKELY_NULL(m_page_zip)) /* For ROW_FORMAT=COMPRESSED, redo log may be written
in PageBulk::compress(). */
mach_write_to_4(m_page + FIL_PAGE_NEXT, next_page_no); else
m_mtr.write<4>(*m_block, m_page + FIL_PAGE_NEXT, next_page_no);
}
/** Set previous page
@param[in] prev_page_no previous page no */ inlinevoid PageBulk::setPrev(ulint prev_page_no)
{ if (UNIV_LIKELY_NULL(m_page_zip)) /* For ROW_FORMAT=COMPRESSED, redo log may be written
in PageBulk::compress(). */
mach_write_to_4(m_page + FIL_PAGE_PREV, prev_page_no); else
m_mtr.write<4>(*m_block, m_page + FIL_PAGE_PREV, prev_page_no);
}
/** Check if required space is available in the page for the rec to be inserted. Wecheckfillfactor&paddinghere. @param[in]lengthrequiredlength
@return true if space is available */ bool
PageBulk::isSpaceAvailable(
ulint rec_size)
{ if (m_rec_no >= 8190) {
ut_ad(srv_page_size == 65536); returnfalse;
}
if (required_space > m_free_space) {
ut_ad(m_rec_no > 0); returnfalse;
}
/* Fillfactor & Padding apply to both leaf and non-leaf pages. Note:wekeepatleast2recordsinapagetoavoidB-treelevel
growing too high. */ if (m_rec_no >= 2
&& ((m_page_zip == NULL && m_free_space - required_space
< m_reserved_space)
|| (m_page_zip != NULL && m_free_space - required_space
< m_padding_space))) { return(false);
}
return(true);
}
/** Check whether the record needs to be stored externally.
@return false if the entire record can be stored locally on the page */ bool
PageBulk::needExt( const dtuple_t* tuple,
ulint rec_size)
{ return page_zip_rec_needs_ext(rec_size, m_is_comp,
dtuple_get_n_fields(tuple),
m_block->zip_size());
}
if (page_bulk->getRecNo() <= 1) { return(DB_TOO_BIG_RECORD);
}
/* Initialize a new page */
PageBulk new_page_bulk(m_index, m_trx, FIL_NULL,
page_bulk->getLevel());
dberr_t err = new_page_bulk.init(); if (err != DB_SUCCESS) { return(err);
}
/* Copy the upper half to the new page. */
rec_t* split_rec = page_bulk->getSplitRec();
new_page_bulk.copyIn(split_rec);
page_bulk->copyOut(split_rec);
/* Commit the pages after split. */
err = pageCommit(page_bulk, &new_page_bulk, true); if (err != DB_SUCCESS) {
pageAbort(&new_page_bulk); return(err);
}
/** Commit(finish) a page. We set next/prev page no, compress a page of compressedtableandsplitthepageifcompressionfails,insertanode pointertofatherpageifneeded,andcommitmini-transaction. @param[in]page_bulkpagetocommit @param[in]next_page_bulknextpage @param[in]insert_fatherfalsewhenpage_bulkisarootpageand truewhenit'sanon-rootpage
@return error code */
dberr_t
BtrBulk::pageCommit(
PageBulk* page_bulk,
PageBulk* next_page_bulk, bool insert_father)
{
page_bulk->finish();
/* Set page links */ if (next_page_bulk != NULL) {
ut_ad(page_bulk->getLevel() == next_page_bulk->getLevel());
page_bulk->setNext(next_page_bulk->getPageNo());
next_page_bulk->setPrev(page_bulk->getPageNo());
} else {
ut_ad(!page_has_next(page_bulk->getPage())); /* If a page is released and latched again, we need to
mark it modified in mini-transaction. */
page_bulk->set_modified();
}
ut_ad(!m_index->lock.have_any());
/* Compress page if it's a compressed table. */ if (page_bulk->getPageZip() != NULL && !page_bulk->compress()) { return(pageSplit(page_bulk, next_page_bulk));
}
/* Insert node pointer to father page. */ if (insert_father) {
dtuple_t* node_ptr = page_bulk->getNodePtr();
dberr_t err = insert(node_ptr, page_bulk->getLevel()+1);
/** Insert a tuple to page in a level @param[in]tupletupletoinsert @param[in]levelB-treelevel
@return error code */
dberr_t
BtrBulk::insert(
dtuple_t* tuple,
ulint level)
{ bool is_left_most = false;
dberr_t err = DB_SUCCESS;
/* Check if we need to create a PageBulk for the level. */ if (level + 1 > m_page_bulks.size()) {
PageBulk* new_page_bulk
= UT_NEW_NOKEY(PageBulk(m_index, m_trx, FIL_NULL,
level));
err = new_page_bulk->init(); if (err != DB_SUCCESS) {
UT_DELETE(new_page_bulk); return(err);
}
if (is_left_most && level > 0 && page_bulk->getRecNo() == 0) { /* The node pointer must be marked as the predefined minimum record,asthereisnoloweralphabeticallimittorecordsin
the leftmost node of a level: */
dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
| REC_INFO_MIN_REC_FLAG);
}
if (page_bulk->needExt(tuple, rec_size)) { /* The record is so big that we have to store some fields
externally on separate database pages */
big_rec = dtuple_convert_big_rec(m_index, 0, tuple, &n_ext);
if (big_rec == NULL) { return(DB_TOO_BIG_RECORD);
}
/* Important: log_free_check whether we need a checkpoint. */ if (page_is_leaf(sibling_page_bulk->getPage())) { if (trx_is_interrupted(m_trx)) {
err = DB_INTERRUPTED; goto func_exit;
}
func_exit: if (big_rec != NULL) {
dtuple_convert_back_big_rec(m_index, tuple, big_rec);
}
return(err);
}
/** Btree bulk load finish. We commit the last page in each level andcopythelastpageintopleveltotherootpageoftheindex ifnoerroroccurs. @param[in]errwhetherbulkloadwassuccessfuluntilnow
@return error code */
dberr_t
BtrBulk::finish(dberr_t err)
{
uint32_t last_page_no = FIL_NULL;
ut_ad(!m_index->table->is_temporary());
if (m_page_bulks.size() == 0) { /* The table is empty. The root page of the index tree
is already in a consistent state. No need to flush. */ return(err);
}
ut_ad(m_root_level + 1 == m_page_bulks.size());
/* Finish all page bulks */ for (ulint level = 0; level <= m_root_level; level++) {
PageBulk* page_bulk = m_page_bulks.at(level);
first_rec = page_rec_get_next(
page_get_infimum_rec(last_block->page.frame)); /* Because this index tree is being created by this thread,
we assume that it cannot be corrupted. */
ut_ad(first_rec);
ut_ad(page_rec_is_user_rec(first_rec));
/* Copy last page to root page. */
err = root_page_bulk.init(); if (err != DB_SUCCESS) { goto err_exit;
}
root_page_bulk.copyIn(first_rec);
root_page_bulk.finish();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.