bool PessimisticTxnManager::PerformDelete(const oid_t &tile_group_id, const oid_t &tuple_id, const ItemPointer &new_location) { LOG_TRACE("Performing Delete"); auto transaction_id = current_txn->GetTransactionId(); auto tile_group_header = catalog::Manager::GetInstance().GetTileGroup(tile_group_id)->GetHeader(); auto new_tile_group_header = catalog::Manager::GetInstance() .GetTileGroup(new_location.block)->GetHeader(); assert(tile_group_header->GetTransactionId(tuple_id) == transaction_id); assert(new_tile_group_header->GetTransactionId(new_location.offset) == INVALID_TXN_ID); assert(new_tile_group_header->GetBeginCommitId(new_location.offset) == MAX_CID); assert(new_tile_group_header->GetEndCommitId(new_location.offset) == MAX_CID); // Set up double linked list tile_group_header->SetNextItemPointer(tuple_id, new_location); new_tile_group_header->SetPrevItemPointer( new_location.offset, ItemPointer(tile_group_id, tuple_id)); new_tile_group_header->SetTransactionId(new_location.offset, transaction_id); new_tile_group_header->SetEndCommitId(new_location.offset, INVALID_CID); current_txn->RecordDelete(tile_group_id, tuple_id); return true; }
bool PessimisticTxnManager::PerformUpdate(const oid_t &tile_group_id, const oid_t &tuple_id, const ItemPointer &new_location) { LOG_INFO("Performing Write %lu %lu", tile_group_id, tuple_id); auto transaction_id = current_txn->GetTransactionId(); auto tile_group_header = catalog::Manager::GetInstance().GetTileGroup(tile_group_id)->GetHeader(); auto new_tile_group_header = catalog::Manager::GetInstance() .GetTileGroup(new_location.block)->GetHeader(); // if we can perform update, then we must have already locked the older // version. assert(tile_group_header->GetTransactionId(tuple_id) == transaction_id); assert(new_tile_group_header->GetTransactionId(new_location.offset) == INVALID_TXN_ID); assert(new_tile_group_header->GetBeginCommitId(new_location.offset) == MAX_CID); assert(new_tile_group_header->GetEndCommitId(new_location.offset) == MAX_CID); tile_group_header->SetTransactionId(tuple_id, transaction_id); // The write lock must have been acquired // Notice: if the executor doesn't call PerformUpdate after AcquireOwnership, // no // one will possibly release the write lock acquired by this txn. // Set double linked list tile_group_header->SetNextItemPointer(tuple_id, new_location); new_tile_group_header->SetPrevItemPointer( new_location.offset, ItemPointer(tile_group_id, tuple_id)); new_tile_group_header->SetTransactionId(new_location.offset, transaction_id); // Add the old tuple into the update set current_txn->RecordUpdate(tile_group_id, tuple_id); return true; }
TEST_F(LoggingTests, BasicDeleteTest) { auto recovery_table = ExecutorTestsUtil::CreateTable(1024); auto &manager = catalog::Manager::GetInstance(); storage::Database db(DEFAULT_DB_ID); manager.AddDatabase(&db); db.AddTable(recovery_table); EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0); EXPECT_EQ(recovery_table->GetTileGroupCount(), 1); logging::WriteAheadFrontendLogger fel(true); cid_t test_commit_id = 10; auto curr_rec = new logging::TupleRecord( LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(), INVALID_ITEMPOINTER, ItemPointer(100, 4), nullptr, DEFAULT_DB_ID); fel.DeleteTuple(curr_rec); delete curr_rec; auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader(); EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id); // EXPECT_EQ(recovery_table->GetNumberOfTuples(), 1); EXPECT_EQ(recovery_table->GetTileGroupCount(), 2); }
// this function returns a free tuple slot, if one exists // called by data_table. ItemPointer GCManager::ReturnFreeSlot(const oid_t &table_id) { if (this->gc_type_ == GC_TYPE_OFF) { return INVALID_ITEMPOINTER; } std::shared_ptr<LockfreeQueue<TupleMetadata>> recycle_queue; // if there exists recycle_queue if (recycle_queue_map_.find(table_id, recycle_queue) == true) { TupleMetadata tuple_metadata; if (recycle_queue->Dequeue(tuple_metadata) == true) { LOG_TRACE("Reuse tuple(%u, %u) in table %u", tuple_metadata.tile_group_id, tuple_metadata.tuple_slot_id, table_id); return ItemPointer(tuple_metadata.tile_group_id, tuple_metadata.tuple_slot_id); } } return ItemPointer(); }
TEST_F(LoggingTests, BasicUpdateTest) { auto recovery_table = ExecutorTestsUtil::CreateTable(1024); auto &manager = catalog::Manager::GetInstance(); storage::Database db(DEFAULT_DB_ID); manager.AddDatabase(&db); db.AddTable(recovery_table); auto tuples = BuildLoggingTuples(recovery_table, 1, false, false); EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0); EXPECT_EQ(recovery_table->GetTileGroupCount(), 1); EXPECT_EQ(tuples.size(), 1); logging::WriteAheadFrontendLogger fel(true); // auto bel = logging::WriteAheadBackendLogger::GetInstance(); cid_t test_commit_id = 10; Value val0 = tuples[0]->GetValue(0); Value val1 = tuples[0]->GetValue(1); Value val2 = tuples[0]->GetValue(2); Value val3 = tuples[0]->GetValue(3); auto curr_rec = new logging::TupleRecord( LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id, recovery_table->GetOid(), ItemPointer(100, 5), ItemPointer(100, 4), tuples[0], DEFAULT_DB_ID); curr_rec->SetTuple(tuples[0]); fel.UpdateTuple(curr_rec); delete curr_rec; auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader(); EXPECT_TRUE(tg_header->GetBeginCommitId(5) <= test_commit_id); EXPECT_EQ(tg_header->GetEndCommitId(5), MAX_CID); EXPECT_EQ(tg_header->GetEndCommitId(4), test_commit_id); EXPECT_TRUE( val0.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 0)) == 0); EXPECT_TRUE( val1.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 1)) == 0); EXPECT_TRUE( val2.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 2)) == 0); EXPECT_TRUE( val3.Compare(recovery_table->GetTileGroupById(100)->GetValue(5, 3)) == 0); EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0); EXPECT_EQ(recovery_table->GetTileGroupCount(), 2); }
TEST_F(LoggingTests, OutOfOrderCommitTest) { auto recovery_table = ExecutorTestsUtil::CreateTable(1024); auto &manager = catalog::Manager::GetInstance(); storage::Database db(DEFAULT_DB_ID); manager.AddDatabase(&db); db.AddTable(recovery_table); auto tuples = BuildLoggingTuples(recovery_table, 1, false, false); EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0); EXPECT_EQ(recovery_table->GetTileGroupCount(), 1); EXPECT_EQ(tuples.size(), 1); logging::WriteAheadFrontendLogger fel(true); // auto bel = logging::WriteAheadBackendLogger::GetInstance(); cid_t test_commit_id = 10; auto curr_rec = new logging::TupleRecord( LOGRECORD_TYPE_TUPLE_UPDATE, test_commit_id + 1, recovery_table->GetOid(), INVALID_ITEMPOINTER, ItemPointer(100, 5), nullptr, DEFAULT_DB_ID); fel.DeleteTuple(curr_rec); delete curr_rec; EXPECT_EQ(recovery_table->GetTileGroupCount(), 2); curr_rec = new logging::TupleRecord( LOGRECORD_TYPE_TUPLE_INSERT, test_commit_id, recovery_table->GetOid(), ItemPointer(100, 5), INVALID_ITEMPOINTER, tuples[0], DEFAULT_DB_ID); curr_rec->SetTuple(tuples[0]); fel.InsertTuple(curr_rec); delete curr_rec; auto tg_header = recovery_table->GetTileGroupById(100)->GetHeader(); EXPECT_EQ(tg_header->GetEndCommitId(5), test_commit_id + 1); EXPECT_EQ(recovery_table->GetNumberOfTuples(), 0); EXPECT_EQ(recovery_table->GetTileGroupCount(), 2); }
/** * @brief Move Tuples from log record-based local transaction to recovery * transaction * @param destination * @param source */ void AriesFrontendLogger::MoveTuples(concurrency::Transaction *destination, concurrency::Transaction *source) { // This is the local transaction auto inserted_tuples = source->GetInsertedTuples(); // Record the inserts in recovery txn for (auto entry : inserted_tuples) { oid_t tile_group_id = entry.first; for (auto tuple_slot : entry.second) { destination->RecordInsert(ItemPointer(tile_group_id, tuple_slot)); } } // Record the deletes in recovery txn auto deleted_tuples = source->GetDeletedTuples(); for (auto entry : deleted_tuples) { oid_t tile_group_id = entry.first; for (auto tuple_slot : entry.second) { destination->RecordDelete(ItemPointer(tile_group_id, tuple_slot)); } } // Clear inserted/deleted tuples from txn, just in case source->ResetState(); }
TEST_F(LogRecordTests, LogRecordTest) { std::vector<LogRecordType> tuple_type_list = { LogRecordType::TUPLE_INSERT, LogRecordType::TUPLE_DELETE, LogRecordType::TUPLE_UPDATE }; for (auto type : tuple_type_list) { logging::LogRecord tuple_record = logging::LogRecordFactory::CreateTupleRecord(type, ItemPointer(0, 0)); EXPECT_EQ(tuple_record.GetType(), type); } std::vector<LogRecordType> txn_type_list = { LogRecordType::TRANSACTION_BEGIN, LogRecordType::TRANSACTION_COMMIT }; for (auto type : txn_type_list) { logging::LogRecord txn_record = logging::LogRecordFactory::CreateTxnRecord(type, 50); EXPECT_EQ(txn_record.GetType(), type); } std::vector<LogRecordType> epoch_type_list = { LogRecordType::EPOCH_BEGIN, LogRecordType::EPOCH_END }; for (auto type : epoch_type_list) { logging::LogRecord epoch_record = logging::LogRecordFactory::CreateEpochRecord(type, 100); EXPECT_EQ(epoch_record.GetType(), type); } }
TEST_F(LogicalTileTests, TileMaterializationTest) { const int tuple_count = 4; std::shared_ptr<storage::TileGroup> tile_group( ExecutorTestsUtil::CreateTileGroup(tuple_count)); // Create tuple schema from tile schemas. std::vector<catalog::Schema> &tile_schemas = tile_group->GetTileSchemas(); std::unique_ptr<catalog::Schema> schema( catalog::Schema::AppendSchemaList(tile_schemas)); // Create tuples and insert them into tile group. const bool allocate = true; storage::Tuple tuple1(schema.get(), allocate); storage::Tuple tuple2(schema.get(), allocate); auto pool = tile_group->GetTilePool(1); tuple1.SetValue(0, ValueFactory::GetIntegerValue(1), pool); tuple1.SetValue(1, ValueFactory::GetIntegerValue(1), pool); tuple1.SetValue(2, ValueFactory::GetTinyIntValue(1), pool); tuple1.SetValue(3, ValueFactory::GetStringValue("tuple 1"), pool); tuple2.SetValue(0, ValueFactory::GetIntegerValue(2), pool); tuple2.SetValue(1, ValueFactory::GetIntegerValue(2), pool); tuple2.SetValue(2, ValueFactory::GetTinyIntValue(2), pool); tuple2.SetValue(3, ValueFactory::GetStringValue("tuple 2"), pool); auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); txn_manager.BeginTransaction(); // txn_id_t txn_id = txn->GetTransactionId(); auto tuple_id1 = tile_group->InsertTuple(&tuple1); auto tuple_id2 = tile_group->InsertTuple(&tuple2); auto tuple_id3 = tile_group->InsertTuple(&tuple1); txn_manager.PerformInsert(ItemPointer(tile_group->GetTileGroupId(), tuple_id1)); txn_manager.PerformInsert(ItemPointer(tile_group->GetTileGroupId(), tuple_id2)); txn_manager.PerformInsert(ItemPointer(tile_group->GetTileGroupId(), tuple_id3)); txn_manager.CommitTransaction(); //////////////////////////////////////////////////////////////// // LOGICAL TILE (1 BASE TILE) //////////////////////////////////////////////////////////////// // Don't transfer ownership of any base tile to logical tile. auto base_tile_ref = tile_group->GetTileReference(1); std::vector<oid_t> position_list1 = {0, 1}; std::vector<oid_t> position_list2 = {0, 1}; std::unique_ptr<executor::LogicalTile> logical_tile( executor::LogicalTileFactory::GetTile()); logical_tile->AddPositionList(std::move(position_list1)); logical_tile->AddPositionList(std::move(position_list2)); assert(tile_schemas.size() == 2); catalog::Schema *schema1 = &tile_schemas[0]; catalog::Schema *schema2 = &tile_schemas[1]; oid_t column_count = schema2->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count; column_itr++) { logical_tile->AddColumn(base_tile_ref, column_itr, column_itr); } LOG_INFO("%s", logical_tile->GetInfo().c_str()); //////////////////////////////////////////////////////////////// // LOGICAL TILE (2 BASE TILE) //////////////////////////////////////////////////////////////// logical_tile.reset(executor::LogicalTileFactory::GetTile()); auto base_tile_ref1 = tile_group->GetTileReference(0); auto base_tile_ref2 = tile_group->GetTileReference(1); position_list1 = {0, 1}; position_list2 = {0, 1}; std::vector<oid_t> position_list3 = {0, 1}; std::vector<oid_t> position_list4 = {0, 1}; logical_tile->AddPositionList(std::move(position_list1)); logical_tile->AddPositionList(std::move(position_list2)); logical_tile->AddPositionList(std::move(position_list3)); logical_tile->AddPositionList(std::move(position_list4)); oid_t column_count1 = schema1->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count1; column_itr++) { logical_tile->AddColumn(base_tile_ref1, column_itr, column_itr); } oid_t column_count2 = schema2->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count2; column_itr++) { logical_tile->AddColumn(base_tile_ref2, column_itr, column_count1 + column_itr); } LOG_INFO("%s", logical_tile->GetInfo().c_str()); }
TEST_F(LogicalTileTests, TileMaterializationTest) { const int tuple_count = 4; std::shared_ptr<storage::TileGroup> tile_group( TestingExecutorUtil::CreateTileGroup(tuple_count)); std::vector<const catalog::Schema *> tile_schemas; for (unsigned int i = 0; i < tile_group->NumTiles(); i++) { tile_schemas.push_back(tile_group->GetTile(i)->GetSchema()); } // Create tuple schema from tile schemas. std::unique_ptr<catalog::Schema> schema( catalog::Schema::AppendSchemaPtrList(tile_schemas)); // Create tuples and insert them into tile group. const bool allocate = true; storage::Tuple tuple1(schema.get(), allocate); storage::Tuple tuple2(schema.get(), allocate); auto pool = tile_group->GetTilePool(1); tuple1.SetValue(0, type::ValueFactory::GetIntegerValue(1), pool); tuple1.SetValue(1, type::ValueFactory::GetIntegerValue(1), pool); tuple1.SetValue(2, type::ValueFactory::GetTinyIntValue(1), pool); tuple1.SetValue(3, type::ValueFactory::GetVarcharValue("tuple 1"), pool); tuple2.SetValue(0, type::ValueFactory::GetIntegerValue(2), pool); tuple2.SetValue(1, type::ValueFactory::GetIntegerValue(2), pool); tuple2.SetValue(2, type::ValueFactory::GetTinyIntValue(2), pool); tuple2.SetValue(3, type::ValueFactory::GetVarcharValue("tuple 2"), pool); auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); // txn_id_t txn_id = txn->GetTransactionId(); auto tuple_id1 = tile_group->InsertTuple(&tuple1); auto tuple_id2 = tile_group->InsertTuple(&tuple2); auto tuple_id3 = tile_group->InsertTuple(&tuple1); ItemPointer *index_entry_ptr = nullptr; txn_manager.PerformInsert( txn, ItemPointer(tile_group->GetTileGroupId(), tuple_id1), index_entry_ptr); txn_manager.PerformInsert( txn, ItemPointer(tile_group->GetTileGroupId(), tuple_id2), index_entry_ptr); txn_manager.PerformInsert( txn, ItemPointer(tile_group->GetTileGroupId(), tuple_id3), index_entry_ptr); txn_manager.CommitTransaction(txn); //////////////////////////////////////////////////////////////// // LOGICAL TILE (1 BASE TILE) //////////////////////////////////////////////////////////////// // Don't transfer ownership of any base tile to logical tile. auto base_tile_ref = tile_group->GetTileReference(1); std::vector<oid_t> position_list1 = {0, 1}; std::vector<oid_t> position_list2 = {0, 1}; std::unique_ptr<executor::LogicalTile> logical_tile( executor::LogicalTileFactory::GetTile()); logical_tile->AddPositionList(std::move(position_list1)); logical_tile->AddPositionList(std::move(position_list2)); oid_t column_count = tile_schemas[1]->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count; column_itr++) { logical_tile->AddColumn(base_tile_ref, column_itr, column_itr); } LOG_TRACE("%s", logical_tile->GetInfo().c_str()); //////////////////////////////////////////////////////////////// // LOGICAL TILE (2 BASE TILE) //////////////////////////////////////////////////////////////// logical_tile.reset(executor::LogicalTileFactory::GetTile()); auto base_tile_ref1 = tile_group->GetTileReference(0); auto base_tile_ref2 = tile_group->GetTileReference(1); position_list1 = {0, 1}; position_list2 = {0, 1}; std::vector<oid_t> position_list3 = {0, 1}; std::vector<oid_t> position_list4 = {0, 1}; logical_tile->AddPositionList(std::move(position_list1)); logical_tile->AddPositionList(std::move(position_list2)); logical_tile->AddPositionList(std::move(position_list3)); logical_tile->AddPositionList(std::move(position_list4)); oid_t column_count1 = tile_schemas[0]->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count1; column_itr++) { logical_tile->AddColumn(base_tile_ref1, column_itr, column_itr); } oid_t column_count2 = tile_schemas[1]->GetColumnCount(); for (oid_t column_itr = 0; column_itr < column_count2; column_itr++) { logical_tile->AddColumn(base_tile_ref2, column_itr, column_count1 + column_itr); } LOG_TRACE("%s", logical_tile->GetInfo().c_str()); }