EM scaleability project has two parts: phase1 and phase2.
This is phase1 that brings EM index to speed up(from O(n) down
to the speed of boost::unordered_map) EM lookups looking for
<dbroot, oid, partition> tuple to turn it into LBID,
e.g. most bulk insertion meta info operations.
The basis is boost::shared_managed_object where EMIndex is
stored. Whilst it is not debug-friendly it allows to put a
nested structs into shmem. EMIndex has 3 tiers. Top down description:
vector of dbroots, map of oids to partition vectors, partition
vectors that have EM indices.
Separate EM methods now queries index before they do EM run.
EMIndex has a separate shmem file with the fixed id
MCS-shm-00060001.
* MCOL-4560 remove unused xml entries and code that references it.
There is reader code and variables for some of these settings, but nobody uses them.
EM and PP are most resource-hungry runtimes.
The merge enables to control their cummulative
resource consumption, thread allocation + enables
zero-copy data exchange b/w local EM and PP facilities.
The idea is relatively simple - encode prefixes of collated strings as
integers and use them to compute extents' ranges. Then we can eliminate
extents with strings.
The actual patch does have all the code there but miss one important
step: we do not keep collation index, we keep charset index. Because of
this, some of the tests in the bugfix suite fail and thus main
functionality is turned off.
The reason of this patch to be put into PR at all is that it contains
changes that made CHAR/VARCHAR columns unsigned. This change is needed in
vectorization work.
* Fix clang warnings
* Remove vim tab guides
* initialize variables
* 'strncpy' output truncated before terminating nul copying as many bytes from a string as its length
* Fix ISO C++17 does not allow 'register' storage class specifier for outdated bison
* chars are unsigned on ARM, having if (ival < 0) always false
* chars are unsigned by default on ARM and comparison with -1 if always true
Part 1:
As part of MCOL-3776 to address synchronization issue while accessing
the fTimeZone member of the Func class, mutex locks were added to the
accessor and mutator methods. However, this slows down processing
of TIMESTAMP columns in PrimProc significantly as all threads across
all concurrently running queries would serialize on the mutex. This
is because PrimProc only has a single global object for the functor
class (class derived from Func in utils/funcexp/functor.h) for a given
function name. To fix this problem:
(1) We remove the fTimeZone as a member of the Func derived classes
(hence removing the mutexes) and instead use the fOperationType
member of the FunctionColumn class to propagate the timezone values
down to the individual functor processing functions such as
FunctionColumn::getStrVal(), FunctionColumn::getIntVal(), etc.
(2) To achieve (1), a timezone member is added to the
execplan::CalpontSystemCatalog::ColType class.
Part 2:
Several functors in the Funcexp code call dataconvert::gmtSecToMySQLTime()
and dataconvert::mySQLTimeToGmtSec() functions for conversion between seconds
since unix epoch and broken-down representation. These functions in turn call
the C library function localtime_r() which currently has a known bug of holding
a global lock via a call to __tz_convert. This significantly reduces performance
in multi-threaded applications where multiple threads concurrently call
localtime_r(). More details on the bug:
https://sourceware.org/bugzilla/show_bug.cgi?id=16145
This bug in localtime_r() caused processing of the Functors in PrimProc to
slowdown significantly since a query execution causes Functors code to be
processed in a multi-threaded manner.
As a fix, we remove the calls to localtime_r() from gmtSecToMySQLTime()
and mySQLTimeToGmtSec() by performing the timezone-to-offset conversion
(done in dataconvert::timeZoneToOffset()) during the execution plan
creation in the plugin. Note that localtime_r() is only called when the
time_zone system variable is set to "SYSTEM".
This fix also required changing the timezone type from a std::string to
a long across the system.
DML statements executed on the primary node in a ColumnStore
cluster do not need to be written to the primary's binlog. This
is due to ColumnStore's distributed storage architecture.
With this patch, we disable writing to binlog when a DML statement
(INSERT/DELETE/UPDATE/LDI/INSERT..SELECT) is performed on a ColumnStore
table. HANDLER::external_lock() calls are used to
1. Turn OFF the OPTION_BIN_LOG flag
2. Turn ON the OPTION_BIN_TMP_LOG_OFF flag
in THD::variables.option_bits during a WRITE lock call.
THD::variables.option_bits is restored back to the original state
during the UNLOCK call in HANDLER::external_lock().
Further, isDMLStatement() function is added to reduce code verbosity
to check if a given statement is a DML statement.
Note that with this patch, not writing to primary's binlog means
DML replication from a ColumnStore cluster to another ColumnStore
cluster or to another foreign engine will not work.
on a non-ColumnStore table does not work.
As part of MCOL-4617, we moved the in-to-exists predicate creation
and injection from the server into the engine. However, when query
with an IN Subquery contains a non-ColumnStore table, the server
still performs the in-to-exists predicate transformation for the
foreign engine table. This caused ColumnStore's execution plan to
contain incorrect WHERE predicates. As a fix, we call
mutate_optimizer_flags() for the WRITE lock, in addition to the READ
table lock. And in mutate_optimizer_flags(), we change the optimizer
flag from OPTIMIZER_SWITCH_IN_TO_EXISTS to OPTIMIZER_SWITCH_MATERIALIZATION.
data types TEXT, CHAR, VARCHAR, FLOAT and DOUBLE are not yet supported by vectorized path
This patch introduces an example for Google benchmarking suite to measure a perf diff
b/w legacy scan/filtering code and the templated version
wide decimal column in a non-ColumnStore table throws an exception.
ROW::getSignedNullValue() method does not support wide decimal fields
yet. To fix this exception, we remove the call to this method from
CrossEngineStep::setField().
* MCOL-4769 Do not replay INSERTs and LDIs on the replica nodes when
the write cache is enabled.
* MCOL-4769 If a table is created with the write cache disabled
(i.e. when columnstore_cache_inserts=OFF), make it accessible when
the cache feature is enabled (columnstore_cache_inserts=ON).
This patch changes the logic of the `receiveMultiPrimitiveMessages`
function in the following way:
1. We have only one aggregation thread which reads the data from Queue (which is populated
by messages from BPPs).
2. Processing of the received `bytestream vector` could be in parallel depends on the
type of `TupleBPS` operation (join, fe2, ...) and actual thread pool workload.
The motivation is to eliminate some amount of context switches.
After an AggreateColumn corresponding to SUM(1+1) is created,
it is pushed to the list:
gwi.count_asterisk_list.push_back(ac)
Later, in getSelectPlan(), the expression SUM(1+1) was erroneously
treated as a constant:
if (!hasNonSupportItem && !nonConstFunc(ifp) && !(parseInfo & AF_BIT) && tmpVec.size() == 0)
{
srcp.reset(buildReturnedColumn(item, gwi, gwi.fatalParseError));
This code freed the original AggregateColumn and replaced to a ConstantColumn.
But gwi.count_asterisk_list still pointer to the freed AggregateColumn().
The expression SUM(1+1) was treated as a constant because tmpVec
was empty due to a bug in this code:
// special handling for count(*). This should not be treated as constant.
if (isp->argument_count() == 1 &&
( sfitempp[0]->type() == Item::CONST_ITEM &&
(sfitempp[0]->cmp_type() == INT_RESULT ||
sfitempp[0]->cmp_type() == STRING_RESULT ||
sfitempp[0]->cmp_type() == REAL_RESULT ||
sfitempp[0]->cmp_type() == DECIMAL_RESULT)
)
)
{
field_vec.push_back((Item_field*)item); //dummy
Notice, it handles only aggregate functions with explicit literals
passed as an argument, while it does not handle constant expressions
such as 1+1.
Fix:
- Adding new classes ConstantColumnNull, ConstantColumnString,
ConstantColumnNum, ConstantColumnUInt, ConstantColumnSInt,
ConstantColumnReal, ValStrStdString, to reuse the code easier.
- Moving a part of the code from the case branch handling CONST_ITEM
in buildReturnedColumn() into a new function
newConstantColumnNotNullUsingValNativeNoTz(). This
makes the code easier to read and to reuse in the future.
- Adding a new function newConstantColumnMaybeNullFromValStrNoTz().
Removing dulplicate code from !!!four!!! places, using the new
function instead.
- Adding a function isSupportedAggregateWithOneConstArg() to
properly catch all constant expressions. Using the new function parse_item()
in the code commented as "special handling for count(*)".
Now it pushes all constant expressions to field_vec, not only
explicit literals.
- Moving a part of the code from buildAggregateColumn()
to a helper function processAggregateColumnConstArg().
Using processAggregateColumnConstArg() in the CONST_ITEM
and NULL_ITEM branches.
- Adding a new branch in buildReturnedColumn() handling FUNC_ITEM.
If a function has constant arguments, a ConstantColumn() is
immediately created, without going to
buildArithmeticColumn()/buildFunctionColumn().
- Reusing isSupportedAggregateWithOneConstArg()
and processAggregateColumnConstArg() in buildAggregateColumn().
A new branch catches aggregate function has only one constant argument
and immediately creates a single ConstantColumn without
traversing to the argument sub-components.
When an outer query filter accesses an subquery column that contains an aggregate or a window function, certain optimizations can't be performed. We had been looking at the surface of the returned column. We now iterate into any functions or operations looking for aggregates and window functions.