polardbxengine/storage/innobase/lob/lob0pages.cc

223 lines
6.7 KiB
C++

/*****************************************************************************
Copyright (c) 2016, 2019, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Free Software Foundation.
This program is also distributed with certain software (including but not
limited to OpenSSL) that is licensed under separate terms, as designated in a
particular file or component or in included license documentation. The authors
of MySQL hereby grant you an additional permission to link the program and
your derivative works with the separately licensed software that they have
included with MySQL.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "lob0pages.h"
#include "lob0impl.h"
#include "my_dbug.h"
#include "trx0trx.h"
namespace lob {
void data_page_t::replace_inline(trx_t *trx, ulint offset, const byte *&ptr,
ulint &want, mtr_t *mtr) {
byte *old_ptr = data_begin() + offset;
ulint data_len = get_data_len();
ut_ad(data_len > offset);
/** Copy the new data to page. */
ulint data_avail = data_len - offset;
ulint data_to_copy = want > data_avail ? data_avail : want;
mlog_write_string(old_ptr, ptr, data_to_copy, mtr);
ptr += data_to_copy;
want -= data_to_copy;
}
/** Create a new data page and replace some or all parts of the old data
with data.
@param[in] trx the current transaction.
@param[in] offset the offset where replace begins.
@param[in,out] ptr pointer to new data.
@param[in] want amount of data the caller wants to replace.
@param[in] mtr the mini transaction context.
@return the buffer block of the new data page. */
buf_block_t *data_page_t::replace(trx_t *trx, ulint offset, const byte *&ptr,
ulint &want, mtr_t *mtr) {
ulint cur_data_len = get_data_len();
ut_a(offset > 0 || want < cur_data_len);
buf_block_t *new_block = nullptr;
/** Allocate a new data page. */
data_page_t new_page(mtr, m_index);
new_block = new_page.alloc(mtr, false);
if (new_block == nullptr) {
return (nullptr);
}
byte *new_ptr = new_page.data_begin();
byte *old_ptr = data_begin();
DBUG_LOG("data_page_t", PrintBuffer(old_ptr, cur_data_len));
DBUG_LOG("data_page_t", "offset=" << offset << ", want=" << want);
new_page.set_trx_id(trx->id);
new_page.set_data_len(get_data_len());
/** Copy contents from old page to new page. */
mlog_write_string(new_ptr, old_ptr, offset, mtr);
new_ptr += offset;
old_ptr += offset;
/** Copy the new data to new page. */
ulint data_avail = get_data_len() - offset;
ulint data_to_copy = want > data_avail ? data_avail : want;
mlog_write_string(new_ptr, ptr, data_to_copy, mtr);
new_ptr += data_to_copy;
old_ptr += data_to_copy;
ptr += data_to_copy;
/** Copy contents from old page to new page. */
if (want < data_avail) {
ut_ad(data_to_copy == want);
ulint remain = data_avail - want;
mlog_write_string(new_ptr, old_ptr, remain, mtr);
}
want -= data_to_copy;
DBUG_LOG("data_page_t", PrintBuffer(new_page.data_begin(), cur_data_len));
return (new_block);
}
/** Append given data in data page.
@param[in] trxid transaction doing append.
@param[in,out] data data to be appended.
@param[in,out] len length of data.
@return number of bytes appended. */
ulint data_page_t::append(trx_id_t trxid, byte *&data, ulint &len) {
DBUG_TRACE;
ulint old_data_len = get_data_len();
byte *ptr = data_begin() + old_data_len;
ulint space_available = max_space_available() - old_data_len;
if (space_available == 0 || len == 0) {
return 0;
}
ulint written = (len > space_available) ? space_available : len;
mlog_write_string(ptr, data, written, m_mtr);
set_data_len(old_data_len + written);
set_trx_id(trxid);
data += written;
len -= written;
return written;
}
ulint data_page_t::space_left() const { return (payload() - get_data_len()); }
buf_block_t *data_page_t::alloc(mtr_t *alloc_mtr, bool is_bulk) {
ut_ad(m_block == nullptr);
ut_ad(m_index != nullptr);
ut_ad(m_mtr != nullptr);
ut_ad(alloc_mtr != nullptr);
page_no_t hint = FIL_NULL;
/* For testing purposes, pretend that the LOB page allocation failed.*/
DBUG_EXECUTE_IF("innodb_lob_data_page_alloc_failed", return (nullptr););
m_block = alloc_lob_page(m_index, alloc_mtr, hint, is_bulk);
if (m_block == nullptr) {
return (m_block);
}
set_page_type();
set_version_0();
set_next_page_null();
page_type_t type = fil_page_get_type(m_block->frame);
ut_a(type == FIL_PAGE_TYPE_LOB_DATA);
return (m_block);
}
/** Write data into a data page.
@param[in] trxid the transaction identifier of the session writing data.
@param[in,out] data the data to be written. it will be updated to point
to the byte not yet written.
@param[in,out] len length of data available to be written.
@return amount of data actually written into the page. */
ulint data_page_t::write(trx_id_t trxid, const byte *&data, ulint &len) {
byte *ptr = data_begin();
ulint written = (len > payload()) ? payload() : len;
/* Write data into page. */
mlog_write_string(ptr, data, written, m_mtr);
set_data_len(written);
data += written;
len -= written;
return (written);
}
buf_block_t *data_page_t::load_x(page_no_t page_no) {
ut_ad(m_mtr != nullptr);
ut_ad(m_index != nullptr);
space_id_t space_id = dict_index_get_space(m_index);
const page_id_t page_id(space_id, page_no);
const page_size_t page_size = dict_table_page_size(m_index->table);
m_block = buf_page_get(page_id, page_size, RW_X_LATCH, m_mtr);
return (m_block);
}
/** Read data from the data page.
@param[in] offset read begins at this offset.
@param[out] ptr the output buffer.
@param[in] want bytes to read
@return bytes actually read. */
ulint data_page_t::read(ulint offset, byte *ptr, ulint want) {
DBUG_TRACE;
byte *start = data_begin();
start += offset;
ulint avail_data = get_data_len() - offset;
ulint copy_len = want < avail_data ? want : avail_data;
memcpy(ptr, start, copy_len);
DBUG_LOG("lob", "page_no=" << get_page_no());
DBUG_LOG("lob", PrintBuffer(ptr, copy_len));
return copy_len;
}
} // namespace lob