File record_descriptor.cpp¶
File List > cubrid > src > storage > record_descriptor.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
//
// record_descriptor.cpp - extended functionality of recdes
//
#include "record_descriptor.hpp"
#include "error_code.h"
#include "memory_alloc.h"
#include "packer.hpp"
#include "slotted_page.h"
#include <cstring>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
// record_descriptor extends functionality for recdes:
//
// typedef struct recdes RECDES; /* RECORD DESCRIPTOR */
// struct recdes
// {
// int area_size; /* Length of the allocated area. It includes only the data field. The value is negative
// * if data is inside buffer. For example, peeking in a slotted page. */
// int length; /* Length of the data. Does not include the length and type fields */
// INT16 type; /* Type of record */
// char *data; /* The data */
// };
//
record_descriptor::record_descriptor (const cubmem::block_allocator &alloc /* = cubmem::PRIVATE_BLOCK_ALLOCATOR */)
: m_recdes ()
, m_own_data (alloc)
, m_data_source (data_source::INVALID)
{
m_recdes.area_size = 0;
m_recdes.length = 0;
m_recdes.type = REC_HOME;
m_recdes.data = NULL;
}
record_descriptor::record_descriptor (const recdes &rec,
const cubmem::block_allocator &alloc /* = cubmem::PRIVATE_BLOCK_ALLOCATOR */)
: record_descriptor (alloc)
{
set_recdes (rec);
}
record_descriptor::record_descriptor (record_descriptor &&other)
{
m_recdes = other.m_recdes;
m_own_data = std::move (other.m_own_data);
m_data_source = other.m_data_source;
other.m_data_source = data_source::INVALID;
other.m_recdes.data = NULL;
other.m_recdes.type = REC_UNKNOWN;
}
record_descriptor::record_descriptor (const char *data, std::size_t size)
: record_descriptor ()
{
set_data (data, size);
}
record_descriptor::~record_descriptor (void)
{
}
void
record_descriptor::set_recdes (const recdes &rec)
{
assert (m_data_source == data_source::INVALID);
m_recdes.type = rec.type;
if (rec.length != 0)
{
// copy content from argument
m_recdes.area_size = rec.length;
m_recdes.length = m_recdes.area_size;
m_own_data.extend_to ((std::size_t) m_recdes.area_size);
m_recdes.data = m_own_data.get_ptr ();
std::memcpy (m_recdes.data, rec.data, m_recdes.length);
m_data_source = data_source::COPIED; // we assume this is a copied record
}
}
int
record_descriptor::peek (cubthread::entry *thread_p, PAGE_PTR page, PGSLOTID slotid)
{
return get (thread_p, page, slotid, record_get_mode::PEEK_RECORD);
}
int
record_descriptor::copy (cubthread::entry *thread_p, PAGE_PTR page, PGSLOTID slotid)
{
return get (thread_p, page, slotid, record_get_mode::COPY_RECORD);
}
int
record_descriptor::get (cubthread::entry *thread_p, PAGE_PTR page, PGSLOTID slotid, record_get_mode mode)
{
int mode_to_int = static_cast<int> (mode);
SCAN_CODE sc = spage_get_record (thread_p, page, slotid, &m_recdes, mode_to_int);
if (sc == S_SUCCESS)
{
update_source_after_get (mode);
return NO_ERROR;
}
if (sc == S_DOESNT_FIT)
{
// extend and try again
assert (m_recdes.length < 0);
assert (mode == record_get_mode::COPY_RECORD);
std::size_t required_size = static_cast<std::size_t> (-m_recdes.length);
resize_buffer (required_size);
sc = spage_get_record (thread_p, page, slotid, &m_recdes, mode_to_int);
if (sc == S_SUCCESS)
{
update_source_after_get (mode);
return NO_ERROR;
}
}
// failed
assert (false);
return ER_FAILED;
}
void
record_descriptor::resize_buffer (std::size_t required_size)
{
assert (m_data_source == data_source::INVALID || is_mutable ());
if (m_recdes.area_size > 0 && required_size <= (std::size_t) m_recdes.area_size)
{
// resize not required
return;
}
m_own_data.extend_to (required_size);
m_recdes.data = m_own_data.get_ptr ();
m_recdes.area_size = (int) required_size;
if (m_data_source == data_source::INVALID)
{
m_data_source = data_source::NEW;
}
}
void
record_descriptor::update_source_after_get (record_get_mode mode)
{
switch (mode)
{
case record_get_mode::PEEK_RECORD:
m_data_source = data_source::PEEKED;
break;
case record_get_mode::COPY_RECORD:
m_data_source = data_source::COPIED;
break;
default:
assert (false);
m_data_source = data_source::INVALID;
break;
}
}
const recdes &
record_descriptor::get_recdes (void) const
{
assert (m_data_source != data_source::INVALID);
return m_recdes;
}
const char *
record_descriptor::get_data (void) const
{
assert (m_data_source != data_source::INVALID);
return m_recdes.data;
}
std::size_t
record_descriptor::get_size (void) const
{
assert (m_data_source != data_source::INVALID);
assert (m_recdes.length > 0);
return static_cast<std::size_t> (m_recdes.length);
}
char *
record_descriptor::get_data_for_modify (void)
{
check_changes_are_permitted ();
return m_recdes.data;
}
void
record_descriptor::set_data (const char *data, std::size_t size)
{
// data is assigned and cannot be changed
m_data_source = data_source::IMMUTABLE;
m_recdes.data = const_cast<char *> (data); // status will protect against changes
m_recdes.length = (int) size;
}
void
record_descriptor::set_record_length (std::size_t length)
{
check_changes_are_permitted ();
assert (m_recdes.area_size >= 0 && length <= (size_t) m_recdes.area_size);
m_recdes.length = (int) length;
}
void
record_descriptor::set_type (std::int16_t type)
{
check_changes_are_permitted ();
m_recdes.type = type;
}
void
record_descriptor::set_external_buffer (char *buf, std::size_t buf_size)
{
m_own_data.freemem ();
m_recdes.data = buf;
m_recdes.area_size = (int) buf_size;
m_data_source = data_source::NEW;
}
void
record_descriptor::move_data (std::size_t dest_offset, std::size_t source_offset)
{
check_changes_are_permitted ();
// should replace RECORD_MOVE_DATA
if (dest_offset == source_offset)
{
// no moving
return;
}
std::size_t rec_size = get_size ();
// safe-guard: source offset cannot be outside record
assert (rec_size >= source_offset);
std::size_t memmove_size = rec_size - source_offset;
std::size_t new_size = rec_size + dest_offset - source_offset;
if (dest_offset > source_offset)
{
// record is being increased; make sure we have enough space
resize_buffer (new_size);
}
if (memmove_size > 0)
{
std::memmove (m_recdes.data + dest_offset, m_recdes.data + source_offset, memmove_size);
}
m_recdes.length = static_cast<int> (new_size);
}
void
record_descriptor::modify_data (std::size_t offset, std::size_t old_size, std::size_t new_size, const char *new_data)
{
check_changes_are_permitted ();
// should replace RECORD_REPLACE_DATA
move_data (offset + new_size, offset + old_size);
if (new_size > 0)
{
std::memcpy (m_recdes.data + offset, new_data, new_size);
}
}
void
record_descriptor::delete_data (std::size_t offset, std::size_t data_size)
{
check_changes_are_permitted ();
// just move data
move_data (offset, offset + data_size);
}
void
record_descriptor::insert_data (std::size_t offset, std::size_t new_size, const char *new_data)
{
modify_data (offset, 0, new_size, new_data);
}
void
record_descriptor::check_changes_are_permitted (void) const
{
assert (is_mutable ());
}
bool
record_descriptor::is_mutable () const
{
return m_data_source == data_source::COPIED || m_data_source == data_source::NEW;
}
void
record_descriptor::pack (cubpacking::packer &packer) const
{
packer.pack_short (m_recdes.type);
packer.pack_buffer_with_length (m_recdes.data, m_recdes.length);
}
void
record_descriptor::unpack (cubpacking::unpacker &unpacker)
{
// resize_buffer requires m_data_source to be set
m_data_source = data_source::COPIED;
unpacker.unpack_short (m_recdes.type);
unpacker.peek_unpack_buffer_length (m_recdes.length);
resize_buffer (m_recdes.length);
unpacker.unpack_buffer_with_length (m_recdes.data, m_recdes.length);
}
std::size_t
record_descriptor::get_packed_size (cubpacking::packer &packer, std::size_t curr_offset) const
{
std::size_t entry_size = packer.get_packed_short_size (curr_offset);
entry_size += packer.get_packed_buffer_size (m_recdes.data, m_recdes.length, entry_size);
return entry_size;
}
void
record_descriptor::release_buffer (char *&data, std::size_t &size)
{
size = m_own_data.get_size ();
data = m_own_data.release_ptr ();
}