pos_list_t Store::buildValidPositions(tx::transaction_cid_t last_commit_id, tx::transaction_id_t tid) const { pos_list_t result; functional::forEachWithIndex(_cidBeginVector, [&](size_t i, tx::transaction_cid_t v){ if(isVisibleForTransaction(i, last_commit_id, tid)) result.push_back(i); }); return std::move(result); }
void Store::merge() { if (merger == nullptr) { throw std::runtime_error("No Merger set."); } // Create new delta and merge atable_ptr_t new_delta = delta->copy_structure(create_concurrent_dict, create_concurrent_storage); // Prepare the merge std::vector<c_atable_ptr_t> tmp {_main_table, delta}; // get valid positions std::vector<bool> validPositions(_cidBeginVector.size()); tx::transaction_cid_t last_commit_id = tx::TransactionManager::getInstance().getLastCommitId(); functional::forEachWithIndex(_cidBeginVector, [&](size_t i, bool v){ validPositions[i] = isVisibleForTransaction(i, last_commit_id, tx::MERGE_TID); }); auto tables = merger->merge(tmp, true, validPositions); assert(tables.size() == 1); _main_table = tables.front(); // Fixup the cid and tid vectors _cidBeginVector = tbb::concurrent_vector<tx::transaction_cid_t>(_main_table->size(), tx::UNKNOWN_CID); _cidEndVector = tbb::concurrent_vector<tx::transaction_cid_t>(_main_table->size(), tx::INF_CID); _tidVector = tbb::concurrent_vector<tx::transaction_id_t>(_main_table->size(), tx::START_TID); // Replace the delta partition delta = new_delta; _delta_size = new_delta->size(); }
// This method iterates of the pos list and validates each position void Store::validatePositions(pos_list_t& pos, tx::transaction_cid_t last_commit_id, tx::transaction_id_t tid) const { // Make sure we captured all rows assert(_cidBeginVector.size() == size() && _cidEndVector.size() == size() && _tidVector.size() == size()); // Pos is nullptr, we should circumvent auto end = std::remove_if(std::begin(pos), std::end(pos), [&](const pos_t& v){ return !isVisibleForTransaction(v, last_commit_id, tid); } ); if (end != pos.end()) pos.erase(end, pos.end()); }
void CompoundIndexScan::executePlanOperation() { if (!_main_index_name.empty()) setMainIndex(_main_index_name); if (!_delta_index_name.empty()) setDeltaIndex(_delta_index_name); pos_list_t* result = new pos_list_t; if (!_validate) { if (!_json_predicates.empty()) parseJsonPredicates(); if (_main_index) { if (_predicates_added_main != _main_index->getColumns().size()) { throw std::runtime_error( "Incomplete predicate set specified - Partial Search only Implemeted for Validating-IndexScan"); } storage::PositionRange main_result = _main_index->getPositionsForKey(_valueid_key_builder.get()); result->resize(main_result.size()); std::copy(main_result.cbegin(), main_result.cend(), result->begin()); } if (_delta_index) { storage::PositionRange delta_result = _delta_index->getPositionsForKey(_value_key_builder.get()); size_t real_result_size = result->size(); // we need to resize the result list below result->resize(result->size() + delta_result.size()); std::copy(delta_result.cbegin(), delta_result.cend(), result->begin() + real_result_size); } } else { // The index performs a validation of results directly, minimizing the overhead for copying large, invalid positions // around. // Note: A large part of the index-lookup of the main is already performed during the predicate evaluation, when all // predicate-values are checked against the Main dictioanries. // therefore we seperatly create the predicates for the delta first, to save that work in the unqiue index-case // Refactoring Discussion: // The best solution might be a Planop "IndexLookup" for Complete-Key Lookups // and a seperate Planop IndexScan for partial keys. // auto c_store = checked_pointer_cast<const storage::Store>(input.getTables()[0]); pos_list_t validated_delta_result; bool skipmain = false; if (!_unique_index and !_json_predicates.empty()) parseJsonPredicates(/*set_for_main=*/true, /*set_for_delta=*/true); if (_delta_index) { if (_unique_index and !_json_predicates.empty()) parseJsonPredicates(/*set_for_main=*/false, /*set_for_delta=*/true); if (_main_index and _predicates_added_delta != _main_index->getColumns().size()) { // partial search auto s_key = _value_key_builder.get(); auto up_key = _value_key_builder.get_upperbound(); auto iterator_pair = _delta_index->getIteratorsForKeyBetween(s_key, up_key); if (!_unique_index) { for (auto dp = iterator_pair.first; dp != iterator_pair.second; ++dp) { if (c_store->isVisibleForTransaction(dp->second, _txContext.lastCid, _txContext.tid)) { validated_delta_result.push_back(dp->second); } } } else { // Evaluate a unique index auto dp = iterator_pair.second; // Validate entries from delta index backwards, as newer items are to be found at the end.; while (dp != iterator_pair.first) { // skips if start==end dp--; if (c_store->isVisibleForTransaction(dp->second, _txContext.lastCid, _txContext.tid)) { validated_delta_result.push_back(dp->second); skipmain = true; break; // Unique Index, one hit sufficient } } } } else { // all attr in index specified auto iterator_pair = _delta_index->getIteratorsForKey(_value_key_builder.get()); if (!_unique_index) { for (auto dp = iterator_pair.first; dp != iterator_pair.second; ++dp) { if (c_store->isVisibleForTransaction(dp->second, _txContext.lastCid, _txContext.tid)) { validated_delta_result.push_back(dp->second); } } } else { // Evaluate a unique index auto dp = iterator_pair.second; // Validate entries from delta index backwards, as newer items are to be found at the end.; while (dp != iterator_pair.first) { // skips if start==end dp--; if (c_store->isVisibleForTransaction(dp->second, _txContext.lastCid, _txContext.tid)) { validated_delta_result.push_back(dp->second); skipmain = true; break; // Unique Index, one hit sufficient } } } } } if (!skipmain and _main_index) { if (_unique_index and !_json_predicates.empty()) parseJsonPredicates(/*set_for_main=*/true, /*set_for_delta=*/false); if (_predicates_added_main != _main_index->getColumns().size()) { // incomplete key, perform partial search compound_valueid_key_t search_key = _valueid_key_builder.get(); compound_valueid_key_t valid_bits = _valueid_key_builder.getValidBitMaskForCurrentKey(); compound_valueid_key_t upper_bound = search_key | (~valid_bits); // std::cout << "SK: " << search_key << " UP:" << upper_bound << " Valid Bits: " << valid_bits << std::endl; storage::PositionRange main_result = _main_index->getPositionsForKeyBetween(search_key, upper_bound); result->resize(main_result.size()); std::copy(main_result.cbegin(), main_result.cend(), result->begin()); // note: can this break if the largest value id is a power of two? } else { storage::PositionRange main_result = _main_index->getPositionsForKey(_valueid_key_builder.get()); result->resize(main_result.size()); std::copy(main_result.cbegin(), main_result.cend(), result->begin()); } c_store->validatePositions(*result, _txContext.lastCid, _txContext.tid); } if (skipmain) { result->swap(validated_delta_result); } else { size_t real_result_size = result->size(); // we need to resize the result list below result->resize(result->size() + validated_delta_result.size()); std::copy(validated_delta_result.cbegin(), validated_delta_result.cend(), result->begin() + real_result_size); } } addResult(storage::PointerCalculator::create(input.getTables()[0], result)); }