bool DataTable::InsertInSecondaryIndexes(const storage::Tuple *tuple, ItemPointer location) { int index_count = GetIndexCount(); // (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: break; case INDEX_CONSTRAINT_TYPE_UNIQUE: { // if in this index there has been a visible or uncommitted // <key, location> pair, this constraint is violated index->InsertEntry(key.get(), location); } 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; }
bool DataTable::InsertInSecondaryIndexes(const AbstractTuple *tuple, const TargetList *targets_ptr, ItemPointer *index_entry_ptr) { int index_count = GetIndexCount(); // Transaform 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); } // 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); auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); if (index->GetIndexType() == INDEX_CONSTRAINT_TYPE_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 INDEX_CONSTRAINT_TYPE_PRIMARY_KEY: break; case INDEX_CONSTRAINT_TYPE_UNIQUE: break; case INDEX_CONSTRAINT_TYPE_DEFAULT: default: index->InsertEntry(key.get(), index_entry_ptr); break; } LOG_TRACE("Index constraint check on %s passed.", index->GetName().c_str()); } return true; }
void IndexTuner::BuildIndex(storage::DataTable* table, std::shared_ptr<index::Index> index) { auto table_schema = table->GetSchema(); auto index_tile_group_offset = index->GetIndexedTileGroupOff(); auto table_tile_group_count = table->GetTileGroupCount(); oid_t tile_groups_indexed = 0; auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); std::unique_ptr<storage::Tuple> key(new storage::Tuple(index_schema, true)); while (index_tile_group_offset < table_tile_group_count && (tile_groups_indexed < max_tile_groups_indexed)) { std::unique_ptr<storage::Tuple> tuple_ptr( new storage::Tuple(table_schema, true)); auto tile_group = table->GetTileGroup(index_tile_group_offset); auto tile_group_id = tile_group->GetTileGroupId(); oid_t active_tuple_count = tile_group->GetNextTupleSlot(); for (oid_t tuple_id = 0; tuple_id < active_tuple_count; tuple_id++) { // Copy over the tuple tile_group->CopyTuple(tuple_id, tuple_ptr.get()); // Set the location ItemPointer location(tile_group_id, tuple_id); // Set the key key->SetFromTuple(tuple_ptr.get(), indexed_columns, index->GetPool()); // Insert in specific index // index->InsertEntry(key.get(), location); } // Update indexed tile group offset (set of tgs indexed) index->IncrementIndexedTileGroupOffset(); // Sleep a bit // std::this_thread::sleep_for(std::chrono::microseconds(sleep_duration)); index_tile_group_offset++; tile_groups_indexed++; } }
/** * @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; }
// delete a tuple from all its indexes it belongs to. void TransactionLevelGCManager::DeleteTupleFromIndexes(ItemPointer *indirection) { // do nothing if indirection is null if (indirection == nullptr){ return; } LOG_TRACE("Deleting indirection %p from index", indirection); ItemPointer location = *indirection; auto &manager = catalog::Manager::GetInstance(); auto tile_group = manager.GetTileGroup(location.block); PL_ASSERT(tile_group != nullptr); storage::DataTable *table = dynamic_cast<storage::DataTable *>(tile_group->GetAbstractTable()); PL_ASSERT(table != nullptr); // construct the expired version. expression::ContainerTuple<storage::TileGroup> expired_tuple(tile_group.get(), location.offset); // unlink the version from all the indexes. for (size_t idx = 0; idx < table->GetIndexCount(); ++idx) { auto index = table->GetIndex(idx); auto index_schema = index->GetKeySchema(); auto indexed_columns = index_schema->GetIndexedColumns(); // build key. std::unique_ptr<storage::Tuple> key( new storage::Tuple(index_schema, true)); key->SetFromTuple(&expired_tuple, indexed_columns, index->GetPool()); index->DeleteEntry(key.get(), indirection); } }
/** * @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; }