// Return false if the tuple's table (tile group) is dropped. // In such case, this recycled tuple can not be added to the recycled_list. // Since no one will use it any more, keeping track of it is useless. // Note that, if we drop a single tile group without dropping the whole table, // such assumption is problematic. bool GCManager::ResetTuple(const TupleMetadata &tuple_metadata) { auto &manager = catalog::Manager::GetInstance(); auto tile_group = manager.GetTileGroup(tuple_metadata.tile_group_id); // During the resetting, a table may deconstruct because of the DROP TABLE request if (tile_group == nullptr) { LOG_TRACE("Garbage tuple(%u, %u) in table %u no longer exists", tuple_metadata.tile_group_id, tuple_metadata.tuple_slot_id, tuple_metadata.table_id); return false; } // From now on, the tile group shared pointer is held by us // It's safe to set headers from now on. auto tile_group_header = tile_group->GetHeader(); // Reset the header tile_group_header->SetTransactionId(tuple_metadata.tuple_slot_id, INVALID_TXN_ID); tile_group_header->SetBeginCommitId(tuple_metadata.tuple_slot_id, MAX_CID); tile_group_header->SetEndCommitId(tuple_metadata.tuple_slot_id, MAX_CID); tile_group_header->SetPrevItemPointer(tuple_metadata.tuple_slot_id, INVALID_ITEMPOINTER); tile_group_header->SetNextItemPointer(tuple_metadata.tuple_slot_id, INVALID_ITEMPOINTER); PL_MEMSET( tile_group_header->GetReservedFieldRef(tuple_metadata.tuple_slot_id), 0, storage::TileGroupHeader::GetReservedSize()); LOG_TRACE("Garbage tuple(%u, %u) in table %u is reset", tuple_metadata.tile_group_id, tuple_metadata.tuple_slot_id, tuple_metadata.table_id); return true; }
TileGroupHeader::TileGroupHeader(BackendType backend_type, int tuple_count) : backend_type(backend_type), data(nullptr), num_tuple_slots(tuple_count), next_tuple_slot(0) { header_size = num_tuple_slots * header_entry_size; // allocate storage space for header auto &storage_manager = storage::StorageManager::GetInstance(); data = reinterpret_cast<char *>( storage_manager.Allocate(backend_type, header_size)); assert(data != nullptr); // zero out the data std::memset(data, 0, header_size); // Set MVCC Initial Value for (oid_t tuple_slot_id = START_OID; tuple_slot_id < num_tuple_slots; tuple_slot_id++) { SetTransactionId(tuple_slot_id, INVALID_TXN_ID); SetBeginCommitId(tuple_slot_id, MAX_CID); SetEndCommitId(tuple_slot_id, MAX_CID); SetInsertCommit(tuple_slot_id, false); SetDeleteCommit(tuple_slot_id, false); } }
TileGroupHeader::TileGroupHeader(const BackendType &backend_type, const int &tuple_count) : backend_type(backend_type), data(nullptr), num_tuple_slots(tuple_count), next_tuple_slot(0), tile_header_lock() { header_size = num_tuple_slots * header_entry_size; // allocate storage space for header auto &storage_manager = storage::StorageManager::GetInstance(); data = reinterpret_cast<char *>( storage_manager.Allocate(backend_type, header_size)); PL_ASSERT(data != nullptr); // zero out the data PL_MEMSET(data, 0, header_size); // Set MVCC Initial Value for (oid_t tuple_slot_id = START_OID; tuple_slot_id < num_tuple_slots; tuple_slot_id++) { SetTransactionId(tuple_slot_id, INVALID_TXN_ID); SetBeginCommitId(tuple_slot_id, MAX_CID); SetEndCommitId(tuple_slot_id, MAX_CID); SetNextItemPointer(tuple_slot_id, INVALID_ITEMPOINTER); SetPrevItemPointer(tuple_slot_id, INVALID_ITEMPOINTER); SetInsertCommit(tuple_slot_id, false); // unused SetDeleteCommit(tuple_slot_id, false); // unused } }
bool TransactionLevelGCManager::ResetTuple(const ItemPointer &location) { auto &manager = catalog::Manager::GetInstance(); auto tile_group = manager.GetTileGroup(location.block).get(); auto tile_group_header = tile_group->GetHeader(); // Reset the header tile_group_header->SetTransactionId(location.offset, INVALID_TXN_ID); tile_group_header->SetBeginCommitId(location.offset, MAX_CID); tile_group_header->SetEndCommitId(location.offset, MAX_CID); tile_group_header->SetPrevItemPointer(location.offset, INVALID_ITEMPOINTER); tile_group_header->SetNextItemPointer(location.offset, INVALID_ITEMPOINTER); PL_MEMSET( tile_group_header->GetReservedFieldRef(location.offset), 0, storage::TileGroupHeader::GetReservedSize()); // Reclaim the varlen pool CheckAndReclaimVarlenColumns(tile_group, location.offset); LOG_TRACE("Garbage tuple(%u, %u) is reset", location.block, location.offset); return true; }
Result PessimisticTxnManager::AbortTransaction() { LOG_TRACE("Aborting peloton txn : %lu ", current_txn->GetTransactionId()); auto &manager = catalog::Manager::GetInstance(); auto &rw_set = current_txn->GetRWSet(); for (auto &tile_group_entry : rw_set) { oid_t tile_group_id = tile_group_entry.first; auto tile_group = manager.GetTileGroup(tile_group_id); auto tile_group_header = tile_group->GetHeader(); for (auto &tuple_entry : tile_group_entry.second) { auto tuple_slot = tuple_entry.first; if (tuple_entry.second == RW_TYPE_READ) { if (pessimistic_released_rdlock.find(tile_group_id) == pessimistic_released_rdlock.end() || pessimistic_released_rdlock[tile_group_id].find(tuple_slot) == pessimistic_released_rdlock[tile_group_id].end()) { ReleaseReadLock(tile_group_header, tuple_slot); pessimistic_released_rdlock[tile_group_id].insert(tuple_slot); } } else if (tuple_entry.second == RW_TYPE_UPDATE) { ItemPointer new_version = tile_group_header->GetNextItemPointer(tuple_slot); auto new_tile_group_header = manager.GetTileGroup(new_version.block)->GetHeader(); new_tile_group_header->SetBeginCommitId(new_version.offset, MAX_CID); new_tile_group_header->SetEndCommitId(new_version.offset, MAX_CID); COMPILER_MEMORY_FENCE; tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); COMPILER_MEMORY_FENCE; new_tile_group_header->SetTransactionId(new_version.offset, INVALID_TXN_ID); tile_group_header->SetTransactionId(tuple_slot, INITIAL_TXN_ID); } else if (tuple_entry.second == RW_TYPE_DELETE) { ItemPointer new_version = tile_group_header->GetNextItemPointer(tuple_slot); auto new_tile_group_header = manager.GetTileGroup(new_version.block)->GetHeader(); new_tile_group_header->SetBeginCommitId(new_version.offset, MAX_CID); new_tile_group_header->SetEndCommitId(new_version.offset, MAX_CID); COMPILER_MEMORY_FENCE; tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); COMPILER_MEMORY_FENCE; new_tile_group_header->SetTransactionId(new_version.offset, INVALID_TXN_ID); tile_group_header->SetTransactionId(tuple_slot, INITIAL_TXN_ID); } else if (tuple_entry.second == RW_TYPE_INSERT) { tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); tile_group_header->SetBeginCommitId(tuple_slot, MAX_CID); COMPILER_MEMORY_FENCE; tile_group_header->SetTransactionId(tuple_slot, INVALID_TXN_ID); } else if (tuple_entry.second == RW_TYPE_INS_DEL) { tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); tile_group_header->SetBeginCommitId(tuple_slot, MAX_CID); COMPILER_MEMORY_FENCE; tile_group_header->SetTransactionId(tuple_slot, INVALID_TXN_ID); } } } EndTransaction(); pessimistic_released_rdlock.clear(); return Result::RESULT_ABORTED; }
Result PessimisticTxnManager::CommitTransaction() { LOG_TRACE("Committing peloton txn : %lu ", current_txn->GetTransactionId()); auto &manager = catalog::Manager::GetInstance(); auto &rw_set = current_txn->GetRWSet(); //***************************************************** // we can optimize read-only transaction. if (current_txn->IsReadOnly() == true) { // validate read set. for (auto &tile_group_entry : rw_set) { oid_t tile_group_id = tile_group_entry.first; auto tile_group = manager.GetTileGroup(tile_group_id); auto tile_group_header = tile_group->GetHeader(); for (auto &tuple_entry : tile_group_entry.second) { auto tuple_slot = tuple_entry.first; // if this tuple is not newly inserted. if (tuple_entry.second == RW_TYPE_READ) { // Release read locks if (pessimistic_released_rdlock.find(tile_group_id) == pessimistic_released_rdlock.end() || pessimistic_released_rdlock[tile_group_id].find(tuple_slot) == pessimistic_released_rdlock[tile_group_id].end()) { ReleaseReadLock(tile_group_header, tuple_slot); pessimistic_released_rdlock[tile_group_id].insert(tuple_slot); } } else { assert(tuple_entry.second == RW_TYPE_INS_DEL); } } } // is it always true??? Result ret = current_txn->GetResult(); EndTransaction(); return ret; } //***************************************************** // generate transaction id. cid_t end_commit_id = GetNextCommitId(); auto &log_manager = logging::LogManager::GetInstance(); log_manager.LogBeginTransaction(end_commit_id); // install everything. for (auto &tile_group_entry : rw_set) { oid_t tile_group_id = tile_group_entry.first; auto tile_group = manager.GetTileGroup(tile_group_id); auto tile_group_header = tile_group->GetHeader(); for (auto &tuple_entry : tile_group_entry.second) { auto tuple_slot = tuple_entry.first; if (tuple_entry.second == RW_TYPE_READ) { // Release read locks if (pessimistic_released_rdlock.find(tile_group_id) == pessimistic_released_rdlock.end() || pessimistic_released_rdlock[tile_group_id].find(tuple_slot) == pessimistic_released_rdlock[tile_group_id].end()) { ReleaseReadLock(tile_group_header, tuple_slot); pessimistic_released_rdlock[tile_group_id].insert(tuple_slot); } } else if (tuple_entry.second == RW_TYPE_UPDATE) { // we must guarantee that, at any time point, only one version is // visible. ItemPointer new_version = tile_group_header->GetNextItemPointer(tuple_slot); ItemPointer old_version(tile_group_id, tuple_slot); // logging. log_manager.LogUpdate(current_txn, end_commit_id, old_version, new_version); auto new_tile_group_header = manager.GetTileGroup(new_version.block)->GetHeader(); new_tile_group_header->SetEndCommitId(new_version.offset, MAX_CID); new_tile_group_header->SetBeginCommitId(new_version.offset, end_commit_id); COMPILER_MEMORY_FENCE; tile_group_header->SetEndCommitId(tuple_slot, end_commit_id); COMPILER_MEMORY_FENCE; new_tile_group_header->SetTransactionId(new_version.offset, INITIAL_TXN_ID); tile_group_header->SetTransactionId(tuple_slot, INITIAL_TXN_ID); } else if (tuple_entry.second == RW_TYPE_DELETE) { ItemPointer new_version = tile_group_header->GetNextItemPointer(tuple_slot); ItemPointer delete_location(tile_group_id, tuple_slot); // logging. log_manager.LogDelete(end_commit_id, delete_location); // we do not change begin cid for old tuple. auto new_tile_group_header = manager.GetTileGroup(new_version.block)->GetHeader(); new_tile_group_header->SetEndCommitId(new_version.offset, MAX_CID); new_tile_group_header->SetBeginCommitId(new_version.offset, end_commit_id); COMPILER_MEMORY_FENCE; tile_group_header->SetEndCommitId(tuple_slot, end_commit_id); COMPILER_MEMORY_FENCE; new_tile_group_header->SetTransactionId(new_version.offset, INVALID_TXN_ID); tile_group_header->SetTransactionId(tuple_slot, INITIAL_TXN_ID); } else if (tuple_entry.second == RW_TYPE_INSERT) { assert(tile_group_header->GetTransactionId(tuple_slot) == current_txn->GetTransactionId()); // set the begin commit id to persist insert ItemPointer insert_location(tile_group_id, tuple_slot); log_manager.LogInsert(current_txn, end_commit_id, insert_location); tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); tile_group_header->SetBeginCommitId(tuple_slot, end_commit_id); COMPILER_MEMORY_FENCE; tile_group_header->SetTransactionId(tuple_slot, INITIAL_TXN_ID); } else if (tuple_entry.second == RW_TYPE_INS_DEL) { assert(tile_group_header->GetTransactionId(tuple_slot) == current_txn->GetTransactionId()); tile_group_header->SetEndCommitId(tuple_slot, MAX_CID); tile_group_header->SetBeginCommitId(tuple_slot, MAX_CID); COMPILER_MEMORY_FENCE; // set the begin commit id to persist insert tile_group_header->SetTransactionId(tuple_slot, INVALID_TXN_ID); } } } log_manager.LogCommitTransaction(end_commit_id); EndTransaction(); pessimistic_released_rdlock.clear(); return Result::RESULT_SUCCESS; }