TEST_F(MutateTests, DeleteTest) { // We are going to insert a tile group into a table in this test storage::DataTable *table = ExecutorTestsUtil::CreateTable(); auto testing_pool = TestingHarness::GetInstance().GetTestingPool(); LaunchParallelTest(1, InsertTuple, table, testing_pool); LaunchParallelTest(1, DeleteTuple, table); auto &txn_manager = concurrency::OptimisticTxnManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn)); // Seq scan std::vector<oid_t> column_ids = {0}; planner::SeqScanPlan seq_scan_node(table, nullptr, column_ids); executor::SeqScanExecutor seq_scan_executor(&seq_scan_node, context.get()); EXPECT_TRUE(seq_scan_executor.Init()); auto tuple_cnt = 0; while (seq_scan_executor.Execute()) { std::unique_ptr<executor::LogicalTile> result_logical_tile( seq_scan_executor.GetOutput()); tuple_cnt += result_logical_tile->GetTupleCount(); } txn_manager.CommitTransaction(); EXPECT_EQ(tuple_cnt, 6); delete table; tuple_id = 0; }
/** * @brief Convenience function to pass a single logical tile through an * executor which has only one child. * @param executor Executor to pass logical tile through. * @param source_logical_tile Logical tile to pass through executor. * @param check the value of logical tiles * * @return Pointer to processed logical tile. */ executor::LogicalTile *ExecutorTestsUtil::ExecuteTile( executor::AbstractExecutor *executor, executor::LogicalTile *source_logical_tile) { MockExecutor child_executor; executor->AddChild(&child_executor); // Uneventful init... EXPECT_CALL(child_executor, DInit()).WillOnce(Return(true)); EXPECT_TRUE(executor->Init()); // Where the main work takes place... EXPECT_CALL(child_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(child_executor, GetOutput()) .WillOnce(Return(source_logical_tile)); EXPECT_TRUE(executor->Execute()); std::unique_ptr<executor::LogicalTile> result_logical_tile( executor->GetOutput()); EXPECT_THAT(result_logical_tile, NotNull()); EXPECT_THAT(executor->Execute(), false); return result_logical_tile.release(); }
// "Pass-through" test case. There is nothing to materialize as // there is only one base tile in the logical tile. TEST_F(MaterializationTests, SingleBaseTileTest) { const int tuple_count = 9; std::shared_ptr<storage::TileGroup> tile_group( ExecutorTestsUtil::CreateTileGroup(tuple_count)); ExecutorTestsUtil::PopulateTiles(tile_group, tuple_count); // Create logical tile from single base tile. auto source_base_tile = tile_group->GetTileReference(0); // Add a reference because we are going to wrap around it and we don't own it std::unique_ptr<executor::LogicalTile> source_logical_tile( executor::LogicalTileFactory::WrapTiles({source_base_tile})); // Pass through materialization executor. executor::MaterializationExecutor executor(nullptr, nullptr); std::unique_ptr<executor::LogicalTile> result_logical_tile( ExecutorTestsUtil::ExecuteTile(&executor, source_logical_tile.release())); // Verify that logical tile is only made up of a single base tile. int num_cols = result_logical_tile->GetColumnCount(); EXPECT_EQ(2, num_cols); storage::Tile *result_base_tile = result_logical_tile->GetBaseTile(0); EXPECT_THAT(result_base_tile, NotNull()); EXPECT_TRUE(source_base_tile.get() == result_base_tile); EXPECT_EQ(result_logical_tile->GetBaseTile(1), result_base_tile); // Check that the base tile has the correct values. for (int i = 0; i < tuple_count; i++) { type::Value val0 = (result_base_tile->GetValue(i, 0)); type::Value val1 = (result_base_tile->GetValue(i, 1)); type::CmpBool cmp = (val0.CompareEquals( type::ValueFactory::GetIntegerValue(ExecutorTestsUtil::PopulatedValue(i, 0)))); EXPECT_TRUE(cmp == type::CMP_TRUE); cmp = val1.CompareEquals(type::ValueFactory::GetIntegerValue( ExecutorTestsUtil::PopulatedValue(i, 1))); EXPECT_TRUE(cmp == type::CMP_TRUE); // Double check that logical tile is functioning. type::Value logic_val0 = (result_logical_tile->GetValue(i, 0)); type::Value logic_val1 = (result_logical_tile->GetValue(i, 1)); cmp = (logic_val0.CompareEquals(val0)); EXPECT_TRUE(cmp == type::CMP_TRUE); cmp = (logic_val1.CompareEquals(val1)); EXPECT_TRUE(cmp == type::CMP_TRUE); } }
TEST_F(GCDeleteTestVacuum, DeleteTest) { peloton::gc::GCManagerFactory::Configure(type); peloton::gc::GCManagerFactory::GetInstance().StartGC(); auto *table = ExecutorTestsUtil::CreateTable(1024); auto &manager = catalog::Manager::GetInstance(); storage::Database db(DEFAULT_DB_ID); manager.AddDatabase(&db); db.AddTable(table); // We are going to insert a tile group into a table in this test auto testing_pool = TestingHarness::GetInstance().GetTestingPool(); auto before_insert = catalog::Manager::GetInstance().GetMemoryFootprint(); LaunchParallelTest(1, InsertTuple, table, testing_pool); auto after_insert = catalog::Manager::GetInstance().GetMemoryFootprint(); EXPECT_GT(after_insert, before_insert); LaunchParallelTest(1, DeleteTuple, table); std::this_thread::sleep_for(std::chrono::seconds(10)); auto after_delete = catalog::Manager::GetInstance().GetMemoryFootprint(); EXPECT_EQ(after_insert, after_delete); auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn)); // Seq scan std::vector<oid_t> column_ids = {0}; planner::SeqScanPlan seq_scan_node(table, nullptr, column_ids); executor::SeqScanExecutor seq_scan_executor(&seq_scan_node, context.get()); EXPECT_TRUE(seq_scan_executor.Init()); auto tuple_cnt = 0; while (seq_scan_executor.Execute()) { std::unique_ptr<executor::LogicalTile> result_logical_tile( seq_scan_executor.GetOutput()); tuple_cnt += result_logical_tile->GetTupleCount(); } txn_manager.CommitTransaction(); EXPECT_EQ(tuple_cnt, 6); tuple_id = 0; }
int SeqScanCount(storage::DataTable *table, const std::vector<oid_t> &column_ids, expression::AbstractExpression *predicate) { auto &txn_manager = concurrency::OptimisticTxnManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); std::unique_ptr<executor::ExecutorContext> context( new executor::ExecutorContext(txn)); planner::SeqScanPlan seq_scan_node(table, predicate, column_ids); executor::SeqScanExecutor seq_scan_executor(&seq_scan_node, context.get()); EXPECT_TRUE(seq_scan_executor.Init()); auto tuple_cnt = 0; while (seq_scan_executor.Execute()) { std::unique_ptr<executor::LogicalTile> result_logical_tile( seq_scan_executor.GetOutput()); tuple_cnt += result_logical_tile->GetTupleCount(); } txn_manager.CommitTransaction(); return tuple_cnt; }
void ExecuteJoinTest(PlanNodeType join_algorithm, PelotonJoinType join_type, oid_t join_test_type) { //===--------------------------------------------------------------------===// // Mock table scan executors //===--------------------------------------------------------------------===// MockExecutor left_table_scan_executor, right_table_scan_executor; // Create a table and wrap it in logical tile size_t tile_group_size = TESTS_TUPLES_PER_TILEGROUP; size_t left_table_tile_group_count = 3; size_t right_table_tile_group_count = 2; auto &txn_manager = concurrency::TransactionManager::GetInstance(); auto txn = txn_manager.BeginTransaction(); auto txn_id = txn->GetTransactionId(); // Left table has 3 tile groups std::unique_ptr<storage::DataTable> left_table( ExecutorTestsUtil::CreateTable(tile_group_size)); ExecutorTestsUtil::PopulateTable( txn, left_table.get(), tile_group_size * left_table_tile_group_count, false, false, false); // Right table has 2 tile groups std::unique_ptr<storage::DataTable> right_table( ExecutorTestsUtil::CreateTable(tile_group_size)); ExecutorTestsUtil::PopulateTable( txn, right_table.get(), tile_group_size * right_table_tile_group_count, false, false, false); txn_manager.CommitTransaction(); //std::cout << (*left_table); //std::cout << (*right_table); // Wrap the input tables with logical tiles std::unique_ptr<executor::LogicalTile> left_table_logical_tile1( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> left_table_logical_tile2( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(1), txn_id)); std::unique_ptr<executor::LogicalTile> left_table_logical_tile3( executor::LogicalTileFactory::WrapTileGroup(left_table->GetTileGroup(2), txn_id)); std::unique_ptr<executor::LogicalTile> right_table_logical_tile1( executor::LogicalTileFactory::WrapTileGroup( right_table->GetTileGroup(0), txn_id)); std::unique_ptr<executor::LogicalTile> right_table_logical_tile2( executor::LogicalTileFactory::WrapTileGroup( right_table->GetTileGroup(1), txn_id)); // Left scan executor returns logical tiles from the left table EXPECT_CALL(left_table_scan_executor, DInit()).WillOnce(Return(true)); //===--------------------------------------------------------------------===// // Setup left table //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { EXPECT_CALL(left_table_scan_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(left_table_scan_executor, GetOutput()) .WillOnce(Return(left_table_logical_tile1.release())) .WillOnce(Return(left_table_logical_tile2.release())) .WillOnce(Return(left_table_logical_tile3.release())); } // Right scan executor returns logical tiles from the right table EXPECT_CALL(right_table_scan_executor, DInit()).WillOnce(Return(true)); //===--------------------------------------------------------------------===// // Setup right table //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { EXPECT_CALL(right_table_scan_executor, DExecute()) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(false)); EXPECT_CALL(right_table_scan_executor, GetOutput()) .WillOnce(Return(right_table_logical_tile1.release())) .WillOnce(Return(right_table_logical_tile2.release())); } //===--------------------------------------------------------------------===// // Setup join plan nodes and executors and run them //===--------------------------------------------------------------------===// oid_t result_tuple_count = 0; oid_t tuples_with_null = 0; auto projection = JoinTestsUtil::CreateProjection(); // Construct predicate expression::AbstractExpression *predicate = JoinTestsUtil::CreateJoinPredicate(); // Differ based on join algorithm switch (join_algorithm) { case PLAN_NODE_TYPE_NESTLOOP: { // Create nested loop join plan node. planner::NestedLoopJoinPlan nested_loop_join_node(join_type, predicate, projection); // Run the nested loop join executor executor::NestedLoopJoinExecutor nested_loop_join_executor( &nested_loop_join_node, nullptr); // Construct the executor tree nested_loop_join_executor.AddChild(&left_table_scan_executor); nested_loop_join_executor.AddChild(&right_table_scan_executor); // Run the nested loop join executor EXPECT_TRUE(nested_loop_join_executor.Init()); while (nested_loop_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( nested_loop_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); //std::cout << (*result_logical_tile); } } } break; case PLAN_NODE_TYPE_MERGEJOIN: { // Create join clauses std::vector<planner::MergeJoinPlan::JoinClause> join_clauses; join_clauses = CreateJoinClauses(); // Create merge join plan node planner::MergeJoinPlan merge_join_node(join_type, predicate, projection, join_clauses); // Construct the merge join executor executor::MergeJoinExecutor merge_join_executor(&merge_join_node, nullptr); // Construct the executor tree merge_join_executor.AddChild(&left_table_scan_executor); merge_join_executor.AddChild(&right_table_scan_executor); // Run the merge join executor EXPECT_TRUE(merge_join_executor.Init()); while (merge_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( merge_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); //std::cout << (*result_logical_tile); } } } break; case PLAN_NODE_TYPE_HASHJOIN: { // Create hash plan node expression::AbstractExpression *right_table_attr_1 = new expression::TupleValueExpression(1, 1); std::vector<std::unique_ptr<const expression::AbstractExpression> > hash_keys; hash_keys.emplace_back(right_table_attr_1); // Create hash plan node planner::HashPlan hash_plan_node(hash_keys); // Construct the hash executor executor::HashExecutor hash_executor(&hash_plan_node, nullptr); // Create hash join plan node. planner::HashJoinPlan hash_join_plan_node(join_type, predicate, projection); // Construct the hash join executor executor::HashJoinExecutor hash_join_executor(&hash_join_plan_node, nullptr); // Construct the executor tree hash_join_executor.AddChild(&left_table_scan_executor); hash_join_executor.AddChild(&hash_executor); hash_executor.AddChild(&right_table_scan_executor); // Run the hash_join_executor EXPECT_TRUE(hash_join_executor.Init()); while (hash_join_executor.Execute() == true) { std::unique_ptr<executor::LogicalTile> result_logical_tile( hash_join_executor.GetOutput()); if (result_logical_tile != nullptr) { result_tuple_count += result_logical_tile->GetTupleCount(); tuples_with_null += CountTuplesWithNullFields(result_logical_tile.get()); // std::cout << (*result_logical_tile); } } } break; default: throw Exception("Unsupported join algorithm : " + std::to_string(join_algorithm)); break; } //===--------------------------------------------------------------------===// // Execute test //===--------------------------------------------------------------------===// if(join_test_type == BASIC_TEST) { // Check output switch (join_type) { case JOIN_TYPE_INNER: EXPECT_EQ(result_tuple_count, 10); EXPECT_EQ(tuples_with_null, 0); break; case JOIN_TYPE_LEFT: EXPECT_EQ(result_tuple_count, 15); EXPECT_EQ(tuples_with_null, 5); break; case JOIN_TYPE_RIGHT: EXPECT_EQ(result_tuple_count, 10); EXPECT_EQ(tuples_with_null, 0); break; case JOIN_TYPE_OUTER: EXPECT_EQ(result_tuple_count, 15); EXPECT_EQ(tuples_with_null, 5); break; default: throw Exception("Unsupported join type : " + std::to_string(join_type)); break; } } }
// Materializing logical tile composed of two base tiles. // The materialized tile's output columns are reordered. // Also, one of the columns is dropped. TEST_F(MaterializationTests, TwoBaseTilesWithReorderTest) { const int tuple_count = 9; std::shared_ptr<storage::TileGroup> tile_group( ExecutorTestsUtil::CreateTileGroup(tuple_count)); ExecutorTestsUtil::PopulateTiles(tile_group, tuple_count); // Create logical tile from two base tiles. const std::vector<std::shared_ptr<storage::Tile> > source_base_tiles = { tile_group->GetTileReference(0), tile_group->GetTileReference(1)}; // Add a reference because we are going to wrap around it and we don't own it std::unique_ptr<executor::LogicalTile> source_logical_tile( executor::LogicalTileFactory::WrapTiles(source_base_tiles)); // Create materialization node for this test. // Construct output schema. We drop column 3 and reorder the others to 3,1,0. std::vector<catalog::Column> output_columns; // Note that Column 3 in the tile group is column 1 in the second tile. output_columns.push_back(source_base_tiles[1]->GetSchema()->GetColumn(1)); output_columns.push_back(source_base_tiles[0]->GetSchema()->GetColumn(1)); output_columns.push_back(source_base_tiles[0]->GetSchema()->GetColumn(0)); std::unique_ptr<catalog::Schema> output_schema( new catalog::Schema(output_columns)); // Construct mapping using the ordering mentioned above. std::unordered_map<oid_t, oid_t> old_to_new_cols; old_to_new_cols[3] = 0; old_to_new_cols[1] = 1; old_to_new_cols[0] = 2; bool physify_flag = true; // is going to create a physical tile planner::MaterializationPlan node(old_to_new_cols, output_schema.release(), physify_flag); // Pass through materialization executor. executor::MaterializationExecutor executor(&node, nullptr); std::unique_ptr<executor::LogicalTile> result_logical_tile( ExecutorTestsUtil::ExecuteTile(&executor, source_logical_tile.release())); // Verify that logical tile is only made up of a single base tile. int num_cols = result_logical_tile->GetColumnCount(); EXPECT_EQ(3, num_cols); storage::Tile *result_base_tile = result_logical_tile->GetBaseTile(0); EXPECT_THAT(result_base_tile, NotNull()); EXPECT_EQ(result_base_tile, result_logical_tile->GetBaseTile(1)); EXPECT_EQ(result_base_tile, result_logical_tile->GetBaseTile(2)); // Check that the base tile has the correct values. for (int i = 0; i < tuple_count; i++) { // Output column 2. EXPECT_EQ( ValueFactory::GetIntegerValue(ExecutorTestsUtil::PopulatedValue(i, 0)), result_base_tile->GetValue(i, 2)); // Output column 1. EXPECT_EQ( ValueFactory::GetIntegerValue(ExecutorTestsUtil::PopulatedValue(i, 1)), result_base_tile->GetValue(i, 1)); // Output column 0. Value string_value(ValueFactory::GetStringValue( std::to_string(ExecutorTestsUtil::PopulatedValue(i, 3)))); EXPECT_EQ(string_value, result_base_tile->GetValue(i, 0)); // Double check that logical tile is functioning. EXPECT_EQ(result_base_tile->GetValue(i, 0), result_logical_tile->GetValue(i, 0)); EXPECT_EQ(result_base_tile->GetValue(i, 1), result_logical_tile->GetValue(i, 1)); EXPECT_EQ(result_base_tile->GetValue(i, 2), result_logical_tile->GetValue(i, 2)); } }