OmniSciDB  06b3bd477c
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ColumnarResults Class Reference

#include <ColumnarResults.h>

Public Types

using ReadFunction = std::function< int64_t(const ResultSet &, const size_t, const size_t, const size_t)>
 
using WriteFunction = std::function< void(const ResultSet &, const size_t, const size_t, const size_t, const size_t, const ReadFunction &)>
 

Public Member Functions

 ColumnarResults (const std::shared_ptr< RowSetMemoryOwner > row_set_mem_owner, const ResultSet &rows, const size_t num_columns, const std::vector< SQLTypeInfo > &target_types, const bool is_parallel_execution_enforced=false)
 
 ColumnarResults (const std::shared_ptr< RowSetMemoryOwner > row_set_mem_owner, const int8_t *one_col_buffer, const size_t num_rows, const SQLTypeInfo &target_type)
 
const std::vector< int8_t * > & getColumnBuffers () const
 
const size_t size () const
 
const SQLTypeInfogetColumnType (const int col_id) const
 
bool isParallelConversion () const
 
bool isDirectColumnarConversionPossible () const
 

Static Public Member Functions

static std::unique_ptr
< ColumnarResults
mergeResults (const std::shared_ptr< RowSetMemoryOwner > row_set_mem_owner, const std::vector< std::unique_ptr< ColumnarResults >> &sub_results)
 

Protected Attributes

std::vector< int8_t * > column_buffers_
 
size_t num_rows_
 

Private Member Functions

 ColumnarResults (const size_t num_rows, const std::vector< SQLTypeInfo > &target_types)
 
void writeBackCell (const TargetValue &col_val, const size_t row_idx, const size_t column_idx)
 
void materializeAllColumnsDirectly (const ResultSet &rows, const size_t num_columns)
 
void materializeAllColumnsThroughIteration (const ResultSet &rows, const size_t num_columns)
 
void materializeAllColumnsGroupBy (const ResultSet &rows, const size_t num_columns)
 
void materializeAllColumnsProjection (const ResultSet &rows, const size_t num_columns)
 
void copyAllNonLazyColumns (const std::vector< ColumnLazyFetchInfo > &lazy_fetch_info, const ResultSet &rows, const size_t num_columns)
 
void materializeAllLazyColumns (const std::vector< ColumnLazyFetchInfo > &lazy_fetch_info, const ResultSet &rows, const size_t num_columns)
 
void locateAndCountEntries (const ResultSet &rows, ColumnBitmap &bitmap, std::vector< size_t > &non_empty_per_thread, const size_t entry_count, const size_t num_threads, const size_t size_per_thread) const
 
void compactAndCopyEntries (const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)
 
void compactAndCopyEntriesWithTargetSkipping (const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const std::vector< size_t > &global_offsets, const std::vector< bool > &targets_to_skip, const std::vector< size_t > &slot_idx_per_target_idx, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)
 
void compactAndCopyEntriesWithoutTargetSkipping (const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const std::vector< size_t > &global_offsets, const std::vector< size_t > &slot_idx_per_target_idx, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)
 
template<typename DATA_TYPE >
void writeBackCellDirect (const ResultSet &rows, const size_t input_buffer_entry_idx, const size_t output_buffer_entry_idx, const size_t target_idx, const size_t slot_idx, const ReadFunction &read_function)
 
std::vector< WriteFunctioninitWriteFunctions (const ResultSet &rows, const std::vector< bool > &targets_to_skip={})
 
template<QueryDescriptionType QUERY_TYPE, bool COLUMNAR_OUTPUT>
std::vector< ReadFunctioninitReadFunctions (const ResultSet &rows, const std::vector< size_t > &slot_idx_per_target_idx, const std::vector< bool > &targets_to_skip={})
 
std::tuple< std::vector
< WriteFunction >, std::vector
< ReadFunction > > 
initAllConversionFunctions (const ResultSet &rows, const std::vector< size_t > &slot_idx_per_target_idx, const std::vector< bool > &targets_to_skip={})
 
template<>
void writeBackCellDirect (const ResultSet &rows, const size_t input_buffer_entry_idx, const size_t output_buffer_entry_idx, const size_t target_idx, const size_t slot_idx, const ReadFunction &read_from_function)
 
template<>
void writeBackCellDirect (const ResultSet &rows, const size_t input_buffer_entry_idx, const size_t output_buffer_entry_idx, const size_t target_idx, const size_t slot_idx, const ReadFunction &read_from_function)
 

Private Attributes

const std::vector< SQLTypeInfotarget_types_
 
bool parallel_conversion_
 
bool direct_columnar_conversion_
 

Detailed Description

Definition at line 61 of file ColumnarResults.h.

Member Typedef Documentation

using ColumnarResults::ReadFunction = std::function<int64_t(const ResultSet&, const size_t, const size_t, const size_t)>

Definition at line 94 of file ColumnarResults.h.

using ColumnarResults::WriteFunction = std::function<void(const ResultSet&, const size_t, const size_t, const size_t, const size_t, const ReadFunction&)>

Definition at line 103 of file ColumnarResults.h.

Constructor & Destructor Documentation

ColumnarResults::ColumnarResults ( const std::shared_ptr< RowSetMemoryOwner row_set_mem_owner,
const ResultSet rows,
const size_t  num_columns,
const std::vector< SQLTypeInfo > &  target_types,
const bool  is_parallel_execution_enforced = false 
)

Definition at line 43 of file ColumnarResults.cpp.

References column_buffers_, DEBUG_TIMER, isDirectColumnarConversionPossible(), kENCODING_NONE, materializeAllColumnsDirectly(), materializeAllColumnsThroughIteration(), and num_rows_.

Referenced by mergeResults().

48  : column_buffers_(num_columns)
49  , num_rows_(use_parallel_algorithms(rows) || rows.isDirectColumnarConversionPossible()
50  ? rows.entryCount()
51  : rows.rowCount())
52  , target_types_(target_types)
53  , parallel_conversion_(is_parallel_execution_enforced ? true
55  , direct_columnar_conversion_(rows.isDirectColumnarConversionPossible()) {
56  auto timer = DEBUG_TIMER(__func__);
57  column_buffers_.resize(num_columns);
58  for (size_t i = 0; i < num_columns; ++i) {
59  const bool is_varlen = target_types[i].is_array() ||
60  (target_types[i].is_string() &&
61  target_types[i].get_compression() == kENCODING_NONE) ||
62  target_types[i].is_geometry();
63  if (is_varlen) {
65  }
67  !rows.isZeroCopyColumnarConversionPossible(i)) {
68  column_buffers_[i] =
69  row_set_mem_owner->allocate(num_rows_ * target_types[i].get_size());
70  }
71  }
72 
73  if (isDirectColumnarConversionPossible() && rows.entryCount() > 0) {
74  materializeAllColumnsDirectly(rows, num_columns);
75  } else {
76  materializeAllColumnsThroughIteration(rows, num_columns);
77  }
78 }
std::vector< int8_t * > column_buffers_
bool use_parallel_algorithms(const ResultSet &rows)
Definition: ResultSet.cpp:1000
bool direct_columnar_conversion_
void materializeAllColumnsThroughIteration(const ResultSet &rows, const size_t num_columns)
bool isDirectColumnarConversionPossible() const
void materializeAllColumnsDirectly(const ResultSet &rows, const size_t num_columns)
#define DEBUG_TIMER(name)
Definition: Logger.h:313
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

ColumnarResults::ColumnarResults ( const std::shared_ptr< RowSetMemoryOwner row_set_mem_owner,
const int8_t *  one_col_buffer,
const size_t  num_rows,
const SQLTypeInfo target_type 
)

Definition at line 80 of file ColumnarResults.cpp.

84  : column_buffers_(1)
86  , target_types_{target_type}
87  , parallel_conversion_(false)
89  auto timer = DEBUG_TIMER(__func__);
90  const bool is_varlen =
91  target_type.is_array() ||
92  (target_type.is_string() && target_type.get_compression() == kENCODING_NONE) ||
93  target_type.is_geometry();
94  if (is_varlen) {
96  }
97  const auto buf_size = num_rows * target_type.get_size();
98  column_buffers_[0] = reinterpret_cast<int8_t*>(row_set_mem_owner->allocate(buf_size));
99  memcpy(((void*)column_buffers_[0]), one_col_buffer, buf_size);
100 }
std::vector< int8_t * > column_buffers_
HOST DEVICE int get_size() const
Definition: sqltypes.h:268
const int8_t const int64_t * num_rows
bool direct_columnar_conversion_
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:266
bool is_geometry() const
Definition: sqltypes.h:427
#define DEBUG_TIMER(name)
Definition: Logger.h:313
bool is_string() const
Definition: sqltypes.h:415
const std::vector< SQLTypeInfo > target_types_
bool is_array() const
Definition: sqltypes.h:423
ColumnarResults::ColumnarResults ( const size_t  num_rows,
const std::vector< SQLTypeInfo > &  target_types 
)
inlineprivate

Definition at line 110 of file ColumnarResults.h.

111  : num_rows_(num_rows), target_types_(target_types) {}
const int8_t const int64_t * num_rows
const std::vector< SQLTypeInfo > target_types_

Member Function Documentation

void ColumnarResults::compactAndCopyEntries ( const ResultSet rows,
const ColumnBitmap bitmap,
const std::vector< size_t > &  non_empty_per_thread,
const size_t  num_columns,
const size_t  entry_count,
const size_t  num_threads,
const size_t  size_per_thread 
)
private

This function goes through all non-empty elements marked in the bitmap data structure, and store them back into output column buffers. The output column buffers are compacted without any holes in it.

TODO(Saman): if necessary, we can look into the distribution of non-empty entries and choose a different load-balanced strategy (assigning equal number of non-empties to each thread) as opposed to equal partitioning of the bitmap

Definition at line 540 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, compactAndCopyEntriesWithoutTargetSkipping(), compactAndCopyEntriesWithTargetSkipping(), GroupByBaselineHash, GroupByPerfectHash, and isDirectColumnarConversionPossible().

Referenced by materializeAllColumnsGroupBy().

547  {
549  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
550  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
551  CHECK_EQ(num_threads, non_empty_per_thread.size());
552 
553  // compute the exclusive scan over all non-empty totals
554  std::vector<size_t> global_offsets(num_threads + 1, 0);
555  std::partial_sum(non_empty_per_thread.begin(),
556  non_empty_per_thread.end(),
557  std::next(global_offsets.begin()));
558 
559  const auto slot_idx_per_target_idx = rows.getSlotIndicesForTargetIndices();
560  const auto [single_slot_targets_to_skip, num_single_slot_targets] =
561  rows.getSupportedSingleSlotTargetBitmap();
562 
563  // We skip multi-slot targets (e.g., AVG). These skipped targets are treated
564  // differently and accessed through result set's iterator
565  if (num_single_slot_targets < num_columns) {
567  bitmap,
568  non_empty_per_thread,
569  global_offsets,
570  single_slot_targets_to_skip,
571  slot_idx_per_target_idx,
572  num_columns,
573  entry_count,
574  num_threads,
575  size_per_thread);
576  } else {
578  bitmap,
579  non_empty_per_thread,
580  global_offsets,
581  slot_idx_per_target_idx,
582  num_columns,
583  entry_count,
584  num_threads,
585  size_per_thread);
586  }
587 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
void compactAndCopyEntriesWithTargetSkipping(const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const std::vector< size_t > &global_offsets, const std::vector< bool > &targets_to_skip, const std::vector< size_t > &slot_idx_per_target_idx, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)
void compactAndCopyEntriesWithoutTargetSkipping(const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const std::vector< size_t > &global_offsets, const std::vector< size_t > &slot_idx_per_target_idx, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::compactAndCopyEntriesWithoutTargetSkipping ( const ResultSet rows,
const ColumnBitmap bitmap,
const std::vector< size_t > &  non_empty_per_thread,
const std::vector< size_t > &  global_offsets,
const std::vector< size_t > &  slot_idx_per_target_idx,
const size_t  num_columns,
const size_t  entry_count,
const size_t  num_threads,
const size_t  size_per_thread 
)
private

This functions takes a bitmap of non-empty entries within the result set's storage and compact and copy those contents back into the output column_buffers_. In this variation, all targets are assumed to be single-slot and thus can be directly columnarized.

Definition at line 684 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, GroupByBaselineHash, GroupByPerfectHash, initAllConversionFunctions(), and isDirectColumnarConversionPossible().

Referenced by compactAndCopyEntries().

693  {
695  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
696  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
697 
698  const auto [write_functions, read_functions] =
699  initAllConversionFunctions(rows, slot_idx_per_target_idx);
700  CHECK_EQ(write_functions.size(), num_columns);
701  CHECK_EQ(read_functions.size(), num_columns);
702 
703  auto compact_buffer_func = [&rows,
704  &bitmap,
705  &global_offsets,
706  &non_empty_per_thread,
707  &num_columns,
708  &slot_idx_per_target_idx,
709  &write_functions = write_functions,
710  &read_functions = read_functions](const size_t start_index,
711  const size_t end_index,
712  const size_t thread_idx) {
713  const size_t total_non_empty = non_empty_per_thread[thread_idx];
714  size_t non_empty_idx = 0;
715  size_t local_idx = 0;
716  for (size_t entry_idx = start_index; entry_idx < end_index;
717  entry_idx++, local_idx++) {
718  if (non_empty_idx >= total_non_empty) {
719  // all non-empty entries has been written back
720  break;
721  }
722  const size_t output_buffer_row_idx = global_offsets[thread_idx] + non_empty_idx;
723  if (bitmap.get(local_idx, thread_idx)) {
724  for (size_t column_idx = 0; column_idx < num_columns; column_idx++) {
725  write_functions[column_idx](rows,
726  entry_idx,
727  output_buffer_row_idx,
728  column_idx,
729  slot_idx_per_target_idx[column_idx],
730  read_functions[column_idx]);
731  }
732  non_empty_idx++;
733  } else {
734  continue;
735  }
736  }
737  };
738 
739  std::vector<std::future<void>> compaction_threads;
740  for (size_t thread_idx = 0; thread_idx < num_threads; thread_idx++) {
741  const size_t start_entry = thread_idx * size_per_thread;
742  const size_t end_entry = std::min(start_entry + size_per_thread, entry_count);
743  compaction_threads.push_back(std::async(
744  std::launch::async, compact_buffer_func, start_entry, end_entry, thread_idx));
745  }
746 
747  for (auto& child : compaction_threads) {
748  child.wait();
749  }
750 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
CHECK(cgen_state)
std::tuple< std::vector< WriteFunction >, std::vector< ReadFunction > > initAllConversionFunctions(const ResultSet &rows, const std::vector< size_t > &slot_idx_per_target_idx, const std::vector< bool > &targets_to_skip={})
bool isDirectColumnarConversionPossible() const

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::compactAndCopyEntriesWithTargetSkipping ( const ResultSet rows,
const ColumnBitmap bitmap,
const std::vector< size_t > &  non_empty_per_thread,
const std::vector< size_t > &  global_offsets,
const std::vector< bool > &  targets_to_skip,
const std::vector< size_t > &  slot_idx_per_target_idx,
const size_t  num_columns,
const size_t  entry_count,
const size_t  num_threads,
const size_t  size_per_thread 
)
private

This functions takes a bitmap of non-empty entries within the result set's storage and compact and copy those contents back into the output column_buffers_. In this variation, multi-slot targets (e.g., AVG) are treated with the existing result set's iterations, but everything else is directly columnarized.

Definition at line 595 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, GroupByBaselineHash, GroupByPerfectHash, initAllConversionFunctions(), isDirectColumnarConversionPossible(), and writeBackCell().

Referenced by compactAndCopyEntries().

605  {
607  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
608  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
609 
610  const auto [write_functions, read_functions] =
611  initAllConversionFunctions(rows, slot_idx_per_target_idx, targets_to_skip);
612  CHECK_EQ(write_functions.size(), num_columns);
613  CHECK_EQ(read_functions.size(), num_columns);
614 
615  auto compact_buffer_func = [this,
616  &rows,
617  &bitmap,
618  &global_offsets,
619  &non_empty_per_thread,
620  &num_columns,
621  &targets_to_skip,
622  &slot_idx_per_target_idx,
623  &write_functions = write_functions,
624  &read_functions = read_functions](const size_t start_index,
625  const size_t end_index,
626  const size_t thread_idx) {
627  const size_t total_non_empty = non_empty_per_thread[thread_idx];
628  size_t non_empty_idx = 0;
629  size_t local_idx = 0;
630  for (size_t entry_idx = start_index; entry_idx < end_index;
631  entry_idx++, local_idx++) {
632  if (non_empty_idx >= total_non_empty) {
633  // all non-empty entries has been written back
634  break;
635  }
636  const size_t output_buffer_row_idx = global_offsets[thread_idx] + non_empty_idx;
637  if (bitmap.get(local_idx, thread_idx)) {
638  // targets that are recovered from the result set iterators:
639  const auto crt_row = rows.getRowAtNoTranslations(entry_idx, targets_to_skip);
640  for (size_t column_idx = 0; column_idx < num_columns; ++column_idx) {
641  if (!targets_to_skip.empty() && !targets_to_skip[column_idx]) {
642  writeBackCell(crt_row[column_idx], output_buffer_row_idx, column_idx);
643  }
644  }
645  // targets that are copied directly without any translation/decoding from
646  // result set
647  for (size_t column_idx = 0; column_idx < num_columns; column_idx++) {
648  if (!targets_to_skip.empty() && !targets_to_skip[column_idx]) {
649  continue;
650  }
651  write_functions[column_idx](rows,
652  entry_idx,
653  output_buffer_row_idx,
654  column_idx,
655  slot_idx_per_target_idx[column_idx],
656  read_functions[column_idx]);
657  }
658  non_empty_idx++;
659  } else {
660  continue;
661  }
662  }
663  };
664 
665  std::vector<std::future<void>> compaction_threads;
666  for (size_t thread_idx = 0; thread_idx < num_threads; thread_idx++) {
667  const size_t start_entry = thread_idx * size_per_thread;
668  const size_t end_entry = std::min(start_entry + size_per_thread, entry_count);
669  compaction_threads.push_back(std::async(
670  std::launch::async, compact_buffer_func, start_entry, end_entry, thread_idx));
671  }
672 
673  for (auto& child : compaction_threads) {
674  child.wait();
675  }
676 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
CHECK(cgen_state)
std::tuple< std::vector< WriteFunction >, std::vector< ReadFunction > > initAllConversionFunctions(const ResultSet &rows, const std::vector< size_t > &slot_idx_per_target_idx, const std::vector< bool > &targets_to_skip={})
bool isDirectColumnarConversionPossible() const
void writeBackCell(const TargetValue &col_val, const size_t row_idx, const size_t column_idx)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::copyAllNonLazyColumns ( const std::vector< ColumnLazyFetchInfo > &  lazy_fetch_info,
const ResultSet rows,
const size_t  num_columns 
)
private

Definition at line 346 of file ColumnarResults.cpp.

References CHECK(), column_buffers_, isDirectColumnarConversionPossible(), num_rows_, and target_types_.

Referenced by materializeAllColumnsProjection().

349  {
351  const auto is_column_non_lazily_fetched = [&lazy_fetch_info](const size_t col_idx) {
352  // Saman: make sure when this lazy_fetch_info is empty
353  if (lazy_fetch_info.empty()) {
354  return true;
355  } else {
356  return !lazy_fetch_info[col_idx].is_lazily_fetched;
357  }
358  };
359 
360  // parallelized by assigning each column to a thread
361  std::vector<std::future<void>> direct_copy_threads;
362  for (size_t col_idx = 0; col_idx < num_columns; col_idx++) {
363  if (rows.isZeroCopyColumnarConversionPossible(col_idx)) {
364  CHECK(!column_buffers_[col_idx]);
365  column_buffers_[col_idx] = const_cast<int8_t*>(rows.getColumnarBuffer(col_idx));
366  } else if (is_column_non_lazily_fetched(col_idx)) {
367  direct_copy_threads.push_back(std::async(
368  std::launch::async,
369  [&rows, this](const size_t column_index) {
370  const size_t column_size = num_rows_ * target_types_[column_index].get_size();
371  rows.copyColumnIntoBuffer(
372  column_index, column_buffers_[column_index], column_size);
373  },
374  col_idx));
375  }
376  }
377 
378  for (auto& child : direct_copy_threads) {
379  child.wait();
380  }
381 }
std::vector< int8_t * > column_buffers_
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

const std::vector<int8_t*>& ColumnarResults::getColumnBuffers ( ) const
inline

Definition at line 78 of file ColumnarResults.h.

References column_buffers_.

Referenced by ColumnFetcher::transferColumnIfNeeded().

78 { return column_buffers_; }
std::vector< int8_t * > column_buffers_

+ Here is the caller graph for this function:

const SQLTypeInfo& ColumnarResults::getColumnType ( const int  col_id) const
inline

Definition at line 82 of file ColumnarResults.h.

References CHECK_GE, CHECK_LT, and target_types_.

Referenced by ColumnFetcher::transferColumnIfNeeded().

82  {
83  CHECK_GE(col_id, 0);
84  CHECK_LT(static_cast<size_t>(col_id), target_types_.size());
85  return target_types_[col_id];
86  }
#define CHECK_GE(x, y)
Definition: Logger.h:210
#define CHECK_LT(x, y)
Definition: Logger.h:207
const std::vector< SQLTypeInfo > target_types_

+ Here is the caller graph for this function:

std::tuple< std::vector< ColumnarResults::WriteFunction >, std::vector< ColumnarResults::ReadFunction > > ColumnarResults::initAllConversionFunctions ( const ResultSet rows,
const std::vector< size_t > &  slot_idx_per_target_idx,
const std::vector< bool > &  targets_to_skip = {} 
)
private

This function goes through all target types in the output, and chooses appropriate write and read functions per target. The goal is then to simply use these functions for each row and per target. Read functions are used to read each cell's data content (particular target in a row), and write functions are used to properly write back the cell's content into the output column buffers.

Definition at line 1043 of file ColumnarResults.cpp.

References CHECK(), GroupByBaselineHash, GroupByPerfectHash, initWriteFunctions(), and isDirectColumnarConversionPossible().

Referenced by compactAndCopyEntriesWithoutTargetSkipping(), and compactAndCopyEntriesWithTargetSkipping().

1046  {
1048  (rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
1049  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash));
1050 
1051  const auto write_functions = initWriteFunctions(rows, targets_to_skip);
1052  if (rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash) {
1053  if (rows.didOutputColumnar()) {
1054  return std::make_tuple(
1055  std::move(write_functions),
1056  initReadFunctions<QueryDescriptionType::GroupByPerfectHash, true>(
1057  rows, slot_idx_per_target_idx, targets_to_skip));
1058  } else {
1059  return std::make_tuple(
1060  std::move(write_functions),
1061  initReadFunctions<QueryDescriptionType::GroupByPerfectHash, false>(
1062  rows, slot_idx_per_target_idx, targets_to_skip));
1063  }
1064  } else {
1065  if (rows.didOutputColumnar()) {
1066  return std::make_tuple(
1067  std::move(write_functions),
1068  initReadFunctions<QueryDescriptionType::GroupByBaselineHash, true>(
1069  rows, slot_idx_per_target_idx, targets_to_skip));
1070  } else {
1071  return std::make_tuple(
1072  std::move(write_functions),
1073  initReadFunctions<QueryDescriptionType::GroupByBaselineHash, false>(
1074  rows, slot_idx_per_target_idx, targets_to_skip));
1075  }
1076  }
1077 }
CHECK(cgen_state)
std::vector< WriteFunction > initWriteFunctions(const ResultSet &rows, const std::vector< bool > &targets_to_skip={})
bool isDirectColumnarConversionPossible() const

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

template<QueryDescriptionType QUERY_TYPE, bool COLUMNAR_OUTPUT>
std::vector< ColumnarResults::ReadFunction > ColumnarResults::initReadFunctions ( const ResultSet rows,
const std::vector< size_t > &  slot_idx_per_target_idx,
const std::vector< bool > &  targets_to_skip = {} 
)
private

Initializes a set of read funtions to properly access the contents of the result set's storage buffer. Each particular read function is chosen based on the data type and data size used to store that target in the result set's storage buffer. These functions are then used for each row in the result set.

Definition at line 945 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, GroupByBaselineHash, anonymous_namespace{ColumnarResults.cpp}::invalid_read_func(), isDirectColumnarConversionPossible(), kDOUBLE, kFLOAT, target_types_, and UNREACHABLE.

948  {
950  CHECK(COLUMNAR_OUTPUT == rows.didOutputColumnar());
951  CHECK(QUERY_TYPE == rows.getQueryDescriptionType());
952 
953  std::vector<ReadFunction> read_functions;
954  read_functions.reserve(target_types_.size());
955 
956  for (size_t target_idx = 0; target_idx < target_types_.size(); target_idx++) {
957  if (!targets_to_skip.empty() && !targets_to_skip[target_idx]) {
958  // for targets that should be skipped, we use a placeholder function that should
959  // never be called. The CHECKs inside it make sure that never happens.
960  read_functions.emplace_back(invalid_read_func);
961  continue;
962  }
963 
964  if (QUERY_TYPE == QueryDescriptionType::GroupByBaselineHash) {
965  if (rows.getPaddedSlotWidthBytes(slot_idx_per_target_idx[target_idx]) == 0) {
966  // for key columns only
967  CHECK(rows.query_mem_desc_.getTargetGroupbyIndex(target_idx) >= 0);
968  if (target_types_[target_idx].is_fp()) {
969  CHECK_EQ(size_t(8), rows.query_mem_desc_.getEffectiveKeyWidth());
970  switch (target_types_[target_idx].get_type()) {
971  case kFLOAT:
972  read_functions.emplace_back(
973  read_float_key_baseline<QUERY_TYPE, COLUMNAR_OUTPUT>);
974  break;
975  case kDOUBLE:
976  read_functions.emplace_back(read_double_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
977  break;
978  default:
979  UNREACHABLE()
980  << "Invalid data type encountered (BaselineHash, floating point key).";
981  break;
982  }
983  } else {
984  switch (rows.query_mem_desc_.getEffectiveKeyWidth()) {
985  case 8:
986  read_functions.emplace_back(read_int64_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
987  break;
988  case 4:
989  read_functions.emplace_back(read_int32_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
990  break;
991  default:
992  UNREACHABLE()
993  << "Invalid data type encountered (BaselineHash, integer key).";
994  }
995  }
996  continue;
997  }
998  }
999  if (target_types_[target_idx].is_fp()) {
1000  switch (rows.getPaddedSlotWidthBytes(slot_idx_per_target_idx[target_idx])) {
1001  case 8:
1002  read_functions.emplace_back(read_double_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1003  break;
1004  case 4:
1005  read_functions.emplace_back(read_float_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1006  break;
1007  default:
1008  UNREACHABLE() << "Invalid data type encountered (floating point agg column).";
1009  break;
1010  }
1011  } else {
1012  switch (rows.getPaddedSlotWidthBytes(slot_idx_per_target_idx[target_idx])) {
1013  case 8:
1014  read_functions.emplace_back(read_int64_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1015  break;
1016  case 4:
1017  read_functions.emplace_back(read_int32_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1018  break;
1019  case 2:
1020  read_functions.emplace_back(read_int16_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1021  break;
1022  case 1:
1023  read_functions.emplace_back(read_int8_func<QUERY_TYPE, COLUMNAR_OUTPUT>);
1024  break;
1025  default:
1026  UNREACHABLE() << "Invalid data type encountered (integer agg column).";
1027  break;
1028  }
1029  }
1030  }
1031  return read_functions;
1032 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
#define UNREACHABLE()
Definition: Logger.h:241
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
int64_t invalid_read_func(const ResultSet &rows, const size_t input_buffer_entry_idx, const size_t target_idx, const size_t slot_idx)
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

std::vector< ColumnarResults::WriteFunction > ColumnarResults::initWriteFunctions ( const ResultSet rows,
const std::vector< bool > &  targets_to_skip = {} 
)
private

Initialize a set of write functions per target (i.e., column). Target types' logical size are used to categorize the correct write function per target. These functions are then used for every row in the result set.

Definition at line 757 of file ColumnarResults.cpp.

References CHECK(), GroupByBaselineHash, GroupByPerfectHash, isDirectColumnarConversionPossible(), run_benchmark_import::result, target_types_, and UNREACHABLE.

Referenced by initAllConversionFunctions().

759  {
761  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
762  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
763 
764  std::vector<WriteFunction> result;
765  result.reserve(target_types_.size());
766 
767  for (size_t target_idx = 0; target_idx < target_types_.size(); target_idx++) {
768  if (!targets_to_skip.empty() && !targets_to_skip[target_idx]) {
769  result.emplace_back([](const ResultSet& rows,
770  const size_t input_buffer_entry_idx,
771  const size_t output_buffer_entry_idx,
772  const size_t target_idx,
773  const size_t slot_idx,
774  const ReadFunction& read_function) {
775  UNREACHABLE() << "Invalid write back function used.";
776  });
777  continue;
778  }
779 
780  if (target_types_[target_idx].is_fp()) {
781  switch (target_types_[target_idx].get_size()) {
782  case 8:
783  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<double>,
784  this,
785  std::placeholders::_1,
786  std::placeholders::_2,
787  std::placeholders::_3,
788  std::placeholders::_4,
789  std::placeholders::_5,
790  std::placeholders::_6));
791  break;
792  case 4:
793  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<float>,
794  this,
795  std::placeholders::_1,
796  std::placeholders::_2,
797  std::placeholders::_3,
798  std::placeholders::_4,
799  std::placeholders::_5,
800  std::placeholders::_6));
801  break;
802  default:
803  UNREACHABLE() << "Invalid target type encountered.";
804  break;
805  }
806  } else {
807  switch (target_types_[target_idx].get_size()) {
808  case 8:
809  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<int64_t>,
810  this,
811  std::placeholders::_1,
812  std::placeholders::_2,
813  std::placeholders::_3,
814  std::placeholders::_4,
815  std::placeholders::_5,
816  std::placeholders::_6));
817  break;
818  case 4:
819  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<int32_t>,
820  this,
821  std::placeholders::_1,
822  std::placeholders::_2,
823  std::placeholders::_3,
824  std::placeholders::_4,
825  std::placeholders::_5,
826  std::placeholders::_6));
827  break;
828  case 2:
829  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<int16_t>,
830  this,
831  std::placeholders::_1,
832  std::placeholders::_2,
833  std::placeholders::_3,
834  std::placeholders::_4,
835  std::placeholders::_5,
836  std::placeholders::_6));
837  break;
838  case 1:
839  result.emplace_back(std::bind(&ColumnarResults::writeBackCellDirect<int8_t>,
840  this,
841  std::placeholders::_1,
842  std::placeholders::_2,
843  std::placeholders::_3,
844  std::placeholders::_4,
845  std::placeholders::_5,
846  std::placeholders::_6));
847  break;
848  default:
849  UNREACHABLE() << "Invalid target type encountered.";
850  break;
851  }
852  }
853  }
854  return result;
855 }
#define UNREACHABLE()
Definition: Logger.h:241
CHECK(cgen_state)
std::function< int64_t(const ResultSet &, const size_t, const size_t, const size_t)> ReadFunction
bool isDirectColumnarConversionPossible() const
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool ColumnarResults::isDirectColumnarConversionPossible ( ) const
inline
bool ColumnarResults::isParallelConversion ( ) const
inline

Definition at line 88 of file ColumnarResults.h.

References parallel_conversion_.

Referenced by materializeAllColumnsGroupBy(), and materializeAllColumnsThroughIteration().

88 { return parallel_conversion_; }

+ Here is the caller graph for this function:

void ColumnarResults::locateAndCountEntries ( const ResultSet rows,
ColumnBitmap bitmap,
std::vector< size_t > &  non_empty_per_thread,
const size_t  entry_count,
const size_t  num_threads,
const size_t  size_per_thread 
) const
private

This function goes through all the keys in the result set, and count the total number of non-empty keys. It also store the location of non-empty keys in a bitmap data structure for later faster access.

Definition at line 493 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, GroupByBaselineHash, GroupByPerfectHash, and isDirectColumnarConversionPossible().

Referenced by materializeAllColumnsGroupBy().

498  {
500  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
501  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
502  CHECK_EQ(num_threads, non_empty_per_thread.size());
503  auto locate_and_count_func =
504  [&rows, &bitmap, &non_empty_per_thread](
505  size_t start_index, size_t end_index, size_t thread_idx) {
506  size_t total_non_empty = 0;
507  size_t local_idx = 0;
508  for (size_t entry_idx = start_index; entry_idx < end_index;
509  entry_idx++, local_idx++) {
510  if (!rows.isRowAtEmpty(entry_idx)) {
511  total_non_empty++;
512  bitmap.set(local_idx, thread_idx, true);
513  }
514  }
515  non_empty_per_thread[thread_idx] = total_non_empty;
516  };
517 
518  std::vector<std::future<void>> conversion_threads;
519  for (size_t thread_idx = 0; thread_idx < num_threads; thread_idx++) {
520  const size_t start_entry = thread_idx * size_per_thread;
521  const size_t end_entry = std::min(start_entry + size_per_thread, entry_count);
522  conversion_threads.push_back(std::async(
523  std::launch::async, locate_and_count_func, start_entry, end_entry, thread_idx));
524  }
525 
526  for (auto& child : conversion_threads) {
527  child.wait();
528  }
529 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::materializeAllColumnsDirectly ( const ResultSet rows,
const size_t  num_columns 
)
private

This function materializes all columns from the main storage and all appended storages and form a single continguous column for each output column. Depending on whether the column is lazily fetched or not, it will treat them differently.

NOTE: this function should only be used when the result set is columnar and completely compacted (e.g., in columnar projections).

Definition at line 298 of file ColumnarResults.cpp.

References CHECK(), GroupByBaselineHash, GroupByPerfectHash, isDirectColumnarConversionPossible(), materializeAllColumnsGroupBy(), materializeAllColumnsProjection(), Projection, and UNREACHABLE.

Referenced by ColumnarResults().

299  {
301  switch (rows.getQueryDescriptionType()) {
303  materializeAllColumnsProjection(rows, num_columns);
304  break;
305  }
308  materializeAllColumnsGroupBy(rows, num_columns);
309  break;
310  }
311  default:
312  UNREACHABLE()
313  << "Direct columnar conversion for this query type is not supported yet.";
314  }
315 }
#define UNREACHABLE()
Definition: Logger.h:241
CHECK(cgen_state)
void materializeAllColumnsGroupBy(const ResultSet &rows, const size_t num_columns)
bool isDirectColumnarConversionPossible() const
void materializeAllColumnsProjection(const ResultSet &rows, const size_t num_columns)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::materializeAllColumnsGroupBy ( const ResultSet rows,
const size_t  num_columns 
)
private

This function is to directly columnarize a result set for group by queries. Its main difference with the traditional alternative is that it directly reads non-empty entries from the result set, and then writes them into output column buffers, rather than using the result set's iterators.

Definition at line 458 of file ColumnarResults.cpp.

References CHECK(), compactAndCopyEntries(), cpu_threads(), GroupByBaselineHash, GroupByPerfectHash, isDirectColumnarConversionPossible(), isParallelConversion(), and locateAndCountEntries().

Referenced by materializeAllColumnsDirectly().

459  {
461  CHECK(rows.getQueryDescriptionType() == QueryDescriptionType::GroupByPerfectHash ||
462  rows.getQueryDescriptionType() == QueryDescriptionType::GroupByBaselineHash);
463 
464  const size_t num_threads = isParallelConversion() ? cpu_threads() : 1;
465  const size_t entry_count = rows.entryCount();
466  const size_t size_per_thread = (entry_count + num_threads - 1) / num_threads;
467 
468  // step 1: compute total non-empty elements and store a bitmap per thread
469  std::vector<size_t> non_empty_per_thread(num_threads,
470  0); // number of non-empty entries per thread
471 
472  ColumnBitmap bitmap(size_per_thread, num_threads);
473 
475  rows, bitmap, non_empty_per_thread, entry_count, num_threads, size_per_thread);
476 
477  // step 2: go through the generated bitmap and copy/decode corresponding entries
478  // into the output buffer
480  bitmap,
481  non_empty_per_thread,
482  num_columns,
483  entry_count,
484  num_threads,
485  size_per_thread);
486 }
bool isParallelConversion() const
void locateAndCountEntries(const ResultSet &rows, ColumnBitmap &bitmap, std::vector< size_t > &non_empty_per_thread, const size_t entry_count, const size_t num_threads, const size_t size_per_thread) const
void compactAndCopyEntries(const ResultSet &rows, const ColumnBitmap &bitmap, const std::vector< size_t > &non_empty_per_thread, const size_t num_columns, const size_t entry_count, const size_t num_threads, const size_t size_per_thread)
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
int cpu_threads()
Definition: thread_count.h:25

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::materializeAllColumnsProjection ( const ResultSet rows,
const size_t  num_columns 
)
private

This function handles materialization for two types of columns in columnar projections:

  1. for all non-lazy columns, it directly copies the results from the result set's storage into the output column buffers
  2. for all lazy fetched columns, it uses result set's iterators to decode the proper values before storing them into the output column buffers

Definition at line 324 of file ColumnarResults.cpp.

References CHECK(), copyAllNonLazyColumns(), isDirectColumnarConversionPossible(), materializeAllLazyColumns(), and Projection.

Referenced by materializeAllColumnsDirectly().

325  {
326  CHECK(rows.query_mem_desc_.didOutputColumnar());
328  rows.query_mem_desc_.getQueryDescriptionType() ==
330 
331  const auto& lazy_fetch_info = rows.getLazyFetchInfo();
332 
333  // We can directly copy each non-lazy column's content
334  copyAllNonLazyColumns(lazy_fetch_info, rows, num_columns);
335 
336  // Only lazy columns are iterated through first and then materialized
337  materializeAllLazyColumns(lazy_fetch_info, rows, num_columns);
338 }
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
void copyAllNonLazyColumns(const std::vector< ColumnLazyFetchInfo > &lazy_fetch_info, const ResultSet &rows, const size_t num_columns)
void materializeAllLazyColumns(const std::vector< ColumnLazyFetchInfo > &lazy_fetch_info, const ResultSet &rows, const size_t num_columns)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::materializeAllColumnsThroughIteration ( const ResultSet rows,
const size_t  num_columns 
)
private

This function iterates through the result set (using the getRowAtNoTranslation and getNextRow family of functions) and writes back the results into output column buffers.

Definition at line 146 of file ColumnarResults.cpp.

References cpu_threads(), isParallelConversion(), makeIntervals(), num_rows_, and writeBackCell().

Referenced by ColumnarResults().

147  {
148  std::atomic<size_t> row_idx{0};
149  const auto do_work = [num_columns, this](const std::vector<TargetValue>& crt_row,
150  const size_t row_idx) {
151  for (size_t i = 0; i < num_columns; ++i) {
152  writeBackCell(crt_row[i], row_idx, i);
153  }
154  };
155  if (isParallelConversion()) {
156  const size_t worker_count = cpu_threads();
157  std::vector<std::future<void>> conversion_threads;
158  for (auto interval : makeIntervals(size_t(0), rows.entryCount(), worker_count)) {
159  conversion_threads.push_back(std::async(
160  std::launch::async,
161  [&rows, &do_work, &row_idx](const size_t start, const size_t end) {
162  for (size_t i = start; i < end; ++i) {
163  const auto crt_row = rows.getRowAtNoTranslations(i);
164  if (!crt_row.empty()) {
165  do_work(crt_row, row_idx.fetch_add(1));
166  }
167  }
168  },
169  interval.begin,
170  interval.end));
171  }
172  for (auto& child : conversion_threads) {
173  child.wait();
174  }
175 
176  num_rows_ = row_idx;
177  rows.setCachedRowCount(num_rows_);
178  return;
179  }
180  while (true) {
181  const auto crt_row = rows.getNextRow(false, false);
182  if (crt_row.empty()) {
183  break;
184  }
185  do_work(crt_row, row_idx);
186  ++row_idx;
187  }
188  rows.moveToBegin();
189 }
bool isParallelConversion() const
Intervals< T > makeIntervals(T begin, T end, std::size_t n_workers)
Definition: Intervals.h:108
void writeBackCell(const TargetValue &col_val, const size_t row_idx, const size_t column_idx)
int cpu_threads()
Definition: thread_count.h:25

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ColumnarResults::materializeAllLazyColumns ( const std::vector< ColumnLazyFetchInfo > &  lazy_fetch_info,
const ResultSet rows,
const size_t  num_columns 
)
private

For all lazy fetched columns, we should iterate through the column's content and properly materialize it.

This function is parallelized through dividing total rows among all existing threads. Since there's no invalid element in the result set (e.g., columnar projections), the output buffer will have as many rows as there are in the result set, removing the need for atomicly incrementing the output buffer position.

Definition at line 392 of file ColumnarResults.cpp.

References CHECK(), CHECK_EQ, cpu_threads(), isDirectColumnarConversionPossible(), makeIntervals(), use_parallel_algorithms(), and writeBackCell().

Referenced by materializeAllColumnsProjection().

395  {
397  const auto do_work_just_lazy_columns = [num_columns, this](
398  const std::vector<TargetValue>& crt_row,
399  const size_t row_idx,
400  const std::vector<bool>& targets_to_skip) {
401  for (size_t i = 0; i < num_columns; ++i) {
402  if (!targets_to_skip.empty() && !targets_to_skip[i]) {
403  writeBackCell(crt_row[i], row_idx, i);
404  }
405  }
406  };
407 
408  const auto contains_lazy_fetched_column =
409  [](const std::vector<ColumnLazyFetchInfo>& lazy_fetch_info) {
410  for (auto& col_info : lazy_fetch_info) {
411  if (col_info.is_lazily_fetched) {
412  return true;
413  }
414  }
415  return false;
416  };
417 
418  // parallelized by assigning a chunk of rows to each thread)
419  const bool skip_non_lazy_columns = rows.isPermutationBufferEmpty();
420  if (contains_lazy_fetched_column(lazy_fetch_info)) {
421  const size_t worker_count = use_parallel_algorithms(rows) ? cpu_threads() : 1;
422  std::vector<std::future<void>> conversion_threads;
423  std::vector<bool> targets_to_skip;
424  if (skip_non_lazy_columns) {
425  CHECK_EQ(lazy_fetch_info.size(), size_t(num_columns));
426  targets_to_skip.reserve(num_columns);
427  for (size_t i = 0; i < num_columns; i++) {
428  // we process lazy columns (i.e., skip non-lazy columns)
429  targets_to_skip.push_back(!lazy_fetch_info[i].is_lazily_fetched);
430  }
431  }
432  for (auto interval : makeIntervals(size_t(0), rows.entryCount(), worker_count)) {
433  conversion_threads.push_back(std::async(
434  std::launch::async,
435  [&rows, &do_work_just_lazy_columns, &targets_to_skip](const size_t start,
436  const size_t end) {
437  for (size_t i = start; i < end; ++i) {
438  const auto crt_row = rows.getRowAtNoTranslations(i, targets_to_skip);
439  do_work_just_lazy_columns(crt_row, i, targets_to_skip);
440  }
441  },
442  interval.begin,
443  interval.end));
444  }
445 
446  for (auto& child : conversion_threads) {
447  child.wait();
448  }
449  }
450 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
bool use_parallel_algorithms(const ResultSet &rows)
Definition: ResultSet.cpp:1000
Intervals< T > makeIntervals(T begin, T end, std::size_t n_workers)
Definition: Intervals.h:108
CHECK(cgen_state)
bool isDirectColumnarConversionPossible() const
void writeBackCell(const TargetValue &col_val, const size_t row_idx, const size_t column_idx)
int cpu_threads()
Definition: thread_count.h:25

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::unique_ptr< ColumnarResults > ColumnarResults::mergeResults ( const std::shared_ptr< RowSetMemoryOwner row_set_mem_owner,
const std::vector< std::unique_ptr< ColumnarResults >> &  sub_results 
)
static

Definition at line 102 of file ColumnarResults.cpp.

References CHECK_EQ, ColumnarResults(), logger::init(), run_benchmark_import::result, and target_types_.

Referenced by ColumnFetcher::getAllTableColumnFragments().

104  {
105  if (sub_results.empty()) {
106  return nullptr;
107  }
108  const auto total_row_count = std::accumulate(
109  sub_results.begin(),
110  sub_results.end(),
111  size_t(0),
112  [](const size_t init, const std::unique_ptr<ColumnarResults>& result) {
113  return init + result->size();
114  });
115  std::unique_ptr<ColumnarResults> merged_results(
116  new ColumnarResults(total_row_count, sub_results[0]->target_types_));
117  const auto col_count = sub_results[0]->column_buffers_.size();
118  const auto nonempty_it = std::find_if(
119  sub_results.begin(),
120  sub_results.end(),
121  [](const std::unique_ptr<ColumnarResults>& needle) { return needle->size(); });
122  if (nonempty_it == sub_results.end()) {
123  return nullptr;
124  }
125  for (size_t col_idx = 0; col_idx < col_count; ++col_idx) {
126  const auto byte_width = (*nonempty_it)->getColumnType(col_idx).get_size();
127  auto write_ptr = row_set_mem_owner->allocate(byte_width * total_row_count);
128  merged_results->column_buffers_.push_back(write_ptr);
129  for (auto& rs : sub_results) {
130  CHECK_EQ(col_count, rs->column_buffers_.size());
131  if (!rs->size()) {
132  continue;
133  }
134  CHECK_EQ(byte_width, rs->getColumnType(col_idx).get_size());
135  memcpy(write_ptr, rs->column_buffers_[col_idx], rs->size() * byte_width);
136  write_ptr += rs->size() * byte_width;
137  }
138  }
139  return merged_results;
140 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
void init(LogOptions const &log_opts)
Definition: Logger.cpp:276
ColumnarResults(const std::shared_ptr< RowSetMemoryOwner > row_set_mem_owner, const ResultSet &rows, const size_t num_columns, const std::vector< SQLTypeInfo > &target_types, const bool is_parallel_execution_enforced=false)
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

const size_t ColumnarResults::size ( ) const
inline

Definition at line 80 of file ColumnarResults.h.

References num_rows_.

Referenced by ColumnFetcher::transferColumnIfNeeded().

80 { return num_rows_; }

+ Here is the caller graph for this function:

void ColumnarResults::writeBackCell ( const TargetValue col_val,
const size_t  row_idx,
const size_t  column_idx 
)
inlineprivate

Definition at line 199 of file ColumnarResults.cpp.

References CHECK(), column_buffers_, anonymous_namespace{ColumnarResults.cpp}::fixed_encoding_nullable_val(), kDOUBLE, kFLOAT, and target_types_.

Referenced by compactAndCopyEntriesWithTargetSkipping(), materializeAllColumnsThroughIteration(), and materializeAllLazyColumns().

201  {
202  const auto scalar_col_val = boost::get<ScalarTargetValue>(&col_val);
203  CHECK(scalar_col_val);
204  auto i64_p = boost::get<int64_t>(scalar_col_val);
205  const auto& type_info = target_types_[column_idx];
206  if (i64_p) {
207  const auto val = fixed_encoding_nullable_val(*i64_p, type_info);
208  switch (target_types_[column_idx].get_size()) {
209  case 1:
210  ((int8_t*)column_buffers_[column_idx])[row_idx] = static_cast<int8_t>(val);
211  break;
212  case 2:
213  ((int16_t*)column_buffers_[column_idx])[row_idx] = static_cast<int16_t>(val);
214  break;
215  case 4:
216  ((int32_t*)column_buffers_[column_idx])[row_idx] = static_cast<int32_t>(val);
217  break;
218  case 8:
219  ((int64_t*)column_buffers_[column_idx])[row_idx] = val;
220  break;
221  default:
222  CHECK(false);
223  }
224  } else {
225  CHECK(target_types_[column_idx].is_fp());
226  switch (target_types_[column_idx].get_type()) {
227  case kFLOAT: {
228  auto float_p = boost::get<float>(scalar_col_val);
229  ((float*)column_buffers_[column_idx])[row_idx] = static_cast<float>(*float_p);
230  break;
231  }
232  case kDOUBLE: {
233  auto double_p = boost::get<double>(scalar_col_val);
234  ((double*)column_buffers_[column_idx])[row_idx] = static_cast<double>(*double_p);
235  break;
236  }
237  default:
238  CHECK(false);
239  }
240  }
241 }
std::vector< int8_t * > column_buffers_
CHECK(cgen_state)
int64_t fixed_encoding_nullable_val(const int64_t val, const SQLTypeInfo &type_info)
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

template<typename DATA_TYPE >
void ColumnarResults::writeBackCellDirect ( const ResultSet rows,
const size_t  input_buffer_entry_idx,
const size_t  output_buffer_entry_idx,
const size_t  target_idx,
const size_t  slot_idx,
const ReadFunction read_from_function 
)
private

A set of write functions to be used to directly write into final column_buffers_. The read_from_function is used to read from the input result set's storage NOTE: currently only used for direct columnarizations

Definition at line 249 of file ColumnarResults.cpp.

References column_buffers_, anonymous_namespace{ColumnarResults.cpp}::fixed_encoding_nullable_val(), and target_types_.

254  {
255  const auto val = static_cast<DATA_TYPE>(fixed_encoding_nullable_val(
256  read_from_function(rows, input_buffer_entry_idx, target_idx, slot_idx),
257  target_types_[target_idx]));
258  reinterpret_cast<DATA_TYPE*>(column_buffers_[target_idx])[output_buffer_entry_idx] =
259  val;
260 }
std::vector< int8_t * > column_buffers_
int64_t fixed_encoding_nullable_val(const int64_t val, const SQLTypeInfo &type_info)
const std::vector< SQLTypeInfo > target_types_

+ Here is the call graph for this function:

template<>
void ColumnarResults::writeBackCellDirect ( const ResultSet rows,
const size_t  input_buffer_entry_idx,
const size_t  output_buffer_entry_idx,
const size_t  target_idx,
const size_t  slot_idx,
const ReadFunction read_from_function 
)
private

Definition at line 263 of file ColumnarResults.cpp.

268  {
269  const int32_t ival =
270  read_from_function(rows, input_buffer_entry_idx, target_idx, slot_idx);
271  const float fval = *reinterpret_cast<const float*>(may_alias_ptr(&ival));
272  reinterpret_cast<float*>(column_buffers_[target_idx])[output_buffer_entry_idx] = fval;
273 }
std::vector< int8_t * > column_buffers_
template<>
void ColumnarResults::writeBackCellDirect ( const ResultSet rows,
const size_t  input_buffer_entry_idx,
const size_t  output_buffer_entry_idx,
const size_t  target_idx,
const size_t  slot_idx,
const ReadFunction read_from_function 
)
private

Definition at line 276 of file ColumnarResults.cpp.

282  {
283  const int64_t ival =
284  read_from_function(rows, input_buffer_entry_idx, target_idx, slot_idx);
285  const double dval = *reinterpret_cast<const double*>(may_alias_ptr(&ival));
286  reinterpret_cast<double*>(column_buffers_[target_idx])[output_buffer_entry_idx] = dval;
287 }
std::vector< int8_t * > column_buffers_

Member Data Documentation

std::vector<int8_t*> ColumnarResults::column_buffers_
protected
bool ColumnarResults::direct_columnar_conversion_
private

Definition at line 193 of file ColumnarResults.h.

Referenced by isDirectColumnarConversionPossible().

size_t ColumnarResults::num_rows_
protected
bool ColumnarResults::parallel_conversion_
private

Definition at line 191 of file ColumnarResults.h.

Referenced by isParallelConversion().

const std::vector<SQLTypeInfo> ColumnarResults::target_types_
private

The documentation for this class was generated from the following files: