File px_scan_index_key_range_list.cpp¶
File List > cubrid > src > query > parallel > px_scan > index > px_scan_index_key_range_list.cpp
Go to the documentation of this file
/*
*
* 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.
*
*/
/* px_scan_index_key_range_list.cpp — main-thread range conversion + shared BTID_INT. */
#include "px_scan_index_key_range_list.hpp"
#include "btree.h"
#include "btree_load.h"
#include "dbtype.h"
#include "error_code.h"
#include "error_manager.h"
#include "memory_alloc.h"
#include "object_primitive.h"
#include "page_buffer.h"
#include "scan_manager.h"
#include "storage_common.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace parallel_index_scan
{
/* key buffers live on main heap so XASL cleanup's pr_clear_value matches mspace. */
int
key_range_list::init_on_main (THREAD_ENTRY *thread_p, INDX_INFO *indx_info, SCAN_ID *scan_id, val_descr *vd)
{
assert (indx_info != nullptr);
BTID_COPY (&m_btid, &indx_info->btid);
m_indx_info = indx_info;
m_use_desc_index = (indx_info->use_desc_index != 0);
m_key_val_ranges.clear ();
m_part_key_desc = false;
VPID root_vpid;
root_vpid.volid = m_btid.vfid.volid;
root_vpid.pageid = m_btid.root_pageid;
PAGE_PTR root_page = pgbuf_fix (thread_p, &root_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
if (root_page == NULL)
{
ASSERT_ERROR ();
return ER_FAILED;
}
(void) pgbuf_check_page_ptype (thread_p, root_page, PAGE_BTREE);
BTREE_ROOT_HEADER *root_header = btree_get_root_header (thread_p, root_page);
if (root_header == NULL)
{
pgbuf_unfix_and_init (thread_p, root_page);
return ER_FAILED;
}
if (btree_glean_root_header_info (thread_p, root_header, &m_btid_int, true) != NO_ERROR)
{
pgbuf_unfix_and_init (thread_p, root_page);
return ER_FAILED;
}
m_btid_int.sys_btid = &m_btid;
pgbuf_unfix_and_init (thread_p, root_page);
int conv_err = convert_all_key_ranges (thread_p, scan_id, vd);
if (conv_err != NO_ERROR)
{
return conv_err;
}
return NO_ERROR;
}
/* idempotent; sort + part_key_desc swap. */
int
key_range_list::convert_all_key_ranges (THREAD_ENTRY *thread_p, SCAN_ID *worker_scan_id, val_descr *vd)
{
if (!m_key_val_ranges.empty ())
{
return NO_ERROR;
}
int key_cnt = (m_indx_info != nullptr) ? m_indx_info->key_info.key_cnt : 0;
if (key_cnt <= 0)
{
m_key_val_ranges.resize (1);
m_key_val_ranges[0].range = INF_INF;
m_key_val_ranges[0].is_truncated = false;
m_key_val_ranges[0].num_index_term = 0;
db_make_null (&m_key_val_ranges[0].key1);
db_make_null (&m_key_val_ranges[0].key2);
return NO_ERROR;
}
/* scan_id needs coordinator's prebuilt_midxkey_domains; scan_dbvals_to_midxkey NULL-derefs on F_MIDXKEY otherwise. */
if (worker_scan_id == nullptr)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_FAILED, 0);
return ER_FAILED;
}
INDX_SCAN_ID *isidp = &worker_scan_id->s.isid;
TP_DOMAIN *btree_domainp = m_btid_int.key_type;
/* lazy-alloc prebuilt_midxkey_domains (parallel path bypasses scan_open_index_scan); scan_dbvals_to_midxkey would NULL-deref otherwise. */
if (isidp->prebuilt_midxkey_domains == NULL)
{
size_t alloc_size = (size_t) key_cnt * sizeof (TP_DOMAIN *);
isidp->prebuilt_midxkey_domains = (TP_DOMAIN **) db_private_alloc (thread_p, alloc_size);
if (isidp->prebuilt_midxkey_domains == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, alloc_size);
return ER_FAILED;
}
for (int j = 0; j < key_cnt; j++)
{
isidp->prebuilt_midxkey_domains[j] = NULL;
}
}
m_part_key_desc = false;
m_key_val_ranges.resize (key_cnt);
for (int i = 0; i < key_cnt; i++)
{
KEY_RANGE *kr = &m_indx_info->key_info.key_ranges[i];
db_make_null (&m_key_val_ranges[i].key1);
db_make_null (&m_key_val_ranges[i].key2);
m_key_val_ranges[i].range = kr->range;
m_key_val_ranges[i].is_truncated = false;
m_key_val_ranges[i].num_index_term = 0;
if (kr->range == NA_NA || kr->range == INF_INF)
{
continue;
}
int ret = scan_regu_key_to_index_key (thread_p, kr, &m_key_val_ranges[i],
isidp, btree_domainp, vd, i);
if (ret != NO_ERROR)
{
for (int j = 0; j <= i; j++)
{
pr_clear_value (&m_key_val_ranges[j].key1);
pr_clear_value (&m_key_val_ranges[j].key2);
}
m_key_val_ranges.clear ();
return ret;
}
/* Prefix index: truncated bounds become inclusive (GT->GE, LT->LE). */
if (m_key_val_ranges[i].is_truncated)
{
switch (m_key_val_ranges[i].range)
{
case GT_INF:
m_key_val_ranges[i].range = GE_INF;
break;
case GT_LE:
case GT_LT:
case GE_LT:
m_key_val_ranges[i].range = GE_LE;
break;
case INF_LT:
m_key_val_ranges[i].range = INF_LE;
break;
default:
break;
}
}
}
/* part_key_desc detection from first valid range — matches btree_prepare_bts. */
for (int i = 0; i < static_cast<int> (m_key_val_ranges.size ()); i++)
{
if (m_key_val_ranges[i].range != NA_NA && m_key_val_ranges[i].num_index_term > 0)
{
TP_DOMAIN *dom = btree_domainp;
if (dom != nullptr && TP_DOMAIN_TYPE (dom) == DB_TYPE_MIDXKEY)
{
dom = dom->setdomain;
}
for (int k = 1; k < m_key_val_ranges[i].num_index_term && dom != nullptr; k++, dom = dom->next)
;
if (dom != nullptr)
{
m_part_key_desc = (dom->is_desc != 0);
}
break;
}
}
/* full XOR mirrors btree_prepare_bts:15970-15977 — swap whenever traversal direction disagrees with partial-key DESC. */
if ((m_part_key_desc && !m_use_desc_index) || (m_use_desc_index && !m_part_key_desc))
{
for (int i = 0; i < static_cast<int> (m_key_val_ranges.size ()); i++)
{
if (m_key_val_ranges[i].range == NA_NA || m_key_val_ranges[i].range == INF_INF)
{
continue;
}
range_reverse (m_key_val_ranges[i].range);
DB_VALUE tmp_key = m_key_val_ranges[i].key1;
m_key_val_ranges[i].key1 = m_key_val_ranges[i].key2;
m_key_val_ranges[i].key2 = tmp_key;
}
}
/* delegate sort + dedup/merge to scan_manager helper (R_KEYLIST: eliminate_duplicated_keys; R_RANGELIST: merge_key_ranges) so serial and parallel share the same overlap/IN-dup handling. */
if (m_key_val_ranges.size () > 1 && m_indx_info != nullptr)
{
int new_cnt = scan_dedup_or_merge_key_ranges (m_indx_info->range_type, m_key_val_ranges.data (),
static_cast<int> (m_key_val_ranges.size ()));
if (new_cnt < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_FAILED, 0);
m_key_val_ranges.clear ();
return ER_FAILED;
}
m_key_val_ranges.resize (new_cnt);
}
return NO_ERROR;
}
void
key_range_list::cleanup_keys (THREAD_ENTRY *thread_p)
{
/* main thread post worker-release: pr_clear matches db_private_alloc mspace from convert_all_key_ranges. */
for (auto &kvr : m_key_val_ranges)
{
pr_clear_value (&kvr.key1);
pr_clear_value (&kvr.key2);
}
m_key_val_ranges.clear ();
}
}