/** * @brief Insert a tuple into all indexes. If index is primary/unique, * check visibility of existing * index entries. * @warning This still doesn't guarantee serializability. * * @returns True on success, false if a visible entry exists (in case of *primary/unique). */ bool DataTable::InsertInIndexes(const storage::Tuple *tuple, ItemPointer location) { int index_count = GetIndexCount(); auto &transaction_manager = concurrency::TransactionManagerFactory::GetInstance(); std::function<bool(const ItemPointer &)> fn = std::bind(&concurrency::TransactionManager::IsOccupied, &transaction_manager, std::placeholders::_1); // (A) Check existence for primary/unique indexes // FIXME Since this is NOT protected by a lock, concurrent insert may happen. for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) { auto index = GetIndex(index_itr); auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); std::unique_ptr<storage::Tuple> key(new storage::Tuple(index_schema, true)); key->SetFromTuple(tuple, indexed_columns, index->GetPool()); switch (index->GetIndexType()) { case INDEX_CONSTRAINT_TYPE_PRIMARY_KEY: case INDEX_CONSTRAINT_TYPE_UNIQUE: { // TODO: get unique tuple from primary index. // if in this index there has been a visible or uncommitted // <key, location> pair, this constraint is violated if (index->CondInsertEntry(key.get(), location, fn) == false) { return false; } } break; case INDEX_CONSTRAINT_TYPE_DEFAULT: default: index->InsertEntry(key.get(), location); break; } LOG_TRACE("Index constraint check on %s passed.", index->GetName().c_str()); } return true; }
/** * @brief Insert a tuple into all indexes. If index is primary/unique, * check visibility of existing * index entries. * @warning This still doesn't guarantee serializability. * * @returns True on success, false if a visible entry exists (in case of *primary/unique). */ bool DataTable::InsertInIndexes(const storage::Tuple *tuple, ItemPointer location, concurrency::Transaction *transaction, ItemPointer **index_entry_ptr) { int index_count = GetIndexCount(); size_t active_indirection_array_id = number_of_tuples_ % ACTIVE_INDIRECTION_ARRAY_COUNT; size_t indirection_offset = INVALID_INDIRECTION_OFFSET; while (true) { auto active_indirection_array = active_indirection_arrays_[active_indirection_array_id]; indirection_offset = active_indirection_array->AllocateIndirection(); if (indirection_offset != INVALID_INDIRECTION_OFFSET) { *index_entry_ptr = active_indirection_array->GetIndirectionByOffset(indirection_offset); break; } } (*index_entry_ptr)->block = location.block; (*index_entry_ptr)->offset = location.offset; if (indirection_offset == INDIRECTION_ARRAY_MAX_SIZE - 1) { AddDefaultIndirectionArray(active_indirection_array_id); } auto &transaction_manager = concurrency::TransactionManagerFactory::GetInstance(); std::function<bool(const void *)> fn = std::bind(&concurrency::TransactionManager::IsOccupied, &transaction_manager, transaction, std::placeholders::_1); // Since this is NOT protected by a lock, concurrent insert may happen. bool res = true; int success_count = 0; for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) { auto index = GetIndex(index_itr); auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); std::unique_ptr<storage::Tuple> key(new storage::Tuple(index_schema, true)); key->SetFromTuple(tuple, indexed_columns, index->GetPool()); switch (index->GetIndexType()) { case INDEX_CONSTRAINT_TYPE_PRIMARY_KEY: { // get unique tuple from primary index. // if in this index there has been a visible or uncommitted // <key, location> pair, this constraint is violated res = index->CondInsertEntry(key.get(), *index_entry_ptr, fn); } break; case INDEX_CONSTRAINT_TYPE_UNIQUE: { // get unique tuple from primary index. // if in this index there has been a visible or uncommitted // <key, location> pair, this constraint is violated // res = index->CondInsertEntry(key.get(), *index_entry_ptr, fn); } break; case INDEX_CONSTRAINT_TYPE_DEFAULT: default: index->InsertEntry(key.get(), *index_entry_ptr); break; } // Handle failure if (res == false) { // If some of the indexes have been inserted, // the pointer has a chance to be dereferenced by readers and it cannot be deleted *index_entry_ptr = nullptr; return false; } else { success_count += 1; } LOG_TRACE("Index constraint check on %s passed.", index->GetName().c_str()); } return true; }
bool DataTable::InsertInSecondaryIndexes(const AbstractTuple *tuple, const TargetList *targets_ptr, concurrency::Transaction *transaction, ItemPointer *index_entry_ptr) { int index_count = GetIndexCount(); // Transform the target list into a hash set // when attempting to perform insertion to a secondary index, // we must check whether the updated column is a secondary index column. // insertion happens only if the updated column is a secondary index column. std::unordered_set<oid_t> targets_set; for (auto target : *targets_ptr) { targets_set.insert(target.first); } bool res = true; auto &transaction_manager = concurrency::TransactionManagerFactory::GetInstance(); std::function<bool(const void *)> fn = std::bind(&concurrency::TransactionManager::IsOccupied, &transaction_manager, transaction, std::placeholders::_1); // Check existence for primary/unique indexes // Since this is NOT protected by a lock, concurrent insert may happen. for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) { auto index = GetIndex(index_itr); if (index == nullptr) continue; auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); if (index->GetIndexType() == IndexConstraintType::PRIMARY_KEY) { continue; } // Check if we need to update the secondary index bool updated = false; for (auto col : indexed_columns) { if (targets_set.find(col) != targets_set.end()) { updated = true; break; } } // If attributes on key are not updated, skip the index update if (updated == false) { continue; } // Key attributes are updated, insert a new entry in all secondary index std::unique_ptr<storage::Tuple> key(new storage::Tuple(index_schema, true)); key->SetFromTuple(tuple, indexed_columns, index->GetPool()); switch (index->GetIndexType()) { case IndexConstraintType::PRIMARY_KEY: case IndexConstraintType::UNIQUE: { res = index->CondInsertEntry(key.get(), index_entry_ptr, fn); } break; case IndexConstraintType::DEFAULT: default: index->InsertEntry(key.get(), index_entry_ptr); break; } LOG_TRACE("Index constraint check on %s passed.", index->GetName().c_str()); } return res; }