From 81d28c0295f055a6e694b40dd495a96adb2157a0 Mon Sep 17 00:00:00 2001 From: obdev Date: Sat, 28 Jan 2023 18:08:50 +0800 Subject: [PATCH] [FEAT MERGE] add direct load function Co-authored-by: Monk-Liu <1152761042@qq.com> Co-authored-by: saltonz Co-authored-by: yongshige <598633031@qq.com> --- .gitignore | 1 + deps/oblib/src/lib/allocator/ob_malloc.h | 2 +- deps/oblib/src/lib/queue/ob_fixed_queue.h | 11 +- deps/oblib/src/lib/queue/ob_lighty_queue.cpp | 95 +- deps/oblib/src/lib/queue/ob_lighty_queue.h | 58 +- deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h | 6 + src/objit/include/objit/common/ob_item_type.h | 1 + src/observer/CMakeLists.txt | 43 + src/observer/ob_server.cpp | 35 + src/observer/ob_server.h | 10 +- src/observer/ob_srv_xlator_partition.cpp | 35 + src/observer/ob_srv_xlator_rootserver.cpp | 6 + src/observer/omt/ob_multi_tenant.cpp | 2 + src/observer/table/ob_table_rpc_processor.cpp | 27 +- src/observer/table/ob_table_rpc_processor.h | 6 + .../ob_table_load_abort_processor.cpp | 91 + .../ob_table_load_abort_processor.h | 54 + .../ob_table_load_autoinc_nextval.cpp | 220 ++ .../ob_table_load_autoinc_nextval.h | 34 + .../ob_table_load_begin_processor.cpp | 274 +++ .../ob_table_load_begin_processor.h | 78 + .../table_load/ob_table_load_bucket.cpp | 56 + .../table_load/ob_table_load_bucket.h | 57 + .../ob_table_load_commit_processor.cpp | 96 + .../ob_table_load_commit_processor.h | 54 + .../table_load/ob_table_load_coordinator.cpp | 1517 ++++++++++++ .../table_load/ob_table_load_coordinator.h | 107 + .../ob_table_load_coordinator_ctx.cpp | 646 +++++ .../ob_table_load_coordinator_ctx.h | 148 ++ .../ob_table_load_coordinator_trans.cpp | 189 ++ .../ob_table_load_coordinator_trans.h | 76 + .../table_load/ob_table_load_csv_parser.cpp | 155 ++ .../table_load/ob_table_load_csv_parser.h | 41 + .../ob_table_load_error_row_handler.cpp | 305 +++ .../ob_table_load_error_row_handler.h | 96 + .../table_load/ob_table_load_exec_ctx.cpp | 27 + .../table_load/ob_table_load_exec_ctx.h | 30 + .../ob_table_load_finish_processor.cpp | 130 ++ .../ob_table_load_finish_processor.h | 75 + .../ob_table_load_general_table_compactor.cpp | 531 +++++ .../ob_table_load_general_table_compactor.h | 82 + .../ob_table_load_get_status_processor.cpp | 89 + .../ob_table_load_get_status_processor.h | 54 + .../table_load/ob_table_load_instance.cpp | 240 ++ .../table_load/ob_table_load_instance.h | 61 + .../table_load/ob_table_load_manager.h | 150 ++ .../ob_table_load_mem_compactor.cpp | 678 ++++++ .../table_load/ob_table_load_mem_compactor.h | 91 + .../table_load/ob_table_load_merger.cpp | 433 ++++ .../table_load/ob_table_load_merger.h | 55 + ...ble_load_multiple_heap_table_compactor.cpp | 527 +++++ ...table_load_multiple_heap_table_compactor.h | 74 + .../table_load/ob_table_load_obj_cast.cpp | 354 +++ .../table_load/ob_table_load_obj_cast.h | 238 ++ .../ob_table_load_object_allocator.h | 60 + .../ob_table_load_parallel_merge_ctx.cpp | 921 ++++++++ .../ob_table_load_parallel_merge_ctx.h | 113 + ...le_load_parallel_merge_table_compactor.cpp | 168 ++ ...able_load_parallel_merge_table_compactor.h | 43 + .../ob_table_load_partition_calc.cpp | 289 +++ .../table_load/ob_table_load_partition_calc.h | 80 + .../ob_table_load_partition_location.cpp | 340 +++ .../ob_table_load_partition_location.h | 86 + .../table_load/ob_table_load_processor.cpp | 216 ++ .../table_load/ob_table_load_processor.h | 60 + src/observer/table_load/ob_table_load_queue.h | 108 + .../table_load/ob_table_load_redef_table.cpp | 174 ++ .../table_load/ob_table_load_redef_table.h | 38 + .../table_load/ob_table_load_schema.cpp | 278 +++ .../table_load/ob_table_load_schema.h | 76 + .../table_load/ob_table_load_service.cpp | 339 +++ .../table_load/ob_table_load_service.h | 78 + src/observer/table_load/ob_table_load_stat.h | 140 ++ .../table_load/ob_table_load_store.cpp | 943 ++++++++ src/observer/table_load/ob_table_load_store.h | 94 + .../table_load/ob_table_load_store_ctx.cpp | 918 ++++++++ .../table_load/ob_table_load_store_ctx.h | 168 ++ .../table_load/ob_table_load_store_trans.cpp | 246 ++ .../table_load/ob_table_load_store_trans.h | 78 + .../table_load/ob_table_load_struct.h | 162 ++ .../ob_table_load_table_compactor.cpp | 213 ++ .../ob_table_load_table_compactor.h | 80 + .../table_load/ob_table_load_table_ctx.cpp | 294 +++ .../table_load/ob_table_load_table_ctx.h | 79 + .../table_load/ob_table_load_task.cpp | 61 + src/observer/table_load/ob_table_load_task.h | 105 + .../ob_table_load_task_scheduler.cpp | 330 +++ .../table_load/ob_table_load_task_scheduler.h | 101 + .../table_load/ob_table_load_time_convert.cpp | 105 + .../table_load/ob_table_load_time_convert.h | 39 + .../ob_table_load_trans_bucket_writer.cpp | 339 +++ .../ob_table_load_trans_bucket_writer.h | 81 + .../table_load/ob_table_load_trans_ctx.cpp | 99 + .../table_load/ob_table_load_trans_ctx.h | 46 + .../ob_table_load_trans_processor.cpp | 381 +++ .../ob_table_load_trans_processor.h | 204 ++ .../table_load/ob_table_load_trans_store.cpp | 489 ++++ .../table_load/ob_table_load_trans_store.h | 122 + .../table_load/ob_table_load_utils.cpp | 208 ++ src/observer/table_load/ob_table_load_utils.h | 143 ++ .../ob_all_virtual_load_data_stat.cpp | 90 +- .../ob_all_virtual_load_data_stat.h | 19 +- src/pl/sys_package/ob_dbms_stats.cpp | 2 +- .../ddl_task/ob_column_redefinition_task.cpp | 43 + .../ddl_task/ob_column_redefinition_task.h | 3 + .../ddl_task/ob_ddl_redefinition_task.cpp | 52 - .../ddl_task/ob_ddl_redefinition_task.h | 5 +- src/rootserver/ddl_task/ob_ddl_scheduler.cpp | 679 +++++- src/rootserver/ddl_task/ob_ddl_scheduler.h | 98 +- src/rootserver/ddl_task/ob_ddl_task.cpp | 50 +- src/rootserver/ddl_task/ob_ddl_task.h | 9 +- .../ddl_task/ob_table_redefinition_task.cpp | 231 +- .../ddl_task/ob_table_redefinition_task.h | 25 + src/rootserver/ob_ddl_service.cpp | 135 ++ src/rootserver/ob_ddl_service.h | 2 + src/rootserver/ob_root_service.cpp | 156 +- src/rootserver/ob_root_service.h | 10 +- src/rootserver/ob_rs_rpc_processor.h | 6 + src/share/CMakeLists.txt | 4 + .../ob_inner_table_schema.12201_12250.cpp | 169 +- .../inner_table/ob_inner_table_schema_def.py | 17 +- src/share/ob_common_rpc_proxy.h | 6 + src/share/ob_ddl_common.h | 4 +- src/share/ob_rpc_struct.cpp | 401 ++++ src/share/ob_rpc_struct.h | 300 ++- src/share/ob_tablet_autoincrement_param.cpp | 19 + src/share/ob_tablet_autoincrement_param.h | 2 + src/share/ob_thread_define.h | 2 + src/share/parameter/ob_parameter_seed.ipp | 3 + src/share/rc/ob_tenant_base.h | 2 + src/share/stat/ob_dbms_stats_executor.cpp | 55 +- src/share/stat/ob_dbms_stats_executor.h | 6 - src/share/stat/ob_dbms_stats_utils.cpp | 54 +- src/share/stat/ob_dbms_stats_utils.h | 11 + .../stat/ob_incremental_stat_estimator.cpp | 264 ++- .../stat/ob_incremental_stat_estimator.h | 29 +- src/share/stat/ob_opt_column_stat.h | 1 - src/share/table/ob_table_load_array.h | 282 +++ src/share/table/ob_table_load_define.cpp | 150 ++ src/share/table/ob_table_load_define.h | 538 +++++ src/share/table/ob_table_load_handle.h | 85 + src/share/table/ob_table_load_row.cpp | 40 + src/share/table/ob_table_load_row.h | 185 ++ src/share/table/ob_table_load_row_array.h | 138 ++ src/share/table/ob_table_load_rpc_struct.cpp | 267 +++ src/share/table/ob_table_load_rpc_struct.h | 667 ++++++ .../table/ob_table_load_shared_allocator.cpp | 128 + .../table/ob_table_load_shared_allocator.h | 51 + src/share/table/ob_table_rpc_proxy.h | 31 + src/sql/CMakeLists.txt | 3 + .../code_generator/ob_static_engine_cg.cpp | 12 + src/sql/das/ob_das_dml_ctx_define.cpp | 3 +- src/sql/das/ob_das_dml_ctx_define.h | 9 +- src/sql/das/ob_das_insert_op.cpp | 1 + .../aggregate/ob_aggregate_processor.cpp | 1 - .../engine/aggregate/ob_aggregate_processor.h | 3 +- src/sql/engine/cmd/ob_ddl_executor_util.h | 2 +- .../engine/cmd/ob_load_data_direct_impl.cpp | 2079 +++++++++++++++++ src/sql/engine/cmd/ob_load_data_direct_impl.h | 465 ++++ src/sql/engine/cmd/ob_load_data_executor.cpp | 35 +- src/sql/engine/cmd/ob_load_data_executor.h | 2 + src/sql/engine/cmd/ob_load_data_impl.cpp | 14 +- src/sql/engine/cmd/ob_load_data_impl.h | 7 +- src/sql/engine/cmd/ob_load_data_utils.cpp | 100 +- src/sql/engine/cmd/ob_load_data_utils.h | 100 +- .../engine/cmd/ob_table_direct_insert_ctx.cpp | 148 ++ .../engine/cmd/ob_table_direct_insert_ctx.h | 43 + .../cmd/ob_table_direct_insert_trans.cpp | 116 + .../engine/cmd/ob_table_direct_insert_trans.h | 27 + src/sql/engine/dml/ob_table_insert_op.cpp | 25 + src/sql/engine/ob_exec_context.cpp | 3 +- src/sql/engine/ob_exec_context.h | 4 + src/sql/engine/ob_physical_plan.cpp | 10 +- src/sql/engine/ob_physical_plan.h | 6 + .../static/ob_px_multi_part_insert_op.cpp | 24 +- src/sql/ob_result_set.cpp | 24 +- src/sql/optimizer/ob_del_upd_log_plan.cpp | 41 +- src/sql/optimizer/ob_del_upd_log_plan.h | 2 + src/sql/optimizer/ob_insert_log_plan.cpp | 3 + src/sql/optimizer/ob_log_insert.h | 7 + src/sql/optimizer/ob_table_location.cpp | 152 +- src/sql/optimizer/ob_table_location.h | 12 + src/sql/parser/sql_parser_mysql_mode.l | 22 + src/sql/parser/sql_parser_mysql_mode.y | 14 +- .../resolver/cmd/ob_load_data_resolver.cpp | 79 +- src/sql/resolver/cmd/ob_load_data_stmt.cpp | 45 + src/sql/resolver/cmd/ob_load_data_stmt.h | 25 +- src/sql/resolver/dml/ob_dml_resolver.cpp | 1 + src/sql/resolver/dml/ob_hint.cpp | 5 + src/sql/resolver/dml/ob_hint.h | 8 + src/sql/resolver/dml/ob_insert_resolver.cpp | 10 + src/storage/CMakeLists.txt | 71 + src/storage/access/ob_dml_param.h | 4 + src/storage/access/ob_multiple_merge.cpp | 11 +- .../access/ob_sstable_row_whole_scanner.cpp | 2 + .../access/ob_table_access_context.cpp | 3 +- src/storage/access/ob_table_access_context.h | 8 +- src/storage/blocksstable/ob_sstable.h | 4 + src/storage/blocksstable/ob_tmp_file.cpp | 161 +- src/storage/blocksstable/ob_tmp_file.h | 104 +- .../blocksstable/ob_tmp_file_cache.cpp | 348 ++- src/storage/blocksstable/ob_tmp_file_cache.h | 150 +- .../blocksstable/ob_tmp_file_store.cpp | 435 ++-- src/storage/blocksstable/ob_tmp_file_store.h | 166 +- src/storage/ddl/ob_ddl_heart_beat_task.cpp | 165 ++ src/storage/ddl/ob_ddl_heart_beat_task.h | 82 + src/storage/ddl/ob_ddl_merge_task.cpp | 20 +- src/storage/ddl/ob_ddl_server_client.cpp | 236 ++ src/storage/ddl/ob_ddl_server_client.h | 38 + .../ddl/ob_direct_insert_sstable_ctx.cpp | 647 +++-- .../ddl/ob_direct_insert_sstable_ctx.h | 107 +- .../direct_load/ob_direct_load_compare.cpp | 307 +++ .../direct_load/ob_direct_load_compare.h | 104 + .../direct_load/ob_direct_load_data_block.cpp | 73 + .../direct_load/ob_direct_load_data_block.h | 37 + .../ob_direct_load_data_block_decoder.h | 232 ++ .../ob_direct_load_data_block_encoder.h | 234 ++ .../ob_direct_load_data_block_reader.h | 264 +++ .../ob_direct_load_data_block_writer.h | 280 +++ .../direct_load/ob_direct_load_data_fuse.cpp | 422 ++++ .../direct_load/ob_direct_load_data_fuse.h | 129 + .../direct_load/ob_direct_load_datum.cpp | 347 +++ .../direct_load/ob_direct_load_datum.h | 67 + .../direct_load/ob_direct_load_easy_queue.h | 63 + .../ob_direct_load_external_block_reader.h | 20 + .../ob_direct_load_external_block_writer.h | 33 + .../ob_direct_load_external_fragment.cpp | 133 ++ .../ob_direct_load_external_fragment.h | 65 + ...ob_direct_load_external_fragment_builder.h | 166 ++ .../ob_direct_load_external_interface.h | 36 + .../ob_direct_load_external_merger.h | 256 ++ ...rect_load_external_multi_partition_row.cpp | 193 ++ ...direct_load_external_multi_partition_row.h | 62 + ...ct_load_external_multi_partition_table.cpp | 180 ++ ...rect_load_external_multi_partition_table.h | 61 + .../ob_direct_load_external_row.cpp | 187 ++ .../direct_load/ob_direct_load_external_row.h | 44 + .../ob_direct_load_external_scanner.h | 256 ++ .../ob_direct_load_external_table.cpp | 118 + .../ob_direct_load_external_table.h | 67 + .../ob_direct_load_external_table_builder.cpp | 178 ++ .../ob_direct_load_external_table_builder.h | 62 + ...b_direct_load_external_table_compactor.cpp | 158 ++ .../ob_direct_load_external_table_compactor.h | 50 + .../ob_direct_load_fast_heap_table.cpp | 104 + .../ob_direct_load_fast_heap_table.h | 62 + ...ob_direct_load_fast_heap_table_builder.cpp | 282 +++ .../ob_direct_load_fast_heap_table_builder.h | 78 + .../ob_direct_load_fast_heap_table_ctx.cpp | 197 ++ .../ob_direct_load_fast_heap_table_ctx.h | 77 + .../direct_load/ob_direct_load_i_table.h | 52 + .../ob_direct_load_insert_table_ctx.cpp | 218 ++ .../ob_direct_load_insert_table_ctx.h | 59 + .../ob_direct_load_io_callback.cpp | 73 + .../direct_load/ob_direct_load_io_callback.h | 35 + .../direct_load/ob_direct_load_mem_chunk.h | 196 ++ .../ob_direct_load_mem_context.cpp | 157 ++ .../direct_load/ob_direct_load_mem_context.h | 98 + .../direct_load/ob_direct_load_mem_define.h | 37 + .../direct_load/ob_direct_load_mem_dump.cpp | 451 ++++ .../direct_load/ob_direct_load_mem_dump.h | 96 + .../direct_load/ob_direct_load_mem_loader.cpp | 156 ++ .../direct_load/ob_direct_load_mem_loader.h | 36 + .../direct_load/ob_direct_load_mem_sample.cpp | 176 ++ .../direct_load/ob_direct_load_mem_sample.h | 50 + .../direct_load/ob_direct_load_mem_worker.h | 28 + .../ob_direct_load_memory_writer.h | 178 ++ .../direct_load/ob_direct_load_merge_ctx.cpp | 725 ++++++ .../direct_load/ob_direct_load_merge_ctx.h | 147 ++ .../ob_direct_load_merge_task_iterator.cpp | 79 + .../ob_direct_load_merge_task_iterator.h | 30 + .../direct_load/ob_direct_load_multi_map.h | 170 ++ .../ob_direct_load_multiple_datum_range.cpp | 125 + .../ob_direct_load_multiple_datum_range.h | 46 + .../ob_direct_load_multiple_datum_row.cpp | 181 ++ .../ob_direct_load_multiple_datum_row.h | 40 + .../ob_direct_load_multiple_datum_rowkey.cpp | 242 ++ .../ob_direct_load_multiple_datum_rowkey.h | 60 + .../ob_direct_load_multiple_external_row.cpp | 157 ++ .../ob_direct_load_multiple_external_row.h | 41 + .../ob_direct_load_multiple_heap_table.cpp | 233 ++ .../ob_direct_load_multiple_heap_table.h | 113 + ...irect_load_multiple_heap_table_builder.cpp | 245 ++ ..._direct_load_multiple_heap_table_builder.h | 86 + ...ect_load_multiple_heap_table_compactor.cpp | 337 +++ ...irect_load_multiple_heap_table_compactor.h | 64 + ...t_load_multiple_heap_table_index_block.cpp | 165 ++ ...ect_load_multiple_heap_table_index_block.h | 73 + ...multiple_heap_table_index_block_reader.cpp | 111 + ...d_multiple_heap_table_index_block_reader.h | 37 + ...multiple_heap_table_index_block_writer.cpp | 66 + ...d_multiple_heap_table_index_block_writer.h | 35 + ...ultiple_heap_table_index_entry_compare.cpp | 79 + ..._multiple_heap_table_index_entry_compare.h | 35 + ...multiple_heap_table_index_entry_iterator.h | 113 + ...d_multiple_heap_table_index_scan_merge.cpp | 180 ++ ...oad_multiple_heap_table_index_scan_merge.h | 49 + ...heap_table_index_scan_merge_loser_tree.cpp | 45 + ...e_heap_table_index_scan_merge_loser_tree.h | 46 + ...load_multiple_heap_table_index_scanner.cpp | 206 ++ ...t_load_multiple_heap_table_index_scanner.h | 63 + ...ob_direct_load_multiple_heap_table_map.cpp | 94 + .../ob_direct_load_multiple_heap_table_map.h | 49 + ...irect_load_multiple_heap_table_scanner.cpp | 126 + ..._direct_load_multiple_heap_table_scanner.h | 42 + ...direct_load_multiple_heap_table_sorter.cpp | 235 ++ ...b_direct_load_multiple_heap_table_sorter.h | 61 + .../ob_direct_load_multiple_sstable.cpp | 334 +++ .../ob_direct_load_multiple_sstable.h | 134 ++ ...b_direct_load_multiple_sstable_builder.cpp | 305 +++ .../ob_direct_load_multiple_sstable_builder.h | 83 + ...direct_load_multiple_sstable_compactor.cpp | 195 ++ ...b_direct_load_multiple_sstable_compactor.h | 55 + ...ad_multiple_sstable_data_block_scanner.cpp | 239 ++ ...load_multiple_sstable_data_block_scanner.h | 48 + ...d_multiple_sstable_index_block_compare.cpp | 93 + ...oad_multiple_sstable_index_block_compare.h | 44 + ...tiple_sstable_index_block_meta_scanner.cpp | 343 +++ ...ultiple_sstable_index_block_meta_scanner.h | 115 + ...d_multiple_sstable_index_entry_compare.cpp | 191 ++ ...oad_multiple_sstable_index_entry_compare.h | 72 + ...irect_load_multiple_sstable_scan_merge.cpp | 297 +++ ..._direct_load_multiple_sstable_scan_merge.h | 84 + ...multiple_sstable_scan_merge_loser_tree.cpp | 70 + ...d_multiple_sstable_scan_merge_loser_tree.h | 55 + ...b_direct_load_multiple_sstable_scanner.cpp | 136 ++ .../ob_direct_load_multiple_sstable_scanner.h | 54 + .../ob_direct_load_origin_table.cpp | 312 +++ .../direct_load/ob_direct_load_origin_table.h | 92 + .../ob_direct_load_partition_merge_task.cpp | 816 +++++++ .../ob_direct_load_partition_merge_task.h | 210 ++ .../ob_direct_load_range_splitter.cpp | 1153 +++++++++ .../ob_direct_load_range_splitter.h | 223 ++ .../ob_direct_load_rowkey_iterator.cpp | 116 + .../ob_direct_load_rowkey_iterator.h | 61 + .../ob_direct_load_rowkey_merger.h | 240 ++ .../direct_load/ob_direct_load_sstable.cpp | 348 +++ .../direct_load/ob_direct_load_sstable.h | 182 ++ .../ob_direct_load_sstable_builder.cpp | 894 +++++++ .../ob_direct_load_sstable_builder.h | 239 ++ .../ob_direct_load_sstable_compactor.cpp | 190 ++ .../ob_direct_load_sstable_compactor.h | 55 + .../ob_direct_load_sstable_data_block.cpp | 109 + .../ob_direct_load_sstable_data_block.h | 52 + ...ob_direct_load_sstable_data_block_reader.h | 47 + ...ob_direct_load_sstable_data_block_writer.h | 73 + .../ob_direct_load_sstable_index_block.cpp | 159 ++ .../ob_direct_load_sstable_index_block.h | 61 + ...direct_load_sstable_index_block_iterator.h | 171 ++ ...direct_load_sstable_index_block_reader.cpp | 120 + ...b_direct_load_sstable_index_block_reader.h | 42 + ...direct_load_sstable_index_block_writer.cpp | 67 + ...b_direct_load_sstable_index_block_writer.h | 36 + ...direct_load_sstable_index_entry_iterator.h | 171 ++ .../ob_direct_load_sstable_scan_merge.cpp | 299 +++ .../ob_direct_load_sstable_scan_merge.h | 87 + ...ect_load_sstable_scan_merge_loser_tree.cpp | 77 + ...irect_load_sstable_scan_merge_loser_tree.h | 56 + .../ob_direct_load_sstable_scanner.cpp | 783 +++++++ .../ob_direct_load_sstable_scanner.h | 136 ++ .../ob_direct_load_table_builder_allocator.h | 98 + .../ob_direct_load_table_data_desc.cpp | 64 + .../ob_direct_load_table_data_desc.h | 46 + .../ob_direct_load_table_store.cpp | 361 +++ .../direct_load/ob_direct_load_table_store.h | 90 + .../direct_load/ob_direct_load_tmp_file.cpp | 473 ++++ .../direct_load/ob_direct_load_tmp_file.h | 131 ++ src/storage/ls/ob_ls_tablet_service.cpp | 94 +- src/storage/ls/ob_ls_tablet_service.h | 8 + src/storage/memtable/ob_memtable.h | 2 +- src/storage/memtable/ob_memtable_interface.h | 2 +- src/storage/ob_i_table.h | 1 + src/storage/tx_storage/ob_access_service.cpp | 3 +- .../all_virtual_sys_parameter_stat.result | 1 + tools/upgrade/upgrade_checker.py | 8 + tools/upgrade/upgrade_post.py | 8 + tools/upgrade/upgrade_pre.py | 8 + unittest/storage/CMakeLists.txt | 1 + .../backup/test_backup_index_merger.cpp | 2 +- .../storage/backup/test_backup_iterator.cpp | 4 +- .../storage/blocksstable/test_tmp_file.cpp | 266 ++- unittest/storage/direct_load/CMakeLists.txt | 2 + .../test_direct_load_data_block_writer.cpp | 1529 ++++++++++++ .../test_direct_load_index_block_writer.cpp | 196 ++ 384 files changed, 55860 insertions(+), 1239 deletions(-) create mode 100644 src/observer/table_load/ob_table_load_abort_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_abort_processor.h create mode 100644 src/observer/table_load/ob_table_load_autoinc_nextval.cpp create mode 100644 src/observer/table_load/ob_table_load_autoinc_nextval.h create mode 100644 src/observer/table_load/ob_table_load_begin_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_begin_processor.h create mode 100644 src/observer/table_load/ob_table_load_bucket.cpp create mode 100644 src/observer/table_load/ob_table_load_bucket.h create mode 100644 src/observer/table_load/ob_table_load_commit_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_commit_processor.h create mode 100644 src/observer/table_load/ob_table_load_coordinator.cpp create mode 100644 src/observer/table_load/ob_table_load_coordinator.h create mode 100644 src/observer/table_load/ob_table_load_coordinator_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_coordinator_ctx.h create mode 100644 src/observer/table_load/ob_table_load_coordinator_trans.cpp create mode 100644 src/observer/table_load/ob_table_load_coordinator_trans.h create mode 100644 src/observer/table_load/ob_table_load_csv_parser.cpp create mode 100644 src/observer/table_load/ob_table_load_csv_parser.h create mode 100644 src/observer/table_load/ob_table_load_error_row_handler.cpp create mode 100644 src/observer/table_load/ob_table_load_error_row_handler.h create mode 100644 src/observer/table_load/ob_table_load_exec_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_exec_ctx.h create mode 100644 src/observer/table_load/ob_table_load_finish_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_finish_processor.h create mode 100644 src/observer/table_load/ob_table_load_general_table_compactor.cpp create mode 100644 src/observer/table_load/ob_table_load_general_table_compactor.h create mode 100644 src/observer/table_load/ob_table_load_get_status_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_get_status_processor.h create mode 100644 src/observer/table_load/ob_table_load_instance.cpp create mode 100644 src/observer/table_load/ob_table_load_instance.h create mode 100644 src/observer/table_load/ob_table_load_manager.h create mode 100644 src/observer/table_load/ob_table_load_mem_compactor.cpp create mode 100644 src/observer/table_load/ob_table_load_mem_compactor.h create mode 100644 src/observer/table_load/ob_table_load_merger.cpp create mode 100644 src/observer/table_load/ob_table_load_merger.h create mode 100644 src/observer/table_load/ob_table_load_multiple_heap_table_compactor.cpp create mode 100644 src/observer/table_load/ob_table_load_multiple_heap_table_compactor.h create mode 100644 src/observer/table_load/ob_table_load_obj_cast.cpp create mode 100644 src/observer/table_load/ob_table_load_obj_cast.h create mode 100644 src/observer/table_load/ob_table_load_object_allocator.h create mode 100644 src/observer/table_load/ob_table_load_parallel_merge_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_parallel_merge_ctx.h create mode 100644 src/observer/table_load/ob_table_load_parallel_merge_table_compactor.cpp create mode 100644 src/observer/table_load/ob_table_load_parallel_merge_table_compactor.h create mode 100644 src/observer/table_load/ob_table_load_partition_calc.cpp create mode 100644 src/observer/table_load/ob_table_load_partition_calc.h create mode 100644 src/observer/table_load/ob_table_load_partition_location.cpp create mode 100644 src/observer/table_load/ob_table_load_partition_location.h create mode 100644 src/observer/table_load/ob_table_load_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_processor.h create mode 100644 src/observer/table_load/ob_table_load_queue.h create mode 100644 src/observer/table_load/ob_table_load_redef_table.cpp create mode 100644 src/observer/table_load/ob_table_load_redef_table.h create mode 100644 src/observer/table_load/ob_table_load_schema.cpp create mode 100644 src/observer/table_load/ob_table_load_schema.h create mode 100644 src/observer/table_load/ob_table_load_service.cpp create mode 100644 src/observer/table_load/ob_table_load_service.h create mode 100644 src/observer/table_load/ob_table_load_stat.h create mode 100644 src/observer/table_load/ob_table_load_store.cpp create mode 100644 src/observer/table_load/ob_table_load_store.h create mode 100644 src/observer/table_load/ob_table_load_store_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_store_ctx.h create mode 100644 src/observer/table_load/ob_table_load_store_trans.cpp create mode 100644 src/observer/table_load/ob_table_load_store_trans.h create mode 100644 src/observer/table_load/ob_table_load_struct.h create mode 100644 src/observer/table_load/ob_table_load_table_compactor.cpp create mode 100644 src/observer/table_load/ob_table_load_table_compactor.h create mode 100644 src/observer/table_load/ob_table_load_table_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_table_ctx.h create mode 100644 src/observer/table_load/ob_table_load_task.cpp create mode 100644 src/observer/table_load/ob_table_load_task.h create mode 100644 src/observer/table_load/ob_table_load_task_scheduler.cpp create mode 100644 src/observer/table_load/ob_table_load_task_scheduler.h create mode 100644 src/observer/table_load/ob_table_load_time_convert.cpp create mode 100644 src/observer/table_load/ob_table_load_time_convert.h create mode 100644 src/observer/table_load/ob_table_load_trans_bucket_writer.cpp create mode 100644 src/observer/table_load/ob_table_load_trans_bucket_writer.h create mode 100644 src/observer/table_load/ob_table_load_trans_ctx.cpp create mode 100644 src/observer/table_load/ob_table_load_trans_ctx.h create mode 100644 src/observer/table_load/ob_table_load_trans_processor.cpp create mode 100644 src/observer/table_load/ob_table_load_trans_processor.h create mode 100644 src/observer/table_load/ob_table_load_trans_store.cpp create mode 100644 src/observer/table_load/ob_table_load_trans_store.h create mode 100644 src/observer/table_load/ob_table_load_utils.cpp create mode 100644 src/observer/table_load/ob_table_load_utils.h create mode 100644 src/share/table/ob_table_load_array.h create mode 100644 src/share/table/ob_table_load_define.cpp create mode 100644 src/share/table/ob_table_load_define.h create mode 100644 src/share/table/ob_table_load_handle.h create mode 100644 src/share/table/ob_table_load_row.cpp create mode 100644 src/share/table/ob_table_load_row.h create mode 100644 src/share/table/ob_table_load_row_array.h create mode 100644 src/share/table/ob_table_load_rpc_struct.cpp create mode 100644 src/share/table/ob_table_load_rpc_struct.h create mode 100644 src/share/table/ob_table_load_shared_allocator.cpp create mode 100644 src/share/table/ob_table_load_shared_allocator.h create mode 100644 src/sql/engine/cmd/ob_load_data_direct_impl.cpp create mode 100644 src/sql/engine/cmd/ob_load_data_direct_impl.h create mode 100644 src/sql/engine/cmd/ob_table_direct_insert_ctx.cpp create mode 100644 src/sql/engine/cmd/ob_table_direct_insert_ctx.h create mode 100644 src/sql/engine/cmd/ob_table_direct_insert_trans.cpp create mode 100644 src/sql/engine/cmd/ob_table_direct_insert_trans.h create mode 100644 src/storage/ddl/ob_ddl_heart_beat_task.cpp create mode 100644 src/storage/ddl/ob_ddl_heart_beat_task.h create mode 100644 src/storage/ddl/ob_ddl_server_client.cpp create mode 100644 src/storage/ddl/ob_ddl_server_client.h create mode 100644 src/storage/direct_load/ob_direct_load_compare.cpp create mode 100644 src/storage/direct_load/ob_direct_load_compare.h create mode 100644 src/storage/direct_load/ob_direct_load_data_block.cpp create mode 100644 src/storage/direct_load/ob_direct_load_data_block.h create mode 100644 src/storage/direct_load/ob_direct_load_data_block_decoder.h create mode 100644 src/storage/direct_load/ob_direct_load_data_block_encoder.h create mode 100644 src/storage/direct_load/ob_direct_load_data_block_reader.h create mode 100644 src/storage/direct_load/ob_direct_load_data_block_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_data_fuse.cpp create mode 100644 src/storage/direct_load/ob_direct_load_data_fuse.h create mode 100644 src/storage/direct_load/ob_direct_load_datum.cpp create mode 100644 src/storage/direct_load/ob_direct_load_datum.h create mode 100644 src/storage/direct_load/ob_direct_load_easy_queue.h create mode 100644 src/storage/direct_load/ob_direct_load_external_block_reader.h create mode 100644 src/storage/direct_load/ob_direct_load_external_block_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_external_fragment.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_fragment.h create mode 100644 src/storage/direct_load/ob_direct_load_external_fragment_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_external_interface.h create mode 100644 src/storage/direct_load/ob_direct_load_external_merger.h create mode 100644 src/storage/direct_load/ob_direct_load_external_multi_partition_row.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_multi_partition_row.h create mode 100644 src/storage/direct_load/ob_direct_load_external_multi_partition_table.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_multi_partition_table.h create mode 100644 src/storage/direct_load/ob_direct_load_external_row.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_row.h create mode 100644 src/storage/direct_load/ob_direct_load_external_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_external_table.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_table.h create mode 100644 src/storage/direct_load/ob_direct_load_external_table_builder.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_table_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_external_table_compactor.cpp create mode 100644 src/storage/direct_load/ob_direct_load_external_table_compactor.h create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table.cpp create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table.h create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table_builder.cpp create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.cpp create mode 100644 src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.h create mode 100644 src/storage/direct_load/ob_direct_load_i_table.h create mode 100644 src/storage/direct_load/ob_direct_load_insert_table_ctx.cpp create mode 100644 src/storage/direct_load/ob_direct_load_insert_table_ctx.h create mode 100644 src/storage/direct_load/ob_direct_load_io_callback.cpp create mode 100644 src/storage/direct_load/ob_direct_load_io_callback.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_chunk.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_context.cpp create mode 100644 src/storage/direct_load/ob_direct_load_mem_context.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_define.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_dump.cpp create mode 100644 src/storage/direct_load/ob_direct_load_mem_dump.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_loader.cpp create mode 100644 src/storage/direct_load/ob_direct_load_mem_loader.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_sample.cpp create mode 100644 src/storage/direct_load/ob_direct_load_mem_sample.h create mode 100644 src/storage/direct_load/ob_direct_load_mem_worker.h create mode 100644 src/storage/direct_load/ob_direct_load_memory_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_merge_ctx.cpp create mode 100644 src/storage/direct_load/ob_direct_load_merge_ctx.h create mode 100644 src/storage/direct_load/ob_direct_load_merge_task_iterator.cpp create mode 100644 src/storage/direct_load/ob_direct_load_merge_task_iterator.h create mode 100644 src/storage/direct_load/ob_direct_load_multi_map.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_range.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_range.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_row.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_row.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_external_row.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_external_row.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_iterator.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_map.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_map.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_builder.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_origin_table.cpp create mode 100644 src/storage/direct_load/ob_direct_load_origin_table.h create mode 100644 src/storage/direct_load/ob_direct_load_partition_merge_task.cpp create mode 100644 src/storage/direct_load/ob_direct_load_partition_merge_task.h create mode 100644 src/storage/direct_load/ob_direct_load_range_splitter.cpp create mode 100644 src/storage/direct_load/ob_direct_load_range_splitter.h create mode 100644 src/storage/direct_load/ob_direct_load_rowkey_iterator.cpp create mode 100644 src/storage/direct_load/ob_direct_load_rowkey_iterator.h create mode 100644 src/storage/direct_load/ob_direct_load_rowkey_merger.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_builder.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_builder.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_compactor.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_compactor.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_data_block.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_data_block.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_data_block_reader.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_data_block_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block_iterator.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block_reader.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block_reader.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block_writer.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_block_writer.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_index_entry_iterator.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scan_merge.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scan_merge.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scanner.cpp create mode 100644 src/storage/direct_load/ob_direct_load_sstable_scanner.h create mode 100644 src/storage/direct_load/ob_direct_load_table_builder_allocator.h create mode 100644 src/storage/direct_load/ob_direct_load_table_data_desc.cpp create mode 100644 src/storage/direct_load/ob_direct_load_table_data_desc.h create mode 100644 src/storage/direct_load/ob_direct_load_table_store.cpp create mode 100644 src/storage/direct_load/ob_direct_load_table_store.h create mode 100644 src/storage/direct_load/ob_direct_load_tmp_file.cpp create mode 100644 src/storage/direct_load/ob_direct_load_tmp_file.h create mode 100644 unittest/storage/direct_load/CMakeLists.txt create mode 100644 unittest/storage/direct_load/test_direct_load_data_block_writer.cpp create mode 100644 unittest/storage/direct_load/test_direct_load_index_block_writer.cpp diff --git a/.gitignore b/.gitignore index 666073df25..a9f1a82a74 100644 --- a/.gitignore +++ b/.gitignore @@ -190,6 +190,7 @@ tools/deploy/lib tools/deploy/lib/ tools/deploy/list tools/deploy/log/ +tools/deploy/usr/ tools/deploy/mysql_test/java/mytest.jar tools/deploy/mysql_test/r/*.reject tools/deploy/mysql_test/r/*.reject diff --git a/deps/oblib/src/lib/allocator/ob_malloc.h b/deps/oblib/src/lib/allocator/ob_malloc.h index 28a0d55367..329ce3982f 100644 --- a/deps/oblib/src/lib/allocator/ob_malloc.h +++ b/deps/oblib/src/lib/allocator/ob_malloc.h @@ -260,7 +260,7 @@ extern "C" void ob_zfree(void *ptr); ({ \ T* ret = NULL; \ if (OB_NOT_NULL(pool)) { \ - void *buf = pool->alloc(sizeof(T)); \ + void *buf = (pool)->alloc(sizeof(T)); \ if (OB_NOT_NULL(buf)) \ { \ ret = new(buf) T(__VA_ARGS__); \ diff --git a/deps/oblib/src/lib/queue/ob_fixed_queue.h b/deps/oblib/src/lib/queue/ob_fixed_queue.h index 99e7f0ce69..9cacb4031e 100644 --- a/deps/oblib/src/lib/queue/ob_fixed_queue.h +++ b/deps/oblib/src/lib/queue/ob_fixed_queue.h @@ -33,6 +33,9 @@ public: int init(const int64_t max_num, ObIAllocator *allocator = global_default_allocator, const lib::ObLabel &label = ObModIds::OB_FIXED_QUEUE); + int init(const int64_t max_num, + ObIAllocator *allocator, + const lib::ObMemAttr &attr); void destroy(); public: int push(T *ptr); @@ -81,9 +84,15 @@ ObFixedQueue::~ObFixedQueue() template int ObFixedQueue::init(const int64_t max_num, ObIAllocator *allocator, const lib::ObLabel &label) { - int ret = common::OB_SUCCESS; lib::ObMemAttr attr; attr.label_ = label; + return init(max_num, allocator, attr); +} + +template +int ObFixedQueue::init(const int64_t max_num, ObIAllocator *allocator, const lib::ObMemAttr &attr) +{ + int ret = common::OB_SUCCESS; if (NULL == allocator || 0 >= max_num) { ret = common::OB_INVALID_ARGUMENT; } else if (is_inited_) { diff --git a/deps/oblib/src/lib/queue/ob_lighty_queue.cpp b/deps/oblib/src/lib/queue/ob_lighty_queue.cpp index 3c8ffcc339..6261b3792c 100644 --- a/deps/oblib/src/lib/queue/ob_lighty_queue.cpp +++ b/deps/oblib/src/lib/queue/ob_lighty_queue.cpp @@ -22,7 +22,7 @@ namespace oceanbase { namespace common { -void ObLightyQueue::ObLightyCond::signal() +void ObLightyCond::signal() { (void)ATOMIC_FAA(&futex_.uval(), 1); if (ATOMIC_LOAD(&n_waiters_) > 0) { @@ -30,7 +30,7 @@ void ObLightyQueue::ObLightyCond::signal() } } -void ObLightyQueue::ObLightyCond::wait(const uint32_t cmp, const int64_t timeout) +void ObLightyCond::wait(const uint32_t cmp, const int64_t timeout) { if (timeout > 0) { (void)ATOMIC_FAA(&n_waiters_, 1); @@ -188,5 +188,96 @@ void ObLightyQueue::store(uint64_t seq, void* p) } } +static int64_t get_us() { return ::oceanbase::common::ObTimeUtility::current_time(); } + +int LightyQueue::init(const uint64_t capacity, const lib::ObLabel &label, const uint64_t tenant_id) +{ + ObMemAttr attr(tenant_id, label); + return queue_.init(capacity, global_default_allocator, attr); +} + +int LightyQueue::push(void *data, const int64_t timeout) +{ + int ret = OB_SUCCESS; + int64_t abs_timeout = (timeout > 0 ? (get_us() + timeout) : 0); + int64_t wait_timeout = 0; + while (true) { // WHITESCAN: OB_CUSTOM_ERROR_COVERED + uint32_t seq = cond_.get_seq(); + if (OB_SUCCESS == (ret = queue_.push(data))) { + break; + } else if (timeout <= 0 || (wait_timeout = abs_timeout - get_us()) <= 0) { + ret = OB_TIMEOUT; + break; + } else { + cond_.wait(seq, wait_timeout); + } + } + if (OB_SUCCESS == ret) { + cond_.signal(); + } + return ret; +} + +int LightyQueue::pop(void *&data, const int64_t timeout) +{ + int ret = OB_SUCCESS; + int64_t abs_timeout = (timeout > 0 ? (get_us() + timeout) : 0); + int64_t wait_timeout = 0; + while (true) { // WHITESCAN: OB_CUSTOM_ERROR_COVERED + uint32_t seq = cond_.get_seq(); + if (OB_SUCCESS == (ret = queue_.pop(data))) { + break; + } else if (timeout <= 0 || (wait_timeout = abs_timeout - get_us()) <= 0) { + break; + } else { + cond_.wait(seq, wait_timeout); + } + } + if (OB_SUCCESS == ret) { + cond_.signal(); + } + return ret; +} + +int LightyQueue::multi_pop(void **data, const int64_t data_count, int64_t &avail_count, + const int64_t timeout) +{ + int ret = OB_SUCCESS; + avail_count = 0; + if (data_count > 0) { + void *curr_data = NULL; + int64_t abs_timeout = (timeout > 0 ? (get_us() + timeout) : 0); + int64_t wait_timeout = 0; + while (true) { // WHITESCAN: OB_CUSTOM_ERROR_COVERED + uint32_t seq = cond_.get_seq(); + if (OB_SUCCESS == (ret = queue_.pop(curr_data))) { + data[avail_count++] = curr_data; + curr_data = NULL; + cond_.signal(); + if (avail_count >= data_count) { + //finish then break + break; + } + } else if (avail_count > 0) { + //not finish, but has already got one, break + ret = OB_SUCCESS; + break; + } else if (timeout <= 0 || (wait_timeout = abs_timeout - get_us()) <= 0) { + break; + } else { + cond_.wait(seq, wait_timeout); + } + } + } + return ret; +} + +void LightyQueue::reset() +{ + void *p = NULL; + while (0 == pop(p, 0)) + ; +} + }; // end namespace common }; // end namespace oceanbase diff --git a/deps/oblib/src/lib/queue/ob_lighty_queue.h b/deps/oblib/src/lib/queue/ob_lighty_queue.h index f3d8ff2abc..c4fcce3730 100644 --- a/deps/oblib/src/lib/queue/ob_lighty_queue.h +++ b/deps/oblib/src/lib/queue/ob_lighty_queue.h @@ -19,28 +19,30 @@ #include "lib/alloc/alloc_struct.h" #include "lib/allocator/ob_mod_define.h" #include "lib/lock/ob_futex.h" +#include "lib/queue/ob_fixed_queue.h" namespace oceanbase { namespace common { +struct ObLightyCond +{ +public: + ObLightyCond(): n_waiters_(0) {} + ~ObLightyCond() {} + + void signal(); + uint32_t get_seq() { return ATOMIC_LOAD(&futex_.uval()); } + void wait(const uint32_t cmp, const int64_t timeout); +private: + lib::ObFutex futex_; + uint32_t n_waiters_; +private: + DISALLOW_COPY_AND_ASSIGN(ObLightyCond); +}; + class ObLightyQueue { - struct ObLightyCond - { - public: - ObLightyCond(): n_waiters_(0) {} - ~ObLightyCond() {} - - void signal(); - uint32_t get_seq() { return ATOMIC_LOAD(&futex_.uval()); } - void wait(const uint32_t cmp, const int64_t timeout); - private: - lib::ObFutex futex_; - uint32_t n_waiters_; - private: - DISALLOW_COPY_AND_ASSIGN(ObLightyCond); - }; public: typedef ObLightyCond Cond; ObLightyQueue(): capacity_(0), n_cond_(0), data_(NULL), cond_(NULL), push_(0), pop_(0) {} @@ -80,6 +82,32 @@ private: uint64_t pop_ CACHE_ALIGNED; }; +class LightyQueue +{ +public: + typedef ObLightyCond Cond; + LightyQueue() {} + ~LightyQueue() { destroy(); } +public: + int init(const uint64_t capacity, + const lib::ObLabel &label = ObModIds::OB_LIGHTY_QUEUE, + const uint64_t tenant_id = common::OB_SERVER_TENANT_ID); + void destroy() { queue_.destroy(); } + void reset(); + int64_t size() const { return queue_.get_total(); } + int64_t curr_size() const { return queue_.get_total(); } + int64_t max_size() const { return queue_.capacity(); } + bool is_inited() const { return queue_.is_inited(); } + int push(void *data, const int64_t timeout = 0); + int pop(void *&data, const int64_t timeout = 0); + int multi_pop(void **data, const int64_t data_count, int64_t &avail_count, const int64_t timeout = 0); +private: + typedef ObFixedQueue Queue; + Queue queue_; + Cond cond_; +private: + DISALLOW_COPY_AND_ASSIGN(LightyQueue); +}; }; // end namespace common }; // end namespace oceanbase diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h b/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h index e609b6d8e3..51d449ace3 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_packet_list.h @@ -158,6 +158,12 @@ PCODE_DEF(OB_ADD_SYSVAR, 0x234) PCODE_DEF(OB_MODIFY_SYSVAR, 0x235) PCODE_DEF(OB_FLASHBACK_INDEX, 0x236) PCODE_DEF(OB_PURGE_INDEX, 0x237) +PCODE_DEF(OB_START_REDEF_TABLE, 0x238) +PCODE_DEF(OB_COPY_TABLE_DEPENDENTS, 0x239) +PCODE_DEF(OB_FINISH_REDEF_TABLE, 0x23A) +PCODE_DEF(OB_ABORT_REDEF_TABLE, 0x23B) +PCODE_DEF(OB_UPDATE_DDL_TASK_ACTIVE_TIME, 0x23C) +PCODE_DEF(OB_CREATE_HIDDEN_TABLE, 0x23D) //PCODE_DEF(OB_CHECK_UNIQUE_INDEX_REQUEST, 0x238) // 4.0 not supported //PCODE_DEF(OB_CHECK_UNIQUE_INDEX_RESPONSE, 0x239) // 4.0 not supported //PCODE_DEF(OB_CHECK_SINGLE_REPLICA_MAJOR_SSTABLE_EXIST, 0x23A) // 4.0 not supported diff --git a/src/objit/include/objit/common/ob_item_type.h b/src/objit/include/objit/common/ob_item_type.h index 74c1d6ab55..0d76f6be7d 100755 --- a/src/objit/include/objit/common/ob_item_type.h +++ b/src/objit/include/objit/common/ob_item_type.h @@ -1990,6 +1990,7 @@ typedef enum ObItemType T_RESTORE_TENANT_2, T_GEN_ROWS, T_LOAD_BATCH_SIZE, + T_DIRECT, // direct load data T_REMOTE_OSS, T_PHYSICAL_RESTORE_TENANT, T_REVOKE_SYSAUTH, diff --git a/src/observer/CMakeLists.txt b/src/observer/CMakeLists.txt index 43619d3dae..b970e46fb6 100644 --- a/src/observer/CMakeLists.txt +++ b/src/observer/CMakeLists.txt @@ -150,6 +150,49 @@ ob_set_subtarget(ob_server table table/ob_table_op_wrapper.cpp ) +ob_set_subtarget(ob_server table_load + table_load/ob_table_load_abort_processor.cpp + table_load/ob_table_load_autoinc_nextval.cpp + table_load/ob_table_load_begin_processor.cpp + table_load/ob_table_load_bucket.cpp + table_load/ob_table_load_commit_processor.cpp + table_load/ob_table_load_coordinator_ctx.cpp + table_load/ob_table_load_coordinator_trans.cpp + table_load/ob_table_load_coordinator.cpp + table_load/ob_table_load_csv_parser.cpp + table_load/ob_table_load_error_row_handler.cpp + table_load/ob_table_load_finish_processor.cpp + table_load/ob_table_load_general_table_compactor.cpp + table_load/ob_table_load_get_status_processor.cpp + table_load/ob_table_load_merger.cpp + table_load/ob_table_load_obj_cast.cpp + table_load/ob_table_load_parallel_merge_ctx.cpp + table_load/ob_table_load_parallel_merge_table_compactor.cpp + table_load/ob_table_load_partition_calc.cpp + table_load/ob_table_load_partition_location.cpp + table_load/ob_table_load_processor.cpp + table_load/ob_table_load_schema.cpp + table_load/ob_table_load_service.cpp + table_load/ob_table_load_store_ctx.cpp + table_load/ob_table_load_store_trans.cpp + table_load/ob_table_load_store.cpp + table_load/ob_table_load_table_compactor.cpp + table_load/ob_table_load_table_ctx.cpp + table_load/ob_table_load_task_scheduler.cpp + table_load/ob_table_load_task.cpp + table_load/ob_table_load_time_convert.cpp + table_load/ob_table_load_trans_bucket_writer.cpp + table_load/ob_table_load_trans_ctx.cpp + table_load/ob_table_load_trans_processor.cpp + table_load/ob_table_load_trans_store.cpp + table_load/ob_table_load_utils.cpp + table_load/ob_table_load_mem_compactor.cpp + table_load/ob_table_load_exec_ctx.cpp + table_load/ob_table_load_instance.cpp + table_load/ob_table_load_multiple_heap_table_compactor.cpp + table_load/ob_table_load_redef_table.cpp +) + ob_set_subtarget(ob_server virtual_table virtual_table/ob_agent_table_base.cpp virtual_table/ob_agent_virtual_table.cpp diff --git a/src/observer/ob_server.cpp b/src/observer/ob_server.cpp index 5dc25442f1..27eb0c71e8 100644 --- a/src/observer/ob_server.cpp +++ b/src/observer/ob_server.cpp @@ -99,6 +99,7 @@ #include "share/longops_mgr/ob_longops_mgr.h" #include "logservice/palf/election/interface/election.h" #include "storage/ddl/ob_ddl_redo_log_writer.h" +#include "observer/table_load/ob_table_load_partition_calc.h" using namespace oceanbase::lib; using namespace oceanbase::common; @@ -210,6 +211,8 @@ int ObServer::init(const ObServerOptions &opts, const ObPLogWriterCfg &log_cfg) LOG_ERROR("init retry ctrl failed", KR(ret)); } else if (OB_FAIL(ObTableApiProcessorBase::init_session())) { LOG_ERROR("init static session failed", KR(ret)); + } else if (OB_FAIL(ObTableLoadPartitionCalc::init_session())) { + LOG_ERROR("failed to init static session", KR(ret)); } else if (OB_FAIL(init_loaddata_global_stat())) { LOG_ERROR("init global load data stat map failed", KR(ret)); } else if (OB_FAIL(init_pre_setting())) { @@ -311,6 +314,10 @@ int ObServer::init(const ObServerOptions &opts, const ObPLogWriterCfg &log_cfg) LOG_ERROR("init multi tenant failed", KR(ret)); } else if (OB_FAIL(init_ctas_clean_up_task())) { LOG_ERROR("init ctas clean up task failed", KR(ret)); + } else if (OB_FAIL(init_ddl_heart_beat_task_container())) { + LOG_ERROR("init ddl heart beat task container failed", KR(ret)); + } else if (OB_FAIL(init_redef_heart_beat_task())) { + LOG_ERROR("init redef heart beat task failed", KR(ret)); } else if (OB_FAIL(init_refresh_active_time_task())) { LOG_ERROR("init refresh active time task failed", KR(ret)); } else if (OB_FAIL(init_refresh_network_speed_task())) { @@ -440,6 +447,10 @@ void ObServer::destroy() TG_DESTROY(lib::TGDefIDs::CTASCleanUpTimer); FLOG_INFO("ctas clean up timer destroyed"); + FLOG_INFO("begin to destroy redef heart beat task"); + TG_DESTROY(lib::TGDefIDs::RedefHeartBeatTask); + FLOG_INFO("redef heart beat task destroyed"); + FLOG_INFO("begin to destroy root service"); root_service_.destroy(); FLOG_INFO("root service destroyed"); @@ -958,6 +969,10 @@ int ObServer::stop() TG_STOP(lib::TGDefIDs::CTASCleanUpTimer); FLOG_INFO("ctas clean up timer stopped"); + FLOG_INFO("begin to stop ctas clean up timer"); + TG_STOP(lib::TGDefIDs::HeartBeatCheckTask); + FLOG_INFO("ctas clean up timer stopped"); + FLOG_INFO("begin to stop sql conn pool"); sql_conn_pool_.stop(); FLOG_INFO("sql connection pool stopped"); @@ -1710,6 +1725,8 @@ int ObServer::init_network() LOG_ERROR("get rpc proxy fail", KR(ret)); } else if (OB_FAIL(net_frame_.get_proxy(dbms_sched_job_rpc_proxy_))) { LOG_ERROR("get rpc proxy fail", KR(ret)); + } else if (OB_FAIL(net_frame_.get_proxy(table_rpc_proxy_))) { + LOG_ERROR("get rpc proxy fail", KR(ret)); } else if (OB_FAIL(batch_rpc_.init(net_frame_.get_batch_rpc_req_transport(), net_frame_.get_high_prio_req_transport(), self_addr_))) { @@ -2711,6 +2728,24 @@ int ObServer::init_ctas_clean_up_task() return ret; } +int ObServer::init_redef_heart_beat_task() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(redef_table_heart_beat_task_.init(lib::TGDefIDs::ServerGTimer))) { + LOG_ERROR("fail to init redef heart beat task", KR(ret)); + } + return ret; +} + +int ObServer::init_ddl_heart_beat_task_container() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.init())) { + LOG_ERROR("fail to init ddl heart beat task container", K(ret)); + } + return ret; +} + int ObServer::init_refresh_network_speed_task() { int ret = OB_SUCCESS; diff --git a/src/observer/ob_server.h b/src/observer/ob_server.h index d72aa930c2..f7dec8f01a 100644 --- a/src/observer/ob_server.h +++ b/src/observer/ob_server.h @@ -62,11 +62,14 @@ #include "share/ls/ob_ls_table_operator.h" // for ObLSTableOperator #include "storage/ob_locality_manager.h" #include "storage/ob_partition_component_factory.h" +#include "storage/ddl/ob_ddl_heart_beat_task.h" #include "storage/ob_disk_usage_reporter.h" #include "observer/dbms_scheduler/ob_dbms_sched_job_rpc_proxy.h" #include "logservice/ob_server_log_block_mgr.h" +#include "share/table/ob_table_rpc_proxy.h" + namespace oceanbase { namespace omt @@ -218,6 +221,8 @@ public: common::ObMySQLProxy &get_mysql_proxy() { return sql_proxy_; } int64_t get_start_time() const { return start_time_; } sql::ObConnectResourceMgr& get_conn_res_mgr() { return conn_res_mgr_; } + obrpc::ObTableRpcProxy &get_table_rpc_proxy() { return table_rpc_proxy_; } + share::ObLocationService &get_location_service() { return location_service_; } private: int stop(); @@ -262,10 +267,11 @@ private: int get_network_speed_from_sysfs(int64_t &network_speed); int get_network_speed_from_config_file(int64_t &network_speed); int refresh_network_speed(); - int clean_up_invalid_tables(); int clean_up_invalid_tables_by_tenant(const uint64_t tenant_id); int init_ctas_clean_up_task(); //Regularly clean up the residuals related to querying and building tables and temporary tables + int init_redef_heart_beat_task(); + int init_ddl_heart_beat_task_container(); int refresh_temp_table_sess_active_time(); int init_refresh_active_time_task(); //Regularly update the sess_active_time of the temporary table created by the proxy connection sess int init_refresh_network_speed_task(); @@ -315,6 +321,7 @@ private: obrpc::ObDBMSSchedJobRpcProxy dbms_sched_job_rpc_proxy_; obrpc::ObInterruptRpcProxy interrupt_proxy_; // global interrupt obrpc::ObLoadDataRpcProxy load_data_proxy_; + obrpc::ObTableRpcProxy table_rpc_proxy_; // The OceanBase configuration relating to. common::ObServerConfig &config_; @@ -393,6 +400,7 @@ private: ObTenantDutyTask duty_task_; ObTenantSqlMemoryTimerTask sql_mem_task_; ObCTASCleanUpTask ctas_clean_up_task_; // repeat & no retry + ObRedefTableHeartBeatTask redef_table_heart_beat_task_; ObRefreshTimeTask refresh_active_time_task_; // repeat & no retry ObRefreshNetworkSpeedTask refresh_network_speed_task_; // repeat & no retry ObCollectInfoGCTask collect_info_gc_task_; diff --git a/src/observer/ob_srv_xlator_partition.cpp b/src/observer/ob_srv_xlator_partition.cpp index 1bcf537aa3..f829f20468 100644 --- a/src/observer/ob_srv_xlator_partition.cpp +++ b/src/observer/ob_srv_xlator_partition.cpp @@ -51,6 +51,14 @@ #include "rootserver/freeze/ob_major_freeze_rpc_define.h" // ObTenantMajorFreezeP #include "storage/tx/ob_xa_rpc.h" +#include "observer/table_load/ob_table_load_abort_processor.h" +#include "observer/table_load/ob_table_load_begin_processor.h" +#include "observer/table_load/ob_table_load_commit_processor.h" +#include "observer/table_load/ob_table_load_finish_processor.h" +#include "observer/table_load/ob_table_load_get_status_processor.h" +#include "observer/table_load/ob_table_load_processor.h" +#include "observer/table_load/ob_table_load_trans_processor.h" + using namespace oceanbase; using namespace oceanbase::observer; using namespace oceanbase::lib; @@ -164,6 +172,33 @@ void oceanbase::observer::init_srv_xlator_for_others(ObSrvRpcXlator *xlator) { RPC_PROCESSOR(ObTableQueryAndMutateP, gctx_); RPC_PROCESSOR(ObTableQuerySyncP, gctx_); + // table load api + RPC_PROCESSOR(ObTableLoadBeginP, gctx_); + RPC_PROCESSOR(ObTableLoadFinishP, gctx_); + RPC_PROCESSOR(ObTableLoadCommitP, gctx_); + RPC_PROCESSOR(ObTableLoadAbortP, gctx_); + RPC_PROCESSOR(ObTableLoadGetStatusP, gctx_); + RPC_PROCESSOR(ObTableLoadP, gctx_); + RPC_PROCESSOR(ObTableLoadStartTransP, gctx_); + RPC_PROCESSOR(ObTableLoadFinishTransP, gctx_); + RPC_PROCESSOR(ObTableLoadAbandonTransP, gctx_); + RPC_PROCESSOR(ObTableLoadGetTransStatusP, gctx_); + + RPC_PROCESSOR(ObTableLoadPreBeginPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadConfirmBeginPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadPreMergePeerP, gctx_); + RPC_PROCESSOR(ObTableLoadStartMergePeerP, gctx_); + RPC_PROCESSOR(ObTableLoadCommitPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadAbortPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadGetStatusPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadPreStartTransPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadConfirmStartTransPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadPreFinishTransPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadConfirmFinishTransPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadAbandonTransPeerP, gctx_); + RPC_PROCESSOR(ObTableLoadGetTransStatusPeerP, gctx_); + // HA GTS RPC_PROCESSOR(ObHaGtsPingRequestP, gctx_); RPC_PROCESSOR(ObHaGtsGetRequestP, gctx_); diff --git a/src/observer/ob_srv_xlator_rootserver.cpp b/src/observer/ob_srv_xlator_rootserver.cpp index 722e9317d2..2895a9ad5c 100644 --- a/src/observer/ob_srv_xlator_rootserver.cpp +++ b/src/observer/ob_srv_xlator_rootserver.cpp @@ -96,6 +96,12 @@ void oceanbase::observer::init_srv_xlator_for_rootserver(ObSrvRpcXlator *xlator) RPC_PROCESSOR(rootserver::ObRpcDropTablegroupP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcAlterTablegroupP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcCreateTableP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcStartRedefTableP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcCopyTableDependentsP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcFinishRedefTableP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcAbortRedefTableP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcUpdateDDLTaskActiveTimeP, *gctx_.root_service_); + RPC_PROCESSOR(rootserver::ObRpcCreateHiddenTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcAlterTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcDropTableP, *gctx_.root_service_); RPC_PROCESSOR(rootserver::ObRpcRenameTableP, *gctx_.root_service_); diff --git a/src/observer/omt/ob_multi_tenant.cpp b/src/observer/omt/ob_multi_tenant.cpp index a0507ac987..1d00be3e4f 100644 --- a/src/observer/omt/ob_multi_tenant.cpp +++ b/src/observer/omt/ob_multi_tenant.cpp @@ -91,6 +91,7 @@ #include "storage/blocksstable/ob_shared_macro_block_manager.h" #include "storage/tx_storage/ob_tablet_gc_service.h" #include "share/ob_occam_time_guard.h" +#include "observer/table_load/ob_table_load_service.h" using namespace oceanbase; using namespace oceanbase::lib; @@ -324,6 +325,7 @@ int ObMultiTenant::init(ObAddr myaddr, //MTL_BIND(ObTransAuditRecordMgr::mtl_init, ObTransAuditRecordMgr::mtl_destroy); MTL_BIND(ObTenantSqlMemoryManager::mtl_init, ObTenantSqlMemoryManager::mtl_destroy); MTL_BIND(ObPlanMonitorNodeList::mtl_init, ObPlanMonitorNodeList::mtl_destroy); + MTL_BIND2(mtl_new_default, ObTableLoadService::mtl_init, mtl_start_default, mtl_stop_default, mtl_wait_default, mtl_destroy_default); MTL_BIND2(mtl_new_default, ObSharedMacroBlockMgr::mtl_init, mtl_start_default, mtl_stop_default, mtl_wait_default, mtl_destroy_default); MTL_BIND(ObFLTSpanMgr::mtl_init, ObFLTSpanMgr::mtl_destroy); MTL_BIND(ObSqlPlanMgr::mtl_init, ObSqlPlanMgr::mtl_destroy); diff --git a/src/observer/table/ob_table_rpc_processor.cpp b/src/observer/table/ob_table_rpc_processor.cpp index c24e73554c..192911a553 100644 --- a/src/observer/table/ob_table_rpc_processor.cpp +++ b/src/observer/table/ob_table_rpc_processor.cpp @@ -247,32 +247,37 @@ int ObTableApiProcessorBase::get_ls_id(const ObTabletID &tablet_id, ObLSID &ls_i return ret; } -int ObTableApiProcessorBase::check_user_access(const ObString &credential_str) +int ObTableApiUtils::check_user_access(const ObString &credential_str, const ObGlobalContext &gctx, ObTableApiCredential &credential) { int ret = OB_SUCCESS; int64_t pos = 0; ObTableApiSessGuard guard; const ObTableApiCredential *sess_credetial = nullptr; - if (OB_FAIL(serialization::decode(credential_str.ptr(), credential_str.length(), pos, credential_))) { + if (OB_FAIL(serialization::decode(credential_str.ptr(), credential_str.length(), pos, credential))) { LOG_WARN("failed to serialize credential", K(ret), K(pos)); - } else if (OB_FAIL(GCTX.table_service_->get_sess_mgr().get_sess_info(credential_.tenant_id_, - credential_.user_id_, + } else if (OB_FAIL(gctx.table_service_->get_sess_mgr().get_sess_info(credential.tenant_id_, + credential.user_id_, guard))) { - LOG_WARN("fail to get session info", K(ret), K_(credential)); + LOG_WARN("fail to get session info", K(ret), K(credential)); } else if (OB_FAIL(guard.get_credential(sess_credetial))) { LOG_WARN("fail to get credential", K(ret)); - } else if (sess_credetial->hash_val_ != credential_.hash_val_) { + } else if (sess_credetial->hash_val_ != credential.hash_val_) { ret = OB_ERR_NO_PRIVILEGE; - LOG_WARN("invalid credential", K(ret), K_(credential), K(*sess_credetial)); - } else if (sess_credetial->cluster_id_ != credential_.cluster_id_) { + LOG_WARN("invalid credential", K(ret), K(credential), K(*sess_credetial)); + } else if (sess_credetial->cluster_id_ != credential.cluster_id_) { ret = OB_ERR_NO_PRIVILEGE; - LOG_WARN("invalid credential cluster id", K(ret), K_(credential), K(*sess_credetial)); + LOG_WARN("invalid credential cluster id", K(ret), K(credential), K(*sess_credetial)); } else { - LOG_DEBUG("user can access", K(credential_)); + LOG_DEBUG("user can access", K(credential)); } return ret; } +int ObTableApiProcessorBase::check_user_access(const ObString &credential_str) +{ + return ObTableApiUtils::check_user_access(credential_str, gctx_, credential_); +} + oceanbase::sql::ObSQLSessionInfo &session() { static oceanbase::sql::ObSQLSessionInfo SESSION; @@ -956,4 +961,4 @@ bool oceanbase::observer::is_bad_routing_err(const int err) || is_has_no_readable_replica_err(err) || is_select_dup_follow_replic_err(err) || is_trans_stmt_need_retry_error(err)); -} \ No newline at end of file +} diff --git a/src/observer/table/ob_table_rpc_processor.h b/src/observer/table/ob_table_rpc_processor.h index 58e44bbe85..ae4234b6e8 100644 --- a/src/observer/table/ob_table_rpc_processor.h +++ b/src/observer/table/ob_table_rpc_processor.h @@ -79,6 +79,12 @@ public: int64_t max_local_retry_count_; }; +class ObTableApiUtils +{ +public: + static int check_user_access(const common::ObString &credential_str, const ObGlobalContext &gctx, table::ObTableApiCredential &credential); +}; + /* * Normally, the rpc process flow is: * 1. deserialize diff --git a/src/observer/table_load/ob_table_load_abort_processor.cpp b/src/observer/table_load/ob_table_load_abort_processor.cpp new file mode 100644 index 0000000000..a58ecd99b4 --- /dev/null +++ b/src/observer/table_load/ob_table_load_abort_processor.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_abort_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; + +/** + * ObTableLoadAbortP + */ + +int ObTableLoadAbortP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST == ret)) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } + } else { + if (OB_FAIL(ObTableLoadCoordinator::abort_ctx(table_ctx))) { + LOG_WARN("fail to abort coordinator ctx", KR(ret)); + } else if (OB_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(ret), K(key)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadAbortP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadAbortPeerP + */ + +int ObTableLoadAbortPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST == ret)) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } + } else { + if (OB_FAIL(ObTableLoadStore::abort_ctx(table_ctx))) { + LOG_WARN("fail to abort store ctx", KR(ret)); + } else if (OB_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(ret), K(key)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadAbortPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_abort_processor.h b/src/observer/table_load/ob_table_load_abort_processor.h new file mode 100644 index 0000000000..3daac5356a --- /dev/null +++ b/src/observer/table_load/ob_table_load_abort_processor.h @@ -0,0 +1,54 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadAbortP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadAbortP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadAbortP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadAbortP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadAbortPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadAbortPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadAbortPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadAbortPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_autoinc_nextval.cpp b/src/observer/table_load/ob_table_load_autoinc_nextval.cpp new file mode 100644 index 0000000000..2876d18893 --- /dev/null +++ b/src/observer/table_load/ob_table_load_autoinc_nextval.cpp @@ -0,0 +1,220 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_autoinc_nextval.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace sql; +using namespace share; +using namespace blocksstable; + +int ObTableLoadAutoincNextval::get_uint_value(ObStorageDatum &datum, + bool &is_zero, + uint64_t &casted_value, + const ObObjTypeClass &tc) +{ + int ret = OB_SUCCESS; + if (datum.is_null()) { + is_zero = true; + casted_value = 0; + } else { + switch (tc) { + case ObIntTC: { + is_zero = 0 == datum.get_int(); + casted_value = datum.get_int() < 0 ? 0 : datum.get_int(); + break; + } + case ObUIntTC: { + is_zero = 0 == datum.get_uint64(); + casted_value = datum.get_uint64(); + break; + } + case ObFloatTC: { + is_zero = 0 == datum.get_float(); + if (datum.get_float() > 0) { + casted_value = static_cast(datum.get_float() + 0.5); + } else { + casted_value = 0; + } + break; + } + case ObDoubleTC: { + is_zero = 0 == datum.get_double(); + if (datum.get_double() > 0) { + casted_value = static_cast(datum.get_double() + 0.5); + } else { + casted_value = 0; + } + break; + } + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("only int/float/double types support auto increment", KR(ret), K(datum)); + } + } + return ret; +} + +int ObTableLoadAutoincNextval::get_input_value(ObStorageDatum &datum, + AutoincParam &autoinc_param, + bool &is_to_generate, + uint64_t &casted_value, + const ObObjTypeClass &tc, + const uint64_t &sql_mode) +{ + int ret = OB_SUCCESS; + if (datum.is_null()) { + is_to_generate = true; + } else { + bool is_zero = false; + if (OB_FAIL(get_uint_value(datum, is_zero, casted_value, tc))) { + LOG_WARN("get casted unsigned int value failed", KR(ret)); + } + if (OB_SUCC(ret)) { + if (!(SMO_NO_AUTO_VALUE_ON_ZERO & sql_mode)) { + if (is_zero) { + is_to_generate = true; + } + } + } + } + // do not generate; sync value specified by user + if (OB_SUCC(ret)) { + if (!is_to_generate) { + if (casted_value > autoinc_param.value_to_sync_) { + autoinc_param.value_to_sync_ = casted_value; + autoinc_param.sync_flag_ = true; + } + } + } + return ret; +} + +int ObTableLoadAutoincNextval::generate_autoinc_value(ObAutoincrementService &auto_service, + AutoincParam *autoinc_param, + uint64_t &new_val) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(autoinc_param)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid arguments", KR(ret), K(autoinc_param)); + } else { + // sync insert value globally before sync value globally + if (OB_FAIL(auto_service.sync_insert_value_global(*autoinc_param))) { + LOG_WARN("failed to sync insert value globally", KR(ret)); + } + if (OB_SUCC(ret)) { + uint64_t value = 0; + CacheHandle *&cache_handle = autoinc_param->cache_handle_; + // get cache handle when allocate first auto-increment value + if (OB_ISNULL(cache_handle)) { + if (OB_FAIL(auto_service.get_handle(*autoinc_param, cache_handle))) { + LOG_WARN("failed to get auto_increment handle", KR(ret)); + } else if (OB_ISNULL(cache_handle)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Error unexpceted", KR(ret), K(cache_handle)); + } + } + + if (OB_SUCC(ret)) { + // get auto-increment value + if (OB_FAIL(cache_handle->next_value(value))) { + LOG_DEBUG("failed to get auto_increment value", KR(ret), K(value)); + // release handle No.1 + auto_service.release_handle(cache_handle); + // invalid cache handle; record count + ++autoinc_param->autoinc_intervals_count_; + if (OB_FAIL(auto_service.get_handle(*autoinc_param, cache_handle))) { + LOG_WARN("failed to get auto_increment handle", KR(ret)); + } else if (OB_FAIL(cache_handle->next_value(value))) { + LOG_WARN("failed to get auto_increment value", KR(ret)); + } + } + } + + if (OB_SUCC(ret)) { + new_val = value; + } + } + } + return ret; +} + +int ObTableLoadAutoincNextval::eval_nextval(AutoincParam *autoinc_param, + ObStorageDatum &datum, + const ObObjTypeClass &tc, + const uint64_t &sql_mode) +{ + int ret = OB_SUCCESS; + bool is_to_generate = false; + ObAutoincrementService &auto_service = ObAutoincrementService::get_instance(); + if (OB_ISNULL(autoinc_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Invalid arguments", KR(ret)); + } else { + // this column with column_index is auto-increment column + if (OB_ISNULL(autoinc_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("should find auto-increment param", KR(ret)); + } + // sync last user specified value first(compatible with MySQL) + if (OB_SUCC(ret)) { + if (OB_FAIL(auto_service.sync_insert_value_local(*autoinc_param))) { + LOG_WARN("failed to sync last insert value", KR(ret)); + } + } + uint64_t new_val = 0; + if (OB_SUCC(ret)) { + // check : to generate auto-increment value or not + if (OB_FAIL(get_input_value(datum, *autoinc_param, is_to_generate, new_val, tc, sql_mode))) { + LOG_WARN("check generation failed", KR(ret)); + } else if (is_to_generate && + OB_FAIL(generate_autoinc_value(auto_service, autoinc_param, new_val))) { + LOG_WARN("generate autoinc value failed", KR(ret)); + } + } + + if (OB_SUCC(ret)) { + if (!is_to_generate) { + // do noting, keep the input datum + } else { + switch (tc) { + case ObIntTC: + case ObUIntTC: { + datum.set_uint(new_val); + break; + } + case ObFloatTC: { + datum.set_float(static_cast(new_val)); + break; + } + case ObDoubleTC: { + datum.set_double(static_cast(new_val)); + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("only int/float/double types support auto increment", KR(ret), K(datum)); + } + } + } + } + + if (OB_SUCC(ret)) { + if (autoinc_param->autoinc_desired_count_ > 0) { + --autoinc_param->autoinc_desired_count_; + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_autoinc_nextval.h b/src/observer/table_load/ob_table_load_autoinc_nextval.h new file mode 100644 index 0000000000..d3dcd4bf09 --- /dev/null +++ b/src/observer/table_load/ob_table_load_autoinc_nextval.h @@ -0,0 +1,34 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#pragma once + +#include "common/object/ob_object.h" +#include "share/ob_autoincrement_param.h" +#include "share/ob_autoincrement_service.h" +#include "sql/engine/expr/ob_expr_autoinc_nextval.h" +#include "storage/blocksstable/ob_datum_row.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadAutoincNextval +{ +public: + static int eval_nextval(share::AutoincParam *autoinc_param, blocksstable::ObStorageDatum &datum, + const common::ObObjTypeClass &tc, const uint64_t &sql_mode); + +private: + static int get_uint_value(blocksstable::ObStorageDatum &datum, bool &is_zero, + uint64_t &casted_value, const common::ObObjTypeClass &tc); + static int get_input_value(blocksstable::ObStorageDatum &datum, + share::AutoincParam &autoinc_param, bool &is_to_generate, + uint64_t &casted_value, const common::ObObjTypeClass &tc, + const uint64_t &sql_mode); + static int generate_autoinc_value(share::ObAutoincrementService &auto_service, + share::AutoincParam *autoinc_param, uint64_t &new_val); +}; +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_begin_processor.cpp b/src/observer/table_load/ob_table_load_begin_processor.cpp new file mode 100644 index 0000000000..8a1aa35773 --- /dev/null +++ b/src/observer/table_load/ob_table_load_begin_processor.cpp @@ -0,0 +1,274 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/omt/ob_multi_tenant.h" +#include "observer/omt/ob_tenant.h" +#include "observer/table_load/ob_table_load_begin_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_table_ctx.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; +using namespace sql; +using namespace omt; + +int ObTableLoadBeginP::process() +{ + int ret = OB_SUCCESS; + uint64_t table_id = OB_INVALID_ID; + ObTableLoadArray column_names; + int32_t session_count = 0; + + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret), K_(arg)); + } + + if (OB_SUCC(ret)) { + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(ObTableLoadSchema::get_table_schema(credential_.tenant_id_, + credential_.database_id_, arg_.table_name_, + schema_guard, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K_(arg)); + } else { + table_id = table_schema->get_table_id(); + if (OB_FAIL(ObTableLoadSchema::get_column_names(table_schema, allocator_, column_names))) { + LOG_WARN("fail to get column name", KR(ret), K_(arg)); + } else if (OB_UNLIKELY(column_names.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected empty column names", KR(ret), K_(arg)); + } else if (OB_FAIL(init_idx_array(table_schema))) { + LOG_WARN("failed to init idx array", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { + ObTenant *tenant = nullptr; + if (OB_FAIL(GCTX.omt_->get_tenant(credential_.tenant_id_, tenant))) { + LOG_WARN("fail to get tenant handle", KR(ret), K(credential_.tenant_id_)); + } else { + session_count = MIN(arg_.config_.session_count_, (int32_t)tenant->unit_max_cpu()); + } + } + + if (OB_SUCC(ret)) { + ObTableLoadTableCtx *table_ctx = nullptr; + bool is_new = false; + ObTableLoadParam param; + param.tenant_id_ = credential_.tenant_id_; + param.database_id_ = credential_.database_id_; + param.table_id_ = table_id; + param.batch_size_ = arg_.config_.batch_size_; + param.session_count_ = session_count; + param.max_error_row_count_ = arg_.config_.max_error_row_count_; + param.column_count_ = column_names.count(); + param.need_sort_ = arg_.config_.flag_.is_need_sort_; + param.px_mode_ = false; + param.online_opt_stat_gather_ = false; + param.dup_action_ = ObLoadDupActionType::LOAD_STOP_ON_DUP; + if (OB_FAIL(param.normalize())) { + LOG_WARN("fail to normalize param", KR(ret)); + } else if (arg_.config_.flag_.data_type_ >= static_cast(ObTableLoadDataType::MAX_DATA_TYPE)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("data type is error", KR(ret), K(arg_.config_.flag_.data_type_)); + } else { + param.data_type_ = static_cast(arg_.config_.flag_.data_type_); + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObTableLoadService::create_ctx(param, table_ctx, is_new))) { + LOG_WARN("fail to create table ctx", KR(ret), K(param)); + } else { + if (is_new) { // 新建的ctx需要初始化 + if (OB_FAIL(table_ctx->init_session_info(credential_.user_id_))) { + LOG_WARN("fail to init session info", KR(ret)); + } else if (OB_FAIL(ObTableLoadCoordinator::init_ctx(table_ctx, idx_array_, nullptr))) { + LOG_WARN("fail to coordinator init ctx", KR(ret)); + } + } else { // 已存在的ctx检查是否已初始化 + if (OB_UNLIKELY(!ObTableLoadCoordinator::is_ctx_inited(table_ctx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected uninited coordinator ctx", KR(ret)); + } + } + if (OB_FAIL(ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(tmp_ret)); + } + } + } + if (OB_SUCC(ret)) { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (is_new && OB_FAIL(coordinator.begin())) { // 新建的ctx需要begin + LOG_WARN("fail to coordinator begin", KR(ret)); + } else if (OB_FAIL(coordinator.get_status(result_.status_, result_.error_code_))) { + LOG_WARN("fail to coordinator get status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + + if (OB_SUCC(ret)) { + result_.table_id_ = table_id; + result_.column_names_ = column_names; + } + + return ret; +} + +int ObTableLoadBeginP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +int ObTableLoadBeginP::init_idx_array(const ObTableSchema *table_schema) +{ + int ret = OB_SUCCESS; + ObSEArray column_descs; + if (OB_FAIL(table_schema->get_column_ids(column_descs))) { + LOG_WARN("fail to get column ids", KR(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && (i < column_descs.count()); ++i) { + ObColDesc &col_desc = column_descs.at(i); + const ObColumnSchemaV2 *column_schema = table_schema->get_column_schema(col_desc.col_id_); + if (!column_schema->is_hidden()) { + int64_t idx = col_desc.col_id_ - OB_APP_MIN_COLUMN_ID; + if (OB_FAIL(idx_array_.push_back(idx))) { + LOG_WARN("failed to push back idx to array", K(ret), K(idx)); + } + } + } + } + + return ret; +} + +/** + * ObTableLoadPreBeginPeerP + */ +int ObTableLoadPreBeginPeerP::deserialize() +{ + arg_.partition_id_array_.set_allocator(allocator_); + arg_.target_partition_id_array_.set_allocator(allocator_); + return ParentType::deserialize(); +} + +int ObTableLoadPreBeginPeerP::process() +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret), K_(arg)); + } + + if (OB_SUCC(ret)) { + ObTableLoadTableCtx *table_ctx = nullptr; + bool is_new = false; + ObTableLoadParam param; + param.tenant_id_ = credential_.tenant_id_; + param.database_id_ = credential_.database_id_; + param.table_id_ = arg_.table_id_; + param.target_table_id_ = arg_.target_table_id_; + param.batch_size_ = arg_.config_.batch_size_; + param.session_count_ = arg_.config_.session_count_; + param.max_error_row_count_ = arg_.config_.max_error_row_count_; + param.column_count_ = arg_.column_count_; + param.need_sort_ = arg_.config_.flag_.is_need_sort_; + param.px_mode_ = arg_.px_mode_; + param.online_opt_stat_gather_ = arg_.online_opt_stat_gather_; + param.dup_action_ = arg_.dup_action_; + if (OB_FAIL(ObTableLoadService::create_ctx(param, table_ctx, is_new))) { + LOG_WARN("fail to create table ctx", KR(ret), K(param)); + } else if (OB_UNLIKELY(!is_new)) { // 数据节点不能重复begin + ret = OB_ENTRY_EXIST; + LOG_WARN("table ctx exists", KR(ret)); + } else { + if (OB_FAIL(ObTableLoadStore::init_ctx(table_ctx, arg_.ddl_task_id_, arg_.partition_id_array_, + arg_.target_partition_id_array_))) { + LOG_WARN("fail to store init ctx", KR(ret)); + } + if (OB_FAIL(ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(tmp_ret)); + } + } + } + if (OB_SUCC(ret)) { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_begin())) { + LOG_WARN("fail to store pre begin", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + + return ret; +} + +int ObTableLoadPreBeginPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadConfirmBeginPeerP + */ + +int ObTableLoadConfirmBeginPeerP::process() +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret), K_(arg)); + } + + if (OB_SUCC(ret)) { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_begin())) { + LOG_WARN("fail to store confirm begin", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + + return ret; +} + +int ObTableLoadConfirmBeginPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_begin_processor.h b/src/observer/table_load/ob_table_load_begin_processor.h new file mode 100644 index 0000000000..cc8877cabe --- /dev/null +++ b/src/observer/table_load/ob_table_load_begin_processor.h @@ -0,0 +1,78 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadBeginP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadBeginP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadBeginP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + int init_idx_array(const ObTableSchema *table_schema); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadBeginP); +private: + const ObGlobalContext &gctx_; + common::ObArenaAllocator allocator_; + table::ObTableApiCredential credential_; + common::ObArray idx_array_; +}; + +class ObTableLoadPreBeginPeerP : public obrpc::ObRpcProcessor > +{ + typedef obrpc::ObRpcProcessor > ParentType; +public: + explicit ObTableLoadPreBeginPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadPreBeginPeerP() = default; + +protected: + int deserialize() override; + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPreBeginPeerP); +private: + const ObGlobalContext &gctx_; + common::ObArenaAllocator allocator_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadConfirmBeginPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadConfirmBeginPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadConfirmBeginPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadConfirmBeginPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_bucket.cpp b/src/observer/table_load/ob_table_load_bucket.cpp new file mode 100644 index 0000000000..8c06108117 --- /dev/null +++ b/src/observer/table_load/ob_table_load_bucket.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_bucket.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_utils.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace table; + +int ObTableLoadBucket::init(const ObAddr &leader_addr) { + int ret = OB_SUCCESS; + if (is_inited_) { + ret = OB_INIT_TWICE; + LOG_WARN("init twice", KR(ret)); + } else if (!leader_addr.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid addr", KR(ret), K(leader_addr)); + } else { + leader_addr_ = leader_addr; + is_inited_ = true; + } + return ret; +} + +int ObTableLoadBucket::add_row(const ObTabletID &tablet_id, + const ObTableLoadObjRow &obj_row, + int64_t count, + int64_t batch_size, + bool &flag) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(bucket_add_row_time_us); + int ret = OB_SUCCESS; + ObTableLoadTabletObjRow tablet_obj_row; + tablet_obj_row.tablet_id_ = tablet_id; + tablet_obj_row.obj_row_ = obj_row; + flag = false; + if (OB_FAIL(row_array_.push_back(tablet_obj_row))) { + LOG_WARN("fail to add row", KR(ret)); + } + if (OB_SUCC(ret)) { + flag = (row_array_.count() >= batch_size); + } + return ret; +} + + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_bucket.h b/src/observer/table_load/ob_table_load_bucket.h new file mode 100644 index 0000000000..93a66c547e --- /dev/null +++ b/src/observer/table_load/ob_table_load_bucket.h @@ -0,0 +1,57 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "lib/net/ob_addr.h" +#include "share/table/ob_table_load_row_array.h" +#include "common/row/ob_row.h" + +namespace oceanbase +{ +namespace common +{ +class ObObj; +} // namespace common +namespace observer +{ + +class ObTableLoadBucket +{ +public: + ObTableLoadBucket() : is_inited_(false), sequence_no_(0) {} + + int add_row(const common::ObTabletID &tablet_id, + const table::ObTableLoadObjRow &obj_row, + int64_t count, + int64_t batch_size, + bool &flag); + + void reset() { + is_inited_ = false; + leader_addr_.reset(); + row_array_.reset(); + } + + void clear_data() { + row_array_.reset(); + } + + bool is_inited() const { + return is_inited_; + } + int init(const common::ObAddr &leader_addr); + + TO_STRING_KV(K_(leader_addr), K_(sequence_no)); + +public: + // data members + bool is_inited_; + common::ObAddr leader_addr_; + table::ObTableLoadTabletObjRowArray row_array_; + uint64_t sequence_no_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_commit_processor.cpp b/src/observer/table_load/ob_table_load_commit_processor.cpp new file mode 100644 index 0000000000..823f8082f1 --- /dev/null +++ b/src/observer/table_load/ob_table_load_commit_processor.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_commit_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; +using namespace sql; + +/** + * ObTableLoadCommitP + */ + +int ObTableLoadCommitP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObExecContext *exec_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.commit(*exec_ctx, result_.result_info_))) { + LOG_WARN("fail to coordinator commit", KR(ret)); + } else if (OB_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(ret), K(key)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadCommitP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadCommitPeerP + */ + +int ObTableLoadCommitPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.commit(result_.result_info_, result_.sql_statistics_))) { + LOG_WARN("fail to store commit", KR(ret)); + } else if (OB_FAIL(ObTableLoadService::remove_ctx(table_ctx))) { + LOG_WARN("fail to remove table ctx", KR(ret), K(key)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadCommitPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_commit_processor.h b/src/observer/table_load/ob_table_load_commit_processor.h new file mode 100644 index 0000000000..6b429169b7 --- /dev/null +++ b/src/observer/table_load/ob_table_load_commit_processor.h @@ -0,0 +1,54 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadCommitP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadCommitP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadCommitP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadCommitP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadCommitPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadCommitPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadCommitPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadCommitPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator.cpp b/src/observer/table_load/ob_table_load_coordinator.cpp new file mode 100644 index 0000000000..140e8abef0 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator.cpp @@ -0,0 +1,1517 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/ob_server.h" +#include "observer/table_load/ob_table_load_coordinator_ctx.h" +#include "observer/table_load/ob_table_load_coordinator_trans.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_bucket_writer.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "share/ob_share_util.h" +#include "share/table/ob_table_load_rpc_struct.h" +#include "share/stat/ob_incremental_stat_estimator.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace table; +using namespace share; +using namespace sql; + +#define TABLE_LOAD_RPC_CALL(name, addr, request, result) \ + if (OB_SUCC(ret)) { \ + ObTimeoutCtx ctx; \ + if (OB_FAIL(ObShareUtil::set_default_timeout_ctx(ctx, DEFAULT_TIMEOUT_US))) { \ + LOG_WARN("fail to set default timeout ctx", KR(ret)); \ + } else if (OB_FAIL(ObServer::get_instance() \ + .get_table_rpc_proxy() \ + .timeout(ctx.get_timeout()) \ + .by(MTL_ID()) \ + .to(addr) \ + .name(request, result))) { \ + LOG_WARN("fail to rpc call " #name, KR(ret), K(addr), K(request)); \ + } \ + } + +ObTableLoadCoordinator::ObTableLoadCoordinator(ObTableLoadTableCtx *ctx) + : ctx_(ctx), + param_(ctx->param_), + coordinator_ctx_(ctx->coordinator_ctx_), + is_inited_(false) +{ +} + +bool ObTableLoadCoordinator::is_ctx_inited(ObTableLoadTableCtx *ctx) +{ + bool ret = false; + if (OB_NOT_NULL(ctx) && OB_LIKELY(ctx->is_valid()) && nullptr != ctx->coordinator_ctx_ && + OB_LIKELY(ctx->coordinator_ctx_->is_valid())) { + ret = true; + } + return ret; +} + +int ObTableLoadCoordinator::init_ctx(ObTableLoadTableCtx *ctx, const ObIArray &idx_array, + sql::ObSQLSessionInfo *session_info) +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_ISNULL(ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid agrs", KR(ret)); + } else if (OB_FAIL(ObTableLoadSchema::get_table_schema(ctx->param_.tenant_id_, + ctx->param_.database_id_, ctx->schema_.table_name_, + schema_guard, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(ctx->param_.tenant_id_), + K(ctx->param_.database_id_), K(ctx->schema_.table_name_)); + } else if (OB_FAIL(ObTableLoadSchema::check_constraints(ctx->param_.tenant_id_, + schema_guard, table_schema))) { + LOG_WARN("fail to check schema constraints", KR(ret), K(ctx->param_.tenant_id_)); + } else if (OB_FAIL(ctx->init_coordinator_ctx(idx_array, session_info))) { + LOG_WARN("fail to init coordinator ctx", KR(ret)); + } + return ret; +} + +int ObTableLoadCoordinator::abort_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!ctx->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(ctx)); + } else if (OB_UNLIKELY(nullptr == ctx->coordinator_ctx_ || !ctx->coordinator_ctx_->is_valid())) { + // coordinator ctx not init, do nothing + } else { + LOG_INFO("coordinator abort"); + // 1. mark status abort, speed up background task exit + if (OB_FAIL(ctx->coordinator_ctx_->set_status_abort())) { + LOG_WARN("fail to set coordinator status abort", KR(ret)); + } + // 2. mark all active trans abort + else if (OB_FAIL(abort_active_trans(ctx))) { + LOG_WARN("fail to abort active trans", KR(ret)); + } + // 3. abort peers ctx + else if (OB_FAIL(abort_peers_ctx(ctx))) { + LOG_WARN("fail to abort peers ctx", KR(ret)); + } + // 4. abort ddl redef table, release table lock + else if (OB_FAIL(ctx->coordinator_ctx_->abort())) { + LOG_WARN("fail to abort coordinator ctx", KR(ret)); + } + } + return ret; +} + +int ObTableLoadCoordinator::abort_active_trans(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + ObArray trans_id_array; + if (OB_FAIL(ctx->coordinator_ctx_->get_active_trans_ids(trans_id_array))) { + LOG_WARN("fail to get active trans ids", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_id_array.count(); ++i) { + const ObTableLoadTransId &trans_id = trans_id_array.at(i); + ObTableLoadCoordinatorTrans *trans = nullptr; + if (OB_FAIL(ctx->coordinator_ctx_->get_trans(trans_id, trans))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans", KR(ret), K(trans_id)); + } else { + ret = OB_SUCCESS; + } + } else if (OB_FAIL(trans->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + ctx->coordinator_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadCoordinator::abort_peers_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(ctx->coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_abort_peer_request begin", K(all_addr_array.count())); + ObTableLoadAbortPeerRequest request; + ObTableLoadAbortPeerResult result; + request.credential_ = ctx->coordinator_ctx_->credential_; + request.table_id_ = ctx->param_.table_id_; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + if (OB_FAIL(ObTableLoadStore::abort_ctx(ctx))) { + LOG_WARN("fail to abort store ctx", KR(ret)); + } + } else { // 远端, 发送rpc + const int64_t origin_timeout_ts = THIS_WORKER.get_timeout_ts(); + THIS_WORKER.set_timeout_ts(INT64_MAX); // use default timeout value, avoid timeout now + TABLE_LOAD_RPC_CALL(load_abort_peer, addr, request, result); + THIS_WORKER.set_timeout_ts(origin_timeout_ts); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadCoordinator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!ctx_->is_valid()) || OB_ISNULL(coordinator_ctx_) || + OB_UNLIKELY(!coordinator_ctx_->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC_(ctx)); + } else if (THIS_WORKER.is_timeout_ts_valid() && OB_UNLIKELY(THIS_WORKER.is_timeout())) { + ret = OB_TIMEOUT; + LOG_WARN("worker timeouted", KR(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +/** + * begin + */ + +int ObTableLoadCoordinator::pre_begin_peers() +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_leader_info_array; + ObTableLoadArray target_all_leader_info_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader_info(all_leader_info_array))) { + LOG_WARN("fail to get all leader info", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->target_partition_location_.get_all_leader_info(target_all_leader_info_array))) { + LOG_WARN("fail to get all leader info", KR(ret)); + } else if (all_leader_info_array.count() != target_all_leader_info_array.count()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN( + "origin table leader count must be qual to target table leader count", + K(all_leader_info_array.count()), + K(target_all_leader_info_array.count()), KR(ret)); + } else { + LOG_INFO("route_pre_begin_peer_request begin", K(all_leader_info_array.count())); + ObTableLoadPreBeginPeerRequest request; + ObTableLoadPreBeginPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.target_table_id_ = param_.target_table_id_; + request.ddl_task_id_ = coordinator_ctx_->get_ddl_task_id(); + request.config_.session_count_ = param_.session_count_; + request.config_.max_error_row_count_ = param_.max_error_row_count_; + request.config_.batch_size_ = param_.batch_size_; + request.config_.flag_.is_need_sort_ = param_.need_sort_; + request.column_count_ = param_.column_count_; + request.dup_action_ = param_.dup_action_; + request.px_mode_ = param_.px_mode_; + request.online_opt_stat_gather_ = param_.online_opt_stat_gather_; + for (int64_t i = 0; OB_SUCC(ret) && i < all_leader_info_array.count(); ++i) { + const ObTableLoadPartitionLocation::LeaderInfo &leader_info = all_leader_info_array.at(i); + const ObTableLoadPartitionLocation::LeaderInfo &target_leader_info = target_all_leader_info_array.at(i); + //目前源表和目标表的分区信息连同每个分区的地址都完全一样 + const ObAddr &addr = leader_info.addr_; + if (OB_UNLIKELY(leader_info.addr_ != target_leader_info.addr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("addr must be same", K(leader_info.addr_), K(target_leader_info.addr_), KR(ret)); + } else { + request.partition_id_array_ = leader_info.partition_id_array_; + request.target_partition_id_array_ = target_leader_info.partition_id_array_; + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + if (OB_FAIL(ObTableLoadStore::init_ctx(ctx_, request.ddl_task_id_, request.partition_id_array_, + request.target_partition_id_array_))) { + LOG_WARN("fail to store init ctx", KR(ret)); + } else { + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_begin())) { + LOG_WARN("fail to store pre begin", KR(ret)); + } + } + } else { // 对端, 发送rpc + TABLE_LOAD_RPC_CALL(load_pre_begin_peer, addr, request, result); + } + } + } + } + return ret; +} + +int ObTableLoadCoordinator::confirm_begin_peers() +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_confirm_begin_peer_request begin", K(all_addr_array.count())); + ObTableLoadConfirmBeginPeerRequest request; + ObTableLoadConfirmBeginPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_begin())) { + LOG_WARN("fail to store confirm begin", KR(ret)); + } + } else { // 对端, 发送rpc + TABLE_LOAD_RPC_CALL(load_confirm_begin_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::begin() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator begin"); + if (OB_FAIL(pre_begin_peers())) { + LOG_WARN("fail to pre begin peers", KR(ret)); + } else if (OB_FAIL(confirm_begin_peers())) { + LOG_WARN("fail to confirm begin peers", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->set_status_loading())) { + LOG_WARN("fail to set coordinator status loading", KR(ret)); + } + } + return ret; +} + +/** + * finish + */ + +int ObTableLoadCoordinator::pre_merge_peers() +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_pre_merge_peer_request begin", K(all_addr_array.count())); + ObArenaAllocator allocator("TLD_Coord"); + ObTableLoadPreMergePeerRequest request; + ObTableLoadPreMergePeerResult result; + allocator.set_tenant_id(MTL_ID()); + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + if (!ctx_->param_.px_mode_) { + if (OB_FAIL(coordinator_ctx_->get_committed_trans_ids(request.committed_trans_id_array_, + allocator))) { + LOG_WARN("fail to get committed trans ids", KR(ret)); + } else { + std::sort(request.committed_trans_id_array_.begin(), request.committed_trans_id_array_.end()); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_merge(request.committed_trans_id_array_))) { + LOG_WARN("fail to store pre merge", KR(ret)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_pre_merge_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::start_merge_peers() +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_start_merge_peer_request begin", K(all_addr_array.count())); + ObTableLoadStartMergePeerRequest request; + ObTableLoadStartMergePeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.start_merge())) { + LOG_WARN("fail to store start merge", KR(ret)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_start_merge_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::finish() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator finish"); + bool active_trans_exist = false; + bool committed_trans_eixst = false; + // 1. 冻结状态, 防止后续继续创建trans + if (OB_FAIL(coordinator_ctx_->set_status_frozen())) { + LOG_WARN("fail to set coordinator status frozen", KR(ret)); + } + // 2. 检查当前是否还有trans没有结束 + else if (OB_FAIL(coordinator_ctx_->check_exist_trans(active_trans_exist))) { + LOG_WARN("fail to check exist trans", KR(ret)); + } else if (OB_UNLIKELY(active_trans_exist)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("trans already exist", KR(ret)); + } else if (!ctx_->param_.px_mode_) { + // 3. 检查是否有数据 + if (OB_FAIL(coordinator_ctx_->check_exist_committed_trans(committed_trans_eixst))) { + LOG_WARN("fail to check exist committed trans", KR(ret)); + } else if (OB_UNLIKELY(!committed_trans_eixst)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("segment is null", KR(ret)); + } + } + if (OB_SUCC(ret)) { + // 4. 触发数据节点发起合并 + if (OB_FAIL(pre_merge_peers())) { + LOG_WARN("fail to pre merge peers", KR(ret)); + } else if (OB_FAIL(start_merge_peers())) { + LOG_WARN("fail to start merge peers", KR(ret)); + } + // 5. 设置当前状态为合并中 + else if (OB_FAIL(coordinator_ctx_->set_status_merging())) { + LOG_WARN("fail to set coordinator status merging", KR(ret)); + } + // 6. 添加定时任务检查合并结果 + else if (OB_FAIL(add_check_merge_result_task())) { + LOG_WARN("fail to add check merge result task", KR(ret)); + } + } + } + return ret; +} + +/** + * check merge result + */ + +int ObTableLoadCoordinator::check_peers_merge_result(bool &is_finish) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_get_status_peer_request begin", K(all_addr_array.count())); + ObTableLoadGetStatusPeerRequest request; + ObTableLoadGetStatusPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + is_finish = true; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.get_status(result.status_, result.error_code_))) { + LOG_WARN("fail to store get status", KR(ret)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_get_status_peer, addr, request, result); + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(ObTableLoadStatusType::ERROR == result.status_)) { + ret = result.error_code_; + LOG_WARN("store has error", KR(ret), K(addr), K(result.status_)); + } else if (OB_UNLIKELY(ObTableLoadStatusType::MERGING != result.status_ && + ObTableLoadStatusType::MERGED != result.status_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected peer status", KR(ret), K(addr), K(result.status_)); + } else if (ObTableLoadStatusType::MERGED != result.status_) { + is_finish = false; + } + } + } + } + return ret; +} + +class ObTableLoadCoordinator::CheckMergeResultTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CheckMergeResultTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx) + : ObITableLoadTaskProcessor(task), ctx_(ctx) + { + ctx_->inc_ref_count(); + } + virtual ~CheckMergeResultTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + bool is_merge_finish = false; + ObTableLoadCoordinator coordinator(ctx_); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } + while (OB_SUCC(ret)) { + // 确认状态 + if (OB_FAIL(ctx_->coordinator_ctx_->check_status(ObTableLoadStatusType::MERGING))) { + LOG_WARN("fail to check coordinator status merging", KR(ret)); + } + // 查询合并状态 + else if (OB_FAIL(coordinator.check_peers_merge_result(is_merge_finish))) { + LOG_WARN("fail to check peers merge result", KR(ret)); + } else if (!is_merge_finish) { + usleep(WAIT_INTERVAL_US); // 等待1s后重试 + } else { + break; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ctx_->coordinator_ctx_->set_status_merged())) { + LOG_WARN("fail to set coordinator status merged", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; +}; + +class ObTableLoadCoordinator::CheckMergeResultTaskCallback : public ObITableLoadTaskCallback +{ +public: + CheckMergeResultTaskCallback(ObTableLoadTableCtx *ctx) + : ctx_(ctx) + { + ctx_->inc_ref_count(); + } + virtual ~CheckMergeResultTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + ctx_->coordinator_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; +}; + +int ObTableLoadCoordinator::add_check_merge_result_task() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_))) { + LOG_WARN("fail to set check merge result task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_))) { + LOG_WARN("fail to set check merge result task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(coordinator_ctx_->task_scheduler_->add_task(0, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + return ret; +} + +/** + * commit + */ + +int ObTableLoadCoordinator::commit_peers(ObTableLoadSqlStatistics &sql_statistics) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_commit_peer_request begin", K(all_addr_array.count())); + ObTableLoadCommitPeerRequest request; + ObTableLoadCommitPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.commit(result.result_info_, result.sql_statistics_))) { + LOG_WARN("fail to commit store", KR(ret)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_commit_peer, addr, request, result); + } + if (OB_SUCC(ret)) { + ATOMIC_AAF(&coordinator_ctx_->result_info_.rows_affected_, result.result_info_.rows_affected_); + ATOMIC_AAF(&coordinator_ctx_->result_info_.deleted_, result.result_info_.deleted_); + ATOMIC_AAF(&coordinator_ctx_->result_info_.skipped_, result.result_info_.skipped_); + ATOMIC_AAF(&coordinator_ctx_->result_info_.warnings_, result.result_info_.warnings_); + if (OB_FAIL(sql_statistics.add(result.sql_statistics_))) { + LOG_WARN("fail to add result sql stats", KR(ret), K(addr), K(result)); + } + } + } + } + return ret; +} + +int ObTableLoadCoordinator::commit(ObExecContext &ctx, ObTableLoadResultInfo &result_info) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator commit"); + ObTableLoadSqlStatistics sql_statistics; + if (OB_FAIL(coordinator_ctx_->check_status(ObTableLoadStatusType::MERGED))) { + LOG_WARN("fail to check coordinator status", KR(ret)); + } else if (OB_FAIL(commit_peers(sql_statistics))) { + LOG_WARN("fail to commit peers", KR(ret)); + } else if (param_.online_opt_stat_gather_ && OB_FAIL(drive_sql_stat(ctx, sql_statistics))) { + LOG_WARN("fail to drive sql stat", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->commit())) { + LOG_WARN("fail to commit coordinator", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->set_status_commit())) { + LOG_WARN("fail to set coordinator status commit", KR(ret)); + } else { + result_info = coordinator_ctx_->result_info_; + } + } + return ret; +} + +int ObTableLoadCoordinator::drive_sql_stat(ObExecContext &ctx, ObTableLoadSqlStatistics &sql_statistics) { + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + ObSchemaGetterGuard schema_guard; + ObSchemaGetterGuard *tmp_schema_guard = nullptr; + ObSchemaGetterGuard *tmp_schema_guard2 = nullptr; + const ObTableSchema *table_schema = nullptr; + if (sql_statistics.is_empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sql statistics is empty", K(ret)); + } else if (OB_FAIL(ObTableLoadSchema::get_table_schema(tenant_id, param_.target_table_id_, schema_guard, + table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(param_.target_table_id_), K(tenant_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret)); + } else { + tmp_schema_guard = ctx.get_virtual_table_ctx().schema_guard_; + tmp_schema_guard2 = ctx.get_das_ctx().get_schema_guard(); + ctx.get_sql_ctx()->schema_guard_ = &schema_guard; + ctx.get_das_ctx().get_schema_guard() = &schema_guard; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ObIncrementalStatEstimator::drive_global_stat_by_direct_load( + ctx, sql_statistics.table_stat_array_, sql_statistics.col_stat_array_))) { + LOG_WARN("fail to drive global stat by direct load", KR(ret)); + } + } + ctx.get_sql_ctx()->schema_guard_ = tmp_schema_guard; + ctx.get_das_ctx().get_schema_guard() = tmp_schema_guard2; + return ret; +} + +/** + * get status + */ + +int ObTableLoadCoordinator::get_status(ObTableLoadStatusType &status, int &error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator get status"); + status = coordinator_ctx_->get_status(); + error_code = coordinator_ctx_->get_error_code(); + } + return ret; +} + +/** + * start trans + */ + +int ObTableLoadCoordinator::pre_start_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_pre_start_trans_peer_request begin", K(all_addr_array.count())); + const ObTableLoadTransId &trans_id = trans->get_trans_id(); + ObTableLoadPreStartTransPeerRequest request; + ObTableLoadPreStartTransPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_start_trans(trans_id))) { + LOG_WARN("fail to store pre start trans", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_pre_start_trans_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::confirm_start_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_confirm_start_trans_peer_request begin", K(all_addr_array.count())); + const ObTableLoadTransId &trans_id = trans->get_trans_id(); + ObTableLoadConfirmStartTransPeerRequest request; + ObTableLoadConfirmStartTransPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_start_trans(trans_id))) { + LOG_WARN("fail to store confirm start trans", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_confirm_start_trans_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::start_trans(const ObTableLoadSegmentID &segment_id, + ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator start trans", K(segment_id)); + ObTableLoadTransCtx *trans_ctx = nullptr; + while (OB_SUCC(ret) && nullptr == trans_ctx) { + if (OB_FAIL(coordinator_ctx_->get_segment_trans_ctx(segment_id, trans_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment trans ctx", KR(ret), K(segment_id)); + } else { + ObTableLoadCoordinatorTrans *trans = nullptr; + if (OB_FAIL(coordinator_ctx_->start_trans(segment_id, trans))) { + if (OB_UNLIKELY(OB_ENTRY_EXIST != ret)) { + LOG_WARN("fail to create trans", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } + // 2. 同步到对端 + else if (OB_FAIL(pre_start_trans_peers(trans))) { + LOG_WARN("fail to pre start trans peers", KR(ret)); + } else if (OB_FAIL(confirm_start_trans_peers(trans))) { + LOG_WARN("fail to confirm start trans peers", KR(ret)); + } + // 3. 状态设置为running + else if (OB_FAIL(trans->set_trans_status_running())) { + LOG_WARN("fail to set trans status running", KR(ret)); + } else { + trans_ctx = trans->get_trans_ctx(); + } + if (OB_NOT_NULL(trans)) { + coordinator_ctx_->put_trans(trans); + trans = nullptr; + } + } + } + } + if (OB_SUCC(ret)) { + trans_id = trans_ctx->trans_id_; + } + } + return ret; +} + +/** + * finish trans + */ + +int ObTableLoadCoordinator::pre_finish_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_pre_finish_trans_peer_request begin", K(all_addr_array.count())); + const ObTableLoadTransId &trans_id = trans->get_trans_id(); + ObTableLoadPreFinishTransPeerRequest request; + ObTableLoadPreFinishTransPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_finish_trans(trans_id))) { + LOG_WARN("fail to store pre finish trans", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_pre_finish_trans_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::confirm_finish_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_pre_finish_trans_peer_request begin", K(all_addr_array.count())); + const ObTableLoadTransId &trans_id = trans->get_trans_id(); + ObTableLoadConfirmFinishTransPeerRequest request; + ObTableLoadConfirmFinishTransPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_finish_trans(trans_id))) { + LOG_WARN("fail to store confirm finish trans", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_confirm_finish_trans_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::finish_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator finish trans", K(trans_id)); + ObTableLoadCoordinatorTrans *trans = nullptr; + if (OB_FAIL(coordinator_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret), K(trans_id)); + } else if (OB_FAIL(trans->set_trans_status_frozen())) { + LOG_WARN("fail to freeze trans", KR(ret)); + } else if (OB_FAIL(flush(trans))) { + LOG_WARN("fail to flush", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + coordinator_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +/** + * check peers trans commit + */ + +int ObTableLoadCoordinator::check_peers_trans_commit(ObTableLoadCoordinatorTrans *trans, bool &is_commit) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_check_peers_trans_commit begin", K(all_addr_array.count())); + ObTableLoadGetTransStatusPeerRequest request; + ObTableLoadGetTransStatusPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans->get_trans_id(); + is_commit = true; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.get_trans_status(request.trans_id_, result.trans_status_, + result.error_code_))) { + LOG_WARN("fail to store get trans status", KR(ret)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_get_trans_status_peer, addr, request, result); + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(ObTableLoadTransStatusType::ERROR == result.trans_status_)) { + ret = result.error_code_; + LOG_WARN("trans has error", KR(ret), K(addr)); + } else if (OB_UNLIKELY(ObTableLoadTransStatusType::FROZEN != result.trans_status_ && + ObTableLoadTransStatusType::COMMIT != result.trans_status_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected peer trans status", KR(ret), K(addr), K(result.trans_status_)); + } else if (ObTableLoadTransStatusType::COMMIT != result.trans_status_) { + is_commit = false; + } + } + } + } + return ret; +} + +class ObTableLoadCoordinator::CheckPeersTransCommitTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CheckPeersTransCommitTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadCoordinatorTrans *trans) + : ObITableLoadTaskProcessor(task), ctx_(ctx), trans_(trans) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + } + virtual ~CheckPeersTransCommitTaskProcessor() + { + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + bool is_peers_commit = false; + ObTableLoadCoordinator coordinator(ctx_); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } + while (OB_SUCC(ret)) { + // 确认trans状态为frozen + if (OB_FAIL(trans_->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + LOG_WARN("fail to check trans status frozen", KR(ret)); + } + // 向对端发送pre finish + else if (OB_FAIL(coordinator.check_peers_trans_commit(trans_, is_peers_commit))) { + LOG_WARN("fail to check peers trans commit", KR(ret)); + } else if (!is_peers_commit) { + usleep(WAIT_INTERVAL_US); // 等待1s后重试 + } else { + break; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(coordinator.confirm_finish_trans_peers(trans_))) { + LOG_WARN("fail to confirm finish trans peers", KR(ret)); + } else if (OB_FAIL(coordinator.commit_trans(trans_))) { + LOG_WARN("fail to coordinator commit trans", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; +}; + +class ObTableLoadCoordinator::CheckPeersTransCommitTaskCallback : public ObITableLoadTaskCallback +{ +public: + CheckPeersTransCommitTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadCoordinatorTrans *trans) + : ctx_(ctx), trans_(trans) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + } + virtual ~CheckPeersTransCommitTaskCallback() + { + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + trans_->set_trans_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; +}; + +int ObTableLoadCoordinator::add_check_peers_trans_commit_task(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_, trans))) { + LOG_WARN("fail to set check peer trans commit task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_, trans))) { + LOG_WARN("fail to set check peer trans commit task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(coordinator_ctx_->task_scheduler_->add_task(0, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + return ret; +} + +int ObTableLoadCoordinator::finish_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator finish trans peers"); + if (OB_FAIL(pre_finish_trans_peers(trans))) { + LOG_WARN("fail to pre finish trans peers", KR(ret)); + } else if (OB_FAIL(add_check_peers_trans_commit_task(trans))) { + LOG_WARN("fail to add check peers trans commit task", KR(ret)); + } + } + return ret; +} + +int ObTableLoadCoordinator::commit_trans(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator commit trans"); + if (OB_FAIL(trans->set_trans_status_commit())) { + LOG_WARN("fail to set trans status commit", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->commit_trans(trans))) { + LOG_WARN("fail to commit trans", KR(ret)); + } + } + return ret; +} + +/** + * abandon trans + */ + +int ObTableLoadCoordinator::abandon_trans_peers(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + ObTableLoadArray all_addr_array; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_all_leader(all_addr_array))) { + LOG_WARN("fail to get all addr", KR(ret)); + } else { + LOG_INFO("route_abandon_trans_peer_request begin", K(all_addr_array.count())); + const ObTableLoadTransId &trans_id = trans->get_trans_id(); + ObTableLoadAbandonTransPeerRequest request; + ObTableLoadAbandonTransPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + for (int64_t i = 0; OB_SUCC(ret) && i < all_addr_array.count(); ++i) { + const ObAddr &addr = all_addr_array.at(i); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.abandon_trans(trans_id))) { + LOG_WARN("fail to store abandon trans", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + TABLE_LOAD_RPC_CALL(load_abandon_trans_peer, addr, request, result); + } + } + } + return ret; +} + +int ObTableLoadCoordinator::abandon_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator abandon trans"); + ObTableLoadCoordinatorTrans *trans = nullptr; + if (OB_FAIL(coordinator_ctx_->get_trans(trans_id, trans))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans", KR(ret), K(trans_id)); + } else { + ret = OB_SUCCESS; + } + } else if (OB_FAIL(trans->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } else if (OB_FAIL(abandon_trans_peers(trans))) { + LOG_WARN("fail to abandon trans peers", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->abort_trans(trans))) { + LOG_WARN("fail to abort trans", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + coordinator_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +/** + * get trans status + */ + +int ObTableLoadCoordinator::get_trans_status(const ObTableLoadTransId &trans_id, + ObTableLoadTransStatusType &trans_status, + int &error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_INFO("coordinator get trans status"); + ObTableLoadTransCtx *trans_ctx = nullptr; + if (OB_FAIL(coordinator_ctx_->get_trans_ctx(trans_id, trans_ctx))) { + LOG_WARN("fail to get trans ctx", KR(ret), K(trans_id)); + } else { + trans_status = trans_ctx->get_trans_status(); + error_code = trans_ctx->get_error_code(); + } + } + return ret; +} + +/** + * write + */ + +class ObTableLoadCoordinator::WriteTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + WriteTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObTableLoadCoordinatorTrans *trans, + ObTableLoadTransBucketWriter *bucket_writer, int32_t session_id) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + trans_(trans), + bucket_writer_(bucket_writer), + session_id_(session_id) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + bucket_writer_->inc_ref_count(); + } + virtual ~WriteTaskProcessor() + { + trans_->put_bucket_writer(bucket_writer_); + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int set_objs(const ObTableLoadObjRowArray &obj_rows, const ObIArray &idx_array) + { + int ret = OB_SUCCESS; + + for (int64_t i = 0; OB_SUCC(ret) && (i < obj_rows.count()); ++i) { + const ObTableLoadObjRow &src_obj_row = obj_rows.at(i); + ObTableLoadObjRow out_obj_row; + + if (OB_FAIL(out_obj_row.init(src_obj_row.count_, src_obj_row.allocator_handle_))) { + LOG_WARN("failed to init out_obj_row", KR(ret), K(src_obj_row.count_)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && (j < src_obj_row.count_); ++j) { + out_obj_row.cells_[j] = src_obj_row.cells_[idx_array.at(j)]; + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(obj_rows_.push_back(out_obj_row))) { + LOG_WARN("failed to add row to obj_rows_", KR(ret), K(out_obj_row)); + } + } + } + + return ret; + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(coordinator_write_time_us); + int ret = OB_SUCCESS; + if (OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::RUNNING)) || + OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + if (OB_FAIL(bucket_writer_->write(session_id_, obj_rows_))) { + LOG_WARN("fail to write bucket pool", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; + ObTableLoadTransBucketWriter * const bucket_writer_; + const int32_t session_id_; + ObTableLoadObjRowArray obj_rows_; +}; + +class ObTableLoadCoordinator::WriteTaskCallback : public ObITableLoadTaskCallback +{ +public: + WriteTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadCoordinatorTrans *trans, + ObTableLoadTransBucketWriter *bucket_writer) + : ctx_(ctx), trans_(trans), bucket_writer_(bucket_writer) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + bucket_writer_->inc_ref_count(); + } + virtual ~WriteTaskCallback() + { + trans_->put_bucket_writer(bucket_writer_); + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + trans_->set_trans_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; + ObTableLoadTransBucketWriter * const bucket_writer_; // 为了保证接收完本次写入结果之后再让bucket_writer的引用归零 +}; + +int ObTableLoadCoordinator::write(const ObTableLoadTransId &trans_id, int32_t session_id, + uint64_t sequence_no, const ObTableLoadObjRowArray &obj_rows) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("coordinator write"); + ObTableLoadCoordinatorTrans *trans = nullptr; + ObTableLoadTransBucketWriter *bucket_writer = nullptr; + ObTableLoadMutexGuard guard; + if (OB_FAIL(coordinator_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (session_id == 0 && FALSE_IT(session_id = trans->get_default_session_id())) { + } + // 取出bucket_writer + else if (OB_FAIL(trans->get_bucket_writer_for_write(bucket_writer))) { + LOG_WARN("fail to get bucket writer", KR(ret)); + } else if (OB_FAIL(bucket_writer->advance_sequence_no(session_id, sequence_no, guard))) { + if (OB_UNLIKELY(OB_ENTRY_EXIST != ret)) { + LOG_WARN("fail to advance sequence no", KR(ret), K(session_id)); + } else { + ret = OB_SUCCESS; + } + } else { + ObTableLoadTask *task = nullptr; + WriteTaskProcessor *processor = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_, trans, bucket_writer, session_id))) { + LOG_WARN("fail to set write task processor", KR(ret)); + } else if (OB_ISNULL(processor = dynamic_cast(task->get_processor()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null processor", KR(ret)); + } else if (OB_FAIL(processor->set_objs(obj_rows, coordinator_ctx_->idx_array_))) { + LOG_WARN("fail to set objs", KR(ret), K(coordinator_ctx_->idx_array_)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_, trans, bucket_writer))) { + LOG_WARN("fail to set write task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(coordinator_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + if (OB_NOT_NULL(trans)) { + if (OB_NOT_NULL(bucket_writer)) { + trans->put_bucket_writer(bucket_writer); + bucket_writer = nullptr; + } + coordinator_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +/** + * flush + */ + +class ObTableLoadCoordinator::FlushTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + FlushTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObTableLoadCoordinatorTrans *trans, + ObTableLoadTransBucketWriter *bucket_writer, int32_t session_id) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + trans_(trans), + bucket_writer_(bucket_writer), + session_id_(session_id) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + bucket_writer_->inc_ref_count(); + } + virtual ~FlushTaskProcessor() + { + trans_->put_bucket_writer(bucket_writer_); + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(coordinator_flush_time_us); + int ret = OB_SUCCESS; + if (OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + if (OB_FAIL(bucket_writer_->flush(session_id_))) { + LOG_WARN("fail to flush bucket", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; + ObTableLoadTransBucketWriter * const bucket_writer_; + const int32_t session_id_; +}; + +class ObTableLoadCoordinator::FlushTaskCallback : public ObITableLoadTaskCallback +{ +public: + FlushTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadCoordinatorTrans *trans, + ObTableLoadTransBucketWriter *bucket_writer) + : ctx_(ctx), trans_(trans), bucket_writer_(bucket_writer) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + bucket_writer_->inc_ref_count(); + } + virtual ~FlushTaskCallback() + { + trans_->put_bucket_writer(bucket_writer_); + ctx_->coordinator_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + trans_->set_trans_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadCoordinatorTrans * const trans_; + ObTableLoadTransBucketWriter * const bucket_writer_; // 为了保证接收完本次写入结果之后再让bucket_writer的引用归零 +}; + +int ObTableLoadCoordinator::flush(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("coordinator flush"); + ObTableLoadTransBucketWriter *bucket_writer = nullptr; + // 取出bucket_writer + if (OB_FAIL(trans->get_bucket_writer_for_flush(bucket_writer))) { + LOG_WARN("fail to get bucket writer", KR(ret)); + } else { + for (int32_t session_id = 1; OB_SUCC(ret) && session_id <= param_.session_count_; ++session_id) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_, trans, bucket_writer, + session_id))) { + LOG_WARN("fail to set flush task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_, trans, bucket_writer))) { + LOG_WARN("fail to set flush task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(coordinator_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + } + if (OB_NOT_NULL(bucket_writer)) { + trans->put_bucket_writer(bucket_writer); + bucket_writer = nullptr; + } + } + return ret; +} + +int ObTableLoadCoordinator::write_peer_leader(const ObTableLoadTransId &trans_id, + int32_t session_id, uint64_t sequence_no, + const ObTableLoadTabletObjRowArray &tablet_obj_rows, + const ObAddr &addr) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinator not init", KR(ret), KP(this)); + } else if (tablet_obj_rows.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret)); + } else { + LOG_DEBUG("coordinator write peer leader", K(addr)); + if (ObTableLoadUtils::is_local_addr(addr)) { // 本机 + ObTableLoadStore store(ctx_); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.write(trans_id, session_id, sequence_no, tablet_obj_rows))) { + LOG_WARN("fail to store write", KR(ret), K(trans_id)); + } + } else { // 远端, 发送rpc + common::ObArenaAllocator allocator("TLD_Coord"); + allocator.set_tenant_id(MTL_ID()); + int64_t pos = 0; + int64_t buf_len = tablet_obj_rows.get_serialize_size(); + char *buf = static_cast(allocator.alloc(buf_len)); + if (OB_ISNULL(buf)) { + LOG_WARN("failed to allocate memory", KR(ret), K(buf_len)); + } else if (OB_FAIL(tablet_obj_rows.serialize(buf, buf_len, pos))) { + LOG_WARN("failed to serialize obj row array", KR(ret), KP(buf), K(buf_len), K(pos)); + } else { + ObTableLoadPeerRequest request; + ObTableLoadPeerResult result; + request.credential_ = coordinator_ctx_->credential_; + request.table_id_ = param_.table_id_; + request.trans_id_ = trans_id; + request.session_id_ = session_id; + request.sequence_no_ = sequence_no; + request.payload_.assign(buf, buf_len); + TABLE_LOAD_RPC_CALL(load_peer, addr, request, result); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator.h b/src/observer/table_load/ob_table_load_coordinator.h new file mode 100644 index 0000000000..b029b586c2 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator.h @@ -0,0 +1,107 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/object/ob_object.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" +#include "share/table/ob_table_load_row_array.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTableCtx; +class ObTableLoadCoordinatorCtx; +class ObTableLoadCoordinatorTrans; + +class ObTableLoadCoordinator +{ + static const int64_t WAIT_INTERVAL_US = 1LL * 1000 * 1000; // 1s + static const int64_t DEFAULT_TIMEOUT_US = 10LL * 1000 * 1000; // 10s +public: + ObTableLoadCoordinator(ObTableLoadTableCtx *ctx); + static bool is_ctx_inited(ObTableLoadTableCtx *ctx); + static int init_ctx(ObTableLoadTableCtx *ctx, const common::ObIArray &idx_array, + sql::ObSQLSessionInfo *session_info); + static int abort_ctx(ObTableLoadTableCtx *ctx); + int init(); + bool is_valid() const { return is_inited_; } +private: + int drive_sql_stat(sql::ObExecContext &ctx, table::ObTableLoadSqlStatistics &sql_statistics); + static int abort_active_trans(ObTableLoadTableCtx *ctx); + static int abort_peers_ctx(ObTableLoadTableCtx *ctx); + +// table load ctrl interface +public: + int begin(); + int finish(); + int commit(sql::ObExecContext &ctx, table::ObTableLoadResultInfo &result_info); + int get_status(table::ObTableLoadStatusType &status, int &error_code); +private: + int pre_begin_peers(); + int confirm_begin_peers(); + int pre_merge_peers(); + int start_merge_peers(); + int commit_peers(table::ObTableLoadSqlStatistics &sql_statistics); +private: + int add_check_merge_result_task(); + int check_peers_merge_result(bool &is_finish); + class CheckMergeResultTaskProcessor; + class CheckMergeResultTaskCallback; + +// trans ctrl interface +public: + int start_trans(const table::ObTableLoadSegmentID &segment_id, + table::ObTableLoadTransId &trans_id); + int finish_trans(const table::ObTableLoadTransId &trans_id); + int commit_trans(ObTableLoadCoordinatorTrans *trans); + int abandon_trans(const table::ObTableLoadTransId &trans_id); + int get_trans_status(const table::ObTableLoadTransId &trans_id, + table::ObTableLoadTransStatusType &trans_status, + int &error_code); +private: + int pre_start_trans_peers(ObTableLoadCoordinatorTrans *trans); + int confirm_start_trans_peers(ObTableLoadCoordinatorTrans *trans); + // - OB_SUCCESS: 成功 + // - OB_EAGAIN: 重试 + // - else: 失败 + int pre_finish_trans_peers(ObTableLoadCoordinatorTrans *trans); + int confirm_finish_trans_peers(ObTableLoadCoordinatorTrans *trans); + int abandon_trans_peers(ObTableLoadCoordinatorTrans *trans); +public: + int finish_trans_peers(ObTableLoadCoordinatorTrans *trans); +private: + int add_check_peers_trans_commit_task(ObTableLoadCoordinatorTrans *trans); + int check_peers_trans_commit(ObTableLoadCoordinatorTrans *trans, bool &is_commit); + class CheckPeersTransCommitTaskProcessor; + class CheckPeersTransCommitTaskCallback; + +// write interface +public: + int write(const table::ObTableLoadTransId &trans_id, int32_t session_id, uint64_t sequence_no, + const table::ObTableLoadObjRowArray &obj_rows); + int flush(ObTableLoadCoordinatorTrans *trans); + // 只写到主节点 + int write_peer_leader(const table::ObTableLoadTransId &trans_id, int32_t session_id, + uint64_t sequence_no, const table::ObTableLoadTabletObjRowArray &tablet_obj_rows, + const common::ObAddr &addr); +private: + class WriteTaskProcessor; + class WriteTaskCallback; + class FlushTaskProcessor; + class FlushTaskCallback; + +private: + ObTableLoadTableCtx * const ctx_; + const ObTableLoadParam ¶m_; + ObTableLoadCoordinatorCtx * const coordinator_ctx_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObTableLoadCoordinator); +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator_ctx.cpp b/src/observer/table_load/ob_table_load_coordinator_ctx.cpp new file mode 100644 index 0000000000..6bc5464460 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator_ctx.cpp @@ -0,0 +1,646 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_coordinator_ctx.h" +#include "observer/table_load/ob_table_load_coordinator_trans.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace lib; +using namespace table; +using namespace sql; +using namespace obrpc; + +ObTableLoadCoordinatorCtx::ObTableLoadCoordinatorCtx(ObTableLoadTableCtx *ctx) + : ctx_(ctx), + allocator_("TLD_CoordCtx", OB_MALLOC_NORMAL_BLOCK_SIZE, ctx->param_.tenant_id_), + task_scheduler_(nullptr), + last_trans_gid_(1024), + next_session_id_(0), + status_(ObTableLoadStatusType::NONE), + error_code_(OB_SUCCESS), + redef_table_(), + is_inited_(false) +{ +} + +ObTableLoadCoordinatorCtx::~ObTableLoadCoordinatorCtx() +{ + destroy(); +} + +int ObTableLoadCoordinatorCtx::init(ObSQLSessionInfo *session_info, + const ObIArray &idx_array) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadCoordinatorCtx init twice", KR(ret), KP(this)); + } else if (idx_array.count() != ctx_->param_.column_count_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid idx_array", KR(ret), K(idx_array.count()), K_(ctx_->param_.column_count)); + } else if (OB_FAIL(redef_table_.init(ctx_, session_info))) { + LOG_WARN("failed to init ddl processor", KR(ret)); + } else if (OB_FAIL(redef_table_.start())) { + LOG_WARN("failed to create hidden table", KR(ret)); + } else if (OB_FAIL(target_schema_.init(ctx_->param_.tenant_id_, ctx_->param_.database_id_, + ctx_->param_.target_table_id_, allocator_))) { + LOG_WARN("fail to init table load schema", KR(ret), K(ctx_->param_.tenant_id_), + K(ctx_->param_.target_table_id_)); + } else { + // init idx array + if (OB_FAIL(idx_array_.assign(idx_array))) { + LOG_WARN("failed to assign idx array", KR(ret), K(idx_array)); + } + // init partition_location_ + else if (OB_FAIL(partition_location_.init(ctx_->param_.tenant_id_, ctx_->schema_.partition_ids_, + allocator_))) { + LOG_WARN("fail to init partition location", KR(ret)); + } + else if (OB_FAIL(target_partition_location_.init(ctx_->param_.tenant_id_, + target_schema_.partition_ids_, allocator_))) { + LOG_WARN("fail to init origin partition location", KR(ret)); + } + // init partition_calc_ + else if (OB_FAIL( + partition_calc_.init(ctx_->param_.tenant_id_, ctx_->param_.table_id_))) { + LOG_WARN("fail to init partition calc", KR(ret)); + } + // init trans_allocator_ + else if (OB_FAIL(trans_allocator_.init("TLD_CTransPool", ctx_->param_.tenant_id_))) { + LOG_WARN("fail to init trans allocator", KR(ret)); + } + // init trans_map_ + else if (OB_FAIL( + trans_map_.create(1024, "TLD_TransMap", "TLD_TransMap", ctx_->param_.tenant_id_))) { + LOG_WARN("fail to create trans map", KR(ret)); + } + // init trans_ctx_map_ + else if (OB_FAIL(trans_ctx_map_.create(1024, "TLD_TCtxMap", "TLD_TCtxMap", + ctx_->param_.tenant_id_))) { + LOG_WARN("fail to create trans ctx map", KR(ret)); + } + // init segment_trans_ctx_map_ + else if (OB_FAIL(segment_ctx_map_.init("TLD_SegCtxMap", ctx_->param_.tenant_id_))) { + LOG_WARN("fail to init segment ctx map", KR(ret)); + } + // generate credential_ + else if (OB_FAIL(generate_credential(session_info->get_priv_user_id()))) { + LOG_WARN("fail to generate credential", KR(ret)); + } + // init task_scheduler_ + else if (OB_ISNULL(task_scheduler_ = OB_NEWx(ObTableLoadTaskThreadPoolScheduler, (&allocator_), + ctx_->param_.session_count_, allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTaskThreadPoolScheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->init())) { + LOG_WARN("fail to init task scheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->start())) { + LOG_WARN("fail to start task scheduler", KR(ret)); + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } else { + destroy(); + } + } + return ret; +} + +void ObTableLoadCoordinatorCtx::stop() +{ + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + } + LOG_INFO("coordinator ctx stop succ"); +} + +void ObTableLoadCoordinatorCtx::destroy() +{ + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + task_scheduler_->~ObITableLoadTaskScheduler(); + allocator_.free(task_scheduler_); + task_scheduler_ = nullptr; + } + for (TransMap::const_iterator iter = trans_map_.begin(); iter != trans_map_.end(); ++iter) { + ObTableLoadCoordinatorTrans *trans = iter->second; + abort_unless(0 == trans->get_ref_count()); + trans_allocator_.free(trans); + } + trans_map_.reuse(); + for (TransCtxMap::const_iterator iter = trans_ctx_map_.begin(); iter != trans_ctx_map_.end(); + ++iter) { + ObTableLoadTransCtx *trans_ctx = iter->second; + ctx_->free_trans_ctx(trans_ctx); + } + trans_ctx_map_.reuse(); + segment_ctx_map_.reset(); + commited_trans_ctx_array_.reset(); +} + +int ObTableLoadCoordinatorCtx::generate_credential(uint64_t user_id) +{ + int ret = OB_SUCCESS; + const int64_t expire_ts = 0; + + share::schema::ObSchemaGetterGuard schema_guard; + const share::schema::ObUserInfo *user_info = NULL; + if (OB_ISNULL(GCTX.schema_service_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid schema service", K(ret)); + } else if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard(ctx_->param_.tenant_id_, schema_guard))) { + LOG_WARN("fail to get schema guard", K(ret), "tenant_id", ctx_->param_.tenant_id_); + } else if (OB_FAIL(schema_guard.get_user_info(ctx_->param_.tenant_id_, user_id, user_info))) { + LOG_WARN("fail to get user info", K(ret), K(ctx_->param_.tenant_id_), K(user_id)); + } else if (OB_ISNULL(user_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("user info is null", K(ret), K(ctx_->param_.tenant_id_), K(user_id)); + } else if (OB_FAIL(ObTableLoadUtils::generate_credential(ctx_->param_.tenant_id_, user_id, + ctx_->param_.database_id_, expire_ts, + user_info->get_passwd_str().hash(), allocator_, credential_))) { + LOG_WARN("fail to generate credential", KR(ret)); + } + return ret; +} + +int ObTableLoadCoordinatorCtx::advance_status(ObTableLoadStatusType status) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadStatusType::ERROR == status || + ObTableLoadStatusType::ABORT == status)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(status)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(ObTableLoadStatusType::ERROR == status_)) { + ret = error_code_; + LOG_WARN("coordinator has error", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadStatusType::ABORT == status_)) { + ret = OB_TRANS_KILLED; + LOG_WARN("coordinator is abort", KR(ret)); + } + // 正常运行阶段, 状态是一步步推进的 + else if (OB_UNLIKELY(static_cast(status) != static_cast(status_) + 1)) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("unexpected status", KR(ret), K(status), K(status_)); + } else { + status_ = status; + table_load_status_to_string(status_, ctx_->job_stat_->coordinator.status_); + LOG_INFO("LOAD DATA COORDINATOR advance status", K(status)); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::set_status_error(int error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_UNLIKELY(OB_SUCCESS == error_code)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(error_code)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(status_ == ObTableLoadStatusType::ABORT)) { + ret = OB_TRANS_KILLED; + } else if (status_ != ObTableLoadStatusType::ERROR) { + status_ = ObTableLoadStatusType::ERROR; + error_code_ = error_code; + table_load_status_to_string(status_, ctx_->job_stat_->coordinator.status_); + LOG_INFO("LOAD DATA COORDINATOR status error", KR(error_code)); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::set_status_abort() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(status_ != ObTableLoadStatusType::ABORT)) { + status_ = ObTableLoadStatusType::ABORT; + table_load_status_to_string(status_, ctx_->job_stat_->coordinator.status_); + LOG_INFO("LOAD DATA COORDINATOR status abort"); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::check_status_unlock(ObTableLoadStatusType status) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(status != status_)) { + if (ObTableLoadStatusType::ERROR == status_) { + ret = error_code_; + } else if (ObTableLoadStatusType::ABORT == status_) { + ret = OB_CANCELED; + } else { + ret = OB_STATE_NOT_MATCH; + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::check_status(ObTableLoadStatusType status) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + ret = check_status_unlock(status); + } + return ret; +} + +int ObTableLoadCoordinatorCtx::alloc_trans_ctx(const ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) +{ + int ret = OB_SUCCESS; + trans_ctx = nullptr; + // 分配trans_ctx + if (OB_ISNULL(trans_ctx = ctx_->alloc_trans_ctx(trans_id))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc trans ctx", KR(ret), K(trans_id)); + } + // 把trans_ctx插入map + else if (OB_FAIL(trans_ctx_map_.set_refactored(trans_ctx->trans_id_, trans_ctx))) { + LOG_WARN("fail to set trans ctx", KR(ret), K(trans_ctx->trans_id_)); + } + if (OB_FAIL(ret)) { + if (nullptr != trans_ctx) { + ctx_->free_trans_ctx(trans_ctx); + trans_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::alloc_trans(const ObTableLoadSegmentID &segment_id, + ObTableLoadCoordinatorTrans *&trans) +{ + int ret = OB_SUCCESS; + trans = nullptr; + const uint64_t trans_gid = ATOMIC_AAF(&last_trans_gid_, 1); + const int32_t default_session_id = + (ATOMIC_FAA(&next_session_id_, 1) % ctx_->param_.session_count_) + 1; + ObTableLoadTransId trans_id(segment_id, trans_gid); + ObTableLoadTransCtx *trans_ctx = nullptr; + // 分配trans_ctx + if (OB_FAIL(alloc_trans_ctx(trans_id, trans_ctx))) { + LOG_WARN("fail to alloc trans ctx", KR(ret), K(trans_id)); + } + // 构造trans + else if (OB_ISNULL(trans = trans_allocator_.alloc(trans_ctx, default_session_id))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc ObTableLoadCoordinatorTrans", KR(ret)); + } else if (OB_FAIL(trans->init())) { + LOG_WARN("fail to init trans", KR(ret), K(trans_id)); + } else if (OB_FAIL(trans_map_.set_refactored(trans_id, trans))) { + LOG_WARN("fail to set_refactored", KR(ret), K(trans_id)); + } + if (OB_FAIL(ret)) { + if (nullptr != trans) { + trans_allocator_.free(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::start_trans(const ObTableLoadSegmentID &segment_id, + ObTableLoadCoordinatorTrans *&trans) +{ + int ret = OB_SUCCESS; + trans = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(check_status_unlock(ObTableLoadStatusType::LOADING))) { + LOG_WARN("fail to check status", KR(ret), K_(status)); + } else { + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + if (OB_FAIL(segment_ctx_map_.create(segment_id, segment_ctx))) { + LOG_WARN("fail to create", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(nullptr != segment_ctx->current_trans_ || + nullptr != segment_ctx->committed_trans_ctx_)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("trans already exist", KR(ret)); + } else { + if (OB_FAIL(alloc_trans(segment_id, trans))) { + LOG_WARN("fail to alloc trans", KR(ret)); + } else { + segment_ctx->current_trans_ = trans; + trans->inc_ref_count(); + } + } + } + if (OB_NOT_NULL(segment_ctx)) { + segment_ctx_map_.revert(segment_ctx); + } + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::commit_trans(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObMutexGuard guard(mutex_); + const ObTableLoadSegmentID &segment_id = trans->get_trans_id().segment_id_; + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } + } else if (OB_UNLIKELY(segment_ctx->current_trans_ != trans)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } else if (OB_FAIL(trans->check_trans_status(ObTableLoadTransStatusType::COMMIT))) { + LOG_WARN("fail to check trans status commit", KR(ret)); + } else if (OB_FAIL(commited_trans_ctx_array_.push_back(trans->get_trans_ctx()))) { + LOG_WARN("fail to push back trans ctx", KR(ret)); + } else { + segment_ctx->current_trans_ = nullptr; + segment_ctx->committed_trans_ctx_ = trans->get_trans_ctx(); + trans->set_dirty(); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::abort_trans(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObMutexGuard guard(mutex_); + const ObTableLoadSegmentID &segment_id = trans->get_trans_id().segment_id_; + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } + } else if (OB_UNLIKELY(segment_ctx->current_trans_ != trans)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } else if (OB_FAIL(trans->check_trans_status(ObTableLoadTransStatusType::ABORT))) { + LOG_WARN("fail to check trans status abort", KR(ret)); + } else { + segment_ctx->current_trans_ = nullptr; + trans->set_dirty(); + } + } + return ret; +} + +void ObTableLoadCoordinatorCtx::put_trans(ObTableLoadCoordinatorTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObTableLoadTransCtx *trans_ctx = trans->get_trans_ctx(); + if (0 == trans->dec_ref_count() && trans->is_dirty()) { + ObTableLoadTransStatusType trans_status = trans_ctx->get_trans_status(); + OB_ASSERT(ObTableLoadTransStatusType::COMMIT == trans_status || + ObTableLoadTransStatusType::ABORT == trans_status); + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_map_.erase_refactored(trans->get_trans_id()))) { + LOG_WARN("fail to erase_refactored", KR(ret)); + } else { + trans_allocator_.free(trans); + trans = nullptr; + } + } + } + if (OB_FAIL(ret)) { + set_status_error(ret); + } +} + +int ObTableLoadCoordinatorCtx::get_trans(const ObTableLoadTransId &trans_id, + ObTableLoadCoordinatorTrans *&trans) const +{ + int ret = OB_SUCCESS; + trans = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_map_.get_refactored(trans_id, trans))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get_refactored", KR(ret), K(trans_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } else { + trans->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::get_trans_ctx(const ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_ctx_map_.get_refactored(trans_id, trans_ctx))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans ctx", KR(ret), K(trans_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::get_segment_trans_ctx(const ObTableLoadSegmentID &segment_id, + ObTableLoadTransCtx *&trans_ctx) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } + } else if (nullptr != segment_ctx->current_trans_) { + trans_ctx = segment_ctx->current_trans_->get_trans_ctx(); + } else if (nullptr != segment_ctx->committed_trans_ctx_) { + trans_ctx = segment_ctx->committed_trans_ctx_; + } else { + ret = OB_ENTRY_NOT_EXIST; + } + if (OB_NOT_NULL(segment_ctx)) { + segment_ctx_map_.revert(segment_ctx); + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::get_active_trans_ids( + ObIArray &trans_id_array) const +{ + int ret = OB_SUCCESS; + trans_id_array.reset(); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + for (TransMap::const_iterator trans_iter = trans_map_.begin(); + OB_SUCC(ret) && trans_iter != trans_map_.end(); ++trans_iter) { + if (OB_FAIL(trans_id_array.push_back(trans_iter->first))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::get_committed_trans_ids( + ObTableLoadArray &trans_id_array, ObIAllocator &allocator) const +{ + int ret = OB_SUCCESS; + trans_id_array.reset(); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_id_array.create(commited_trans_ctx_array_.count(), allocator))) { + LOG_WARN("fail to create trans id array", KR(ret)); + } else { + for (int64_t i = 0; i < commited_trans_ctx_array_.count(); ++i) { + ObTableLoadTransCtx *trans_ctx = commited_trans_ctx_array_.at(i); + trans_id_array[i] = trans_ctx->trans_id_; + } + } + } + return ret; +} + +int ObTableLoadCoordinatorCtx::check_exist_trans(bool &is_exist) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + is_exist = !trans_map_.empty(); + } + return ret; +} + +int ObTableLoadCoordinatorCtx::check_exist_committed_trans(bool &is_exist) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + is_exist = !commited_trans_ctx_array_.empty(); + } + return ret; +} + +int ObTableLoadCoordinatorCtx::commit() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_FAIL(check_status(ObTableLoadStatusType::MERGED))) { + LOG_WARN("fail to check status", KR(ret)); + } else if (OB_FAIL(redef_table_.finish())){ + LOG_WARN("failed to finish redef table", KR(ret)); + } + return ret; +} + +int ObTableLoadCoordinatorCtx::abort() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorCtx not init", KR(ret)); + } else if (OB_FAIL(redef_table_.abort())){ + LOG_WARN("failed to abort redef table", KR(ret)); + } + return ret; +} + +int64_t ObTableLoadCoordinatorCtx::get_ddl_task_id() const +{ + return redef_table_.get_ddl_task_id(); +} +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator_ctx.h b/src/observer/table_load/ob_table_load_coordinator_ctx.h new file mode 100644 index 0000000000..e396e9ee59 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator_ctx.h @@ -0,0 +1,148 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_se_array.h" +#include "lib/hash/ob_hashmap.h" +#include "lib/hash/ob_link_hashmap.h" +#include "observer/table_load/ob_table_load_object_allocator.h" +#include "observer/table_load/ob_table_load_partition_calc.h" +#include "observer/table_load/ob_table_load_partition_location.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_redef_table.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTableCtx; +class ObTableLoadTransCtx; +class ObTableLoadCoordinatorTrans; +class ObITableLoadTaskScheduler; + +class ObTableLoadCoordinatorCtx +{ +public: + ObTableLoadCoordinatorCtx(ObTableLoadTableCtx *ctx); + ~ObTableLoadCoordinatorCtx(); + int init(sql::ObSQLSessionInfo *session_info, const common::ObIArray &idx_array); + void stop(); + void destroy(); + bool is_valid() const { return is_inited_; } +public: + OB_INLINE table::ObTableLoadStatusType get_status() const + { + lib::ObMutexGuard guard(mutex_); + return status_; + } + OB_INLINE int get_error_code() const + { + lib::ObMutexGuard guard(mutex_); + return error_code_; + } + OB_INLINE int set_status_inited() + { + return advance_status(table::ObTableLoadStatusType::INITED); + } + OB_INLINE int set_status_loading() + { + return advance_status(table::ObTableLoadStatusType::LOADING); + } + OB_INLINE int set_status_frozen() + { + return advance_status(table::ObTableLoadStatusType::FROZEN); + } + OB_INLINE int set_status_merging() + { + return advance_status(table::ObTableLoadStatusType::MERGING); + } + OB_INLINE int set_status_merged() + { + return advance_status(table::ObTableLoadStatusType::MERGED); + } + OB_INLINE int set_status_commit() + { + return advance_status(table::ObTableLoadStatusType::COMMIT); + } + int set_status_error(int error_code); + int set_status_abort(); + int check_status(table::ObTableLoadStatusType status) const; +private: + int advance_status(table::ObTableLoadStatusType status); + int check_status_unlock(table::ObTableLoadStatusType status) const; +public: + int start_trans(const table::ObTableLoadSegmentID &segment_id, + ObTableLoadCoordinatorTrans *&trans); + int commit_trans(ObTableLoadCoordinatorTrans *trans); + int abort_trans(ObTableLoadCoordinatorTrans *trans); + void put_trans(ObTableLoadCoordinatorTrans *trans); + int get_trans(const table::ObTableLoadTransId &trans_id, + ObTableLoadCoordinatorTrans *&trans) const; + int get_trans_ctx(const table::ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) const; + int get_segment_trans_ctx(const table::ObTableLoadSegmentID &segment_id, + ObTableLoadTransCtx *&trans_ctx); + int get_active_trans_ids(common::ObIArray &trans_id_array) const; + int get_committed_trans_ids(table::ObTableLoadArray &trans_id_array, + common::ObIAllocator &allocator) const; + int check_exist_trans(bool &is_exist) const; + int check_exist_committed_trans(bool &is_exist) const; + int commit(); + int abort(); + int64_t get_ddl_task_id() const; +private: + int generate_credential(uint64_t user_id); + int alloc_trans_ctx(const table::ObTableLoadTransId &trans_id, ObTableLoadTransCtx *&trans_ctx); + int alloc_trans(const table::ObTableLoadSegmentID &segment_id, + ObTableLoadCoordinatorTrans *&trans); +public: + ObTableLoadTableCtx * const ctx_; + common::ObArenaAllocator allocator_; + ObTableLoadSchema target_schema_; + ObTableLoadPartitionLocation partition_location_; + ObTableLoadPartitionLocation target_partition_location_; + ObTableLoadPartitionCalc partition_calc_; + ObITableLoadTaskScheduler *task_scheduler_; + common::ObArray idx_array_; + table::ObTableLoadResultInfo result_info_; + common::ObString credential_; +private: + struct SegmentCtx : public common::LinkHashValue + { + public: + SegmentCtx() : segment_id_(0), current_trans_(nullptr), committed_trans_ctx_(nullptr) {} + TO_STRING_KV(K_(segment_id), KP_(current_trans), KP_(committed_trans_ctx)); + public: + table::ObTableLoadSegmentID segment_id_; + ObTableLoadCoordinatorTrans *current_trans_; + ObTableLoadTransCtx *committed_trans_ctx_; + }; +private: + typedef common::hash::ObHashMap + TransMap; + typedef common::hash::ObHashMap + TransCtxMap; + typedef common::ObLinkHashMap SegmentCtxMap; +private: + ObTableLoadObjectAllocator trans_allocator_; // 多线程安全 + uint64_t last_trans_gid_ CACHE_ALIGNED; + uint64_t next_session_id_ CACHE_ALIGNED; + mutable lib::ObMutex mutex_; + table::ObTableLoadStatusType status_; + int error_code_; + TransMap trans_map_; + TransCtxMap trans_ctx_map_; + SegmentCtxMap segment_ctx_map_; + common::ObSEArray commited_trans_ctx_array_; + ObTableLoadRedefTable redef_table_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator_trans.cpp b/src/observer/table_load/ob_table_load_coordinator_trans.cpp new file mode 100644 index 0000000000..62973c16a6 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator_trans.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_coordinator_trans.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_trans_bucket_writer.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "observer/table_load/ob_table_load_table_ctx.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace lib; +using namespace table; + +ObTableLoadCoordinatorTrans::ObTableLoadCoordinatorTrans(ObTableLoadTransCtx *trans_ctx, int32_t default_session_id) + : trans_ctx_(trans_ctx), + default_session_id_(default_session_id), + trans_bucket_writer_(nullptr), + ref_count_(0), + is_dirty_(false), + is_inited_(false) +{ +} + +ObTableLoadCoordinatorTrans::~ObTableLoadCoordinatorTrans() +{ + if (nullptr != trans_bucket_writer_) { + trans_bucket_writer_->~ObTableLoadTransBucketWriter(); + trans_ctx_->allocator_.free(trans_bucket_writer_); + trans_bucket_writer_ = nullptr; + } +} + +int ObTableLoadCoordinatorTrans::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadCoordinatorTrans init twice", KR(ret), KP(this)); + } else { + if (OB_ISNULL(trans_bucket_writer_ = + OB_NEWx(ObTableLoadTransBucketWriter, (&trans_ctx_->allocator_), trans_ctx_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTransBucketWriter", KR(ret)); + } else if (OB_FAIL(trans_bucket_writer_->init())) { + LOG_WARN("fail to init trans bucket writer", KR(ret)); + } else if (OB_FAIL(set_trans_status_inited())) { + LOG_WARN("fail to set trans status inited", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadCoordinatorTrans::advance_trans_status(ObTableLoadTransStatusType trans_status) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->advance_trans_status(trans_status))) { + LOG_WARN("fail to advance trans status", KR(ret), K(trans_status)); + } else { + table_load_trans_status_to_string(trans_status, + trans_ctx_->ctx_->job_stat_->coordinator.trans_status_); + } + return ret; +} + +int ObTableLoadCoordinatorTrans::set_trans_status_error(int error_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->set_trans_status_error(error_code))) { + LOG_WARN("fail to set trans status error", KR(ret)); + } else { + table_load_trans_status_to_string(ObTableLoadTransStatusType::ERROR, + trans_ctx_->ctx_->job_stat_->coordinator.trans_status_); + } + return ret; +} + +int ObTableLoadCoordinatorTrans::set_trans_status_abort() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } else { + table_load_trans_status_to_string(ObTableLoadTransStatusType::ABORT, + trans_ctx_->ctx_->job_stat_->coordinator.trans_status_); + } + return ret; +} + +int ObTableLoadCoordinatorTrans::get_bucket_writer_for_write( + ObTableLoadTransBucketWriter *&bucket_writer) const +{ + int ret = OB_SUCCESS; + bucket_writer = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorTrans not init", KR(ret), KP(this)); + } else if (OB_FAIL(check_trans_status(ObTableLoadTransStatusType::RUNNING))) { + LOG_WARN("fail to check trans status", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_bucket_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null bucket writer", KR(ret)); + } else if (OB_UNLIKELY(trans_bucket_writer_->is_flush())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans bucket writer has flush", KR(ret)); + } else { + bucket_writer = trans_bucket_writer_; + bucket_writer->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadCoordinatorTrans::get_bucket_writer_for_flush( + ObTableLoadTransBucketWriter *&bucket_writer) const +{ + int ret = OB_SUCCESS; + bucket_writer = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorTrans not init", KR(ret), KP(this)); + } else if (OB_FAIL(check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + LOG_WARN("fail to check trans status", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_bucket_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null bucket writer", KR(ret)); + } else if (OB_UNLIKELY(trans_bucket_writer_->is_flush())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans bucket writer has flush", KR(ret)); + } else { + trans_bucket_writer_->set_is_flush(); + bucket_writer = trans_bucket_writer_; + bucket_writer->inc_ref_count(); + } + } + return ret; +} + +void ObTableLoadCoordinatorTrans::put_bucket_writer(ObTableLoadTransBucketWriter *bucket_writer) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCoordinatorTrans not init", KR(ret)); + } else if (OB_ISNULL(bucket_writer)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid null bucket writer", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + OB_ASSERT(trans_bucket_writer_ == bucket_writer); + } + if (OB_SUCC(ret)) { + if (0 == bucket_writer->dec_ref_count() && OB_FAIL(handle_write_done())) { + LOG_WARN("fail to handle coordinator write done", KR(ret)); + } + } + if (OB_FAIL(ret)) { + set_trans_status_error(ret); + } +} + +int ObTableLoadCoordinatorTrans::handle_write_done() +{ + int ret = OB_SUCCESS; + if (ObTableLoadTransStatusType::FROZEN == trans_ctx_->get_trans_status()) { + ObTableLoadCoordinator coordinator(trans_ctx_->ctx_); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.finish_trans_peers(this))) { + LOG_WARN("fail to finish trans peers", KR(ret)); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_coordinator_trans.h b/src/observer/table_load/ob_table_load_coordinator_trans.h new file mode 100644 index 0000000000..c36f96c2b9 --- /dev/null +++ b/src/observer/table_load/ob_table_load_coordinator_trans.h @@ -0,0 +1,76 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_trans_ctx.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTransCtx; +class ObTableLoadTransBucket; +class ObTableLoadTransBucketWriter; + +struct ObTableLoadCoordinatorTrans +{ + ObTableLoadCoordinatorTrans(ObTableLoadTransCtx *trans_ctx, int32_t default_session_id); + ~ObTableLoadCoordinatorTrans(); + int init(); + OB_INLINE int32_t get_default_session_id() const { return default_session_id_; } + OB_INLINE ObTableLoadTransCtx *get_trans_ctx() const { return trans_ctx_; } + OB_INLINE const table::ObTableLoadTransId &get_trans_id() const + { + return trans_ctx_->trans_id_; + } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } + bool is_dirty() const { return is_dirty_; } + void set_dirty() { is_dirty_ = true; } + TO_STRING_KV(KP_(trans_ctx), KP_(trans_bucket_writer), K_(is_dirty)); +public: + OB_INLINE int check_trans_status(table::ObTableLoadTransStatusType trans_status) const + { + return trans_ctx_->check_trans_status(trans_status); + } + OB_INLINE int set_trans_status_inited() + { + return advance_trans_status(table::ObTableLoadTransStatusType::INITED); + } + OB_INLINE int set_trans_status_running() + { + return advance_trans_status(table::ObTableLoadTransStatusType::RUNNING); + } + OB_INLINE int set_trans_status_frozen() + { + return advance_trans_status(table::ObTableLoadTransStatusType::FROZEN); + } + OB_INLINE int set_trans_status_commit() + { + return advance_trans_status(table::ObTableLoadTransStatusType::COMMIT); + } + int set_trans_status_error(int error_code); + int set_trans_status_abort(); +private: + int advance_trans_status(table::ObTableLoadTransStatusType trans_status); +public: + int get_bucket_writer_for_write(ObTableLoadTransBucketWriter *&bucket_writer) const; + int get_bucket_writer_for_flush(ObTableLoadTransBucketWriter *&bucket_writer) const; + void put_bucket_writer(ObTableLoadTransBucketWriter *bucket_writer); +private: + int handle_write_done(); +private: + ObTableLoadTransCtx * const trans_ctx_; + const int32_t default_session_id_; + ObTableLoadTransBucketWriter *trans_bucket_writer_; + int64_t ref_count_ CACHE_ALIGNED; + volatile bool is_dirty_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_csv_parser.cpp b/src/observer/table_load/ob_table_load_csv_parser.cpp new file mode 100644 index 0000000000..d5e24c61b8 --- /dev/null +++ b/src/observer/table_load/ob_table_load_csv_parser.cpp @@ -0,0 +1,155 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_csv_parser.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "sql/engine/cmd/ob_load_data_parser.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace sql; +using namespace table; + +const char *ObTableLoadCSVParser::default_field_term_str = "|"; + +ObTableLoadCSVParser::ObTableLoadCSVParser() + : allocator_("TLD_CSVParser"), + column_count_(0), + batch_row_count_(0), + str_(nullptr), + end_(nullptr), + escape_buf_(nullptr), + is_inited_(false) +{ +} + +ObTableLoadCSVParser::~ObTableLoadCSVParser() +{ +} + +int ObTableLoadCSVParser::init(ObTableLoadTableCtx *table_ctx, const ObString &data_buffer) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadCSVParser init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == table_ctx || data_buffer.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table_ctx), K(data_buffer.length()), + K(table_ctx->param_.data_type_)); + } else { + column_count_ = table_ctx->param_.column_count_; + batch_row_count_ = table_ctx->param_.batch_size_; + const int64_t total_obj_count = batch_row_count_ * column_count_; + ObDataInFileStruct file_struct; + file_struct.field_term_str_ = default_field_term_str; + if (OB_FAIL(csv_parser_.init(file_struct, column_count_, table_ctx->schema_.collation_type_))) { + LOG_WARN("fail to init csv general parser", KR(ret)); + } else if (OB_FAIL(store_column_objs_.create(total_obj_count, allocator_))) { + LOG_WARN("fail to create objs", KR(ret)); + } else if (OB_ISNULL(escape_buf_ = static_cast( + allocator_.alloc(ObLoadFileBuffer::MAX_BUFFER_SIZE)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate escape buf memory", KR(ret)); + } else { + str_ = data_buffer.ptr(); + end_ = data_buffer.ptr() + data_buffer.length(); + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadCSVParser::get_next_row(ObNewRow &row) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(row.cells_) || OB_UNLIKELY(row.count_ != column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(row)); + } else if (str_ == end_) { + ret = OB_ITER_END; + } else { + ObSEArray err_records; + int64_t nrows = 1; + auto handle_one_line = [](ObIArray &fields_per_line) -> int { + UNUSED(fields_per_line); + return OB_SUCCESS; + }; + ret = csv_parser_.scan( + str_, end_, nrows, escape_buf_, escape_buf_ + ObLoadFileBuffer::MAX_BUFFER_SIZE, + handle_one_line, err_records, true); + if (OB_FAIL(ret)) { + LOG_WARN("fail to csv parser scan", KR(ret)); + } else if (OB_UNLIKELY(!err_records.empty())) { + ret = OB_ERR_WRONG_VALUE; + LOG_WARN("parser error, have err records", KR(ret)); + } else if (0 == nrows) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("parser error 0 == nrows", KR(ret)); + } else { + const ObIArray &field_values_in_file = + csv_parser_.get_fields_per_line(); + for (int64_t i = 0; i < row.count_; ++i) { + const ObCSVGeneralParser::FieldValue &str_v = field_values_in_file.at(i); + ObObj &obj = row.cells_[i]; + if (str_v.is_null_) { + obj.set_null(); + } else { + obj.set_string(ObVarcharType, ObString(str_v.len_, str_v.ptr_)); + obj.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + } + } + } + for (int64_t i = 0; i < err_records.count(); ++i) { + LOG_WARN("csv parser error records", K(i), K(err_records.at(i).err_code)); + } + } + return ret; +} + +int ObTableLoadCSVParser::get_batch_objs(ObTableLoadArray &store_column_objs) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadCSVParser not init", KR(ret), KP(this)); + } else { + uint64_t processed_line_count = 0; + ObNewRow row; + row.cells_ = store_column_objs_.ptr(); + row.count_ = column_count_; + while (OB_SUCC(ret) && processed_line_count < batch_row_count_) { + if (OB_FAIL(get_next_row(row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get row objs", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else { + ++processed_line_count; + row.cells_ += column_count_; + } + } + if (OB_SUCC(ret)) { + if (processed_line_count == 0) { + ret = OB_ITER_END; + } else if (OB_FAIL(store_column_objs.ref(store_column_objs_.ptr(), + processed_line_count * column_count_))) { + LOG_WARN("fail to ref", KR(ret)); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_csv_parser.h b/src/observer/table_load/ob_table_load_csv_parser.h new file mode 100644 index 0000000000..97583ecb3e --- /dev/null +++ b/src/observer/table_load/ob_table_load_csv_parser.h @@ -0,0 +1,41 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#pragma once + +#include "lib/string/ob_string.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "sql/engine/cmd/ob_load_data_impl.h" +#include "sql/engine/cmd/ob_load_data_parser.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" + +namespace oceanbase +{ +namespace observer +{ + +struct ObTableLoadCSVParser +{ +public: + static const char *default_field_term_str; + ObTableLoadCSVParser(); + ~ObTableLoadCSVParser(); + int init(ObTableLoadTableCtx *table_ctx, const ObString &data_buffer); + int get_batch_objs(table::ObTableLoadArray &store_column_objs); +private: + int get_next_row(ObNewRow &row); +private: + sql::ObCSVGeneralParser csv_parser_; + common::ObArenaAllocator allocator_; + int64_t column_count_; + int64_t batch_row_count_; + const char *str_; + const char *end_; + table::ObTableLoadArray store_column_objs_; + char *escape_buf_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_error_row_handler.cpp b/src/observer/table_load/ob_table_load_error_row_handler.cpp new file mode 100644 index 0000000000..0dbfaac25e --- /dev/null +++ b/src/observer/table_load/ob_table_load_error_row_handler.cpp @@ -0,0 +1,305 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +using namespace common; +using namespace common::hash; +using namespace table; +using namespace lib; +using namespace share; +using namespace share::schema; +using namespace blocksstable; +using namespace sql; +namespace observer +{ +ObTableLoadErrorRowHandler::PartitionRowkey::~PartitionRowkey() +{ + if (OB_NOT_NULL(last_rowkey_.get_datum_ptr())) { + allocator_.free((void *)(last_rowkey_.get_datum_ptr())); + } +} + +ObTableLoadErrorRowHandler::PartitionRowkeyMap::~PartitionRowkeyMap() +{ + auto release_map_entry = [this](HashMapPair &entry) { + ObTableLoadErrorRowHandler::PartitionRowkey *part_rowkey = entry.second; + part_rowkey->~PartitionRowkey(); + allocator_.free((void *)part_rowkey); + return 0; + }; + map_.foreach_refactored(release_map_entry); +} + +ObTableLoadErrorRowHandler::ObTableLoadErrorRowHandler() + : capacity_(0), + session_cnt_(0), + safe_allocator_(row_allocator_), + error_row_cnt_(0), + repeated_row_cnt_(0), + is_inited_(false) +{ +} + +ObTableLoadErrorRowHandler::~ObTableLoadErrorRowHandler() +{ +} + +int ObTableLoadErrorRowHandler::init(ObTableLoadTableCtx *const ctx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadErrorRowHandler init twice", KR(ret), KP(this)); + } else { + param_ = ctx->param_; + job_stat_ = ctx->job_stat_; + datum_utils_ = &(ctx->schema_.datum_utils_); + col_descs_ = &(ctx->schema_.column_descs_); + capacity_ = ctx->param_.max_error_row_count_; + rowkey_column_num_ = ctx->schema_.rowkey_column_count_; + session_cnt_ = ctx->param_.session_count_; + if (OB_FAIL(session_maps_.prepare_allocate(session_cnt_))) { + LOG_WARN("failed to pre allocate session maps", K(ret), K(session_cnt_)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && (i < session_maps_.count()); ++i) { + if (OB_FAIL(session_maps_.at(i).map_.create(1024, "TLD_err_chk_map", "TLD_err_chk_map", + ctx->param_.tenant_id_))) { + LOG_WARN("fail to create map", KR(ret), K(ctx->param_.tenant_id_)); + } else { + ObArenaAllocator &allocator = session_maps_.at(i).allocator_; + allocator.set_label("TLD_err_chk"); + allocator.set_tenant_id(MTL_ID()); + } + } + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + return ret; +} + +int ObTableLoadErrorRowHandler::inner_append_error_row(const ObNewRow &row, + ObIArray &error_row_array) +{ + int ret = OB_SUCCESS; + ObNewRow new_row; + ObMutexGuard guard(append_row_mutex_); + if (error_row_cnt_ >= capacity_) { + ret = OB_ERR_TOO_MANY_ROWS; + LOG_WARN("error row count reaches its maximum value", K(ret), K(capacity_), K(error_row_cnt_)); + } else if (OB_FAIL(ObTableLoadUtils::deep_copy(row, new_row, safe_allocator_))) { + LOG_WARN("failed to deep copy new row", K(ret), K(row)); + } else if (OB_FAIL(error_row_array.push_back(new_row))) { + LOG_WARN("failed to push back error row", K(ret), K(new_row)); + } else { + error_row_cnt_++; + ATOMIC_INC(&job_stat_->detected_error_rows_); + } + return ret; +} + +int ObTableLoadErrorRowHandler::inner_append_repeated_row(const ObNewRow &row, + ObIArray &repeated_row_array) +{ + int ret = OB_SUCCESS; + ObNewRow new_row; + ObMutexGuard guard(append_row_mutex_); + if (repeated_row_cnt_ >= DEFAULT_REPEATED_ERROR_ROW_COUNT) { + ret = OB_ERR_TOO_MANY_ROWS; + LOG_WARN("repeated row count reaches its maximum value", K(ret), K(capacity_), + K(repeated_row_cnt_)); + } else if (OB_FAIL(ObTableLoadUtils::deep_copy(row, new_row, safe_allocator_))) { + LOG_WARN("failed to deep copy new row", K(ret), K(row)); + } else if (OB_FAIL(repeated_row_array.push_back(new_row))) { + LOG_WARN("failed to push back error row", K(ret), K(new_row)); + } else { + repeated_row_cnt_ ++; + } + return ret; +} + +int ObTableLoadErrorRowHandler::append_error_row(const ObNewRow &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_FAIL(inner_append_error_row(row, error_row_array_))) { + LOG_WARN("failed to append row to str error row array", K(ret), K(row)); + } + return ret; +} + +int ObTableLoadErrorRowHandler::append_error_row(const ObDatumRow &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else { + ObNewRow new_row; + ObObjBufArray obj_buf; + ObArenaAllocator allocator; + if (OB_FAIL(obj_buf.init(&allocator))) { + LOG_WARN("fail to init obj buf", KR(ret)); + } else if (OB_FAIL(obj_buf.reserve(row.count_))) { + LOG_WARN("Failed to reserve buf for obj buf", K(ret), K(row.count_)); + } else { + new_row.cells_ = obj_buf.get_data(); + new_row.count_ = row.count_; + for (int64_t i = 0; OB_SUCC(ret) && i < (*col_descs_).count(); i++) { + if (OB_FAIL(row.storage_datums_[i].to_obj_enhance(new_row.cells_[i], (*col_descs_).at(i).col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(row.storage_datums_[i])); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(inner_append_error_row(new_row, error_new_row_array_))) { + LOG_WARN("failed to append row to error row array", K(ret), K(new_row)); + } + } + } + } + return ret; +} + +int ObTableLoadErrorRowHandler::append_repeated_row(const common::ObNewRow &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else { + if (param_.dup_action_ == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + if (OB_FAIL(inner_append_error_row(row, error_row_array_))) { + LOG_WARN("failed to append row to error row array", K(ret), K(row)); + } + } else { + if (OB_FAIL(inner_append_repeated_row(row, repeated_row_array_))) { + LOG_WARN("failed to append row to error row array", K(ret), K(row)); + } + } + } + return ret; +} + +int ObTableLoadErrorRowHandler::append_repeated_row(const blocksstable::ObDatumRow &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else { + ObNewRow new_row; + ObObjBufArray obj_buf; + ObArenaAllocator allocator; + if (OB_FAIL(obj_buf.init(&allocator))) { + LOG_WARN("fail to init obj buf", KR(ret)); + } else if (OB_FAIL(obj_buf.reserve(row.count_))) { + LOG_WARN("Failed to reserve buf for obj buf", K(ret), K(row.count_)); + } else { + new_row.cells_ = obj_buf.get_data(); + new_row.count_ = row.count_; + for (int64_t i = 0; OB_SUCC(ret) && i < (*col_descs_).count(); i++) { + if (OB_FAIL(row.storage_datums_[i].to_obj_enhance(new_row.cells_[i], (*col_descs_).at(i).col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(row.storage_datums_[i])); + } + } + if (OB_SUCC(ret)) { + if (param_.dup_action_ == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + if (OB_FAIL(inner_append_error_row(new_row, error_new_row_array_))) { + LOG_WARN("failed to append row to error row array", K(ret), K(new_row)); + } + } else { + if (OB_FAIL(inner_append_repeated_row(new_row, repeated_new_row_array_))) { + LOG_WARN("failed to append row to error row array", K(ret), K(new_row)); + } + } + } + } + } + return ret; +} + +// TODO: convert each obj to string +int ObTableLoadErrorRowHandler::get_all_error_rows(ObTableLoadArray &obj_array) +{ + int ret = OB_NOT_IMPLEMENT; + return ret; +} + +int ObTableLoadErrorRowHandler::check_rowkey_order(int32_t session_id, const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(check_rowkey_order_time_us); + int ret = OB_SUCCESS; + int cmp_ret = 1; + ObTableLoadErrorRowHandler::PartitionRowkey *last_part_rowkey = nullptr; + ObDatumRowkey rowkey; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if ((session_id < 1) || (session_id > session_cnt_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid session id", K(session_id), K(session_cnt_)); + } else if (OB_FAIL(rowkey.assign(datum_row.storage_datums_, rowkey_column_num_))) { + LOG_WARN("failed to assign to rowkey", K(ret), KPC(datum_row.storage_datums_), + K(rowkey_column_num_)); + } else { + ObTableLoadErrorRowHandler::PartitionRowkeyMap &partition_map = + session_maps_.at(session_id - 1); + if (OB_FAIL(partition_map.map_.get_refactored(tablet_id, last_part_rowkey))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get refactored", KR(ret), K(tablet_id)); + } else { + // allocate a new last_part_rowkey for the new partition + if (OB_ISNULL(last_part_rowkey = OB_NEWx(ObTableLoadErrorRowHandler::PartitionRowkey, + (&(partition_map.allocator_))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to new ObDatumRowkey", KR(ret)); + } else if (OB_FAIL(partition_map.map_.set_refactored(tablet_id, last_part_rowkey))) { + LOG_WARN("fail to add last rowkey to map", KR(ret), K(session_id), K(tablet_id)); + } + } + } + if (OB_SUCC(ret)) { + ObDatumRowkey &last_rowkey = last_part_rowkey->last_rowkey_; + if (OB_FAIL(rowkey.compare(last_rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey to last rowkey", KR(ret), K(rowkey), K(last_rowkey)); + } else if (cmp_ret > 0) { + // free last rowkey + last_part_rowkey->allocator_.reuse(); + // overwrite last rowkey + // TODO: deep copy one row each batch instead of each row + if (OB_FAIL( + ObTableLoadUtils::deep_copy(rowkey, last_rowkey, last_part_rowkey->allocator_))) { + LOG_WARN("failed to deep copy rowkey to last rowkey", K(ret), K(rowkey), K(last_rowkey)); + } + } else if (cmp_ret == 0) { + ret = OB_ERR_PRIMARY_KEY_DUPLICATE; + LOG_WARN("rowkey == last rowkey", K(ret), K(cmp_ret), K(session_id), K(tablet_id), + K(last_rowkey), K(rowkey)); + } else { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_WARN("rowkey < last rowkey", K(ret), K(cmp_ret), K(session_id), K(tablet_id), + K(last_rowkey), K(rowkey)); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_error_row_handler.h b/src/observer/table_load/ob_table_load_error_row_handler.h new file mode 100644 index 0000000000..1ed3ca3f26 --- /dev/null +++ b/src/observer/table_load/ob_table_load_error_row_handler.h @@ -0,0 +1,96 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "common/row/ob_row.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" +#include "share/table/ob_table_load_row.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "storage/blocksstable/ob_datum_row.h" +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadTableCtx; + +class ObTableLoadErrorRowHandler +{ +public: + static const int64_t DEFAULT_REPEATED_ERROR_ROW_COUNT = 100; + ObTableLoadErrorRowHandler(); + ~ObTableLoadErrorRowHandler(); + int init(ObTableLoadTableCtx *const ctx); + int append_error_row(const common::ObNewRow &row); + int append_error_row(const blocksstable::ObDatumRow &row); + int append_repeated_row(const common::ObNewRow &row); + int append_repeated_row(const blocksstable::ObDatumRow &row); + int get_all_error_rows(table::ObTableLoadArray &obj_array); + uint64_t get_error_row_cnt() const { return error_row_cnt_; } + int check_rowkey_order(int32_t session_id, const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row); + sql::ObLoadDupActionType get_action() const {return param_.dup_action_;} + TO_STRING_KV(K_(capacity), K_(error_row_cnt), K_(repeated_row_cnt), K_(session_cnt), K_(is_inited)); +private: + int inner_append_error_row(const common::ObNewRow &row, + common::ObIArray &error_row_array); + int inner_append_repeated_row(const common::ObNewRow &row, + common::ObIArray &repeated_row_array); + class PartitionRowkey + { + public: + PartitionRowkey() : allocator_("TLD_err_chk") + { + allocator_.set_tenant_id(MTL_ID()); + last_rowkey_.set_min_rowkey(); + } + ~PartitionRowkey(); + TO_STRING_KV(K(last_rowkey_)); + public: + common::ObArenaAllocator allocator_; + blocksstable::ObDatumRowkey last_rowkey_; + }; + class PartitionRowkeyMap + { + public: + PartitionRowkeyMap() : map_() {} + ~PartitionRowkeyMap(); + PartitionRowkeyMap(const PartitionRowkeyMap &other) {} + PartitionRowkeyMap &operator=(const PartitionRowkeyMap &other) { return *this; } + TO_STRING_KV(K(map_.size())); + // all partitions are written sequentially within one session + // thus they can share the same allocator + common::ObArenaAllocator allocator_; + common::hash::ObHashMap map_; + }; +private: + observer::ObTableLoadParam param_; + sql::ObLoadDataStat *job_stat_; + const oceanbase::blocksstable::ObStorageDatumUtils *datum_utils_; + const common::ObIArray *col_descs_; + uint64_t capacity_; // maximum allowed error row count + int64_t rowkey_column_num_; + int32_t session_cnt_; + common::ObArray session_maps_; + common::ObArenaAllocator row_allocator_; //just for safe allocator + common::ObSafeArenaAllocator safe_allocator_; //该分配器是线程安全的 + mutable lib::ObMutex append_row_mutex_; + uint64_t error_row_cnt_; + uint64_t repeated_row_cnt_; + common::ObArray error_row_array_; + common::ObArray error_new_row_array_; + common::ObArray repeated_row_array_; + common::ObArray repeated_new_row_array_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_exec_ctx.cpp b/src/observer/table_load/ob_table_load_exec_ctx.cpp new file mode 100644 index 0000000000..f62e805eef --- /dev/null +++ b/src/observer/table_load/ob_table_load_exec_ctx.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_exec_ctx.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase +{ +namespace observer +{ +int ObTableLoadExecCtx::check_status() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(SS_STOPPING == GCTX.status_ || SS_STOPPED == GCTX.status_)) { + ret = OB_SERVER_IS_STOPPING; + LOG_WARN("observer is stopped", KR(ret), K(GCTX.status_)); + } else if (OB_FAIL(exec_ctx_->check_status())) { + LOG_WARN("fail to check exec ctx status", KR(ret)); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_exec_ctx.h b/src/observer/table_load/ob_table_load_exec_ctx.h new file mode 100644 index 0000000000..377a710748 --- /dev/null +++ b/src/observer/table_load/ob_table_load_exec_ctx.h @@ -0,0 +1,30 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "lib/allocator/ob_allocator.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExecContext; +} +namespace observer +{ +class ObTableLoadExecCtx +{ +public: + ObTableLoadExecCtx() : exec_ctx_(nullptr), allocator_(nullptr) {} + virtual ~ObTableLoadExecCtx() {}; + virtual int check_status(); + +public: + sql::ObExecContext *exec_ctx_; + common::ObIAllocator *allocator_; +}; + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_finish_processor.cpp b/src/observer/table_load/ob_table_load_finish_processor.cpp new file mode 100644 index 0000000000..5e4106b717 --- /dev/null +++ b/src/observer/table_load/ob_table_load_finish_processor.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_finish_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; + +/** + * ObTableLoadFinishP + */ + +int ObTableLoadFinishP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.finish())) { + LOG_WARN("fail to coordinator finish", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadFinishP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadPreMergePeerP + */ + +int ObTableLoadPreMergePeerP::deserialize() +{ + arg_.committed_trans_id_array_.set_allocator(allocator_); + return ParentType::deserialize(); +} + +int ObTableLoadPreMergePeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_merge(arg_.committed_trans_id_array_))) { + LOG_WARN("fail to store pre merge", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadPreMergePeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadStartMergePeerP + */ + +int ObTableLoadStartMergePeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.start_merge())) { + LOG_WARN("fail to store start merge", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadStartMergePeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_finish_processor.h b/src/observer/table_load/ob_table_load_finish_processor.h new file mode 100644 index 0000000000..4aab309ba1 --- /dev/null +++ b/src/observer/table_load/ob_table_load_finish_processor.h @@ -0,0 +1,75 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadFinishP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadFinishP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadFinishP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadFinishP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadPreMergePeerP : public obrpc::ObRpcProcessor > +{ + typedef obrpc::ObRpcProcessor > ParentType; +public: + explicit ObTableLoadPreMergePeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadPreMergePeerP() = default; + +protected: + int deserialize() override; + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPreMergePeerP); +private: + const ObGlobalContext &gctx_; + common::ObArenaAllocator allocator_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadStartMergePeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadStartMergePeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadStartMergePeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadStartMergePeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_general_table_compactor.cpp b/src/observer/table_load/ob_table_load_general_table_compactor.cpp new file mode 100644 index 0000000000..4e18a1af25 --- /dev/null +++ b/src/observer/table_load/ob_table_load_general_table_compactor.cpp @@ -0,0 +1,531 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_general_table_compactor.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "storage/direct_load/ob_direct_load_external_table_compactor.h" +#include "storage/direct_load/ob_direct_load_sstable_compactor.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace blocksstable; +using namespace common; +using namespace common::hash; +using namespace lib; +using namespace storage; +using namespace table; + +class ObTableLoadGeneralTableCompactor::CompactTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CompactTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadGeneralTableCompactor *compactor) + : ObITableLoadTaskProcessor(task), ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + CompactorTask *compactor_task = nullptr; + while (OB_SUCC(ret)) { + compactor_task = nullptr; + if (OB_FAIL(compactor_->get_next_compactor_task(compactor_task))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next compactor task", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_FAIL(compactor_task->process())) { + LOG_WARN("fail to process compactor task", KR(ret)); + } + if (nullptr != compactor_task) { + compactor_->handle_compactor_task_finish(compactor_task); + } + } + return ret; + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadGeneralTableCompactor *const compactor_; +}; + +class ObTableLoadGeneralTableCompactor::CompactTaskCallback : public ObITableLoadTaskCallback +{ +public: + CompactTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadGeneralTableCompactor *compactor) + : ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(compactor_->handle_compact_thread_finish(ret_code))) { + LOG_WARN("fail to handle compact thread finish", KR(ret)); + } + if (OB_FAIL(ret)) { + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadGeneralTableCompactor *const compactor_; +}; + +/** + * CompactorTask + */ + +ObTableLoadGeneralTableCompactor::CompactorTask::CompactorTask( + ObIDirectLoadTabletTableCompactor *table_compactor) + : table_compactor_(table_compactor) +{ +} + +ObTableLoadGeneralTableCompactor::CompactorTask::~CompactorTask() +{ +} + +int ObTableLoadGeneralTableCompactor::CompactorTask::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table_compactor_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null table compactor", KR(ret), KP(table_compactor_)); + } else if (OB_UNLIKELY(nullptr == table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else if (OB_FAIL(table_compactor_->add_table(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::CompactorTask::process() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table_compactor_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null table compactor", KR(ret), KP(table_compactor_)); + } else if (OB_FAIL(table_compactor_->compact())) { + LOG_WARN("fail to do compact", KR(ret)); + } + return ret; +} + +void ObTableLoadGeneralTableCompactor::CompactorTask::stop() +{ + if (OB_NOT_NULL(table_compactor_)) { + table_compactor_->stop(); + } +} + +/** + * CompactorTaskIter + */ + +ObTableLoadGeneralTableCompactor::CompactorTaskIter::CompactorTaskIter() + : pos_(0) +{ +} + +ObTableLoadGeneralTableCompactor::CompactorTaskIter::~CompactorTaskIter() +{ + reset(); +} + +void ObTableLoadGeneralTableCompactor::CompactorTaskIter::reset() +{ + for (int64_t i = 0; i < compactor_task_array_.count(); ++i) { + CompactorTask *compactor_task = compactor_task_array_.at(i); + compactor_task->~CompactorTask(); + } + compactor_task_array_.reset(); +} + +int ObTableLoadGeneralTableCompactor::CompactorTaskIter::add(CompactorTask *compactor_task) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == compactor_task)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(compactor_task)); + } else if (OB_FAIL(compactor_task_array_.push_back(compactor_task))) { + LOG_WARN("fail to push back", KR(ret)); + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::CompactorTaskIter::get_next_compactor_task( + CompactorTask *&compactor_task) +{ + int ret = OB_SUCCESS; + if (pos_ >= compactor_task_array_.count()) { + ret = OB_ITER_END; + } else { + compactor_task = compactor_task_array_.at(pos_++); + } + return ret; +} + +/** + * ObTableLoadGeneralTableCompactor + */ + +ObTableLoadGeneralTableCompactor::ObTableLoadGeneralTableCompactor() + : store_ctx_(nullptr), + param_(nullptr), + allocator_("TLD_GeneralTC"), + all_compactor_array_(OB_MALLOC_NORMAL_BLOCK_SIZE, ModulePageAllocator(allocator_)), + running_thread_count_(0), + has_error_(false), + is_stop_(false) +{ +} + +ObTableLoadGeneralTableCompactor::~ObTableLoadGeneralTableCompactor() +{ + reset(); +} + +void ObTableLoadGeneralTableCompactor::reset() +{ + abort_unless(compacting_list_.is_empty()); + store_ctx_ = nullptr; + param_ = nullptr; + for (int64_t i = 0; i < all_compactor_array_.count(); ++i) { + ObIDirectLoadTabletTableCompactor *compactor = all_compactor_array_.at(i); + compactor->~ObIDirectLoadTabletTableCompactor(); + allocator_.free(compactor); + } + all_compactor_array_.reset(); + compactor_task_iter_.reset(); + allocator_.reset(); + has_error_ = false; + is_stop_ = false; +} + +int ObTableLoadGeneralTableCompactor::inner_init() +{ + int ret = OB_SUCCESS; + store_ctx_ = compact_ctx_->store_ctx_; + param_ = &store_ctx_->ctx_->param_; + allocator_.set_tenant_id(MTL_ID()); + return ret; +} + +int ObTableLoadGeneralTableCompactor::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadGeneralTableCompactor not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(construct_compactors())) { + LOG_WARN("fail to construct compactors", KR(ret)); + } else if (OB_FAIL(start_compact())) { + LOG_WARN("fail to start compact", KR(ret)); + } + } + return ret; +} + +void ObTableLoadGeneralTableCompactor::stop() +{ + LOG_WARN("LOAD TABLE COMPACT STOP"); + is_stop_ = true; + // 遍历合并中的任务队列, 调用stop + ObMutexGuard guard(mutex_); + CompactorTask *compactor_task = nullptr; + DLIST_FOREACH_NORET(compactor_task, compacting_list_) + { + compactor_task->stop(); + } +} + +int ObTableLoadGeneralTableCompactor::construct_compactors() +{ + int ret = OB_SUCCESS; + ObArenaAllocator allocator; + CompactorTaskMap *compactor_task_map_array = nullptr; + ObSEArray trans_store_array; + if (OB_FAIL(store_ctx_->get_committed_trans_stores(trans_store_array))) { + LOG_WARN("fail to get committed trans stores", KR(ret)); + } else if (OB_ISNULL(compactor_task_map_array = static_cast( + allocator.alloc(sizeof(CompactorTaskMap) * param_->session_count_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + new (compactor_task_map_array) CompactorTaskMap[param_->session_count_]; + } + for (int64_t i = 0; OB_SUCC(ret) && i < param_->session_count_; ++i) { + CompactorTaskMap &compactor_map = compactor_task_map_array[i]; + if (OB_FAIL(compactor_map.create(1024, "TLD_CT_Map", "TLD_CT_Map", MTL_ID()))) { + LOG_WARN("fail to create compactor map", KR(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_store_array.count(); ++i) { + ObTableLoadTransStore *trans_store = trans_store_array.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_store->session_store_array_.count(); ++j) { + const ObTableLoadTransStore::SessionStore *session_store = + trans_store->session_store_array_.at(j); + CompactorTaskMap &compactor_map = compactor_task_map_array[session_store->session_id_ - 1]; + for (int64_t k = 0; OB_SUCC(ret) && k < session_store->partition_table_array_.count(); ++k) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(k); + if (OB_FAIL(add_tablet_table(session_store->session_id_, compactor_map, table))) { + LOG_WARN("fail to add tablet table", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + store_ctx_->clear_committed_trans_stores(); + } + if (nullptr != compactor_task_map_array) { + for (int64_t i = 0; i < param_->session_count_; ++i) { + CompactorTaskMap *compactor_map = compactor_task_map_array + i; + compactor_map->~CompactorTaskMap(); + } + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::add_tablet_table(int32_t session_id, + CompactorTaskMap &compactor_task_map, + ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + const ObTabletID &tablet_id = table->get_tablet_id(); + CompactorTask *compactor_task = nullptr; + if (OB_FAIL(compactor_task_map.get_refactored(tablet_id, compactor_task))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get refactored", KR(ret)); + } else { + ret = OB_SUCCESS; + if (OB_FAIL(create_tablet_compactor_task(session_id, tablet_id, compactor_task))) { + LOG_WARN("fail to create tablet compactor task", KR(ret)); + } else if (OB_FAIL(compactor_task_map.set_refactored(tablet_id, compactor_task))) { + LOG_WARN("fail to set refactored", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(compactor_task->add_table(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::create_tablet_table_compactor( + int32_t session_id, const ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&table_compactor) +{ + int ret = OB_SUCCESS; + table_compactor = nullptr; + if (store_ctx_->ctx_->schema_.is_heap_table_) { + ObDirectLoadExternalTableCompactParam compact_param; + compact_param.tablet_id_ = tablet_id; + compact_param.table_data_desc_ = store_ctx_->table_data_desc_; + ObDirectLoadExternalTableCompactor *external_table_compactor = nullptr; + if (OB_ISNULL(external_table_compactor = + OB_NEWx(ObDirectLoadExternalTableCompactor, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadExternalTableCompactor", KR(ret)); + } else if (OB_FAIL(external_table_compactor->init(compact_param))) { + LOG_WARN("fail to init external table compactor", KR(ret)); + } + table_compactor = external_table_compactor; + } else if (!param_->need_sort_) { + ObDirectLoadSSTableCompactParam compact_param; + compact_param.tablet_id_ = tablet_id; + compact_param.table_data_desc_ = store_ctx_->table_data_desc_; + compact_param.datum_utils_ = &(store_ctx_->ctx_->schema_.datum_utils_); + ObDirectLoadSSTableCompactor *sstable_compactor = nullptr; + if (OB_ISNULL(sstable_compactor = OB_NEWx(ObDirectLoadSSTableCompactor, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadSSTableCompactor", KR(ret)); + } else if (OB_FAIL(sstable_compactor->init(compact_param))) { + LOG_WARN("fail to init sstable compactor", KR(ret)); + } + table_compactor = sstable_compactor; + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table compactor", KR(ret)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(all_compactor_array_.push_back(table_compactor))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + if (OB_FAIL(ret)) { + if (nullptr != table_compactor) { + table_compactor->~ObIDirectLoadTabletTableCompactor(); + allocator_.free(table_compactor); + table_compactor = nullptr; + } + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::create_tablet_compactor_task(int32_t session_id, + const ObTabletID &tablet_id, + CompactorTask *&compactor_task) +{ + int ret = OB_SUCCESS; + compactor_task = nullptr; + ObIDirectLoadTabletTableCompactor *table_compactor = nullptr; + if (OB_FAIL(create_tablet_table_compactor(session_id, tablet_id, table_compactor))) { + LOG_WARN("fail to create tablet table compactor", KR(ret)); + } else if (OB_ISNULL(compactor_task = OB_NEWx(CompactorTask, (&allocator_), table_compactor))) { + LOG_WARN("fail to new CompactorTask", KR(ret)); + } else if (OB_FAIL(compactor_task_iter_.add(compactor_task))) { + LOG_WARN("fail to add compactor task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != compactor_task) { + compactor_task->~CompactorTask(); + compactor_task = nullptr; + } + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::start_compact() +{ + int ret = OB_SUCCESS; + const int64_t thread_count = store_ctx_->task_scheduler_->get_thread_count(); + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + for (int32_t thread_idx = 0; OB_SUCC(ret) && thread_idx < thread_count; ++thread_idx) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, this))) { + LOG_WARN("fail to set compact task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compact task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(thread_idx, task))) { + LOG_WARN("fail to add task", KR(ret), K(thread_idx), KPC(task)); + } + // 5. inc running_thread_count_ + else { + ATOMIC_INC(&running_thread_count_); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + } + if (OB_FAIL(ret)) { + has_error_ = true; + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::get_next_compactor_task(CompactorTask *&compactor_task) +{ + int ret = OB_SUCCESS; + compactor_task = nullptr; + if (OB_UNLIKELY(is_stop_ || has_error_)) { + ret = OB_ITER_END; + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(compactor_task_iter_.get_next_compactor_task(compactor_task))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next compactor task", KR(ret)); + } + } else { + OB_ASSERT(compacting_list_.add_last(compactor_task)); + } + } + return ret; +} + +void ObTableLoadGeneralTableCompactor::handle_compactor_task_finish(CompactorTask *compactor_task) +{ + ObMutexGuard guard(mutex_); + OB_ASSERT(OB_NOT_NULL(compacting_list_.remove(compactor_task))); +} + +int ObTableLoadGeneralTableCompactor::handle_compact_thread_finish(int ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + has_error_ = true; + } + const int64_t running_thread_count = ATOMIC_SAF(&running_thread_count_, 1); + if (0 == running_thread_count) { + if (OB_UNLIKELY(is_stop_ || has_error_)) { + } else { + LOG_INFO("LOAD TABLE COMPACT COMPLETED"); + if (OB_FAIL(build_result())) { + LOG_WARN("fail to build result", KR(ret)); + } else if (OB_FAIL(compact_ctx_->handle_table_compact_success())) { + LOG_WARN("fail to handle table compact success", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadGeneralTableCompactor::build_result() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + // get tables from table compactor + for (int64_t i = 0; OB_SUCC(ret) && i < all_compactor_array_.count(); ++i) { + ObIDirectLoadTabletTableCompactor *table_compactor = all_compactor_array_.at(i); + ObIDirectLoadPartitionTable *table = nullptr; + if (OB_FAIL(table_compactor->get_table(table, result.allocator_))) { + LOG_WARN("fail to get table from table compactor", KR(ret), KPC(table_compactor)); + } else if (OB_FAIL(result.add_table(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != table) { + table->~ObIDirectLoadPartitionTable(); + result.allocator_.free(table); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_general_table_compactor.h b/src/observer/table_load/ob_table_load_general_table_compactor.h new file mode 100644 index 0000000000..47211d9f97 --- /dev/null +++ b/src/observer/table_load/ob_table_load_general_table_compactor.h @@ -0,0 +1,82 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/list/ob_dlist.h" +#include "lib/lock/ob_mutex.h" +#include "observer/table_load/ob_table_load_table_compactor.h" +#include "storage/direct_load/ob_direct_load_i_table.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadParam; + +class ObTableLoadGeneralTableCompactor : public ObTableLoadTableCompactor +{ + class CompactTaskProcessor; + class CompactTaskCallback; +public: + ObTableLoadGeneralTableCompactor(); + virtual ~ObTableLoadGeneralTableCompactor(); + void reset(); + int start() override; + void stop() override; +private: + int inner_init() override; +private: + class CompactorTask : public common::ObDLinkBase + { + public: + CompactorTask(storage::ObIDirectLoadTabletTableCompactor *table_compactor); + ~CompactorTask(); + int add_table(storage::ObIDirectLoadPartitionTable *table); + int process(); + void stop(); + private: + storage::ObIDirectLoadTabletTableCompactor *table_compactor_; + }; + typedef common::hash::ObHashMap CompactorTaskMap; + class CompactorTaskIter + { + public: + CompactorTaskIter(); + ~CompactorTaskIter(); + void reset(); + int add(CompactorTask *compactor_task); + int get_next_compactor_task(CompactorTask *&compactor_task); + private: + common::ObSEArray compactor_task_array_; + int64_t pos_; + }; + int add_tablet_table(int32_t session_id, CompactorTaskMap &compactor_task_map, + storage::ObIDirectLoadPartitionTable *table); + int create_tablet_table_compactor(int32_t session_id, const common::ObTabletID &tablet_id, + storage::ObIDirectLoadTabletTableCompactor *&table_compactor); + int create_tablet_compactor_task(int32_t session_id, const common::ObTabletID &tablet_id, + CompactorTask *&compactor_task); +private: + int construct_compactors(); + int start_compact(); + int get_next_compactor_task(CompactorTask *&compactor_task); + void handle_compactor_task_finish(CompactorTask *compactor_task); + int handle_compact_thread_finish(int ret_code); + int build_result(); +private: + ObTableLoadStoreCtx *store_ctx_; + const ObTableLoadParam *param_; + common::ObArenaAllocator allocator_; + common::ObSEArray all_compactor_array_; + mutable lib::ObMutex mutex_; + CompactorTaskIter compactor_task_iter_; + common::ObDList compacting_list_; + int64_t running_thread_count_ CACHE_ALIGNED; + volatile bool has_error_; + volatile bool is_stop_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_get_status_processor.cpp b/src/observer/table_load/ob_table_load_get_status_processor.cpp new file mode 100644 index 0000000000..1c23e5a4d6 --- /dev/null +++ b/src/observer/table_load/ob_table_load_get_status_processor.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_get_status_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; + +/** + * ObTableLoadGetStatusP + */ + +int ObTableLoadGetStatusP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.get_status(result_.status_, result_.error_code_))) { + LOG_WARN("fail to coordinator get status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadGetStatusP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadGetStatusPeerP + */ + +int ObTableLoadGetStatusPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.get_status(result_.status_, result_.error_code_))) { + LOG_WARN("fail to store get status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadGetStatusPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_get_status_processor.h b/src/observer/table_load/ob_table_load_get_status_processor.h new file mode 100644 index 0000000000..064eda1138 --- /dev/null +++ b/src/observer/table_load/ob_table_load_get_status_processor.h @@ -0,0 +1,54 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadGetStatusP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadGetStatusP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadGetStatusP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadGetStatusP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadGetStatusPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadGetStatusPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadGetStatusPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadGetStatusPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_instance.cpp b/src/observer/table_load/ob_table_load_instance.cpp new file mode 100644 index 0000000000..87ddb95f46 --- /dev/null +++ b/src/observer/table_load/ob_table_load_instance.cpp @@ -0,0 +1,240 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_instance.h" +#include "share/table/ob_table_load_define.h" +#include "observer/table_load/ob_table_load_exec_ctx.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "sql/engine/ob_exec_context.h" + +namespace oceanbase +{ +using namespace table; +using namespace storage; +namespace observer +{ +ObTableLoadInstance::ObTableLoadInstance() + : allocator_(nullptr), + execute_ctx_(nullptr), + table_ctx_(nullptr), + coordinator_(nullptr), + job_stat_(nullptr), + px_mode_(false), + online_opt_stat_gather_(false), + sql_mode_(0), + is_inited_(false) +{ +} + +ObTableLoadInstance::~ObTableLoadInstance() +{ + destroy(); +} + +int ObTableLoadInstance::init(ObTableLoadParam ¶m, + const oceanbase::common::ObIArray &idx_array, + ObTableLoadExecCtx *execute_ctx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadInstance init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == execute_ctx->exec_ctx_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(execute_ctx)); + } else { + bool is_new = false; + allocator_ = execute_ctx->allocator_; + execute_ctx_ = execute_ctx; + px_mode_ = param.px_mode_; + online_opt_stat_gather_ = param.online_opt_stat_gather_; + sql_mode_ = param.sql_mode_; + ObTableLoadSegmentID segment_id(DEFAULT_SEGMENT_ID); + if (OB_FAIL(param.normalize())) { + LOG_WARN("fail to normalize param", KR(ret)); + } else if (OB_FAIL(next_sequence_no_array_.create(param.session_count_, *allocator_))) { + LOG_WARN("fail to create next sequence no array", KR(ret)); + } + // create table ctx + else if (OB_FAIL(ObTableLoadService::create_ctx(param, table_ctx_, is_new))) { + LOG_WARN("fail to create table load ctx", KR(ret), K(param)); + } else if (OB_UNLIKELY(!is_new)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("table load ctx exists", KR(ret)); + } else if (OB_FAIL( + ObTableLoadCoordinator::init_ctx(table_ctx_, idx_array, execute_ctx_->exec_ctx_->get_my_session()))) { + LOG_WARN("fail to coordinator init ctx", KR(ret)); + } + // new coordinator + else if (OB_ISNULL(coordinator_ = OB_NEWx(ObTableLoadCoordinator, allocator_, table_ctx_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadCoordinator", KR(ret)); + } else if (OB_FAIL(coordinator_->init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } + // begin + else if (OB_FAIL(coordinator_->begin())) { + LOG_WARN("fail to coordinator begin", KR(ret)); + } + // start trans + else if (!px_mode_ && OB_FAIL(coordinator_->start_trans(segment_id, trans_id_))) { + LOG_WARN("fail to coordinator start trans", KR(ret)); + } + // init succ + else { + for (int64_t i = 0; i < param.session_count_; ++i) { + next_sequence_no_array_[i] = 1; + } + job_stat_ = table_ctx_->job_stat_; + is_inited_ = true; + } + } + return ret; +} + +void ObTableLoadInstance::destroy() +{ + if (nullptr != coordinator_) { + if (coordinator_->is_valid()) { + ObTableLoadCoordinator::abort_ctx(table_ctx_); + } + coordinator_->~ObTableLoadCoordinator(); + allocator_->free(coordinator_); + coordinator_ = nullptr; + } + if (nullptr != table_ctx_) { + ObTableLoadService::remove_ctx(table_ctx_); + ObTableLoadService::put_ctx(table_ctx_); + table_ctx_ = nullptr; + job_stat_ = nullptr; + } +} + +int ObTableLoadInstance::check_trans_committed() +{ + int ret = OB_SUCCESS; + ObTableLoadTransStatusType trans_status = ObTableLoadTransStatusType::NONE; + int error_code = OB_SUCCESS; + while (OB_SUCC(ret) && ObTableLoadTransStatusType::COMMIT != trans_status && + OB_SUCC(execute_ctx_->check_status())) { + if (OB_FAIL(coordinator_->get_trans_status(trans_id_, trans_status, error_code))) { + LOG_WARN("fail to coordinator get trans status", KR(ret)); + } else{ + switch (trans_status) { + case ObTableLoadTransStatusType::FROZEN: + usleep(WAIT_INTERVAL_US); + break; + case ObTableLoadTransStatusType::COMMIT: + break; + case ObTableLoadTransStatusType::ERROR: + ret = error_code; + LOG_WARN("trans has error", KR(ret)); + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans status", KR(ret), K(trans_status)); + break; + } + } + } + return ret; +} + +int ObTableLoadInstance::check_merged() +{ + int ret = OB_SUCCESS; + ObTableLoadStatusType status = ObTableLoadStatusType::NONE; + int error_code = OB_SUCCESS; + while (OB_SUCC(ret) && ObTableLoadStatusType::MERGED != status && + OB_SUCC(execute_ctx_->check_status())) { + if (OB_FAIL(coordinator_->get_status(status, error_code))) { + LOG_WARN("fail to coordinator get status", KR(ret)); + } else { + switch (status) { + case ObTableLoadStatusType::FROZEN: + case ObTableLoadStatusType::MERGING: + usleep(WAIT_INTERVAL_US); + break; + case ObTableLoadStatusType::MERGED: + break; + case ObTableLoadStatusType::ERROR: + ret = error_code; + LOG_WARN("table load has error", KR(ret)); + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected status", KR(ret), K(status)); + break; + } + } + } + return ret; +} + +int ObTableLoadInstance::commit(ObTableLoadResultInfo &result_info) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadInstance not init", KR(ret), KP(this)); + } else if (!px_mode_) { + // finish trans + if (OB_FAIL(coordinator_->finish_trans(trans_id_))) { + LOG_WARN("fail to finish trans", KR(ret)); + } + // wait trans commit + else if (OB_FAIL(check_trans_committed())) { + LOG_WARN("fail to check trans committed", KR(ret)); + } + } + if (OB_SUCC(ret)) { + // finish + if (OB_FAIL(coordinator_->finish())) { + LOG_WARN("fail to finish", KR(ret)); + } + // wait merge + else if (OB_FAIL(check_merged())) { + LOG_WARN("fail to check merged", KR(ret)); + } + // commit + else if (OB_FAIL(coordinator_->commit(*execute_ctx_->exec_ctx_, result_info))) { + LOG_WARN("fail to commit", KR(ret)); + } + // sql statistics + else { + // Setting coordinator_ to NULL to mark a normal termination + coordinator_->~ObTableLoadCoordinator(); + allocator_->free(coordinator_); + coordinator_ = nullptr; + } + } + return ret; +} + +int ObTableLoadInstance::write(int32_t session_id, + const table::ObTableLoadObjRowArray &obj_rows) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadInstance not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(session_id < 0 || session_id > table_ctx_->param_.session_count_ || + obj_rows.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id), K(obj_rows.count())); + } else { + uint64_t &next_sequence_no = next_sequence_no_array_[session_id - 1]; + if (OB_FAIL(coordinator_->write(trans_id_, session_id, next_sequence_no++, obj_rows))) { + LOG_WARN("fail to write coordinator", KR(ret)); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_instance.h b/src/observer/table_load/ob_table_load_instance.h new file mode 100644 index 0000000000..a086ef293e --- /dev/null +++ b/src/observer/table_load/ob_table_load_instance.h @@ -0,0 +1,61 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "share/table/ob_table_load_row_array.h" +#include "share/table/ob_table_load_define.h" +#include "sql/engine/cmd/ob_load_data_utils.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadParam; +class ObTableLoadTableCtx; +class ObTableLoadCoordinator; +class ObTableLoadExecCtx; + +class ObTableLoadInstance +{ + static const int64_t WAIT_INTERVAL_US = 1LL * 1000 * 1000; // 1s +public: + ObTableLoadInstance(); + ~ObTableLoadInstance(); + int init(observer::ObTableLoadParam ¶m, + const oceanbase::common::ObIArray &idx_array, + observer::ObTableLoadExecCtx *execute_ctx); + void destroy(); + int commit(table::ObTableLoadResultInfo &result_info); + int write(int32_t session_id, const table::ObTableLoadObjRowArray &obj_rows); + sql::ObLoadDataStat *get_job_stat() const { return job_stat_; } + void update_job_stat_parsed_rows(int64_t parsed_rows) + { + ATOMIC_AAF(&job_stat_->parsed_rows_, parsed_rows); + } + void update_job_stat_parsed_bytes(int64_t parsed_bytes) + { + ATOMIC_AAF(&job_stat_->parsed_bytes_, parsed_bytes); + } +private: + int check_trans_committed(); + int check_merged(); +private: + static const int64_t DEFAULT_SEGMENT_ID = 1; + common::ObIAllocator *allocator_; + ObTableLoadExecCtx *execute_ctx_; + ObTableLoadTableCtx *table_ctx_; + ObTableLoadCoordinator *coordinator_; + table::ObTableLoadTransId trans_id_; + table::ObTableLoadArray next_sequence_no_array_; + sql::ObLoadDataStat *job_stat_; + bool px_mode_; + bool online_opt_stat_gather_; + uint64_t sql_mode_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObTableLoadInstance); +}; + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_manager.h b/src/observer/table_load/ob_table_load_manager.h new file mode 100644 index 0000000000..77022f28ac --- /dev/null +++ b/src/observer/table_load/ob_table_load_manager.h @@ -0,0 +1,150 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "lib/allocator/ob_malloc.h" +#include "lib/hash/ob_concurrent_hash_map.h" +#include "lib/lock/ob_mutex.h" +#include "lib/objectpool/ob_concurrency_objpool.h" +#include "observer/table_load/ob_table_load_struct.h" + +namespace oceanbase +{ +namespace observer +{ + +template +class ObTableLoadManager +{ +public: + int init(); + int put(const KeyType &key, ValueType *value); + int get(const KeyType &key, ValueType *&value); + int remove(const KeyType &key, ValueType *value); + void free_value(ValueType *value); + template + int new_and_insert(const KeyType &key, ValueType *&value, const Args&... args); + template + int get_or_new(const KeyType &key, ValueType *&value, bool &is_new, const Args&... args); + template + int for_each(Function &fn) { return value_map_.for_each(fn); } +private: + template + int new_value(const KeyType &key, ValueType *&value, const Args&... args); +private: + common::ObConcurrentHashMap value_map_; + lib::ObMutex mutex_; +}; + +template +int ObTableLoadManager::init() +{ + return value_map_.init(); +} + +template +int ObTableLoadManager::put(const KeyType &key, ValueType *value) +{ + return value_map_.put_refactored(key, value); +} + +template +int ObTableLoadManager::get(const KeyType &key, ValueType *&value) +{ + return value_map_.get_refactored(key, value); +} + +template +int ObTableLoadManager::remove(const KeyType &key, ValueType *value) +{ + return value_map_.remove_refactored(key); +} + +template +template +int ObTableLoadManager::new_value(const KeyType &key, ValueType *&value, + const Args&... args) +{ + int ret = common::OB_SUCCESS; + lib::ObMutexGuard guard(mutex_); + ret = get(key, value); + if (ret == common::OB_ENTRY_NOT_EXIST) { + ret = common::OB_SUCCESS; + if (OB_ISNULL(value = OB_NEW(ValueType, ObMemAttr(MTL_ID(), "TLD_MgrValue"), args...))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to new value", KR(ret), K(key)); + } else { + if (OB_FAIL(value->init())) { + OB_LOG(WARN, "fail to init value", KR(ret)); + } else if (OB_FAIL(put(key, value))) { + OB_LOG(WARN, "fail to put value", KR(ret)); + } + if (OB_FAIL(ret)) { + free_value(value); + value = nullptr; + } + } + } else if (ret != common::OB_SUCCESS) { + OB_LOG(WARN, "fail to get value", KR(ret)); + } else { // 已存在 + ret = common::OB_ENTRY_EXIST; + } + return ret; +} + +template +void ObTableLoadManager::free_value(ValueType *value) +{ + OB_DELETE(ValueType, "TLD_MgrValue", value); +} + +template +template +int ObTableLoadManager::new_and_insert(const KeyType &key, ValueType *&value, + const Args&... args) +{ + int ret = common::OB_SUCCESS; + ret = value_map_.contains_key(key); + if (OB_LIKELY(common::OB_ENTRY_NOT_EXIST == ret)) { + ret = new_value(key, value, args...); + } + if (OB_FAIL(ret)) { + if (OB_LIKELY(common::OB_ENTRY_EXIST == ret)) { + OB_LOG(WARN, "value already exist", KR(ret), K(key)); + } else { + OB_LOG(WARN, "fail to call contains key", KR(ret), K(key)); + } + } + return ret; +} + +template +template +int ObTableLoadManager::get_or_new(const KeyType &key, ValueType *&value, + bool &is_new, const Args&... args) +{ + int ret = common::OB_SUCCESS; + value = nullptr; + is_new = false; + ret = get(key, value); + if (common::OB_ENTRY_NOT_EXIST == ret) { + ret = common::OB_SUCCESS; + if (OB_FAIL(new_value(key, value, args...))) { + if (OB_UNLIKELY(common::OB_ENTRY_EXIST != ret)) { + OB_LOG(WARN, "fail to new value", KR(ret)); + } else { // 已存在 + ret = common::OB_SUCCESS; + } + } else { + is_new = true; + } + } else if (ret != common::OB_SUCCESS) { + OB_LOG(WARN, "fail to get value", KR(ret)); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_mem_compactor.cpp b/src/observer/table_load/ob_table_load_mem_compactor.cpp new file mode 100644 index 0000000000..79651d3cb1 --- /dev/null +++ b/src/observer/table_load/ob_table_load_mem_compactor.cpp @@ -0,0 +1,678 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_mem_compactor.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_mem_loader.h" +#include "storage/direct_load/ob_direct_load_mem_sample.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace storage; +using namespace table; +using namespace blocksstable; + +class ObTableLoadMemCompactor::SampleTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + SampleTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObDirectLoadMemContext *mem_ctx) + : ObITableLoadTaskProcessor(task), ctx_(ctx), mem_ctx_(mem_ctx) + { + ctx_->inc_ref_count(); + } + virtual ~SampleTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + storage::ObDirectLoadMemSample sample(mem_ctx_); + if (OB_FAIL(sample.do_sample())) { + LOG_WARN("fail to do sample", KR(ret)); + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObDirectLoadMemContext *mem_ctx_; +}; + +class ObTableLoadMemCompactor::CompactTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CompactTaskProcessor(ObTableLoadTask &task, + ObTableLoadTableCtx *ctx, + ObDirectLoadMemContext *mem_ctx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + mem_ctx_(mem_ctx) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + ObDirectLoadMemWorker *loader = nullptr; + mem_ctx_->mem_loader_queue_.pop_one(loader); + if (loader == nullptr) { + break; + } + if (OB_FAIL(loader->work())) { + LOG_WARN("fail to compact", KR(ret)); + } + loader->~ObDirectLoadMemWorker(); + loader = nullptr; + } + ATOMIC_AAF(&(mem_ctx_->finish_compact_count_), 1); + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObDirectLoadMemContext *mem_ctx_; +}; + +class ObTableLoadMemCompactor::CompactTaskCallback : public ObITableLoadTaskCallback +{ +public: + CompactTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadMemCompactor *compactor) + : ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = ret_code; + if (OB_SUCC(ret)) { + if (OB_FAIL(compactor_->handle_compact_task_finish(ret_code))) { + LOG_WARN("fail to handle_compact_task_finish", KR(ret)); + } + } + if (OB_FAIL(ret)) { + compactor_->set_has_error(); + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMemCompactor *const compactor_; +}; + +class ObTableLoadMemCompactor::FinishTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + FinishTaskProcessor(ObTableLoadTask &task, + ObTableLoadTableCtx *ctx, + ObTableLoadMemCompactor *compactor) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~FinishTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + return compactor_->finish(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMemCompactor *const compactor_; +}; + +class ObTableLoadMemCompactor::FinishTaskCallback : public ObITableLoadTaskCallback +{ +public: + FinishTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadMemCompactor *compactor) + : ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~FinishTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + compactor_->set_has_error(); + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMemCompactor *const compactor_; +}; + +class ObTableLoadMemCompactor::MemDumpTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + MemDumpTaskProcessor(ObTableLoadTask &task, + ObTableLoadTableCtx *ctx, + ObDirectLoadMemContext *mem_ctx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + mem_ctx_(mem_ctx) + { + ctx_->inc_ref_count(); + } + virtual ~MemDumpTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + void *tmp = nullptr; + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + if (OB_FAIL(mem_ctx_->mem_dump_queue_.pop(tmp))) { + LOG_WARN("fail to pop", KR(ret)); + } else { + if (tmp != nullptr) { + ObDirectLoadMemDump *mem_dump = (ObDirectLoadMemDump *)tmp; + if (OB_FAIL(mem_dump->do_dump())) { + LOG_WARN("fail to dump mem", KR(ret)); + } + mem_dump->~ObDirectLoadMemDump(); + ob_free(mem_dump); + } else { + if (OB_FAIL(mem_ctx_->mem_dump_queue_.push(nullptr))) { + LOG_WARN("fail to push", KR(ret)); + } else { + break; + } + } + } + } + return ret; + } +private: + ObTableLoadTableCtx *const ctx_; + ObDirectLoadMemContext *mem_ctx_; +}; + +ObTableLoadMemCompactor::ObTableLoadMemCompactor() + : store_ctx_(nullptr), + param_(nullptr), + allocator_("TLD_MemC"), + finish_task_count_(0), + task_scheduler_(nullptr), + parallel_merge_cb_(this) +{ +} + +ObTableLoadMemCompactor::~ObTableLoadMemCompactor() +{ + reset(); +} + +void ObTableLoadMemCompactor::reset() +{ + store_ctx_ = nullptr; + param_ = nullptr; + finish_task_count_ = 0; + + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + task_scheduler_->~ObITableLoadTaskScheduler(); + allocator_.free(task_scheduler_); + task_scheduler_ = nullptr; + } + mem_ctx_.reset(); + allocator_.reset(); +} + +int ObTableLoadMemCompactor::inner_init() +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + store_ctx_ = compact_ctx_->store_ctx_; + param_ = &(store_ctx_->ctx_->param_); + allocator_.set_tenant_id(tenant_id); + if (OB_FAIL(init_scheduler())) { + LOG_WARN("fail to init_scheduler", KR(ret)); + } else { + mem_ctx_.mem_dump_task_count_ = param_->session_count_ / 3; //暂时先写成1/3,后续再优化 + if (mem_ctx_.mem_dump_task_count_ == 0) { + mem_ctx_.mem_dump_task_count_ = 1; + } + mem_ctx_.table_data_desc_ = store_ctx_->table_data_desc_; + mem_ctx_.datum_utils_ = &(store_ctx_->ctx_->schema_.datum_utils_); + mem_ctx_.need_sort_ = param_->need_sort_; + mem_ctx_.mem_load_task_count_ = param_->session_count_; + mem_ctx_.column_count_ = param_->column_count_; + mem_ctx_.error_row_handler_ = store_ctx_->error_row_handler_; + mem_ctx_.file_mgr_ = store_ctx_->tmp_file_mgr_; + mem_ctx_.result_info_ = &(store_ctx_->result_info_); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(mem_ctx_.init())) { + LOG_WARN("fail to init compactor ctx", KR(ret)); + } else if (OB_FAIL(parallel_merge_ctx_.init(store_ctx_))) { + LOG_WARN("fail to init parallel merge ctx", KR(ret)); + } + } + + return ret; +} + +int ObTableLoadMemCompactor::init_scheduler() +{ + int ret = OB_SUCCESS; + // 初始化task_scheduler_ + if (OB_ISNULL(task_scheduler_ = OB_NEWx(ObTableLoadTaskThreadPoolScheduler, (&allocator_), + 1, allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTaskThreadPoolScheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->init())) { + LOG_WARN("fail to init task scheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->start())) { + LOG_WARN("fail to start task scheduler", KR(ret)); + } + return ret; +} + +int ObTableLoadMemCompactor::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadMemCompactor not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(construct_compactors())) { + LOG_WARN("fail to construct compactors", KR(ret)); + } else if (OB_FAIL(start_compact())) { + LOG_WARN("fail to start compact", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMemCompactor::construct_compactors() +{ + int ret = OB_SUCCESS; + ObSEArray trans_store_array; + if (OB_FAIL(store_ctx_->get_committed_trans_stores(trans_store_array))) { + LOG_WARN("fail to get committed trans stores", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_store_array.count(); ++i) { + ObTableLoadTransStore *trans_store = trans_store_array.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_store->session_store_array_.count(); ++j) { + const ObTableLoadTransStore::SessionStore *session_store = trans_store->session_store_array_.at(j); + for (int64_t k = 0; OB_SUCC(ret) && k < session_store->partition_table_array_.count(); ++k) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(k); + if (OB_FAIL(add_tablet_table(table))) { + LOG_WARN("fail to add tablet table", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + store_ctx_->clear_committed_trans_stores(); + } + return ret; +} + +int ObTableLoadMemCompactor::add_tablet_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + ObDirectLoadMemLoader *loader = nullptr; + if (OB_FAIL(create_mem_loader(loader))) { + LOG_WARN("fail to create tablet table compactor", KR(ret)); + } else if (OB_FAIL(mem_ctx_.mem_loader_queue_.push(loader))) { + LOG_WARN("fail to push", KR(ret)); + } else if (OB_FAIL(loader->add_table(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMemCompactor::create_mem_loader(ObDirectLoadMemLoader *&mem_loader) +{ + int ret = OB_SUCCESS; + mem_loader = nullptr; + if (OB_ISNULL(mem_loader = + OB_NEWx(ObDirectLoadMemLoader, (&allocator_), &mem_ctx_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMemLoader", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != mem_loader) { + mem_loader->~ObDirectLoadMemLoader(); + allocator_.free(mem_loader); + mem_loader = nullptr; + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_sample() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, &mem_ctx_))) { + LOG_WARN("fail to set compactor task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compactor task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(task_scheduler_->add_task(0, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_dump() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + for (int64_t i = 0; OB_SUCC(ret) && i < mem_ctx_.mem_dump_task_count_; i ++) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, &mem_ctx_))) { + LOG_WARN("fail to set compactor task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compactor task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(param_->session_count_ - mem_ctx_.mem_dump_task_count_ + i, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_finish() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, this))) { + LOG_WARN("fail to set compactor task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compactor task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(0, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_load() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + for (int32_t session_id = 1; OB_SUCC(ret) && session_id <= get_compact_task_count(); ++session_id) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, &mem_ctx_))) { + LOG_WARN("fail to set compact task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compact task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_compact() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(start_load())) { + LOG_WARN("fail to start load", KR(ret)); + } else if (OB_FAIL(start_sample())) { + LOG_WARN("fail to start sample", KR(ret)); + } else if (OB_FAIL(start_dump())) { + LOG_WARN("fail to start dump", KR(ret)); + } + if (OB_FAIL(ret)) { + set_has_error(); + } + return ret; +} + +void ObTableLoadMemCompactor::stop() +{ + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + } + set_has_error(); //先设置为error,因为stop的场景就是error +} + +int64_t ObTableLoadMemCompactor::get_compact_task_count() const +{ + return param_->session_count_ - mem_ctx_.mem_dump_task_count_; +} + +int ObTableLoadMemCompactor::handle_compact_task_finish(int ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + } else { + const int64_t finish_task_count = ATOMIC_AAF(&finish_task_count_, 1); + int64_t task_to_wait = param_->session_count_ + 1; // one for sample task + if (task_to_wait == finish_task_count) { + if (OB_LIKELY(!(mem_ctx_.has_error_)) && OB_FAIL(start_finish())) { + LOG_WARN("fail to start finish", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadMemCompactor::finish() +{ + int ret = OB_SUCCESS; + if (mem_ctx_.table_data_desc_.is_heap_table_) { + if (OB_FAIL(build_result_for_heap_table())) { + LOG_WARN("fail to build result", KR(ret)); + } else if (OB_FAIL(compact_ctx_->handle_table_compact_success())) { + LOG_WARN("fail to handle_table_compact_success", KR(ret)); + } + } else { + if (OB_FAIL(add_table_to_parallel_merge_ctx())) { + LOG_WARN("fail to build result", KR(ret)); + } else if (OB_FAIL(start_parallel_merge())) { + LOG_WARN("fail to start parallel merge", KR(ret)); + } + } + if (OB_SUCC(ret)) { + mem_ctx_.reset(); // mem_ctx的tables已经copy,需要提前释放 + } + return ret; +} + +int ObTableLoadMemCompactor::build_result_for_heap_table() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + for (int64_t i = 0; OB_SUCC(ret) && i < mem_ctx_.tables_.count(); i++) { + ObIDirectLoadPartitionTable *table = mem_ctx_.tables_.at(i); + ObDirectLoadExternalTable *external_table = nullptr; + ObDirectLoadExternalTable *copied_external_table = nullptr; + if (OB_ISNULL(external_table = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), KPC(table)); + } else if (OB_ISNULL(copied_external_table = + OB_NEWx(ObDirectLoadExternalTable, (&result.allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new external table", KR(ret)); + } else if (OB_FAIL(copied_external_table->copy(*external_table))) { + LOG_WARN("fail to copy external table", KR(ret)); + } else if (OB_FAIL(result.add_table(copied_external_table))) { + LOG_WARN("fail to add tablet sstable", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != copied_external_table) { + copied_external_table->~ObDirectLoadExternalTable(); + copied_external_table = nullptr; + } + } + } + return ret; +} + +int ObTableLoadMemCompactor::add_table_to_parallel_merge_ctx() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + for (int64_t i = 0; OB_SUCC(ret) && i < mem_ctx_.tables_.count(); i++) { + ObIDirectLoadPartitionTable *table = mem_ctx_.tables_.at(i); + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), KPC(table)); + } else if (OB_FAIL(parallel_merge_ctx_.add_tablet_sstable(sstable))) { + LOG_WARN("fail to add tablet sstable", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMemCompactor::start_parallel_merge() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(parallel_merge_ctx_.start(¶llel_merge_cb_))) { + LOG_WARN("fail to start parallel merge", KR(ret)); + } + return ret; +} + +int ObTableLoadMemCompactor::ParallelMergeCb::on_success() +{ + return compactor_->handle_merge_success(); +} + +int ObTableLoadMemCompactor::handle_merge_success() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(build_result())) { + LOG_WARN("fail to build result", KR(ret)); + } else { + ret = compact_ctx_->handle_table_compact_success(); + } + return ret; +} + +int ObTableLoadMemCompactor::build_result() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + const ObTableLoadParallelMergeCtx::TabletCtxMap &tablet_ctx_map = + parallel_merge_ctx_.get_tablet_ctx_map(); + for (ObTableLoadParallelMergeCtx::TabletCtxIterator tablet_ctx_iter = tablet_ctx_map.begin(); + OB_SUCC(ret) && tablet_ctx_iter != tablet_ctx_map.end(); ++tablet_ctx_iter) { + ObTableLoadParallelMergeTabletCtx *tablet_ctx = tablet_ctx_iter->second; + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ctx->sstables_.size(); ++i) { + ObDirectLoadMultipleSSTable *sstable = tablet_ctx->sstables_.at(i); + ObDirectLoadMultipleSSTable *copied_sstable = nullptr; + if (OB_ISNULL(copied_sstable = OB_NEWx(ObDirectLoadMultipleSSTable, (&result.allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTable", KR(ret)); + } else if (OB_FAIL(copied_sstable->copy(*sstable))) { + LOG_WARN("fail to copy sstable", KR(ret)); + } else if (OB_FAIL(result.add_table(copied_sstable))) { + LOG_WARN("fail to add table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != copied_sstable) { + copied_sstable->~ObDirectLoadMultipleSSTable(); + result.allocator_.free(copied_sstable); + } + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_mem_compactor.h b/src/observer/table_load/ob_table_load_mem_compactor.h new file mode 100644 index 0000000000..99e3c86344 --- /dev/null +++ b/src/observer/table_load/ob_table_load_mem_compactor.h @@ -0,0 +1,91 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_table_compactor.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_mem_define.h" +#include "storage/direct_load/ob_direct_load_multi_map.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "observer/table_load/ob_table_load_parallel_merge_ctx.h" + +namespace oceanbase +{ +namespace storage +{ + class ObDirectLoadMemDump; + class ObDirectLoadMemLoader; +} + +namespace observer +{ +class ObTableLoadParam; +class ObITableLoadTaskScheduler; + +class ObTableLoadMemCompactor : public ObTableLoadTableCompactor +{ + class CompactTaskProcessor; + class CompactTaskCallback; + class SampleTaskProcessor; + class MemDumpTaskProcessor; + class MemDumpTaskCallback; + class FinishTaskProcessor; + class FinishTaskCallback; + +public: + ObTableLoadMemCompactor(); + virtual ~ObTableLoadMemCompactor(); + void reset(); + int start() override; + void stop() override; + + void set_has_error() + { + mem_ctx_.has_error_ = true; + } + +private: + class ParallelMergeCb : public ObTableLoadParallelMergeCb + { + public: + ParallelMergeCb(ObTableLoadMemCompactor *compactor) : compactor_(compactor) {} + int on_success() override; + private: + ObTableLoadMemCompactor *compactor_; + }; + +private: + int inner_init() override; + int construct_compactors(); + int start_compact(); + int start_load(); + int start_sample(); + int start_dump(); + int start_finish(); + int handle_compact_task_finish(int ret_code); + int handle_merge_success(); + int build_result(); + int add_table_to_parallel_merge_ctx(); + int init_scheduler(); + int finish(); + int start_parallel_merge(); + int build_result_for_heap_table(); +private: + int add_tablet_table(storage::ObIDirectLoadPartitionTable *table); + int create_mem_loader(ObDirectLoadMemLoader *&mem_loader); + int64_t get_compact_task_count() const; +private: + ObTableLoadStoreCtx *store_ctx_; + const ObTableLoadParam *param_; + common::ObArenaAllocator allocator_; //需要最后析构 + int64_t finish_task_count_ CACHE_ALIGNED; + ObITableLoadTaskScheduler *task_scheduler_; + ObDirectLoadMemContext mem_ctx_; + ObTableLoadParallelMergeCtx parallel_merge_ctx_; + ParallelMergeCb parallel_merge_cb_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_merger.cpp b/src/observer/table_load/ob_table_load_merger.cpp new file mode 100644 index 0000000000..0833feca8b --- /dev/null +++ b/src/observer/table_load/ob_table_load_merger.cpp @@ -0,0 +1,433 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_merger.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table.h" +#include "storage/direct_load/ob_direct_load_multi_map.h" +#include "storage/direct_load/ob_direct_load_range_splitter.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace lib; +using namespace storage; +using namespace blocksstable; +using namespace table; + +class ObTableLoadMerger::MergeTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + MergeTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObTableLoadMerger *merger) + : ObITableLoadTaskProcessor(task), ctx_(ctx), merger_(merger) + { + ctx_->inc_ref_count(); + } + virtual ~MergeTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(merge_time_us); + int ret = OB_SUCCESS; + ObDirectLoadPartitionMergeTask *merge_task = nullptr; + while (OB_SUCC(ret)) { + merge_task = nullptr; + if (OB_FAIL(merger_->get_next_merge_task(merge_task))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next compactor task", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_FAIL(merge_task->process())) { + LOG_WARN("fail to process merge task", KR(ret)); + } + if (nullptr != merge_task) { + merger_->handle_merge_task_finish(merge_task); + } + } + return ret; + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMerger *const merger_; +}; + +class ObTableLoadMerger::MergeTaskCallback : public ObITableLoadTaskCallback +{ +public: + MergeTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadMerger *merger) + : ctx_(ctx), merger_(merger) + { + ctx_->inc_ref_count(); + } + virtual ~MergeTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(merger_->handle_merge_thread_finish(ret_code))) { + LOG_WARN("fail to handle merge thread finish", KR(ret)); + } + if (OB_FAIL(ret)) { + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMerger *const merger_; +}; + +/** + * ObTableLoadMerger + */ + +ObTableLoadMerger::ObTableLoadMerger(ObTableLoadStoreCtx *store_ctx) + : store_ctx_(store_ctx), + param_(store_ctx->ctx_->param_), + allocator_("TLD_TLdMerge"), + running_thread_count_(0), + has_error_(false), + is_stop_(false), + is_inited_(false) +{ +} + +ObTableLoadMerger::~ObTableLoadMerger() +{ + abort_unless(merging_list_.is_empty()); +} + +int ObTableLoadMerger::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadMerger init twice", KR(ret), KP(this)); + } else { + if (OB_FAIL(table_compact_ctx_.init(store_ctx_, *this))) { + LOG_WARN("fail to init table compact ctx", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadMerger::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadMerger not init", KR(ret), KP(this)); + } else { + if (store_ctx_->is_fast_heap_table_) { + if (OB_FAIL(build_merge_ctx())) { + LOG_WARN("fail to build merge ctx", KR(ret)); + } else if (OB_FAIL(start_merge())) { + LOG_WARN("fail to start merge", KR(ret)); + } + } else { + if (OB_FAIL(table_compact_ctx_.start())) { + LOG_WARN("fail to start compact table", KR(ret)); + } + } + } + return ret; +} + +void ObTableLoadMerger::stop() +{ + LOG_WARN("LOAD MERGE STOP"); + is_stop_ = true; + // 停止table合并 + table_compact_ctx_.stop(); + // 遍历合并中的任务队列, 调用stop + ObMutexGuard guard(mutex_); + ObDirectLoadPartitionMergeTask *merge_task = nullptr; + DLIST_FOREACH_NORET(merge_task, merging_list_) { + merge_task->stop(); + } +} + +int ObTableLoadMerger::handle_table_compact_success() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(is_stop_)) { + } else { + if (OB_FAIL(build_merge_ctx())) { + LOG_WARN("fail to build merge ctx", KR(ret)); + } else if (OB_FAIL(start_merge())) { + LOG_WARN("fail to start merge", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMerger::build_merge_ctx() +{ + int ret = OB_SUCCESS; + ObDirectLoadMergeParam merge_param; + merge_param.table_id_ = param_.table_id_; + merge_param.target_table_id_ = param_.target_table_id_; + merge_param.rowkey_column_num_ = store_ctx_->ctx_->schema_.rowkey_column_count_; + merge_param.schema_column_count_ = + (store_ctx_->ctx_->schema_.is_heap_table_ ? store_ctx_->table_data_desc_.column_count_ + 1 + : store_ctx_->table_data_desc_.column_count_); + merge_param.table_data_desc_ = store_ctx_->table_data_desc_; + merge_param.datum_utils_ = &(store_ctx_->ctx_->schema_.datum_utils_); + merge_param.col_descs_ = &(store_ctx_->ctx_->schema_.column_descs_); + merge_param.is_heap_table_ = store_ctx_->ctx_->schema_.is_heap_table_; + merge_param.is_fast_heap_table_ = store_ctx_->is_fast_heap_table_; + merge_param.online_opt_stat_gather_ = param_.online_opt_stat_gather_; + merge_param.insert_table_ctx_ = store_ctx_->insert_table_ctx_; + merge_param.error_row_handler_ = store_ctx_->error_row_handler_; + merge_param.result_info_ = &(store_ctx_->result_info_); + if (OB_FAIL(merge_ctx_.init(merge_param, store_ctx_->ls_partition_ids_, + store_ctx_->target_ls_partition_ids_))) { + LOG_WARN("fail to init merge ctx", KR(ret)); + } else if (store_ctx_->is_multiple_mode_) { + const ObIArray &tablet_merge_ctxs = + merge_ctx_.get_tablet_merge_ctxs(); + ObArray empty_table_array; + ObIArray *table_array = nullptr; + if (table_compact_ctx_.result_.tablet_result_map_.size() > 0) { + abort_unless(1 == table_compact_ctx_.result_.tablet_result_map_.size()); + ObTableLoadTableCompactResult::TabletResultMap::Iterator iter( + table_compact_ctx_.result_.tablet_result_map_); + ObTableLoadTableCompactTabletResult *tablet_result = nullptr; + if (OB_ISNULL(tablet_result = iter.next(tablet_result))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null tablet result", KR(ret)); + } else { + table_array = &tablet_result->table_array_; + } + } else { + table_array = &empty_table_array; + } + if (!merge_param.is_heap_table_ && !table_array->empty()) { + ObArray multiple_sstable_array; + ObDirectLoadMultipleMergeRangeSplitter range_splitter; + for (int64_t i = 0; OB_SUCC(ret) && i < table_array->count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table_array->at(i)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), K(table_array)); + } else if (OB_FAIL(multiple_sstable_array.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(range_splitter.init(multiple_sstable_array, merge_param.table_data_desc_, + merge_param.datum_utils_, *merge_param.col_descs_))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_merge_ctxs.count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_merge_ctx = tablet_merge_ctxs.at(i); + if (OB_FAIL(tablet_merge_ctx->build_merge_task_for_multiple_pk_table( + multiple_sstable_array, range_splitter, param_.session_count_))) { + LOG_WARN("fail to build merge task for multiple pk table", KR(ret)); + } + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_merge_ctxs.count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_merge_ctx = tablet_merge_ctxs.at(i); + if (OB_FAIL(tablet_merge_ctx->build_merge_task( + *table_array, store_ctx_->ctx_->schema_.column_descs_, param_.session_count_, + store_ctx_->is_multiple_mode_))) { + LOG_WARN("fail to build merge task", KR(ret)); + } + } + } + } else { + ObArray empty_table_array; + const ObIArray &tablet_merge_ctxs = + merge_ctx_.get_tablet_merge_ctxs(); + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_merge_ctxs.count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_merge_ctx = tablet_merge_ctxs.at(i); + ObTableLoadTableCompactTabletResult *tablet_result = nullptr; + ObIArray *table_array = nullptr; + if (OB_FAIL(table_compact_ctx_.result_.tablet_result_map_.get( + tablet_merge_ctx->get_tablet_id(), tablet_result))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get tablet result", KR(ret)); + } else { + ret = OB_SUCCESS; + table_array = &empty_table_array; + } + } else { + table_array = &tablet_result->table_array_; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_merge_ctx->build_merge_task( + *table_array, store_ctx_->ctx_->schema_.column_descs_, param_.session_count_, + store_ctx_->is_multiple_mode_))) { + LOG_WARN("fail to build merge task", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(merge_task_iter_.init(&merge_ctx_))) { + LOG_WARN("fail to init merge task iter", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMerger::collect_sql_statistics(ObTableLoadSqlStatistics &sql_statistics) +{ + int ret = OB_SUCCESS; + if (store_ctx_->is_fast_heap_table_) { + ObDirectLoadMultiMap tables; + ObArray trans_store_array; + if (OB_FAIL(tables.init())) { + LOG_WARN("fail to init table", KR(ret)); + } else if (OB_FAIL(store_ctx_->get_committed_trans_stores(trans_store_array))) { + LOG_WARN("fail to get trans store", KR(ret)); + } else { + for (int i = 0; OB_SUCC(ret) && i < trans_store_array.count(); ++i) { + ObTableLoadTransStore *trans_store = trans_store_array.at(i); + for (int j = 0; OB_SUCC(ret) && j < trans_store->session_store_array_.count(); ++j) { + ObTableLoadTransStore::SessionStore * session_store = trans_store->session_store_array_.at(j); + for (int k = 0 ; OB_SUCC(ret) && k < session_store->partition_table_array_.count(); ++k) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(k); + ObDirectLoadFastHeapTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected not heap sstable", KR(ret), KPC(table)); + } else { + const ObTabletID &tablet_id = sstable->get_tablet_id(); + if (OB_FAIL(tables.add(tablet_id, sstable))) { + LOG_WARN("fail to add tables", KR(ret), KPC(sstable)); + } + } + } + } + } + for (int i = 0; OB_SUCC(ret) && i < merge_ctx_.get_tablet_merge_ctxs().count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_ctx = merge_ctx_.get_tablet_merge_ctxs().at(i); + ObArray heap_table_array ; + if (OB_FAIL(tables.get(tablet_ctx->get_tablet_id(), heap_table_array))) { + LOG_WARN("get heap sstable failed", KR(ret)); + } else if (OB_FAIL(tablet_ctx->collect_sql_statistics(heap_table_array, sql_statistics))) { + LOG_WARN("fail to collect sql statics", KR(ret)); + } + } + } + } else { + for (int i = 0; OB_SUCC(ret) && i < merge_ctx_.get_tablet_merge_ctxs().count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_ctx = merge_ctx_.get_tablet_merge_ctxs().at(i); + ObArray heap_table_array ; + if (OB_FAIL(tablet_ctx->collect_sql_statistics(heap_table_array, sql_statistics))) { + LOG_WARN("fail to collect sql statics", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadMerger::start_merge() +{ + int ret = OB_SUCCESS; + const int64_t thread_count = store_ctx_->task_scheduler_->get_thread_count(); + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + for (int32_t thread_idx = 0; OB_SUCC(ret) && thread_idx < thread_count; ++thread_idx) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, this))) { + LOG_WARN("fail to set merge task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set merge task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(thread_idx, task))) { + LOG_WARN("fail to add task", KR(ret), K(thread_idx), KPC(task)); + } + // 5. inc running_thread_count_ + else { + ATOMIC_INC(&running_thread_count_); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + } + if (OB_FAIL(ret)) { + has_error_ = true; + } + return ret; +} + +int ObTableLoadMerger::get_next_merge_task(ObDirectLoadPartitionMergeTask *&merge_task) +{ + int ret = OB_SUCCESS; + merge_task = nullptr; + if (OB_UNLIKELY(is_stop_ || has_error_)) { + ret = OB_ITER_END; + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(merge_task_iter_.get_next_task(merge_task))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next merger", KR(ret)); + } + } else { + OB_ASSERT(merging_list_.add_last(merge_task)); + } + } + return ret; +} + +void ObTableLoadMerger::handle_merge_task_finish(ObDirectLoadPartitionMergeTask *&merge_task) +{ + ObMutexGuard guard(mutex_); + OB_ASSERT(OB_NOT_NULL(merging_list_.remove(merge_task))); +} + +int ObTableLoadMerger::handle_merge_thread_finish(int ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + has_error_ = true; + } + const int64_t running_thread_count = ATOMIC_SAF(&running_thread_count_, 1); + if (0 == running_thread_count) { + if (OB_UNLIKELY(is_stop_ || has_error_)) { + } else { + LOG_INFO("LOAD MERGE COMPLETED"); + if (OB_FAIL(store_ctx_->set_status_merged())) { + LOG_WARN("fail to set store status merged", KR(ret)); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_merger.h b/src/observer/table_load/ob_table_load_merger.h new file mode 100644 index 0000000000..8c201c7e81 --- /dev/null +++ b/src/observer/table_load/ob_table_load_merger.h @@ -0,0 +1,55 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/lock/ob_mutex.h" +#include "observer/table_load/ob_table_load_table_compactor.h" +#include "share/table/ob_table_load_define.h" +#include "storage/direct_load/ob_direct_load_merge_ctx.h" +#include "storage/direct_load/ob_direct_load_merge_task_iterator.h" +#include "storage/direct_load/ob_direct_load_partition_merge_task.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadParam; +class ObTableLoadStoreCtx; + +class ObTableLoadMerger +{ + class MergeTaskProcessor; + class MergeTaskCallback; +public: + ObTableLoadMerger(ObTableLoadStoreCtx *store_ctx); + ~ObTableLoadMerger(); + int init(); + int start(); + void stop(); + int handle_table_compact_success(); + int collect_sql_statistics(table::ObTableLoadSqlStatistics &sql_statistics); +private: + int build_merge_ctx(); + int start_merge(); + int get_next_merge_task(storage::ObDirectLoadPartitionMergeTask *&merge_task); + void handle_merge_task_finish(storage::ObDirectLoadPartitionMergeTask *&merge_task); + int handle_merge_thread_finish(int ret_code); +private: + ObTableLoadStoreCtx * const store_ctx_; + const ObTableLoadParam ¶m_; + ObTableLoadTableCompactCtx table_compact_ctx_; + storage::ObDirectLoadMergeCtx merge_ctx_; + mutable lib::ObMutex mutex_; + ObDirectLoadMergeTaskIterator merge_task_iter_; + common::ObDList merging_list_; + common::ObArenaAllocator allocator_; + int64_t running_thread_count_ CACHE_ALIGNED; + volatile bool has_error_; + volatile bool is_stop_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.cpp b/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.cpp new file mode 100644 index 0000000000..8e5e10c229 --- /dev/null +++ b/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.cpp @@ -0,0 +1,527 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_multiple_heap_table_compactor.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_builder.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace storage; +using namespace table; +using namespace blocksstable; + + +/** + * ObTableLoadMultipleHeapTableCompactCompare + */ + +ObTableLoadMultipleHeapTableCompactCompare::ObTableLoadMultipleHeapTableCompactCompare() + : result_code_(OB_SUCCESS) +{ +} + +ObTableLoadMultipleHeapTableCompactCompare::~ObTableLoadMultipleHeapTableCompactCompare() +{ +} + +bool ObTableLoadMultipleHeapTableCompactCompare::operator()( + const ObDirectLoadMultipleHeapTable *lhs, + const ObDirectLoadMultipleHeapTable *rhs) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(lhs), K(rhs)); + } else { + cmp_ret = lhs->get_meta().index_entry_count_ - rhs->get_meta().index_entry_count_; + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } + return cmp_ret < 0; +} + +/** + * ObTableLoadMultipleHeapTableCompactor + */ + +class ObTableLoadMultipleHeapTableCompactor::CompactTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CompactTaskProcessor(ObTableLoadTask &task, + ObTableLoadTableCtx *ctx, + ObDirectLoadMemContext *mem_ctx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + mem_ctx_(mem_ctx), + index_dir_id_(-1), + data_dir_id_(-1) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskProcessor() + { + for (int64_t i = 0; i < heap_table_array_.count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = heap_table_array_.at(i); + heap_table->~ObDirectLoadMultipleHeapTable(); + } + heap_table_array_.reset(); + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + // alloc dir id + if (OB_FAIL(mem_ctx_->file_mgr_->alloc_dir(index_dir_id_))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } else if (OB_FAIL(mem_ctx_->file_mgr_->alloc_dir(data_dir_id_))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } + // build heap table array + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + ObDirectLoadMemWorker *worker = nullptr; + mem_ctx_->mem_loader_queue_.pop_one(worker); + if (worker == nullptr) { + break; + } + ObDirectLoadMultipleHeapTableSorter *sorter = + dynamic_cast(worker); + if (OB_ISNULL(sorter)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected worker", KR(ret), KPC(worker)); + } else if (FALSE_IT(sorter->set_work_param(index_dir_id_, data_dir_id_, heap_table_array_, + heap_table_allocator_))) { + } else if (OB_FAIL(sorter->work())) { + LOG_WARN("fail to compact", KR(ret)); + } + worker->~ObDirectLoadMemWorker(); + } + // compact heap table array + if (OB_SUCC(ret) && !heap_table_array_.empty()) { + // TODO(suzhi.yt) optimize single heap table + if (OB_FAIL(compact_heap_table())) { + LOG_WARN("fail to compact heap table", KR(ret)); + } + } + return ret; + } +private: + int compact_heap_table() + { + int ret = OB_SUCCESS; + ObArray tmp_heap_table_array; + ObArray *curr_round = &heap_table_array_; + ObArray *next_round = &tmp_heap_table_array; + ObDirectLoadMultipleHeapTableCompactParam heap_table_compact_param; + ObDirectLoadMultipleHeapTableCompactor heap_table_compactor; + heap_table_compact_param.table_data_desc_ = mem_ctx_->table_data_desc_; + heap_table_compact_param.file_mgr_ = mem_ctx_->file_mgr_; + heap_table_compact_param.index_dir_id_ = index_dir_id_; + if (OB_FAIL(heap_table_compactor.init(heap_table_compact_param))) { + LOG_WARN("fail to init heap table compactor", KR(ret)); + } + while (OB_SUCC(ret) && + curr_round->count() > mem_ctx_->table_data_desc_.merge_count_per_round_) { + if (OB_FAIL(compact_heap_table_one_round(heap_table_compactor, curr_round, next_round))) { + LOG_WARN("fail to compact heap table one round", KR(ret)); + } else { + heap_table_compactor.reuse(); + std::swap(curr_round, next_round); + } + } + if (OB_SUCC(ret)) { + abort_unless(curr_round->count() > 0 && + curr_round->count() <= mem_ctx_->table_data_desc_.merge_count_per_round_); + for (int64_t i = 0; OB_SUCC(ret) && i < curr_round->count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = curr_round->at(i); + if (OB_FAIL(heap_table_compactor.add_table(heap_table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(heap_table_compactor.compact())) { + LOG_WARN("fail to do compact", KR(ret)); + } else if (OB_FAIL(mem_ctx_->add_tables_from_table_compactor(heap_table_compactor))) { + LOG_WARN("fail to add table from table compactor", KR(ret)); + } + } + } + // release heap table array + for (int64_t i = 0; i < curr_round->count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = curr_round->at(i); + heap_table->~ObDirectLoadMultipleHeapTable(); + } + curr_round->reset(); + for (int64_t i = 0; i < next_round->count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = next_round->at(i); + heap_table->~ObDirectLoadMultipleHeapTable(); + } + next_round->reset(); + return ret; + } + int compact_heap_table_one_round(ObDirectLoadMultipleHeapTableCompactor &heap_table_compactor, + ObArray *curr_round, + ObArray *next_round) + { + int ret = OB_SUCCESS; + // sort heap table array + ObTableLoadMultipleHeapTableCompactCompare compare; + std::sort(curr_round->begin(), curr_round->end(), compare); + // compact top merge_count_per_round heap table + for (int64_t i = 0; OB_SUCC(ret) && i < mem_ctx_->table_data_desc_.merge_count_per_round_; + ++i) { + ObDirectLoadMultipleHeapTable *heap_table = curr_round->at(i); + if (OB_FAIL(heap_table_compactor.add_table(heap_table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObIDirectLoadPartitionTable *compacted_table = nullptr; + ObDirectLoadMultipleHeapTable *compacted_heap_table = nullptr; + if (OB_FAIL(heap_table_compactor.compact())) { + LOG_WARN("fail to do compact", KR(ret)); + } else if (OB_FAIL(heap_table_compactor.get_table(compacted_table, allocator_))) { + LOG_WARN("fail to get table", KR(ret)); + } else if (OB_ISNULL(compacted_heap_table = + dynamic_cast(compacted_table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(compacted_table)); + } else if (OB_FAIL(next_round->push_back(compacted_heap_table))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != compacted_table) { + compacted_table->~ObIDirectLoadPartitionTable(); + allocator_.free(compacted_table); + compacted_table = nullptr; + } + } + } + if (OB_SUCC(ret)) { + for (int64_t i = mem_ctx_->table_data_desc_.merge_count_per_round_; + OB_SUCC(ret) && i < curr_round->count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = curr_round->at(i); + if (OB_FAIL(next_round->push_back(heap_table))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + if (OB_FAIL(ret)) { + // clear next round + ObDirectLoadMultipleHeapTable *compacted_heap_table = next_round->at(0); + compacted_heap_table->~ObDirectLoadMultipleHeapTable(); + next_round->reset(); + } + } + if (OB_SUCC(ret)) { + // clear current round + for (int64_t i = 0; i < mem_ctx_->table_data_desc_.merge_count_per_round_; ++i) { + ObDirectLoadMultipleHeapTable *heap_table = curr_round->at(i); + heap_table->~ObDirectLoadMultipleHeapTable(); + } + curr_round->reset(); + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObDirectLoadMemContext *mem_ctx_; + int64_t index_dir_id_; + int64_t data_dir_id_; + ObArenaAllocator heap_table_allocator_; + ObArray heap_table_array_; +}; + +class ObTableLoadMultipleHeapTableCompactor::CompactTaskCallback : public ObITableLoadTaskCallback +{ +public: + CompactTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadMultipleHeapTableCompactor *compactor) + : ctx_(ctx), compactor_(compactor) + { + ctx_->inc_ref_count(); + } + virtual ~CompactTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = ret_code; + if (OB_SUCC(ret)) { + if (OB_FAIL(compactor_->handle_compact_task_finish(ret_code))) { + LOG_WARN("fail to handle_compact_task_finish", KR(ret)); + } + } + if (OB_FAIL(ret)) { + compactor_->set_has_error(); + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadMultipleHeapTableCompactor *const compactor_; +}; + +ObTableLoadMultipleHeapTableCompactor::ObTableLoadMultipleHeapTableCompactor() + : store_ctx_(nullptr), + param_(nullptr), + allocator_("TLD_MemC"), + finish_task_count_(0) +{ +} + +ObTableLoadMultipleHeapTableCompactor::~ObTableLoadMultipleHeapTableCompactor() +{ + reset(); +} + +void ObTableLoadMultipleHeapTableCompactor::reset() +{ + store_ctx_ = nullptr; + param_ = nullptr; + finish_task_count_ = 0; + mem_ctx_.reset(); + allocator_.reset(); +} + +int ObTableLoadMultipleHeapTableCompactor::inner_init() +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + store_ctx_ = compact_ctx_->store_ctx_; + param_ = &(store_ctx_->ctx_->param_); + allocator_.set_tenant_id(tenant_id); + + mem_ctx_.mem_dump_task_count_ = param_->session_count_ / 3; //暂时先写成1/3,后续再优化 + if (mem_ctx_.mem_dump_task_count_ == 0) { + mem_ctx_.mem_dump_task_count_ = 1; + } + mem_ctx_.table_data_desc_ = store_ctx_->table_data_desc_; + mem_ctx_.datum_utils_ = &(store_ctx_->ctx_->schema_.datum_utils_); + mem_ctx_.need_sort_ = param_->need_sort_; + mem_ctx_.mem_load_task_count_ = param_->session_count_; + mem_ctx_.column_count_ = param_->column_count_; + mem_ctx_.error_row_handler_ = store_ctx_->error_row_handler_; + mem_ctx_.file_mgr_ = store_ctx_->tmp_file_mgr_; + mem_ctx_.result_info_ = &(store_ctx_->result_info_); + + if (OB_SUCC(ret)) { + if (OB_FAIL(mem_ctx_.init())) { + LOG_WARN("fail to init compactor ctx", KR(ret)); + } + } + + return ret; +} + + +int ObTableLoadMultipleHeapTableCompactor::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadMultipleHeapTableCompactor not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(construct_compactors())) { + LOG_WARN("fail to construct compactors", KR(ret)); + } else if (OB_FAIL(start_compact())) { + LOG_WARN("fail to start compact", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::construct_compactors() +{ + int ret = OB_SUCCESS; + ObSEArray trans_store_array; + if (OB_FAIL(store_ctx_->get_committed_trans_stores(trans_store_array))) { + LOG_WARN("fail to get committed trans stores", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_store_array.count(); ++i) { + ObTableLoadTransStore *trans_store = trans_store_array.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_store->session_store_array_.count(); ++j) { + const ObTableLoadTransStore::SessionStore *session_store = trans_store->session_store_array_.at(j); + for (int64_t k = 0; OB_SUCC(ret) && k < session_store->partition_table_array_.count(); ++k) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(k); + if (OB_FAIL(add_tablet_table(table))) { + LOG_WARN("fail to add tablet table", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + store_ctx_->clear_committed_trans_stores(); + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::add_tablet_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + ObDirectLoadMultipleHeapTableSorter *sorter = nullptr; + if (OB_FAIL(create_heap_table_sorter(sorter))) { + LOG_WARN("fail to create tablet table compactor", KR(ret)); + } else if (OB_FAIL(mem_ctx_.mem_loader_queue_.push(sorter))) { + LOG_WARN("fail to push", KR(ret)); + } else if (OB_FAIL(sorter->add_table(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::create_heap_table_sorter(ObDirectLoadMultipleHeapTableSorter *&heap_table_sorter) +{ + int ret = OB_SUCCESS; + heap_table_sorter = nullptr; + if (OB_ISNULL(heap_table_sorter = + OB_NEWx(ObDirectLoadMultipleHeapTableSorter, (&allocator_), &mem_ctx_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleHeapTableSorter", KR(ret)); + } else if (OB_FAIL(heap_table_sorter->init())) { + LOG_WARN("fail to init sorter", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != heap_table_sorter) { + heap_table_sorter->~ObDirectLoadMultipleHeapTableSorter(); + allocator_.free(heap_table_sorter); + heap_table_sorter = nullptr; + } + } + return ret; +} + + +int ObTableLoadMultipleHeapTableCompactor::start_sort() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *ctx = store_ctx_->ctx_; + for (int32_t session_id = 1; OB_SUCC(ret) && session_id <= param_->session_count_; ++session_id) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx, &mem_ctx_))) { + LOG_WARN("fail to set compact task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx, this))) { + LOG_WARN("fail to set compact task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx->free_task(task); + } + } + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::start_compact() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(start_sort())) { + LOG_WARN("fail to start load", KR(ret)); + } + if (OB_FAIL(ret)) { + set_has_error(); + } + return ret; +} + +void ObTableLoadMultipleHeapTableCompactor::stop() +{ + set_has_error(); //先设置为error,因为stop的场景就是error +} + +int ObTableLoadMultipleHeapTableCompactor::handle_compact_task_finish(int ret_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + } else { + const int64_t finish_task_count = ATOMIC_AAF(&finish_task_count_, 1); + int64_t task_to_wait = param_->session_count_; + if (task_to_wait == finish_task_count) { + if (OB_LIKELY(!(mem_ctx_.has_error_)) && OB_FAIL(finish())) { + LOG_WARN("fail to start finish", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::finish() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(build_result_for_heap_table())) { + LOG_WARN("fail to build result", KR(ret)); + } else if (OB_FAIL(compact_ctx_->handle_table_compact_success())) { + LOG_WARN("fail to handle_table_compact_success", KR(ret)); + } + if (OB_SUCC(ret)) { + mem_ctx_.reset(); // mem_ctx的tables已经copy,需要提前释放 + } + return ret; +} + +int ObTableLoadMultipleHeapTableCompactor::build_result_for_heap_table() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + for (int64_t i = 0; OB_SUCC(ret) && i < mem_ctx_.tables_.count(); i++) { + ObIDirectLoadPartitionTable *table = mem_ctx_.tables_.at(i); + ObDirectLoadMultipleHeapTable *multi_heap_sstable = nullptr; + ObDirectLoadMultipleHeapTable *copied_multi_heap_sstable = nullptr; + if (OB_ISNULL(multi_heap_sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), KPC(table)); + } else if (OB_ISNULL(copied_multi_heap_sstable = + OB_NEWx(ObDirectLoadMultipleHeapTable, (&result.allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new external table", KR(ret)); + } else if (OB_FAIL(copied_multi_heap_sstable->copy(*multi_heap_sstable))) { + LOG_WARN("fail to copy external table", KR(ret)); + } else if (OB_FAIL(result.add_table(copied_multi_heap_sstable))) { + LOG_WARN("fail to add tablet sstable", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != copied_multi_heap_sstable) { + copied_multi_heap_sstable->~ObDirectLoadMultipleHeapTable(); + copied_multi_heap_sstable = nullptr; + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.h b/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.h new file mode 100644 index 0000000000..7a0437b86d --- /dev/null +++ b/src/observer/table_load/ob_table_load_multiple_heap_table_compactor.h @@ -0,0 +1,74 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_table_compactor.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_mem_define.h" +#include "storage/direct_load/ob_direct_load_multi_map.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h" + +namespace oceanbase +{ +namespace storage +{ + class ObDirectLoadMemDump; +} + +namespace observer +{ +class ObTableLoadParam; +class ObITableLoadTaskScheduler; + +class ObTableLoadMultipleHeapTableCompactCompare +{ +public: + ObTableLoadMultipleHeapTableCompactCompare(); + ~ObTableLoadMultipleHeapTableCompactCompare(); + bool operator()(const storage::ObDirectLoadMultipleHeapTable *lhs, + const storage::ObDirectLoadMultipleHeapTable *rhs); + int get_error_code() const { return result_code_; } + int result_code_; +}; + +class ObTableLoadMultipleHeapTableCompactor : public ObTableLoadTableCompactor +{ + class CompactTaskProcessor; + class CompactTaskCallback; + +public: + ObTableLoadMultipleHeapTableCompactor(); + virtual ~ObTableLoadMultipleHeapTableCompactor(); + void reset(); + int start() override; + void stop() override; + + void set_has_error() + { + mem_ctx_.has_error_ = true; + } + +private: + int inner_init() override; + int construct_compactors(); + int start_compact(); + int start_sort(); + int finish(); + int handle_compact_task_finish(int ret_code); + int build_result_for_heap_table(); +private: + int add_tablet_table(storage::ObIDirectLoadPartitionTable *table); + int create_heap_table_sorter(ObDirectLoadMultipleHeapTableSorter *&heap_table_sorter); +private: + ObTableLoadStoreCtx *store_ctx_; + const ObTableLoadParam *param_; + common::ObArenaAllocator allocator_; //需要最后析构 + int64_t finish_task_count_ CACHE_ALIGNED; + ObDirectLoadMemContext mem_ctx_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_obj_cast.cpp b/src/observer/table_load/ob_table_load_obj_cast.cpp new file mode 100644 index 0000000000..689c559b44 --- /dev/null +++ b/src/observer/table_load/ob_table_load_obj_cast.cpp @@ -0,0 +1,354 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_obj_cast.h" +#include "observer/table_load/ob_table_load_time_convert.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "sql/engine/expr/ob_expr_util.h" +#include "sql/resolver/expr/ob_raw_expr_util.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace sql; + +const ObObj ObTableLoadObjCaster::zero_obj(0); +const ObObj ObTableLoadObjCaster::null_obj(ObObjType::ObNullType); + +int ObTableLoadObjCaster::cast_obj(ObTableLoadCastObjCtx &cast_obj_ctx, + const ObColumnSchemaV2 *column_schema, const ObObj &src, + ObObj &dst) +{ + int ret = OB_SUCCESS; + const ObObj *convert_src_obj = nullptr; + const ObObjType expect_type = column_schema->get_meta_type().get_type(); + const ObAccuracy &accuracy = column_schema->get_accuracy(); + if (OB_FAIL(convert_obj(expect_type, src, convert_src_obj))) { + LOG_WARN("fail to convert obj", KR(ret)); + } + + if (OB_SUCC(ret)) { + if (column_schema->is_enum_or_set()) { + if (OB_FAIL(handle_string_to_enum_set(cast_obj_ctx, column_schema, src, dst))) { + LOG_WARN("fail to convert string to enum or set", KR(ret), K(src), K(dst)); + } + } else { + if (OB_FAIL(to_type(expect_type, cast_obj_ctx, accuracy, *convert_src_obj, dst))) { + LOG_WARN("fail to do to type", KR(ret)); + } + } + } + + if (OB_SUCC(ret)) { + if (cast_obj_ctx.is_need_check_ && + OB_FAIL(cast_obj_check(cast_obj_ctx, column_schema, dst))) { + LOG_WARN("fail to check cast obj result", KR(ret), K(dst)); + } + } + return ret; +} + +int ObTableLoadObjCaster::convert_obj(const ObObjType &expect_type, const ObObj &src, + const ObObj *&dest) +{ + int ret = OB_SUCCESS; + dest = &src; + if (!src.is_null() && lib::is_mysql_mode() && 0 == src.get_val_len() && !ob_is_string_tc(expect_type)) { + dest = &zero_obj; + } else if (lib::is_oracle_mode() && (src.is_null_oracle() || 0 == src.get_val_len())) { + dest = &null_obj; + } + return ret; +} + +int ObTableLoadObjCaster::handle_string_to_enum_set(ObTableLoadCastObjCtx &cast_obj_ctx, + const ObColumnSchemaV2 *column_schema, + const ObObj &src, ObObj &dst) +{ + int ret = OB_SUCCESS; + int warning = 0; + uint64_t output_value = 0; + const ObIArray &type_infos = column_schema->get_extended_type_info(); + const ObCollationType collation_type = column_schema->get_collation_type(); + const ObObjType expect_type = column_schema->get_meta_type().get_type(); + ObCastMode cast_mode = cast_obj_ctx.cast_ctx_->cast_mode_; + if (src.is_null()) { + dst.set_null(); + } else if (expect_type == ObEnumType) { + if (OB_FAIL(string_to_enum(*(cast_obj_ctx.cast_ctx_->allocator_v2_), src, collation_type, + cast_mode, type_infos, warning, output_value))) { + LOG_WARN("fail to convert string to enum", KR(ret), K(src), K(type_infos), K(output_value)); + } else { + dst.set_enum(output_value); + } + } else if (expect_type == ObSetType) { + if (OB_FAIL(string_to_set(*(cast_obj_ctx.cast_ctx_->allocator_v2_), src, collation_type, + cast_mode, type_infos, warning, output_value))) { + LOG_WARN("fail to convert string to set", KR(ret), K(src), K(type_infos), K(output_value)); + } else { + dst.set_set(output_value); + } + } + return ret; +} + +int ObTableLoadObjCaster::string_to_enum(ObIAllocator &alloc, const ObObj &src, + const ObCollationType cs_type, + const common::ObCastMode cast_mode, + const ObIArray &str_values, int &warning, + uint64_t &output_value) +{ + int ret = OB_SUCCESS; + uint64_t value = 0; + int32_t pos = 0; + ObString in_str; + const ObCollationType in_cs_type = src.get_collation_type(); + const ObString orig_in_str = src.get_string(); + OZ(ObCharset::charset_convert(alloc, orig_in_str, in_cs_type, cs_type, in_str)); + int32_t no_sp_len = + static_cast(ObCharset::strlen_byte_no_sp(cs_type, in_str.ptr(), in_str.length())); + ObString no_sp_val(0, static_cast(no_sp_len), in_str.ptr()); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(find_type(str_values, cs_type, no_sp_val, pos))) { + LOG_WARN("fail to find type", K(str_values), K(cs_type), K(no_sp_val), K(in_str), K(pos), + K(ret)); + } else if (OB_UNLIKELY(pos < 0)) { + // Bug30666903: check implicit cast logic to handle number cases + if (!in_str.is_numeric()) { + ret = OB_ERR_DATA_TRUNCATED; + } else { + int err = 0; + int64_t val_cnt = str_values.count(); + value = ObCharset::strntoull(in_str.ptr(), in_str.length(), 10, &err); + if (err != 0 || value > val_cnt) { + value = 0; + ret = OB_ERR_DATA_TRUNCATED; + LOG_WARN("input value out of range", K(val_cnt), K(ret), K(err)); + } + if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) { + warning = ret; + ret = OB_SUCCESS; + } + } + } else { + value = pos + 1; // enum start from 1 + } + output_value = value; + LOG_DEBUG("finish string_enum", K(ret), K(in_str), K(str_values), K(output_value), K(lbt())); + return ret; +} + +int ObTableLoadObjCaster::string_to_set(ObIAllocator &alloc, const ObObj &src, + const ObCollationType cs_type, + const common::ObCastMode cast_mode, + const ObIArray &str_values, int &warning, + uint64_t &output_value) +{ + int ret = OB_SUCCESS; + uint64_t value = 0; + ObString in_str; + const ObCollationType in_cs_type = src.get_collation_type(); + const ObString orig_in_str = src.get_string(); + OZ(ObCharset::charset_convert(alloc, orig_in_str, in_cs_type, cs_type, in_str)); + if (OB_FAIL(ret)) { + } else if (in_str.empty()) { + // do noting + } else { + bool is_last_value = false; + const ObString &sep = ObCharsetUtils::get_const_str(cs_type, ','); + int32_t pos = 0; + const char *remain = in_str.ptr(); + int64_t remain_len = ObCharset::strlen_byte_no_sp(cs_type, in_str.ptr(), in_str.length()); + ObString val_str; + do { + pos = 0; + const char *sep_loc = NULL; + if (NULL == (sep_loc = static_cast( + memmem(remain, remain_len, sep.ptr(), sep.length())))) { + is_last_value = true; + val_str.assign_ptr(remain, remain_len); + if (OB_FAIL(find_type(str_values, cs_type, val_str, pos))) { + LOG_WARN("fail to find type", K(str_values), K(cs_type), K(in_str), K(pos), K(ret)); + } + } else { + val_str.assign_ptr(remain, sep_loc - remain); + remain_len = remain_len - (sep_loc - remain + sep.length()); + remain = sep_loc + sep.length(); + if (OB_FAIL(find_type(str_values, cs_type, val_str, pos))) { + LOG_WARN("fail to find type", K(str_values), K(cs_type), K(val_str), K(pos), K(ret)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_UNLIKELY(pos < 0)) { // not found + if (CM_IS_WARN_ON_FAIL(cast_mode)) { + warning = OB_ERR_DATA_TRUNCATED; + LOG_INFO("input value out of range, and set out value zero", K(pos), K(val_str), + K(in_str), K(warning)); + } else { + ret = OB_ERR_DATA_TRUNCATED; + LOG_WARN("data truncate", K(pos), K(val_str), K(in_str), K(ret)); + } + } else { + pos %= 64; // MySQL中,如果value存在重复,则value_count可以大于64 + value |= (1ULL << pos); + } + } while (OB_SUCC(ret) && !is_last_value); + } + + // Bug30666903: check implicit cast logic to handle number cases + if (in_str.is_numeric() && (OB_ERR_DATA_TRUNCATED == ret || (OB_ERR_DATA_TRUNCATED == warning && + CM_IS_WARN_ON_FAIL(cast_mode)))) { + int err = 0; + value = ObCharset::strntoull(in_str.ptr(), in_str.length(), 10, &err); + if (err == 0) { + ret = OB_SUCCESS; + uint32_t val_cnt = str_values.count(); + if (OB_UNLIKELY(val_cnt <= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect val_cnt", K(val_cnt), K(ret)); + } else if (val_cnt >= 64) { // do nothing + } else if (val_cnt < 64 && value > ((1ULL << val_cnt) - 1)) { + value = 0; + ret = OB_ERR_DATA_TRUNCATED; + LOG_WARN("input value out of range", K(val_cnt), K(ret)); + } + if (OB_FAIL(ret) && CM_IS_WARN_ON_FAIL(cast_mode)) { + warning = OB_ERR_DATA_TRUNCATED; + ret = OB_SUCCESS; + } + } else { + value = 0; + } + } + + output_value = value; + LOG_DEBUG("finish string_set", K(ret), K(in_str), K(str_values), K(output_value), K(lbt())); + return ret; +} + +int ObTableLoadObjCaster::to_type(const ObObjType &expect_type, ObTableLoadCastObjCtx &cast_obj_ctx, + const ObAccuracy &accuracy, const ObObj &src, ObObj &dst) +{ + int ret = OB_SUCCESS; + ObCastCtx cast_ctx = *cast_obj_ctx.cast_ctx_; + const ObTableLoadTimeConverter time_cvrt = *cast_obj_ctx.time_cvrt_; + if (src.is_null()) { + dst.set_null(); + } else if (src.get_type() == expect_type && expect_type != ObVarcharType && + expect_type != ObCharType && !ob_is_nstring_type(expect_type)) { + dst = src; + } else if (src.get_type_class() == ObStringTC && + (expect_type == ObNumberType || expect_type == ObUNumberType)) { + ObNumberDesc d(0); + uint32_t *digits = nullptr; + cast_obj_ctx.number_fast_ctx_.reset(); + ObString tmp_str; + if (OB_FAIL(src.get_varchar(tmp_str))) { + LOG_WARN("fail to get varchar", KR(ret), K(src)); + } else if (OB_FAIL(number_fast_from(tmp_str.ptr(), tmp_str.length(), cast_ctx.allocator_v2_, d, + digits, accuracy, cast_obj_ctx.number_fast_ctx_))) { + if (ret == OB_EAGAIN) { + if (OB_FAIL(ObObjCaster::to_type(expect_type, cast_ctx, src, dst))) { + LOG_WARN("fail to cast ObObj", KR(ret), K(src), K(expect_type)); + } + } else { + LOG_WARN("fail to cast ObObj", KR(ret), K(src), K(expect_type)); + } + } else { + dst.set_number(expect_type, d, digits); + } + } else if (expect_type == ObDateTimeType && lib::is_oracle_mode()) { + ObCastMode cast_mode = cast_obj_ctx.cast_ctx_->cast_mode_; + if (OB_FAIL(string_datetime_oracle(expect_type, cast_ctx, src, dst, cast_mode, time_cvrt))) { + LOG_WARN("fail to convert string to datetime in oracle mode", KR(ret), K(src), + K(expect_type)); + } + } else { + if (expect_type == ObJsonType) { + cast_ctx.cast_mode_ |= CM_ERROR_ON_SCALE_OVER; + } + if (OB_FAIL(ObObjCaster::to_type(expect_type, cast_ctx, src, dst))) { + LOG_WARN("fail to cast ObObj", KR(ret), K(src), K(expect_type)); + } + } + return ret; +} + +int ObTableLoadObjCaster::cast_obj_check(ObTableLoadCastObjCtx &cast_obj_ctx, + const ObColumnSchemaV2 *column_schema, ObObj &obj) +{ + int ret = OB_SUCCESS; + const ObObj *res_obj = &obj; + ObCollationType collation_type = column_schema->get_collation_type(); + const ObAccuracy &accuracy = column_schema->get_accuracy(); + const ObObjType expect_type = column_schema->get_meta_type().get_type(); + bool is_fast_number = cast_obj_ctx.number_fast_ctx_.is_fast_number_; + if (obj.is_null() && !column_schema->is_nullable()) { + const ObString &column_name = column_schema->get_column_name(); + ret = OB_BAD_NULL_ERROR; + LOG_USER_ERROR(OB_BAD_NULL_ERROR, column_name.length(), column_name.ptr()); + } else if (OB_FAIL(obj_collation_check(true, collation_type, *const_cast(res_obj)))) { + LOG_WARN("failed to check collation", KR(ret), K(collation_type), KPC(res_obj)); + } else if ((expect_type == ObNumberType || expect_type == ObUNumberType) && is_fast_number) { + if (OB_FAIL(number_fast_cast_check(cast_obj_ctx.number_fast_ctx_, obj, accuracy))) { + if (ret == OB_EAGAIN) { + if (OB_FAIL(obj_accuracy_check(*cast_obj_ctx.cast_ctx_, accuracy, collation_type, *res_obj, + obj, res_obj))) { + LOG_WARN("failed to check accuracy", KR(ret), K(accuracy), K(collation_type), + KPC(res_obj)); + } + } else { + LOG_WARN("failed to check accuracy", KR(ret), K(obj), K(expect_type)); + } + } + } else if (OB_FAIL(obj_accuracy_check(*cast_obj_ctx.cast_ctx_, accuracy, collation_type, *res_obj, + obj, res_obj))) { + LOG_WARN("failed to check accuracy", KR(ret), K(accuracy), K(collation_type), KPC(res_obj)); + } + return ret; +} + +int ObTableLoadObjCaster::string_datetime_oracle(const ObObjType expect_type, + ObObjCastParams ¶ms, const ObObj &in, + ObObj &out, const ObCastMode cast_mode, + const ObTableLoadTimeConverter &time_cvrt) +{ + int ret = OB_SUCCESS; + ObString utf8_string; + + if (OB_UNLIKELY((ObStringTC != in.get_type_class() && ObTextTC != in.get_type_class()) || + ObDateTimeTC != ob_obj_type_class(expect_type))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid input type", KR(ret), K(in), K(expect_type)); + } else if (in.is_blob()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("invalid use of blob type", KR(ret), K(in), K(expect_type)); + } else if (OB_FAIL(ObExprUtil::convert_string_collation( + in.get_string(), in.get_collation_type(), utf8_string, + ObCharset::get_system_collation(), *params.allocator_v2_))) { + LOG_WARN("fail to convert string collation", K(ret)); + } else { + int64_t value = 0; + ObTimeConvertCtx cvrt_ctx(params.dtc_params_.tz_info_, ObTimestampType == expect_type); + cvrt_ctx.oracle_nls_format_ = params.dtc_params_.get_nls_format(ObDateTimeType); + if (OB_FAIL(time_cvrt.str_to_datetime_oracle(utf8_string, cvrt_ctx, value))) { + LOG_WARN("fail to convert str to date in oracle mode", KR(ret), K(utf8_string), K(value)); + } else if (CM_IS_ERROR_ON_SCALE_OVER(cast_mode) && + (value == ObTimeConverter::ZERO_DATE || value == ObTimeConverter::ZERO_DATETIME)) { + ret = OB_INVALID_DATE_VALUE; + LOG_WARN("invalid date value", KR(ret), K(utf8_string)); + } else { + out.set_datetime(value); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_obj_cast.h b/src/observer/table_load/ob_table_load_obj_cast.h new file mode 100644 index 0000000000..a54708391a --- /dev/null +++ b/src/observer/table_load/ob_table_load_obj_cast.h @@ -0,0 +1,238 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#pragma once + +#include "common/object/ob_object.h" +#include "lib/ob_define.h" +#include "observer/table_load/ob_table_load_time_convert.h" +#include "share/object/ob_obj_cast.h" +#include "share/schema/ob_column_schema.h" + +namespace oceanbase +{ +namespace observer +{ +struct ObTableLoadNumberFastCtx +{ +public: + ObTableLoadNumberFastCtx() : is_fast_number_(false), integer_count_(0), decimal_count_(0) {} + void reset() + { + is_fast_number_ = false; + integer_count_ = 0; + decimal_count_ = 0; + } + +public: + bool is_fast_number_; + int64_t integer_count_; + int64_t decimal_count_; +}; + +struct ObTableLoadCastObjCtx +{ +public: + ObTableLoadCastObjCtx(const ObTableLoadTimeConverter *time_cvrt, common::ObCastCtx *cast_ctx, + const bool is_need_check) + : time_cvrt_(time_cvrt), cast_ctx_(cast_ctx), is_need_check_(is_need_check){} + +public: + const ObTableLoadTimeConverter *time_cvrt_; + common::ObCastCtx *cast_ctx_; + ObTableLoadNumberFastCtx number_fast_ctx_; + const bool is_need_check_; +}; + +class ObTableLoadObjCaster +{ + static const common::ObObj zero_obj; + static const common::ObObj null_obj; + +public: + static int cast_obj(ObTableLoadCastObjCtx &cast_obj_ctx, + const share::schema::ObColumnSchemaV2 *column_schema, + const common::ObObj &src, common::ObObj &dst); + +private: + static int convert_obj(const common::ObObjType &expect_type, const common::ObObj &src, + const common::ObObj *&dest); + static int handle_string_to_enum_set(ObTableLoadCastObjCtx &cast_obj_ctx, + const share::schema::ObColumnSchemaV2 *column_schema, + const common::ObObj &src, common::ObObj &dst); + static int string_to_enum(common::ObIAllocator &alloc, const common::ObObj &src, + const common::ObCollationType cs_type, + const common::ObCastMode cast_mode, + const common::ObIArray &str_values, int &warning, + uint64_t &output_value); + static int string_to_set(common::ObIAllocator &alloc, const common::ObObj &src, + const common::ObCollationType cs_type, + const common::ObCastMode cast_mode, + const common::ObIArray &str_values, int &warning, + uint64_t &output_value); + static int cast_obj_check(ObTableLoadCastObjCtx &cast_obj_ctx, + const share::schema::ObColumnSchemaV2 *column_schema, + common::ObObj &obj); + static int to_type(const common::ObObjType &expect_type, ObTableLoadCastObjCtx &cast_obj_ctx, + const common::ObAccuracy &accuracy, const common::ObObj &src, common::ObObj &dst); + static int string_datetime_oracle(const common::ObObjType expect_type, + common::ObObjCastParams ¶ms, const common::ObObj &in, + common::ObObj &out, const common::ObCastMode cast_mode, + const ObTableLoadTimeConverter &time_cvrt); + + // fast path for numbertype cast + inline static int number_fast_from(const char *str, const int64_t length, + common::ObIAllocator *allocator, ObNumberDesc &d, + uint32_t *&digits, const common::ObAccuracy &accuracy, + ObTableLoadNumberFastCtx &number_fast_ctx) + { + int ret = OB_SUCCESS; + static const uint32_t ROUND_POWS[] = {0, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000, 1000000000}; + + if (length > number::ObNumber::DIGIT_LEN) { + return OB_EAGAIN; + } + + const char *s = str; + + d.desc_ = 0; + d.sign_ = number::ObNumber::POSITIVE; + d.exp_ = 0x7f & (uint8_t)(number::ObNumber::EXP_ZERO); + if (*s == '+') { + s++; + } else if (*s == '-') { + s++; + d.sign_ = number::ObNumber::NEGATIVE; + d.exp_ = (0x7f & ~d.exp_) + 1; + } + + uint32_t n1 = 0; + int64_t integer_count = 0; + while (s < str + length) { + if (*s >= '0' && *s <= '9') { + n1 *= 10; + n1 += (*s - '0'); + s++; + integer_count++; + } else if (*s == '.') { + s++; + break; + } else { + return OB_EAGAIN; + } + } + number_fast_ctx.integer_count_ = integer_count; + + uint32_t n2 = 0; + int64_t decimal_count = 0; + while (s < str + length) { + if (*s >= '0' && *s <= '9') { + n2 *= 10; + n2 += (*s - '0'); + s++; + decimal_count++; + } else { + return OB_EAGAIN; + } + } + number_fast_ctx.decimal_count_ = decimal_count; + + d.len_++; + if (n2 > 0) { + n2 *= ROUND_POWS[(number::ObNumber::DIGIT_LEN - decimal_count)]; + d.len_++; + } + + digits = (uint32_t *)(allocator->alloc(sizeof(uint32_t) * d.len_)); + if (digits == nullptr) { + return OB_EAGAIN; + } + digits[0] = n1; + if (n2 > 0) { + digits[1] = n2; + } + number_fast_ctx.is_fast_number_ = true; + return ret; + } + + // fast path for numbertype cast result check + inline static int number_fast_cast_check(ObTableLoadNumberFastCtx &number_fast_ctx, + common::ObObj &obj, const common::ObAccuracy &accuracy) + { + int ret = OB_SUCCESS; + static const uint32_t ROUND_POWS[] = {0, 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000, 1000000000}; + + ObPrecision precision = accuracy.get_precision(); + ObScale scale = accuracy.get_scale(); + if (lib::is_oracle_mode()) { + if (OB_MAX_NUMBER_PRECISION >= precision && precision >= OB_MIN_NUMBER_PRECISION && + number::ObNumber::MAX_SCALE >= scale && scale >= number::ObNumber::MIN_SCALE) { + // do noting + } else { + return OB_EAGAIN; + } + } else { + if (precision >= scale && number::ObNumber::MAX_PRECISION >= precision && + precision >= OB_MIN_DECIMAL_PRECISION && number::ObNumber::MAX_SCALE >= scale && + scale >= 0) { + // do noting + } else { + return OB_EAGAIN; + } + } + + number::ObNumber nmb = obj.get_number(); + ObNumberDesc d = nmb.d_; + uint32_t *digits = nmb.get_digits(); + if (d.exp_ == (uint8_t)(number::ObNumber::EXP_ZERO) && d.len_ > 0 && d.len_ <= 2) { + // do nothing + } else { + return OB_EAGAIN; + } + uint32_t n1 = 0, n2 = 0; + int64_t integer_count = number_fast_ctx.integer_count_; + int64_t decimal_count = number_fast_ctx.decimal_count_; + if (d.len_ > 0) { + n1 = digits[0]; + } else { + return OB_EAGAIN; + } + + if (d.len_ > 1) { + n2 = digits[1]; + } + + const int32_t decimal_len = precision - scale; + // precision-scale>0时,整数部分的位数不能超过precision-scale + // precision-scale<=0时,整数部分必须为0,小数点后-(precision-scale)位也必须为0 + if ((decimal_len > 0 && integer_count <= decimal_len) || + (decimal_len <= 0 && n1 == 0 && + n2 / ROUND_POWS[(number::ObNumber::DIGIT_LEN + decimal_len)] == 0)) { + // scale>0时,精度限制在小数点后scale位 + if (scale > 0) { + if (n2 > 0 && decimal_count > scale) { + return OB_EAGAIN; + } + // scale=0时,小数部分被舍去 + } else if (scale == 0) { + if (n2 > 0) { + return OB_EAGAIN; + } + // scale<0时,小数部分被舍去且精度限制在小数点前-scale位 + } else { + if (n2 > 0 || n1 % ROUND_POWS[-scale] == 0) { + return OB_EAGAIN; + } + } + } else { + return OB_EAGAIN; + } + return ret; + } +}; + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_object_allocator.h b/src/observer/table_load/ob_table_load_object_allocator.h new file mode 100644 index 0000000000..60d6108cba --- /dev/null +++ b/src/observer/table_load/ob_table_load_object_allocator.h @@ -0,0 +1,60 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/ob_small_allocator.h" + +namespace oceanbase +{ +namespace observer +{ + +template +class ObTableLoadObjectAllocator +{ +public: + static const int64_t DEFAULT_MIN_OBJ_COUNT_ON_BLOCK = 1; + ObTableLoadObjectAllocator() {} + ~ObTableLoadObjectAllocator() {} + + template + T *alloc(Args&&... args); + void free(T *t); + + int init(const lib::ObLabel &label = nullptr, + const uint64_t tenant_id = common::OB_SERVER_TENANT_ID, + const int64_t block_size = common::OB_MALLOC_NORMAL_BLOCK_SIZE, + const int64_t min_obj_count_on_block = DEFAULT_MIN_OBJ_COUNT_ON_BLOCK, + const int64_t limit_num = INT64_MAX) { + return small_allocator_.init(sizeof(T), label, tenant_id, block_size, min_obj_count_on_block, limit_num); + } + +private: + common::ObSmallAllocator small_allocator_; +}; + +template +template +T *ObTableLoadObjectAllocator::alloc(Args&&... args) +{ + T *t = nullptr; + void *buf = nullptr; + if (OB_NOT_NULL(buf = small_allocator_.alloc())) { + t = new (buf) T(args...); + } + return t; +} + +template +void ObTableLoadObjectAllocator::free(T *t) +{ + if (OB_NOT_NULL(t)) { + t->~T(); + small_allocator_.free(t); + } +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_parallel_merge_ctx.cpp b/src/observer/table_load/ob_table_load_parallel_merge_ctx.cpp new file mode 100644 index 0000000000..bd724f5f38 --- /dev/null +++ b/src/observer/table_load/ob_table_load_parallel_merge_ctx.cpp @@ -0,0 +1,921 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_parallel_merge_ctx.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_builder.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_compactor.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scanner.h" +#include "storage/direct_load/ob_direct_load_range_splitter.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace blocksstable; +using namespace storage; +using namespace lib; + +/** + * ObTableLoadParallelMergeSSTableCompare + */ + +ObTableLoadParallelMergeSSTableCompare::ObTableLoadParallelMergeSSTableCompare() + : result_code_(OB_SUCCESS) +{ +} + +ObTableLoadParallelMergeSSTableCompare::~ObTableLoadParallelMergeSSTableCompare() +{ +} + +bool ObTableLoadParallelMergeSSTableCompare::operator()(const ObDirectLoadMultipleSSTable *lhs, + const ObDirectLoadMultipleSSTable *rhs) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(lhs), K(rhs)); + } else { + cmp_ret = lhs->get_meta().row_count_ - rhs->get_meta().row_count_; + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } + return cmp_ret < 0; +} + +/** + * ObTableLoadParallelMergeTabletCtx + */ +ObTableLoadParallelMergeTabletCtx::ObTableLoadParallelMergeTabletCtx() + : allocator_("TLD_ParalMerge"), + merge_sstable_count_(0), + range_count_(0), + range_sstable_count_(0), + range_allocator_("TLD_ParalMerge") +{ +} + +ObTableLoadParallelMergeTabletCtx::~ObTableLoadParallelMergeTabletCtx() +{ + for (int64_t i = 0; i < sstables_.size(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstables_.at(i); + if (sstable != nullptr) { + sstable->~ObDirectLoadMultipleSSTable(); + allocator_.free(sstable); + } + } + sstables_.reset(); + for (int64_t i = 0; i < range_sstables_.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = range_sstables_.at(i); + if (sstable != nullptr) { + sstable->~ObDirectLoadMultipleSSTable(); + range_allocator_.free(sstable); + } + } + range_sstables_.reset(); +} + +int ObTableLoadParallelMergeTabletCtx::set_parallel_merge_param(int64_t merge_sstable_count, + int64_t range_count) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(merge_sstable_count <= 0 || range_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_sstable_count), K(range_count)); + } else if (OB_UNLIKELY(merge_sstable_count_ > 0 || range_count_ > 0 || range_sstable_count_ > 0 || + ranges_.empty() || ranges_.count() != range_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet ctx", KR(ret), KPC(this)); + } else { + merge_sstable_count_ = merge_sstable_count; + range_count_ = range_count; + range_sstable_count_ = 0; + range_sstables_.reset(); + if (OB_FAIL(range_sstables_.prepare_allocate(range_count))) { + LOG_WARN("fail to prepare allocate array", KR(ret)); + } + } + return ret; +} + +int ObTableLoadParallelMergeTabletCtx::finish_range_merge( + int64_t range_idx, ObDirectLoadMultipleSSTable *range_sstable, bool &all_range_finish) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(range_idx < 0 || range_idx > range_count_ || nullptr == range_sstable || + !range_sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(range_idx), KPC(range_sstable)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(nullptr != range_sstables_.at(range_idx))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range idx", KR(ret), K(range_idx)); + } else { + range_sstables_.at(range_idx) = range_sstable; + all_range_finish = (++range_sstable_count_ >= range_count_); + } + } + return ret; +} + +int ObTableLoadParallelMergeTabletCtx::apply_merged_sstable( + ObDirectLoadMultipleSSTable *merged_sstable) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == merged_sstable || !merged_sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(merged_sstable)); + } else if (OB_UNLIKELY(merge_sstable_count_ <= 0 || range_count_ <= 0 || + range_count_ != range_sstable_count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet ctx", KR(ret), KPC(this)); + } else { + ObVector result_sstables; + LOG_INFO("parallel merge apply merged", K(merge_sstable_count_), K(sstables_.size())); + if (OB_FAIL(result_sstables.push_back(merged_sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < sstables_.size(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstables_[i]; + if (i < merge_sstable_count_) { + sstable->~ObDirectLoadMultipleSSTable(); + allocator_.free(sstable); + } else { + if (OB_FAIL(result_sstables.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(sstables_.assign(result_sstables))) { + LOG_WARN("fail to assign sstables", KR(ret)); + } else { + // clear merge ctx + merge_sstable_count_ = 0; + range_count_ = 0; + range_sstable_count_ = 0; + for (int64_t i = 0; i < range_sstables_.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = range_sstables_.at(i); + sstable->~ObDirectLoadMultipleSSTable(); + range_allocator_.free(sstable); + } + range_sstables_.reset(); + ranges_.reset(); + range_allocator_.reset(); + } + } + } + return ret; +} + +/** + * SplitRangeTaskProcessor + */ + +class ObTableLoadParallelMergeCtx::SplitRangeTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + SplitRangeTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadParallelMergeCtx *parallel_merge_ctx, + ObTableLoadParallelMergeTabletCtx *tablet_ctx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + parallel_merge_ctx_(parallel_merge_ctx), + tablet_ctx_(tablet_ctx) + { + ctx_->inc_ref_count(); + } + virtual ~SplitRangeTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + const int64_t merge_count_per_round = + parallel_merge_ctx_->store_ctx_->table_data_desc_.merge_count_per_round_; + if (OB_UNLIKELY(tablet_ctx_->merge_sstable_count_ > 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet ctx", KPC(tablet_ctx_)); + } else if (OB_UNLIKELY(tablet_ctx_->sstables_.size() <= merge_count_per_round)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet sstable count", KPC(tablet_ctx_), K(merge_count_per_round)); + } else { + const int64_t merge_sstable_count = + MIN(tablet_ctx_->sstables_.size() - merge_count_per_round + 1, merge_count_per_round); + ObSEArray sstable_array; + // sort sstable + ObTableLoadParallelMergeSSTableCompare compare; + std::sort(tablet_ctx_->sstables_.begin(), tablet_ctx_->sstables_.end(), compare); + // collect merged sstables + for (int64_t i = 0; OB_SUCC(ret) && i < merge_sstable_count; ++i) { + ObDirectLoadMultipleSSTable *sstable = tablet_ctx_->sstables_.at(i); + if (OB_FAIL(sstable_array.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + // split range + if (OB_SUCC(ret)) { + ObDirectLoadMultipleSSTableRangeSplitter range_splitter; + if (OB_FAIL(range_splitter.init(sstable_array, + parallel_merge_ctx_->store_ctx_->table_data_desc_, + &ctx_->schema_.datum_utils_))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(tablet_ctx_->ranges_, + parallel_merge_ctx_->thread_count_, + tablet_ctx_->range_allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } + } + if (OB_SUCC(ret)) { + LOG_INFO("parallel merge split range finish", K(tablet_ctx_->sstables_.size()), + K(merge_sstable_count), K(tablet_ctx_->ranges_.count())); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_ctx_->set_parallel_merge_param(merge_sstable_count, + tablet_ctx_->ranges_.count()))) { + LOG_WARN("fail to set parallel merge param", KR(ret)); + } else if (OB_FAIL(parallel_merge_ctx_->handle_tablet_split_range_finish(tablet_ctx_))) { + LOG_WARN("fail to handle tablet split range finish", KR(ret)); + } + } + } + return ret; + } +private: + ObTableLoadTableCtx *ctx_; + ObTableLoadParallelMergeCtx *parallel_merge_ctx_; + ObTableLoadParallelMergeTabletCtx *tablet_ctx_; +}; + +/** + * MergeRangeTaskProcessor + */ + +class ObTableLoadParallelMergeCtx::MergeRangeTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + MergeRangeTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadParallelMergeCtx *parallel_merge_ctx, + ObTableLoadParallelMergeTabletCtx *tablet_ctx, int64_t range_idx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + parallel_merge_ctx_(parallel_merge_ctx), + tablet_ctx_(tablet_ctx), + range_idx_(range_idx), + extra_buf_(nullptr), + extra_buf_size_(0) + { + ctx_->inc_ref_count(); + } + virtual ~MergeRangeTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + const ObDirectLoadMultipleDatumRow *datum_row = nullptr; + ObSEArray table_array; + bool all_range_finish = false; + if (OB_FAIL(init_scan_merge())) { + LOG_WARN("fail to init scan merge", KR(ret)); + } else if (OB_FAIL(init_sstable_builder())) { + LOG_WARN("fail to init sstable builder", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(scan_merge_.get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_FAIL(sstable_builder_.append_row(*datum_row))) { + LOG_WARN("fail to append row", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(sstable_builder_.close())) { + LOG_WARN("fail to close sstable builder", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObMutexGuard guard(tablet_ctx_->mutex_); + if (OB_FAIL(sstable_builder_.get_tables(table_array, tablet_ctx_->range_allocator_))) { + LOG_WARN("fail to get tables", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_UNLIKELY(1 != table_array.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table array count", KR(ret), K(table_array)); + } else if (OB_ISNULL(sstable = + dynamic_cast(table_array.at(0)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table_array.at(0))); + } else if (OB_FAIL(tablet_ctx_->finish_range_merge(range_idx_, sstable, all_range_finish))) { + LOG_WARN("fail to finish range merge", KR(ret)); + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < table_array.count(); ++i) { + ObIDirectLoadPartitionTable *table = table_array.at(i); + table->~ObIDirectLoadPartitionTable(); + } + table_array.reset(); + } + } + if (OB_SUCC(ret) && all_range_finish) { + if (OB_FAIL(parallel_merge_ctx_->handle_tablet_range_merge_finish(tablet_ctx_))) { + LOG_WARN("fail to handle tablet range merge finish", KR(ret)); + } + } + return ret; + } + int init_scan_merge() + { + int ret = OB_SUCCESS; + ObDirectLoadMultipleSSTableScanMergeParam scan_merge_param; + scan_merge_param.table_data_desc_ = parallel_merge_ctx_->store_ctx_->table_data_desc_; + scan_merge_param.datum_utils_ = &(ctx_->schema_.datum_utils_); + scan_merge_param.error_row_handler_ = parallel_merge_ctx_->store_ctx_->error_row_handler_; + scan_merge_param.result_info_ = &(parallel_merge_ctx_->store_ctx_->result_info_); + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ctx_->merge_sstable_count_; ++i) { + ObDirectLoadMultipleSSTable *sstable = tablet_ctx_->sstables_.at(i); + if (OB_FAIL(sstable_array_.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(scan_merge_.init(scan_merge_param, sstable_array_, + tablet_ctx_->ranges_.at(range_idx_)))) { + LOG_WARN("fail to init sstable scan merge", KR(ret)); + } + } + return ret; + } + int init_sstable_builder() + { + int ret = OB_SUCCESS; + extra_buf_size_ = parallel_merge_ctx_->store_ctx_->table_data_desc_.extra_buf_size_; + if (OB_ISNULL(extra_buf_ = static_cast(allocator_.alloc(extra_buf_size_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + ObDirectLoadMultipleSSTableBuildParam build_param; + build_param.table_data_desc_ = parallel_merge_ctx_->store_ctx_->table_data_desc_; + build_param.datum_utils_ = &(ctx_->schema_.datum_utils_); + build_param.file_mgr_ = parallel_merge_ctx_->store_ctx_->tmp_file_mgr_; + build_param.extra_buf_ = extra_buf_; + build_param.extra_buf_size_ = extra_buf_size_; + if (OB_FAIL(sstable_builder_.init(build_param))) { + LOG_WARN("fail to init sstable builder", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx *ctx_; + ObTableLoadParallelMergeCtx *parallel_merge_ctx_; + ObTableLoadParallelMergeTabletCtx *tablet_ctx_; + int64_t range_idx_; + ObSEArray sstable_array_; + ObDirectLoadMultipleSSTableScanMerge scan_merge_; + char *extra_buf_; + int64_t extra_buf_size_; + ObDirectLoadMultipleSSTableBuilder sstable_builder_; +}; + +class ObTableLoadParallelMergeCtx::CompactSSTableTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CompactSSTableTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadParallelMergeCtx *parallel_merge_ctx, + ObTableLoadParallelMergeTabletCtx *tablet_ctx) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + parallel_merge_ctx_(parallel_merge_ctx), + tablet_ctx_(tablet_ctx) + { + ctx_->inc_ref_count(); + } + virtual ~CompactSSTableTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_compactor_time_us); + int ret = OB_SUCCESS; + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_FAIL(compact_sstable(sstable))) { + LOG_WARN("fail to compact sstable", KR(ret)); + } else if (OB_FAIL(tablet_ctx_->apply_merged_sstable(sstable))) { + LOG_WARN("fail to apply merged sstable", KR(ret)); + } else if (OB_FAIL(parallel_merge_ctx_->handle_tablet_compact_sstable_finish(tablet_ctx_))) { + LOG_WARN("fail to handle compact sstable finish", KR(ret)); + } + return ret; + } + int compact_sstable(ObDirectLoadMultipleSSTable *&result_sstable) + { + int ret = OB_SUCCESS; + ObDirectLoadMultipleSSTableCompactParam compact_param; + compact_param.table_data_desc_ = parallel_merge_ctx_->store_ctx_->table_data_desc_; + compact_param.datum_utils_ = &ctx_->schema_.datum_utils_; + if (OB_FAIL(compactor_.init(compact_param))) { + LOG_WARN("fail to init sstable compactor", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ctx_->range_sstables_.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = tablet_ctx_->range_sstables_.at(i); + if (OB_FAIL(compactor_.add_table(sstable))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(compactor_.compact())) { + LOG_WARN("fail to do compact", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObIDirectLoadPartitionTable *table = nullptr; + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_FAIL(compactor_.get_table(table, tablet_ctx_->allocator_))) { + LOG_WARN("fail to get compacted table", KR(ret)); + } else if (OB_ISNULL(sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table)); + } else { + result_sstable = sstable; + } + if (OB_FAIL(ret)) { + if (nullptr != table) { + table->~ObIDirectLoadPartitionTable(); + tablet_ctx_->allocator_.free(table); + } + } + } + return ret; + } +private: + ObTableLoadTableCtx *ctx_; + ObTableLoadParallelMergeCtx *parallel_merge_ctx_; + ObTableLoadParallelMergeTabletCtx *tablet_ctx_; + ObDirectLoadMultipleSSTableCompactor compactor_; +}; + +/** + * ParallelMergeTaskCallback + */ + +class ObTableLoadParallelMergeCtx::ParallelMergeTaskCallback : public ObITableLoadTaskCallback +{ +public: + ParallelMergeTaskCallback(ObTableLoadTableCtx *ctx, + ObTableLoadParallelMergeCtx *parallel_merge_ctx, int64_t thread_idx) + : ctx_(ctx), parallel_merge_ctx_(parallel_merge_ctx), thread_idx_(thread_idx) + { + ctx_->inc_ref_count(); + } + virtual ~ParallelMergeTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(parallel_merge_ctx_->handle_task_finish(thread_idx_, ret_code))) { + LOG_WARN("fail to handle task finish", KR(ret)); + } + if (OB_FAIL(ret)) { + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx *const ctx_; + ObTableLoadParallelMergeCtx *const parallel_merge_ctx_; + int64_t thread_idx_; +}; + +/** + * ObTableLoadParallelMergeCtx + */ + +ObTableLoadParallelMergeCtx::ObTableLoadParallelMergeCtx() + : store_ctx_(nullptr), + thread_count_(0), + cb_(nullptr), + allocator_("TLD_ParalMerge"), + has_error_(false), + is_stop_(false), + is_inited_(false) +{ +} + +ObTableLoadParallelMergeCtx::~ObTableLoadParallelMergeCtx() +{ + for (TabletCtxIterator iter = tablet_ctx_map_.begin(); iter != tablet_ctx_map_.end(); ++iter) { + ObTableLoadParallelMergeTabletCtx *tablet_ctx = iter->second; + tablet_ctx->~ObTableLoadParallelMergeTabletCtx(); + allocator_.free(tablet_ctx); + } + tablet_ctx_map_.reuse(); + for (int64_t i = 0; i < light_task_list_.count(); ++i) { + ObTableLoadTask *task = light_task_list_.at(i); + store_ctx_->ctx_->free_task(task); + } + light_task_list_.reset(); + for (int64_t i = 0; i < heavy_task_list_.count(); ++i) { + ObTableLoadTask *task = heavy_task_list_.at(i); + store_ctx_->ctx_->free_task(task); + } + heavy_task_list_.reset(); +} + +int ObTableLoadParallelMergeCtx::init(ObTableLoadStoreCtx *store_ctx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadParallelMergeCtx init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == store_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(store_ctx)); + } else { + if (OB_FAIL(tablet_ctx_map_.create(1024, "TLD_CptCtxMap", "TLD_CptCtxMap", MTL_ID()))) { + LOG_WARN("fail to create ctx map", KR(ret)); + } else { + store_ctx_ = store_ctx; + thread_count_ = store_ctx_->task_scheduler_->get_thread_count(); + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::add_tablet_sstable(ObDirectLoadMultipleSSTable *sstable) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadParallelMergeCtx not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + const ObTabletID &tablet_id = sstable->get_tablet_id(); + ObTableLoadParallelMergeTabletCtx *tablet_ctx = nullptr; + if (OB_FAIL(tablet_ctx_map_.get_refactored(tablet_id, tablet_ctx))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get refactored", KR(ret)); + } else { + ret = OB_SUCCESS; + if (OB_ISNULL(tablet_ctx = OB_NEWx(ObTableLoadParallelMergeTabletCtx, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadParallelMergeTabletCtx", KR(ret)); + } else { + tablet_ctx->tablet_id_ = tablet_id; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_ctx_map_.set_refactored(tablet_id, tablet_ctx))) { + LOG_WARN("fail to set refactored", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleSSTable *copied_sstable = nullptr; + if (OB_ISNULL(copied_sstable = + OB_NEWx(ObDirectLoadMultipleSSTable, (&tablet_ctx->allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTable", KR(ret)); + } else if (OB_FAIL(copied_sstable->copy(*sstable))) { + LOG_WARN("fail to copy multiple sstable", KR(ret)); + } else if (OB_FAIL(tablet_ctx->sstables_.push_back(copied_sstable))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != copied_sstable) { + copied_sstable->~ObDirectLoadMultipleSSTable(); + tablet_ctx->allocator_.free(copied_sstable); + copied_sstable = nullptr; + } + } + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::add_light_task(ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + if (OB_FAIL(light_task_list_.push_back(task))) { + LOG_WARN("fail to push back task", KR(ret)); + } + return ret; +} + +int ObTableLoadParallelMergeCtx::add_heavy_task(ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + if (OB_FAIL(heavy_task_list_.push_back(task))) { + LOG_WARN("fail to push back task", KR(ret)); + } + return ret; +} + +int64_t ObTableLoadParallelMergeCtx::get_task_count() const +{ + ObMutexGuard guard(mutex_); + return light_task_list_.count() + heavy_task_list_.count(); +} + +int ObTableLoadParallelMergeCtx::add_idle_thread(int64_t thread_idx) +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + if (OB_FAIL(idle_thread_list_.push_back(thread_idx))) { + LOG_WARN("fail to push back thread idx", KR(ret)); + } + return ret; +} + +int64_t ObTableLoadParallelMergeCtx::get_idle_thread_count() const +{ + ObMutexGuard guard(mutex_); + return idle_thread_list_.count(); +} + +int ObTableLoadParallelMergeCtx::start(ObTableLoadParallelMergeCb *cb) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadParallelMergeCtx not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == cb)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(cb)); + } else { + cb_ = cb; + abort_unless(1 >= tablet_ctx_map_.size()); // mutiple tablet sstable only + for (TabletCtxIterator iter = tablet_ctx_map_.begin(); + OB_SUCC(ret) && iter != tablet_ctx_map_.end(); ++iter) { + ObTableLoadParallelMergeTabletCtx *tablet_ctx = iter->second; + if (tablet_ctx->sstables_.size() > store_ctx_->table_data_desc_.merge_count_per_round_) { + // need merge + if (OB_FAIL(construct_split_range_task(tablet_ctx))) { + LOG_WARN("fail to construct split range task", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (get_task_count() > 0) { + if (OB_FAIL(start_merge())) { + LOG_WARN("fail to start merge", KR(ret)); + } + } else { + // no need to merge + ret = cb_->on_success(); + } + } + } + return ret; +} + +void ObTableLoadParallelMergeCtx::stop() +{ + is_stop_ = true; +} + +int ObTableLoadParallelMergeCtx::start_merge() +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + for (int64_t thread_idx = 0; OB_SUCC(ret) && thread_idx < thread_count_; ++thread_idx) { + if (OB_FAIL(idle_thread_list_.push_back(thread_idx))) { + LOG_WARN("fail to push back idle thread", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(schedule_merge_unlock())) { + LOG_WARN("fail to schedule merge", KR(ret)); + } + } + if (OB_FAIL(ret)) { + has_error_ = true; + } + return ret; +} + +int ObTableLoadParallelMergeCtx::schedule_merge_unlock() +{ + int ret = OB_SUCCESS; + ObIArray *task_list = nullptr; + if (heavy_task_list_.count() < thread_count_ && !light_task_list_.empty()) { + task_list = &light_task_list_; + } else { + task_list = &heavy_task_list_; + } + while (OB_SUCC(ret) && !task_list->empty() && !idle_thread_list_.empty()) { + ObTableLoadTask *task = nullptr; + int64_t thread_idx = -1; + if (OB_FAIL(task_list->pop_back(task))) { + LOG_WARN("fail to pop back task", KR(ret)); + } else if (OB_FAIL(idle_thread_list_.pop_back(thread_idx))) { + LOG_WARN("fail to pop back thread idx", KR(ret)); + } + // 设置task的callback + else if (OB_FAIL( + task->set_callback(store_ctx_->ctx_, this, thread_idx))) { + LOG_WARN("fail to set task callback", KR(ret)); + } + // 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(thread_idx, task))) { + LOG_WARN("fail to add task", KR(ret), K(thread_idx), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + store_ctx_->ctx_->free_task(task); + } + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::construct_split_range_task( + ObTableLoadParallelMergeTabletCtx *tablet_ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(store_ctx_->ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL( + task->set_processor(store_ctx_->ctx_, this, tablet_ctx))) { + LOG_WARN("fail to set split range task processor", KR(ret)); + } + // 3. 添加到任务队列 + else if (OB_FAIL(add_light_task(task))) { + LOG_WARN("fail to add light task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + store_ctx_->ctx_->free_task(task); + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::construct_merge_range_task( + ObTableLoadParallelMergeTabletCtx *tablet_ctx, int64_t range_idx) +{ + int ret = OB_SUCCESS; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(store_ctx_->ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(store_ctx_->ctx_, this, tablet_ctx, + range_idx))) { + LOG_WARN("fail to set merge range task processor", KR(ret)); + } + // 3. 添加到任务队列 + else if (OB_FAIL(add_heavy_task(task))) { + LOG_WARN("fail to add heavy task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + store_ctx_->ctx_->free_task(task); + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::construct_compact_sstable_task( + ObTableLoadParallelMergeTabletCtx *tablet_ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(store_ctx_->ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(store_ctx_->ctx_, this, + tablet_ctx))) { + LOG_WARN("fail to set compact sstable task processor", KR(ret)); + } + // 3. 添加到任务队列 + else if (OB_FAIL(add_light_task(task))) { + LOG_WARN("fail to add light task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + store_ctx_->ctx_->free_task(task); + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::handle_tablet_split_range_finish( + ObTableLoadParallelMergeTabletCtx *tablet_ctx) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == tablet_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(tablet_ctx)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ctx->range_count_; ++i) { + if (OB_FAIL(construct_merge_range_task(tablet_ctx, i))) { + LOG_WARN("fail to construct merge range task", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::handle_tablet_range_merge_finish( + ObTableLoadParallelMergeTabletCtx *tablet_ctx) +{ + LOG_INFO("parallel merge all merge finish"); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == tablet_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(tablet_ctx)); + } else if (OB_FAIL(construct_compact_sstable_task(tablet_ctx))) { + LOG_WARN("fail to construct compact sstable task", KR(ret)); + } + return ret; +} + +int ObTableLoadParallelMergeCtx::handle_tablet_compact_sstable_finish( + ObTableLoadParallelMergeTabletCtx *tablet_ctx) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == tablet_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(tablet_ctx)); + } else if (tablet_ctx->sstables_.size() > store_ctx_->table_data_desc_.merge_count_per_round_) { + // still need merge + if (OB_FAIL(construct_split_range_task(tablet_ctx))) { + LOG_WARN("fail to construct split range task", KR(ret)); + } + } + return ret; +} + +int ObTableLoadParallelMergeCtx::handle_task_finish(int64_t thread_idx, int ret_code) +{ + int ret = OB_SUCCESS; + bool is_merge_completed = false; + { + ObMutexGuard guard(mutex_); + if (OB_FAIL(ret_code)) { + has_error_ = true; + } + if (OB_UNLIKELY(is_stop_ || has_error_)) { + } else { + if (OB_FAIL(idle_thread_list_.push_back(thread_idx))) { + LOG_WARN("fail to push back idle thread", KR(ret)); + } else if (OB_FAIL(schedule_merge_unlock())) { + LOG_WARN("fail to schedule merge", KR(ret)); + } else { + is_merge_completed = (idle_thread_list_.count() == thread_count_); + } + if (OB_FAIL(ret)) { + has_error_ = true; + } + } + } + if (is_merge_completed) { + LOG_INFO("LOAD PARALLEL MERGE COMPLETED"); + ret = cb_->on_success(); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_parallel_merge_ctx.h b/src/observer/table_load/ob_table_load_parallel_merge_ctx.h new file mode 100644 index 0000000000..4db5a469f6 --- /dev/null +++ b/src/observer/table_load/ob_table_load_parallel_merge_ctx.h @@ -0,0 +1,113 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "lib/container/ob_vector.h" +#include "lib/hash/ob_hashmap.h" +#include "lib/lock/ob_mutex.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadStoreCtx; +class ObTableLoadTask; + +class ObTableLoadParallelMergeSSTableCompare +{ +public: + ObTableLoadParallelMergeSSTableCompare(); + ~ObTableLoadParallelMergeSSTableCompare(); + bool operator()(const storage::ObDirectLoadMultipleSSTable *lhs, + const storage::ObDirectLoadMultipleSSTable *rhs); + int get_error_code() const { return result_code_; } + int result_code_; +}; + +struct ObTableLoadParallelMergeTabletCtx +{ +public: + ObTableLoadParallelMergeTabletCtx(); + ~ObTableLoadParallelMergeTabletCtx(); + int set_parallel_merge_param(int64_t merge_sstable_count, int64_t range_count); + int finish_range_merge(int64_t range_idx, storage::ObDirectLoadMultipleSSTable *range_sstable, + bool &all_range_finish); + int apply_merged_sstable(storage::ObDirectLoadMultipleSSTable *merged_sstable); + TO_STRING_KV(K_(tablet_id), K_(sstables), K_(merge_sstable_count), K_(range_count), + K_(range_sstable_count), K_(ranges), K_(range_sstables)); +public: + common::ObTabletID tablet_id_; + common::ObArenaAllocator allocator_; // for alloc sstables + common::ObVector sstables_; + int64_t merge_sstable_count_; + int64_t range_count_; + int64_t range_sstable_count_; + lib::ObMutex mutex_; // for alloc range sstable + common::ObArenaAllocator range_allocator_; // for alloc range and range sstable + common::ObSEArray ranges_; + common::ObSEArray range_sstables_; +}; + +class ObTableLoadParallelMergeCb +{ +public: + virtual ~ObTableLoadParallelMergeCb() = default; + virtual int on_success() = 0; +}; + +class ObTableLoadParallelMergeCtx +{ + class SplitRangeTaskProcessor; + class MergeRangeTaskProcessor; + class CompactSSTableTaskProcessor; + class ParallelMergeTaskCallback; +public: + typedef common::hash::ObHashMap + TabletCtxMap; + typedef TabletCtxMap::const_iterator TabletCtxIterator; + ObTableLoadParallelMergeCtx(); + ~ObTableLoadParallelMergeCtx(); + int init(ObTableLoadStoreCtx *store_ctx); + int add_tablet_sstable(storage::ObDirectLoadMultipleSSTable *sstable); + int start(ObTableLoadParallelMergeCb *cb); + void stop(); + const TabletCtxMap &get_tablet_ctx_map() const { return tablet_ctx_map_; } +private: + int start_merge(); + int schedule_merge_unlock(); + int construct_split_range_task(ObTableLoadParallelMergeTabletCtx *tablet_ctx); + int construct_merge_range_task(ObTableLoadParallelMergeTabletCtx *tablet_ctx, int64_t range_idx); + int construct_compact_sstable_task(ObTableLoadParallelMergeTabletCtx *tablet_ctx); + int handle_tablet_split_range_finish(ObTableLoadParallelMergeTabletCtx *tablet_ctx); + int handle_tablet_range_merge_finish(ObTableLoadParallelMergeTabletCtx *tablet_ctx); + int handle_tablet_compact_sstable_finish(ObTableLoadParallelMergeTabletCtx *tablet_ctx); + int handle_task_finish(int64_t thread_idx, int ret_code); +private: + int add_light_task(ObTableLoadTask *task); + int add_heavy_task(ObTableLoadTask *task); + int64_t get_task_count() const; + int add_idle_thread(int64_t thread_idx); + int64_t get_idle_thread_count() const; +private: + ObTableLoadStoreCtx *store_ctx_; + int64_t thread_count_; + ObTableLoadParallelMergeCb *cb_; + common::ObArenaAllocator allocator_; + TabletCtxMap tablet_ctx_map_; + mutable lib::ObMutex mutex_; + ObArray light_task_list_; + ObArray heavy_task_list_; + ObArray idle_thread_list_; + bool has_error_; + volatile bool is_stop_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.cpp b/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.cpp new file mode 100644 index 0000000000..54c317e2f1 --- /dev/null +++ b/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.cpp @@ -0,0 +1,168 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_parallel_merge_table_compactor.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace blocksstable; + +/** + * ParallelMergeCb + */ + +ObTableLoadParallelMergeTableCompactor::ParallelMergeCb::ParallelMergeCb() + : table_compactor_(nullptr) +{ +} + +int ObTableLoadParallelMergeTableCompactor::ParallelMergeCb::init( + ObTableLoadParallelMergeTableCompactor *table_compactor) +{ + int ret = OB_SUCCESS; + if (OB_NOT_NULL(table_compactor_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ParallelMergeCb init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == table_compactor)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table_compactor)); + } else { + table_compactor_ = table_compactor; + } + return ret; +} + +int ObTableLoadParallelMergeTableCompactor::ParallelMergeCb::on_success() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table_compactor_)) { + ret = OB_NOT_INIT; + LOG_WARN("ParallelMergeCb not init", KR(ret), KP(this)); + } else if (OB_FAIL(table_compactor_->handle_parallel_merge_success())) { + LOG_WARN("fail to handle parallel merge success", KR(ret)); + } + return ret; +} + +/** + * ObTableLoadParallelMergeTableCompactor + */ + +ObTableLoadParallelMergeTableCompactor::ObTableLoadParallelMergeTableCompactor() +{ +} + +ObTableLoadParallelMergeTableCompactor::~ObTableLoadParallelMergeTableCompactor() +{ +} + +int ObTableLoadParallelMergeTableCompactor::inner_init() +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + if (OB_FAIL(parallel_merge_ctx_.init(compact_ctx_->store_ctx_))) { + LOG_WARN("fail to init parallel merge ctx", KR(ret)); + } else if (OB_FAIL(parallel_merge_cb_.init(this))) { + LOG_WARN("fail to init parallel merge cb", KR(ret)); + } + return ret; +} + +int ObTableLoadParallelMergeTableCompactor::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadParallelMergeTableCompactor not init", KR(ret), KP(this)); + } else { + ObSEArray trans_store_array; + if (OB_FAIL(compact_ctx_->store_ctx_->get_committed_trans_stores(trans_store_array))) { + LOG_WARN("fail to get committed trans stores", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_store_array.count(); ++i) { + ObTableLoadTransStore *trans_store = trans_store_array.at(i); + for (int64_t j = 0; OB_SUCC(ret) && j < trans_store->session_store_array_.count(); ++j) { + const ObTableLoadTransStore::SessionStore *session_store = + trans_store->session_store_array_.at(j); + for (int64_t k = 0; OB_SUCC(ret) && k < session_store->partition_table_array_.count(); + ++k) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(k); + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table)); + } else if (OB_FAIL(parallel_merge_ctx_.add_tablet_sstable(sstable))) { + LOG_WARN("fail to add tablet sstable", KR(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + compact_ctx_->store_ctx_->clear_committed_trans_stores(); + if (OB_FAIL(parallel_merge_ctx_.start(¶llel_merge_cb_))) { + LOG_WARN("fail to start parallel merge", KR(ret)); + } + } + } + return ret; +} + +void ObTableLoadParallelMergeTableCompactor::stop() +{ + parallel_merge_ctx_.stop(); +} + +int ObTableLoadParallelMergeTableCompactor::handle_parallel_merge_success() +{ + int ret = OB_SUCCESS; + if (build_result()) { + LOG_WARN("fail to build result", KR(ret)); + } else if (OB_FAIL(compact_ctx_->handle_table_compact_success())) { + LOG_WARN("fail to notify table compact success", KR(ret)); + } + return ret; +} + +int ObTableLoadParallelMergeTableCompactor::build_result() +{ + int ret = OB_SUCCESS; + ObTableLoadTableCompactResult &result = compact_ctx_->result_; + // get tables from tablet ctx + const ObTableLoadParallelMergeCtx::TabletCtxMap &tablet_ctx_map = + parallel_merge_ctx_.get_tablet_ctx_map(); + for (ObTableLoadParallelMergeCtx::TabletCtxIterator tablet_ctx_iter = tablet_ctx_map.begin(); + OB_SUCC(ret) && tablet_ctx_iter != tablet_ctx_map.end(); ++tablet_ctx_iter) { + ObTableLoadParallelMergeTabletCtx *tablet_ctx = tablet_ctx_iter->second; + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ctx->sstables_.size(); ++i) { + ObDirectLoadMultipleSSTable *sstable = tablet_ctx->sstables_.at(i); + ObDirectLoadMultipleSSTable *copied_sstable = nullptr; + if (OB_ISNULL(copied_sstable = OB_NEWx(ObDirectLoadMultipleSSTable, (&result.allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTable", KR(ret)); + } else if (OB_FAIL(copied_sstable->copy(*sstable))) { + LOG_WARN("fail to copy multiple sstable", KR(ret)); + } else if (OB_FAIL(result.add_table(copied_sstable))) { + LOG_WARN("fail to add table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != copied_sstable) { + copied_sstable->~ObDirectLoadMultipleSSTable(); + result.allocator_.free(copied_sstable); + } + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.h b/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.h new file mode 100644 index 0000000000..227d8c8cfb --- /dev/null +++ b/src/observer/table_load/ob_table_load_parallel_merge_table_compactor.h @@ -0,0 +1,43 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_parallel_merge_ctx.h" +#include "observer/table_load/ob_table_load_table_compactor.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadParallelMergeTableCompactor : public ObTableLoadTableCompactor +{ +public: + ObTableLoadParallelMergeTableCompactor(); + virtual ~ObTableLoadParallelMergeTableCompactor(); + int start() override; + void stop() override; +private: + int inner_init() override; + int handle_parallel_merge_success(); + int build_result(); +private: + class ParallelMergeCb : public ObTableLoadParallelMergeCb + { + public: + ParallelMergeCb(); + virtual ~ParallelMergeCb() = default; + int init(ObTableLoadParallelMergeTableCompactor *table_compactor); + int on_success() override; + private: + ObTableLoadParallelMergeTableCompactor *table_compactor_; + }; +private: + ObTableLoadParallelMergeCtx parallel_merge_ctx_; + ParallelMergeCb parallel_merge_cb_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_partition_calc.cpp b/src/observer/table_load/ob_table_load_partition_calc.cpp new file mode 100644 index 0000000000..8499b23fb3 --- /dev/null +++ b/src/observer/table_load/ob_table_load_partition_calc.cpp @@ -0,0 +1,289 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_partition_calc.h" +#include "observer/ob_server_struct.h" +#include "observer/omt/ob_tenant_timezone_mgr.h" +#include "observer/table_load/ob_table_load_obj_cast.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/schema/ob_multi_version_schema_service.h" +#include "sql/session/ob_sql_session_info.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace share::schema; +using namespace sql; +using namespace table; + +static ObSQLSessionInfo &session() +{ + static ObSQLSessionInfo SESSION; + return SESSION; +} + +ObArenaAllocator &session_alloc() +{ + static ObArenaAllocator SESSION_ALLOC; + return SESSION_ALLOC; +} + +ObSQLSessionInfo &ObTableLoadPartitionCalc::get_session() +{ + return session(); +} + +int ObTableLoadPartitionCalc::init_session() +{ + int ret = OB_SUCCESS; + static const uint32_t sess_version = 0; + static const uint32_t sess_id = 1; + static const uint64_t proxy_sess_id = 1; + + // ensure allocator is constructed before session to + // avoid coredump at observer exit + // https://work.aone.alibaba-inc.com/issue/38530967 + ObArenaAllocator *allocator = &session_alloc(); + ObSQLSessionInfo &sess = session(); + + if (OB_FAIL(sess.test_init(sess_version, sess_id, proxy_sess_id, allocator))) { + LOG_WARN("init session failed", KR(ret)); + } else if (OB_FAIL(sess.load_default_sys_variable(false, true))) { + LOG_WARN("failed to load default sys var", KR(ret)); + } + return ret; +} + +ObTableLoadPartitionCalc::ObTableLoadPartitionCalc() + : tenant_id_(OB_INVALID_ID), + table_id_(OB_INVALID_ID), + is_partitioned_(false), + allocator_("TLD_PartCalc"), + exec_ctx_(allocator_), + is_inited_(false) +{ +} + +int ObTableLoadPartitionCalc::init(uint64_t tenant_id, uint64_t table_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadPartitionCalc init twice", KR(ret), KP(this)); + } else { + allocator_.set_tenant_id(tenant_id); + if (OB_FAIL(OTTZ_MGR.get_tenant_tz(tenant_id, tz_info_.get_tz_map_wrap()))) { + LOG_WARN("fail to get tenant time zone", KR(ret), K(tenant_id_)); + } else { + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + ObDataTypeCastParams cast_params(&tz_info_); + if (OB_FAIL(time_cvrt_.init(cast_params.get_nls_format(ObDateTimeType)))) { + LOG_WARN("fail to init time converter", KR(ret)); + } else if (OB_FAIL(ObTableLoadSchema::get_table_schema(tenant_id, table_id, schema_guard, + table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else { + const bool is_partitioned = table_schema->is_partitioned_table(); + if (!is_partitioned) { // 非分区表 + if (OB_FAIL(table_schema->get_tablet_and_object_id(partition_id_.tablet_id_, + partition_id_.partition_id_))) { + LOG_WARN("fail to get tablet and object", KR(ret)); + } + } else { // 分区表 + exec_ctx_.set_sql_ctx(&sql_ctx_); + // 初始化table_location_ + if (OB_FAIL( + table_location_.init_partition_ids_by_rowkey2(exec_ctx_, session(), schema_guard, table_id))) { + LOG_WARN("fail to init table location", KR(ret)); + } + // 获取rowkey_obj_index_ + else if (OB_FAIL(init_rowkey_index(table_schema, allocator_))) { + LOG_WARN("fail to get rowkey index", KR(ret)); + } + } + if (OB_SUCC(ret)) { + tenant_id_ = tenant_id; + table_id_ = table_id; + is_partitioned_ = is_partitioned; + is_inited_ = true; + } + } + } + } + return ret; +} + +int ObTableLoadPartitionCalc::init_rowkey_index(const ObTableSchema *table_schema, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObSEArray column_descs; + if (OB_FAIL(table_schema->get_column_ids(column_descs))) { + LOG_WARN("fail to get column ids", KR(ret)); + } else if (OB_UNLIKELY(column_descs.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected empty column desc", KR(ret)); + } + + int64_t part_key_num = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < column_descs.count(); ++i) { + const ObColumnSchemaV2 *column_schema = + table_schema->get_column_schema(column_descs.at(i).col_id_); + // pos是从1开始 + int64_t part_key_pos = column_schema->get_part_key_pos(); + int64_t sub_part_key_pos = column_schema->get_subpart_key_pos(); + if (part_key_pos > 0 || sub_part_key_pos > 0) { + part_key_num ++; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_obj_index_.create(part_key_num, allocator))) { + LOG_WARN("fail to create", KR(ret)); + } + } + int64_t pos = 0; + for (int64_t i = 0; OB_SUCC(ret) && i < column_descs.count(); ++i) { + const ObColumnSchemaV2 *column_schema = + table_schema->get_column_schema(column_descs.at(i).col_id_); + // pos是从1开始 + int64_t part_key_pos = column_schema->get_part_key_pos(); + int64_t sub_part_key_pos = column_schema->get_subpart_key_pos(); + if (part_key_pos > 0 || sub_part_key_pos > 0) { + pos ++; + if (OB_UNLIKELY(pos > rowkey_obj_index_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected rowkey position", KR(ret), KPC(column_schema), K(pos)); + } else { + if (table_schema->is_heap_table()) { + abort_unless(i > 0); + rowkey_obj_index_[pos - 1].index_ = i - 1; + } else { + rowkey_obj_index_[pos - 1].index_ = i; + } + rowkey_obj_index_[pos - 1].column_schema_ = column_schema; + } + } + } + return ret; +} + +int ObTableLoadPartitionCalc::calc(ObTableLoadPartitionCalcContext &ctx) const +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(calc_part_time_us); + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadPartitionCalc not init", KR(ret), KP(this)); + } else { + const ObTableLoadObjRowArray &obj_rows = ctx.obj_rows_; + const int64_t column_count = ctx.column_count_; + if (OB_UNLIKELY(obj_rows.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(column_count), K(obj_rows.count())); + } else { + const int64_t row_count = obj_rows.count(); + if (!is_partitioned_) { // 非分区表 + for (int64_t i = 0; OB_SUCC(ret) && i < row_count; ++i) { + if (OB_FAIL(ctx.partition_ids_.push_back(partition_id_))) { + LOG_WARN("failed to push back partition id", KR(ret)); + } + } + } else { // 分区表 + ObArray part_rows; + part_rows.set_block_allocator(ModulePageAllocator(ctx.allocator_)); + for (int64_t i = 0; OB_SUCC(ret) && i < row_count; ++i) { + ObNewRow part_row; + if (OB_FAIL( + get_row(obj_rows.at(i), column_count, part_row, ctx.allocator_))) { + LOG_WARN("fail to get rowkey", KR(ret)); + } else if (OB_FAIL(part_rows.push_back(part_row))) { + LOG_WARN("failed to push back partition row", KR(ret), K(part_row)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(get_partition_by_row(part_rows, ctx.partition_ids_))) { + LOG_WARN("fail to get partition", KR(ret)); + } + } + } + } + } + return ret; +} + +// FIXME: TODO, 对于非分区表,不能进入到这里计算 +int ObTableLoadPartitionCalc::get_row(const ObTableLoadObjRow &obj_row, int32_t length, ObNewRow &part_row, + ObIAllocator &allocator) const +{ + int ret = OB_SUCCESS; + const int64_t rowkey_obj_count = rowkey_obj_index_.count(); + ObObj *rowkey_objs = static_cast(allocator.alloc(sizeof(ObObj) * rowkey_obj_count)); + ObDataTypeCastParams cast_params(&tz_info_); + ObCastCtx cast_ctx(&allocator, &cast_params, CM_NONE, ObCharset::get_system_collation()); + ObTableLoadCastObjCtx cast_obj_ctx(&time_cvrt_, &cast_ctx, false); + if (OB_ISNULL(rowkey_objs)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_obj_count; ++i) { + const IndexAndType &index_and_type = rowkey_obj_index_.at(i); + const int64_t obj_index = index_and_type.index_; + if (OB_UNLIKELY(obj_index >= length)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid length", KR(ret), K(obj_index), K(length)); + } else if (index_and_type.column_schema_->is_identity_column() && obj_row.cells_[obj_index].is_null()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("partition column with identity cannot be null", KR(ret), K(index_and_type.column_schema_->get_column_name())); + } else if (index_and_type.column_schema_->is_autoincrement() && obj_row.cells_[obj_index].is_null()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("partition column with auto_increment cannot be null", KR(ret), K(index_and_type.column_schema_->get_column_name())); + } else if (OB_FAIL(ObTableLoadObjCaster::cast_obj(cast_obj_ctx, index_and_type.column_schema_, + obj_row.cells_[obj_index], rowkey_objs[i]))) { + LOG_WARN("fail to cast obj", KR(ret)); + } + } + if (OB_SUCC(ret)) { + part_row.assign(rowkey_objs, rowkey_obj_count); + } + return ret; +} + +int ObTableLoadPartitionCalc::get_partition_by_row( + ObIArray &part_rows, ObIArray &partition_ids) const +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + ObArray tablet_ids; + ObArray part_ids; + if (OB_FAIL(ObTableLoadSchema::get_schema_guard(tenant_id_, schema_guard))) { + LOG_WARN("fail to get schema guard", KR(ret), K_(tenant_id)); + } else if (OB_FAIL(table_location_.calculate_partition_ids_by_rows2( + session(), schema_guard, table_id_, part_rows, tablet_ids, part_ids))) { + LOG_WARN("fail to calc partition id", KR(ret)); + } else if (OB_UNLIKELY(part_rows.count() != part_ids.count() || + part_rows.count() != tablet_ids.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", K(part_ids.count()), K(tablet_ids.count())); + } + for (int i = 0; OB_SUCC(ret) && i < part_rows.count(); i++) { + if (OB_INVALID_PARTITION_ID == part_ids.at(i) + || ObTabletID::INVALID_TABLET_ID == tablet_ids.at(i).id()) { + ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; + LOG_WARN("no partition matched", KR(ret), K(part_ids.at(i)), K(tablet_ids.at(i))); + } else if (OB_FAIL( + partition_ids.push_back(ObTableLoadPartitionId(part_ids.at(i), tablet_ids.at(i))))) { + LOG_WARN("fail to push partition id", KR(ret)); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_partition_calc.h b/src/observer/table_load/ob_table_load_partition_calc.h new file mode 100644 index 0000000000..6ba0af3f65 --- /dev/null +++ b/src/observer/table_load/ob_table_load_partition_calc.h @@ -0,0 +1,80 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "common/object/ob_object.h" +#include "share/schema/ob_column_schema.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_row_array.h" +#include "share/table/ob_table_load_define.h" +#include "sql/optimizer/ob_table_location.h" +#include "sql/engine/ob_exec_context.h" +#include "observer/table_load/ob_table_load_time_convert.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadSchema; + +struct ObTableLoadPartitionCalcContext +{ + ObTableLoadPartitionCalcContext(const table::ObTableLoadObjRowArray &obj_rows, + int64_t column_count, common::ObIAllocator &allocator) + : obj_rows_(obj_rows), column_count_(column_count), allocator_(allocator) + { + partition_ids_.set_block_allocator(common::ModulePageAllocator(allocator_)); + } + const table::ObTableLoadObjRowArray &obj_rows_; + const int64_t column_count_; + common::ObIAllocator &allocator_; + common::ObArray partition_ids_; +}; + +class ObTableLoadPartitionCalc +{ +public: + static int init_session(); + static oceanbase::sql::ObSQLSessionInfo &get_session(); +public: + ObTableLoadPartitionCalc(); + int init(uint64_t tenant_id, uint64_t table_id); + int calc(ObTableLoadPartitionCalcContext &ctx) const; +private: + int init_rowkey_index(const share::schema::ObTableSchema *table_schema, + common::ObIAllocator &allocator); + int get_row(const table::ObTableLoadObjRow &obj_row, int32_t length, common::ObNewRow &part_row, + common::ObIAllocator &allocator) const; + int get_partition_by_row(common::ObIArray &part_rows, + common::ObIArray &partition_ids) const; +private: + struct IndexAndType + { + IndexAndType() : index_(-1) {} + int64_t index_; + const share::schema::ObColumnSchemaV2 *column_schema_; + TO_STRING_KV(K_(index), KP_(column_schema)); + }; +private: + // data members + uint64_t tenant_id_; + uint64_t table_id_; + bool is_partitioned_; + // 非分区表 + table::ObTableLoadPartitionId partition_id_; + // 分区表 + common::ObArenaAllocator allocator_; + sql::ObSqlCtx sql_ctx_; + sql::ObExecContext exec_ctx_; + sql::ObTableLocation table_location_; + table::ObTableLoadArray rowkey_obj_index_; + common::ObTimeZoneInfo tz_info_; + ObTableLoadTimeConverter time_cvrt_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPartitionCalc); +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_partition_location.cpp b/src/observer/table_load/ob_table_load_partition_location.cpp new file mode 100644 index 0000000000..58ca7031f2 --- /dev/null +++ b/src/observer/table_load/ob_table_load_partition_location.cpp @@ -0,0 +1,340 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_partition_location.h" +#include "observer/ob_server.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "storage/tx_storage/ob_ls_handle.h" +#include "storage/tx_storage/ob_ls_service.h" +#include "share/tablet/ob_tablet_to_ls_operator.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace share; +using namespace storage; +using namespace table; + +int ObTableLoadPartitionLocation::fetch_ls_id(uint64_t tenant_id, const ObTabletID &tablet_id, + ObLSID &ls_id) +{ + int ret = OB_SUCCESS; + ObLocationService &location_service = OBSERVER.get_location_service(); + const int64_t cluster_id = GCONF.cluster_id.get_value(); + MAKE_TENANT_SWITCH_SCOPE_GUARD(tenant_guard); + bool is_cache_hit = false; + if (OB_FAIL(tenant_guard.switch_to(OB_SYS_TENANT_ID))) { + LOG_WARN("fail to switch tenant", KR(ret), K(OB_SYS_TENANT_ID)); + } else if (OB_FAIL(location_service.get(tenant_id, tablet_id, INT64_MAX, is_cache_hit, ls_id))) { + LOG_WARN("fail to get ls id", KR(ret), K(tenant_id)); + } + return ret; +} + +int ObTableLoadPartitionLocation::fetch_ls_location(uint64_t tenant_id, const ObTabletID &tablet_id, + ObLSLocation &ls_location, ObLSID &ls_id) +{ + int ret = OB_SUCCESS; + ObLocationService &location_service = OBSERVER.get_location_service(); + const int64_t cluster_id = GCONF.cluster_id.get_value(); + MAKE_TENANT_SWITCH_SCOPE_GUARD(tenant_guard); + bool is_cache_hit = false; + if (OB_FAIL(tenant_guard.switch_to(OB_SYS_TENANT_ID))) { + LOG_WARN("fail to switch tenant", KR(ret), K(OB_SYS_TENANT_ID)); + } else if (OB_FAIL(location_service.get(tenant_id, tablet_id, INT64_MAX, is_cache_hit, ls_id))) { + LOG_WARN("fail to get ls id", KR(ret), K(tenant_id)); + } else if (OB_FAIL(location_service.get(cluster_id, tenant_id, ls_id, INT64_MAX, is_cache_hit, + ls_location))) { + LOG_WARN("fail to get location", KR(ret)); + } + return ret; +} + +int ObTableLoadPartitionLocation::fetch_ls_locations(uint64_t tenant_id, + const ObTableLoadArray &partition_ids) +{ + int ret = OB_SUCCESS; + ObArray ls_ids; + + for (int64_t i = 0; OB_SUCC(ret) && (i < partition_ids.count()); ++i) { + const ObTabletID &tablet_id = partition_ids[i].tablet_id_; + if (OB_FAIL(tablet_ids_.push_back(tablet_id))) { + LOG_WARN("failed to push back tablet_id", K(tablet_id), K(i)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObTabletToLSTableOperator::batch_get_ls(*(GCTX.sql_proxy_), + tenant_id, tablet_ids_, ls_ids))) { + LOG_WARN("table_load_partition failed to batch get ls", K(ret), K(tenant_id)); + } else { + ObLSLocation location; + ObHashMap ls_location_map; + ObLocationService &location_service = OBSERVER.get_location_service(); + const int64_t cluster_id = GCONF.cluster_id.get_value(); + MAKE_TENANT_SWITCH_SCOPE_GUARD(tenant_guard); + bool is_cache_hit = false; + + if (OB_FAIL(tenant_guard.switch_to(OB_SYS_TENANT_ID))) { + LOG_WARN("fail to switch tenant", KR(ret), K(OB_SYS_TENANT_ID)); + } else if (OB_FAIL(ls_location_map.create(1024, "TLD_PartLoc", "TLD_PartLoc", tenant_id))) { + LOG_WARN("fail to create location info map", KR(ret)); + } else { + // avoid redundant location info lookups + for (int64_t i = 0; OB_SUCC(ret) && i < partition_ids.count(); ++i) { + const ObLSID &ls_id = ls_ids.at(i); + PartitionLocationInfo info; + info.partition_id_.part_tablet_id_ = partition_ids.at(i); + info.partition_id_.ls_id_ = ls_id; + + if (OB_FAIL(ls_location_map.get_refactored(ls_id, info.leader_addr_))) { + if (ret != OB_HASH_NOT_EXIST) { + LOG_WARN("failed to get refactored", K(ret), K(i), K(ls_id)); + } else if (OB_FAIL(location_service.get(cluster_id, + tenant_id, ls_id, INT64_MAX, is_cache_hit, location))) { + LOG_WARN("fail to get location", KR(ret)); + } else if (OB_FAIL(location.get_leader(info.leader_addr_))) { + LOG_WARN("fail to get leader", KR(ret)); + } else if (OB_FAIL(ls_location_map.set_refactored(ls_id, info.leader_addr_))) { + LOG_WARN("failed to set refactored", K(ret), K(ls_id), K(info)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(partition_map_.set_refactored(tablet_ids_.at(i), info))) { + LOG_WARN("fail to set refactored", KR(ret), K(i), K(info)); + } + } + } + } + + return ret; +} + +int ObTableLoadPartitionLocation::fetch_location_leader(uint64_t tenant_id, + const ObTabletID &tablet_id, PartitionLocationInfo &info) +{ + int ret = OB_SUCCESS; + ObLSLocation location; + if (OB_FAIL(fetch_ls_location(tenant_id, tablet_id, location, info.partition_id_.ls_id_))) { + LOG_WARN("fail to fetch ls location", KR(ret), K(tenant_id), K(tablet_id)); + } else if (OB_FAIL(location.get_leader(info.leader_addr_))) { + LOG_WARN("fail to get leader", KR(ret)); + } + return ret; +} + +int ObTableLoadPartitionLocation::fetch_tablet_handle(uint64_t tenant_id, const ObLSID &ls_id, + const ObTabletID &tablet_id, + ObTabletHandle &tablet_handle) +{ + int ret = OB_SUCCESS; + ObLSService *ls_svr = nullptr; + ObLSHandle ls_handle; + ObLS *ls = nullptr; + ObLSTabletService *tablet_service = nullptr; + if (OB_ISNULL(ls_svr = MTL(ObLSService *))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("MTL ObLSService failed", KR(ret), "tenant_id", OB_SYS_TENANT_ID, K(MTL_ID())); + } else if (OB_FAIL(ls_svr->get_ls(ls_id, ls_handle, ObLSGetMod::STORAGE_MOD))) { + if (OB_UNLIKELY(OB_LS_NOT_EXIST == ret)) { + LOG_WARN("get ls handle failed", KR(ret), "log_stream_id", ls_id.id()); + } + } else if (OB_ISNULL(ls = ls_handle.get_ls())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ls_handle.get_ls() is nullptr", KR(ret)); + } else if (OB_ISNULL(tablet_service = ls->get_tablet_svr())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("tablet service should not be NULL", KR(ret), KP(tablet_service)); + } else if (OB_FAIL(tablet_service->get_tablet(tablet_id, tablet_handle))) { + LOG_WARN("fail to get tablet", KR(ret)); + } + return ret; +} + +int ObTableLoadPartitionLocation::fetch_tablet_handle(uint64_t tenant_id, + const ObTabletID &tablet_id, + ObTabletHandle &tablet_handle) +{ + int ret = OB_SUCCESS; + ObLSID ls_id; + if (OB_FAIL(fetch_ls_id(tenant_id, tablet_id, ls_id))) { + LOG_WARN("fail to fetch ls id", KR(ret)); + } else if (OB_FAIL(fetch_tablet_handle(tenant_id, ls_id, tablet_id, tablet_handle))) { + LOG_WARN("fail to fetch tablet handle", KR(ret)); + } + return ret; +} + +int ObTableLoadPartitionLocation::init( + uint64_t tenant_id, const ObTableLoadArray &partition_ids, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadPartitionLocation init twice", KR(ret)); + } else if (OB_UNLIKELY(partition_ids.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(partition_ids)); + } else { + if (OB_FAIL(partition_map_.create(1024, "TLD_PartLoc", "TLD_PartLoc", tenant_id))) { + LOG_WARN("fail to create map", KR(ret)); + } else if (OB_FAIL(init_all_partition_location(tenant_id, partition_ids, allocator))) { + LOG_WARN("fail to init all partition location", KR(ret)); + } else if (OB_FAIL(init_all_leader_info(allocator))) { + LOG_WARN("fail to init all leader info", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadPartitionLocation::init_all_partition_location( + uint64_t tenant_id, const ObTableLoadArray &partition_ids, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(fetch_ls_locations(tenant_id, partition_ids))) { + LOG_WARN("fail to fetch locations", KR(ret), K(tenant_id), K(table_id)); + } + return ret; +} + +int ObTableLoadPartitionLocation::init_all_leader_info(ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObArenaAllocator tmp_allocator("TLD_PL_Tmp"); + ObHashMap *> addr_map; + ObHashMap *>::const_iterator addr_iter; + int64_t pos = 0; + // 将所有addr存到set中 + if (OB_FAIL(addr_map.create(64, "TLD_PL_Tmp", "TLD_PL_Tmp"))) { + LOG_WARN("fail to create hashmap", KR(ret)); + } else { + ObHashMap::const_iterator iter; + for (int64_t i = 0; OB_SUCC(ret) && i < tablet_ids_.count(); i ++) { + PartitionLocationInfo info; + if (OB_FAIL(partition_map_.get_refactored(tablet_ids_.at(i), info))) { + LOG_WARN("fail to get tablet info", K(tablet_ids_.at(i)), KR(ret)); + } + const ObTableLoadLSIdAndPartitionId &partition_id = info.partition_id_; + const ObAddr &addr = info.leader_addr_; + ObIArray *partition_id_array = nullptr; + if (OB_SUCC(ret)) { + if (OB_FAIL(addr_map.get_refactored(addr, partition_id_array))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get refactored", KR(ret), K(addr)); + } else { + if (OB_ISNULL(partition_id_array = + OB_NEWx(ObArray, (&tmp_allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new array", KR(ret)); + } else if (OB_FAIL(addr_map.set_refactored(addr, partition_id_array))) { + LOG_WARN("fail to set refactored", KR(ret), K(addr)); + } + if (OB_FAIL(ret)) { + if (nullptr != partition_id_array) { + partition_id_array->~ObIArray(); + tmp_allocator.free(partition_id_array); + partition_id_array = nullptr; + } + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(partition_id_array->push_back(partition_id))) { + LOG_WARN("fail to push back partition id", KR(ret)); + } + } + } + } + } + // 将set中的addr存到array中 + if (OB_SUCC(ret)) { + if (OB_FAIL(all_leader_addr_array_.create(addr_map.size(), allocator))) { + LOG_WARN("fail to create leader addr array", KR(ret)); + } else if (OB_FAIL(all_leader_info_array_.create(addr_map.size(), allocator))) { + LOG_WARN("fail to create leader info array", KR(ret)); + } + } + ObArray sort_array; + for (addr_iter = addr_map.begin(); OB_SUCC(ret) && addr_iter != addr_map.end(); ++pos, ++addr_iter) { + LeaderInfoForSort item; + item.addr_ = addr_iter->first; + item.partition_id_array_ptr_ = addr_iter->second; + if (OB_FAIL(sort_array.push_back(item))) { + LOG_WARN("fail to push_back item", KR(ret)); + } + } + if (OB_SUCC(ret)) { + std::sort(sort_array.begin(), sort_array.end(), [](const ObTableLoadPartitionLocation::LeaderInfoForSort &a, + ObTableLoadPartitionLocation::LeaderInfoForSort &b) { + return a.addr_ < b.addr_; + }); + } + for (int64_t i = 0; OB_SUCC(ret) && i < sort_array.count(); i ++) { + const ObAddr &addr = sort_array.at(i).addr_; + ObIArray *partition_id_array = sort_array.at(i).partition_id_array_ptr_; + all_leader_addr_array_[i] = addr; + LeaderInfo &leader_info = all_leader_info_array_[i]; + leader_info.addr_ = addr; + if (OB_FAIL(ObTableLoadUtils::deep_copy(*partition_id_array, leader_info.partition_id_array_, + allocator))) { + LOG_WARN("fail to deep copy partition id array", KR(ret)); + } + partition_id_array->~ObIArray(); + tmp_allocator.free(partition_id_array); + } + + return ret; +} + +int ObTableLoadPartitionLocation::get_leader(ObTabletID tablet_id, PartitionLocationInfo &info) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadPartitionLocation not init", KR(ret)); + } else { + if (OB_FAIL(partition_map_.get_refactored(tablet_id, info))) { + LOG_WARN("fail to get refactored", KR(ret), K(tablet_id)); + } + } + return ret; +} + +int ObTableLoadPartitionLocation::get_all_leader(ObTableLoadArray &addr_array) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadPartitionLocation not init", KR(ret)); + } else { + addr_array = all_leader_addr_array_; + } + return ret; +} + +int ObTableLoadPartitionLocation::get_all_leader_info(ObTableLoadArray &info_array) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadPartitionLocation not init", KR(ret)); + } else { + info_array = all_leader_info_array_; + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_partition_location.h b/src/observer/table_load/ob_table_load_partition_location.h new file mode 100644 index 0000000000..674601f3a7 --- /dev/null +++ b/src/observer/table_load/ob_table_load_partition_location.h @@ -0,0 +1,86 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "common/ob_tablet_id.h" +#include "lib/hash/ob_hashmap.h" +#include "lib/net/ob_addr.h" +#include "share/ob_ls_id.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace share +{ +class ObLSLocation; +} // namespace share +namespace storage +{ +class ObTabletHandle; +} // namespace storage +namespace observer +{ + +class ObTableLoadPartitionLocation +{ +public: + struct PartitionLocationInfo + { + table::ObTableLoadLSIdAndPartitionId partition_id_; + common::ObAddr leader_addr_; + TO_STRING_KV(K_(partition_id), K_(leader_addr)); + }; + struct LeaderInfo + { + common::ObAddr addr_; + table::ObTableLoadArray partition_id_array_; + TO_STRING_KV(K_(addr), K_(partition_id_array)); + }; + struct LeaderInfoForSort + { + common::ObAddr addr_; + common::ObIArray *partition_id_array_ptr_; + TO_STRING_KV(K_(addr), KP_(partition_id_array_ptr)); + }; +public: + ObTableLoadPartitionLocation() : is_inited_(false) {} + int init(uint64_t tenant_id, + const table::ObTableLoadArray &partition_ids, + common::ObIAllocator &allocator); + int get_leader(common::ObTabletID tablet_id, PartitionLocationInfo &info) const; + int get_all_leader(table::ObTableLoadArray &addr_array) const; + int get_all_leader_info(table::ObTableLoadArray &info_array) const; +public: + // 通过tablet_id获取 + static int fetch_ls_id(uint64_t tenant_id, const common::ObTabletID &tablet_id, + share::ObLSID &ls_id); + static int fetch_ls_location(uint64_t tenant_id, const common::ObTabletID &tablet_id, + share::ObLSLocation &ls_location, share::ObLSID &ls_id); + static int fetch_location_leader(uint64_t tenant_id, const common::ObTabletID &tablet_id, + PartitionLocationInfo &info); + static int fetch_tablet_handle(uint64_t tenant_id, const share::ObLSID &ls_id, + const common::ObTabletID &tablet_id, + storage::ObTabletHandle &tablet_handle); + static int fetch_tablet_handle(uint64_t tenant_id, const common::ObTabletID &tablet_id, + storage::ObTabletHandle &tablet_handle); +private: + int init_all_partition_location( + uint64_t tenant_id, const table::ObTableLoadArray &partition_ids, + common::ObIAllocator &allocator); + int init_all_leader_info(common::ObIAllocator &allocator); + int fetch_ls_locations( + uint64_t tenant_id, + const table::ObTableLoadArray &partition_ids); + private: + common::ObArray tablet_ids_; //保证遍历partition_map_的时候顺序不变 + common::hash::ObHashMap partition_map_; + table::ObTableLoadArray all_leader_addr_array_; + table::ObTableLoadArray all_leader_info_array_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_processor.cpp b/src/observer/table_load/ob_table_load_processor.cpp new file mode 100644 index 0000000000..93547b7fd4 --- /dev/null +++ b/src/observer/table_load/ob_table_load_processor.cpp @@ -0,0 +1,216 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_csv_parser.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "sql/engine/cmd/ob_load_data_parser.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; +using namespace sql; + +/** + * ObTableLoadP + */ + +int ObTableLoadP::deserialize() +{ + return ParentType::deserialize(); +} + +int ObTableLoadP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadSharedAllocatorHandle allocator_handle = ObTableLoadSharedAllocatorHandle::make_handle(); + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (!allocator_handle) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to make allocator handle", KR(ret)); + } else if (table_ctx->param_.data_type_ == ObTableLoadDataType::RAW_STRING) { + int64_t col_count = table_ctx->param_.column_count_; + ObTableLoadObjRowArray obj_rows; + obj_rows.set_allocator(allocator_handle); + ObTableLoadCSVParser csv_parser; + ObTableLoadArray store_column_objs; + if (OB_FAIL(csv_parser.init(table_ctx, arg_.payload_))) { + LOG_WARN("fail to init csv parser", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(csv_parser.get_batch_objs(store_column_objs))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get batch objs", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else { + ObObj *src_objs = store_column_objs.ptr(); + int64_t row_count = store_column_objs.count() / col_count; + for (int64_t i = 0; OB_SUCC(ret) && (i < row_count); ++i) { + ObTableLoadObjRow obj_row; + if (OB_FAIL(obj_row.deep_copy_and_assign(src_objs, col_count, allocator_handle))) { + LOG_WARN("failed to deep copy and assign src_objs to obj_row", KR(ret)); + } else if (OB_FAIL(obj_rows.push_back(obj_row))) { + LOG_WARN("failed to add row to obj_rows", KR(ret), K(obj_row)); + } else { + src_objs += col_count; + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(coordinator.write(arg_.trans_id_, arg_.session_id_, arg_.sequence_no_, + obj_rows))) { + LOG_WARN("fail to coordinator write objs", KR(ret)); + } + } + } + } + } else { + int64_t pos = 0; + int64_t data_len = arg_.payload_.length(); + char *buf = static_cast(allocator_handle->alloc(data_len)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", KR(ret)); + } else { + MEMCPY(buf, arg_.payload_.ptr(), data_len); + if (table_ctx->param_.data_type_ == ObTableLoadDataType::OBJ_ARRAY) { + ObTableLoadObjRowArray obj_rows; + obj_rows.set_allocator(allocator_handle); + if (OB_FAIL(obj_rows.deserialize(buf, data_len, pos))) { + LOG_WARN("failed to deserialize obj rows", KR(ret)); + } else if (OB_FAIL( + coordinator.write(arg_.trans_id_, arg_.session_id_, arg_.sequence_no_, obj_rows))) { + LOG_WARN("fail to coordinator write", KR(ret)); + } + } else if (table_ctx->param_.data_type_ == ObTableLoadDataType::STR_ARRAY) { + ObTableLoadObjRowArray obj_rows; + obj_rows.set_allocator(allocator_handle); + ObTableLoadStrRowArray str_rows; + str_rows.set_allocator(allocator_handle); + + if (OB_FAIL(str_rows.deserialize(buf, data_len, pos))) { + LOG_WARN("failed to deserialize str rows", KR(ret)); + } else { + int64_t col_count = table_ctx->param_.column_count_; + for (int64_t i = 0; OB_SUCC(ret) && (i < str_rows.count()); ++i) { + ObTableLoadObjRow obj_row; + if (OB_FAIL(obj_row.init(col_count, allocator_handle))) { + LOG_WARN("failed to init obj_row", KR(ret)); + } else { + ObTableLoadStrRow &str_row = str_rows.at(i); + for (int64_t j = 0; OB_SUCC(ret) && (j < col_count); ++j) { + obj_row.cells_[j].set_string(ObVarcharType, str_row.cells_[j]); + obj_row.cells_[j].set_collation_type( + ObCharset::get_default_collation(ObCharset::get_default_charset())); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(obj_rows.push_back(obj_row))) { + LOG_WARN("failed to push back obj_row to obj_rows", KR(ret)); + } + } + } // end for() + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(coordinator.write(arg_.trans_id_, arg_.session_id_, arg_.sequence_no_, + obj_rows))) { + LOG_WARN("fail to coordinator write objs", KR(ret)); + } + } + } + } + } // end if + } // end if + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadPeerP + */ + +int ObTableLoadPeerP::deserialize() +{ + return ParentType::deserialize(); +} + +int ObTableLoadPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + ObTableLoadSharedAllocatorHandle allocator_handle = ObTableLoadSharedAllocatorHandle::make_handle(); + int64_t data_len = arg_.payload_.length(); + char *buf = nullptr; + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else if (!allocator_handle) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to make allocator handle", KR(ret)); + } else if (OB_ISNULL(buf = static_cast(allocator_handle->alloc(data_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", KR(ret)); + } else { + int64_t pos = 0; + ObTableLoadStore store(table_ctx); + ObTableLoadTabletObjRowArray row_array; + row_array.set_allocator(allocator_handle); + MEMCPY(buf, arg_.payload_.ptr(), data_len); + if (OB_FAIL(row_array.deserialize(buf, data_len, pos))) { + LOG_WARN("failed to deserialize obj rows", KR(ret)); + } else if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.write(arg_.trans_id_, arg_.session_id_, arg_.sequence_no_, row_array))) { + LOG_WARN("fail to store write", KR(ret), K_(arg)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_processor.h b/src/observer/table_load/ob_table_load_processor.h new file mode 100644 index 0000000000..cfc1ac79a4 --- /dev/null +++ b/src/observer/table_load/ob_table_load_processor.h @@ -0,0 +1,60 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadP : public obrpc::ObRpcProcessor > +{ + typedef obrpc::ObRpcProcessor > ParentType; +public: + explicit ObTableLoadP(const ObGlobalContext &gctx) : gctx_(gctx), allocator_("TLD_LoadP") {} + virtual ~ObTableLoadP() = default; + +protected: + int deserialize() override; + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; + common::ObArenaAllocator allocator_; +}; + +class ObTableLoadPeerP : public obrpc::ObRpcProcessor > +{ + typedef obrpc::ObRpcProcessor > ParentType; +public: + explicit ObTableLoadPeerP(const ObGlobalContext &gctx) : gctx_(gctx), allocator_("TLD_PLoadP") {} + virtual ~ObTableLoadPeerP() = default; + +protected: + int deserialize() override; + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; + common::ObArenaAllocator allocator_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_queue.h b/src/observer/table_load/ob_table_load_queue.h new file mode 100644 index 0000000000..a79b1da857 --- /dev/null +++ b/src/observer/table_load/ob_table_load_queue.h @@ -0,0 +1,108 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/ob_malloc.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_utility.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace observer +{ + +template +class ObTableLoadQueue +{ +public: + ObTableLoadQueue(); + ~ObTableLoadQueue(); + int init(uint64_t tenant_id, uint64_t capacity); + int push(T *obj, int64_t timeout_us = 0); + int pop(T *&obj, int64_t timeout_us = 0); + int push_nowait(T *obj); + int pop_nowait(T *&obj); + int64_t size() const; +private: + T **queue_; + uint64_t capacity_; + uint64_t push_; + uint64_t pop_; + int64_t size_; + mutable pthread_mutex_t mutex_; + pthread_cond_t push_cond_; + pthread_cond_t pop_cond_; + bool is_inited_; +}; + +template +ObTableLoadQueue::ObTableLoadQueue() + : queue_(nullptr), capacity_(0), push_(0), pop_(0), size_(0), is_inited_(false) +{ + OB_ASSERT(0 == pthread_mutex_init(&mutex_, nullptr)); + OB_ASSERT(0 == pthread_cond_init(&push_cond_, nullptr)); + OB_ASSERT(0 == pthread_cond_init(&pop_cond_, nullptr)); +} + +template +ObTableLoadQueue::~ObTableLoadQueue() +{ + if (nullptr != queue_) { + common::ob_free(queue_); + queue_ = nullptr; + } + OB_ASSERT(0 == pthread_mutex_destroy(&mutex_)); + OB_ASSERT(0 == pthread_cond_destroy(&push_cond_)); + OB_ASSERT(0 == pthread_cond_destroy(&pop_cond_)); +} + +template +int ObTableLoadQueue::init(uint64_t tenant_id, uint64_t capacity) +{ + int ret = common::OB_SUCCESS; + return ret; +} + +template +int64_t ObTableLoadQueue::size() const +{ + int64_t size = 0; + pthread_mutex_lock(&mutex_); + size = size_; + pthread_mutex_unlock(&mutex_); + return size; +} + +template +int ObTableLoadQueue::push(T *obj, int64_t timeout_us) +{ + int ret = common::OB_SUCCESS; + return ret; +} + +template +int ObTableLoadQueue::pop(T *&obj, int64_t timeout_us) +{ + int ret = common::OB_SUCCESS; + return ret; +} + +template +int ObTableLoadQueue::push_nowait(T *obj) +{ + int ret = common::OB_SUCCESS; + return ret; +} + +template +int ObTableLoadQueue::pop_nowait(T *&obj) +{ + int ret = common::OB_SUCCESS; + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_redef_table.cpp b/src/observer/table_load/ob_table_load_redef_table.cpp new file mode 100644 index 0000000000..53af6c5ff5 --- /dev/null +++ b/src/observer/table_load/ob_table_load_redef_table.cpp @@ -0,0 +1,174 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_redef_table.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/ob_common_rpc_proxy.h" +#include "sql/engine/cmd/ob_ddl_executor_util.h" +#include "storage/ddl/ob_ddl_server_client.h" + +namespace oceanbase +{ +using namespace common; +using namespace sql; +using namespace obrpc; +namespace observer +{ +ObTableLoadRedefTable::ObTableLoadRedefTable() + : ctx_(nullptr), + session_info_(nullptr), + ddl_task_id_(0), + schema_version_(0), + is_finish_or_abort_called_(false), + is_inited_(false) +{ +} + +ObTableLoadRedefTable::~ObTableLoadRedefTable() +{ + if (!is_finish_or_abort_called_) { + abort(); // 这个必须执行 + } +} + +int ObTableLoadRedefTable::init(ObTableLoadTableCtx *ctx, ObSQLSessionInfo *session_info) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadRedefTable init twice", KR(ret), KP(this)); + } else if (OB_ISNULL(ctx) || OB_ISNULL(session_info)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("table_ctx or session_info cannot be null", KR(ret)); + } else { + ctx_ = ctx; + session_info_ = session_info; + is_inited_ = true; + } + return ret; +} + +int ObTableLoadRedefTable::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadRedefTable not init", KR(ret)); + } else { + const int64_t origin_timeout_ts = THIS_WORKER.get_timeout_ts(); + ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + ObCreateHiddenTableArg create_table_arg; + ObCreateHiddenTableRes create_table_res; + create_table_arg.reset(); + create_table_arg.tenant_id_ = ctx_->param_.tenant_id_; + create_table_arg.table_id_ = ctx_->param_.table_id_; + create_table_arg.dest_tenant_id_ = ctx_->param_.tenant_id_; + create_table_arg.parallelism_ = ctx_->param_.session_count_; + create_table_arg.ddl_type_ = share::DDL_DIRECT_LOAD; + create_table_arg.session_id_ = session_info_->get_sessid_for_table(); + create_table_arg.sql_mode_ = session_info_->get_sql_mode(); + create_table_arg.tz_info_ = session_info_->get_tz_info_wrap().get_tz_info_offset(); + create_table_arg.nls_formats_[ObNLSFormatEnum::NLS_DATE] = session_info_->get_local_nls_date_format(); + create_table_arg.nls_formats_[ObNLSFormatEnum::NLS_TIMESTAMP] = session_info_->get_local_nls_timestamp_format(); + create_table_arg.nls_formats_[ObNLSFormatEnum::NLS_TIMESTAMP_TZ] = session_info_->get_local_nls_timestamp_tz_format(); + if (OB_FAIL(create_table_arg.tz_info_wrap_.deep_copy(session_info_->get_tz_info_wrap()))) { + LOG_WARN("failed to deep copy tz_info_wrap", KR(ret)); + } else if (OB_FAIL(ObDDLServerClient::create_hidden_table(create_table_arg, create_table_res, *session_info_))) { + LOG_WARN("failed to create hidden table", KR(ret), K(create_table_arg)); + } else { + ddl_task_id_ = create_table_res.task_id_; + schema_version_ = create_table_res.schema_version_; + const_cast(ctx_->param_).target_table_id_ = create_table_res.dest_table_id_; + LOG_INFO("succeed to create hidden table", K(create_table_res), K(create_table_res)); + } + THIS_WORKER.set_timeout_ts(origin_timeout_ts); + } + + + return ret; +} + +int ObTableLoadRedefTable::finish() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadRedefTable not init", KR(ret)); + } else { + const int64_t origin_timeout_ts = THIS_WORKER.get_timeout_ts(); + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + obrpc::ObCopyTableDependentsArg copy_table_dependents_arg; + copy_table_dependents_arg.task_id_ = ddl_task_id_; + copy_table_dependents_arg.tenant_id_ = ctx_->param_.tenant_id_; + copy_table_dependents_arg.copy_indexes_ = true; + copy_table_dependents_arg.copy_constraints_ = true; + copy_table_dependents_arg.copy_triggers_ = false; + copy_table_dependents_arg.ignore_errors_ = false; + if (OB_FAIL(ObDDLServerClient::copy_table_dependents(copy_table_dependents_arg))) { + LOG_WARN("failed to copy table dependents", KR(ret), K(copy_table_dependents_arg)); + } else { + LOG_INFO("succeed to copy table dependents", K(copy_table_dependents_arg)); + obrpc::ObFinishRedefTableArg finish_redef_table_arg; + finish_redef_table_arg.task_id_ = ddl_task_id_; + finish_redef_table_arg.tenant_id_ = ctx_->param_.tenant_id_; + + ObDDLBuildSingleReplicaResponseArg build_single_replica_response_arg; + build_single_replica_response_arg.task_id_ = ddl_task_id_; + build_single_replica_response_arg.tenant_id_ = ctx_->param_.tenant_id_; + build_single_replica_response_arg.ls_id_ = share::ObLSID(1); + build_single_replica_response_arg.tablet_id_ = ObTableID(-1); + build_single_replica_response_arg.source_table_id_ = ctx_->param_.table_id_; + build_single_replica_response_arg.dest_schema_id_ = ctx_->param_.target_table_id_; + build_single_replica_response_arg.ret_code_ = ret; + build_single_replica_response_arg.task_id_ = ddl_task_id_; + build_single_replica_response_arg.snapshot_version_ = 1; + build_single_replica_response_arg.schema_version_ = schema_version_; + build_single_replica_response_arg.execution_id_ = 1; + if (OB_FAIL(ObDDLServerClient::finish_redef_table(finish_redef_table_arg))) { + LOG_WARN("failed to finish redef table", KR(ret), K(finish_redef_table_arg)); + } else if (OB_FAIL(ObDDLServerClient::build_ddl_single_replica_response(build_single_replica_response_arg))) { + LOG_WARN("failed to build ddl single replica reponse", KR(ret)); + } else if (OB_FAIL(ObDDLExecutorUtil::wait_ddl_finish(ctx_->param_.tenant_id_, ddl_task_id_, + *session_info_, common_rpc_proxy))) { + LOG_WARN("failed to wait ddl finish", KR(ret)); + } else { + is_finish_or_abort_called_ = true; + LOG_INFO("succeed to finish redef table", KR(ret), K(finish_redef_table_arg)); + } + } + THIS_WORKER.set_timeout_ts(origin_timeout_ts); + } + return ret; +} + +int ObTableLoadRedefTable::abort() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadRedefTable not init", KR(ret)); + } else { + const int64_t origin_timeout_ts = THIS_WORKER.get_timeout_ts(); + is_finish_or_abort_called_ = true; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + obrpc::ObAbortRedefTableArg abort_redef_table_arg; + abort_redef_table_arg.task_id_ = ddl_task_id_; + abort_redef_table_arg.tenant_id_ = ctx_->param_.tenant_id_; + if (OB_FAIL(ObDDLServerClient::abort_redef_table(abort_redef_table_arg))) { + LOG_WARN("failed to abort redef table", KR(ret), K(abort_redef_table_arg)); + } else if (OB_FAIL(ObDDLExecutorUtil::wait_ddl_finish(ctx_->param_.tenant_id_, ddl_task_id_, + *session_info_, common_rpc_proxy))) { + LOG_WARN("failed to wait ddl finish", KR(ret)); + } else { + LOG_INFO("abort_redef_table success", KR(ret)); + } + THIS_WORKER.set_timeout_ts(origin_timeout_ts); + } + return ret; +} +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_redef_table.h b/src/observer/table_load/ob_table_load_redef_table.h new file mode 100644 index 0000000000..2cf4ed4737 --- /dev/null +++ b/src/observer/table_load/ob_table_load_redef_table.h @@ -0,0 +1,38 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace sql +{ +class ObSQLSessionInfo; +} +namespace observer +{ +class ObTableLoadTableCtx; + +class ObTableLoadRedefTable +{ +public: + ObTableLoadRedefTable(); + ~ObTableLoadRedefTable(); + int init(ObTableLoadTableCtx *ctx, sql::ObSQLSessionInfo *session_info); + int start(); + int finish(); + int abort(); + OB_INLINE int64_t get_ddl_task_id() const { return ddl_task_id_; } +private: + ObTableLoadTableCtx * ctx_; + sql::ObSQLSessionInfo *session_info_; + int64_t ddl_task_id_; + int64_t schema_version_; + bool is_finish_or_abort_called_; + bool is_inited_; +}; +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_schema.cpp b/src/observer/table_load/ob_table_load_schema.cpp new file mode 100644 index 0000000000..c512595740 --- /dev/null +++ b/src/observer/table_load/ob_table_load_schema.cpp @@ -0,0 +1,278 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "share/schema/ob_multi_version_schema_service.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace share::schema; +using namespace table; + +int ObTableLoadSchema::get_schema_guard(uint64_t tenant_id, ObSchemaGetterGuard &schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard(tenant_id, + schema_guard))) { + LOG_WARN("fail to get tenant schema guard", KR(ret), K(tenant_id)); + } + return ret; +} + +int ObTableLoadSchema::get_table_schema(uint64_t tenant_id, uint64_t database_id, + const ObString &table_name, + ObSchemaGetterGuard &schema_guard, + const ObTableSchema *&table_schema) +{ + int ret = OB_SUCCESS; + table_schema = nullptr; + if (OB_FAIL(get_schema_guard(tenant_id, schema_guard))) { + LOG_WARN("fail to get schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, database_id, table_name, false, + table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(database_id), K(table_name)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(database_id), K(table_name)); + } + return ret; +} + +int ObTableLoadSchema::get_table_schema(uint64_t tenant_id, uint64_t table_id, + ObSchemaGetterGuard &schema_guard, + const ObTableSchema *&table_schema) +{ + int ret = OB_SUCCESS; + table_schema = nullptr; + if (OB_FAIL(get_schema_guard(tenant_id, schema_guard))) { + LOG_WARN("fail to get schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(table_id)); + } + return ret; +} + +int ObTableLoadSchema::get_database_and_table_schema(uint64_t tenant_id, uint64_t database_id, + uint64_t table_id, + ObSchemaGetterGuard &schema_guard, + const ObDatabaseSchema *&database_schema, + const ObTableSchema *&table_schema) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(get_schema_guard(tenant_id, schema_guard))) { + LOG_WARN("fail to get schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_database_schema(tenant_id, database_id, database_schema))) { + LOG_WARN("fail to get database schema", KR(ret), K(tenant_id), K(database_id)); + } else if (OB_ISNULL(database_schema)) { + ret = OB_ERR_BAD_DATABASE; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(database_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(database_id), K(table_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(database_id), K(table_id)); + } + return ret; +} + +int ObTableLoadSchema::get_column_names(const ObTableSchema *table_schema, ObIAllocator &allocator, + ObTableLoadArray &column_names) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table_schema)) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadSchema not init", KR(ret)); + } else { + ObSEArray column_name_array; + ObColumnIterByPrevNextID iter(*table_schema); + const ObColumnSchemaV2 *column_schema = NULL; + while (OB_SUCC(ret) && OB_SUCC(iter.next(column_schema))) { + if (OB_ISNULL(column_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("The column is null", K(ret)); + } else if (!column_schema->is_hidden() + && !column_schema->is_invisible_column()) { + if (column_schema->is_virtual_generated_column()) { + } else if (OB_FAIL(column_name_array.push_back(column_schema->get_column_name_str()))) { + LOG_WARN("failed to push back item", K(ret)); + } + } + } + if (ret != OB_ITER_END) { + LOG_WARN("Failed to iterate all table columns. iter quit. ", K(ret)); + } else { + ret = OB_SUCCESS; + if (OB_UNLIKELY(column_name_array.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected empty column desc", KR(ret)); + } else if (OB_FAIL(column_names.create(column_name_array.count(), allocator))) { + LOG_WARN("fail to create", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < column_name_array.count(); ++i) { + const ObString &column_name = column_name_array.at(i); + if (OB_FAIL(ob_write_string(allocator, column_name, column_names[i]))) { + LOG_WARN("fail to write string", KR(ret), K(i), K(column_name)); + } + } + } + } + return ret; +} + +int ObTableLoadSchema::get_schema_version(uint64_t tenant_id, uint64_t table_id, + int64_t &schema_version) +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL( + ObTableLoadSchema::get_table_schema(tenant_id, table_id, schema_guard, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else { + schema_version = table_schema->get_schema_version(); + } + return ret; +} + +int ObTableLoadSchema::check_constraints(uint64_t tenant_id, + ObSchemaGetterGuard &schema_guard, + const ObTableSchema *table_schema) +{ + int ret = OB_SUCCESS; + bool trigger_enabled = false; + ObArray simple_index_infos; + if (OB_FAIL(table_schema->get_simple_index_infos(simple_index_infos))) { + LOG_WARN("failed to get simple index infos", KR(ret)); + } else if (OB_FAIL(table_schema->check_has_trigger_on_table(schema_guard, trigger_enabled))) { + LOG_WARN("failed to check has trigger in table", KR(ret)); + } else if (trigger_enabled) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("direct-load does not support table with trigger enabled", KR(ret), K(trigger_enabled)); + } + return ret; +} + +ObTableLoadSchema::ObTableLoadSchema() + : is_partitioned_table_(false), + is_heap_table_(false), + has_autoinc_column_(false), + has_identity_column_(false), + rowkey_column_count_(0), + column_count_(0), + collation_type_(CS_TYPE_INVALID), + schema_version_(0), + is_inited_(false) +{ +} + +int ObTableLoadSchema::init(uint64_t tenant_id, uint64_t database_id, uint64_t table_id, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadSchema init twice", KR(ret)); + } else { + ObSchemaGetterGuard schema_guard; + const ObDatabaseSchema *database_schema = nullptr; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(get_database_and_table_schema(tenant_id, database_id, table_id, schema_guard, + database_schema, table_schema))) { + LOG_WARN("fail to get database and table schema", KR(ret), K(tenant_id)); + } else if (OB_FAIL(init_database_schema(database_schema, allocator))) { + LOG_WARN("fail to init database schema", KR(ret)); + } else if (OB_FAIL(init_table_schema(table_schema, allocator))) { + LOG_WARN("fail to init table schema", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadSchema::init_database_schema(const ObDatabaseSchema *database_schema, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(database_schema)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(database_schema)); + } else { + if (OB_FAIL(ObTableLoadUtils::deep_copy(database_schema->get_database_name_str(), + database_name_, allocator))) { + LOG_WARN("fail to deep copy database name", KR(ret)); + } + } + return ret; +} + +int ObTableLoadSchema::init_table_schema(const ObTableSchema *table_schema, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(table_schema)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table_schema)); + } else { + is_partitioned_table_ = table_schema->is_partitioned_table(); + is_heap_table_ = table_schema->is_heap_table(); + has_autoinc_column_ = (table_schema->get_autoinc_column_id() != 0); + rowkey_column_count_ = table_schema->get_rowkey_column_num(); + column_count_ = table_schema->get_column_count(); + collation_type_ = table_schema->get_collation_type(); + schema_version_ = table_schema->get_schema_version(); + if (OB_FAIL(ObTableLoadUtils::deep_copy(table_schema->get_table_name_str(), table_name_, + allocator))) { + LOG_WARN("fail to deep copy table name", KR(ret)); + } else if (OB_FAIL(table_schema->get_column_ids(column_descs_))) { + LOG_WARN("fail to get column descs", KR(ret)); + } else if (OB_FAIL(table_schema->get_multi_version_column_descs(multi_version_column_descs_))) { + LOG_WARN("fail to get multi version column descs", KR(ret)); + } else if (OB_FAIL(datum_utils_.init(multi_version_column_descs_, rowkey_column_count_, + lib::is_oracle_mode(), allocator))) { + LOG_WARN("fail to init datum utils", KR(ret)); + } + if (OB_SUCC(ret)) { + ObArray tablet_ids; + ObArray part_ids; + if (OB_FAIL(table_schema->get_all_tablet_and_object_ids(tablet_ids, part_ids))) { + LOG_WARN("fail to get all tablet ids", KR(ret)); + } else if (OB_FAIL(partition_ids_.create(part_ids.count(), allocator))) { + LOG_WARN("fail to create array", KR(ret)); + } else { + for (int64_t i = 0; i < part_ids.count(); ++i) { + partition_ids_[i].partition_id_ = part_ids.at(i); + partition_ids_[i].tablet_id_ = tablet_ids.at(i); + } + } + for (ObTableSchema::const_column_iterator iter = table_schema->column_begin(); + OB_SUCC(ret) && iter != table_schema->column_end(); ++iter) { + ObColumnSchemaV2 *column_schema = *iter; + if (OB_ISNULL(column_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid column schema", K(column_schema)); + } else { + uint64_t column_id = column_schema->get_column_id(); + if (column_schema->is_identity_column() && column_id != OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { + has_identity_column_ = true; + break; + } + } + }//end for + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_schema.h b/src/observer/table_load/ob_table_load_schema.h new file mode 100644 index 0000000000..bd42b10b02 --- /dev/null +++ b/src/observer/table_load/ob_table_load_schema.h @@ -0,0 +1,76 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#pragma once + +#include "common/object/ob_obj_type.h" +#include "lib/container/ob_iarray.h" +#include "lib/string/ob_string.h" +#include "share/schema/ob_schema_getter_guard.h" +#include "share/schema/ob_table_param.h" +#include "share/schema/ob_table_schema.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadSchema +{ +public: + static int get_schema_guard(uint64_t tenant_id, share::schema::ObSchemaGetterGuard &schema_guard); + static int get_table_schema(uint64_t tenant_id, uint64_t database_id, + const common::ObString &table_name, + share::schema::ObSchemaGetterGuard &schema_guard, + const share::schema::ObTableSchema *&table_schema); + static int get_table_schema(uint64_t tenant_id, uint64_t table_id, + share::schema::ObSchemaGetterGuard &schema_guard, + const share::schema::ObTableSchema *&table_schema); + static int get_database_and_table_schema(uint64_t tenant_id, uint64_t database_id, + uint64_t table_id, + share::schema::ObSchemaGetterGuard &schema_guard, + const share::schema::ObDatabaseSchema *&database_schema, + const share::schema::ObTableSchema *&table_schema); + static int get_column_names(const share::schema::ObTableSchema *table_schema, + common::ObIAllocator &allocator, + table::ObTableLoadArray &column_names); + static int get_schema_version(uint64_t tenant_id, uint64_t table_id, int64_t &schema_version); + static int check_constraints(uint64_t tenant_id, + share::schema::ObSchemaGetterGuard &schema_guard, + const share::schema::ObTableSchema *table_schema); +public: + ObTableLoadSchema(); + int init(uint64_t tenant_id, uint64_t database_id, uint64_t table_id, + common::ObIAllocator &allocator); + bool is_valid() const { return is_inited_; } + TO_STRING_KV(K_(database_name), K_(table_name), K_(is_partitioned_table), K_(is_heap_table), + K_(has_autoinc_column), K_(has_identity_column), K_(rowkey_column_count), K_(column_count), + K_(collation_type), K_(column_descs), K_(is_inited)); +private: + int init_database_schema(const share::schema::ObDatabaseSchema *database_schema, + common::ObIAllocator &allocator); + int init_table_schema(const share::schema::ObTableSchema *table_schema, + common::ObIAllocator &allocator); +public: + common::ObString database_name_; + common::ObString table_name_; + bool is_partitioned_table_; + bool is_heap_table_; + bool has_autoinc_column_; + bool has_identity_column_; + int64_t rowkey_column_count_; + int64_t column_count_; + common::ObCollationType collation_type_; + int64_t schema_version_; + common::ObSEArray column_descs_; + common::ObSEArray multi_version_column_descs_; + blocksstable::ObStorageDatumUtils datum_utils_; + table::ObTableLoadArray partition_ids_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_service.cpp b/src/observer/table_load/ob_table_load_service.cpp new file mode 100644 index 0000000000..239ac608cb --- /dev/null +++ b/src/observer/table_load/ob_table_load_service.cpp @@ -0,0 +1,339 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "share/rc/ob_tenant_base.h" +#include "share/schema/ob_table_schema.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace lib; +using namespace share::schema; +using namespace table; + +/** + * ObGCTask + */ + +int ObTableLoadService::ObGCTask::init(uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadService::ObGCTask init twice", KR(ret), KP(this)); + } else { + tenant_id_ = tenant_id; + is_inited_ = true; + } + return ret; +} + +void ObTableLoadService::ObGCTask::runTimerTask() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadService::ObGCTask not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("table load start gc", K(tenant_id_)); + auto fn = [this](uint64_t table_id, ObTableLoadTableCtx *) -> bool { + int ret = OB_SUCCESS; + ObTableLoadTableCtx *table_ctx = nullptr; + if (OB_FAIL(service_.get_table_ctx(table_id, table_ctx))) { + } else if (table_ctx->is_dirty()) { + LOG_DEBUG("table load ctx is dirty", K(tenant_id_), K(table_id), "ref_count", table_ctx->get_ref_count()); + } else if (table_ctx->get_ref_count() > 1) { + // wait all task exit + } else { + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + uint64_t target_table_id = table_ctx->param_.target_table_id_; + if (target_table_id == OB_INVALID_ID) { + // do nothing because hidden table has not been created + } else if (OB_FAIL(ObTableLoadSchema::get_table_schema(tenant_id_, + target_table_id, + schema_guard, + table_schema))) { + if (OB_UNLIKELY(OB_TABLE_NOT_EXIST != ret)) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id_), K(target_table_id)); + } else { + // table not exist, gc table load ctx + LOG_DEBUG("table not exist gc table load ctx", K(tenant_id_), K(target_table_id)); + service_.remove_table_ctx(table_ctx); + } + } else if (table_schema->is_in_recyclebin()) { + // table in recyclebin, gc table load ctx + LOG_DEBUG("table is in recyclebin gc table load ctx", K(tenant_id_), K(target_table_id)); + service_.remove_table_ctx(table_ctx); + } else { + LOG_DEBUG("table load ctx is running", K(target_table_id)); + } + } + if (OB_NOT_NULL(table_ctx)) { + service_.put_table_ctx(table_ctx); + table_ctx = nullptr; + } + return true; + }; + service_.table_ctx_manager_.for_each(fn); + } +} + +/** + * ObReleaseTask + */ + +int ObTableLoadService::ObReleaseTask::init(uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadService::ObReleaseTask init twice", KR(ret), KP(this)); + } else { + tenant_id_ = tenant_id; + is_inited_ = true; + } + return ret; +} + +void ObTableLoadService::ObReleaseTask::runTimerTask() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadService::ObReleaseTask not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("table load start release", K(tenant_id_)); + ObArray releasable_ctx_array; + { + ObMutexGuard guard(service_.mutex_); + ObTableLoadTableCtx *table_ctx = nullptr; + DLIST_FOREACH_REMOVESAFE(table_ctx, service_.dirty_list_) + { + if (table_ctx->get_ref_count() > 0) { + // wait all task exit + } else if (OB_FAIL(releasable_ctx_array.push_back(table_ctx))) { + LOG_WARN("fail to push back", KR(ret)); + } else { + abort_unless(OB_NOT_NULL(service_.dirty_list_.remove(table_ctx))); + } + } + } + for (int64_t i = 0; i < releasable_ctx_array.count(); ++i) { + ObTableLoadTableCtx *table_ctx = releasable_ctx_array.at(i); + LOG_INFO("free table ctx", KP(table_ctx)); + service_.table_ctx_manager_.free_value(table_ctx); + } + } +} + +int ObTableLoadService::mtl_init(ObTableLoadService *&service) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + if (OB_ISNULL(service)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(service)); + } else if (OB_FAIL(service->init(tenant_id))) { + LOG_WARN("fail to init table load service", KR(ret), K(tenant_id)); + } + return ret; +} + +int ObTableLoadService::create_ctx(const ObTableLoadParam ¶m, ObTableLoadTableCtx *&ctx, + bool &is_new) +{ + int ret = OB_SUCCESS; + ObTableLoadService *service = nullptr; + if (OB_ISNULL(service = MTL(ObTableLoadService *))) { + ret = OB_ERR_SYS; + LOG_WARN("null table load service", KR(ret)); + } else { + ret = service->create_table_ctx(param, ctx, is_new); + } + return ret; +} + +int ObTableLoadService::get_ctx(const ObTableLoadKey &key, ObTableLoadTableCtx *&ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadService *service = nullptr; + if (OB_ISNULL(service = MTL(ObTableLoadService *))) { + ret = OB_ERR_SYS; + LOG_WARN("null table load service", KR(ret)); + } else { + ret = service->get_table_ctx(key.table_id_, ctx); + } + return ret; +} + +void ObTableLoadService::put_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadService *service = nullptr; + if (OB_ISNULL(service = MTL(ObTableLoadService *))) { + ret = OB_ERR_SYS; + LOG_WARN("null table load service", KR(ret)); + } else { + service->put_table_ctx(ctx); + } +} + +int ObTableLoadService::remove_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + ObTableLoadService *service = nullptr; + if (OB_ISNULL(service = MTL(ObTableLoadService *))) { + ret = OB_ERR_SYS; + LOG_WARN("null table load service", KR(ret)); + } else { + ret = service->remove_table_ctx(ctx); + } + return ret; +} + +ObTableLoadService::ObTableLoadService() + : gc_task_(*this), release_task_(*this), is_inited_(false) +{ +} + +int ObTableLoadService::init(uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadService init twice", KR(ret), KP(this)); + } else if (OB_FAIL(table_ctx_manager_.init())) { + LOG_WARN("fail to init table ctx manager", KR(ret)); + } else if (OB_FAIL(gc_task_.init(tenant_id))) { + LOG_WARN("fail to init gc task", KR(ret)); + } else if (OB_FAIL(release_task_.init(tenant_id))) { + LOG_WARN("fail to init release task", KR(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObTableLoadService::start() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadService not init", KR(ret), KP(this)); + } else { + gc_timer_.set_run_wrapper(MTL_CTX()); + if (OB_FAIL(gc_timer_.init("TableLoadGc"))) { + LOG_WARN("fail to init gc timer", KR(ret)); + } else if (OB_FAIL(gc_timer_.schedule(gc_task_, GC_INTERVAL, true))) { + LOG_WARN("fail to schedule gc task", KR(ret)); + } else if (OB_FAIL(gc_timer_.schedule(release_task_, RELEASE_INTERVAL, true))) { + LOG_WARN("fail to schedule release task", KR(ret)); + } + } + return ret; +} + +int ObTableLoadService::stop() +{ + int ret = OB_SUCCESS; + gc_timer_.stop(); + return ret; +} + +void ObTableLoadService::wait() +{ + gc_timer_.wait(); +} + +void ObTableLoadService::destroy() +{ + is_inited_ = false; + gc_timer_.destroy(); +} + +int ObTableLoadService::create_table_ctx(const ObTableLoadParam ¶m, ObTableLoadTableCtx *&ctx, + bool &is_new) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + if (OB_FAIL(table_ctx_manager_.get_or_new(param.table_id_, ctx, is_new, param))) { + LOG_WARN("fail to new and insert table ctx", KR(ret)); + } else if (OB_ISNULL(ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null table ctx", KR(ret), K(param)); + } else if (OB_UNLIKELY(ctx->is_dirty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected dirty table ctx", KR(ret)); + } else { + ctx->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadService::get_table_ctx(uint64_t table_id, ObTableLoadTableCtx *&ctx) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_INVALID_ID == table_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(table_id)); + } else if (OB_FAIL(table_ctx_manager_.get(table_id, ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(table_id)); + } else if (OB_ISNULL(ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null table ctx", KR(ret), K(table_id)); + } else if (OB_UNLIKELY(ctx->is_dirty())) { + ret = OB_ENTRY_NOT_EXIST; + LOG_WARN("table ctx is dirty", KR(ret)); + } else { + ctx->inc_ref_count(); + } + return ret; +} + +void ObTableLoadService::put_table_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(ctx)); + } else { + abort_unless(ctx->dec_ref_count() >= 0); + } +} + +int ObTableLoadService::remove_table_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(ctx)); + } else if (OB_UNLIKELY(ctx->is_dirty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected dirty table ctx", KR(ret), KP(ctx)); + } else { + ctx->set_dirty(); + if (OB_FAIL(table_ctx_manager_.remove(ctx->param_.table_id_, ctx))) { + LOG_WARN("fail to remove table ctx", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + abort_unless(dirty_list_.add_last(ctx)); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_service.h b/src/observer/table_load/ob_table_load_service.h new file mode 100644 index 0000000000..c1d81b80ef --- /dev/null +++ b/src/observer/table_load/ob_table_load_service.h @@ -0,0 +1,78 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/list/ob_dlist.h" +#include "lib/task/ob_timer.h" +#include "observer/table_load/ob_table_load_manager.h" +#include "observer/table_load/ob_table_load_struct.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTableCtx; + +class ObTableLoadService +{ +public: + static int mtl_init(ObTableLoadService *&service); + static int create_ctx(const ObTableLoadParam ¶m, ObTableLoadTableCtx *&ctx, bool &is_new); + static int get_ctx(const ObTableLoadKey &key, ObTableLoadTableCtx *&ctx); + static void put_ctx(ObTableLoadTableCtx *ctx); + static int remove_ctx(ObTableLoadTableCtx *ctx); +public: + ObTableLoadService(); + int init(uint64_t tenant_id); + int start(); + int stop(); + void wait(); + void destroy(); +public: + int create_table_ctx(const ObTableLoadParam ¶m, ObTableLoadTableCtx *&ctx, bool &is_new); + int get_table_ctx(uint64_t table_id, ObTableLoadTableCtx *&ctx); + void put_table_ctx(ObTableLoadTableCtx *ctx); + int remove_table_ctx(ObTableLoadTableCtx *ctx); +private: + static const int64_t GC_INTERVAL = 30LL * 1000 * 1000; // 30s + static const int64_t RELEASE_INTERVAL = 1LL * 1000 * 1000; // 1s + class ObGCTask : public common::ObTimerTask + { + public: + ObGCTask(ObTableLoadService &service) + : service_(service), tenant_id_(common::OB_INVALID_ID), is_inited_(false) {} + virtual ~ObGCTask() = default; + int init(uint64_t tenant_id); + void runTimerTask() override; + private: + ObTableLoadService &service_; + uint64_t tenant_id_; + bool is_inited_; + }; + class ObReleaseTask : public common::ObTimerTask + { + public: + ObReleaseTask(ObTableLoadService &service) + : service_(service), tenant_id_(common::OB_INVALID_ID), is_inited_(false) {} + virtual ~ObReleaseTask() = default; + int init(uint64_t tenant_id); + void runTimerTask() override; + private: + ObTableLoadService &service_; + uint64_t tenant_id_; + bool is_inited_; + }; +private: + ObTableLoadManager table_ctx_manager_; + mutable lib::ObMutex mutex_; + common::ObDList dirty_list_; + common::ObTimer gc_timer_; + ObGCTask gc_task_; + ObReleaseTask release_task_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_stat.h b/src/observer/table_load/ob_table_load_stat.h new file mode 100644 index 0000000000..e7c68c635d --- /dev/null +++ b/src/observer/table_load/ob_table_load_stat.h @@ -0,0 +1,140 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/coro/co_var.h" +#include "lib/alloc/alloc_assist.h" +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace observer +{ + +#define ENABLE_TABLE_LOAD_STAT 1 + +struct ObTableLoadStat +{ + ObTableLoadStat() + { + reset(); + } + void reset() + { + MEMSET(this, 0, sizeof(*this)); + } + int64_t execute_time_us_; + int64_t add_task_time_us_; + int64_t calc_part_time_us_; + int64_t get_part_bucket_time_us_; + int64_t bucket_add_row_time_us_; + int64_t cast_obj_time_us_; + int64_t check_rowkey_order_time_us_; + int64_t sstable_append_row_time_us_; + int64_t simple_sstable_append_row_time_us_; + int64_t simple_sstable_set_last_key_time_us_; + int64_t external_append_row_time_us_; + int64_t external_write_buffer_time_us_; + int64_t external_read_buffer_time_us_; + int64_t external_flush_buffer_time_us_; + int64_t external_fetch_buffer_time_us_; + int64_t external_heap_compare_time_us_; + int64_t transfer_external_row_time_us_; + int64_t transfer_datum_row_time_us_; + int64_t external_row_deep_copy_time_us_; + int64_t external_row_serialize_time_us_; + int64_t external_row_deserialize_time_us_; + int64_t alloc_fragment_time_us_; + int64_t memory_add_item_time_us_; + int64_t memory_sort_item_time_us_; + int64_t external_table_compact_merge_store_; + int64_t table_compactor_time_us_; + int64_t merge_time_us_; + int64_t merge_get_next_row_time_us_; + int64_t coordinator_write_time_us_; + int64_t coordinator_flush_time_us_; + int64_t store_write_time_us_; + int64_t store_flush_time_us_; + int64_t external_write_bytes_; + int64_t external_serialize_bytes_; + int64_t external_raw_bytes_; + int64_t table_store_append_row_; + int64_t table_store_get_bucket_; + int64_t table_store_bucket_append_row_; + int64_t table_store_row_count_; + int64_t fast_heap_table_refresh_pk_cache_; + TO_STRING_KV(K_(execute_time_us), K_(add_task_time_us), K_(calc_part_time_us), + K_(get_part_bucket_time_us), K_(bucket_add_row_time_us), K_(cast_obj_time_us), + K_(check_rowkey_order_time_us), K_(sstable_append_row_time_us), + K_(simple_sstable_append_row_time_us), K_(simple_sstable_set_last_key_time_us), + K_(external_append_row_time_us), K_(external_write_buffer_time_us), + K_(external_read_buffer_time_us), K_(external_flush_buffer_time_us), + K_(external_fetch_buffer_time_us), K_(external_heap_compare_time_us), + K_(transfer_external_row_time_us), K_(transfer_datum_row_time_us), + K_(external_row_deep_copy_time_us), K_(external_row_serialize_time_us), + K_(external_row_deserialize_time_us), K_(alloc_fragment_time_us), + K_(memory_add_item_time_us), K_(memory_sort_item_time_us), + K_(table_compactor_time_us), K_(external_table_compact_merge_store), K_(merge_time_us), K_(merge_get_next_row_time_us), + K_(coordinator_write_time_us), K_(coordinator_flush_time_us), + K_(store_write_time_us), K_(store_flush_time_us), K_(external_write_bytes), K_(external_serialize_bytes), K_(external_raw_bytes), + K_(table_store_append_row), K_(table_store_get_bucket), K_(table_store_bucket_append_row), K_(table_store_row_count), + K_(fast_heap_table_refresh_pk_cache)); +}; + +class ObTableLoadTimeCoster +{ +public: + ObTableLoadTimeCoster(int64_t &save_value) : save_value_(save_value) + { + start_time_ = common::ObTimeUtil::current_time(); + } + ~ObTableLoadTimeCoster() + { + save_value_ += common::ObTimeUtil::current_time() - start_time_; + } +private: + int64_t start_time_; + int64_t &save_value_; +}; + +OB_INLINE ObTableLoadStat *get_local_table_load_stat() +{ + RLOCAL_INLINE(ObTableLoadStat, default_local_stat); + return &default_local_stat; +} + +#if defined(ENABLE_TABLE_LOAD_STAT) && ENABLE_TABLE_LOAD_STAT == 1 + +#define OB_TABLE_LOAD_STATISTICS_TIME_COST(field_name) \ + observer::ObTableLoadTimeCoster field_name##_time_coster( \ + observer::get_local_table_load_stat()->field_name##_) + +#define OB_TABLE_LOAD_STATISTICS_COUNTER(field_name) \ + ++observer::get_local_table_load_stat()->field_name##_ + +#define OB_TABLE_LOAD_STATISTICS_INC(field_name, value) \ + observer::get_local_table_load_stat()->field_name##_ += value + +#define OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET() \ + { \ + observer::ObTableLoadStat *stat = observer::get_local_table_load_stat(); \ + LOG_INFO("table load stat", KPC(stat)); \ + stat->reset(); \ + } + +#else + +#define OB_TABLE_LOAD_STATISTICS_TIME_COST(field_name) + +#define OB_TABLE_LOAD_STATISTICS_COUNTER(field_name) + +#define OB_TABLE_LOAD_STATISTICS_INC(field_name, value) + +#define OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET() + +#endif + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store.cpp b/src/observer/table_load/ob_table_load_store.cpp new file mode 100644 index 0000000000..3387cf7f1d --- /dev/null +++ b/src/observer/table_load/ob_table_load_store.cpp @@ -0,0 +1,943 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_merger.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_store_trans.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "observer/table_load/ob_table_load_utils.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace table; + +ObTableLoadStore::ObTableLoadStore(ObTableLoadTableCtx *ctx) + : ctx_(ctx), param_(ctx->param_), store_ctx_(ctx->store_ctx_), is_inited_(false) +{ +} + +int ObTableLoadStore::init_ctx(ObTableLoadTableCtx *ctx, + int64_t ddl_task_id, + const ObTableLoadArray &partition_id_array, + const ObTableLoadArray &target_partition_id_array) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid agrs", KR(ret)); + } else if (OB_FAIL(ctx->init_store_ctx(ddl_task_id, partition_id_array, target_partition_id_array))) { + LOG_WARN("fail to init store ctx", KR(ret)); + } + return ret; +} + +int ObTableLoadStore::abort_ctx(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!ctx->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(ctx)); + } else if (OB_UNLIKELY(nullptr == ctx->store_ctx_ || !ctx->store_ctx_->is_valid())) { + // store ctx not init, do nothing + } else { + LOG_INFO("store abort"); + // 1. mark status abort, speed up background task exit + if (OB_FAIL(ctx->store_ctx_->set_status_abort())) { + LOG_WARN("fail to set store status abort", KR(ret)); + } + // 2. mark all active trans abort + else if (OB_FAIL(abort_active_trans(ctx))) { + LOG_WARN("fail to abort active trans", KR(ret)); + } + } + return ret; +} + +int ObTableLoadStore::abort_active_trans(ObTableLoadTableCtx *ctx) +{ + int ret = OB_SUCCESS; + ObArray trans_id_array; + if (OB_FAIL(ctx->store_ctx_->get_active_trans_ids(trans_id_array))) { + LOG_WARN("fail to get active trans ids", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < trans_id_array.count(); ++i) { + const ObTableLoadTransId &trans_id = trans_id_array.at(i); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(ctx->store_ctx_->get_trans(trans_id, trans))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans", KR(ret), K(trans_id)); + } else { + ret = OB_SUCCESS; + } + } else if (OB_FAIL(trans->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + ctx->store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadCoordinator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!ctx_->is_valid()) || OB_ISNULL(store_ctx_) || + OB_UNLIKELY(!store_ctx_->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC_(ctx), KPC_(store_ctx)); + } else if (THIS_WORKER.is_timeout_ts_valid() && OB_UNLIKELY(THIS_WORKER.is_timeout())) { + ret = OB_TIMEOUT; + LOG_WARN("worker timeouted", KR(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObTableLoadStore::pre_begin() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store pre begin"); + // do nothing + } + return ret; +} + +int ObTableLoadStore::confirm_begin() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store confirm begin"); + if (OB_FAIL(store_ctx_->set_status_loading())) { + LOG_WARN("fail to set store status loading", KR(ret)); + } + } + return ret; +} + +/** + * merge + */ + +class ObTableLoadStore::MergeTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + MergeTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx) + : ObITableLoadTaskProcessor(task), ctx_(ctx) + { + ctx_->inc_ref_count(); + } + virtual ~MergeTaskProcessor() + { + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ctx_->store_ctx_->merger_->start())) { + LOG_WARN("fail to start merger", KR(ret)); + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; +}; + +class ObTableLoadStore::MergeTaskCallback : public ObITableLoadTaskCallback +{ +public: + MergeTaskCallback(ObTableLoadTableCtx *ctx) : ctx_(ctx) + { + ctx_->inc_ref_count(); + } + virtual ~MergeTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + ctx_->store_ctx_->set_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; +}; + +int ObTableLoadStore::pre_merge( + const ObTableLoadArray &committed_trans_id_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store pre merge"); + ObArenaAllocator allocator; + bool trans_exist = false; + ObTableLoadArray store_committed_trans_id_array; + // 1. 冻结状态, 防止后续继续创建trans + if (OB_FAIL(store_ctx_->set_status_frozen())) { + LOG_WARN("fail to set store status frozen", KR(ret)); + } + // 2. 检查当前是否还有trans没有结束 + else if (OB_FAIL(store_ctx_->check_exist_trans(trans_exist))) { + LOG_WARN("fail to check exist trans", KR(ret)); + } else if (OB_UNLIKELY(trans_exist)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("trans already exist", KR(ret)); + } else if (!ctx_->param_.px_mode_) { + // 3. 检查数据一致性 + if (OB_FAIL( + store_ctx_->get_committed_trans_ids(store_committed_trans_id_array, allocator))) { + LOG_WARN("fail to get committed trans ids", KR(ret)); + } else if (OB_UNLIKELY(committed_trans_id_array.count() != + store_committed_trans_id_array.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected committed trans count", KR(ret), K(committed_trans_id_array), + K(store_committed_trans_id_array)); + } else { + std::sort(store_committed_trans_id_array.begin(), store_committed_trans_id_array.end()); + for (int64_t i = 0; OB_SUCC(ret) && i < committed_trans_id_array.count(); ++i) { + if (OB_UNLIKELY(committed_trans_id_array[i] != store_committed_trans_id_array[i])) { + ret = OB_ITEM_NOT_MATCH; + LOG_WARN("committed trans id not match", KR(ret), K(i), K(committed_trans_id_array[i]), + K(store_committed_trans_id_array[i])); + } + } + } + } + } + return ret; +} + +int ObTableLoadStore::start_merge() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store start merge"); + if (OB_FAIL(store_ctx_->set_status_merging())) { + LOG_WARN("fail to set store status merging", KR(ret)); + } else { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_))) { + LOG_WARN("fail to set merge task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_))) { + LOG_WARN("fail to set merge task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(0, task))) { + LOG_WARN("fail to add task", KR(ret), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + } + return ret; +} + +int ObTableLoadStore::commit(ObTableLoadResultInfo &result_info, ObTableLoadSqlStatistics &sql_statistics) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store commit"); + if (OB_FAIL(store_ctx_->check_status(ObTableLoadStatusType::MERGED))) { + LOG_WARN("fail to check store status", KR(ret)); + } else if (OB_FAIL(store_ctx_->commit())) { + LOG_WARN("fail to commit store", KR(ret)); + } else if (OB_FAIL(store_ctx_->set_status_commit())) { + LOG_WARN("fail to set store status commit", KR(ret)); + } else if (param_.online_opt_stat_gather_ && OB_FAIL(store_ctx_->merger_->collect_sql_statistics(sql_statistics))){ + LOG_WARN("fail to collect sql stats", KR(ret)); + } else { + result_info = store_ctx_->result_info_; + } + } + return ret; +} + +int ObTableLoadStore::get_status(ObTableLoadStatusType &status, int &error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store get status"); + status = store_ctx_->get_status(); + error_code = store_ctx_->get_error_code(); + } + return ret; +} + +int ObTableLoadStore::pre_start_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store pre start trans", K(trans_id)); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->start_trans(trans_id, trans))) { + LOG_WARN("fail to start trans", KR(ret), K(trans_id)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::confirm_start_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store confirm start trans", K(trans_id)); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (OB_FAIL(trans->set_trans_status_running())) { + LOG_WARN("fail to set trans status running", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::pre_finish_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store pre finish trans", K(trans_id)); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (OB_FAIL(trans->set_trans_status_frozen())) { + LOG_WARN("fail to freeze trans", KR(ret)); + } else if (OB_FAIL(flush(trans))) { + LOG_WARN("fail to flush", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::confirm_finish_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store confirm finish trans", K(trans_id)); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (OB_FAIL(store_ctx_->commit_trans(trans))) { + LOG_WARN("fail to commit trans", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::abandon_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store abandon trans", K(trans_id)); + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } else if (OB_UNLIKELY(trans_id != trans->get_trans_ctx()->trans_id_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid trans id", KR(ret), K(trans_id), KPC(trans)); + } else if (OB_FAIL(trans->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } else if (OB_FAIL(store_ctx_->abort_trans(trans))) { + LOG_WARN("fail to abort trans", KR(ret)); + } else if (OB_FAIL(clean_up_trans(trans))) { + LOG_WARN("fail to clean up trans", KR(ret)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +class ObTableLoadStore::CleanUpTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + CleanUpTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, + ObTableLoadStoreTrans *trans, ObTableLoadTransStoreWriter *store_writer, + int32_t session_id) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + trans_(trans), + store_writer_(store_writer), + session_id_(session_id) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + store_writer_->inc_ref_count(); + } + virtual ~CleanUpTaskProcessor() + { + trans_->put_store_writer(store_writer_); + ctx_->store_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + int ret = OB_SUCCESS; + store_writer_->clean_up(session_id_); + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadStoreTrans * const trans_; + ObTableLoadTransStoreWriter * const store_writer_; + const int32_t session_id_; +}; + +class ObTableLoadStore::CleanUpTaskCallback : public ObITableLoadTaskCallback +{ +public: + CleanUpTaskCallback(ObTableLoadTableCtx *ctx) : ctx_(ctx) + { + ctx_->inc_ref_count(); + } + virtual ~CleanUpTaskCallback() + { + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; +}; + +int ObTableLoadStore::clean_up_trans(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + LOG_DEBUG("store clean up trans"); + ObTableLoadTransStoreWriter *store_writer = nullptr; + // 取出当前store_writer + if (OB_FAIL(trans->get_store_writer_for_clean_up(store_writer))) { + LOG_WARN("fail to get store writer", KR(ret)); + } else { + for (int32_t session_id = 1; OB_SUCC(ret) && session_id <= param_.session_count_; + ++session_id) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_, trans, store_writer, + session_id))) { + LOG_WARN("fail to set clean up task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_))) { + LOG_WARN("fail to set clean up task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + } + if (OB_NOT_NULL(store_writer)) { + trans->put_store_writer(store_writer); + store_writer = nullptr; + } + return ret; +} + +/** + * get trans status + */ + +int ObTableLoadStore::get_trans_status(const ObTableLoadTransId &trans_id, + ObTableLoadTransStatusType &trans_status, + int &error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_INFO("store get trans status"); + ObTableLoadTransCtx *trans_ctx = nullptr; + if (OB_FAIL(store_ctx_->get_trans_ctx(trans_id, trans_ctx))) { + LOG_WARN("fail to get trans ctx", KR(ret), K(trans_id)); + } else { + trans_status = trans_ctx->get_trans_status(); + error_code = trans_ctx->get_error_code(); + } + } + return ret; +} + +/** + * write + */ + +class ObTableLoadStore::WriteTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + WriteTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObTableLoadStoreTrans *trans, + ObTableLoadTransStoreWriter *store_writer, int32_t session_id) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + trans_(trans), + store_writer_(store_writer), + session_id_(session_id) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + store_writer_->inc_ref_count(); + } + virtual ~WriteTaskProcessor() + { + trans_->put_store_writer(store_writer_); + ctx_->store_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int set_row_array(const ObTableLoadTabletObjRowArray &row_array) + { + int ret = OB_SUCCESS; + if (OB_FAIL(row_array_.assign(row_array))) { + LOG_WARN("fail to assign row array", KR(ret)); + } + return ret; + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(store_write_time_us); + int ret = OB_SUCCESS; + if (OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::RUNNING)) || + OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + if (OB_FAIL(store_writer_->write(session_id_, row_array_))) { + LOG_WARN("fail to write store", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadStoreTrans * const trans_; + ObTableLoadTransStoreWriter * const store_writer_; + const int32_t session_id_; + ObTableLoadTabletObjRowArray row_array_; +}; + +class ObTableLoadStore::WriteTaskCallback : public ObITableLoadTaskCallback +{ +public: + WriteTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadStoreTrans *trans, + ObTableLoadTransStoreWriter *store_writer) + : ctx_(ctx), trans_(trans), store_writer_(store_writer) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + store_writer_->inc_ref_count(); + } + virtual ~WriteTaskCallback() + { + trans_->put_store_writer(store_writer_); + ctx_->store_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + trans_->set_trans_status_error(ret); + } + ctx_->free_task(task); + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadStoreTrans * const trans_; + ObTableLoadTransStoreWriter * const store_writer_; // 为了保证接收完本次写入结果之后再让store的引用归零 +}; + +int ObTableLoadStore::write(const ObTableLoadTransId &trans_id, int32_t session_id, + uint64_t sequence_no, const ObTableLoadTabletObjRowArray &row_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("store write"); + ObTableLoadStoreTrans *trans = nullptr; + ObTableLoadTransStoreWriter *store_writer = nullptr; + ObTableLoadMutexGuard guard; + // 取出当前trans + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } + // 取出store_writer + else if (OB_FAIL(trans->get_store_writer_for_write(store_writer))) { + LOG_WARN("fail to get store writer", KR(ret)); + //} else if (OB_FAIL(store_writer->advance_sequence_no(session_id, partition_id, sequence_no, guard))) { + // if (OB_UNLIKELY(OB_ENTRY_EXIST != ret)) { + // LOG_WARN("fail to advance sequence no", KR(ret), K(session_id)); + // } else { + // ret = OB_SUCCESS; + // } + } else { + ObTableLoadTask *task = nullptr; + WriteTaskProcessor *processor = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor(ctx_, trans, store_writer, + session_id))) { + LOG_WARN("fail to set write task processor", KR(ret)); + } else if (OB_ISNULL(processor = dynamic_cast(task->get_processor()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null processor", KR(ret)); + } else if (OB_FAIL(processor->set_row_array(row_array))) { + LOG_WARN("fail to set objs", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_, trans, store_writer))) { + LOG_WARN("fail to set write task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + if (OB_NOT_NULL(trans)) { + if (OB_NOT_NULL(store_writer)) { + trans->put_store_writer(store_writer); + store_writer = nullptr; + } + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +/** + * flush + */ + +class ObTableLoadStore::FlushTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + FlushTaskProcessor(ObTableLoadTask &task, ObTableLoadTableCtx *ctx, ObTableLoadStoreTrans *trans, + ObTableLoadTransStoreWriter *store_writer, int32_t session_id) + : ObITableLoadTaskProcessor(task), + ctx_(ctx), + trans_(trans), + store_writer_(store_writer), + session_id_(session_id) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + store_writer_->inc_ref_count(); + } + virtual ~FlushTaskProcessor() + { + trans_->put_store_writer(store_writer_); + ctx_->store_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + int process() override + { + OB_TABLE_LOAD_STATISTICS_TIME_COST(store_flush_time_us); + int ret = OB_SUCCESS; + if (OB_SUCC(trans_->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + if (OB_FAIL(store_writer_->flush(session_id_))) { + LOG_WARN("fail to flush store", KR(ret)); + } + } + return ret; + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadStoreTrans * const trans_; + ObTableLoadTransStoreWriter * const store_writer_; + const int32_t session_id_; +}; + +class ObTableLoadStore::FlushTaskCallback : public ObITableLoadTaskCallback +{ +public: + FlushTaskCallback(ObTableLoadTableCtx *ctx, ObTableLoadStoreTrans *trans, + ObTableLoadTransStoreWriter *store_writer) + : ctx_(ctx), trans_(trans), store_writer_(store_writer) + { + ctx_->inc_ref_count(); + trans_->inc_ref_count(); + store_writer_->inc_ref_count(); + } + virtual ~FlushTaskCallback() + { + trans_->put_store_writer(store_writer_); + ctx_->store_ctx_->put_trans(trans_); + ObTableLoadService::put_ctx(ctx_); + } + void callback(int ret_code, ObTableLoadTask *task) override + { + int ret = OB_SUCCESS; + if (OB_FAIL(ret_code)) { + trans_->set_trans_status_error(ret); + } + ctx_->free_task(task); + OB_TABLE_LOAD_STATISTICS_PRINT_AND_RESET(); + } +private: + ObTableLoadTableCtx * const ctx_; + ObTableLoadStoreTrans * const trans_; + ObTableLoadTransStoreWriter * const store_writer_; // 为了保证接收完本次写入结果之后再让store的引用归零 +}; + +int ObTableLoadStore::flush(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + LOG_DEBUG("store flush"); + ObTableLoadTransStoreWriter *store_writer = nullptr; + // 取出当前store_writer + if (OB_FAIL(trans->get_store_writer_for_flush(store_writer))) { + LOG_WARN("fail to get store writer", KR(ret)); + } else { + for (int32_t session_id = 1; OB_SUCC(ret) && session_id <= param_.session_count_; ++session_id) { + ObTableLoadTask *task = nullptr; + // 1. 分配task + if (OB_FAIL(ctx_->alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } + // 2. 设置processor + else if (OB_FAIL(task->set_processor( + ctx_, trans, store_writer, session_id))) { + LOG_WARN("fail to set flush task processor", KR(ret)); + } + // 3. 设置callback + else if (OB_FAIL(task->set_callback(ctx_, trans, store_writer))) { + LOG_WARN("fail to set flush task callback", KR(ret)); + } + // 4. 把task放入调度器 + else if (OB_FAIL(store_ctx_->task_scheduler_->add_task(session_id - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(session_id), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + ctx_->free_task(task); + } + } + } + } + if (OB_NOT_NULL(store_writer)) { + trans->put_store_writer(store_writer); + store_writer = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::px_start_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->start_trans(trans_id, trans))) { + LOG_WARN("fail to start trans", KR(ret), K(trans_id)); + } else if (OB_FAIL(trans->set_trans_status_running())) { + LOG_WARN("fail to set trans status running", KR(ret)); + } else { + LOG_DEBUG("succeed to start trans", K(trans_id)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::px_finish_trans(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + ObTableLoadStoreTrans *trans = nullptr; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (OB_FAIL(trans->set_trans_status_frozen())) { + LOG_WARN("fail to freeze trans", KR(ret)); + } else if (OB_FAIL(px_flush(trans))) { + LOG_WARN("fail to do px flush", KR(ret)); + } else if (OB_FAIL(store_ctx_->commit_trans(trans))) { + LOG_WARN("fail to commit trans", KR(ret)); + } else { + LOG_DEBUG("succeed to commit trans", K(trans_id)); + } + if (OB_NOT_NULL(trans)) { + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::px_write(const ObTableLoadTransId &trans_id, + const ObTabletID &tablet_id, const ObIArray &row_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + ObTableLoadStoreTrans *trans = nullptr; + ObTableLoadTransStoreWriter *store_writer = nullptr; + ObTableLoadMutexGuard guard; + if (OB_FAIL(store_ctx_->get_trans(trans_id, trans))) { + LOG_WARN("fail to get trans", KR(ret)); + } else if (OB_FAIL(trans->get_store_writer_for_write(store_writer))) { + LOG_WARN("fail to get store writer", KR(ret)); + } else { + if (OB_SUCC(trans->check_trans_status(ObTableLoadTransStatusType::RUNNING)) || + OB_SUCC(trans->check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + if (OB_FAIL(store_writer->write(PX_DEFAULT_SESSION_ID, tablet_id, row_array))) { + LOG_WARN("fail to write store", KR(ret)); + } else { + LOG_DEBUG("succeed to write store", K(trans_id), K(tablet_id)); + } + } + } + if (OB_NOT_NULL(trans)) { + if (OB_NOT_NULL(store_writer)) { + trans->put_store_writer(store_writer); + store_writer = nullptr; + } + store_ctx_->put_trans(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStore::px_flush(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStore not init", KR(ret), KP(this)); + } else { + ObTableLoadTransStoreWriter *store_writer = nullptr; + if (OB_FAIL(trans->get_store_writer_for_flush(store_writer))) { + LOG_WARN("fail to get store writer", KR(ret)); + } else if (OB_FAIL(store_writer->flush(PX_DEFAULT_SESSION_ID))) { + LOG_WARN("fail to flush store", KR(ret)); + } else { + LOG_DEBUG("succeed to flush store"); + } + if (OB_NOT_NULL(store_writer)) { + trans->put_store_writer(store_writer); + store_writer = nullptr; + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store.h b/src/observer/table_load/ob_table_load_store.h new file mode 100644 index 0000000000..618a2feedb --- /dev/null +++ b/src/observer/table_load/ob_table_load_store.h @@ -0,0 +1,94 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/net/ob_addr.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" +#include "share/table/ob_table_load_row_array.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTableCtx; +class ObTableLoadStoreCtx; +class ObTableLoadStoreTrans; + +class ObTableLoadStore +{ +public: + ObTableLoadStore(ObTableLoadTableCtx *ctx); + static int init_ctx( + ObTableLoadTableCtx *ctx, + int64_t ddl_task_id, + const table::ObTableLoadArray &partition_id_array, + const table::ObTableLoadArray &target_partition_id_array); + static int abort_ctx(ObTableLoadTableCtx *ctx); + int init(); +private: + static int abort_active_trans(ObTableLoadTableCtx *ctx); + +// table load ctrl interface +public: + int pre_begin(); + int confirm_begin(); + int pre_merge(const table::ObTableLoadArray &committed_trans_id_array); + int start_merge(); + int commit(table::ObTableLoadResultInfo &result_info, table::ObTableLoadSqlStatistics &sql_statistics); + int get_status(table::ObTableLoadStatusType &status, int &error_code); +private: + class MergeTaskProcessor; + class MergeTaskCallback; + +// trans ctrl interface +public: + int pre_start_trans(const table::ObTableLoadTransId &trans_id); + int confirm_start_trans(const table::ObTableLoadTransId &trans_id); + int pre_finish_trans(const table::ObTableLoadTransId &trans_id); + int confirm_finish_trans(const table::ObTableLoadTransId &trans_id); + int abandon_trans(const table::ObTableLoadTransId &trans_id); + int get_trans_status(const table::ObTableLoadTransId &trans_id, + table::ObTableLoadTransStatusType &trans_status, + int &error_code); +private: + int clean_up_trans(ObTableLoadStoreTrans *trans); + class CleanUpTaskProcessor; + class CleanUpTaskCallback; + +// write interface +public: + int write(const table::ObTableLoadTransId &trans_id, int32_t session_id, uint64_t sequence_no, + const table::ObTableLoadTabletObjRowArray &row_array); + int flush(ObTableLoadStoreTrans *trans); +private: + class WriteTaskProcessor; + class WriteTaskCallback; + class FlushTaskProcessor; + class FlushTaskCallback; + +// px trans interface +public: + static const int32_t PX_DEFAULT_SESSION_ID = 1; + int px_start_trans(const table::ObTableLoadTransId &trans_id); + int px_finish_trans(const table::ObTableLoadTransId &trans_id); + int px_abandon_trans(const table::ObTableLoadTransId &trans_id); + int px_write(const table::ObTableLoadTransId &trans_id, + const ObTabletID &tablet_id, + const common::ObIArray &row_array); +private: + int px_flush(ObTableLoadStoreTrans *trans); + +private: + ObTableLoadTableCtx * const ctx_; + const ObTableLoadParam ¶m_; + ObTableLoadStoreCtx * const store_ctx_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObTableLoadStore); +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store_ctx.cpp b/src/observer/table_load/ob_table_load_store_ctx.cpp new file mode 100644 index 0000000000..0b1f6c1d52 --- /dev/null +++ b/src/observer/table_load/ob_table_load_store_ctx.cpp @@ -0,0 +1,918 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "observer/table_load/ob_table_load_merger.h" +#include "observer/table_load/ob_table_load_store_trans.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "storage/direct_load/ob_direct_load_data_block.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table_ctx.h" +#include "storage/direct_load/ob_direct_load_insert_table_ctx.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block.h" +#include "storage/direct_load/ob_direct_load_sstable_scan_merge.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" +#include "share/ob_autoincrement_service.h" +#include "share/sequence/ob_sequence_cache.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace lib; +using namespace table; +using namespace storage; +using namespace share; + +ObTableLoadStoreCtx::ObTableLoadStoreCtx(ObTableLoadTableCtx *ctx) + : ctx_(ctx), + task_scheduler_(nullptr), + merger_(nullptr), + insert_table_ctx_(nullptr), + is_multiple_mode_(false), + is_fast_heap_table_(false), + fast_heap_table_ctx_(nullptr), + tmp_file_mgr_(nullptr), + error_row_handler_(nullptr), + allocator_("TLD_StoreCtx", OB_MALLOC_NORMAL_BLOCK_SIZE, ctx->param_.tenant_id_), + status_(ObTableLoadStatusType::NONE), + error_code_(OB_SUCCESS), + is_inited_(false) +{ +} + +ObTableLoadStoreCtx::~ObTableLoadStoreCtx() +{ + destroy(); +} + +int ObTableLoadStoreCtx::init(int64_t ddl_task_id, + const ObTableLoadArray &partition_id_array, + const ObTableLoadArray &target_partition_id_array) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadStoreCtx init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(partition_id_array.empty() || target_partition_id_array.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(partition_id_array), K(target_partition_id_array)); + } else { + ObDirectLoadInsertTableParam insert_table_param; + insert_table_param.table_id_ = ctx_->param_.table_id_; + insert_table_param.schema_version_ = ctx_->schema_.schema_version_; + insert_table_param.snapshot_version_ = ObTimeUtil::current_time_ns(); + insert_table_param.ddl_task_id_ = ddl_task_id; + insert_table_param.execution_id_ = 1; //仓氐说暂时设置为1,不然后面检测过不了 + for (int64_t i = 0; OB_SUCC(ret) && i < partition_id_array.count(); ++i) { + const ObLSID &ls_id = partition_id_array[i].ls_id_; + const ObTableLoadPartitionId &part_tablet_id = partition_id_array[i].part_tablet_id_; + if (OB_FAIL(ls_partition_ids_.push_back(ObTableLoadLSIdAndPartitionId(ls_id, part_tablet_id)))) { + LOG_WARN("fail to push back ls tablet id", KR(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < target_partition_id_array.count(); ++i) { + const ObLSID &ls_id = target_partition_id_array[i].ls_id_; + const ObTableLoadPartitionId &tablet_id = target_partition_id_array[i].part_tablet_id_; + if (OB_FAIL(target_ls_partition_ids_.push_back(ObTableLoadLSIdAndPartitionId(ls_id, tablet_id)))) { + LOG_WARN("fail to push back ls tablet id", KR(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(insert_table_param.ls_partition_ids_.assign(target_ls_partition_ids_))) { + LOG_WARN("fail to assign ls tablet ids", KR(ret)); + } + // init trans_allocator_ + else if (OB_FAIL(trans_allocator_.init("TLD_STransPool", ctx_->param_.tenant_id_))) { + LOG_WARN("fail to init trans allocator", KR(ret)); + } + // init trans_map_ + else if (OB_FAIL(trans_map_.create(1024, "TLD_STransMap", "TLD_STransMap", + ctx_->param_.tenant_id_))) { + LOG_WARN("fail to create trans map", KR(ret)); + } + // init trans_ctx_map_ + else if (OB_FAIL(trans_ctx_map_.create(1024, "TLD_TCtxMap", "TLD_TCtxMap", + ctx_->param_.tenant_id_))) { + LOG_WARN("fail to create trans ctx map", KR(ret)); + } + // init segment_trans_ctx_map_ + else if (OB_FAIL(segment_ctx_map_.init("TLD_SegCtxMap", ctx_->param_.tenant_id_))) { + LOG_WARN("fail to init segment ctx map", KR(ret)); + } + // 初始化task_scheduler_ + else if (OB_ISNULL(task_scheduler_ = OB_NEWx(ObTableLoadTaskThreadPoolScheduler, (&allocator_), + ctx_->param_.session_count_, allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTaskThreadPoolScheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->init())) { + LOG_WARN("fail to init task scheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->start())) { + LOG_WARN("fail to start task scheduler", KR(ret)); + } + // 初始化merger_ + else if (OB_ISNULL(merger_ = OB_NEWx(ObTableLoadMerger, (&allocator_), this))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadMerger", KR(ret)); + } else if (OB_FAIL(merger_->init())) { + LOG_WARN("fail to init merger", KR(ret)); + } + // init insert_table_ctx_ + else if (OB_ISNULL(insert_table_ctx_ = + OB_NEWx(ObDirectLoadInsertTableContext, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadInsertTableContext", KR(ret)); + } else if (OB_FAIL(insert_table_ctx_->init(insert_table_param))) { + LOG_WARN("fail to init insert table ctx", KR(ret)); + } + // init tmp_file_mgr_ + else if (OB_ISNULL(tmp_file_mgr_ = OB_NEWx(ObDirectLoadTmpFileManager, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadTmpFileManager", KR(ret)); + } else if (OB_FAIL(tmp_file_mgr_->init(ctx_->param_.tenant_id_))) { + LOG_WARN("fail to init tmp file manager", KR(ret)); + } + // init error_row_handler_ + else if (OB_ISNULL(error_row_handler_ = + OB_NEWx(ObTableLoadErrorRowHandler, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadErrorRowHandler", KR(ret)); + } else if (OB_FAIL(error_row_handler_->init(ctx_))) { + LOG_WARN("fail to init error row handler", KR(ret), K(ctx_->param_.tenant_id_), + K(ctx_->param_.table_id_), K(ctx_->param_.max_error_row_count_), + K(ctx_->param_.session_count_)); + } + // init session_ctx_array_ + else if (OB_FAIL(init_session_ctx_array())) { + LOG_WARN("fail to init session ctx array", KR(ret)); + } + // init sequence_cache_ and sequence_schema_ + else if (ctx_->schema_.has_identity_column_ && OB_FAIL(init_sequence())) { + LOG_WARN("fail to init sequence", KR(ret)); + } + if (OB_SUCC(ret)) { + is_multiple_mode_ = (!ctx_->schema_.is_heap_table_ && ctx_->param_.need_sort_) || + ls_partition_ids_.count() > ObDirectLoadTableStore::MAX_BUCKET_CNT; + if (!is_multiple_mode_ && ctx_->schema_.is_heap_table_) { + is_fast_heap_table_ = true; + if (OB_ISNULL(fast_heap_table_ctx_ = + OB_NEWx(ObDirectLoadFastHeapTableContext, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadFastHeapTableContext", KR(ret)); + } else if (OB_FAIL(fast_heap_table_ctx_->init(ctx_->param_.tenant_id_, + ls_partition_ids_, + target_ls_partition_ids_, + ctx_->param_.session_count_))) { + LOG_WARN("fail to init fast heap table ctx", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + table_data_desc_.rowkey_column_num_ = + (!ctx_->schema_.is_heap_table_ ? ctx_->schema_.rowkey_column_count_ : 0); + table_data_desc_.column_count_ = ctx_->param_.column_count_; + table_data_desc_.external_data_block_size_ = ObDirectLoadDataBlock::DEFAULT_DATA_BLOCK_SIZE; + table_data_desc_.sstable_index_block_size_ = + ObDirectLoadSSTableIndexBlock::DEFAULT_INDEX_BLOCK_SIZE; + table_data_desc_.sstable_data_block_size_ = + ObDirectLoadSSTableDataBlock::DEFAULT_DATA_BLOCK_SIZE; + table_data_desc_.extra_buf_size_ = ObDirectLoadTableDataDesc::DEFAULT_EXTRA_BUF_SIZE; + table_data_desc_.compressor_type_ = ObCompressorType::NONE_COMPRESSOR; + table_data_desc_.is_heap_table_ = ctx_->schema_.is_heap_table_; + + int64_t wa_mem_limit = 0; + if (OB_FAIL(get_wa_memory_limit(wa_mem_limit))) { + LOG_WARN("failed to get work area memory limit", KR(ret), K(ctx_->param_.tenant_id_)); + } else if (wa_mem_limit < ObDirectLoadMemContext::MIN_MEM_LIMIT) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("wa_mem_limit is too small", KR(ret), K(wa_mem_limit)); + } else { + table_data_desc_.merge_count_per_round_ = min(wa_mem_limit + / table_data_desc_.sstable_data_block_size_ + / ctx_->param_.session_count_, ObDirectLoadSSTableScanMerge::MAX_SSTABLE_COUNT); + + table_data_desc_.max_mem_chunk_count_ = 128; + int64_t mem_chunk_size = wa_mem_limit / table_data_desc_.max_mem_chunk_count_; + if (mem_chunk_size <= ObDirectLoadExternalMultiPartitionRowChunk::MIN_MEMORY_LIMIT) { + mem_chunk_size = ObDirectLoadExternalMultiPartitionRowChunk::MIN_MEMORY_LIMIT; + table_data_desc_.max_mem_chunk_count_ = wa_mem_limit / mem_chunk_size; + } + table_data_desc_.mem_chunk_size_ = mem_chunk_size; + table_data_desc_.heap_table_mem_chunk_size_ = wa_mem_limit / ctx_->param_.session_count_; + LOG_INFO("table_data_desc init end", K(table_data_desc_)); + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } else { + destroy(); + } + } + return ret; +} + +void ObTableLoadStoreCtx::stop() +{ + if (nullptr != merger_) { + merger_->stop(); + } + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + } + LOG_INFO("store ctx stop succ"); +} + +void ObTableLoadStoreCtx::destroy() +{ + if (nullptr != merger_) { + merger_->~ObTableLoadMerger(); + allocator_.free(merger_); + merger_ = nullptr; + } + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + task_scheduler_->~ObITableLoadTaskScheduler(); + allocator_.free(task_scheduler_); + task_scheduler_ = nullptr; + } + for (TransMap::const_iterator iter = trans_map_.begin(); iter != trans_map_.end(); ++iter) { + ObTableLoadStoreTrans *trans = iter->second; + abort_unless(0 == trans->get_ref_count()); + trans_allocator_.free(trans); + } + trans_map_.reuse(); + for (int64_t i = 0; i < committed_trans_store_array_.count(); ++i) { + ObTableLoadTransStore *trans_store = committed_trans_store_array_.at(i); + ObTableLoadTransCtx *trans_ctx = trans_store->trans_ctx_; + trans_store->~ObTableLoadTransStore(); + trans_ctx->allocator_.free(trans_store); + } + committed_trans_store_array_.reset(); + for (TransCtxMap::const_iterator iter = trans_ctx_map_.begin(); iter != trans_ctx_map_.end(); + ++iter) { + ObTableLoadTransCtx *trans_ctx = iter->second; + ctx_->free_trans_ctx(trans_ctx); + } + trans_ctx_map_.reuse(); + if (nullptr != insert_table_ctx_) { + insert_table_ctx_->~ObDirectLoadInsertTableContext(); + allocator_.free(insert_table_ctx_); + insert_table_ctx_ = nullptr; + } + if (nullptr != fast_heap_table_ctx_) { + fast_heap_table_ctx_->~ObDirectLoadFastHeapTableContext(); + allocator_.free(fast_heap_table_ctx_); + fast_heap_table_ctx_ = nullptr; + } + if (nullptr != tmp_file_mgr_) { + tmp_file_mgr_->~ObDirectLoadTmpFileManager(); + allocator_.free(tmp_file_mgr_); + tmp_file_mgr_ = nullptr; + } + if (nullptr != error_row_handler_) { + error_row_handler_->~ObTableLoadErrorRowHandler(); + allocator_.free(error_row_handler_); + error_row_handler_ = nullptr; + } +} + +int ObTableLoadStoreCtx::advance_status(ObTableLoadStatusType status) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadStatusType::ERROR == status || + ObTableLoadStatusType::ABORT == status)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(status)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(ObTableLoadStatusType::ERROR == status_)) { + ret = error_code_; + LOG_WARN("store has error", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadStatusType::ABORT == status_)) { + ret = OB_TRANS_KILLED; + LOG_WARN("store is abort", KR(ret)); + } + // 正常运行阶段, 状态是一步步推进的 + else if (OB_UNLIKELY(static_cast(status) != static_cast(status_) + 1)) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("unexpected status", KR(ret), K(status), K(status_)); + } else { + status_ = status; + table_load_status_to_string(status_, ctx_->job_stat_->store.status_); + LOG_INFO("LOAD DATA STORE advance status", K(status)); + } + } + return ret; +} + +int ObTableLoadStoreCtx::set_status_error(int error_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_UNLIKELY(OB_SUCCESS == error_code)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(error_code)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(status_ == ObTableLoadStatusType::ABORT)) { + ret = OB_TRANS_KILLED; + } else if (status_ != ObTableLoadStatusType::ERROR) { + status_ = ObTableLoadStatusType::ERROR; + error_code_ = error_code; + table_load_status_to_string(status_, ctx_->job_stat_->store.status_); + LOG_INFO("LOAD DATA STORE status error", KR(error_code)); + } + } + return ret; +} + +int ObTableLoadStoreCtx::set_status_abort() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(status_ != ObTableLoadStatusType::ABORT)) { + status_ = ObTableLoadStatusType::ABORT; + table_load_status_to_string(status_, ctx_->job_stat_->store.status_); + LOG_INFO("LOAD DATA STORE status abort"); + } + } + return ret; +} + +int ObTableLoadStoreCtx::check_status_unlock(ObTableLoadStatusType status) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(status != status_)) { + if (ObTableLoadStatusType::ERROR == status_) { + ret = error_code_; + } else if (ObTableLoadStatusType::ABORT == status_) { + ret = OB_CANCELED; + } else { + ret = OB_STATE_NOT_MATCH; + } + } + return ret; +} + +int ObTableLoadStoreCtx::check_status(ObTableLoadStatusType status) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + ret = check_status_unlock(status); + } + return ret; +} + +int ObTableLoadStoreCtx::alloc_trans_ctx(const ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) +{ + int ret = OB_SUCCESS; + trans_ctx = nullptr; + // 分配trans_ctx + if (OB_ISNULL(trans_ctx = ctx_->alloc_trans_ctx(trans_id))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc trans ctx", KR(ret), K(trans_id)); + } + // 把trans_ctx插入map + else if (OB_FAIL(trans_ctx_map_.set_refactored(trans_ctx->trans_id_, trans_ctx))) { + LOG_WARN("fail to set trans ctx", KR(ret), K(trans_ctx->trans_id_)); + } + if (OB_FAIL(ret)) { + if (nullptr != trans_ctx) { + ctx_->free_trans_ctx(trans_ctx); + trans_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadStoreCtx::get_wa_memory_limit(int64_t &wa_mem_limit) +{ + int ret = OB_SUCCESS; + schema::ObSchemaGetterGuard schema_guard; + const schema::ObSysVarSchema *var_schema = NULL; + ObObj value; + int64_t pctg = 0; + int64_t tenant_id = MTL_ID(); + if (OB_ISNULL(GCTX.schema_service_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("schema service is null"); + } else if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard(tenant_id, schema_guard))) { + LOG_WARN("get schema guard failed", KR(ret)); + } else if (OB_FAIL(schema_guard.get_tenant_system_variable(tenant_id, + SYS_VAR_OB_SQL_WORK_AREA_PERCENTAGE, var_schema))) { + LOG_WARN("get tenant system variable failed", KR(ret), K(tenant_id)); + } else if (OB_ISNULL(var_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("var_schema is null"); + } else if (OB_FAIL(var_schema->get_value(&allocator_, NULL, value))) { + LOG_WARN("get value from var_schema failed", KR(ret), K(*var_schema)); + } else if (OB_FAIL(value.get_int(pctg))) { + LOG_WARN("get int from value failed", KR(ret), K(value)); + } else { + const int64_t tenant_limit = lib::get_tenant_memory_limit(tenant_id); + wa_mem_limit = (tenant_limit / 100) * pctg; + } + return ret; +} + +int ObTableLoadStoreCtx::alloc_trans(const ObTableLoadTransId &trans_id, + ObTableLoadStoreTrans *&trans) +{ + int ret = OB_SUCCESS; + trans = nullptr; + ObTableLoadTransCtx *trans_ctx = nullptr; + // 分配trans_ctx + if (OB_FAIL(alloc_trans_ctx(trans_id, trans_ctx))) { + LOG_WARN("fail to alloc trans ctx", KR(ret), K(trans_id)); + } + // 构造trans + else if (OB_ISNULL(trans = trans_allocator_.alloc(trans_ctx))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc ObTableLoadStoreTrans", KR(ret)); + } else if (OB_FAIL(trans->init())) { + LOG_WARN("fail to init trans", KR(ret), K(trans_id)); + } else if (OB_FAIL(trans_map_.set_refactored(trans_id, trans))) { + LOG_WARN("fail to set_refactored", KR(ret), K(trans_id)); + } + if (OB_FAIL(ret)) { + if (nullptr != trans) { + trans_allocator_.free(trans); + trans = nullptr; + } + } + return ret; +} + +int ObTableLoadStoreCtx::generate_autoinc_params(AutoincParam &autoinc_param) +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(ObTableLoadSchema::get_table_schema(ctx_->param_.tenant_id_, + ctx_->param_.table_id_, + schema_guard, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(ctx_->param_.tenant_id_), + K(ctx_->param_.table_id_)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(ctx_->param_.tenant_id_), K(ctx_->param_.table_id_)); + } else { + //ddl对于auto increment是最后进行自增值同步,对于autoinc_param参数初始化得使用原表table id的table schema + ObColumnSchemaV2 *autoinc_column_schema = nullptr; + uint64_t column_id = 0; + for (ObTableSchema::const_column_iterator iter = table_schema->column_begin(); + OB_SUCC(ret) && iter != table_schema->column_end(); ++iter) { + ObColumnSchemaV2 *column_schema = *iter; + if (OB_ISNULL(column_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid column schema", KR(ret), KP(column_schema)); + } else { + column_id = column_schema->get_column_id(); + if (column_schema->is_autoincrement() && column_id != OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { + autoinc_column_schema = column_schema; + break; + } + } + }//end for + if (OB_SUCC(ret)) { + if (OB_ISNULL(autoinc_column_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null autoinc column schema", KR(ret), KP(autoinc_column_schema)); + } else { + autoinc_param.tenant_id_ = ctx_->param_.tenant_id_; + autoinc_param.autoinc_table_id_ = ctx_->param_.table_id_; + autoinc_param.autoinc_first_part_num_ = table_schema->get_first_part_num(); + autoinc_param.autoinc_table_part_num_ = table_schema->get_all_part_num(); + autoinc_param.autoinc_col_id_ = column_id; + autoinc_param.auto_increment_cache_size_ = MAX_INCREMENT_CACHE_SIZE; + autoinc_param.part_level_ = table_schema->get_part_level(); + autoinc_param.autoinc_col_type_ = autoinc_column_schema->get_data_type(); + autoinc_param.total_value_count_ = 1; + autoinc_param.autoinc_desired_count_ = 0; + autoinc_param.autoinc_mode_is_order_ = table_schema->is_order_auto_increment_mode(); + autoinc_param.autoinc_increment_ = 1; + autoinc_param.autoinc_offset_ = 1; + autoinc_param.part_value_no_order_ = true; + if (autoinc_column_schema->is_tbl_part_key_column()) { + // don't keep intra-partition value asc order when partkey column is auto inc + autoinc_param.part_value_no_order_ = true; + } + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::init_sequence() +{ + int ret = OB_SUCCESS; + share::schema::ObSchemaGetterGuard table_schema_guard; + share::schema::ObSchemaGetterGuard sequence_schema_guard; + const ObSequenceSchema *sequence_schema = nullptr; + uint64_t tenant_id = ctx_->param_.tenant_id_; + const ObTableSchema *target_table_schema = nullptr; + uint64_t sequence_id = OB_INVALID_ID; + if (OB_FAIL(ObTableLoadSchema::get_table_schema(ctx_->param_.tenant_id_, + ctx_->param_.target_table_id_, + table_schema_guard, target_table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(ctx_->param_.tenant_id_), + K(ctx_->param_.target_table_id_)); + } else if (OB_ISNULL(target_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), + K(ctx_->param_.target_table_id_)); + } else { + //ddl对于identity是建表的时候进行自增值同步,对于sequence参数初始化得用隐藏表table id的table schema + for (ObTableSchema::const_column_iterator iter = target_table_schema->column_begin(); + OB_SUCC(ret) && iter != target_table_schema->column_end(); ++iter) { + ObColumnSchemaV2 *column_schema = *iter; + if (OB_ISNULL(column_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid column schema", K(column_schema)); + } else { + uint64_t column_id = column_schema->get_column_id(); + if (column_schema->is_identity_column() && column_id != OB_HIDDEN_PK_INCREMENT_COLUMN_ID) { + sequence_id = column_schema->get_sequence_id(); + break; + } + } + }//end for + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(GCTX.schema_service_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("schema service is null", KR(ret)); + } else if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard( + tenant_id, + sequence_schema_guard))) { + LOG_WARN("get schema guard failed", KR(ret)); + } else if (OB_FAIL(sequence_schema_guard.get_sequence_schema( + tenant_id, + sequence_id, + sequence_schema))) { + LOG_WARN("fail get sequence schema", K(sequence_id), KR(ret)); + } else if (OB_ISNULL(sequence_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null unexpected", KR(ret)); + } else if (OB_FAIL(sequence_schema_.assign(*sequence_schema))) { + LOG_WARN("cache sequence_schema fail", K(tenant_id), K(sequence_id), KR(ret)); + } + return ret; +} + +int ObTableLoadStoreCtx::commit_autoinc_value() +{ + int ret = OB_SUCCESS; + ObAutoincrementService &auto_service = ObAutoincrementService::get_instance(); + for (int64_t i = 0; OB_SUCC(ret) && i < ctx_->param_.session_count_; ++i) { + SessionContext *session_ctx = session_ctx_array_ + i; + if (OB_FAIL(auto_service.sync_insert_value_local(session_ctx->autoinc_param_))) { + LOG_WARN("fail to sync insert auto increment value local", KR(ret), K(session_ctx->autoinc_param_)); + } else if (OB_FAIL(auto_service.sync_insert_value_global(session_ctx->autoinc_param_))) { + LOG_WARN("fail to sync insert auto increment value global", KR(ret), K(session_ctx->autoinc_param_)); + } + } + return ret; +} + +int ObTableLoadStoreCtx::init_session_ctx_array() +{ + int ret = OB_SUCCESS; + void *buf = nullptr; + AutoincParam autoinc_param; + if (OB_ISNULL(buf = allocator_.alloc(sizeof(SessionContext) * ctx_->param_.session_count_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else if (ctx_->schema_.has_autoinc_column_ && OB_FAIL(generate_autoinc_params(autoinc_param))) { + LOG_WARN("fail to init auto increment param", KR(ret)); + } else { + session_ctx_array_ = new (buf) SessionContext[ctx_->param_.session_count_]; + for (int64_t i = 0; OB_SUCC(ret) && i < ctx_->param_.session_count_; ++i) { + SessionContext *session_ctx = session_ctx_array_ + i; + session_ctx->autoinc_param_ = autoinc_param; + } + } + return ret; +} + +int ObTableLoadStoreCtx::start_trans(const ObTableLoadTransId &trans_id, + ObTableLoadStoreTrans *&trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(check_status_unlock(ObTableLoadStatusType::LOADING))) { + LOG_WARN("fail to check status", KR(ret), K_(status)); + } else { + const ObTableLoadSegmentID &segment_id = trans_id.segment_id_; + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + if (OB_FAIL(segment_ctx_map_.create(segment_id, segment_ctx))) { + LOG_WARN("fail to create", KR(ret)); + } else { + segment_ctx->segment_id_ = segment_id; + } + } + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(nullptr != segment_ctx->current_trans_ || + nullptr != segment_ctx->committed_trans_store_)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("trans already exist", KR(ret), KPC(segment_ctx)); + } else { + if (OB_FAIL(alloc_trans(trans_id, trans))) { + LOG_WARN("fail to alloc trans", KR(ret)); + } else { + segment_ctx->current_trans_ = trans; + trans->inc_ref_count(); + } + } + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::commit_trans(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObMutexGuard guard(mutex_); + const ObTableLoadSegmentID &segment_id = trans->get_trans_id().segment_id_; + SegmentCtx *segment_ctx = nullptr; + ObTableLoadTransStore *trans_store = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } + } else if (OB_UNLIKELY(segment_ctx->current_trans_ != trans)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } else if (OB_FAIL(trans->check_trans_status(ObTableLoadTransStatusType::COMMIT))) { + LOG_WARN("fail to check trans status commit", KR(ret)); + } else if (OB_FAIL(trans->output_store(trans_store))) { + LOG_WARN("fail to output store", KR(ret)); + } else if (OB_FAIL(committed_trans_store_array_.push_back(trans_store))) { + LOG_WARN("fail to push back trans store", KR(ret)); + } else { + segment_ctx->current_trans_ = nullptr; + segment_ctx->committed_trans_store_ = trans_store; + trans->set_dirty(); + } + if (OB_FAIL(ret)) { + if (nullptr != trans_store) { + trans_store->~ObTableLoadTransStore(); + trans_store = nullptr; + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::abort_trans(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObMutexGuard guard(mutex_); + const ObTableLoadSegmentID &segment_id = trans->get_trans_id().segment_id_; + SegmentCtx *segment_ctx = nullptr; + if (OB_FAIL(segment_ctx_map_.get(segment_id, segment_ctx))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get segment ctx", KR(ret)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } + } else if (OB_UNLIKELY(segment_ctx->current_trans_ != trans)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected trans", KR(ret)); + } else if (OB_FAIL(trans->check_trans_status(ObTableLoadTransStatusType::ABORT))) { + LOG_WARN("fail to check trans status abort", KR(ret)); + } else { + segment_ctx->current_trans_ = nullptr; + trans->set_dirty(); + } + } + return ret; +} + +void ObTableLoadStoreCtx::put_trans(ObTableLoadStoreTrans *trans) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_ISNULL(trans)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(trans)); + } else { + ObTableLoadTransCtx *trans_ctx = trans->get_trans_ctx(); + if (0 == trans->dec_ref_count() && trans->is_dirty()) { + ObTableLoadTransStatusType trans_status = trans_ctx->get_trans_status(); + OB_ASSERT(ObTableLoadTransStatusType::COMMIT == trans_status || + ObTableLoadTransStatusType::ABORT == trans_status); + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_map_.erase_refactored(trans->get_trans_id()))) { + LOG_WARN("fail to erase_refactored", KR(ret)); + } else { + trans_allocator_.free(trans); + trans = nullptr; + } + } + } + if (OB_FAIL(ret)) { + set_status_error(ret); + } +} + +int ObTableLoadStoreCtx::get_trans(const ObTableLoadTransId &trans_id, + ObTableLoadStoreTrans *&trans) +{ + int ret = OB_SUCCESS; + trans = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_map_.get_refactored(trans_id, trans))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get_refactored", KR(ret), K(trans_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } else { + trans->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadStoreCtx::get_trans_ctx(const ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_ctx_map_.get_refactored(trans_id, trans_ctx))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get trans ctx", KR(ret), K(trans_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::get_active_trans_ids( + ObIArray &trans_id_array) const +{ + int ret = OB_SUCCESS; + trans_id_array.reset(); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + for (TransMap::const_iterator trans_iter = trans_map_.begin(); + OB_SUCC(ret) && trans_iter != trans_map_.end(); ++trans_iter) { + if (OB_FAIL(trans_id_array.push_back(trans_iter->first))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::get_committed_trans_ids( + ObTableLoadArray &trans_id_array, ObIAllocator &allocator) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_id_array.create(committed_trans_store_array_.count(), allocator))) { + LOG_WARN("fail to create trans id array", KR(ret)); + } else { + for (int64_t i = 0; i < committed_trans_store_array_.count(); ++i) { + ObTableLoadTransStore *trans_store = committed_trans_store_array_.at(i); + trans_id_array[i] = trans_store->trans_ctx_->trans_id_; + } + } + } + return ret; +} + +int ObTableLoadStoreCtx::get_committed_trans_stores( + ObIArray &trans_store_array) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(trans_store_array.assign(committed_trans_store_array_))) { + LOG_WARN("fail to assign trans store array", KR(ret)); + } + } + return ret; +} + +int ObTableLoadStoreCtx::check_exist_trans(bool &exist) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else { + ObMutexGuard guard(mutex_); + exist = !trans_map_.empty(); + } + return ret; +} + +void ObTableLoadStoreCtx::clear_committed_trans_stores() +{ + ObMutexGuard guard(mutex_); + for (int64_t i = 0; i < committed_trans_store_array_.count(); ++i) { + ObTableLoadTransStore *trans_store = committed_trans_store_array_.at(i); + ObTableLoadTransCtx *trans_ctx = trans_store->trans_ctx_; + trans_store->~ObTableLoadTransStore(); + trans_ctx->allocator_.free(trans_store); + } + committed_trans_store_array_.reset(); +} + +int ObTableLoadStoreCtx::commit() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreCtx not init", KR(ret)); + } else if (OB_FAIL(check_status(ObTableLoadStatusType::MERGED))) { + LOG_WARN("fail to check status", KR(ret)); + } else if (OB_FAIL(insert_table_ctx_->commit())) { + LOG_WARN("fail to commit insert table", KR(ret)); + } else if (ctx_->schema_.has_autoinc_column_ && OB_FAIL(commit_autoinc_value())) { + LOG_WARN("fail to commit sync auto increment value", KR(ret)); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store_ctx.h b/src/observer/table_load/ob_table_load_store_ctx.h new file mode 100644 index 0000000000..efc07ea918 --- /dev/null +++ b/src/observer/table_load/ob_table_load_store_ctx.h @@ -0,0 +1,168 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_se_array.h" +#include "lib/hash/ob_link_hashmap.h" +#include "observer/table_load/ob_table_load_object_allocator.h" +#include "share/ob_autoincrement_param.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadInsertTableContext; +class ObDirectLoadFastHeapTableContext; +class ObDirectLoadTmpFileManager; +} // namespace storage +namespace share +{ +class ObSequenceCache; +} // namespace share +namespace observer +{ +class ObTableLoadTableCtx; +class ObTableLoadStoreTrans; +class ObTableLoadTransCtx; +class ObTableLoadTransStore; +class ObITableLoadTaskScheduler; +class ObTableLoadMerger; +class ObTableLoadErrorRowHandler; + +class ObTableLoadStoreCtx +{ +public: + ObTableLoadStoreCtx(ObTableLoadTableCtx *ctx); + ~ObTableLoadStoreCtx(); + int init(int64_t ddl_task_id, + const table::ObTableLoadArray &partition_id_array, + const table::ObTableLoadArray &target_partition_id_array); + void stop(); + void destroy(); + bool is_valid() const { return is_inited_; } + TO_STRING_KV(K_(is_inited)); +public: + OB_INLINE table::ObTableLoadStatusType get_status() const + { + lib::ObMutexGuard guard(mutex_); + return status_; + } + OB_INLINE int get_error_code() const + { + lib::ObMutexGuard guard(mutex_); + return error_code_; + } + OB_INLINE int set_status_inited() + { + return advance_status(table::ObTableLoadStatusType::INITED); + } + OB_INLINE int set_status_loading() + { + return advance_status(table::ObTableLoadStatusType::LOADING); + } + OB_INLINE int set_status_frozen() + { + return advance_status(table::ObTableLoadStatusType::FROZEN); + } + OB_INLINE int set_status_merging() + { + return advance_status(table::ObTableLoadStatusType::MERGING); + } + OB_INLINE int set_status_merged() + { + return advance_status(table::ObTableLoadStatusType::MERGED); + } + OB_INLINE int set_status_commit() + { + return advance_status(table::ObTableLoadStatusType::COMMIT); + } + int set_status_error(int error_code); + int set_status_abort(); + int check_status(table::ObTableLoadStatusType status) const; +private: + int advance_status(table::ObTableLoadStatusType status); + int check_status_unlock(table::ObTableLoadStatusType status) const; +public: + int start_trans(const table::ObTableLoadTransId &trans_id, ObTableLoadStoreTrans *&trans); + int commit_trans(ObTableLoadStoreTrans *trans); + int abort_trans(ObTableLoadStoreTrans *trans); + void put_trans(ObTableLoadStoreTrans *trans); + int get_trans(const table::ObTableLoadTransId &trans_id, ObTableLoadStoreTrans *&trans); + int get_trans_ctx(const table::ObTableLoadTransId &trans_id, + ObTableLoadTransCtx *&trans_ctx) const; + int get_active_trans_ids(common::ObIArray &trans_id_array) const; + int get_committed_trans_ids(table::ObTableLoadArray &trans_id_array, + common::ObIAllocator &allocator) const; + int get_committed_trans_stores( + common::ObIArray &trans_store_array) const; + int check_exist_trans(bool &exist) const; + // release disk space + void clear_committed_trans_stores(); + int commit(); +private: + int alloc_trans_ctx(const table::ObTableLoadTransId &trans_id, ObTableLoadTransCtx *&trans_ctx); + int alloc_trans(const table::ObTableLoadTransId &trans_id, ObTableLoadStoreTrans *&trans); + int get_wa_memory_limit(int64_t &wa_mem_limit); + int init_session_ctx_array(); + int generate_autoinc_params(share::AutoincParam &autoinc_param); + int init_sequence(); + int commit_autoinc_value(); +public: + ObTableLoadTableCtx * const ctx_; + common::ObArray ls_partition_ids_; + common::ObArray target_ls_partition_ids_; + storage::ObDirectLoadTableDataDesc table_data_desc_; + table::ObTableLoadResultInfo result_info_; + ObITableLoadTaskScheduler *task_scheduler_; + ObTableLoadMerger *merger_; + storage::ObDirectLoadInsertTableContext *insert_table_ctx_; + bool is_multiple_mode_; + bool is_fast_heap_table_; + storage::ObDirectLoadFastHeapTableContext *fast_heap_table_ctx_; + storage::ObDirectLoadTmpFileManager *tmp_file_mgr_; + ObTableLoadErrorRowHandler *error_row_handler_; + share::schema::ObSequenceSchema sequence_schema_; + struct SessionContext + { + share::AutoincParam autoinc_param_; + }; + SessionContext *session_ctx_array_; +private: + struct SegmentCtx : public common::LinkHashValue + { + public: + SegmentCtx() : segment_id_(0), current_trans_(nullptr), committed_trans_store_(nullptr) {} + TO_STRING_KV(K_(segment_id), KP_(current_trans), KP_(committed_trans_store)); + public: + table::ObTableLoadSegmentID segment_id_; + ObTableLoadStoreTrans *current_trans_; + ObTableLoadTransStore *committed_trans_store_; + }; +private: + typedef common::hash::ObHashMap + TransMap; + typedef common::hash::ObHashMap + TransCtxMap; + typedef common::ObLinkHashMap SegmentCtxMap; +private: + ObTableLoadObjectAllocator trans_allocator_; // 多线程安全 + mutable lib::ObMutex mutex_; + common::ObArenaAllocator allocator_; + table::ObTableLoadStatusType status_; + int error_code_; + TransMap trans_map_; + TransCtxMap trans_ctx_map_; + SegmentCtxMap segment_ctx_map_; + common::ObSEArray committed_trans_store_array_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store_trans.cpp b/src/observer/table_load/ob_table_load_store_trans.cpp new file mode 100644 index 0000000000..a2b166273c --- /dev/null +++ b/src/observer/table_load/ob_table_load_store_trans.cpp @@ -0,0 +1,246 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_store_trans.h" +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_trans_store.h" +#include "sql/engine/cmd/ob_load_data_utils.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace lib; +using namespace table; + +ObTableLoadStoreTrans::ObTableLoadStoreTrans(ObTableLoadTransCtx *trans_ctx) + : trans_ctx_(trans_ctx), + trans_store_(nullptr), + trans_store_writer_(nullptr), + ref_count_(0), + is_dirty_(false), + is_inited_(false) +{ +} + +ObTableLoadStoreTrans::~ObTableLoadStoreTrans() +{ + if (nullptr != trans_store_writer_) { + trans_store_writer_->~ObTableLoadTransStoreWriter(); + trans_ctx_->allocator_.free(trans_store_writer_); + trans_store_writer_ = nullptr; + } + if (nullptr != trans_store_) { + trans_store_->~ObTableLoadTransStore(); + trans_ctx_->allocator_.free(trans_store_); + trans_store_ = nullptr; + } +} + +int ObTableLoadStoreTrans::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadStoreTrans init twice", KR(ret), KP(this)); + } else { + if (OB_ISNULL(trans_store_ = + OB_NEWx(ObTableLoadTransStore, (&trans_ctx_->allocator_), trans_ctx_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTransStore", KR(ret)); + } else if (OB_ISNULL(trans_store_writer_ = OB_NEWx(ObTableLoadTransStoreWriter, + (&trans_ctx_->allocator_), trans_store_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTransStoreWriter", KR(ret)); + } else if (OB_FAIL(trans_store_->init())) { + LOG_WARN("fail to init trans store", KR(ret)); + } else if (OB_FAIL(trans_store_writer_->init())) { + LOG_WARN("fail to init trans store writer", KR(ret)); + } else if (OB_FAIL(set_trans_status_inited())) { + LOG_WARN("fail to set trans status inited", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadStoreTrans::advance_trans_status(ObTableLoadTransStatusType trans_status) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->advance_trans_status(trans_status))) { + LOG_WARN("fail to advance trans status", KR(ret), K(trans_status)); + } else { + table_load_trans_status_to_string(trans_status, + trans_ctx_->ctx_->job_stat_->store.trans_status_); + } + return ret; +} + +int ObTableLoadStoreTrans::set_trans_status_error(int error_code) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->set_trans_status_error(error_code))) { + LOG_WARN("fail to set trans status error", KR(ret)); + } else { + table_load_trans_status_to_string(ObTableLoadTransStatusType::ERROR, + trans_ctx_->ctx_->job_stat_->store.trans_status_); + } + return ret; +} + +int ObTableLoadStoreTrans::set_trans_status_abort() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(trans_ctx_->set_trans_status_abort())) { + LOG_WARN("fail to set trans status abort", KR(ret)); + } else { + table_load_trans_status_to_string(ObTableLoadTransStatusType::ABORT, + trans_ctx_->ctx_->job_stat_->store.trans_status_); + } + return ret; +} + +int ObTableLoadStoreTrans::get_store_writer_for_write( + ObTableLoadTransStoreWriter *&store_writer) const +{ + int ret = OB_SUCCESS; + store_writer = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreTrans not init", KR(ret), KP(this)); + } else if (OB_FAIL(check_trans_status(ObTableLoadTransStatusType::RUNNING))) { + LOG_WARN("fail to check trans status", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_store_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null store writer", KR(ret)); + } else if (OB_UNLIKELY(trans_store_writer_->is_flush())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans store writer is flush", KR(ret)); + } else { + store_writer = trans_store_writer_; + store_writer->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadStoreTrans::get_store_writer_for_flush( + ObTableLoadTransStoreWriter *&store_writer) const +{ + int ret = OB_SUCCESS; + store_writer = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreTrans not init", KR(ret), KP(this)); + } else if (OB_FAIL(check_trans_status(ObTableLoadTransStatusType::FROZEN))) { + LOG_WARN("fail to check trans status", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_store_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null store writer", KR(ret)); + } else if (OB_UNLIKELY(trans_store_writer_->is_flush())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("trans store writer is flush", KR(ret)); + } else { + trans_store_writer_->set_is_flush(); + store_writer = trans_store_writer_; + store_writer->inc_ref_count(); + } + } + return ret; +} + +int ObTableLoadStoreTrans::get_store_writer_for_clean_up( + ObTableLoadTransStoreWriter *&store_writer) const +{ + int ret = OB_SUCCESS; + store_writer = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreTrans not init", KR(ret), KP(this)); + } else if (OB_FAIL(check_trans_status(ObTableLoadTransStatusType::ABORT))) { + LOG_WARN("fail to check trans status", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_store_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null store writer", KR(ret)); + } else { + store_writer = trans_store_writer_; + store_writer->inc_ref_count(); + } + } + return ret; +} + +void ObTableLoadStoreTrans::put_store_writer(ObTableLoadTransStoreWriter *store_writer) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreTrans not init", KR(ret)); + } else if (OB_ISNULL(store_writer)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid null store", KR(ret)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + OB_ASSERT(trans_store_writer_ == store_writer); + } + if (OB_SUCC(ret)) { + if (0 == store_writer->dec_ref_count() && OB_FAIL(handle_write_done())) { + LOG_WARN("fail to handle store write done", KR(ret)); + } + } + if (OB_FAIL(ret)) { + set_trans_status_error(ret); + } +} + +int ObTableLoadStoreTrans::handle_write_done() +{ + int ret = OB_SUCCESS; + if (ObTableLoadTransStatusType::FROZEN == trans_ctx_->get_trans_status()) { + if (OB_FAIL(set_trans_status_commit())) { + LOG_WARN("fail to set trans status commit", KR(ret)); + } + } + return ret; +} + +int ObTableLoadStoreTrans::output_store(ObTableLoadTransStore *&trans_store) +{ + int ret = OB_SUCCESS; + trans_store = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadStoreTrans not init", KR(ret), KP(this)); + } else { + ObMutexGuard guard(trans_ctx_->mutex_); + if (OB_ISNULL(trans_store_) || OB_ISNULL(trans_store_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null store", KR(ret), KP_(trans_store), KP_(trans_store_writer)); + } else if (OB_UNLIKELY(0 != trans_store_writer_->get_ref_count())) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("store writer already be hold", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadTransStatusType::COMMIT != trans_ctx_->trans_status_)) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("store is not committed", KR(ret)); + } else { + trans_store = trans_store_; + trans_store_ = nullptr; + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_store_trans.h b/src/observer/table_load/ob_table_load_store_trans.h new file mode 100644 index 0000000000..6e74048e07 --- /dev/null +++ b/src/observer/table_load/ob_table_load_store_trans.h @@ -0,0 +1,78 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_trans_ctx.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTransStore; +class ObTableLoadTransStoreWriter; + +struct ObTableLoadStoreTrans +{ + ObTableLoadStoreTrans(ObTableLoadTransCtx *trans_ctx); + ~ObTableLoadStoreTrans(); + int init(); + OB_INLINE ObTableLoadTransCtx *get_trans_ctx() const { return trans_ctx_; } + OB_INLINE const table::ObTableLoadTransId &get_trans_id() const + { + return trans_ctx_->trans_id_; + } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } + bool is_dirty() const { return is_dirty_; } + void set_dirty() { is_dirty_ = true; } + TO_STRING_KV(KP_(trans_ctx), K_(is_dirty)); +public: + OB_INLINE int check_trans_status(table::ObTableLoadTransStatusType trans_status) const + { + return trans_ctx_->check_trans_status(trans_status); + } + OB_INLINE int set_trans_status_inited() + { + return advance_trans_status(table::ObTableLoadTransStatusType::INITED); + } + OB_INLINE int set_trans_status_running() + { + return advance_trans_status(table::ObTableLoadTransStatusType::RUNNING); + } + OB_INLINE int set_trans_status_frozen() + { + return advance_trans_status(table::ObTableLoadTransStatusType::FROZEN); + } + OB_INLINE int set_trans_status_commit() + { + return advance_trans_status(table::ObTableLoadTransStatusType::COMMIT); + } + int set_trans_status_error(int error_code); + int set_trans_status_abort(); +private: + int advance_trans_status(table::ObTableLoadTransStatusType trans_status); +public: + int get_store_writer_for_write(ObTableLoadTransStoreWriter *&store_writer) const; + int get_store_writer_for_flush(ObTableLoadTransStoreWriter *&store_writer) const; + int get_store_writer_for_clean_up(ObTableLoadTransStoreWriter *&store_writer) const; + void put_store_writer(ObTableLoadTransStoreWriter *store_writer); + // 取出store + int output_store(ObTableLoadTransStore *&trans_store); +private: + int handle_write_done(); +private: + ObTableLoadTransCtx * const trans_ctx_; + ObTableLoadTransStore *trans_store_; + ObTableLoadTransStoreWriter *trans_store_writer_; + int64_t ref_count_ CACHE_ALIGNED; + volatile bool is_dirty_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_struct.h b/src/observer/table_load/ob_table_load_struct.h new file mode 100644 index 0000000000..48c6f4a85f --- /dev/null +++ b/src/observer/table_load/ob_table_load_struct.h @@ -0,0 +1,162 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/hash_func/murmur_hash.h" +#include "lib/lock/ob_mutex.h" +#include "lib/utility/ob_print_utils.h" +#include "share/table/ob_table_load_array.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" + +namespace oceanbase +{ +namespace common +{ +class ObObj; +} +namespace observer +{ + +static const int32_t MAX_TABLE_LOAD_SESSION_COUNT = 128; + +enum class ObTableLoadDataType : int32_t +{ + OBJ_ARRAY = 0, //obobj[] + STR_ARRAY = 1, //string[] + RAW_STRING = 2, //string + MAX_DATA_TYPE +}; + +struct ObTableLoadKey +{ +public: + ObTableLoadKey() : tenant_id_(common::OB_INVALID_ID), table_id_(common::OB_INVALID_ID) {} + ObTableLoadKey(uint64_t tenant_id, uint64_t table_id) : tenant_id_(tenant_id), table_id_(table_id) {} + uint64_t tenant_id_; + uint64_t table_id_; + bool is_valid() const + { + return common::OB_INVALID_ID != tenant_id_ && common::OB_INVALID_ID != table_id_; + } + bool operator==(const ObTableLoadKey &other) const + { + return (tenant_id_ == other.tenant_id_ && table_id_ == other.table_id_); + } + bool operator!=(const ObTableLoadKey &other) const + { + return !(*this == other); + } + uint64_t hash() const + { + uint64_t hash_val = common::murmurhash(&tenant_id_, sizeof(tenant_id_), 0); + hash_val = common::murmurhash(&table_id_, sizeof(table_id_), hash_val); + return hash_val; + } + int compare(const ObTableLoadKey &other) const + { + return (tenant_id_ != other.tenant_id_ ? tenant_id_ - other.tenant_id_ + : table_id_ - other.table_id_); + } + TO_STRING_KV(K_(tenant_id), K_(table_id)); +}; + +struct ObTableLoadParam +{ + ObTableLoadParam() + : tenant_id_(common::OB_INVALID_ID), + database_id_(common::OB_INVALID_ID), + table_id_(common::OB_INVALID_ID), + target_table_id_(common::OB_INVALID_ID), + session_count_(0), + batch_size_(0), + max_error_row_count_(0), + sql_mode_(0), + column_count_(0), + need_sort_(false), + px_mode_(false), + online_opt_stat_gather_(false), + data_type_(ObTableLoadDataType::RAW_STRING), + dup_action_(sql::ObLoadDupActionType::LOAD_INVALID_MODE) + { + } + uint64_t tenant_id_; + uint64_t database_id_; + uint64_t table_id_; + uint64_t target_table_id_; + int32_t session_count_; + int32_t batch_size_; + uint64_t max_error_row_count_; + uint64_t sql_mode_; + int32_t column_count_; + bool need_sort_; + bool px_mode_; + bool online_opt_stat_gather_; + ObTableLoadDataType data_type_; + sql::ObLoadDupActionType dup_action_; + + int normalize() + { + int ret = common::OB_SUCCESS; + if (need_sort_) { + if (session_count_ < 2) { + session_count_ = 2; //排序至少要两个线程才能工作 + } + } + return ret; + } + + bool is_valid() const + { + return common::OB_INVALID_ID != tenant_id_ && + common::OB_INVALID_ID != database_id_ && + common::OB_INVALID_ID != table_id_ && + //common::OB_INVALID_ID != target_table_id_ && + session_count_ > 0 && session_count_ <= MAX_TABLE_LOAD_SESSION_COUNT && + batch_size_ > 0 && + column_count_ > 0; + } + + TO_STRING_KV(K_(tenant_id), K_(database_id), K_(table_id), K_(target_table_id), K_(session_count), + K_(batch_size), K_(max_error_row_count), K_(column_count), + K_(need_sort), K_(px_mode), K_(data_type), K_(dup_action)); +}; + +class ObTableLoadMutexGuard +{ +public: + ObTableLoadMutexGuard() : mutex_(nullptr) {} + ~ObTableLoadMutexGuard() + { + reset(); + } + void reset() + { + int ret = common::OB_SUCCESS; + if (nullptr != mutex_) { + if (OB_FAIL(mutex_->unlock())) { + SERVER_LOG(WARN, "fail to unlock mutex", KR(ret)); + } + mutex_ = nullptr; + } + } + int init(lib::ObMutex &mutex) + { + int ret = common::OB_SUCCESS; + reset(); + if (OB_FAIL(mutex.lock())) { + SERVER_LOG(WARN, "fail to lock mutex", KR(ret)); + } else { + mutex_ = &mutex; + } + return ret; + } + bool is_valid() const { return nullptr != mutex_; } + TO_STRING_KV(KP_(mutex)); +private: + lib::ObMutex *mutex_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_table_compactor.cpp b/src/observer/table_load/ob_table_load_table_compactor.cpp new file mode 100644 index 0000000000..512cfcc64a --- /dev/null +++ b/src/observer/table_load/ob_table_load_table_compactor.cpp @@ -0,0 +1,213 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_table_compactor.h" +#include "observer/table_load/ob_table_load_general_table_compactor.h" +#include "observer/table_load/ob_table_load_merger.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_mem_compactor.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "observer/table_load/ob_table_load_multiple_heap_table_compactor.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace storage; + +/** + * ObTableLoadTableCompactResult + */ + +ObTableLoadTableCompactResult::ObTableLoadTableCompactResult() + : allocator_("TLD_TCResult"), tablet_result_map_(64) +{ +} + +ObTableLoadTableCompactResult::~ObTableLoadTableCompactResult() +{ + reset(); +} + +void ObTableLoadTableCompactResult::reset() +{ + for (int64_t i = 0; i < all_table_array_.count(); ++i) { + ObIDirectLoadPartitionTable *table = all_table_array_.at(i); + table->~ObIDirectLoadPartitionTable(); + allocator_.free(table); + } + all_table_array_.reset(); + allocator_.reset(); + tablet_result_map_.reset(); +} + +int ObTableLoadTableCompactResult::init() +{ + int ret = OB_SUCCESS; + allocator_.set_tenant_id(MTL_ID()); + if (OB_FAIL(tablet_result_map_.init("TLD_TCResult", MTL_ID()))) { + LOG_WARN("fail to init link hash map", KR(ret)); + } + return ret; +} + +int ObTableLoadTableCompactResult::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + const ObTabletID &tablet_id = table->get_tablet_id(); + ObTableLoadTableCompactTabletResult *tablet_result = nullptr; + if (OB_FAIL(tablet_result_map_.get(tablet_id, tablet_result))) { + if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { + LOG_WARN("fail to get", KR(ret)); + } else { + if (OB_FAIL(tablet_result_map_.create(tablet_id, tablet_result))) { + LOG_WARN("fail to create", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_result->table_array_.push_back(table))) { + LOG_WARN("fail to push back", KR(ret)); + } else if (OB_FAIL(all_table_array_.push_back(table))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + if (OB_NOT_NULL(tablet_result)) { + tablet_result_map_.revert(tablet_result); + } + } + return ret; +} + +/** + * ObTableLoadTableCompactCtx + */ + +ObTableLoadTableCompactCtx::ObTableLoadTableCompactCtx() + : allocator_("TLD_TCCtx"), store_ctx_(nullptr), merger_(nullptr), compactor_(nullptr) +{ +} + +ObTableLoadTableCompactCtx::~ObTableLoadTableCompactCtx() +{ + if (nullptr != compactor_) { + compactor_->~ObTableLoadTableCompactor(); + allocator_.free(compactor_); + compactor_ = nullptr; + } +} + +int ObTableLoadTableCompactCtx::init(ObTableLoadStoreCtx *store_ctx, ObTableLoadMerger &merger) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == store_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(store_ctx)); + } else { + if (OB_FAIL(result_.init())) { + LOG_WARN("fail to init result", KR(ret)); + } else { + allocator_.set_tenant_id(MTL_ID()); + store_ctx_ = store_ctx; + merger_ = &merger; + } + } + return ret; +} + +bool ObTableLoadTableCompactCtx::is_valid() const +{ + return nullptr != store_ctx_ && nullptr != merger_; +} + +ObTableLoadTableCompactor *ObTableLoadTableCompactCtx::new_compactor() +{ + ObTableLoadTableCompactor *ret = nullptr; + if (store_ctx_->is_multiple_mode_) { + if (store_ctx_->table_data_desc_.is_heap_table_) { + ret = OB_NEWx(ObTableLoadMultipleHeapTableCompactor, (&allocator_)); + } else { + ret = OB_NEWx(ObTableLoadMemCompactor, (&allocator_)); + } + } else { + ret = OB_NEWx(ObTableLoadGeneralTableCompactor, (&allocator_)); + } + return ret; +} + +int ObTableLoadTableCompactCtx::start() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(compactor_ = new_compactor())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadGeneralTableCompactor", KR(ret)); + } else if (OB_FAIL(compactor_->init(this))) { + LOG_WARN("fail to init compactor", KR(ret)); + } else if (OB_FAIL(compactor_->start())) { + LOG_WARN("fail to start compactor", KR(ret)); + } + return ret; +} + +void ObTableLoadTableCompactCtx::stop() +{ + if (OB_NOT_NULL(compactor_)) { + compactor_->stop(); + } +} + +int ObTableLoadTableCompactCtx::handle_table_compact_success() +{ + // release compactor + compactor_->~ObTableLoadTableCompactor(); + allocator_.free(compactor_); + compactor_ = nullptr; + // notify merger + return merger_->handle_table_compact_success(); +} + +/** + * ObTableLoadTableCompactor + */ + +ObTableLoadTableCompactor::ObTableLoadTableCompactor() + : compact_ctx_(nullptr), is_inited_(false) +{ +} + +ObTableLoadTableCompactor::~ObTableLoadTableCompactor() +{ +} + +int ObTableLoadTableCompactor::init(ObTableLoadTableCompactCtx *compact_ctx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadTableCompactor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == compact_ctx || !compact_ctx->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(compact_ctx)); + } else { + compact_ctx_ = compact_ctx; + if (OB_FAIL(inner_init())) { + LOG_WARN("fail to inner init", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_table_compactor.h b/src/observer/table_load/ob_table_load_table_compactor.h new file mode 100644 index 0000000000..9e5a92f4eb --- /dev/null +++ b/src/observer/table_load/ob_table_load_table_compactor.h @@ -0,0 +1,80 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "lib/allocator/page_arena.h" +#include "lib/hash/ob_link_hashmap.h" +#include "storage/direct_load/ob_direct_load_i_table.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadStoreCtx; +class ObTableLoadMerger; +class ObTableLoadTableCompactor; + +struct ObTableLoadTableCompactTabletResult : public common::LinkHashValue +{ + common::ObSEArray table_array_; + TO_STRING_KV(K_(table_array)); +}; + +struct ObTableLoadTableCompactResult +{ +public: + ObTableLoadTableCompactResult(); + ~ObTableLoadTableCompactResult(); + void reset(); + int init(); + int add_table(storage::ObIDirectLoadPartitionTable *table); +public: + typedef common::ObLinkHashMap + TabletResultMap; + common::ObArenaAllocator allocator_; + common::ObArray all_table_array_; + TabletResultMap tablet_result_map_; +}; + +class ObTableLoadTableCompactCtx +{ +public: + ObTableLoadTableCompactCtx(); + ~ObTableLoadTableCompactCtx(); + int init(ObTableLoadStoreCtx *store_ctx, ObTableLoadMerger &merger); + bool is_valid() const; + int start(); + void stop(); + int handle_table_compact_success(); + TO_STRING_KV(KP_(store_ctx), KP_(merger), KP_(compactor)); +private: + ObTableLoadTableCompactor *new_compactor(); + +public: + common::ObArenaAllocator allocator_; + ObTableLoadStoreCtx *store_ctx_; + ObTableLoadMerger *merger_; + ObTableLoadTableCompactor *compactor_; + ObTableLoadTableCompactResult result_; +}; + +class ObTableLoadTableCompactor +{ +public: + ObTableLoadTableCompactor(); + virtual ~ObTableLoadTableCompactor(); + int init(ObTableLoadTableCompactCtx *compact_ctx); + virtual int start() = 0; + virtual void stop() = 0; +protected: + virtual int inner_init() = 0; +protected: + ObTableLoadTableCompactCtx *compact_ctx_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_table_ctx.cpp b/src/observer/table_load/ob_table_load_table_ctx.cpp new file mode 100644 index 0000000000..2f811fc44d --- /dev/null +++ b/src/observer/table_load/ob_table_load_table_ctx.cpp @@ -0,0 +1,294 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "lib/allocator/ob_malloc.h" +#include "observer/table_load/ob_table_load_coordinator_ctx.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "observer/table_load/ob_table_load_trans_ctx.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "share/ob_common_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace sql; +using namespace table; +using namespace obrpc; + +ObTableLoadTableCtx::ObTableLoadTableCtx(const ObTableLoadParam ¶m) + : param_(param), + coordinator_ctx_(nullptr), + store_ctx_(nullptr), + job_stat_(nullptr), + allocator_("TLD_TableCtx", OB_MALLOC_NORMAL_BLOCK_SIZE, param.tenant_id_), + ref_count_(0), + is_dirty_(false), + is_inited_(false) +{ +} + +ObTableLoadTableCtx::~ObTableLoadTableCtx() +{ + destroy(); +} + +int ObTableLoadTableCtx::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadTableCtx init twice", KR(ret)); + } else { + if (OB_FAIL(schema_.init(param_.tenant_id_, param_.database_id_, param_.table_id_, + allocator_))) { + LOG_WARN("fail to init table load schema", KR(ret), K(param_.tenant_id_), + K(param_.table_id_)); + } else if (OB_FAIL(task_allocator_.init("TLD_TaskPool", param_.tenant_id_))) { + LOG_WARN("fail to init allocator", KR(ret)); + } else if (OB_FAIL(trans_ctx_allocator_.init("TLD_TCtxPool", param_.tenant_id_))) { + LOG_WARN("fail to init allocator", KR(ret)); + } else if (OB_FAIL(register_job_stat())) { + LOG_WARN("fail to register job stat", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadTableCtx::register_job_stat() +{ + int ret = OB_SUCCESS; + ObLoadDataStat *job_stat = nullptr; + if (OB_ISNULL(job_stat = OB_NEWx(ObLoadDataStat, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObLoadDataStat", KR(ret)); + } else { + ObLoadDataGID temp_gid; + ObLoadDataGID::generate_new_id(temp_gid); + job_stat->tenant_id_ = param_.tenant_id_; + job_stat->job_id_ = param_.table_id_; + job_stat->job_type_ = "direct"; + job_stat->table_column_ = param_.column_count_; + job_stat->batch_size_ = param_.batch_size_; + job_stat->parallel_ = param_.session_count_; + job_stat->start_time_ = ObTimeUtil::current_time(); + job_stat->max_allowed_error_rows_ = param_.max_error_row_count_; + job_stat->detected_error_rows_ = 0; + job_stat->coordinator.received_rows_ = 0; + job_stat->coordinator.last_commit_segment_id_ = 0; + job_stat->coordinator.status_ = "none"; + job_stat->coordinator.trans_status_ = "none"; + job_stat->store.processed_rows_ = 0; + job_stat->store.last_commit_segment_id_ = 0; + job_stat->store.status_ = "none"; + job_stat->store.trans_status_ = "none"; + if (OB_FAIL(ObTableLoadUtils::deep_copy(schema_.table_name_, job_stat->table_name_, + job_stat->allocator_))) { + LOG_WARN("fail to deep copy table name", KR(ret)); + } else if (OB_FAIL(ObGlobalLoadDataStatMap::getInstance()->register_job(temp_gid, job_stat))) { + LOG_WARN("fail to register job stat", KR(ret)); + } else { + gid_ = temp_gid; + job_stat_ = job_stat; + job_stat_->aquire(); + } + if (OB_FAIL(ret)) { + job_stat->~ObLoadDataStat(); + allocator_.free(job_stat); + job_stat = nullptr; + } + } + return ret; +} + +void ObTableLoadTableCtx::unregister_job_stat() +{ + int ret = OB_SUCCESS; + if (nullptr != job_stat_) { + job_stat_->release(); + job_stat_ = nullptr; + } + if (gid_.is_valid()) { + ObLoadDataStat *job_stat = nullptr; + if (OB_FAIL(ObGlobalLoadDataStatMap::getInstance()->unregister_job(gid_, job_stat))) { + LOG_ERROR("fail to unregister job stat", KR(ret), K_(gid)); + } else if (OB_ISNULL(job_stat)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("unexpected null job stat", KR(ret), K_(gid)); + } else { + // 可能还有其他地方在引用这个对象, 等待释放引用 + int64_t log_print_cnt = 0; + int64_t ref_cnt = 0; + while ((ref_cnt = job_stat->get_ref_cnt()) > 0) { + usleep(1L * 1000 * 1000); // 1s + if ((log_print_cnt++) % 10 == 0) { + LOG_WARN("LOAD DATA wait job handle release", KR(ret), "wait_seconds", log_print_cnt * 10, + K_(gid), K(ref_cnt)); + } + } + job_stat->~ObLoadDataStat(); + allocator_.free(job_stat); + job_stat = nullptr; + gid_.reset(); + } + } +} + +int ObTableLoadTableCtx::init_coordinator_ctx(const ObIArray &idx_array, + ObSQLSessionInfo *session_info) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else if (OB_NOT_NULL(coordinator_ctx_)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("coordinator ctx already exist", KR(ret)); + } else { + if (session_info == nullptr) { + session_info = &session_info_; + } + if (OB_ISNULL(coordinator_ctx_ = OB_NEWx(ObTableLoadCoordinatorCtx, (&allocator_), this))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadCoordinatorCtx", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->init(session_info, idx_array))) { + LOG_WARN("fail to init coordinator ctx", KR(ret)); + } else if (OB_FAIL(coordinator_ctx_->set_status_inited())) { + LOG_WARN("fail to set coordinator status inited", KR(ret)); + } + } + return ret; +} + +int ObTableLoadTableCtx::init_session_info(uint64_t user_id) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(session_info_.init(0, 0, nullptr, nullptr, ObTimeUtility::current_time(), MTL_ID()))) { + LOG_WARN("fail to init session info", KR(ret)); + } + OZ (session_info_.load_default_sys_variable(false, false)); //加载默认的session参数 + OZ (session_info_.load_default_configs_in_pc()); + OX (session_info_.set_priv_user_id(user_id)); + return ret; +} + +int ObTableLoadTableCtx::init_store_ctx( + int64_t ddl_task_id, + const ObTableLoadArray &partition_id_array, + const ObTableLoadArray &target_partition_id_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else if (OB_NOT_NULL(store_ctx_)) { + ret = OB_ENTRY_EXIST; + LOG_WARN("store ctx already exist", KR(ret)); + } else { + if (OB_ISNULL(store_ctx_ = OB_NEWx(ObTableLoadStoreCtx, (&allocator_), this))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadStoreCtx", KR(ret)); + } else if (OB_FAIL(store_ctx_->init(ddl_task_id, partition_id_array, target_partition_id_array))) { + LOG_WARN("fail to init store ctx", KR(ret)); + } else if (OB_FAIL(store_ctx_->set_status_inited())) { + LOG_WARN("fail to set store status inited", KR(ret)); + } + } + return ret; +} + +void ObTableLoadTableCtx::stop() +{ + if (nullptr != coordinator_ctx_) { + coordinator_ctx_->stop(); + } + if (nullptr != store_ctx_) { + store_ctx_->stop(); + } + LOG_INFO("ctx stop succ"); +} + +void ObTableLoadTableCtx::destroy() +{ + abort_unless(0 == get_ref_count()); + if (nullptr != coordinator_ctx_) { + coordinator_ctx_->~ObTableLoadCoordinatorCtx(); + allocator_.free(coordinator_ctx_); + coordinator_ctx_ = nullptr; + } + if (nullptr != store_ctx_) { + store_ctx_->~ObTableLoadStoreCtx(); + allocator_.free(store_ctx_); + store_ctx_ = nullptr; + } + unregister_job_stat(); + is_inited_ = false; +} + +int ObTableLoadTableCtx::alloc_task(ObTableLoadTask *&task) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else { + if (OB_ISNULL(task = task_allocator_.alloc(param_.tenant_id_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc task", KR(ret)); + } + } + return ret; +} + +void ObTableLoadTableCtx::free_task(ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else if (OB_ISNULL(task)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid null task", KR(ret)); + } else { + task_allocator_.free(task); + } +} + +ObTableLoadTransCtx *ObTableLoadTableCtx::alloc_trans_ctx(const ObTableLoadTransId &trans_id) +{ + int ret = OB_SUCCESS; + ObTableLoadTransCtx *trans_ctx = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else { + trans_ctx = trans_ctx_allocator_.alloc(this, trans_id); + } + return trans_ctx; +} + +void ObTableLoadTableCtx::free_trans_ctx(ObTableLoadTransCtx *trans_ctx) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTableCtx not init", KR(ret)); + } else if (OB_ISNULL(trans_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid null trans ctx", KR(ret)); + } else { + trans_ctx_allocator_.free(trans_ctx); + } +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_table_ctx.h b/src/observer/table_load/ob_table_load_table_ctx.h new file mode 100644 index 0000000000..2655728a83 --- /dev/null +++ b/src/observer/table_load/ob_table_load_table_ctx.h @@ -0,0 +1,79 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/list/ob_dlink_node.h" +#include "lib/utility/ob_print_utils.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_define.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "observer/table_load/ob_table_load_object_allocator.h" +#include "sql/session/ob_sql_session_info.h" + +namespace oceanbase +{ +namespace observer +{ +class ObITableLoadTaskScheduler; +class ObTableLoadCoordinatorCtx; +class ObTableLoadStoreCtx; +class ObTableLoadTask; +class ObTableLoadTransCtx; + +class ObTableLoadTableCtx : public common::ObDLinkBase +{ +public: + ObTableLoadTableCtx(const ObTableLoadParam ¶m); + ~ObTableLoadTableCtx(); + int init(); + void stop(); + void destroy(); + bool is_valid() const { return is_inited_; } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } + bool is_dirty() const { return is_dirty_; } + void set_dirty() { is_dirty_ = true; } + TO_STRING_KV(K_(param), KP_(coordinator_ctx), KP_(store_ctx), "ref_count", get_ref_count(), + K_(is_dirty), K_(is_inited)); +public: + int init_coordinator_ctx(const common::ObIArray &idx_array, + sql::ObSQLSessionInfo *session_info); + int init_store_ctx( + int64_t ddl_task_id, + const table::ObTableLoadArray &partition_id_array, + const table::ObTableLoadArray &target_partition_id_array); + int init_session_info(uint64_t user_id); +public: + int alloc_task(ObTableLoadTask *&task); + void free_task(ObTableLoadTask *task); + ObTableLoadTransCtx *alloc_trans_ctx(const table::ObTableLoadTransId &trans_id); + void free_trans_ctx(ObTableLoadTransCtx *trans_ctx); +private: + int register_job_stat(); + void unregister_job_stat(); + +public: + const ObTableLoadParam param_; + // 只在初始化的时候使用, 线程不安全 + ObTableLoadSchema schema_; + ObTableLoadCoordinatorCtx *coordinator_ctx_; // 只在控制节点构造 + ObTableLoadStoreCtx *store_ctx_; // 只在数据节点构造 + sql::ObLoadDataGID gid_; + sql::ObLoadDataStat *job_stat_; +private: + sql::ObSQLSessionInfo session_info_; + common::ObArenaAllocator allocator_; + ObTableLoadObjectAllocator task_allocator_; // 多线程安全 + ObTableLoadObjectAllocator trans_ctx_allocator_; // 多线程安全 + int64_t ref_count_ CACHE_ALIGNED; + volatile bool is_dirty_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObTableLoadTableCtx); +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_task.cpp b/src/observer/table_load/ob_table_load_task.cpp new file mode 100644 index 0000000000..23953349f3 --- /dev/null +++ b/src/observer/table_load/ob_table_load_task.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_task.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; + +ObTableLoadTask::ObTableLoadTask(uint64_t tenant_id) + : trace_id_(*ObCurTraceId::get_trace_id()), + allocator_("TLD_Task", OB_MALLOC_NORMAL_BLOCK_SIZE, tenant_id), + processor_(nullptr), + callback_(nullptr) +{ +} + +ObTableLoadTask::~ObTableLoadTask() +{ + if (nullptr != processor_) { + processor_->~ObITableLoadTaskProcessor(); + allocator_.free(processor_); + processor_ = nullptr; + } + if (nullptr != callback_) { + callback_->~ObITableLoadTaskCallback(); + allocator_.free(callback_); + callback_ = nullptr; + } +} + +int ObTableLoadTask::do_work() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(processor_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null processor", KR(ret)); + } else { + ret = processor_->process(); + } + return ret; +} + +void ObTableLoadTask::callback(int ret_code) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(callback_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null callback", KR(ret)); + } else { + callback_->callback(ret_code, this); + } +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_task.h b/src/observer/table_load/ob_table_load_task.h new file mode 100644 index 0000000000..5ec5a938ad --- /dev/null +++ b/src/observer/table_load/ob_table_load_task.h @@ -0,0 +1,105 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/profile/ob_trace_id.h" +#include "lib/string/ob_string.h" +#include "lib/utility/ob_print_utils.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace observer +{ +class ObITableLoadTaskProcessor; +class ObITableLoadTaskCallback; + +class ObTableLoadTask +{ + friend class ObITableLoadTaskProcessor; + friend class ObITableLoadTaskCallback; +public: + ObTableLoadTask(uint64_t tenant_id); + ~ObTableLoadTask(); + template + int set_processor(Args&&... args); + template + int set_callback(Args&&... args); + const common::ObCurTraceId::TraceId get_trace_id() const { return trace_id_; } + ObITableLoadTaskProcessor *get_processor() const { return processor_; } + ObITableLoadTaskCallback *get_callback() const { return callback_; } + bool is_valid() const { return nullptr != processor_ && nullptr != callback_; } + int do_work(); + void callback(int ret_code); + TO_STRING_KV(KPC_(processor), KP_(callback)); +protected: + common::ObCurTraceId::TraceId trace_id_; + common::ObArenaAllocator allocator_; + ObITableLoadTaskProcessor *processor_; + ObITableLoadTaskCallback *callback_; +private: + DISABLE_COPY_ASSIGN(ObTableLoadTask); +}; + +template +int ObTableLoadTask::set_processor(Args&&... args) +{ + int ret = common::OB_SUCCESS; + if (OB_NOT_NULL(processor_)) { + ret = common::OB_ERR_UNEXPECTED; + SERVER_LOG(WARN, "unexpected alloc processor", KR(ret)); + } else { + if (OB_ISNULL(processor_ = OB_NEWx(Processor, (&allocator_), *this, args...))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + SERVER_LOG(WARN, "fail to new processor", KR(ret)); + } + } + return ret; +} + +template +int ObTableLoadTask::set_callback(Args&&... args) +{ + int ret = common::OB_SUCCESS; + if (OB_NOT_NULL(callback_)) { + ret = common::OB_ERR_UNEXPECTED; + SERVER_LOG(WARN, "unexpected alloc callback", KR(ret)); + } else { + if (OB_ISNULL(callback_ = OB_NEWx(Callback, (&allocator_), args...))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + SERVER_LOG(WARN, "fail to new callback", KR(ret)); + } + } + return ret; +} + +class ObITableLoadTaskProcessor +{ +public: + ObITableLoadTaskProcessor(ObTableLoadTask &task) + : parent_(task), allocator_(task.allocator_) {} + virtual ~ObITableLoadTaskProcessor() = default; + virtual int process() = 0; + VIRTUAL_TO_STRING_KV(KP(this)); +protected: + ObTableLoadTask &parent_; + common::ObIAllocator &allocator_; +private: + DISABLE_COPY_ASSIGN(ObITableLoadTaskProcessor); +}; + +class ObITableLoadTaskCallback +{ +public: + ObITableLoadTaskCallback() = default; + virtual ~ObITableLoadTaskCallback() = default; + virtual void callback(int ret_code, ObTableLoadTask *task) = 0; +private: + DISABLE_COPY_ASSIGN(ObITableLoadTaskCallback); +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_task_scheduler.cpp b/src/observer/table_load/ob_table_load_task_scheduler.cpp new file mode 100644 index 0000000000..10264fa047 --- /dev/null +++ b/src/observer/table_load/ob_table_load_task_scheduler.cpp @@ -0,0 +1,330 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "common/ob_timeout_ctx.h" +#include "lib/stat/ob_session_stat.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_task.h" +#include "share/ob_share_util.h" +#include "share/rc/ob_tenant_base.h" +#include "observer/omt/ob_tenant.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace share; + +void ObTableLoadTaskThreadPoolScheduler::MyThreadPool::run1() +{ + OB_ASSERT(OB_NOT_NULL(scheduler_)); + ObTenantStatEstGuard stat_est_guard(MTL_ID()); + const int64_t thread_count = get_thread_count(); + // LOG_INFO("table load task thread start", KP(this), "pid", get_tid_cache(), "thread_idx", get_thread_idx()); + // 启动成功的线程数+1 + if (thread_count == ATOMIC_AAF(&running_thread_count_, 1)) { + scheduler_->before_running(); + } + while (!has_set_stop()) { + // 等待所有线程起来 + if (!scheduler_->is_running()) { + PAUSE(); + } else { + scheduler_->run(get_thread_idx()); + break; + } + } + // 启动成功的线程数-1 + if (0 == ATOMIC_AAF(&running_thread_count_, -1)) { + scheduler_->after_running(); + } +} + +ObTableLoadTaskThreadPoolScheduler::ObTableLoadTaskThreadPoolScheduler(int64_t thread_count, + ObIAllocator &allocator, + int64_t session_queue_size) + : allocator_(allocator), + thread_count_(thread_count), + session_queue_size_(session_queue_size), + timeout_ts_(INT64_MAX), + thread_pool_(this), + worker_ctx_array_(nullptr), + state_(STATE_ZERO), + is_inited_(false) +{ +} + +ObTableLoadTaskThreadPoolScheduler::~ObTableLoadTaskThreadPoolScheduler() +{ + if (nullptr != worker_ctx_array_) { + for (int64_t i = 0; i < thread_count_; ++i) { + WorkerContext *worker_ctx = worker_ctx_array_ + i; + worker_ctx->~WorkerContext(); + } + allocator_.free(worker_ctx_array_); + worker_ctx_array_ = nullptr; + } +} + +int ObTableLoadTaskThreadPoolScheduler::init_worker_ctx_array() +{ + int ret = OB_SUCCESS; + void *buf = nullptr; + if (OB_ISNULL(buf = allocator_.alloc(sizeof(WorkerContext) * thread_count_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else { + worker_ctx_array_ = new (buf) WorkerContext[thread_count_]; + for (int64_t i = 0; OB_SUCC(ret) && i < thread_count_; ++i) { + WorkerContext *worker_ctx = worker_ctx_array_ + i; + worker_ctx->worker_id_ = i; + if (OB_FAIL(worker_ctx->cond_.init(1))) { + LOG_WARN("fail to init thread cond", KR(ret)); + } else if (OB_FAIL(worker_ctx->task_queue_.init(session_queue_size_, "TLD_Queue", MTL_ID()))) { + LOG_WARN("fail to init task queue", KR(ret), K(i)); + } + } + } + return ret; +} + +int ObTableLoadTaskThreadPoolScheduler::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler init twice", KR(ret), KP(this)); + } else if (OB_FAIL(init_worker_ctx_array())) { + LOG_WARN("fail to init worker ctx array", KR(ret)); + } else { + thread_pool_.set_thread_count(thread_count_); + thread_pool_.set_run_wrapper(MTL_CTX()); + ObCurTraceId::TraceId *cur_trace_id = ObCurTraceId::get_trace_id(); + if (nullptr != cur_trace_id) { + trace_id_ = *cur_trace_id; + } else { + // generate trace id + ObAddr zero_addr; + trace_id_.init(zero_addr); + } + timeout_ts_ = THIS_WORKER.get_timeout_ts(); + is_inited_ = true; + } + return ret; +} + +int ObTableLoadTaskThreadPoolScheduler::start() +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(state_mutex_); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(STATE_ZERO != state_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("state must be zero", KR(ret), K_(state)); + } else { + state_ = STATE_STARTING; + if (OB_FAIL(thread_pool_.start())) { + LOG_WARN("fail to start thread pool", KR(ret)); + } else { + while (STATE_STARTING == state_) { + PAUSE(); + } + if (OB_UNLIKELY(STATE_RUNNING != state_)) { + ret = OB_NOT_RUNNING; + LOG_WARN("thread not running", KR(ret)); + } + } + } + return ret; +} + +void ObTableLoadTaskThreadPoolScheduler::stop() +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(state_mutex_); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler not init", KR(ret), KP(this)); + } else { + if (state_ == STATE_ZERO) { + state_ = STATE_STOPPED_NO_WAIT; + } else if (STATE_STARTING == state_) { + ret = OB_ERR_UNEXPECTED; //因为加锁了,这种情况不能出现 + LOG_WARN("state cann't be starting here", KR(ret)); + } else if (STATE_RUNNING == state_) { + thread_pool_.stop(); + state_ = STATE_STOPPING; + // 唤醒所有线程 + for (int64_t i = 0; i < thread_count_; ++i) { + WorkerContext &worker_ctx = worker_ctx_array_[i]; + ObThreadCondGuard guard(worker_ctx.cond_); + worker_ctx.cond_.signal(); + } + } + } +} + +//调用wait前,必须保证之前调用过stop +void ObTableLoadTaskThreadPoolScheduler::wait() +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(state_mutex_); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler not init", KR(ret), KP(this)); + } else { + if (state_ == STATE_STOPPING || state_ == STATE_STOPPED) { + thread_pool_.wait(); + } + } +} + +void ObTableLoadTaskThreadPoolScheduler::before_running() +{ + OB_ASSERT(STATE_STARTING == state_); + state_ = STATE_RUNNING; +} + +void ObTableLoadTaskThreadPoolScheduler::after_running() +{ + state_ = STATE_STOPPED; + clear_all_task(); +} + +void ObTableLoadTaskThreadPoolScheduler::run(uint64_t thread_idx) +{ + int ret = OB_SUCCESS; + + // set trace id + ObCurTraceId::set(trace_id_); + // set worker timeout + THIS_WORKER.set_timeout_ts(timeout_ts_); + // set compatibility mode + share::ObTenantBase *tenant_base = MTL_CTX(); + lib::Worker::CompatMode mode = ((omt::ObTenant *)tenant_base)->get_compat_mode(); + lib::Worker::set_compatibility_mode(mode); + + LOG_INFO("table load task thread run", KP(this), "pid", get_tid_cache(), K(thread_idx)); + + WorkerContext &worker_ctx = worker_ctx_array_[thread_idx]; + while (OB_SUCC(ret) && OB_LIKELY(STATE_RUNNING == state_)) { + if (OB_FAIL(execute_worker_tasks(worker_ctx))) { + LOG_WARN("fail to execute worker tasks", KR(ret)); + } else { + ObThreadCondGuard guard(worker_ctx.cond_); + if (OB_LIKELY(STATE_RUNNING == state_) && 0 == worker_ctx.task_queue_.size()) { + // LOG_WARN("table load task thread wait begin", KP(this), K(thread_idx), "size", worker_ctx.task_queue_.size()); + worker_ctx.need_signal_ = true; + worker_ctx.cond_.wait(); + worker_ctx.need_signal_ = false; + // LOG_WARN("table load task thread wait end", KP(this), K(thread_idx), "size", worker_ctx.task_queue_.size()); + } + } + } + + // 为了保证在abort场景, clean_up_task能在工作线程执行 + execute_worker_tasks(worker_ctx); + + // 线程非正常结束, 设置全局状态, 阻止其他线程继续执行 + if (STATE_RUNNING == state_) { + state_ = STATE_STOPPING; + } + + LOG_INFO("table load task thread stopped", KP(this), "pid", get_tid_cache(), K(thread_idx)); +} + +int ObTableLoadTaskThreadPoolScheduler::add_task(int64_t thread_idx, ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(thread_idx >= thread_count_) || OB_ISNULL(task) || + OB_UNLIKELY(!task->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(thread_idx), K_(thread_count), KPC(task)); + } else if (OB_UNLIKELY(STATE_RUNNING != state_)) { + ret = OB_NOT_RUNNING; + LOG_WARN("scheduler not running", KR(ret), K_(state)); + } else { + ObTimeoutCtx ctx; + if (OB_FAIL(ObShareUtil::set_default_timeout_ctx(ctx, DEFAULT_TIMEOUT_US))) { + LOG_WARN("fail to set default timeout ctx", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(add_task_time_us); + WorkerContext &worker_ctx = worker_ctx_array_[thread_idx]; + // LOG_WARN("table load add task begin", KP(this), K(thread_idx), "size", worker_ctx.task_queue_.size()); + if (OB_FAIL(worker_ctx.task_queue_.push(task, ctx.get_timeout()))) { + if (OB_UNLIKELY(OB_TIMEOUT != ret)) { + LOG_WARN("fail to push task into queue", KR(ret), KPC(task)); + } + } else { + // 唤醒线程 + ObThreadCondGuard guard(worker_ctx.cond_); + // LOG_WARN("table load add task end", KP(this), K(thread_idx), "size", worker_ctx.task_queue_.size(), "need_signal", worker_ctx.need_signal_); + if (worker_ctx.need_signal_) { + worker_ctx.cond_.signal(); + } + } + } + } + return ret; +} + +int ObTableLoadTaskThreadPoolScheduler::execute_worker_tasks(WorkerContext &worker_ctx) +{ + int ret = OB_SUCCESS; + int64_t size = 0; + while (OB_SUCC(ret) && (size = worker_ctx.task_queue_.size()) > 0) { + while (OB_SUCC(ret) && size-- > 0) { + void *tmp = nullptr; + if (OB_FAIL(worker_ctx.task_queue_.pop(tmp))) { + LOG_WARN("fail to pop queue", KR(ret), K(worker_ctx.worker_id_)); + } else { + // 任务的运行结果不影响工作线程的运行 + ObTableLoadTask *task = (ObTableLoadTask *)tmp; + ObTraceIdGuard trace_id_guard(task->get_trace_id()); + int task_ret = task->do_work(); + task->callback(task_ret); + } + } + } + return ret; +} + +void ObTableLoadTaskThreadPoolScheduler::clear_all_task() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTaskThreadPoolScheduler not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(STATE_STOPPED != state_)) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("scheduler not stopped", KR(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < thread_count_; ++i) { + WorkerContext &worker_ctx = worker_ctx_array_[i]; + while (worker_ctx.task_queue_.size() > 0) { + void *tmp = nullptr; + if (OB_FAIL(worker_ctx.task_queue_.pop(tmp))) { + LOG_WARN("fail to pop queue", KR(ret), K(i)); + } else { + // 触发task回调 + ObTableLoadTask *task = (ObTableLoadTask *)tmp; + ObTraceIdGuard trace_id_guard(task->get_trace_id()); + task->callback(OB_CANCELED); + } + } + } + } +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_task_scheduler.h b/src/observer/table_load/ob_table_load_task_scheduler.h new file mode 100644 index 0000000000..4aaf06fae5 --- /dev/null +++ b/src/observer/table_load/ob_table_load_task_scheduler.h @@ -0,0 +1,101 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/lock/ob_mutex.h" +#include "lib/lock/ob_thread_cond.h" +#include "lib/profile/ob_trace_id.h" +#include "lib/queue/ob_lighty_queue.h" +#include "share/ob_thread_pool.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTask; + +class ObITableLoadTaskScheduler +{ +public: + ObITableLoadTaskScheduler() = default; + virtual ~ObITableLoadTaskScheduler() = default; + virtual int init() = 0; + virtual int start() = 0; + virtual void stop() = 0; + virtual void wait() = 0; + virtual int add_task(int64_t thread_idx, ObTableLoadTask *task) = 0; + virtual int64_t get_thread_count() const = 0; +private: + DISALLOW_COPY_AND_ASSIGN(ObITableLoadTaskScheduler); +}; + +class ObTableLoadTaskThreadPoolScheduler final : public ObITableLoadTaskScheduler +{ + static const int64_t DEFAULT_TIMEOUT_US = 10LL * 1000 * 1000; // 10s + // 运行状态 + static const int STATE_ZERO = 0; + static const int STATE_STARTING = 1; + static const int STATE_RUNNING = 2; + static const int STATE_STOPPING = 3; + static const int STATE_STOPPED = 4; + static const int STATE_STOPPED_NO_WAIT = 5; +public: + ObTableLoadTaskThreadPoolScheduler(int64_t thread_count, common::ObIAllocator &allocator, + int64_t session_queue_size = 64); + virtual ~ObTableLoadTaskThreadPoolScheduler(); + int init() override; + int start() override; + void stop() override; + void wait() override; + int add_task(int64_t thread_idx, ObTableLoadTask *task) override; + int64_t get_thread_count() const override { return thread_count_; } +private: + void run(uint64_t thread_idx); + int init_worker_ctx_array(); + OB_INLINE bool is_running() const + { + return state_ == STATE_RUNNING; + } + // 启动成功才会调用 + void before_running(); + // 启动失败也可能调用 + void after_running(); + void clear_all_task(); +private: + class MyThreadPool : public share::ObThreadPool + { + public: + MyThreadPool(ObTableLoadTaskThreadPoolScheduler *scheduler) + : scheduler_(scheduler), running_thread_count_(0) {} + virtual ~MyThreadPool() = default; + void run1() override; + private: + ObTableLoadTaskThreadPoolScheduler * const scheduler_; + int64_t running_thread_count_ CACHE_ALIGNED; + }; + struct WorkerContext + { + WorkerContext() : need_signal_(false) {} + int64_t worker_id_; + common::ObThreadCond cond_; + bool need_signal_; + common::LightyQueue task_queue_; // 多线程安全 + }; + int execute_worker_tasks(WorkerContext &worker_ctx); +private: + common::ObIAllocator &allocator_; + const int64_t thread_count_; + const int64_t session_queue_size_; + common::ObCurTraceId::TraceId trace_id_; + int64_t timeout_ts_; + MyThreadPool thread_pool_; + WorkerContext *worker_ctx_array_; + volatile int state_; + bool is_inited_; + lib::ObMutex state_mutex_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_time_convert.cpp b/src/observer/table_load/ob_table_load_time_convert.cpp new file mode 100644 index 0000000000..83ffb1f2a9 --- /dev/null +++ b/src/observer/table_load/ob_table_load_time_convert.cpp @@ -0,0 +1,105 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_time_convert.h" +#include "sql/engine/cmd/ob_load_data_utils.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace sql; + +ObTableLoadTimeConverter::ObTableLoadTimeConverter() + : is_inited_(false) +{ +} + +ObTableLoadTimeConverter::~ObTableLoadTimeConverter() +{ +} + +int ObTableLoadTimeConverter::init(const ObString &format) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("init twice", KR(ret)); + } else { + ObTime ob_time; + ob_time.mode_ |= DT_TYPE_DATETIME; + if (ob_is_otimestamp_type(ObDateTimeType)) { + ob_time.mode_ |= DT_TYPE_ORACLE; + } + if (ob_is_timestamp_tz(ObDateTimeType)) { + ob_time.mode_ |= DT_TYPE_TIMEZONE; + } + if (OB_FAIL(ObDFMUtil::parse_datetime_format_string(format, dfm_elems_))) { + LOG_WARN("fail to parse oracle datetime format string", KR(ret), K(format)); + } else if (OB_FAIL(ObDFMUtil::check_semantic(dfm_elems_, elem_flags_, ob_time.mode_))) { + LOG_WARN("check semantic of format string failed", KR(ret), K(format)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadTimeConverter::str_to_datetime_oracle(const ObString &str, + const ObTimeConvertCtx &cvrt_ctx, + ObDateTime &value) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTimeConverter not init", KR(ret)); + } else { + ObTime ob_time; + ObDateTime result_value = 0; + ObScale scale = 0; // not used + if (OB_FAIL(str_to_ob_time(str, cvrt_ctx, ObDateTimeType, ob_time, scale))) { + LOG_WARN("failed to convert str to ob_time", K(str), K(cvrt_ctx.oracle_nls_format_)); + } else if (OB_FAIL(ObTimeConverter::ob_time_to_datetime(ob_time, cvrt_ctx, result_value))) { + LOG_WARN("convert ob_time to datetime failed", K(ret), K(ob_time)); + } else { + value = result_value; + } + } + return ret; +} + +int ObTableLoadTimeConverter::str_to_ob_time(const ObString &str, const ObTimeConvertCtx &cvrt_ctx, + const ObObjType target_type, ObTime &ob_time, + ObScale &scale) const +{ + int ret = OB_SUCCESS; + const ObString &format = cvrt_ctx.oracle_nls_format_; + + if (OB_UNLIKELY(str.empty() || format.empty() || + (!ob_is_otimestamp_type(target_type) && !ob_is_datetime_tc(target_type)))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(str), K(format), K(ob_time.mode_)); + } else { + ob_time.mode_ |= DT_TYPE_DATETIME; + if (ob_is_otimestamp_type(target_type)) { + ob_time.mode_ |= DT_TYPE_ORACLE; + } + if (ob_is_timestamp_tz(target_type)) { + ob_time.mode_ |= DT_TYPE_TIMEZONE; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ObTimeConverter::str_to_ob_time_by_dfm_elems(str, dfm_elems_, elem_flags_, cvrt_ctx, + target_type, ob_time, scale))) { + LOG_WARN("fail to str to ob time by dfm elements", KR(ret)); + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_time_convert.h b/src/observer/table_load/ob_table_load_time_convert.h new file mode 100644 index 0000000000..dd5ce6c24f --- /dev/null +++ b/src/observer/table_load/ob_table_load_time_convert.h @@ -0,0 +1,39 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// xiaotao.ht + +#pragma once + +#include "common/object/ob_object.h" +#include "lib/container/ob_se_array.h" +#include "lib/ob_define.h" +#include "lib/timezone/ob_oracle_format_models.h" +#include "lib/timezone/ob_time_convert.h" +#include "share/object/ob_obj_cast.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTimeConverter +{ +public: + ObTableLoadTimeConverter(); + ~ObTableLoadTimeConverter(); + int init(const ObString &format); + int str_to_datetime_oracle(const common::ObString &str, const common::ObTimeConvertCtx &cvrt_ctx, + common::ObDateTime &value) const; + +private: + int str_to_ob_time(const common::ObString &str, const common::ObTimeConvertCtx &cvrt_ctx, + const common::ObObjType target_type, common::ObTime &ob_time, + common::ObScale &scale) const; + +private: + common::ObSEArray dfm_elems_; + common::ObFixedBitSet elem_flags_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/observer/table_load/ob_table_load_trans_bucket_writer.cpp b/src/observer/table_load/ob_table_load_trans_bucket_writer.cpp new file mode 100644 index 0000000000..e41a203dfe --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_bucket_writer.cpp @@ -0,0 +1,339 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_trans_bucket_writer.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_coordinator_ctx.h" +#include "observer/table_load/ob_table_load_partition_calc.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_trans_ctx.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace common::hash; +using namespace share::schema; +using namespace sql; +using namespace table; + +ObTableLoadTransBucketWriter::SessionContext::SessionContext() + : session_id_(0), allocator_("TLD_TB_SessCtx"), last_receive_sequence_no_(0) +{ +} + +ObTableLoadTransBucketWriter::SessionContext::~SessionContext() +{ + reset(); +} + +void ObTableLoadTransBucketWriter::SessionContext::reset() +{ + for (int64_t i = 0; i < load_bucket_array_.count(); ++i) { + ObTableLoadBucket *load_bucket = load_bucket_array_.at(i); + load_bucket->~ObTableLoadBucket(); + allocator_.free(load_bucket); + } + load_bucket_array_.reset(); + load_bucket_map_.reuse(); +} + +ObTableLoadTransBucketWriter::ObTableLoadTransBucketWriter(ObTableLoadTransCtx *trans_ctx) + : trans_ctx_(trans_ctx), + coordinator_ctx_(trans_ctx_->ctx_->coordinator_ctx_), + param_(trans_ctx_->ctx_->param_), + allocator_("TLD_TBWriter", OB_MALLOC_NORMAL_BLOCK_SIZE, param_.tenant_id_), + is_partitioned_(false), + session_ctx_array_(nullptr), + ref_count_(0), + is_flush_(false), + is_inited_(false) +{ +} + +ObTableLoadTransBucketWriter::~ObTableLoadTransBucketWriter() +{ + if (nullptr != session_ctx_array_) { + for (int64_t i = 0; i < param_.session_count_; i++) { + SessionContext *session_ctx = session_ctx_array_ + i; + session_ctx->~SessionContext(); + } + allocator_.free(session_ctx_array_); + session_ctx_array_ = nullptr; + } +} + +int ObTableLoadTransBucketWriter::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadTransBucketWriter init twice", KR(ret), KP(this)); + } else if (OB_ISNULL(coordinator_ctx_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null coordinator ctx", KR(ret)); + } else { + is_partitioned_ = coordinator_ctx_->ctx_->schema_.is_partitioned_table_; + if (OB_FAIL(init_session_ctx_array())) { + LOG_WARN("fail to init session ctx array", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::init_session_ctx_array() +{ + int ret = OB_SUCCESS; + void *buf = nullptr; + if (OB_ISNULL(buf = allocator_.alloc(sizeof(SessionContext) * param_.session_count_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else { + session_ctx_array_ = new (buf) SessionContext[param_.session_count_]; + for (int64_t i = 0; OB_SUCC(ret) && i < param_.session_count_; ++i) { + SessionContext *session_ctx = session_ctx_array_ + i; + session_ctx->session_id_ = i + 1; + session_ctx->allocator_.set_tenant_id(param_.tenant_id_); + if (!is_partitioned_) { + ObTableLoadPartitionLocation::PartitionLocationInfo info; + if (OB_UNLIKELY(1 != coordinator_ctx_->ctx_->schema_.partition_ids_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected partition id num in non partitioned table", KR(ret), "count", + coordinator_ctx_->ctx_->schema_.partition_ids_.count()); + } else if (FALSE_IT(session_ctx->partition_id_ = + coordinator_ctx_->ctx_->schema_.partition_ids_[0])) { + } else if (OB_FAIL(coordinator_ctx_->partition_location_.get_leader( + session_ctx->partition_id_.tablet_id_, info))) { + LOG_WARN("failed to get leader addr", K(ret)); + } else if (OB_FAIL(session_ctx->load_bucket_.init(info.leader_addr_))) { + LOG_WARN("fail to init bucket", KR(ret)); + } + } else { + if (OB_FAIL(session_ctx->load_bucket_map_.create(1024, "TLD_BucketMap", "TLD_BucketMap", + param_.tenant_id_))) { + LOG_WARN("fail to init partition bucket map", KR(ret)); + } + } + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::advance_sequence_no(int32_t session_id, uint64_t sequence_no, + ObTableLoadMutexGuard &guard) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransBucketWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id), K(sequence_no)); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + if (OB_FAIL(guard.init(session_ctx.mutex_))) { + LOG_WARN("fail to init mutex guard", KR(ret)); + } else { + // if (OB_UNLIKELY(sequence_no != session_ctx.last_receive_sequence_no_ + 1)) { + // if (OB_UNLIKELY(sequence_no != session_ctx.last_receive_sequence_no_)) { + // ret = OB_INVALID_ARGUMENT; + // LOG_WARN("invalid sequence no", KR(ret), K(sequence_no), + // K(session_ctx.last_receive_sequence_no_)); + // } else { + // ret = OB_ENTRY_EXIST; + // } + //} else { + // session_ctx.last_receive_sequence_no_ = sequence_no; + //} + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::write(int32_t session_id, const ObTableLoadObjRowArray &obj_rows) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransBucketWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_ || obj_rows.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id), K(obj_rows.count())); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + if (!is_partitioned_) { + if (OB_FAIL(write_for_non_partitioned(session_ctx, obj_rows))) { + LOG_WARN("fail to write for non partitioned", KR(ret)); + } + } else { + if (OB_FAIL(write_for_partitioned(session_ctx, obj_rows))) { + LOG_WARN("fail to write for partitioned", KR(ret)); + } + } + + if (OB_SUCC(ret)) { + int64_t row_cnt = obj_rows.count(); + ATOMIC_AAF(&trans_ctx_->ctx_->job_stat_->coordinator.received_rows_, row_cnt); + ATOMIC_AAF(&trans_ctx_->ctx_->coordinator_ctx_->result_info_.records_, row_cnt); + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::write_for_non_partitioned(SessionContext &session_ctx, + const ObTableLoadObjRowArray &obj_rows) +{ + int ret = OB_SUCCESS; + const int64_t row_count = obj_rows.count(); + ObTableLoadBucket *load_bucket = &session_ctx.load_bucket_; + for (int64_t i = 0; OB_SUCC(ret) && i < row_count; ++i) { + bool need_write = false; + if (OB_FAIL(load_bucket->add_row(session_ctx.partition_id_.tablet_id_, + obj_rows.at(i), param_.column_count_, + param_.batch_size_, need_write))) { + LOG_WARN("fail to add row", KR(ret)); + } else if (need_write && OB_FAIL(write_load_bucket(session_ctx, load_bucket))) { + LOG_WARN("fail to write partition bucket", KR(ret)); + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::write_for_partitioned(SessionContext &session_ctx, + const ObTableLoadObjRowArray &obj_rows) +{ + int ret = OB_SUCCESS; + ObArenaAllocator allocator("TLD_Misc", OB_MALLOC_NORMAL_BLOCK_SIZE, param_.tenant_id_); + ObTableLoadPartitionCalcContext calc_ctx(obj_rows, param_.column_count_, allocator); + if (OB_FAIL(coordinator_ctx_->partition_calc_.calc(calc_ctx))) { + LOG_WARN("fail to calc partition", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < calc_ctx.partition_ids_.count(); ++i) { + const ObTableLoadPartitionId &partition_id = calc_ctx.partition_ids_.at(i); + ObTableLoadBucket *load_bucket = nullptr; + bool need_write = false; + if (OB_FAIL(get_load_bucket(session_ctx, partition_id, load_bucket))) { + LOG_WARN("fail to get partition bucket", KR(ret), K(session_ctx.session_id_), + K(partition_id)); + } else if (OB_FAIL(load_bucket->add_row( + partition_id.tablet_id_, obj_rows.at(i), + param_.column_count_, param_.batch_size_, need_write))) { + LOG_WARN("fail to add row", KR(ret)); + } else if (need_write && OB_FAIL(write_load_bucket(session_ctx, load_bucket))) { + LOG_WARN("fail to write partition bucket", KR(ret)); + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::flush(int32_t session_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransBucketWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id)); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + if (!is_partitioned_) { + ObTableLoadBucket *load_bucket = &session_ctx.load_bucket_; + if (!(load_bucket->row_array_.empty())) { + if (OB_FAIL(write_load_bucket(session_ctx, load_bucket))) { + LOG_WARN("fail to write partition bucket", KR(ret), KPC(load_bucket)); + } + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < session_ctx.load_bucket_array_.count(); ++i) { + ObTableLoadBucket *load_bucket = session_ctx.load_bucket_array_.at(i); + if (!(load_bucket->row_array_.empty())) { + if (OB_FAIL(write_load_bucket(session_ctx, load_bucket))) { + LOG_WARN("fail to write partition bucket", KR(ret), KPC(load_bucket)); + } + } + } + } + // release memory + session_ctx.reset(); + } + return ret; +} + +int ObTableLoadTransBucketWriter::get_load_bucket(SessionContext &session_ctx, + const ObTableLoadPartitionId &partition_id, + ObTableLoadBucket *&load_bucket) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(get_part_bucket_time_us); + int ret = OB_SUCCESS; + load_bucket = nullptr; + if (OB_UNLIKELY(!is_partitioned_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected non partitioned table", KR(ret)); + } else { + ObTableLoadPartitionLocation::PartitionLocationInfo info; + if (OB_FAIL(coordinator_ctx_->partition_location_.get_leader(partition_id.tablet_id_, info))) { + LOG_WARN("failed to get leader addr", K(ret)); + } + if (OB_SUCC(ret)) { + ret = session_ctx.load_bucket_map_.get_refactored(info.leader_addr_, load_bucket); + if (OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + if (OB_ISNULL(load_bucket = OB_NEWx(ObTableLoadBucket, (&session_ctx.allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to new partition bucket", KR(ret)); + } else if (OB_FAIL(load_bucket->init(info.leader_addr_))) { + LOG_WARN("fail to init", KR(ret)); + } else if (OB_FAIL(session_ctx.load_bucket_map_.set_refactored(info.leader_addr_, load_bucket))) { + LOG_WARN("fail to put bucket", KR(ret)); + } else if (OB_FAIL(session_ctx.load_bucket_array_.push_back(load_bucket))) { + LOG_WARN("fail to push back bucket", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != load_bucket) { + load_bucket->~ObTableLoadBucket(); + session_ctx.allocator_.free(load_bucket); + load_bucket = nullptr; + } + } + } else if (OB_FAIL(ret)) { + LOG_WARN("fail to get bucket", KR(ret), K(partition_id)); + } + } + } + return ret; +} + +int ObTableLoadTransBucketWriter::write_load_bucket(SessionContext &session_ctx, + ObTableLoadBucket *load_bucket) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(load_bucket)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(load_bucket)); + } else { + ObTableLoadCoordinator coordinator(coordinator_ctx_->ctx_); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.write_peer_leader( + trans_ctx_->trans_id_, session_ctx.session_id_, ++load_bucket->sequence_no_, + load_bucket->row_array_, load_bucket->leader_addr_))) { + LOG_WARN("fail to coordinator write peer leader", KR(ret), K(session_ctx.session_id_), + KPC(load_bucket)); + } + } + if (OB_SUCC(ret)) { + load_bucket->clear_data(); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_bucket_writer.h b/src/observer/table_load/ob_table_load_trans_bucket_writer.h new file mode 100644 index 0000000000..5315bbdab4 --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_bucket_writer.h @@ -0,0 +1,81 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/hash/ob_hashmap.h" +#include "lib/lock/ob_mutex.h" +#include "observer/table_load/ob_table_load_bucket.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadParam; +class ObTableLoadTransCtx; +class ObTableLoadCoordinatorCtx; + +class ObTableLoadTransBucketWriter +{ +public: + ObTableLoadTransBucketWriter(ObTableLoadTransCtx *trans_ctx); + ~ObTableLoadTransBucketWriter(); + int init(); + int advance_sequence_no(int32_t session_id, uint64_t sequence_no, ObTableLoadMutexGuard &guard); + // 只在对应工作线程中调用, 串行执行 + int write(int32_t session_id, const table::ObTableLoadObjRowArray &obj_rows); + int flush(int32_t session_id); +public: + void set_is_flush() { is_flush_ = true; } + bool is_flush() const { return is_flush_; } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } +private: + class SessionContext; + int init_session_ctx_array(); + // 非分区表 + int write_for_non_partitioned(SessionContext &session_ctx, + const table::ObTableLoadObjRowArray &obj_rows); + // 分区表 + int write_for_partitioned(SessionContext &session_ctx, + const table::ObTableLoadObjRowArray &obj_rows); + int get_load_bucket(SessionContext &session_ctx, const table::ObTableLoadPartitionId &partition_id, + ObTableLoadBucket *&load_bucket); + int write_load_bucket(SessionContext &session_ctx, ObTableLoadBucket *load_bucket); +private: + ObTableLoadTransCtx *const trans_ctx_; + ObTableLoadCoordinatorCtx *const coordinator_ctx_; + const ObTableLoadParam ¶m_; + common::ObArenaAllocator allocator_; + bool is_partitioned_; + struct SessionContext + { + SessionContext(); + ~SessionContext(); + void reset(); + int32_t session_id_; + // 以下参数只在对应工作线程中访问 + common::ObArenaAllocator allocator_; + // for non-partitioned table + table::ObTableLoadPartitionId partition_id_; + ObTableLoadBucket load_bucket_; + // for partitioned table + common::hash::ObHashMap load_bucket_map_; + common::ObSEArray load_bucket_array_; + // 以下参数加锁访问 + lib::ObMutex mutex_; + uint64_t last_receive_sequence_no_; + }; + SessionContext *session_ctx_array_; + int64_t ref_count_ CACHE_ALIGNED; + bool is_flush_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_ctx.cpp b/src/observer/table_load/ob_table_load_trans_ctx.cpp new file mode 100644 index 0000000000..5e52a57b2f --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_ctx.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_trans_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace common; +using namespace lib; +using namespace table; + +ObTableLoadTransCtx::ObTableLoadTransCtx(ObTableLoadTableCtx *ctx, + const ObTableLoadTransId &trans_id) + : ctx_(ctx), + trans_id_(trans_id), + allocator_("TLD_TCtx", OB_MALLOC_NORMAL_BLOCK_SIZE, ctx->param_.tenant_id_), + trans_status_(ObTableLoadTransStatusType::NONE), + error_code_(OB_SUCCESS) +{ +} + +int ObTableLoadTransCtx::advance_trans_status(ObTableLoadTransStatusType trans_status) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(ObTableLoadTransStatusType::ERROR == trans_status || + ObTableLoadTransStatusType::ABORT == trans_status)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(trans_status)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(ObTableLoadTransStatusType::ERROR == trans_status_)) { + ret = error_code_; + LOG_WARN("trans has error", KR(ret)); + } else if (OB_UNLIKELY(ObTableLoadTransStatusType::ABORT == trans_status_)) { + ret = OB_TRANS_KILLED; + LOG_WARN("trans is abort", KR(ret)); + } + // 正常运行阶段, 状态是一步步推进的 + else if (OB_UNLIKELY(static_cast(trans_status) != + static_cast(trans_status_) + 1)) { + ret = OB_STATE_NOT_MATCH; + LOG_WARN("unexpected trans status", KR(ret), K(trans_status), K(trans_status_)); + } else { + trans_status_ = trans_status; + } + } + return ret; +} + +int ObTableLoadTransCtx::set_trans_status_error(int error_code) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_SUCCESS == error_code)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(error_code)); + } else { + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(trans_status_ == ObTableLoadTransStatusType::ABORT)) { + ret = OB_TRANS_KILLED; + } else if (trans_status_ != ObTableLoadTransStatusType::ERROR) { + trans_status_ = ObTableLoadTransStatusType::ERROR; + error_code_ = error_code; + } + } + return ret; +} + +int ObTableLoadTransCtx::set_trans_status_abort() +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + trans_status_ = ObTableLoadTransStatusType::ABORT; + return ret; +} + +int ObTableLoadTransCtx::check_trans_status(ObTableLoadTransStatusType trans_status) const +{ + int ret = OB_SUCCESS; + ObMutexGuard guard(mutex_); + if (OB_UNLIKELY(trans_status != trans_status_)) { + if (ObTableLoadTransStatusType::ERROR == trans_status_) { + ret = error_code_; + } else if (ObTableLoadTransStatusType::ABORT == trans_status_) { + ret = OB_TRANS_KILLED; + } else { + ret = OB_STATE_NOT_MATCH; + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_ctx.h b/src/observer/table_load/ob_table_load_trans_ctx.h new file mode 100644 index 0000000000..72bfe2c03a --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_ctx.h @@ -0,0 +1,46 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/utility/ob_print_utils.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadTableCtx; + +struct ObTableLoadTransCtx +{ +public: + ObTableLoadTransCtx(ObTableLoadTableCtx *ctx, const table::ObTableLoadTransId &trans_id); + OB_INLINE table::ObTableLoadTransStatusType get_trans_status() const + { + lib::ObMutexGuard guard(mutex_); + return trans_status_; + } + OB_INLINE int get_error_code() const + { + lib::ObMutexGuard guard(mutex_); + return error_code_; + } + int advance_trans_status(table::ObTableLoadTransStatusType trans_status); + int set_trans_status_error(int error_code); + int set_trans_status_abort(); + int check_trans_status(table::ObTableLoadTransStatusType trans_status) const; + TO_STRING_KV(K_(trans_id), K_(trans_status), K_(error_code)); +public: + ObTableLoadTableCtx * const ctx_; + const table::ObTableLoadTransId trans_id_; + mutable lib::ObMutex mutex_; + common::ObArenaAllocator allocator_; + table::ObTableLoadTransStatusType trans_status_; + int error_code_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_processor.cpp b/src/observer/table_load/ob_table_load_trans_processor.cpp new file mode 100644 index 0000000000..664f729600 --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_processor.cpp @@ -0,0 +1,381 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_trans_processor.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_store.h" +#include "observer/table_load/ob_table_load_service.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace table; + +/** + * ObTableLoadStartTransP + */ + +int ObTableLoadStartTransP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.start_trans(arg_.segment_id_, result_.trans_id_))) { + LOG_WARN("fail to coordinator start trans", KR(ret)); + } else if (OB_FAIL(coordinator.get_trans_status(result_.trans_id_, result_.trans_status_, + result_.error_code_))) { + LOG_WARN("fail to coordinator get trans status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadStartTransP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadPreStartTransPeerP + */ + +int ObTableLoadPreStartTransPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_start_trans(arg_.trans_id_))) { + LOG_WARN("fail to store pre start trans", KR(ret), K(arg_.trans_id_)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadPreStartTransPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadConfirmStartTransPeerP + */ + +int ObTableLoadConfirmStartTransPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_start_trans(arg_.trans_id_))) { + LOG_WARN("fail to store confirm start trans", KR(ret), K(arg_.trans_id_)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadConfirmStartTransPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +////////////////////////////////////////////////////////////////////// + +/** + * ObTableLoadFinishTransP + */ + +int ObTableLoadFinishTransP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.finish_trans(arg_.trans_id_))) { + LOG_WARN("fail to coordinator finish trans", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadFinishTransP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadPreFinishTransPeerP + */ + +int ObTableLoadPreFinishTransPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.pre_finish_trans(arg_.trans_id_))) { + LOG_WARN("fail to store pre finish trans", KR(ret), K(arg_.trans_id_)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadPreFinishTransPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadConfirmFinishTransPeerP + */ + +int ObTableLoadConfirmFinishTransPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.confirm_finish_trans(arg_.trans_id_))) { + LOG_WARN("fail to store confirm finish trans", KR(ret), K(arg_.trans_id_)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadConfirmFinishTransPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +////////////////////////////////////////////////////////////////////// + +/** + * ObTableLoadAbandonTransP + */ + +int ObTableLoadAbandonTransP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.abandon_trans(arg_.trans_id_))) { + LOG_WARN("fail to coordinator abandon trans", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadAbandonTransP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +/** + * ObTableLoadAbandonTransPeerP + */ + +int ObTableLoadAbandonTransPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.abandon_trans(arg_.trans_id_))) { + LOG_WARN("fail to store abandon trans", KR(ret), K(arg_.trans_id_)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadAbandonTransPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +////////////////////////////////////////////////////////////////////// + +/** + * ObTableLoadGetTransStatusP + */ + +int ObTableLoadGetTransStatusP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadCoordinator coordinator(table_ctx); + if (OB_FAIL(coordinator.init())) { + LOG_WARN("fail to init coordinator", KR(ret)); + } else if (OB_FAIL(coordinator.get_trans_status(arg_.trans_id_, result_.trans_status_, + result_.error_code_))) { + LOG_WARN("fail to coordinator get trans status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadGetTransStatusP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + + +/** + * ObTableLoadGetTransStatusPeerP + */ + +int ObTableLoadGetTransStatusPeerP::process() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(check_user_access(arg_.credential_))) { + LOG_WARN("fail to check_user_access", KR(ret)); + } else { + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(credential_.tenant_id_, arg_.table_id_); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.get_trans_status(arg_.trans_id_, result_.trans_status_, + result_.error_code_))) { + LOG_WARN("fail to store get trans status", KR(ret)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + } + return ret; +} + +int ObTableLoadGetTransStatusPeerP::check_user_access(const ObString &credential_str) +{ + return ObTableLoadUtils::check_user_access(credential_str, gctx_, credential_); +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_processor.h b/src/observer/table_load/ob_table_load_trans_processor.h new file mode 100644 index 0000000000..1440c1aebc --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_processor.h @@ -0,0 +1,204 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table/ob_table_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_processor.h" +#include "rpc/obrpc/ob_rpc_proxy.h" +#include "share/table/ob_table_rpc_proxy.h" + +namespace oceanbase +{ +namespace observer +{ + +class ObTableLoadStartTransP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadStartTransP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadStartTransP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadStartTransP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadPreStartTransPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadPreStartTransPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadPreStartTransPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPreStartTransPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadConfirmStartTransPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadConfirmStartTransPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadConfirmStartTransPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadConfirmStartTransPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +//////////////////////////////////////////////////////////////// + +class ObTableLoadFinishTransP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadFinishTransP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadFinishTransP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadFinishTransP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadPreFinishTransPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadPreFinishTransPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadPreFinishTransPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadPreFinishTransPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadConfirmFinishTransPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadConfirmFinishTransPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadConfirmFinishTransPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadConfirmFinishTransPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +//////////////////////////////////////////////////////////////// + +class ObTableLoadAbandonTransP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadAbandonTransP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadAbandonTransP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadAbandonTransP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadAbandonTransPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadAbandonTransPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadAbandonTransPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadAbandonTransPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +//////////////////////////////////////////////////////////////// + +class ObTableLoadGetTransStatusP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadGetTransStatusP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadGetTransStatusP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadGetTransStatusP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +class ObTableLoadGetTransStatusPeerP : public obrpc::ObRpcProcessor > +{ +public: + explicit ObTableLoadGetTransStatusPeerP(const ObGlobalContext &gctx) : gctx_(gctx) {} + virtual ~ObTableLoadGetTransStatusPeerP() = default; + +protected: + int process() override; + +private: + int check_user_access(const ObString &credential_str); + + DISALLOW_COPY_AND_ASSIGN(ObTableLoadGetTransStatusPeerP); +private: + const ObGlobalContext &gctx_; + table::ObTableApiCredential credential_; +}; + +} // end namespace observer +} // end namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_store.cpp b/src/observer/table_load/ob_table_load_trans_store.cpp new file mode 100644 index 0000000000..2b7c096239 --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_store.cpp @@ -0,0 +1,489 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_trans_store.h" +#include "observer/omt/ob_tenant_timezone_mgr.h" +#include "observer/table/ob_table_service.h" +#include "observer/table_load/ob_table_load_autoinc_nextval.h" +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_trans_ctx.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "sql/engine/cmd/ob_load_data_utils.h" +#include "sql/resolver/expr/ob_raw_expr_util.h" +#include "share/ob_autoincrement_service.h" +#include "share/sequence/ob_sequence_cache.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace blocksstable; +using namespace common; +using namespace common::hash; +using namespace share::schema; +using namespace share; +using namespace sql; +using namespace storage; +using namespace table; + +/** + * ObTableLoadTransStore + */ + +int ObTableLoadTransStore::init() +{ + int ret = OB_SUCCESS; + const int32_t session_count = trans_ctx_->ctx_->param_.session_count_; + SessionStore *session_store = nullptr; + for (int32_t i = 0; OB_SUCC(ret) && i < session_count; ++i) { + if (OB_ISNULL(session_store = OB_NEWx(SessionStore, (&trans_ctx_->allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new SessionStore", KR(ret)); + } else { + session_store->session_id_ = i + 1; + session_store->allocator_.set_tenant_id(trans_ctx_->ctx_->param_.tenant_id_); + session_store->partition_table_array_.set_block_allocator( + ModulePageAllocator(session_store->allocator_)); + if (OB_FAIL(session_store_array_.push_back(session_store))) { + LOG_WARN("fail to push back session store", KR(ret)); + } + } + if (OB_FAIL(ret)) { + if (nullptr != session_store) { + session_store->~SessionStore(); + trans_ctx_->allocator_.free(session_store); + session_store = nullptr; + } + } + } + return ret; +} + +void ObTableLoadTransStore::reset() +{ + for (int64_t i = 0; i < session_store_array_.count(); ++i) { + SessionStore *session_store = session_store_array_.at(i); + // free partition tables + for (int64_t j = 0; j < session_store->partition_table_array_.count(); ++j) { + ObIDirectLoadPartitionTable *table = session_store->partition_table_array_.at(j); + table->~ObIDirectLoadPartitionTable(); + session_store->allocator_.free(table); + } + session_store->partition_table_array_.reset(); + // free session_store + session_store->~SessionStore(); + trans_ctx_->allocator_.free(session_store); + } + session_store_array_.reset(); +} + +/** + * ObTableLoadTransStoreWriter + */ + +ObTableLoadTransStoreWriter::SessionContext::SessionContext(int32_t session_id, uint64_t tenant_id, ObDataTypeCastParams cast_params) + : session_id_(session_id), + cast_allocator_("TLD_TS_Caster", OB_MALLOC_NORMAL_BLOCK_SIZE, tenant_id), + cast_params_(cast_params), + last_receive_sequence_no_(0), + extra_buf_(nullptr), + extra_buf_size_(0) +{ +} + +ObTableLoadTransStoreWriter::SessionContext::~SessionContext() +{ + datum_row_.reset(); +} + +ObTableLoadTransStoreWriter::ObTableLoadTransStoreWriter(ObTableLoadTransStore *trans_store) + : trans_store_(trans_store), + trans_ctx_(trans_store->trans_ctx_), + store_ctx_(trans_ctx_->ctx_->store_ctx_), + param_(trans_ctx_->ctx_->param_), + allocator_("TLD_TSWriter", OB_MALLOC_NORMAL_BLOCK_SIZE, param_.tenant_id_), + table_data_desc_(nullptr), + column_descs_(nullptr), + ref_count_(0), + is_flush_(false), + is_inited_(false) +{ +} + +ObTableLoadTransStoreWriter::~ObTableLoadTransStoreWriter() +{ + if (nullptr != session_ctx_array_) { + for (int64_t i = 0; i < param_.session_count_; ++i) { + SessionContext *session_ctx = session_ctx_array_ + i; + session_ctx->~SessionContext(); + } + allocator_.free(session_ctx_array_); + session_ctx_array_ = nullptr; + } +} + +int ObTableLoadTransStoreWriter::init() +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableLoadTransStoreWriter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(trans_store_->session_store_array_.count() != param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(trans_store_)); + } else if (OB_FAIL(OTTZ_MGR.get_tenant_tz(param_.tenant_id_, tz_info_.get_tz_map_wrap()))) { + LOG_WARN("fail to get tenant time zone", KR(ret), K(param_.tenant_id_)); + } else { + table_data_desc_ = &trans_ctx_->ctx_->store_ctx_->table_data_desc_; + collation_type_ = trans_ctx_->ctx_->schema_.collation_type_; + column_descs_ = &(trans_ctx_->ctx_->schema_.column_descs_); + if (OB_FAIL(init_session_ctx_array())) { + LOG_WARN("fail to init session ctx array", KR(ret)); + } else if (OB_FAIL(init_column_schemas())) { + LOG_WARN("fail to init column schemas", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::init_column_schemas() +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(ObTableLoadSchema::get_table_schema(param_.tenant_id_, param_.table_id_, schema_guard, + table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(param_)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < table_schema->get_column_count(); ++i) { + const ObColumnSchemaV2 *column_schema = + table_schema->get_column_schema(column_descs_->at(i).col_id_); + if (column_schema->is_hidden()) { + } else if (OB_FAIL(column_schemas_.push_back(column_schema))) { + LOG_WARN("failed to push back column schema", K(ret), K(i), KPC(column_schema)); + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::init_session_ctx_array() +{ + int ret = OB_SUCCESS; + void *buf = nullptr; + ObDataTypeCastParams cast_params(&tz_info_); + if (OB_ISNULL(buf = allocator_.alloc(sizeof(SessionContext) * param_.session_count_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else if (OB_FAIL(time_cvrt_.init(cast_params.get_nls_format(ObDateTimeType)))) { + LOG_WARN("fail to init time converter", KR(ret)); + } else { + session_ctx_array_ = static_cast(buf); + for (int64_t i = 0; i < param_.session_count_; ++i) { + new (session_ctx_array_ + i) + SessionContext(i + 1, param_.tenant_id_, cast_params); + } + } + ObDirectLoadTableStoreParam param; + param.table_data_desc_ = *table_data_desc_; + param.datum_utils_ = &(trans_ctx_->ctx_->schema_.datum_utils_); + param.col_descs_ = &(trans_ctx_->ctx_->schema_.column_descs_); + param.file_mgr_ = trans_ctx_->ctx_->store_ctx_->tmp_file_mgr_; + param.is_multiple_mode_ = trans_ctx_->ctx_->store_ctx_->is_multiple_mode_; + param.is_fast_heap_table_ = trans_ctx_->ctx_->store_ctx_->is_fast_heap_table_; + param.online_opt_stat_gather_ = trans_ctx_->ctx_->param_.online_opt_stat_gather_; + param.insert_table_ctx_ = trans_ctx_->ctx_->store_ctx_->insert_table_ctx_; + param.fast_heap_table_ctx_ = trans_ctx_->ctx_->store_ctx_->fast_heap_table_ctx_; + param.result_info_ = &(trans_ctx_->ctx_->store_ctx_->result_info_); + for (int64_t i = 0; OB_SUCC(ret) && i < param_.session_count_; ++i) { + SessionContext *session_ctx = session_ctx_array_ + i; + if (store_ctx_->is_multiple_mode_) { + session_ctx->extra_buf_size_ = store_ctx_->table_data_desc_.extra_buf_size_; + if (OB_ISNULL(session_ctx->extra_buf_ = + static_cast(allocator_.alloc(session_ctx->extra_buf_size_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + param.extra_buf_ = session_ctx->extra_buf_; + param.extra_buf_size_ = session_ctx->extra_buf_size_; + } + } + if (OB_FAIL(ret)) { + } + // init table_store_ + else if (OB_FAIL(session_ctx->table_store_.init(param))) { + LOG_WARN("fail to init table store", KR(ret)); + } + // init datum_row_ + else if (OB_FAIL(session_ctx->datum_row_.init(table_data_desc_->column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + session_ctx->datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + session_ctx->datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::advance_sequence_no(int32_t session_id, uint64_t sequence_no, + ObTableLoadMutexGuard &guard) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransStoreWriter not init", KR(ret)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id)); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + if (OB_UNLIKELY(sequence_no != session_ctx.last_receive_sequence_no_ + 1)) { + if (OB_UNLIKELY(sequence_no != session_ctx.last_receive_sequence_no_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid sequence no", KR(ret), K(sequence_no), + K(session_ctx.last_receive_sequence_no_)); + } else { + ret = OB_ENTRY_EXIST; + } + } else { + session_ctx.last_receive_sequence_no_ = sequence_no; + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::write(int32_t session_id, + const ObTableLoadTabletObjRowArray &row_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransStoreWriter not init", KR(ret)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_) || + row_array.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id), K(row_array.empty())); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + for (int64_t i = 0; OB_SUCC(ret) && i < row_array.count(); ++i) { + const ObTableLoadTabletObjRow &row = row_array.at(i); + ObNewRow new_row(row.obj_row_.cells_, row.obj_row_.count_); + if (OB_FAIL(cast_row(session_ctx.cast_allocator_, session_ctx.cast_params_, new_row, session_ctx.datum_row_, + session_id))) { + if (OB_UNLIKELY(OB_EAGAIN != ret)) { + LOG_WARN("fail to cast row", KR(ret), K(session_id), K(row.tablet_id_), K(i)); + } else { + ret = OB_SUCCESS; + } + } else if (OB_FAIL(write_row_to_table_store(session_ctx.table_store_, row.tablet_id_, session_ctx.datum_row_))) { + LOG_WARN("fail to write row", KR(ret), K(session_id), K(row.tablet_id_), K(i)); + } + } + if (OB_SUCC(ret)) { + ATOMIC_AAF(&trans_ctx_->ctx_->job_stat_->store.processed_rows_, row_array.count()); + } + session_ctx.cast_allocator_.reuse(); + } + return ret; +} + +int ObTableLoadTransStoreWriter::write(int32_t session_id, + const ObTabletID &tablet_id, const ObIArray &row_array) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransStoreWriter not init", KR(ret)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_) || + row_array.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id), K(row_array.empty())); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + for (int64_t i = 0; OB_SUCC(ret) && i < row_array.count(); ++i) { + const ObNewRow &row = row_array.at(i); + for (int64_t j = 0; OB_SUCC(ret) && (j < table_data_desc_->column_count_); ++j) { + const ObObj &obj = row.cells_[j]; + if (OB_FAIL(session_ctx.datum_row_.storage_datums_[j].from_obj_enhance(obj))) { + LOG_WARN("fail to from obj enhance", KR(ret), K(obj)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(write_row_to_table_store(session_ctx.table_store_, tablet_id, session_ctx.datum_row_))) { + LOG_WARN("fail to write row", KR(ret), K(session_id), K(tablet_id)); + } + } + } + if (OB_SUCC(ret)) { + ATOMIC_AAF(&trans_ctx_->ctx_->job_stat_->store.processed_rows_, row_array.count()); + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::flush(int32_t session_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransStoreWriter not init", KR(ret)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id)); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + ObTableLoadTransStore::SessionStore *session_store = + trans_store_->session_store_array_.at(session_id - 1); + if (OB_FAIL(session_ctx.table_store_.close())) { + LOG_WARN("fail to close table store", KR(ret), K(session_id)); + } else if (OB_FAIL(session_ctx.table_store_.get_tables(session_store->partition_table_array_, + session_store->allocator_))) { + LOG_WARN("fail to get tables", KR(ret)); + } else { + session_ctx.table_store_.clean_up(); + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::clean_up(int32_t session_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableLoadTransStoreWriter not init", KR(ret)); + } else if (OB_UNLIKELY(session_id < 1 || session_id > param_.session_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(session_id)); + } else { + SessionContext &session_ctx = session_ctx_array_[session_id - 1]; + session_ctx.table_store_.clean_up(); + } + return ret; +} + +int ObTableLoadTransStoreWriter::cast_row(ObArenaAllocator &cast_allocator, + ObDataTypeCastParams cast_params, const ObNewRow &row, + ObDatumRow &datum_row, int32_t session_id) +{ + int ret = OB_SUCCESS; + ObObj out_obj; + for (int64_t i = 0; OB_SUCC(ret) && i < table_data_desc_->column_count_; ++i) { + out_obj.set_null(); + const ObColumnSchemaV2 *column_schema = column_schemas_.at(i); + ObCastCtx cast_ctx(&cast_allocator, &cast_params, CM_NONE, column_schema->get_collation_type()); + ObTableLoadCastObjCtx cast_obj_ctx(&time_cvrt_, &cast_ctx, true); + if ((!row.cells_[i].is_null() || + (!column_schema->is_autoincrement() && !column_schema->is_identity_column())) && + OB_FAIL( + ObTableLoadObjCaster::cast_obj(cast_obj_ctx, column_schema, row.cells_[i], out_obj))) { + LOG_WARN("fail to cast obj and check", KR(ret), K(i), K(row.cells_[i])); + } else if (OB_FAIL(datum_row.storage_datums_[i].from_obj_enhance(out_obj))) { + LOG_WARN("fail to from obj enhance", KR(ret), K(out_obj)); + } else if (column_schema->is_autoincrement() && + OB_FAIL(handle_autoinc_column(column_schema, datum_row.storage_datums_[i], + column_schema->get_meta_type().get_type_class(), + session_id))) { + LOG_WARN("fail to handle autoinc column", KR(ret), K(i), K(datum_row.storage_datums_[i])); + } else if (column_schema->is_identity_column() && + OB_FAIL(handle_identity_column(column_schema, datum_row.storage_datums_[i]))) { + LOG_WARN("fail to handle identity column", KR(ret), K(i), K(datum_row.storage_datums_[i])); + } + } + if (OB_FAIL(ret)) { + int tmp_ret = OB_SUCCESS; + ObTableLoadErrorRowHandler *error_row_handler = + trans_ctx_->ctx_->store_ctx_->error_row_handler_; + if (OB_TMP_FAIL(error_row_handler->append_error_row(row))) { + LOG_WARN("failed to append error row", K(ret), K(row)); + } else { + ret = OB_EAGAIN; + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::handle_autoinc_column(const ObColumnSchemaV2 *column_schema, + ObStorageDatum &datum, + const ObObjTypeClass &tc, int32_t session_id) +{ + int ret = OB_SUCCESS; + const int64_t save_timeout_ts = THIS_WORKER.get_timeout_ts(); + THIS_WORKER.set_timeout_ts(ObTimeUtility::current_time() + + max(GCONF.rpc_timeout, RPC_TIMEOUT_US)); + if (OB_FAIL(ObTableLoadAutoincNextval::eval_nextval( + &(store_ctx_->session_ctx_array_[session_id - 1].autoinc_param_), datum, tc, + param_.sql_mode_))) { + LOG_WARN("fail to get auto increment next value", KR(ret)); + } + THIS_WORKER.set_timeout_ts(save_timeout_ts); + return ret; +} + +int ObTableLoadTransStoreWriter::handle_identity_column(const ObColumnSchemaV2 *column_schema, + ObStorageDatum &datum) +{ + int ret = OB_SUCCESS; + if (column_schema->is_always_identity_column()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("direct-load does not support always identity column", KR(ret)); + } else if (column_schema->is_default_identity_column() && datum.is_null()) { + ret = OB_ERR_INVALID_NOT_NULL_CONSTRAINT_ON_IDENTITY_COLUMN; + LOG_WARN("default identity column has null value", KR(ret)); + } else if (column_schema->is_default_on_null_identity_column()) { + if (OB_FAIL(share::ObSequenceCache::get_instance().nextval( + trans_ctx_->ctx_->store_ctx_->sequence_schema_, allocator_, seq_value_))) { + LOG_WARN("fail get nextval for seq", KR(ret)); + } else if (datum.is_null()) { + datum.set_number(seq_value_.val()); + } + } + return ret; +} + +int ObTableLoadTransStoreWriter::write_row_to_table_store(ObDirectLoadTableStore &table_store, + const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(table_store.append_row(tablet_id, datum_row))) { + LOG_WARN("fail to append row", KR(ret), K(datum_row)); + } + if (OB_FAIL(ret)) { + ObTableLoadErrorRowHandler *error_row_handler = trans_ctx_->ctx_->store_ctx_->error_row_handler_; + if (OB_LIKELY(OB_ERR_PRIMARY_KEY_DUPLICATE == ret)) { + int tmp_ret = OB_SUCCESS; + if (trans_ctx_->ctx_->param_.dup_action_ == ObLoadDupActionType::LOAD_REPLACE) { + ATOMIC_AAF(&trans_ctx_->ctx_->store_ctx_->result_info_.rows_affected_, 2); + ATOMIC_INC(&trans_ctx_->ctx_->store_ctx_->result_info_.deleted_); + } else if (trans_ctx_->ctx_->param_.dup_action_ == ObLoadDupActionType::LOAD_IGNORE) { + ATOMIC_INC(&trans_ctx_->ctx_->store_ctx_->result_info_.skipped_); + } else if (trans_ctx_->ctx_->param_.dup_action_ == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + if (OB_TMP_FAIL(error_row_handler->append_error_row(datum_row))) { + LOG_WARN("failed to append repeated row", K(ret), K(tablet_id), K(datum_row)); + } + } + if (OB_LIKELY(OB_SUCCESS == tmp_ret)) { + ret = OB_SUCCESS; + } + } else if (OB_LIKELY(OB_ROWKEY_ORDER_ERROR == ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(error_row_handler->append_error_row(datum_row))) { + LOG_WARN("failed to append error row", K(ret), K(tablet_id), K(datum_row)); + } else { + ret = OB_SUCCESS; + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_trans_store.h b/src/observer/table_load/ob_table_load_trans_store.h new file mode 100644 index 0000000000..e13a1fffd2 --- /dev/null +++ b/src/observer/table_load/ob_table_load_trans_store.h @@ -0,0 +1,122 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/object/ob_object.h" +#include "lib/allocator/page_arena.h" +#include "observer/table_load/ob_table_load_obj_cast.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "observer/table_load/ob_table_load_time_convert.h" +#include "share/ob_autoincrement_param.h" +#include "share/object/ob_obj_cast.h" +#include "share/schema/ob_column_schema.h" +#include "share/table/ob_table_load_row_array.h" +#include "storage/blocksstable/ob_datum_row.h" +#include "storage/direct_load/ob_direct_load_table_store.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +} // namespace storage +namespace observer +{ +class ObTableLoadParam; +class ObTableLoadTransCtx; +class ObTableLoadStoreCtx; + +class ObTableLoadTransStore +{ +public: + ObTableLoadTransStore(ObTableLoadTransCtx *trans_ctx) : trans_ctx_(trans_ctx) {} + ~ObTableLoadTransStore() { reset(); } + int init(); + void reset(); + TO_STRING_KV(KP_(trans_ctx), K_(session_store_array)); + struct SessionStore + { + SessionStore() : session_id_(0), allocator_("TLD_SessStore") {} + int32_t session_id_; + common::ObArenaAllocator allocator_; + common::ObArray partition_table_array_; + TO_STRING_KV(K_(session_id), K_(partition_table_array)); + }; + ObTableLoadTransCtx *const trans_ctx_; + common::ObSEArray session_store_array_; +}; + +class ObTableLoadTransStoreWriter +{ + static const int64_t RPC_TIMEOUT_US = 20LL * 1000 * 1000; // 20s +public: + ObTableLoadTransStoreWriter(ObTableLoadTransStore *trans_store); + ~ObTableLoadTransStoreWriter(); + int init(); + int advance_sequence_no(int32_t session_id, uint64_t sequence_no, ObTableLoadMutexGuard &guard); + TO_STRING_KV(KP_(trans_ctx)); +public: + // 只在对应工作线程中调用, 串行执行 + int write(int32_t session_id, const table::ObTableLoadTabletObjRowArray &row_array); + int write(int32_t session_id, const ObTabletID &tablet_id, + const common::ObIArray &row_array); + int flush(int32_t session_id); + int clean_up(int32_t session_id); +public: + void set_is_flush() { is_flush_ = true; } + bool is_flush() const { return is_flush_; } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } +private: + class SessionContext; + int init_session_ctx_array(); + int init_column_schemas(); + int cast_row(common::ObArenaAllocator &cast_allocator, ObDataTypeCastParams cast_params, + const common::ObNewRow &row, blocksstable::ObDatumRow &datum_row, + int32_t session_id); + int handle_autoinc_column(const share::schema::ObColumnSchemaV2 *column_schema, + blocksstable::ObStorageDatum &datum, + const ObObjTypeClass &tc, + int32_t session_id); + int handle_identity_column(const share::schema::ObColumnSchemaV2 *column_schema, + blocksstable::ObStorageDatum &datum); + int write_row_to_table_store(storage::ObDirectLoadTableStore &table_store, + const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row); +private: + ObTableLoadTransStore *const trans_store_; + ObTableLoadTransCtx *const trans_ctx_; + ObTableLoadStoreCtx *const store_ctx_; + const ObTableLoadParam ¶m_; + common::ObArenaAllocator allocator_; + storage::ObDirectLoadTableDataDesc *table_data_desc_; + common::ObCollationType collation_type_; + common::ObTimeZoneInfo tz_info_; + ObTableLoadTimeConverter time_cvrt_; + const common::ObIArray *column_descs_; + common::ObArray column_schemas_; + struct SessionContext + { + SessionContext(int32_t session_id, uint64_t tenant_id, ObDataTypeCastParams cast_params); + ~SessionContext(); + const int32_t session_id_; + blocksstable::ObDatumRow datum_row_; + common::ObArenaAllocator cast_allocator_; + ObDataTypeCastParams cast_params_; + storage::ObDirectLoadTableStore table_store_; + uint64_t last_receive_sequence_no_; + char *extra_buf_; + int64_t extra_buf_size_; + }; + SessionContext *session_ctx_array_; + int64_t ref_count_ CACHE_ALIGNED; + bool is_flush_; + share::ObSequenceValue seq_value_; + bool is_inited_; +}; + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_utils.cpp b/src/observer/table_load/ob_table_load_utils.cpp new file mode 100644 index 0000000000..ebb20f8999 --- /dev/null +++ b/src/observer/table_load/ob_table_load_utils.cpp @@ -0,0 +1,208 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SERVER + +#include "observer/table_load/ob_table_load_utils.h" +#include "common/object/ob_object.h" +#include "observer/ob_server.h" +#include "observer/table/ob_table_rpc_processor.h" +#include "storage/blocksstable/ob_datum_row.h" +#include "storage/blocksstable/ob_datum_range.h" + +namespace oceanbase +{ +namespace observer +{ +using namespace blocksstable; +using namespace common; +using namespace table; +using namespace observer; + +int ObTableLoadUtils::check_user_access(const common::ObString &credential_str, + const observer::ObGlobalContext &gctx, + table::ObTableApiCredential &credential) +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + if (OB_FAIL(serialization::decode(credential_str.ptr(), credential_str.length(), pos, credential))) { + LOG_WARN("failed to serialize credential", K(ret), K(pos)); + } + //暂时不检查用户,后续加上 + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObString &src, ObString &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ob_write_string(allocator, src, dest))) { + LOG_WARN("fail to deep copy str", KR(ret)); + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObObj &src, ObObj &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (!src.need_deep_copy()) { + dest = src; + } else { + const int64_t size = src.get_deep_copy_size(); + char *buf = nullptr; + int64_t pos = 0; + if (OB_ISNULL(buf = static_cast(allocator.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else { + if (OB_FAIL(dest.deep_copy(src, buf, size, pos))) { + LOG_WARN("fail to deep copy obj", KR(ret), K(src)); + } + if (OB_FAIL(ret)) { + allocator.free(buf); + } + } + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObNewRow &src, ObNewRow &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + const int64_t size = src.get_deep_copy_size(); + char *buf = nullptr; + int64_t pos = 0; + + if (OB_ISNULL(buf = static_cast(allocator.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else { + if (OB_FAIL(dest.deep_copy(src, buf, size, pos))) { + LOG_WARN("fail to deep copy obj", K(ret), K(src)); + } + if (OB_FAIL(ret)) { + allocator.free(buf); + } + } + + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObStoreRowkey &src, ObStoreRowkey &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(src.deep_copy(dest, allocator))) { + LOG_WARN("fail to deep copy store rowkey", KR(ret), K(src)); + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObStoreRange &src, ObStoreRange &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(src.deep_copy(allocator, dest))) { + LOG_WARN("fail to deep copy store range", KR(ret), K(src)); + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObDatumRow &src, ObDatumRow &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(dest.deep_copy(src, allocator))) { + LOG_WARN("fail to deep copy datum row", K(ret), K(src)); + } + + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObStorageDatum &src, ObStorageDatum &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(dest.deep_copy(src, allocator))) { + LOG_WARN("fail to deep copy datum", KR(ret), K(src)); + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObDatumRowkey &src, ObDatumRowkey &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(src.deep_copy(dest, allocator))) { + LOG_WARN("fail to deep copy datum rowkey", KR(ret), K(src)); + } else if (OB_FAIL(deep_copy(src.store_rowkey_, dest.store_rowkey_, allocator))) { + LOG_WARN("fail to deep copy store rowkey", KR(ret), K(src)); + } + return ret; +} + +int ObTableLoadUtils::deep_copy(const ObDatumRange &src, ObDatumRange &dest, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(deep_copy(src.start_key_, dest.start_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret), K(src)); + } else if (OB_FAIL(deep_copy(src.end_key_, dest.end_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret), K(src)); + } else { + dest.group_idx_ = src.group_idx_; + dest.border_flag_ = src.border_flag_; + } + return ret; +} + +bool ObTableLoadUtils::is_local_addr(const ObAddr &addr) +{ + return (ObServer::get_instance().get_self() == addr); +} + +int ObTableLoadUtils::generate_credential(uint64_t tenant_id, uint64_t user_id, + uint64_t database_id, int64_t expire_ts, + uint64_t user_token, ObIAllocator &allocator, + ObString &credential_str) +{ + int ret = OB_SUCCESS; + table::ObTableApiCredential credential; + credential.cluster_id_ = GCONF.cluster_id; + credential.tenant_id_ = tenant_id; + credential.user_id_ = user_id; + credential.database_id_ = database_id; + credential.expire_ts_ = expire_ts; + credential.hash_val_ = credential.hash(user_token); + char *credential_buf = nullptr; + int64_t pos = 0; + if (OB_ISNULL(credential_buf = static_cast(allocator.alloc(CREDENTIAL_BUF_SIZE)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else if (OB_FAIL(serialization::encode(credential_buf, CREDENTIAL_BUF_SIZE, pos, credential))) { + LOG_WARN("failed to serialize credential", KR(ret), K(pos)); + } else { + credential_str.assign_ptr(credential_buf, static_cast(pos)); + } + return ret; +} + +int ObTableLoadUtils::generate_credential(uint64_t tenant_id, uint64_t user_id, + uint64_t database_id, int64_t expire_ts, + uint64_t user_token, char *buf, int64_t size, + ObString &credential_str) +{ + int ret = OB_SUCCESS; + table::ObTableApiCredential credential; + credential.cluster_id_ = GCONF.cluster_id; + credential.tenant_id_ = tenant_id; + credential.user_id_ = user_id; + credential.database_id_ = database_id; + credential.expire_ts_ = expire_ts; + credential.hash_val_ = credential.hash(user_token); + int64_t pos = 0; + if (OB_FAIL(serialization::encode(buf, size, pos, credential))) { + LOG_WARN("failed to serialize credential", KR(ret), K(pos)); + } else { + credential_str.assign_ptr(buf, static_cast(pos)); + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/table_load/ob_table_load_utils.h b/src/observer/table_load/ob_table_load_utils.h new file mode 100644 index 0000000000..cd2860572b --- /dev/null +++ b/src/observer/table_load/ob_table_load_utils.h @@ -0,0 +1,143 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_iarray.h" +#include "share/table/ob_table_load_array.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatum; +class ObDatumRange; +class ObDatumRowkey; +class ObDatumRow; +} // namespace blocksstable +namespace common +{ +class ObAddr; +class ObString; +class ObObj; +class ObStoreRowkey; +class ObStoreRange; +class ObNewRow; +} // namespace common +namespace table +{ + class ObTableApiCredential; +} +namespace observer +{ +class ObGlobalContext; + +class ObTableLoadUtils +{ +public: + template + static int deep_copy(const T &src, T &dest, common::ObIAllocator &allocator); + static int deep_copy(const common::ObString &src, common::ObString &dest, common::ObIAllocator &allocator); + static int deep_copy(const common::ObObj &src, common::ObObj &dest, common::ObIAllocator &allocator); + static int deep_copy(const common::ObNewRow &src, common::ObNewRow &dest, common::ObIAllocator &allocator); + static int deep_copy(const common::ObStoreRowkey &src, common::ObStoreRowkey &dest, common::ObIAllocator &allocator); + static int deep_copy(const common::ObStoreRange &src, common::ObStoreRange &dest, common::ObIAllocator &allocator); + static int deep_copy(const blocksstable::ObDatumRow &src, blocksstable::ObDatumRow &dest, common::ObIAllocator &allocator); + static int deep_copy(const blocksstable::ObStorageDatum &src, blocksstable::ObStorageDatum &dest, common::ObIAllocator &allocator); + static int deep_copy(const blocksstable::ObDatumRowkey &src, blocksstable::ObDatumRowkey &dest, common::ObIAllocator &allocator); + static int deep_copy(const blocksstable::ObDatumRange &src, blocksstable::ObDatumRange &dest, common::ObIAllocator &allocator); + + template + static int deep_copy(const table::ObTableLoadArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator); + + template + static int deep_copy_transform(const table::ObTableLoadArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator, const common::ObIArray &idx_array); + + template + static int deep_copy(const common::ObIArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator); + + static bool is_local_addr(const common::ObAddr &addr); + + static const int64_t CREDENTIAL_BUF_SIZE = 256; + static int generate_credential(uint64_t tenant_id, uint64_t user_id, uint64_t database_id, + int64_t expire_ts, uint64_t user_token, + common::ObIAllocator &allocator, common::ObString &credential_str); + static int generate_credential(uint64_t tenant_id, uint64_t user_id, uint64_t database_id, + int64_t expire_ts, uint64_t user_token, char *buf, int64_t size, + common::ObString &credential_str); + static int check_user_access(const common::ObString &credential_str, const observer::ObGlobalContext &gctx, table::ObTableApiCredential &credential); +}; + +template +int ObTableLoadUtils::deep_copy(const T &src, T &dest, common::ObIAllocator &allocator) +{ + dest = src; + return common::OB_SUCCESS; +} + +template +int ObTableLoadUtils::deep_copy(const table::ObTableLoadArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator) +{ + int ret = common::OB_SUCCESS; + dest.reset(); + if (!src.empty()) { + if (OB_FAIL(dest.create(src.count(), allocator))) { + OB_LOG(WARN, "fail to create", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < src.count(); ++i) { + if (OB_FAIL(deep_copy(src[i], dest[i], allocator))) { + OB_LOG(WARN, "fail to deep copy", KR(ret)); + } + } + } + return ret; +} + +template +int ObTableLoadUtils::deep_copy_transform(const table::ObTableLoadArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator, const common::ObIArray &idx_array) +{ + int ret = common::OB_SUCCESS; + dest.reset(); + if (!src.empty()) { + int64_t col_count = idx_array.count(); + int64_t row_count = src.count() / col_count; + if (OB_FAIL(dest.create(src.count(), allocator))) { + OB_LOG(WARN, "fail to create", KR(ret)); + } else { + const T* src_row = &src[0]; + T* dest_row = &dest[0]; + for (int64_t i = 0; OB_SUCC(ret) && (i < row_count); ++i) { + for (int64_t j = 0; OB_SUCC(ret) && (j < col_count); ++j) { + if (OB_FAIL(deep_copy(src_row[idx_array.at(j)], dest_row[j], allocator))) { + OB_LOG(WARN, "fail to deep copy", KR(ret), K(row_count), K(col_count), K(i), K(j)); + } + } + src_row += col_count; + dest_row += col_count; + } + } + } + return ret; +} + +template +int ObTableLoadUtils::deep_copy(const common::ObIArray &src, table::ObTableLoadArray &dest, common::ObIAllocator &allocator) +{ + int ret = common::OB_SUCCESS; + dest.reset(); + if (!src.empty()) { + if (OB_FAIL(dest.create(src.count(), allocator))) { + OB_LOG(WARN, "fail to create", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < src.count(); ++i) { + if (OB_FAIL(deep_copy(src.at(i), dest[i], allocator))) { + OB_LOG(WARN, "fail to deep copy", KR(ret)); + } + } + } + return ret; +} + +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/virtual_table/ob_all_virtual_load_data_stat.cpp b/src/observer/virtual_table/ob_all_virtual_load_data_stat.cpp index 2e2c8c707a..fbbfe25360 100644 --- a/src/observer/virtual_table/ob_all_virtual_load_data_stat.cpp +++ b/src/observer/virtual_table/ob_all_virtual_load_data_stat.cpp @@ -42,18 +42,16 @@ int ObAllVirtualLoadDataStat::inner_open() { int ret = OB_SUCCESS; sql::ObGlobalLoadDataStatMap *job_status_map = sql::ObGlobalLoadDataStatMap::getInstance(); - - job_status_map->get_all_job_status(all_job_status_op_); - + if (OB_FAIL(job_status_map->get_all_job_status(all_job_status_op_))) { + SERVER_LOG(WARN, "fail to get all job status", K(ret)); + } return ret; } int ObAllVirtualLoadDataStat::inner_close() { int ret = OB_SUCCESS; - all_job_status_op_.reset(); - return ret; } @@ -61,14 +59,10 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) { int ret = OB_SUCCESS; sql::ObLoadDataStat *job_status = nullptr; - - if (all_job_status_op_.end()) { - all_job_status_op_.reset(); - ret = OB_ITER_END; - } else if ((job_status = all_job_status_op_.next_job_status()) == nullptr) { - all_job_status_op_.reset(); - ret = OB_ERR_UNEXPECTED; - SERVER_LOG(WARN, "job_status = null", K(ret)); + if (OB_FAIL(all_job_status_op_.get_next_job_status(job_status))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + SERVER_LOG(WARN, "fail to get next job status", KR(ret)); + } } else { ObObj *cells = cur_row_.cells_; const int64_t col_count = output_column_ids_.count(); @@ -100,6 +94,11 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) cells[i].set_int(job_status->job_id_); break; } + case JOB_TYPE: { + cells[i].set_varchar(job_status->job_type_); + cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } case TABLE_NAME: { cells[i].set_varchar(job_status->table_name_); cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); @@ -131,16 +130,19 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) break; } case LOAD_TIME: {//当前导入数据已经花费的秒数 + int64_t current_time = common::ObTimeUtility::current_time(); cells[i].set_int((current_time - job_status->start_time_) / 1000000); break; } case ESTIMATED_REMAINING_TIME: { int64_t load_time = current_time - job_status->start_time_; int64_t estimated_remaining_time = 0; - if (job_status->processed_bytes_ != 0) { - int64_t remain_bytes = job_status->total_bytes_ - job_status->processed_bytes_; - double speed = (double)job_status->processed_bytes_ / load_time; - estimated_remaining_time = (int64_t)(remain_bytes / speed / 1000000); + if ((job_status->parsed_bytes_ != 0) && OB_LIKELY(load_time != 0)) { + double speed = (double)job_status->parsed_bytes_ / load_time; + if (OB_LIKELY(speed != 0)) { + int64_t remain_bytes = job_status->total_bytes_ - job_status->parsed_bytes_; + estimated_remaining_time = (int64_t)(remain_bytes / speed / 1000000); + } } if (estimated_remaining_time < 0) { cells[i].set_int(INT64_MAX); @@ -157,12 +159,12 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) cells[i].set_int(job_status->read_bytes_); break; } - case PROCESSED_BYTES: { - cells[i].set_int(job_status->processed_bytes_); + case PARSED_BYTES: { + cells[i].set_int(job_status->parsed_bytes_); break; } - case PROCESSED_ROWS: { - cells[i].set_int(job_status->processed_rows_); + case PARSED_ROWS: { + cells[i].set_int(job_status->parsed_rows_); break; } case TOTAL_SHUFFLE_TASK: { @@ -185,6 +187,50 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) cells[i].set_int(job_status->total_wait_secs_); break; } + case MAX_ALLOWED_ERROR_ROWS: { + cells[i].set_int(job_status->max_allowed_error_rows_); + break; + } + case DETECTED_ERROR_ROWS: { + cells[i].set_int(job_status->detected_error_rows_); + break; + } + case COORDINATOR_RECEIVED_ROWS: { + cells[i].set_int(job_status->coordinator.received_rows_); + break; + } + case COORDINATOR_LAST_COMMIT_SEGMENT_ID: { + cells[i].set_int(job_status->coordinator.last_commit_segment_id_); + break; + } + case COORDINATOR_STATUS: { + cells[i].set_varchar(job_status->coordinator.status_); + cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case COORDINATOR_TRANS_STATUS: { + cells[i].set_varchar(job_status->coordinator.trans_status_); + cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case STORE_PROCESSED_ROWS: { + cells[i].set_int(job_status->store.processed_rows_); + break; + } + case STORE_LAST_COMMIT_SEGMENT_ID: { + cells[i].set_int(job_status->store.last_commit_segment_id_); + break; + } + case STORE_STATUS: { + cells[i].set_varchar(job_status->store.status_); + cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case STORE_TRANS_STATUS: { + cells[i].set_varchar(job_status->store.trans_status_); + cells[i].set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } default: { ret = OB_ERR_UNEXPECTED; SERVER_LOG(WARN, "invalid col_id", K(ret), K(col_id)); @@ -202,4 +248,4 @@ int ObAllVirtualLoadDataStat::inner_get_next_row(ObNewRow *&row) } } // namespace observer -} // namespace oceanbasenamespace observer +} // namespace oceanbase diff --git a/src/observer/virtual_table/ob_all_virtual_load_data_stat.h b/src/observer/virtual_table/ob_all_virtual_load_data_stat.h index 276fb17325..08d529c0bc 100644 --- a/src/observer/virtual_table/ob_all_virtual_load_data_stat.h +++ b/src/observer/virtual_table/ob_all_virtual_load_data_stat.h @@ -46,6 +46,7 @@ private: SVR_IP, SVR_PORT, JOB_ID, + JOB_TYPE, TABLE_NAME, FILE_PATH, TABLE_COLUMN, @@ -57,18 +58,30 @@ private: ESTIMATED_REMAINING_TIME, TOTAL_BYTES, READ_BYTES, - PROCESSED_BYTES, - PROCESSED_ROWS, + PARSED_BYTES, + PARSED_ROWS, TOTAL_SHUFFLE_TASK, TOTAL_INSERT_TASK, SHUFFLE_RT_SUM, INSERT_RT_SUM, - TOTAL_WAIT_SECS + TOTAL_WAIT_SECS, + MAX_ALLOWED_ERROR_ROWS, + DETECTED_ERROR_ROWS, + COORDINATOR_RECEIVED_ROWS, + COORDINATOR_LAST_COMMIT_SEGMENT_ID, + COORDINATOR_STATUS, + COORDINATOR_TRANS_STATUS, + STORE_PROCESSED_ROWS, + STORE_LAST_COMMIT_SEGMENT_ID, + STORE_STATUS, + STORE_TRANS_STATUS }; common::ObAddr addr_; char ip_buf_[common::OB_IP_STR_BUFF]; sql::ObGetAllJobStatusOp all_job_status_op_; + TO_STRING_KV(K(addr_)); + private: DISALLOW_COPY_AND_ASSIGN(ObAllVirtualLoadDataStat); }; diff --git a/src/pl/sys_package/ob_dbms_stats.cpp b/src/pl/sys_package/ob_dbms_stats.cpp index f538032ff4..2553eadf25 100644 --- a/src/pl/sys_package/ob_dbms_stats.cpp +++ b/src/pl/sys_package/ob_dbms_stats.cpp @@ -5864,7 +5864,7 @@ int ObDbmsStats::set_param_global_part_id(ObExecContext &ctx, int64_t target_table_id = is_data_table ? data_table_id : param.table_id_; if (OB_FAIL(ctx.get_das_ctx().get_das_tablet_mapper(target_table_id, tablet_mapper))) { LOG_WARN("fail to get das tablet mapper", K(ret)); - } else if (tablet_mapper.get_non_partition_tablet_id(tmp_tablet_ids, tmp_part_ids)) { + } else if (OB_FAIL(tablet_mapper.get_non_partition_tablet_id(tmp_tablet_ids, tmp_part_ids))) { LOG_WARN("failed to get non partition tablet id", K(ret)); } else if (tmp_part_ids.count() == 1 && tmp_tablet_ids.count() == 1) { if (is_data_table) { diff --git a/src/rootserver/ddl_task/ob_column_redefinition_task.cpp b/src/rootserver/ddl_task/ob_column_redefinition_task.cpp index ce92cdf528..589d269944 100644 --- a/src/rootserver/ddl_task/ob_column_redefinition_task.cpp +++ b/src/rootserver/ddl_task/ob_column_redefinition_task.cpp @@ -454,6 +454,49 @@ int ObColumnRedefinitionTask::copy_table_foreign_keys() return ret; } +int ObColumnRedefinitionTask::serialize_params_to_message(char *buf, const int64_t buf_len, int64_t &pos) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == buf || buf_len <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), KP(buf), K(buf_len)); + } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, task_version_))) { + LOG_WARN("fail to serialize task version", K(ret), K(task_version_)); + } else if (OB_FAIL(alter_table_arg_.serialize(buf, buf_len, pos))) { + LOG_WARN("serialize table arg failed", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_ENCODE, parallelism_, cluster_version_); + } + return ret; +} + +int ObColumnRedefinitionTask::deserlize_params_from_message(const char *buf, const int64_t data_len, int64_t &pos) +{ + int ret = OB_SUCCESS; + obrpc::ObAlterTableArg tmp_arg; + if (OB_UNLIKELY(nullptr == buf || data_len <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), KP(buf), K(data_len)); + } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, &task_version_))) { + LOG_WARN("fail to deserialize task version", K(ret)); + } else if (OB_FAIL(tmp_arg.deserialize(buf, data_len, pos))) { + LOG_WARN("serialize table failed", K(ret)); + } else if (OB_FAIL(deep_copy_table_arg(allocator_, tmp_arg, alter_table_arg_))) { + LOG_WARN("deep copy table arg failed", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_DECODE, parallelism_, cluster_version_); + } + return ret; +} + +int64_t ObColumnRedefinitionTask::get_serialize_param_size() const +{ + return alter_table_arg_.get_serialize_size() + + serialization::encoded_length_i64(task_version_) + + serialization::encoded_length_i64(parallelism_) + + serialization::encoded_length_i64(cluster_version_); +} + int ObColumnRedefinitionTask::copy_table_dependent_objects(const ObDDLTaskStatus next_task_status) { int ret = OB_SUCCESS; diff --git a/src/rootserver/ddl_task/ob_column_redefinition_task.h b/src/rootserver/ddl_task/ob_column_redefinition_task.h index 049a3c302f..0fe2d99b4f 100644 --- a/src/rootserver/ddl_task/ob_column_redefinition_task.h +++ b/src/rootserver/ddl_task/ob_column_redefinition_task.h @@ -60,6 +60,9 @@ private: int copy_table_indexes(); int copy_table_constraints(); int copy_table_foreign_keys(); + virtual int serialize_params_to_message(char *buf, const int64_t buf_len, int64_t &pos) const override; + virtual int deserlize_params_from_message(const char *buf, const int64_t data_len, int64_t &pos) override; + virtual int64_t get_serialize_param_size() const override; private: static const int64_t OB_COLUMN_REDEFINITION_TASK_VERSION = 1L; int64_t sstable_complete_request_time_; diff --git a/src/rootserver/ddl_task/ob_ddl_redefinition_task.cpp b/src/rootserver/ddl_task/ob_ddl_redefinition_task.cpp index 33f6db801c..adc9750542 100644 --- a/src/rootserver/ddl_task/ob_ddl_redefinition_task.cpp +++ b/src/rootserver/ddl_task/ob_ddl_redefinition_task.cpp @@ -1308,58 +1308,6 @@ int ObDDLRedefinitionTask::notify_update_autoinc_finish(const uint64_t autoinc_v return ret; } -int ObDDLRedefinitionTask::serialize_params_to_message(char *buf, const int64_t buf_len, int64_t &pos) const -{ - int ret = OB_SUCCESS; - if (OB_UNLIKELY(nullptr == buf || buf_len <= 0)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid arguments", K(ret), KP(buf), K(buf_len)); - } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, task_version_))) { - LOG_WARN("fail to serialize task version", K(ret), K(task_version_)); - } else if (OB_FAIL(alter_table_arg_.serialize(buf, buf_len, pos))) { - LOG_WARN("serialize table arg failed", K(ret)); - } else { - LST_DO_CODE(OB_UNIS_ENCODE, parallelism_, cluster_version_); - if (OB_SUCC(ret)) { - if (OB_FAIL(ddl_tracing_.serialize(buf, buf_len, pos))) { - LOG_WARN("fail to serialize ddl_flt_ctx", K(ret)); - } - } - } - return ret; -} - -int ObDDLRedefinitionTask::deserlize_params_from_message(const char *buf, const int64_t data_len, int64_t &pos) -{ - int ret = OB_SUCCESS; - obrpc::ObAlterTableArg tmp_arg; - if (OB_UNLIKELY(nullptr == buf || data_len <= 0)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid arguments", K(ret), KP(buf), K(data_len)); - } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, &task_version_))) { - LOG_WARN("fail to deserialize task version", K(ret)); - } else if (OB_FAIL(tmp_arg.deserialize(buf, data_len, pos))) { - LOG_WARN("serialize table failed", K(ret)); - } else if (OB_FAIL(deep_copy_table_arg(allocator_, tmp_arg, alter_table_arg_))) { - LOG_WARN("deep copy table arg failed", K(ret)); - } else { - LST_DO_CODE(OB_UNIS_DECODE, parallelism_, cluster_version_); - if (OB_SUCC(ret) && pos < data_len) { - if (OB_FAIL(ddl_tracing_.deserialize(buf, data_len, pos))) { - LOG_WARN("fail to deserialize ddl_tracing_", K(ret)); - } - } - } - return ret; -} - -int64_t ObDDLRedefinitionTask::get_serialize_param_size() const -{ - return alter_table_arg_.get_serialize_size() + serialization::encoded_length_i64(task_version_) - + serialization::encoded_length_i64(parallelism_) + serialization::encoded_length_i64(cluster_version_) - + ddl_tracing_.get_serialize_size(); -} - int ObDDLRedefinitionTask::check_health() { int ret = OB_SUCCESS; diff --git a/src/rootserver/ddl_task/ob_ddl_redefinition_task.h b/src/rootserver/ddl_task/ob_ddl_redefinition_task.h index e30de28e30..81c3240f90 100644 --- a/src/rootserver/ddl_task/ob_ddl_redefinition_task.h +++ b/src/rootserver/ddl_task/ob_ddl_redefinition_task.h @@ -111,7 +111,7 @@ public: dependent_task_result_map_(), snapshot_held_(false), has_synced_autoincrement_(false), has_synced_stats_info_(false), update_autoinc_job_ret_code_(INT64_MAX), update_autoinc_job_time_(0), check_table_empty_job_ret_code_(INT64_MAX), check_table_empty_job_time_(0) {} - virtual ~ObDDLRedefinitionTask(){}; + virtual ~ObDDLRedefinitionTask() {} virtual int process() = 0; virtual int update_complete_sstable_job_status( const common::ObTabletID &tablet_id, @@ -122,9 +122,6 @@ public: int on_child_task_finish( const uint64_t child_task_key, const int ret_code); - virtual int serialize_params_to_message(char *buf, const int64_t buf_size, int64_t &pos) const override; - virtual int deserlize_params_from_message(const char *buf, const int64_t buf_size, int64_t &pos) override; - virtual int64_t get_serialize_param_size() const override; int notify_update_autoinc_finish(const uint64_t autoinc_val, const int ret_code); virtual void flt_set_task_span_tag() const = 0; virtual void flt_set_status_span_tag() const = 0; diff --git a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp index d4ea1df9b7..4654edd7bd 100644 --- a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp +++ b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp @@ -218,6 +218,250 @@ int ObDDLTaskQueue::get_task(const int64_t task_id, ObDDLTask *&task) return ret; } +int ObDDLTaskQueue::update_task_copy_deps_setting(const int64_t task_id, + const bool is_copy_constraints, + const bool is_copy_indexes, + const bool is_copy_triggers, + const bool is_copy_foreign_keys, + const bool is_ignore_errors) +{ + int ret = OB_SUCCESS; + ObDDLTask *task = nullptr; + ObTableRedefinitionTask *table_redefinition_task = nullptr; + common::ObSpinLockGuard guard(lock_); + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLTaskQueue has not been inited", K(ret)); + } else if (OB_UNLIKELY(task_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id)); + } else if (OB_FAIL(task_id_map_.get_refactored(task_id, task))) { + ret = OB_HASH_NOT_EXIST == ret ? OB_ENTRY_NOT_EXIST : ret; + LOG_WARN("get from task map failed", K(ret), K(task_id)); + } else if (OB_ISNULL(table_redefinition_task = static_cast(task))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ddl_task is null", K(ret)); + } else { + table_redefinition_task->set_is_copy_constraints(is_copy_constraints); + table_redefinition_task->set_is_copy_indexes(is_copy_indexes); + table_redefinition_task->set_is_copy_triggers(is_copy_triggers); + table_redefinition_task->set_is_copy_foreign_keys(is_copy_foreign_keys); + table_redefinition_task->set_is_ignore_errors(is_ignore_errors); + } + return ret; +} + +int ObDDLTaskQueue::update_task_process_schedulable(const int64_t task_id) +{ + int ret = OB_SUCCESS; + ObDDLTask *ddl_task = nullptr; + ObTableRedefinitionTask *table_redefinition_task = nullptr; + common::ObSpinLockGuard guard(lock_); + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLTaskQueue has not been inited", K(ret)); + } else if (OB_UNLIKELY(task_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id)); + } else if (OB_FAIL(task_id_map_.get_refactored(task_id, ddl_task))) { + ret = OB_HASH_NOT_EXIST == ret ? OB_ENTRY_NOT_EXIST : ret; + LOG_WARN("get from task map failed", K(ret), K(task_id)); + } else if (OB_ISNULL(table_redefinition_task = static_cast(ddl_task))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ddl_task is null", K(ret)); + } else { + table_redefinition_task->set_is_do_finish(true); + } + return ret; +} + +int ObDDLTaskQueue::abort_task(const int64_t task_id, common::ObMySQLProxy &mysql_proxy) +{ + int ret = OB_SUCCESS; + share::ObTaskId trace_id; + ObDDLTask *ddl_task = nullptr; + common::ObSpinLockGuard guard(lock_); + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLTaskQueue has not been inited", K(ret)); + } else if (OB_UNLIKELY(task_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id)); + } else if (OB_FAIL(task_id_map_.get_refactored(task_id, ddl_task))) { + if (OB_HASH_NOT_EXIST == ret) { + bool exist = false; + if (OB_FAIL(ObDDLTaskRecordOperator::check_task_id_exist(mysql_proxy, task_id, exist))) { + LOG_WARN("check task id exist fail", K(ret)); + } else { + if (exist) { + ret = OB_EAGAIN; + LOG_INFO("entry exist, the ddl scheduler hasn't recovered the task yet", K(ret), K(task_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + LOG_WARN("this task does not exist in the hash table", K(ret), K(task_id)); + } + } + } + LOG_WARN("get from task map failed", K(ret), K(task_id)); + } else if (OB_ISNULL(ddl_task)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ddl_task is null", K(ret)); + } else { + trace_id.set(ddl_task->get_trace_id()); + if (OB_UNLIKELY(trace_id.is_invalid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), K(trace_id)); + } else if (OB_FAIL(SYS_TASK_STATUS_MGR.cancel_task(trace_id))) { + LOG_WARN("cancel task failed", K(ret)); + } else { + LOG_INFO("succeed to abort task", K(task_id)); + } + } + return ret; +} + +ObDDLTaskHeartBeatMananger::ObDDLTaskHeartBeatMananger() + : is_inited_(false), bucket_lock_() +{} + +ObDDLTaskHeartBeatMananger::~ObDDLTaskHeartBeatMananger() +{ + bucket_lock_.destroy(); +} + +int ObDDLTaskHeartBeatMananger::init() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(is_inited_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ObManagerRegisterHeartBeatTask inited twice", K(ret)); + } else if (OB_FAIL(register_task_time_.create(BUCKET_LOCK_BUCKET_CNT, "register_task", "register_task"))) { + LOG_WARN("failed to create register_task_time map", K(ret)); + } else if (OB_FAIL(bucket_lock_.init(BUCKET_LOCK_BUCKET_CNT))) { + LOG_WARN("fail to init bucket lock", K(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObDDLTaskHeartBeatMananger::update_task_active_time(const int64_t task_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObManagerRegisterHeartBeatTask not inited", K(ret)); + } else { + ObBucketHashWLockGuard lock_guard(bucket_lock_, task_id); + // setting flag=1 to update the old time-value in the hash map with current time + if (OB_FAIL(register_task_time_.set_refactored(task_id, + ObTimeUtility::current_time(), 1, 0, 0))) { + LOG_WARN("set register task time failed", K(ret)); + } + } + return ret; +} + +int ObDDLTaskHeartBeatMananger::remove_task(const int64_t task_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObManagerRegisterHeartBeatTask not inited", K(ret)); + } else { + ObBucketHashWLockGuard lock_guard(bucket_lock_, task_id); + if (OB_FAIL(register_task_time_.erase_refactored(task_id))) { + LOG_WARN("remove register task time failed", K(ret)); + } + } + return ret; +} + +int ObDDLTaskHeartBeatMananger::get_inactive_ddl_task_ids(ObArray& remove_task_ids) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObManagerRegisterHeartBeatTask not inited", K(ret)); + } else { + const int64_t TIME_OUT_THRESHOLD = 5L * 60L * 1000L * 1000L; + ObBucketTryRLockAllGuard all_ddl_task_guard(bucket_lock_); + if (OB_FAIL(all_ddl_task_guard.get_ret())) { + if (OB_EAGAIN == ret) { + ret = OB_SUCCESS; + } + } else { + for (common::hash::ObHashMap::iterator it = register_task_time_.begin(); OB_SUCC(ret) && it != register_task_time_.end(); it++) { + if (ObTimeUtility::current_time() - it->second > TIME_OUT_THRESHOLD) { + if (OB_FAIL(remove_task_ids.push_back(it->first))) { + LOG_WARN("remove_task_ids push_back task_id fail", K(ret), K(it->first)); + } + } + } + } + } + return ret; +} + +ObPrepareAlterTableArgParam::ObPrepareAlterTableArgParam() : session_id_(OB_INVALID_ID) {} + +int ObPrepareAlterTableArgParam::init(const uint64_t session_id, + const ObSQLMode &sql_mode, + const ObString &ddl_stmt_str, + const ObString &orig_table_name, + const ObString &orig_database_name, + const ObString &target_database_name, + const ObTimeZoneInfo &tz_info, + const ObTimeZoneInfoWrap &tz_info_wrap, + const ObString *nls_formats) +{ + int ret = OB_SUCCESS; + if (FALSE_IT(session_id_ = session_id)) { + // do nothing + } else if (FALSE_IT(sql_mode_ = sql_mode)) { + // do nothing + } else if (FALSE_IT(ddl_stmt_str_.assign_ptr(ddl_stmt_str.ptr(), ddl_stmt_str.length()))) { + // do nothing + } else if (FALSE_IT(orig_table_name_.assign_ptr(orig_table_name.ptr(), orig_table_name.length()))) { + // do nothing + } else if (FALSE_IT(orig_database_name_.assign_ptr(orig_database_name.ptr(), orig_database_name.length()))) { + // do nothing + } else if (FALSE_IT(target_database_name_.assign_ptr(target_database_name.ptr(), target_database_name.length()))) { + // do nothinh + } else if (OB_FAIL(tz_info_.assign(tz_info))) { + LOG_WARN("tz_info assign failed", K(ret)); + } else if (OB_FAIL(tz_info_wrap_.deep_copy(tz_info_wrap))) { + LOG_WARN("failed to deep_copy tz info wrap", K(ret), "tz_info_wrap", tz_info_wrap); + } else if (OB_FAIL(set_nls_formats(nls_formats))) { + LOG_WARN("failed to set nls formats", K(ret)); + } + return ret; +} +int ObPrepareAlterTableArgParam::set_nls_formats(const common::ObString *nls_formats) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(nls_formats)) { + ret = OB_INVALID_ARGUMENT; + } else { + char *tmp_ptr[ObNLSFormatEnum::NLS_MAX] = {}; + common::ObArenaAllocator allocator; + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; ++i) { + if (OB_ISNULL(tmp_ptr[i] = (char *)allocator.alloc(nls_formats[i].length()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + SHARE_LOG(ERROR, "failed to alloc memory!", "size", nls_formats[i].length(), K(ret)); + } else { + MEMCPY(tmp_ptr[i], nls_formats[i].ptr(), nls_formats[i].length()); + nls_formats_[i].assign_ptr(tmp_ptr[i], nls_formats[i].length()); + } + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; ++i) { + allocator.free(tmp_ptr[i]); + } + } + } + return ret; +} int ObDDLScheduler::DDLScanTask::schedule(int tg_id) { return TG_SCHEDULE(tg_id, *this, DDL_TASK_SCAN_PERIOD, true); @@ -231,8 +475,28 @@ void ObDDLScheduler::DDLScanTask::runTimerTask() } } +int ObDDLScheduler::HeartBeatCheckTask::schedule(int tg_id) +{ + return TG_SCHEDULE(tg_id, *this, DDL_TASK_CHECK_PERIOD, true); +} + +void ObDDLScheduler::HeartBeatCheckTask::runTimerTask() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ddl_scheduler_.remove_inactive_ddl_task())) { + LOG_WARN("failed to check register task", K(ret)); + } +} + ObDDLScheduler::ObDDLScheduler() - : is_inited_(false), is_started_(false), tg_id_(-1), root_service_(nullptr), idle_stop_(false), idler_(idle_stop_), scan_task_(*this) + : is_inited_(false), + is_started_(false), + tg_id_(-1), + root_service_(nullptr), + idle_stop_(false), + idler_(idle_stop_), + scan_task_(*this), + heart_beat_check_task_(*this) { } @@ -258,6 +522,8 @@ int ObDDLScheduler::init(ObRootService *root_service) LOG_WARN("init allocator failed", K(ret)); } else if (OB_FAIL(task_queue_.init(MAX_TASK_NUM))) { LOG_WARN("init task queue failed", K(ret)); + } else if (OB_FAIL(manager_reg_heart_beat_task_.init())) { + LOG_WARN("init manager register heart beat task failed", K(ret)); } else if (OB_FAIL(TG_CREATE(lib::TGDefIDs::DDLTaskExecutor3, tg_id_))) { LOG_WARN("tg create failed", K(ret)); } else { @@ -283,6 +549,10 @@ int ObDDLScheduler::start() LOG_WARN("start ddl scan task failed", K(ret)); } else if (OB_FAIL(scan_task_.schedule(lib::TGDefIDs::DDLScanTask))) { LOG_WARN("failed to schedule ddl scan task", K(ret)); + } else if (OB_FAIL(TG_START(lib::TGDefIDs::HeartBeatCheckTask))) { + LOG_WARN("start heart beat check task failed", K(ret)); + } else if (OB_FAIL(heart_beat_check_task_.schedule(lib::TGDefIDs::HeartBeatCheckTask))) { + LOG_WARN("failed to schedule heart beat check task", K(ret)); } else { is_started_ = true; idle_stop_ = false; @@ -294,6 +564,7 @@ void ObDDLScheduler::stop() { TG_STOP(tg_id_); TG_STOP(lib::TGDefIDs::DDLScanTask); + TG_STOP(lib::TGDefIDs::HeartBeatCheckTask); idle_stop_ = true; is_started_ = false; destroy_all_tasks(); @@ -303,6 +574,7 @@ void ObDDLScheduler::wait() { TG_WAIT(tg_id_); TG_WAIT(lib::TGDefIDs::DDLScanTask); + TG_WAIT(lib::TGDefIDs::HeartBeatCheckTask); } void ObDDLScheduler::run1() @@ -367,8 +639,15 @@ int ObDDLScheduler::create_ddl_task(const ObCreateDDLTaskParam ¶m, const obrpc::ObCreateIndexArg *create_index_arg = nullptr; const obrpc::ObDropIndexArg *drop_index_arg = nullptr; ObRootService *root_service = GCTX.root_service_; + uint64_t tenant_id = param.tenant_id_; + uint64_t compat_version = 0; LOG_INFO("create ddl task", K(param)); - if (OB_UNLIKELY(!is_inited_)) { + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0 && GCONF.in_upgrade_mode()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("4.0 is being upgrade to 4.1, create_ddl_task not supported", K(ret)); + } else if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("ObDDLScheduler has not been inited", K(ret)); } else if (OB_ISNULL(root_service)) { @@ -410,6 +689,7 @@ int ObDDLScheduler::create_ddl_task(const ObCreateDDLTaskParam ¶m, case DDL_ALTER_PARTITION_BY: case DDL_CONVERT_TO_CHARACTER: case DDL_TABLE_REDEFINITION: + case DDL_DIRECT_LOAD: if (OB_FAIL(create_table_redefinition_task(proxy, param.type_, param.src_table_schema_, @@ -552,6 +832,299 @@ int ObDDLScheduler::remove_sys_task(ObDDLTask *task) } return ret; } +int ObDDLScheduler::prepare_alter_table_arg(const ObPrepareAlterTableArgParam ¶m, + const ObTableSchema *target_table_schema, + obrpc::ObAlterTableArg &alter_table_arg) +{ + int ret = OB_SUCCESS; + AlterTableSchema *alter_table_schema = &alter_table_arg.alter_table_schema_; + alter_table_schema->alter_type_ = OB_DDL_ALTER_TABLE; + const ObString &ddl_stmt_str = param.ddl_stmt_str_; + if (OB_UNLIKELY(!param.is_valid() || OB_ISNULL(target_table_schema))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), K(param), KP(target_table_schema)); + } else if (FALSE_IT(alter_table_arg.session_id_ = param.session_id_)) { + // do nothing + } else if (FALSE_IT(alter_table_arg.sql_mode_ = param.sql_mode_)) { + // do nothing + } else if (FALSE_IT(alter_table_arg.ddl_stmt_str_.assign_ptr(ddl_stmt_str.ptr(), ddl_stmt_str.length()))) { + // do nothing + } else if (OB_FAIL(alter_table_arg.tz_info_.assign(param.tz_info_))) { + LOG_WARN("tz_info assign failed", K(ret)); + } else if (OB_FAIL(alter_table_arg.tz_info_wrap_.deep_copy(param.tz_info_wrap_))) { + LOG_WARN("failed to deep_copy tz info wrap", K(ret), "tz_info_wrap", param.tz_info_wrap_); + } else if (OB_FAIL(alter_table_arg.set_nls_formats(param.nls_formats_))) { + LOG_WARN("failed to set_nls_formats", K(ret)); + } else if (OB_FAIL(alter_table_schema->assign(*target_table_schema))) { + LOG_WARN("failed to assign alter table schema", K(ret)); + } else if (OB_FAIL(alter_table_schema->set_origin_table_name(param.orig_table_name_))) { + LOG_WARN("failed to set origin table name", K(ret)); + } else if (OB_FAIL(alter_table_schema->set_origin_database_name(param.orig_database_name_))) { + LOG_WARN("failed to set origin database name", K(ret)); + } else if (OB_FAIL(alter_table_schema->set_table_name(target_table_schema->get_table_name_str()))) { + LOG_WARN("failed to set table name", K(ret)); + } else if (OB_FAIL(alter_table_schema->set_database_name(param.target_database_name_))) { + LOG_WARN("failed to set database name", K(ret)); + } else if (!target_table_schema->is_mysql_tmp_table() + && OB_FAIL(alter_table_schema->alter_option_bitset_.add_member(obrpc::ObAlterTableArg::SESSION_ID))) { + LOG_WARN("failed to add member SESSION_ID for alter table schema", K(ret), K(alter_table_arg)); + } else if (OB_FAIL(alter_table_schema->alter_option_bitset_.add_member(obrpc::ObAlterTableArg::TABLE_NAME))) { + LOG_WARN("failed to add member TABLE_NAME for alter table schema", K(ret), K(alter_table_arg)); + } else { + LOG_DEBUG("alter table arg preparation complete!", K(ret), K(*alter_table_schema)); + } + return ret; +} + +int ObDDLScheduler::abort_redef_table(const int64_t task_id) +{ + int ret = OB_SUCCESS; + share::ObTaskId trace_id; + ObDDLTask *ddl_task = nullptr; + if (OB_UNLIKELY(task_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id)); + } else if (OB_FAIL(task_queue_.abort_task(task_id, root_service_->get_sql_proxy()))) { + LOG_WARN("abort redef table task failed", K(ret)); + } + return ret; +} + +int ObDDLScheduler::copy_table_dependents(const int64_t task_id, + const uint64_t tenant_id, + const bool is_copy_constraints, + const bool is_copy_indexes, + const bool is_copy_triggers, + const bool is_copy_foreign_keys, + const bool is_ignore_errors) +{ + int ret = OB_SUCCESS; + ObDDLTask *task = nullptr; + ObTableRedefinitionTask *table_redefinition_task = nullptr; + int64_t table_task_status = 0; + int64_t table_execution_id = 0; + int64_t pos = 0; + ObString message; + ObMySQLTransaction trans; + if (OB_UNLIKELY(0 >= task_id || OB_INVALID_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id), K(tenant_id)); + } else if (OB_FAIL(trans.start(&root_service_->get_sql_proxy(), tenant_id))) { + LOG_WARN("start transaction failed", K(ret)); + } else if (OB_FAIL(ObDDLTaskRecordOperator::select_for_update(trans, + tenant_id, + task_id, + table_task_status, + table_execution_id))) { + LOG_WARN("select for update failed", K(ret), K(tenant_id), K(task_id)); + } else if (OB_FAIL(task_queue_.get_task(task_id, task))) { + LOG_WARN("get task fail", K(ret)); + } else if (OB_ISNULL(table_redefinition_task = static_cast(task))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get task", K(ret)); + } else { + HEAP_VAR(ObTableRedefinitionTask, redefinition_task) { + ObDDLTaskRecord task_record; + common::ObArenaAllocator allocator(lib::ObLabel("copy_table_dep")); + task_record.reset(); + if (OB_UNLIKELY(!table_redefinition_task->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("table rdefinition task is not valid", K(ret)); + } else if (OB_FAIL(table_redefinition_task->convert_to_record(task_record, allocator))) { + LOG_WARN("convert to ddl task record failed", K(ret), K(*table_redefinition_task)); + } else if (OB_FAIL(redefinition_task.init(task_record))) { + LOG_WARN("init table redefinition task failed", K(ret)); + } else if (OB_FAIL(redefinition_task.set_trace_id(task_record.trace_id_))) { + LOG_WARN("set trace id failed", K(ret)); + } else { + redefinition_task.set_is_copy_constraints(is_copy_constraints); + redefinition_task.set_is_copy_indexes(is_copy_indexes); + redefinition_task.set_is_copy_triggers(is_copy_triggers); + redefinition_task.set_is_copy_foreign_keys(is_copy_foreign_keys); + redefinition_task.set_is_ignore_errors(is_ignore_errors); + if (OB_FAIL(redefinition_task.convert_to_record(task_record, allocator))) { + LOG_WARN("convert to ddl task record failed", K(ret), K(redefinition_task)); + } else if (OB_UNLIKELY(!task_record.is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ddl task record is invalid", K(ret), K(task_record)); + } else { + message.assign(task_record.message_.ptr(), task_record.message_.length()); + if (OB_FAIL(ObDDLTaskRecordOperator::update_message(trans, tenant_id, task_id, message))) { + LOG_WARN("update task message failed", K(ret), K(tenant_id), K(task_id), K(message)); + } else { + bool commit = (OB_SUCCESS == ret); + int tmp_ret = trans.end(commit); + if (OB_SUCCESS != tmp_ret) { + ret = (OB_SUCCESS == ret) ? tmp_ret : ret; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(task_queue_.update_task_copy_deps_setting(task_id, + is_copy_constraints, + is_copy_indexes, + is_copy_triggers, + is_copy_foreign_keys, + is_ignore_errors))) { + LOG_WARN("update task process setting failed", K(ret)); + } + } + } + } + } + } + } + return ret; +} + +int ObDDLScheduler::finish_redef_table(const int64_t task_id, const uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + ObDDLTask *task = nullptr; + ObTableRedefinitionTask *table_redefinition_task = nullptr; + int64_t table_task_status = 0; + int64_t table_execution_id = 0; + int64_t pos = 0; + ObString message; + ObMySQLTransaction trans; + if (OB_UNLIKELY(0 >= task_id || OB_INVALID_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id), K(tenant_id)); + } else if (OB_FAIL(trans.start(&root_service_->get_sql_proxy(), tenant_id))) { + LOG_WARN("start transaction failed", K(ret)); + } else if (OB_FAIL(ObDDLTaskRecordOperator::select_for_update(trans, + tenant_id, + task_id, + table_task_status, + table_execution_id))) { + LOG_WARN("select for update failed", K(ret), K(tenant_id), K(task_id)); + } else if (OB_FAIL(task_queue_.get_task(task_id, task))) { + LOG_WARN("get task fail", K(ret)); + } else if (OB_ISNULL(table_redefinition_task = static_cast(task))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get task", K(ret)); + } else { + HEAP_VAR(ObTableRedefinitionTask, redefinition_task) { + ObDDLTaskRecord task_record; + common::ObArenaAllocator allocator(lib::ObLabel("finish_redef")); + task_record.reset(); + if (OB_UNLIKELY(!table_redefinition_task->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("table rdefinition task is not valid", K(ret)); + } else if (OB_FAIL(table_redefinition_task->convert_to_record(task_record, allocator))) { + LOG_WARN("convert to ddl task record failed", K(ret), K(*table_redefinition_task)); + } else if (OB_FAIL(redefinition_task.init(task_record))) { + LOG_WARN("init table redefinition task failed", K(ret)); + } else if (OB_FAIL(redefinition_task.set_trace_id(task_record.trace_id_))) { + LOG_WARN("set trace id failed", K(ret)); + } else { + redefinition_task.set_is_do_finish(true); + if (OB_FAIL(redefinition_task.convert_to_record(task_record, allocator))) { + LOG_WARN("convert to ddl task record failed", K(ret), K(redefinition_task)); + } else if (OB_UNLIKELY(!task_record.is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ddl task record is invalid", K(ret), K(task_record)); + } else { + message.assign(task_record.message_.ptr(), task_record.message_.length()); + if (OB_FAIL(ObDDLTaskRecordOperator::update_message(trans, tenant_id, task_id, message))) { + LOG_WARN("update task message failed", K(ret), K(tenant_id), K(task_id), K(message)); + } else { + bool commit = (OB_SUCCESS == ret); + int tmp_ret = trans.end(commit); + if (OB_SUCCESS != tmp_ret) { + ret = (OB_SUCCESS == ret) ? tmp_ret : ret; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(task_queue_.update_task_process_schedulable(task_id))) { + LOG_WARN("update task process setting failed", K(ret)); + } + } + } + } + } + } + } + return ret; +} + +int ObDDLScheduler::start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res) +{ + int ret = OB_SUCCESS; + ObDDLTaskRecord task_record; + ObSchemaGetterGuard orig_schema_guard; + ObSchemaGetterGuard target_schema_guard; + ObMultiVersionSchemaService *schema_service = GCTX.schema_service_; + const int64_t tenant_id = arg.orig_tenant_id_; + const int64_t table_id = arg.orig_table_id_; + const int64_t dest_tenant_id = arg.target_tenant_id_; + const int64_t dest_table_id = arg.target_table_id_; + const ObTableSchema *orig_table_schema = nullptr; + const ObTableSchema *target_table_schema = nullptr; + const ObDatabaseSchema *orig_database_schema = nullptr; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(schema_service)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("schema_service is null", K(ret)); + } else if (OB_FAIL(schema_service->get_tenant_schema_guard(tenant_id, orig_schema_guard))) { + LOG_WARN("fail to get orig schema guard with version in inner table", K(ret), K(tenant_id)); + } else if (OB_FAIL(orig_schema_guard.get_table_schema(tenant_id, table_id, orig_table_schema))) { + LOG_WARN("fail to get orig table schema", K(ret)); + } else if (OB_ISNULL(orig_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("orig_table_schema is nullptr", K(ret)); + } else if (OB_FAIL(orig_schema_guard.get_database_schema(tenant_id, orig_table_schema->get_database_id(), orig_database_schema))) { + LOG_WARN("fail to get orig database schema", K(ret)); + } else if (OB_ISNULL(orig_database_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("orig_database_schema is nullptr", K(ret)); + } else if (OB_FAIL(schema_service->get_tenant_schema_guard(dest_tenant_id, target_schema_guard))) { + LOG_WARN("fail to get orig schema guard with version in inner table", K(ret), K(dest_tenant_id)); + } else if (OB_FAIL(target_schema_guard.get_table_schema(dest_tenant_id, dest_table_id, target_table_schema))) { + LOG_WARN("fail to get target table schema", K(ret)); + } else if (OB_ISNULL(target_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("target_table_schema is nullptr", K(ret)); + } else { + HEAP_VAR(obrpc::ObAlterTableArg, alter_table_arg) { + ObPrepareAlterTableArgParam param; + if (OB_FAIL(param.init(arg.session_id_, + arg.sql_mode_, + arg.ddl_stmt_str_, + orig_table_schema->get_table_name_str(), + orig_database_schema->get_database_name_str(), + orig_database_schema->get_database_name_str(), + arg.tz_info_, + arg.tz_info_wrap_, + arg.nls_formats_))) { + LOG_WARN("param init failed", K(ret)); + } else if (OB_FAIL(prepare_alter_table_arg(param, target_table_schema, alter_table_arg))) { + LOG_WARN("failed to build alter table arg", K(ret)); + } else { + common::ObArenaAllocator allocator(lib::ObLabel("StartRedefTable")); + ObCreateDDLTaskParam param(tenant_id, + arg.ddl_type_, + orig_table_schema, + target_table_schema, + orig_table_schema->get_table_id(), + orig_table_schema->get_schema_version(), + arg.parallelism_, + &allocator, + &alter_table_arg, + 0); + if (OB_FAIL(create_ddl_task(param, root_service_->get_sql_proxy(), task_record))) { + LOG_WARN("submit ddl task failed", K(ret), K(alter_table_arg)); + } else if (OB_FAIL(schedule_ddl_task(task_record))) { + LOG_WARN("fail to schedule ddl task", K(ret), K(task_record)); + } else { + res.task_id_ = task_record.task_id_; + res.tenant_id_ = task_record.tenant_id_; + res.schema_version_ = task_record.schema_version_; + } + } + } + } + return ret; +} int ObDDLScheduler::create_build_index_task( common::ObISQLClient &proxy, @@ -684,29 +1257,29 @@ int ObDDLScheduler::create_table_redefinition_task( int ret = OB_SUCCESS; int64_t task_id = 0; SMART_VAR(ObTableRedefinitionTask, redefinition_task) { - if (OB_UNLIKELY(!is_inited_)) { - ret = OB_NOT_INIT; - LOG_WARN("ObDDLScheduler has not been inited", K(ret)); - } else if (OB_ISNULL(alter_table_arg) || OB_ISNULL(src_schema) || OB_ISNULL(dest_schema)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid arguments", K(ret), KP(alter_table_arg), KP(src_schema), KP(dest_schema)); - } else if (OB_FAIL(ObDDLTask::fetch_new_task_id(root_service_->get_sql_proxy(), task_id))) { - LOG_WARN("fetch new task id failed", K(ret)); - } else if (OB_FAIL(redefinition_task.init(src_schema->get_tenant_id(), - task_id, - type, - src_schema->get_table_id(), - dest_schema->get_table_id(), - dest_schema->get_schema_version(), - parallelism, - *alter_table_arg))) { - LOG_WARN("fail to init redefinition task", K(ret)); - } else if (OB_FAIL(redefinition_task.set_trace_id(*ObCurTraceId::get_trace_id()))) { - LOG_WARN("set trace id failed", K(ret)); - } else if (OB_FAIL(insert_task_record(proxy, redefinition_task, allocator, task_record))) { - LOG_WARN("fail to insert task record", K(ret)); - } - LOG_INFO("ddl_scheduler create table redefinition task finished", K(ret), K(redefinition_task), K(common::lbt())); + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLScheduler has not been inited", K(ret)); + } else if (OB_ISNULL(alter_table_arg) || OB_ISNULL(src_schema) || OB_ISNULL(dest_schema)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), KP(alter_table_arg), KP(src_schema), KP(dest_schema)); + } else if (OB_FAIL(ObDDLTask::fetch_new_task_id(root_service_->get_sql_proxy(), task_id))) { + LOG_WARN("fetch new task id failed", K(ret)); + } else if (OB_FAIL(redefinition_task.init(src_schema->get_tenant_id(), + task_id, + type, + src_schema->get_table_id(), + dest_schema->get_table_id(), + dest_schema->get_schema_version(), + parallelism, + *alter_table_arg))) { + LOG_WARN("fail to init redefinition task", K(ret)); + } else if (OB_FAIL(redefinition_task.set_trace_id(*ObCurTraceId::get_trace_id()))) { + LOG_WARN("set trace id failed", K(ret)); + } else if (OB_FAIL(insert_task_record(proxy, redefinition_task, allocator, task_record))) { + LOG_WARN("fail to insert task record", K(ret)); + } + LOG_INFO("ddl_scheduler create table redefinition task finished", K(ret), K(redefinition_task), K(common::lbt())); } return ret; } @@ -930,6 +1503,41 @@ int ObDDLScheduler::recover_task() return ret; } +int ObDDLScheduler::remove_inactive_ddl_task() +{ + int ret = OB_SUCCESS; + ObArray remove_task_ids; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else { + if (OB_FAIL(manager_reg_heart_beat_task_.get_inactive_ddl_task_ids(remove_task_ids))){ + LOG_WARN("failed to check register time", K(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < remove_task_ids.size(); i++) { + int64_t remove_task_id = 0; + if (OB_FAIL(remove_task_ids.at(i, remove_task_id))) { + LOG_WARN("get remove task id fail", K(ret)); + } else if (OB_FAIL(abort_redef_table(remove_task_id))) { + if (OB_ENTRY_NOT_EXIST == ret) { + LOG_INFO("abort_redef_table() success, but manager_reg_heart_beat_task last deletion failed", K(ret)); + ret = OB_SUCCESS; + } else { + LOG_WARN("remove ddl task fail", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(manager_reg_heart_beat_task_.remove_task(remove_task_id))) { + LOG_WARN("RegTaskTime map erase remove_task_id fail", K(ret)); + } + } + } + LOG_INFO("remove all timeout ddl task succeed"); + } + } + return ret; +} + int ObDDLScheduler::schedule_ddl_task(const ObDDLTaskRecord &record) { int ret = OB_SUCCESS; @@ -961,6 +1569,7 @@ int ObDDLScheduler::schedule_ddl_task(const ObDDLTaskRecord &record) case DDL_ALTER_PARTITION_BY: case DDL_CONVERT_TO_CHARACTER: case DDL_TABLE_REDEFINITION: + case DDL_DIRECT_LOAD: if (OB_FAIL(schedule_table_redefinition_task(record))) { LOG_WARN("schedule table redefinition task failed", K(ret)); } @@ -1085,6 +1694,9 @@ int ObDDLScheduler::schedule_table_redefinition_task(const ObDDLTaskRecord &task if (OB_ENTRY_EXIST != ret) { LOG_WARN("inner schedule task failed", K(ret), K(*redefinition_task)); } + } else if (ObDDLType::DDL_DIRECT_LOAD == task_record.ddl_type_ + && OB_FAIL(manager_reg_heart_beat_task_.update_task_active_time(task_record.task_id_))) { + LOG_WARN("register_task_time recover fail", K(ret)); } if (OB_FAIL(ret) && nullptr != redefinition_task) { redefinition_task->~ObTableRedefinitionTask(); @@ -1421,6 +2033,7 @@ int ObDDLScheduler::on_sstable_complement_job_reply( case ObDDLType::DDL_MODIFY_COLUMN: case ObDDLType::DDL_CONVERT_TO_CHARACTER: case ObDDLType::DDL_TABLE_REDEFINITION: + case ObDDLType::DDL_DIRECT_LOAD: if (OB_FAIL(static_cast(ddl_task)->update_complete_sstable_job_status(tablet_id, snapshot_version, execution_id, ret_code, addition_info))) { LOG_WARN("update complete sstable job status", K(ret)); } @@ -1518,6 +2131,7 @@ int ObDDLScheduler::notify_update_autoinc_end(const ObDDLTaskKey &task_key, case ObDDLType::DDL_MODIFY_COLUMN: case ObDDLType::DDL_ALTER_PARTITION_BY: case ObDDLType::DDL_TABLE_REDEFINITION: + case ObDDLType::DDL_DIRECT_LOAD: if (OB_FAIL(static_cast(ddl_task)->notify_update_autoinc_finish(autoinc_val, ret_code))) { LOG_WARN("update complete sstable job status", K(ret)); } @@ -1561,6 +2175,21 @@ void ObDDLScheduler::destroy_all_tasks() } } +int ObDDLScheduler::update_ddl_task_active_time(const int64_t task_id) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + ret = OB_NOT_INIT; + LOG_WARN("not inited", K(ret)); + } else if (task_id <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(task_id)); + } else if (OB_FAIL(manager_reg_heart_beat_task_.update_task_active_time(task_id))) { + LOG_WARN("fail to set RegTaskTime map", K(ret), K(task_id)); + } + return ret; +} + } // end namespace rootserver } // end namespace oceanbase diff --git a/src/rootserver/ddl_task/ob_ddl_scheduler.h b/src/rootserver/ddl_task/ob_ddl_scheduler.h index 2b7ef6ce18..2d812b4800 100644 --- a/src/rootserver/ddl_task/ob_ddl_scheduler.h +++ b/src/rootserver/ddl_task/ob_ddl_scheduler.h @@ -61,6 +61,14 @@ public: int add_task_to_last(ObDDLTask *task); int get_task(const ObDDLTaskKey &task_key, ObDDLTask *&task); int get_task(const int64_t task_id, ObDDLTask *&task); + int update_task_copy_deps_setting(const int64_t task_id, + const bool is_copy_constraints, + const bool is_copy_indexes, + const bool is_copy_triggers, + const bool is_copy_foreign_keys, + const bool is_ignore_errors); + int update_task_process_schedulable(const int64_t task_id); + int abort_task(const int64_t task_id, common::ObMySQLProxy &mysql_proxy); int64_t get_task_cnt() const { return task_list_.get_size(); } void destroy(); private: @@ -76,6 +84,63 @@ private: bool is_inited_; }; +class ObDDLTaskHeartBeatMananger final +{ +public: + ObDDLTaskHeartBeatMananger(); + ~ObDDLTaskHeartBeatMananger(); + int init(); + int update_task_active_time(const int64_t task_id); + int remove_task(const int64_t task_id); + int get_inactive_ddl_task_ids(ObArray& remove_task_ids); +private: + static const int64_t BUCKET_LOCK_BUCKET_CNT = 10243L; + common::hash::ObHashMap register_task_time_; + bool is_inited_; + common::ObBucketLock bucket_lock_; +}; +struct ObPrepareAlterTableArgParam final +{ +public: + ObPrepareAlterTableArgParam(); + ~ObPrepareAlterTableArgParam() = default; + int init(const uint64_t session_id, + const ObSQLMode &sql_mode, + const ObString &ddl_stmt_str, + const ObString &orig_table_name, + const ObString &orig_database_name, + const ObString &target_database_name, + const ObTimeZoneInfo &tz_info, + const ObTimeZoneInfoWrap &tz_info_wrap, + const ObString *nls_formats); + bool is_valid() const + { + return OB_INVALID_ID != session_id_ && + !orig_table_name_.empty() && + !orig_database_name_.empty() && + !target_database_name_.empty(); + } + int set_nls_formats(const common::ObString *nls_formats); + TO_STRING_KV(K_(session_id), + K_(sql_mode), + K_(ddl_stmt_str), + K_(orig_table_name), + K_(orig_database_name), + K_(target_database_name), + K_(tz_info_wrap), + "nls_formats", common::ObArrayWrap(nls_formats_, common::ObNLSFormatEnum::NLS_MAX)); +public: + uint64_t session_id_; + ObSQLMode sql_mode_; + common::ObString ddl_stmt_str_; + common::ObString orig_table_name_; + common::ObString orig_database_name_; + common::ObString target_database_name_; + common::ObTimeZoneInfo tz_info_; + common::ObTimeZoneInfoWrap tz_info_wrap_; + common::ObString nls_formats_[common::ObNLSFormatEnum::NLS_MAX]; +}; + /* * the only scheduler for all ddl tasks executed in root service * @@ -102,6 +167,7 @@ public: int schedule_ddl_task( const ObDDLTaskRecord &task_record); int recover_task(); + int remove_inactive_ddl_task(); int destroy_task(); @@ -128,11 +194,25 @@ public: const ObDDLTaskKey &task_key, const uint64_t autoinc_val, const int ret_code); + int abort_redef_table(const int64_t task_id); + + int copy_table_dependents(const int64_t task_id, + const uint64_t tenant_id, + const bool is_copy_constraints, + const bool is_copy_indexes, + const bool is_copy_triggers, + const bool is_copy_foreign_keys, + const bool is_ignore_errors); + int finish_redef_table(const int64_t task_id, const uint64_t tenant_id); + int start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res); + int update_ddl_task_active_time(const int64_t task_id); int on_update_execution_id( const int64_t task_id, int64_t &ret_execution_id); - + int prepare_alter_table_arg(const ObPrepareAlterTableArgParam ¶m, + const ObTableSchema *target_table_schema, + obrpc::ObAlterTableArg &alter_table_arg); private: class DDLIdling : public ObThreadIdling { @@ -153,6 +233,19 @@ private: static const int64_t DDL_TASK_SCAN_PERIOD = 60 * 1000L * 1000L; // 60s ObDDLScheduler &ddl_scheduler_; }; + + class HeartBeatCheckTask : public common::ObTimerTask + { + public: + explicit HeartBeatCheckTask(ObDDLScheduler &ddl_scheduler): ddl_scheduler_(ddl_scheduler) {} + virtual ~HeartBeatCheckTask() {}; + int schedule(int tg_id); + private: + void runTimerTask() override; + private: + static const int64_t DDL_TASK_CHECK_PERIOD = 30 * 1000L * 1000L; // 30s + ObDDLScheduler &ddl_scheduler_; + }; private: int insert_task_record( common::ObISQLClient &proxy, @@ -240,7 +333,6 @@ private: const obrpc::ObDDLArg *arg, ObIAllocator &allocator, ObDDLTaskRecord &task_record); - int schedule_build_index_task( const ObDDLTaskRecord &task_record); int schedule_drop_primary_key_task(const ObDDLTaskRecord &task_record); @@ -267,7 +359,9 @@ private: DDLIdling idler_; common::ObConcurrentFIFOAllocator allocator_; ObDDLTaskQueue task_queue_; + ObDDLTaskHeartBeatMananger manager_reg_heart_beat_task_; DDLScanTask scan_task_; + HeartBeatCheckTask heart_beat_check_task_; }; template diff --git a/src/rootserver/ddl_task/ob_ddl_task.cpp b/src/rootserver/ddl_task/ob_ddl_task.cpp index 5c4569d43a..4b5510362c 100644 --- a/src/rootserver/ddl_task/ob_ddl_task.cpp +++ b/src/rootserver/ddl_task/ob_ddl_task.cpp @@ -660,6 +660,9 @@ int ObDDLTask::get_ddl_type_str(const int64_t ddl_type, const char *&ddl_type_st case DDL_TABLE_REDEFINITION: ddl_type_str = "table redefinition"; break; + case DDL_DIRECT_LOAD: + ddl_type_str = "direct load"; + break; case DDL_MODIFY_AUTO_INCREMENT: ddl_type_str = "modify auto increment"; break; @@ -889,8 +892,9 @@ int ObDDLTask::switch_status(ObDDLTaskStatus new_status, const bool enable_flt, } if (OB_CANCELED == real_ret_code) { - (void)ObDDLTaskRecordOperator::kill_task_inner_sql(root_service->get_sql_proxy(), - trace_id_, tenant_id_, sql_exec_addr_); // ignore return code + // (void)ObDDLTaskRecordOperator::kill_task_inner_sql(root_service->get_sql_proxy(), + // trace_id_, tenant_id_, sql_exec_addr_); // ignore return code + LOG_WARN("ddl_task switch_status kill_task_inner_sql"); } } return ret; @@ -2633,6 +2637,42 @@ int ObDDLTaskRecordOperator::get_all_record( return ret; } +int ObDDLTaskRecordOperator::check_task_id_exist(common::ObMySQLProxy &proxy, const int64_t task_id, bool &exist) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!proxy.is_inited())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(proxy.is_inited())); + } else { + ObSqlString sql_string; + SMART_VAR(ObMySQLProxy::MySQLResult, res) { + sqlclient::ObMySQLResult *result = NULL; + if (OB_FAIL(sql_string.assign_fmt("SELECT count(*) as have FROM %s WHERE task_id=%lu", OB_ALL_VIRTUAL_DDL_TASK_STATUS_TNAME, task_id))) { + LOG_WARN("assign sql string failed", K(ret)); + } else if (OB_FAIL(proxy.read(res, sql_string.ptr()))) { + LOG_WARN("query ddl task record failed", K(ret), K(sql_string)); + } else if (OB_ISNULL((result = res.get_result()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get sql result", K(ret), KP(result)); + } else { + int64_t have = 0; + int64_t cnt = 0; + while (OB_SUCC(ret) && OB_SUCC(result->next())) { + EXTRACT_INT_FIELD_MYSQL(*result, "have", have, uint64_t); + cnt++; + } + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } + if (OB_SUCC(ret)) { + exist = (1 == cnt && have >= 1); + } + } + } + } + return ret; +} + int ObDDLTaskRecordOperator::to_hex_str(const ObString &src, ObSqlString &dst) { int ret = OB_SUCCESS; @@ -2821,7 +2861,11 @@ int ObDDLTaskRecordOperator::select_for_update( ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get sql result", K(ret), KP(result)); } else if (OB_FAIL(result->next())) { - LOG_WARN("fail to get next row", K(ret)); + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("fail to get next row", K(ret)); + } } else { EXTRACT_INT_FIELD_MYSQL(*result, "status", task_status, int64_t); EXTRACT_INT_FIELD_MYSQL(*result, "execution_id", execution_id, int64_t); diff --git a/src/rootserver/ddl_task/ob_ddl_task.h b/src/rootserver/ddl_task/ob_ddl_task.h index 43ccff0730..9ecc32cc61 100644 --- a/src/rootserver/ddl_task/ob_ddl_task.h +++ b/src/rootserver/ddl_task/ob_ddl_task.h @@ -175,6 +175,10 @@ public: common::ObMySQLProxy &proxy, common::ObIAllocator &allocator, common::ObIArray &records); + static int check_task_id_exist( + common::ObMySQLProxy &proxy, + const int64_t task_id, + bool &exist); static int check_is_adding_constraint( common::ObMySQLProxy *proxy, @@ -385,6 +389,7 @@ public: virtual bool need_retry() const { return need_retry_; }; share::ObDDLType get_task_type() const { return task_type_; } void set_not_running() { ATOMIC_SET(&is_running_, false); } + void set_task_status(const share::ObDDLTaskStatus new_status) {task_status_ = new_status; } bool try_set_running() { return !ATOMIC_CAS(&is_running_, false, true); } uint64_t get_tenant_id() const { return tenant_id_; } uint64_t get_object_id() const { return object_id_; } @@ -400,10 +405,12 @@ public: int64_t get_task_version() const { return task_version_; } int64_t get_execution_id() const { return execution_id_; } int64_t get_parallelism() const { return parallelism_; } + static int deep_copy_table_arg(common::ObIAllocator &allocator, + const obrpc::ObDDLArg &source_arg, + obrpc::ObDDLArg &dest_arg); void set_longops_stat(share::ObDDLLongopsStat *longops_stat) { longops_stat_ = longops_stat; } share::ObDDLLongopsStat *get_longops_stat() const { return longops_stat_; } int64_t get_cluster_version() const { return cluster_version_; } - static int deep_copy_table_arg(common::ObIAllocator &allocator, const obrpc::ObDDLArg &source_arg, obrpc::ObDDLArg &dest_arg); static int fetch_new_task_id(ObMySQLProxy &sql_proxy, int64_t &new_task_id); virtual int serialize_params_to_message(char *buf, const int64_t buf_size, int64_t &pos) const = 0; virtual int deserlize_params_from_message(const char *buf, const int64_t buf_size, int64_t &pos) = 0; diff --git a/src/rootserver/ddl_task/ob_table_redefinition_task.cpp b/src/rootserver/ddl_task/ob_table_redefinition_task.cpp index c10728a0a7..6d1505fa92 100644 --- a/src/rootserver/ddl_task/ob_table_redefinition_task.cpp +++ b/src/rootserver/ddl_task/ob_table_redefinition_task.cpp @@ -31,7 +31,8 @@ using namespace oceanbase::rootserver; using namespace oceanbase::obrpc; ObTableRedefinitionTask::ObTableRedefinitionTask() - : ObDDLRedefinitionTask(ObDDLType::DDL_TABLE_REDEFINITION), has_rebuild_index_(false), has_rebuild_constraint_(false), has_rebuild_foreign_key_(false), allocator_(lib::ObLabel("RedefTask")) + : ObDDLRedefinitionTask(ObDDLType::DDL_TABLE_REDEFINITION), has_rebuild_index_(false), has_rebuild_constraint_(false), has_rebuild_foreign_key_(false), allocator_(lib::ObLabel("RedefTask")), + is_copy_indexes_(true), is_copy_triggers_(true), is_copy_constraints_(true), is_copy_foreign_keys_(true), is_ignore_errors_(false), is_do_finish_(false) { } @@ -92,7 +93,7 @@ int ObTableRedefinitionTask::init(const ObDDLTaskRecord &task_record) ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), K(task_record)); } else if (OB_FAIL(deserlize_params_from_message(task_record.message_.ptr(), task_record.message_.length(), pos))) { - LOG_WARN("deserialize params from message failed", K(ret)); + LOG_WARN("deserialize params from message failed", K(ret), K(task_record.message_), K(common::lbt())); } else if (OB_FAIL(set_ddl_stmt_str(task_record.ddl_stmt_str_))) { LOG_WARN("set ddl stmt str failed", K(ret)); } else { @@ -135,20 +136,50 @@ int ObTableRedefinitionTask::update_complete_sstable_job_status(const common::Ob LOG_WARN("ObTableRedefinitionTask has not been inited", K(ret)); } else if (ObDDLTaskStatus::CHECK_TABLE_EMPTY == task_status_) { check_table_empty_job_ret_code_ = ret_code; - } else if (OB_UNLIKELY(snapshot_version_ != snapshot_version)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("error unexpected, snapshot version is not equal", K(ret), K(snapshot_version_), K(snapshot_version)); - } else if (execution_id < execution_id_) { - LOG_INFO("receive a mismatch execution result, ignore", K(ret_code), K(execution_id), K(execution_id_)); } else { - complete_sstable_job_ret_code_ = ret_code; - execution_id_ = execution_id; // update ObTableRedefinitionTask::execution_id_ from ObDDLRedefinitionSSTableBuildTask::execution_id_ - LOG_INFO("table redefinition task callback", K(complete_sstable_job_ret_code_), K(execution_id_)); + switch(task_type_) { + case ObDDLType::DDL_DIRECT_LOAD: { + complete_sstable_job_ret_code_ = ret_code; + LOG_INFO("table redefinition task callback", K(complete_sstable_job_ret_code_)); + break; + } + default : { + if (OB_UNLIKELY(snapshot_version_ != snapshot_version)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error unexpected, snapshot version is not equal", K(ret), K(snapshot_version_), K(snapshot_version)); + } else if (execution_id < execution_id_) { + LOG_INFO("receive a mismatch execution result, ignore", K(ret_code), K(execution_id), K(execution_id_)); + } else { + complete_sstable_job_ret_code_ = ret_code; + execution_id_ = execution_id; // update ObTableRedefinitionTask::execution_id_ from ObDDLRedefinitionSSTableBuildTask::execution_id_ + LOG_INFO("table redefinition task callback", K(complete_sstable_job_ret_code_), K(execution_id_)); + } + break; + } + } } return ret; } int ObTableRedefinitionTask::send_build_replica_request() +{ + int ret = OB_SUCCESS; + switch (task_type_) { + case DDL_DIRECT_LOAD: { + // do nothing + break; + } + default: { + if (send_build_replica_request_by_sql()) { + LOG_WARN("failed to send build replica request", K(ret)); + } + break; + } + } + return ret; +} + +int ObTableRedefinitionTask::send_build_replica_request_by_sql() { int ret = OB_SUCCESS; bool modify_autoinc = false; @@ -298,8 +329,8 @@ int ObTableRedefinitionTask::table_redefinition(const ObDDLTaskStatus next_task_ if (is_build_replica_end) { ret = complete_sstable_job_ret_code_; if (OB_SUCC(ret)) { - if (OB_FAIL(check_data_dest_tables_columns_checksum(execution_id_))) { - LOG_WARN("fail to check the columns checksum of data table and destination table", K(ret)); + if (OB_FAIL(replica_end_check(ret))) { + LOG_WARN("fail to check", K(ret)); } } if (OB_FAIL(switch_status(next_task_status, true, ret))) { @@ -309,6 +340,23 @@ int ObTableRedefinitionTask::table_redefinition(const ObDDLTaskStatus next_task_ return ret; } +int ObTableRedefinitionTask::replica_end_check(const int ret_code) +{ + int ret = OB_SUCCESS; + switch(task_type_) { + case DDL_DIRECT_LOAD : { + break; + } + default : { + if (OB_FAIL(check_data_dest_tables_columns_checksum(execution_id_))) { + LOG_WARN("fail to check the columns checksum of data table and destination table", K(ret)); + } + break; + } + } + return ret; +} + int ObTableRedefinitionTask::copy_table_indexes() { int ret = OB_SUCCESS; @@ -466,7 +514,6 @@ int ObTableRedefinitionTask::copy_table_constraints() } else { LOG_INFO("constraint has already been built"); } - DEBUG_SYNC(TABLE_REDEFINITION_COPY_TABLE_CONSTRAINTS); if (OB_SUCC(ret) && constraint_ids.count() > 0) { for (int64_t i = 0; OB_SUCC(ret) && i < constraint_ids.count(); ++i) { @@ -565,11 +612,11 @@ int ObTableRedefinitionTask::copy_table_dependent_objects(const ObDDLTaskStatus } else if (!dependent_task_result_map_.created() && OB_FAIL(dependent_task_result_map_.create(MAX_DEPEND_OBJECT_COUNT, lib::ObLabel("DepTasMap")))) { LOG_WARN("create dependent task map failed", K(ret)); } else { - if (OB_FAIL(copy_table_indexes())) { + if (get_is_copy_indexes() && OB_FAIL(copy_table_indexes())) { LOG_WARN("copy table indexes failed", K(ret)); - } else if (OB_FAIL(copy_table_constraints())) { + } else if (get_is_copy_constraints() && OB_FAIL(copy_table_constraints())) { LOG_WARN("copy table constraints failed", K(ret)); - } else if (OB_FAIL(copy_table_foreign_keys())) { + } else if (get_is_copy_foreign_keys() && OB_FAIL(copy_table_foreign_keys())) { LOG_WARN("copy table foreign keys failed", K(ret)); } else { // copy triggers(at current, not supported, skip it) @@ -603,6 +650,9 @@ int ObTableRedefinitionTask::copy_table_dependent_objects(const ObDDLTaskStatus finished_task_cnt++; if (error_message.ret_code_ != OB_SUCCESS) { ret = error_message.ret_code_; + if (get_is_ignore_errors()) { + ret = OB_SUCCESS; + } } } } @@ -696,6 +746,31 @@ int ObTableRedefinitionTask::take_effect(const ObDDLTaskStatus next_task_status) return ret; } +int ObTableRedefinitionTask::repending(const share::ObDDLTaskStatus next_task_status) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLRedefinitionTask has not been inited", K(ret)); + } else { + switch (task_type_) { + case DDL_DIRECT_LOAD: + if (get_is_do_finish()) { + if (OB_FAIL(switch_status(next_task_status, true, ret))) { + LOG_WARN("fail to switch status", K(ret)); + } + } + break; + default: + if (OB_FAIL(switch_status(next_task_status, true, ret))) { + LOG_WARN("fail to switch status", K(ret)); + } + break; + } + } + return ret; +} + int ObTableRedefinitionTask::process() { int ret = OB_SUCCESS; @@ -718,10 +793,15 @@ int ObTableRedefinitionTask::process() } break; case ObDDLTaskStatus::LOCK_TABLE: - if (OB_FAIL(lock_table(ObDDLTaskStatus::CHECK_TABLE_EMPTY))) { + if (OB_FAIL(lock_table(ObDDLTaskStatus::REPENDING))) { LOG_WARN("fail to lock table", K(ret)); } break; + case ObDDLTaskStatus::REPENDING: + if (OB_FAIL(repending(ObDDLTaskStatus::CHECK_TABLE_EMPTY))) { + LOG_WARN("fail to repending", K(ret)); + } + break; case ObDDLTaskStatus::CHECK_TABLE_EMPTY: if (OB_FAIL(check_table_empty(ObDDLTaskStatus::REDEFINITION))) { LOG_WARN("fail to check table empty", K(ret)); @@ -786,6 +866,123 @@ int ObTableRedefinitionTask::check_modify_autoinc(bool &modify_autoinc) return ret; } +int64_t ObTableRedefinitionTask::get_serialize_param_size() const +{ + int8_t copy_indexes = static_cast(is_copy_indexes_); + int8_t copy_triggers = static_cast(is_copy_triggers_); + int8_t copy_constraints = static_cast(is_copy_constraints_); + int8_t copy_foreign_keys = static_cast(is_copy_foreign_keys_); + int8_t ignore_errors = static_cast(is_ignore_errors_); + int8_t do_finish = static_cast(is_do_finish_); + return alter_table_arg_.get_serialize_size() + serialization::encoded_length_i64(task_version_) + + serialization::encoded_length_i64(parallelism_) + serialization::encoded_length_i64(cluster_version_) + + serialization::encoded_length_i8(copy_indexes) + serialization::encoded_length_i8(copy_triggers) + + serialization::encoded_length_i8(copy_constraints) + serialization::encoded_length_i8(copy_foreign_keys) + + serialization::encoded_length_i8(ignore_errors) + serialization::encoded_length_i8(do_finish); +} + +int ObTableRedefinitionTask::serialize_params_to_message(char *buf, const int64_t buf_len, int64_t &pos) const +{ + int ret = OB_SUCCESS; + int8_t copy_indexes = static_cast(is_copy_indexes_); + int8_t copy_triggers = static_cast(is_copy_triggers_); + int8_t copy_constraints = static_cast(is_copy_constraints_); + int8_t copy_foreign_keys = static_cast(is_copy_foreign_keys_); + int8_t ignore_errors = static_cast(is_ignore_errors_); + int8_t do_finish = static_cast(is_do_finish_); + if (OB_UNLIKELY(nullptr == buf || buf_len <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), KP(buf), K(buf_len)); + } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, task_version_))) { + LOG_WARN("fail to serialize task version", K(ret), K(task_version_)); + } else if (OB_FAIL(alter_table_arg_.serialize(buf, buf_len, pos))) { + LOG_WARN("serialize table arg failed", K(ret)); + } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, parallelism_))) { + LOG_WARN("fail to serialize parallelism_", K(ret)); + } else if (OB_FAIL(serialization::encode_i64(buf, buf_len, pos, cluster_version_))) { + LOG_WARN("fail to serialize parallelism_", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, copy_indexes))) { + LOG_WARN("fail to serialize is_copy_indexes", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, copy_triggers))) { + LOG_WARN("fail to serialize is_copy_triggers", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, copy_constraints))) { + LOG_WARN("fail to serialize is_copy_constraints", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, copy_foreign_keys))) { + LOG_WARN("fail to serialize is_copy_foreign_keys", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, ignore_errors))) { + LOG_WARN("fail to serialize is_ignore_errors", K(ret)); + } else if (OB_FAIL(serialization::encode_i8(buf, buf_len, pos, do_finish))) { + LOG_WARN("fail to serialize is_do_finish"); + } + return ret; +} + +int ObTableRedefinitionTask::deserlize_params_from_message(const char *buf, const int64_t data_len, int64_t &pos) +{ + int ret = OB_SUCCESS; + int8_t copy_indexes = 0; + int8_t copy_triggers = 0; + int8_t copy_constraints = 0; + int8_t copy_foreign_keys = 0; + int8_t ignore_errors = 0; + int8_t do_finish = 0; + obrpc::ObAlterTableArg tmp_arg; + if (OB_UNLIKELY(nullptr == buf || data_len <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), KP(buf), K(data_len)); + } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, &task_version_))) { + LOG_WARN("fail to deserialize task version", K(ret)); + } else if (OB_FAIL(tmp_arg.deserialize(buf, data_len, pos))) { + LOG_WARN("serialize table failed", K(ret)); + } else if (OB_FAIL(deep_copy_table_arg(allocator_, tmp_arg, alter_table_arg_))) { + LOG_WARN("deep copy table arg failed", K(ret)); + } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, ¶llelism_))) { + LOG_WARN("fail to deserialize parallelism", K(ret)); + } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, &cluster_version_))) { + LOG_WARN("fail to deserialize cluster_version", K(ret)); + } else if (pos < data_len) { + if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, ©_indexes))) { + LOG_WARN("fail to deserialize is_copy_indexes_", K(ret)); + } else if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, ©_triggers))) { + LOG_WARN("fail to deserialize is_copy_triggers_", K(ret)); + } else if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, ©_constraints))) { + LOG_WARN("fail to deserialize is_copy_constraints_", K(ret)); + } else if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, ©_foreign_keys))) { + LOG_WARN("fail to deserialize is_copy_foreign_keys_", K(ret)); + } else if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, &ignore_errors))) { + LOG_WARN("fail to deserialize is_ignore_errors_", K(ret)); + } else if (OB_FAIL(serialization::decode_i8(buf, data_len, pos, &do_finish))) { + LOG_WARN("fail to deserialize is_do_finish_", K(ret)); + } else { + is_copy_indexes_ = static_cast(copy_indexes); + is_copy_triggers_ = static_cast(copy_triggers); + is_copy_constraints_ = static_cast(copy_constraints); + is_copy_foreign_keys_ = static_cast(copy_foreign_keys); + is_ignore_errors_ = static_cast(ignore_errors); + is_do_finish_ = static_cast(do_finish); + } + } + return ret; +} + +int ObTableRedefinitionTask::assign(const ObTableRedefinitionTask *table_redef_task) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(deep_copy_table_arg(allocator_, table_redef_task->alter_table_arg_, alter_table_arg_))) { + LOG_WARN("assign alter_table_arg failed", K(ret)); + } else { + task_version_ = table_redef_task->task_version_; + parallelism_ = table_redef_task->parallelism_; + set_is_copy_indexes(table_redef_task->get_is_copy_indexes()); + set_is_copy_triggers(table_redef_task->get_is_copy_triggers()); + set_is_copy_constraints(table_redef_task->get_is_copy_constraints()); + set_is_copy_foreign_keys(table_redef_task->get_is_copy_foreign_keys()); + set_is_ignore_errors(table_redef_task->get_is_ignore_errors()); + set_is_do_finish(table_redef_task->get_is_do_finish()); + } + return ret; +} + int ObTableRedefinitionTask::collect_longops_stat(ObLongopsValue &value) { int ret = OB_SUCCESS; diff --git a/src/rootserver/ddl_task/ob_table_redefinition_task.h b/src/rootserver/ddl_task/ob_table_redefinition_task.h index 6d5a49fcbf..715466bd85 100644 --- a/src/rootserver/ddl_task/ob_table_redefinition_task.h +++ b/src/rootserver/ddl_task/ob_table_redefinition_task.h @@ -46,6 +46,16 @@ public: const int64_t execution_id, const int ret_code, const ObDDLTaskInfo &addition_info) override; + inline void set_is_copy_indexes(const bool is_copy_indexes) {is_copy_indexes_ = is_copy_indexes;} + inline void set_is_copy_triggers(const bool is_copy_triggers) {is_copy_triggers_ = is_copy_triggers;} + inline void set_is_copy_constraints(const bool is_copy_constraints) {is_copy_constraints_ = is_copy_constraints;} + inline void set_is_copy_foreign_keys(const bool is_copy_foreign_keys) {is_copy_foreign_keys_ = is_copy_foreign_keys;} + inline void set_is_ignore_errors(const bool is_ignore_errors) {is_ignore_errors_ = is_ignore_errors;} + inline void set_is_do_finish(const bool is_do_finish) {is_do_finish_ = is_do_finish;} + virtual int serialize_params_to_message(char *buf, const int64_t buf_len, int64_t &pos) const override; + virtual int deserlize_params_from_message(const char *buf, const int64_t data_len, int64_t &pos) override; + virtual int64_t get_serialize_param_size() const override; + int assign(const ObTableRedefinitionTask *table_redef_task); virtual int collect_longops_stat(share::ObLongopsValue &value) override; virtual bool support_longops_monitoring() const override { return true; } virtual void flt_set_task_span_tag() const override; @@ -54,13 +64,22 @@ protected: int table_redefinition(const share::ObDDLTaskStatus next_task_status); int copy_table_dependent_objects(const share::ObDDLTaskStatus next_task_status); int take_effect(const share::ObDDLTaskStatus next_task_status); + int repending(const share::ObDDLTaskStatus next_task_status); private: + inline bool get_is_copy_indexes() const {return is_copy_indexes_;} + inline bool get_is_copy_triggers() const {return is_copy_triggers_;} + inline bool get_is_copy_constraints() const {return is_copy_constraints_;} + inline bool get_is_copy_foreign_keys() const {return is_copy_foreign_keys_;} + inline bool get_is_ignore_errors() const {return is_ignore_errors_;} + inline bool get_is_do_finish() const {return is_do_finish_;} int copy_table_indexes(); int copy_table_constraints(); int copy_table_foreign_keys(); int send_build_replica_request(); + int send_build_replica_request_by_sql(); int check_build_replica_timeout(); int check_build_replica_end(bool &is_end); + int replica_end_check(const int ret_code); int check_modify_autoinc(bool &modify_autoinc); int check_use_heap_table_ddl_plan(bool &use_heap_table_ddl_plan); private: @@ -69,6 +88,12 @@ private: bool has_rebuild_constraint_; bool has_rebuild_foreign_key_; common::ObArenaAllocator allocator_; + bool is_copy_indexes_; + bool is_copy_triggers_; + bool is_copy_constraints_; + bool is_copy_foreign_keys_; + bool is_ignore_errors_; + bool is_do_finish_; }; } // end namespace rootserver diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index a856a8a601..78d0200b41 100644 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -9120,6 +9120,8 @@ const char* ObDDLService::ddl_type_str(const ObDDLType ddl_type) str = "column redefinition"; } else if (DDL_TABLE_REDEFINITION == ddl_type) { str = "table redefinition"; + } else if (DDL_DIRECT_LOAD == ddl_type) { + str = "direct load"; } else if (DDL_MODIFY_AUTO_INCREMENT == ddl_type) { str = "modify auto_increment"; } else if (DDL_CONVERT_TO_CHARACTER == ddl_type) { @@ -10923,6 +10925,135 @@ int ObDDLService::do_offline_ddl_in_trans(obrpc::ObAlterTableArg &alter_table_ar return ret; } +int ObDDLService::create_hidden_table( + const obrpc::ObCreateHiddenTableArg &create_hidden_table_arg, + obrpc::ObCreateHiddenTableRes &res) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = create_hidden_table_arg.tenant_id_; + const int64_t table_id = create_hidden_table_arg.table_id_; + const uint64_t dest_tenant_id = create_hidden_table_arg.dest_tenant_id_; + ObRootService *root_service = GCTX.root_service_; + bool bind_tablets = true; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *orig_table_schema = NULL; + const ObDatabaseSchema *orig_database_schema = nullptr; + common::ObArenaAllocator allocator_for_redef(lib::ObLabel("StartRedefTable")); + if (OB_UNLIKELY(!create_hidden_table_arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("create_hidden_table_arg is invalid", K(ret), K(create_hidden_table_arg)); + } else if (OB_ISNULL(root_service)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error unexpected, root service must not be nullptr", K(ret)); + } else if (OB_FAIL(check_inner_stat())) { + LOG_WARN("variable is not init", K(ret)); + } else if (OB_FAIL(get_tenant_schema_guard_with_version_in_inner_table(tenant_id, schema_guard))) { + LOG_WARN("fail to get schema guard with version in inner table", K(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, orig_table_schema))) { + LOG_WARN("fail to get table schema", K(ret)); + } else if (OB_ISNULL(orig_table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("orig table schema is nullptr", K(ret)); + } else if (OB_FAIL(schema_guard.get_database_schema(tenant_id, orig_table_schema->get_database_id(), orig_database_schema))) { + LOG_WARN("fail to get orig database schema", K(ret)); + } else if (OB_ISNULL(orig_database_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("orig_database_schema is nullptr", K(ret)); + } else { + HEAP_VAR(ObTableSchema, new_table_schema) { + ObDDLOperator ddl_operator(*schema_service_, *sql_proxy_); + if (OB_FAIL(new_table_schema.assign(*orig_table_schema))) { + LOG_WARN("fail to assign schema", K(ret)); + } else { + ObDDLSQLTransaction trans(schema_service_); + common::ObArenaAllocator allocator; + ObDDLTaskRecord task_record; + int64_t refreshed_schema_version = 0; + new_table_schema.set_tenant_id(dest_tenant_id); + new_table_schema.set_table_state_flag(ObTableStateFlag::TABLE_STATE_OFFLINE_DDL); + if (orig_table_schema->get_table_state_flag() == ObTableStateFlag::TABLE_STATE_OFFLINE_DDL) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("not in offline ddl, create hidden table fail", K(ret)); + } else if (OB_FAIL(schema_guard.get_schema_version(tenant_id, refreshed_schema_version))) { + LOG_WARN("failed to get tenant schema version", KR(ret), K(tenant_id)); + } else if (OB_FAIL(trans.start(sql_proxy_, tenant_id, refreshed_schema_version))) { + LOG_WARN("start transaction failed", KR(ret), K(tenant_id), K(refreshed_schema_version)); + } else if (OB_FAIL(create_user_hidden_table( + *orig_table_schema, + new_table_schema, + nullptr, + bind_tablets, + schema_guard, + ddl_operator, + trans, + allocator))) { + LOG_WARN("fail to create hidden table", K(ret)); + } else { + LOG_INFO("create hidden table success!"); + } + if (OB_SUCC(ret)) { + HEAP_VAR(obrpc::ObAlterTableArg, alter_table_arg) { + ObPrepareAlterTableArgParam param; + if (OB_FAIL(param.init(create_hidden_table_arg.session_id_, + create_hidden_table_arg.sql_mode_, + create_hidden_table_arg.ddl_stmt_str_, + orig_table_schema->get_table_name_str(), + orig_database_schema->get_database_name_str(), + orig_database_schema->get_database_name_str(), + create_hidden_table_arg.tz_info_, + create_hidden_table_arg.tz_info_wrap_, + create_hidden_table_arg.nls_formats_))) { + LOG_WARN("param init failed", K(ret)); + } else if (OB_FAIL(root_service->get_ddl_scheduler().prepare_alter_table_arg(param, &new_table_schema, alter_table_arg))) { + LOG_WARN("prepare alter table arg fail", K(ret)); + } else { + LOG_DEBUG("alter table arg preparation complete!", K(ret), K(alter_table_arg)); + ObCreateDDLTaskParam param(tenant_id, + create_hidden_table_arg.ddl_type_, + orig_table_schema, + &new_table_schema, + table_id, + orig_table_schema->get_schema_version(), + create_hidden_table_arg.parallelism_, + &allocator_for_redef, + &alter_table_arg); + if (OB_FAIL(root_service->get_ddl_scheduler().create_ddl_task(param, trans, task_record))) { + LOG_WARN("submit ddl task failed", K(ret)); + } else { + res.tenant_id_ = tenant_id; + res.table_id_ = table_id; + res.dest_tenant_id_ = dest_tenant_id; + res.dest_table_id_ = task_record.target_object_id_; + res.schema_version_ = task_record.schema_version_; + res.trace_id_ = task_record.trace_id_; + res.task_id_ = task_record.task_id_; + } + } + } + if (trans.is_started()) { + int temp_ret = OB_SUCCESS; + if (OB_SUCCESS != (temp_ret = trans.end(OB_SUCC(ret)))) { + LOG_WARN("trans end failed", "is_commit", OB_SUCC(ret), K(temp_ret)); + ret = (OB_SUCC(ret)) ? temp_ret : ret; + } + } + if (OB_SUCC(ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_FAIL(publish_schema(tenant_id))) { + LOG_WARN("publish_schema failed", K(ret)); + } else if (OB_TMP_FAIL(root_service->get_ddl_scheduler().schedule_ddl_task(task_record))) { + LOG_WARN("fail to schedule ddl task", K(tmp_ret), K(task_record)); + } else { + LOG_INFO("schedule ddl task success"); + } + } + } + } + } + } + return ret; +} + int ObDDLService::get_and_check_table_schema( const obrpc::ObAlterTableArg &alter_table_arg, ObSchemaGetterGuard &schema_guard, @@ -13364,6 +13495,10 @@ int ObDDLService::create_user_hidden_table(const ObTableSchema &orig_table_schem trans, schema_guard, is_add_identity_column ? sequence_ddl_arg : nullptr))) { + // alter table t1 modify c2 int generated always as identity; + // alter table t1 add c2 int generated by default on null as identity; + // alter table t1 add column c6 datetime(6) default '20180224' after c2; + // alter table t1 add column c1_5 int generated always as identity after c1; LOG_WARN("failed to create sequence in create table", K(ret)); } else if (OB_FAIL(build_aux_lob_table_schema_if_need(hidden_table_schema, aux_table_schemas))) { LOG_WARN("failed to build_aux_lob_table_schema_if_need", K(ret), K(hidden_table_schema)); diff --git a/src/rootserver/ob_ddl_service.h b/src/rootserver/ob_ddl_service.h index fcdd4d7896..5458d40a26 100644 --- a/src/rootserver/ob_ddl_service.h +++ b/src/rootserver/ob_ddl_service.h @@ -237,6 +237,8 @@ public: const share::schema::ObTableType expected_table_type, share::schema::ObSchemaGetterGuard &guard, const share::schema::ObTableSchema **table_schema); + int create_hidden_table(const obrpc::ObCreateHiddenTableArg &create_hidden_table_arg, + obrpc::ObCreateHiddenTableRes &res); virtual int update_index_status(const obrpc::ObUpdateIndexStatusArg &arg); int upgrade_table_schema(const obrpc::ObUpgradeTableSchemaArg &arg); diff --git a/src/rootserver/ob_root_service.cpp b/src/rootserver/ob_root_service.cpp index 700914ae7a..a7b51e0d73 100644 --- a/src/rootserver/ob_root_service.cpp +++ b/src/rootserver/ob_root_service.cpp @@ -12,6 +12,7 @@ #define USING_LOG_PREFIX RS +#include "observer/ob_server.h" #include "rootserver/ob_root_service.h" #include "share/ob_define.h" @@ -91,6 +92,7 @@ #include "share/ob_max_id_fetcher.h" //ObMaxIdFetcher #include "observer/ob_service.h" #include "storage/ob_file_system_router.h" +#include "storage/ddl/ob_ddl_heart_beat_task.h" #include "rootserver/freeze/ob_major_freeze_helper.h" #include "share/restore/ob_physical_restore_table_operator.h"//ObPhysicalRestoreTableOperator #include "share/ob_cluster_event_history_table_operator.h"//CLUSTER_EVENT_INSTANCE @@ -954,7 +956,6 @@ int ObRootService::init(ObServerConfig &config, schema_service_))) { FLOG_WARN("init disaster recovery task mgr failed", KR(ret)); } - if (OB_SUCC(ret)) { inited_ = true; FLOG_INFO("[ROOTSERVICE_NOTICE] init rootservice success", KR(ret), K_(inited)); @@ -3842,6 +3843,159 @@ int ObRootService::precheck_interval_part(const obrpc::ObAlterTableArg &arg) return ret; } +int ObRootService::create_hidden_table(const obrpc::ObCreateHiddenTableArg &arg, obrpc::ObCreateHiddenTableRes &res) +{ + LOG_DEBUG("receive create hidden table arg", K(arg)); + int ret = OB_SUCCESS; + const uint64_t tenant_id = arg.tenant_id_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_service_.create_hidden_table(arg, res))) { + LOG_WARN("do create hidden table in trans failed", K(ret)); + } + return ret; +} + +int ObRootService::update_ddl_task_active_time(const obrpc::ObUpdateDDLTaskActiveTimeArg &arg) +{ + LOG_DEBUG("receive recv ddl task status arg", K(arg)); + int ret = OB_SUCCESS; + const int64_t task_id = arg.task_id_; + const uint64_t tenant_id = arg.tenant_id_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_scheduler_.update_ddl_task_active_time(task_id))) { + LOG_WARN("fail to set RegTaskTime map", K(ret), K(task_id)); + } + return ret; +} + +int ObRootService::abort_redef_table(const obrpc::ObAbortRedefTableArg &arg) +{ + LOG_DEBUG("receive abort redef table arg", K(arg)); + int ret = OB_SUCCESS; + const int64_t task_id = arg.task_id_; + const uint64_t tenant_id = arg.tenant_id_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_scheduler_.abort_redef_table(task_id))) { + LOG_WARN("cancel task failed", K(ret), K(task_id)); + } + return ret; +} + +int ObRootService::finish_redef_table(const obrpc::ObFinishRedefTableArg &arg) +{ + LOG_DEBUG("receive finish redef table arg", K(arg)); + int ret = OB_SUCCESS; + const int64_t task_id = arg.task_id_; + const uint64_t tenant_id = arg.tenant_id_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_scheduler_.finish_redef_table(task_id, tenant_id))) { + LOG_WARN("failed to finish redef table", K(ret), K(task_id), K(tenant_id)); + } + return ret; +} + +int ObRootService::copy_table_dependents(const obrpc::ObCopyTableDependentsArg &arg) +{ + LOG_DEBUG("receive copy table dependents arg", K(arg)); + int ret = OB_SUCCESS; + const int64_t task_id = arg.task_id_; + const uint64_t tenant_id = arg.tenant_id_; + const bool is_copy_indexes = arg.copy_indexes_; + const bool is_copy_triggers = arg.copy_triggers_; + const bool is_copy_constraints = arg.copy_constraints_; + const bool is_copy_foreign_keys = arg.copy_foreign_keys_; + const bool is_ignore_errors = arg.ignore_errors_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_scheduler_.copy_table_dependents(task_id, + tenant_id, + is_copy_constraints, + is_copy_indexes, + is_copy_triggers, + is_copy_foreign_keys, + is_ignore_errors))) { + LOG_WARN("failed to copy table dependents", K(ret), K(arg)); + } + return ret; +} + +int ObRootService::start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res) +{ + LOG_DEBUG("receive start redef table arg", K(arg)); + int ret = OB_SUCCESS; + const uint64_t tenant_id = arg.orig_tenant_id_; + uint64_t compat_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compat_version))) { + LOG_WARN("fail to get data version", K(ret), K(tenant_id)); + } else if (compat_version < DATA_VERSION_4_1_0_0) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("version 4.0 does not support this operation", K(ret)); + } else if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("not init", K(ret)); + } else if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_FAIL(ddl_scheduler_.start_redef_table(arg, res))) { + LOG_WARN("start redef table failed", K(ret)); + } + return ret; +} + int ObRootService::alter_table(const obrpc::ObAlterTableArg &arg, obrpc::ObAlterTableRes &res) { LOG_DEBUG("receive alter table arg", K(arg)); diff --git a/src/rootserver/ob_root_service.h b/src/rootserver/ob_root_service.h index d30ea16a50..2e533494fe 100644 --- a/src/rootserver/ob_root_service.h +++ b/src/rootserver/ob_root_service.h @@ -201,7 +201,7 @@ public: DISALLOW_COPY_AND_ASSIGN(ObStatusChangeCallback); }; -class ObServerChangeCallback : public ObIServerChangeCallback + class ObServerChangeCallback : public ObIServerChangeCallback { public: explicit ObServerChangeCallback(ObRootService &root_service) : root_service_(root_service) {} @@ -287,7 +287,7 @@ class ObServerChangeCallback : public ObIServerChangeCallback ObRootService &root_service_; }; -class ObUpdateAllServerConfigTask : public common::ObAsyncTimerTask + class ObUpdateAllServerConfigTask : public common::ObAsyncTimerTask { public: explicit ObUpdateAllServerConfigTask(ObRootService &root_service); @@ -498,6 +498,12 @@ public: int create_table(const obrpc::ObCreateTableArg &arg, obrpc::ObCreateTableRes &res); int alter_database(const obrpc::ObAlterDatabaseArg &arg); int alter_table(const obrpc::ObAlterTableArg &arg, obrpc::ObAlterTableRes &res); + int start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res); + int copy_table_dependents(const obrpc::ObCopyTableDependentsArg &arg); + int finish_redef_table(const obrpc::ObFinishRedefTableArg &arg); + int abort_redef_table(const obrpc::ObAbortRedefTableArg &arg); + int update_ddl_task_active_time(const obrpc::ObUpdateDDLTaskActiveTimeArg &arg); + int create_hidden_table(const obrpc::ObCreateHiddenTableArg &arg, obrpc::ObCreateHiddenTableRes &res); int execute_ddl_task(const obrpc::ObAlterTableArg &arg, common::ObSArray &obj_ids); int cancel_ddl_task(const obrpc::ObCancelDDLTaskArg &arg); int alter_tablegroup(const obrpc::ObAlterTablegroupArg &arg); diff --git a/src/rootserver/ob_rs_rpc_processor.h b/src/rootserver/ob_rs_rpc_processor.h index 9d23a6e31a..3b548f0896 100644 --- a/src/rootserver/ob_rs_rpc_processor.h +++ b/src/rootserver/ob_rs_rpc_processor.h @@ -309,6 +309,12 @@ DEFINE_RS_RPC_PROCESSOR(obrpc::OB_BROADCAST_DS_ACTION, ObBroadcastDSActionP, bro DEFINE_RS_RPC_PROCESSOR(obrpc::OB_FETCH_LOCATION, ObRpcFetchLocationP, fetch_location(arg_, result_)); DEFINE_RS_RPC_PROCESSOR(obrpc::OB_ADMIN_SET_CONFIG, ObRpcAdminSetConfigP, admin_set_config(arg_)); DEFINE_RS_RPC_PROCESSOR(obrpc::OB_ADMIN_FLUSH_BALANCE_INFO, ObRpcAdminFlushBalanceInfoP, admin_clear_balance_task(arg_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_COPY_TABLE_DEPENDENTS, ObRpcCopyTableDependentsP, copy_table_dependents(arg_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_FINISH_REDEF_TABLE, ObRpcFinishRedefTableP, finish_redef_table(arg_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_ABORT_REDEF_TABLE, ObRpcAbortRedefTableP, abort_redef_table(arg_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_UPDATE_DDL_TASK_ACTIVE_TIME, ObRpcUpdateDDLTaskActiveTimeP, update_ddl_task_active_time(arg_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_CREATE_HIDDEN_TABLE, ObRpcCreateHiddenTableP, create_hidden_table(arg_, result_)); +DEFINE_RS_RPC_PROCESSOR(obrpc::OB_START_REDEF_TABLE, ObRpcStartRedefTableP, start_redef_table(arg_, result_)); // ddl rpc processors DEFINE_DDL_RS_RPC_PROCESSOR(obrpc::OB_COMMIT_ALTER_TENANT_LOCALITY, ObRpcCommitAlterTenantLocalityP, commit_alter_tenant_locality(arg_)); diff --git a/src/share/CMakeLists.txt b/src/share/CMakeLists.txt index f31bdfc087..dbdfbc0aec 100644 --- a/src/share/CMakeLists.txt +++ b/src/share/CMakeLists.txt @@ -233,6 +233,10 @@ ob_set_subtarget(ob_share common_mixed system_variable/ob_system_variable_init.cpp table/ob_table.cpp table/ob_table_rpc_struct.cpp + table/ob_table_load_define.cpp + table/ob_table_load_rpc_struct.cpp + table/ob_table_load_shared_allocator.cpp + table/ob_table_load_row.cpp ) ob_set_subtarget(ob_share tablet diff --git a/src/share/inner_table/ob_inner_table_schema.12201_12250.cpp b/src/share/inner_table/ob_inner_table_schema.12201_12250.cpp index 45d7b63325..9f5b01c9d7 100644 --- a/src/share/inner_table/ob_inner_table_schema.12201_12250.cpp +++ b/src/share/inner_table/ob_inner_table_schema.12201_12250.cpp @@ -9477,6 +9477,21 @@ int ObInnerTableSchema::all_virtual_load_data_stat_schema(ObTableSchema &table_s false); //is_autoincrement } + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("job_type", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + OB_MAX_PARAMETERS_NAME_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + if (OB_SUCC(ret)) { ADD_COLUMN_SCHEMA("table_name", //column_name ++column_id, //column_id @@ -9643,7 +9658,7 @@ int ObInnerTableSchema::all_virtual_load_data_stat_schema(ObTableSchema &table_s } if (OB_SUCC(ret)) { - ADD_COLUMN_SCHEMA("processed_bytes", //column_name + ADD_COLUMN_SCHEMA("parsed_bytes", //column_name ++column_id, //column_id 0, //rowkey_id 0, //index_id @@ -9658,7 +9673,7 @@ int ObInnerTableSchema::all_virtual_load_data_stat_schema(ObTableSchema &table_s } if (OB_SUCC(ret)) { - ADD_COLUMN_SCHEMA("processed_rows", //column_name + ADD_COLUMN_SCHEMA("parsed_rows", //column_name ++column_id, //column_id 0, //rowkey_id 0, //index_id @@ -9746,6 +9761,156 @@ int ObInnerTableSchema::all_virtual_load_data_stat_schema(ObTableSchema &table_s false, //is_nullable false); //is_autoincrement } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("max_allowed_error_rows", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("detected_error_rows", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("coordinator_received_rows", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("coordinator_last_commit_segment_id", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("coordinator_status", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + OB_MAX_PARAMETERS_NAME_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("coordinator_trans_status", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + OB_MAX_PARAMETERS_NAME_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("store_processed_rows", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("store_last_commit_segment_id", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObIntType, //column_type + CS_TYPE_INVALID, //column_collation_type + sizeof(int64_t), //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("store_status", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + OB_MAX_PARAMETERS_NAME_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("store_trans_status", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 0, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + OB_MAX_PARAMETERS_NAME_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } if (OB_SUCC(ret)) { table_schema.get_part_option().set_part_num(1); table_schema.set_part_level(PARTITION_LEVEL_ONE); diff --git a/src/share/inner_table/ob_inner_table_schema_def.py b/src/share/inner_table/ob_inner_table_schema_def.py index c4452b54fc..77d4e89991 100644 --- a/src/share/inner_table/ob_inner_table_schema_def.py +++ b/src/share/inner_table/ob_inner_table_schema_def.py @@ -9870,6 +9870,7 @@ def_table_schema( ('svr_ip', 'varchar:MAX_IP_ADDR_LENGTH'), ('svr_port', 'int'), ('job_id', 'int'), + ('job_type', 'varchar:OB_MAX_PARAMETERS_NAME_LENGTH'), ('table_name', 'varchar:OB_MAX_TABLE_NAME_LENGTH'), ('file_path', 'varchar:MAX_PATH_SIZE'), ('table_column', 'int'), @@ -9881,13 +9882,23 @@ def_table_schema( ('estimated_remaining_time', 'int'), ('total_bytes', 'int'), ('read_bytes', 'int'), - ('processed_bytes', 'int'), - ('processed_rows', 'int'), + ('parsed_bytes', 'int'), + ('parsed_rows', 'int'), ('total_shuffle_task', 'int'), ('total_insert_task', 'int'), ('shuffle_rt_sum', 'int'), ('insert_rt_sum', 'int'), - ('total_wait_secs', 'int') + ('total_wait_secs', 'int'), + ('max_allowed_error_rows', 'int'), + ('detected_error_rows', 'int'), + ('coordinator_received_rows', 'int'), + ('coordinator_last_commit_segment_id', 'int'), + ('coordinator_status', 'varchar:OB_MAX_PARAMETERS_NAME_LENGTH'), + ('coordinator_trans_status', 'varchar:OB_MAX_PARAMETERS_NAME_LENGTH'), + ('store_processed_rows', 'int'), + ('store_last_commit_segment_id', 'int'), + ('store_status', 'varchar:OB_MAX_PARAMETERS_NAME_LENGTH'), + ('store_trans_status', 'varchar:OB_MAX_PARAMETERS_NAME_LENGTH') ], partition_columns = ['svr_ip', 'svr_port'], vtable_route_policy = 'distributed', diff --git a/src/share/ob_common_rpc_proxy.h b/src/share/ob_common_rpc_proxy.h index ee26a9d238..1d3846f613 100644 --- a/src/share/ob_common_rpc_proxy.h +++ b/src/share/ob_common_rpc_proxy.h @@ -65,6 +65,7 @@ public: RPC_S(PRD create_tablegroup, obrpc::OB_CREATE_TABLEGROUP, (ObCreateTablegroupArg), UInt64); RPC_S(PRD create_table, obrpc::OB_CREATE_TABLE, (ObCreateTableArg), ObCreateTableRes); RPC_S(PRD alter_table, obrpc::OB_ALTER_TABLE, (ObAlterTableArg), ObAlterTableRes); + RPC_S(PRD create_hidden_table, obrpc::OB_CREATE_HIDDEN_TABLE, (obrpc::ObCreateHiddenTableArg), ObCreateHiddenTableRes); RPC_S(PRD alter_database, obrpc::OB_ALTER_DATABASE, (ObAlterDatabaseArg)); RPC_S(PRD drop_database, obrpc::OB_DROP_DATABASE, (ObDropDatabaseArg), ObDropDatabaseRes); RPC_S(PRD drop_tablegroup, obrpc::OB_DROP_TABLEGROUP, (ObDropTablegroupArg)); @@ -244,6 +245,11 @@ public: RPC_S(PR5 calc_column_checksum_response, obrpc::OB_CALC_COLUMN_CHECKSUM_RESPONSE, (obrpc::ObCalcColumnChecksumResponseArg)); RPC_S(PR5 build_ddl_single_replica_response, obrpc::OB_DDL_BUILD_SINGLE_REPLICA_RESPONSE, (obrpc::ObDDLBuildSingleReplicaResponseArg)); RPC_S(PR5 cancel_ddl_task, obrpc::OB_CANCEL_DDL_TASK, (obrpc::ObCancelDDLTaskArg)); + RPC_S(PR5 start_redef_table, obrpc::OB_START_REDEF_TABLE, (ObStartRedefTableArg), ObStartRedefTableRes); + RPC_S(PR5 copy_table_dependents, obrpc::OB_COPY_TABLE_DEPENDENTS, (ObCopyTableDependentsArg)); + RPC_S(PR5 finish_redef_table, obrpc::OB_FINISH_REDEF_TABLE, (ObFinishRedefTableArg)); + RPC_S(PR5 abort_redef_table, obrpc::OB_ABORT_REDEF_TABLE, (obrpc::ObAbortRedefTableArg)); + RPC_S(PR5 update_ddl_task_active_time, obrpc::OB_UPDATE_DDL_TASK_ACTIVE_TIME, (obrpc::ObUpdateDDLTaskActiveTimeArg)); RPC_S(PR5 backup_ls_data_res, OB_BACKUP_LS_DATA_RES, (ObBackupTaskRes)); RPC_S(PR5 delete_backup_ls_task_res, OB_DELETE_BACKUP_LS_TASK_RES, (ObBackupTaskRes)); diff --git a/src/share/ob_ddl_common.h b/src/share/ob_ddl_common.h index e9b96cb522..1731566d43 100644 --- a/src/share/ob_ddl_common.h +++ b/src/share/ob_ddl_common.h @@ -50,7 +50,6 @@ enum ObDDLType DDL_MODIFY_AUTO_INCREMENT = 4, DDL_CREATE_INDEX = 5, DDL_DROP_INDEX = 6, - ///< @note Drop schema, and refuse concurrent trans. DDL_DROP_SCHEMA_AVOID_CONCURRENT_TRANS = 500, DDL_DROP_DATABASE = 501, @@ -73,6 +72,8 @@ enum ObDDLType DDL_ADD_COLUMN_OFFLINE = 1008, // only add columns DDL_COLUMN_REDEFINITION = 1009, // only add/drop columns DDL_TABLE_REDEFINITION = 1010, + DDL_DIRECT_LOAD = 1011, + // @note new normal ddl type to be defined here !!! DDL_NORMAL_TYPE = 10001, @@ -118,6 +119,7 @@ enum ObDDLTaskStatus { DROP_SCHEMA = 14, CHECK_TABLE_EMPTY = 15, WAIT_CHILD_TASK_FINISH = 16, + REPENDING = 17, FAIL = 99, SUCCESS = 100 }; diff --git a/src/share/ob_rpc_struct.cpp b/src/share/ob_rpc_struct.cpp index efece29bad..8d3e44045b 100644 --- a/src/share/ob_rpc_struct.cpp +++ b/src/share/ob_rpc_struct.cpp @@ -284,6 +284,407 @@ int ObMergeResourcePoolArg::assign(const ObMergeResourcePoolArg &other) return ret; } +bool ObStartRedefTableArg::is_valid() const +{ + return (OB_INVALID_ID != orig_tenant_id_ && OB_INVALID_ID != orig_table_id_ + && OB_INVALID_ID != target_tenant_id_ && OB_INVALID_ID != target_table_id_ + && share::DDL_INVALID != ddl_type_); +} +int ObStartRedefTableArg::set_nls_formats(const common::ObString *nls_formats) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(nls_formats)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("nls_formats is nullptr", K(ret)); + } else { + char *tmp_ptr[ObNLSFormatEnum::NLS_MAX] = {}; + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; ++i) { + if (OB_ISNULL(tmp_ptr[i] = (char *)allocator_.alloc(nls_formats[i].length()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory!", K(ret), "size: ", nls_formats[i].length()); + } else { + MEMCPY(tmp_ptr[i], nls_formats[i].ptr(), nls_formats[i].length()); + nls_formats_[i].assign_ptr(tmp_ptr[i], nls_formats[i].length()); + } + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; ++i) { + allocator_.free(tmp_ptr[i]); + } + } + } + return ret; +} + +int ObStartRedefTableArg::assign(const ObStartRedefTableArg &arg) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tz_info_.assign(arg.tz_info_))) { + LOG_WARN("tz_info assign failed", K(ret)); + } else if (OB_FAIL(tz_info_wrap_.deep_copy(arg.tz_info_wrap_))) { + LOG_WARN("failed to deep_copy tz info wrap", K(ret), "tz_info_wrap", arg.tz_info_wrap_); + } else if (FALSE_IT(ddl_stmt_str_.assign_ptr(arg.ddl_stmt_str_.ptr(), static_cast(arg.ddl_stmt_str_.length())))) { + // do nothing + } else { + orig_tenant_id_ = arg.orig_tenant_id_; + orig_table_id_ = arg.orig_table_id_; + target_tenant_id_ = arg.target_tenant_id_; + target_table_id_ = arg.target_table_id_; + session_id_ = arg.session_id_; + parallelism_ = arg.parallelism_; + ddl_type_ = arg.ddl_type_; + trace_id_ = arg.trace_id_; + sql_mode_ = arg.sql_mode_; + for (int64_t i = 0; OB_SUCC(ret) && i < common::ObNLSFormatEnum::NLS_MAX; i++) { + nls_formats_[i].assign_ptr(arg.nls_formats_[i].ptr(), static_cast(arg.nls_formats_[i].length())); + } + } + return ret; +} + +int ObStartRedefTableRes::assign(const ObStartRedefTableRes &res) +{ + int ret = OB_SUCCESS; + task_id_ = res.task_id_; + tenant_id_ = res.tenant_id_; + schema_version_ = res.schema_version_; + return ret; +} + +OB_DEF_SERIALIZE(ObStartRedefTableArg) +{ + int ret = OB_SUCCESS; + if (!is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_ENCODE, + orig_tenant_id_, + orig_table_id_, + target_tenant_id_, + target_table_id_, + session_id_, + parallelism_, + ddl_type_, + ddl_stmt_str_, + trace_id_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; i++) { + if (OB_FAIL(nls_formats_[i].serialize(buf, buf_len, pos))) { + LOG_WARN("fail to serialize nls_formats_[i]", K(ret), K(nls_formats_[i])); + } + } + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObStartRedefTableArg) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_DECODE, + orig_tenant_id_, + orig_table_id_, + target_tenant_id_, + target_table_id_, + session_id_, + parallelism_, + ddl_type_, + ddl_stmt_str_, + trace_id_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + ObString tmp_string; + char *tmp_ptr[ObNLSFormatEnum::NLS_MAX] = {}; + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; i++) { + if (OB_FAIL(tmp_string.deserialize(buf, data_len, pos))) { + LOG_WARN("fail to deserialize nls_formats_", K(ret), K(i)); + } else if (OB_ISNULL(tmp_ptr[i] = (char *)allocator_.alloc(tmp_string.length()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory!", K(ret)); + } else { + MEMCPY(tmp_ptr[i], tmp_string.ptr(), tmp_string.length()); + nls_formats_[i].assign_ptr(tmp_ptr[i], tmp_string.length()); + tmp_string.reset(); + } + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; i++) { + allocator_.free(tmp_ptr[i]); + } + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObStartRedefTableArg) +{ + int64_t len = 0; + int ret = OB_SUCCESS; + if (!is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_ADD_LEN, + orig_tenant_id_, + orig_table_id_, + target_tenant_id_, + target_table_id_, + session_id_, + parallelism_, + ddl_type_, + ddl_stmt_str_, + trace_id_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; i++) { + len += nls_formats_[i].get_serialize_size(); + } + } + } + if (OB_FAIL(ret)) { + len = -1; + } + return len; +} + +bool ObCopyTableDependentsArg::is_valid() const +{ + return 0 != task_id_ && OB_INVALID_ID != tenant_id_; +} + +int ObCopyTableDependentsArg::assign(const ObCopyTableDependentsArg &arg) +{ + int ret = OB_SUCCESS; + task_id_ = arg.task_id_; + tenant_id_ = arg.tenant_id_; + copy_indexes_ = arg.copy_indexes_; + copy_triggers_ = arg.copy_triggers_; + copy_constraints_ = arg.copy_constraints_; + copy_foreign_keys_ = arg.copy_foreign_keys_; + ignore_errors_ = arg.ignore_errors_; + return ret; +} + +bool ObFinishRedefTableArg::is_valid() const +{ + return (0 != task_id_ && OB_INVALID_ID != tenant_id_); +} + +int ObFinishRedefTableArg::assign(const ObFinishRedefTableArg &arg) +{ + int ret = OB_SUCCESS; + task_id_ = arg.task_id_; + tenant_id_ = arg.tenant_id_; + return ret; +} + +bool ObAbortRedefTableArg::is_valid() const +{ + return 0 != task_id_ && OB_INVALID_ID != tenant_id_; +} + +int ObAbortRedefTableArg::assign(const ObAbortRedefTableArg &arg) +{ + int ret = OB_SUCCESS; + task_id_ = arg.task_id_; + tenant_id_ = arg.tenant_id_; + return ret; +} + +bool ObUpdateDDLTaskActiveTimeArg::is_valid() const +{ + return 0 != task_id_ && OB_INVALID_ID != tenant_id_; +} + +int ObUpdateDDLTaskActiveTimeArg::assign(const ObUpdateDDLTaskActiveTimeArg &arg) +{ + int ret = OB_SUCCESS; + task_id_ = arg.task_id_; + tenant_id_ = arg.tenant_id_; + return ret; +} + +bool ObCreateHiddenTableArg::is_valid() const +{ + return (OB_INVALID_ID != tenant_id_ + && OB_INVALID_ID != table_id_ + && OB_INVALID_ID != dest_tenant_id_ + && share::DDL_INVALID != ddl_type_); +} + +int ObCreateHiddenTableArg::assign(const ObCreateHiddenTableArg &arg) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tz_info_.assign(arg.tz_info_))) { + LOG_WARN("tz_info assign failed", K(ret)); + } else if (OB_FAIL(tz_info_wrap_.deep_copy(arg.tz_info_wrap_))) { + LOG_WARN("failed to deep_copy tz info wrap", K(ret), "tz_info_wrap", arg.tz_info_wrap_); + } else if (FALSE_IT(ddl_stmt_str_.assign_ptr(arg.ddl_stmt_str_.ptr(), static_cast(arg.ddl_stmt_str_.length())))) { + // do nothing + } else { + tenant_id_ = arg.tenant_id_; + table_id_ = arg.table_id_; + dest_tenant_id_ = arg.dest_tenant_id_; + session_id_ = arg.session_id_; + parallelism_ = arg.parallelism_; + ddl_type_ = arg.ddl_type_; + sql_mode_ = arg.sql_mode_; + for (int64_t i = 0; OB_SUCC(ret) && i < common::ObNLSFormatEnum::NLS_MAX; i++) { + nls_formats_[i].assign_ptr(arg.nls_formats_[i].ptr(), static_cast(arg.nls_formats_[i].length())); + } + } + return ret; +} + +OB_DEF_SERIALIZE(ObCreateHiddenTableArg) +{ + int ret = OB_SUCCESS; + if (!is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_ENCODE, + tenant_id_, + table_id_, + dest_tenant_id_, + session_id_, + parallelism_, + ddl_type_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; i++) { + if (OB_FAIL(nls_formats_[i].serialize(buf, buf_len, pos))) { + LOG_WARN("fail to serialize nls_formats_[i]", K(ret), K(nls_formats_[i])); + } + } + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObCreateHiddenTableArg) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_DECODE, + tenant_id_, + table_id_, + dest_tenant_id_, + session_id_, + parallelism_, + ddl_type_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + ObString tmp_string; + char *tmp_ptr[ObNLSFormatEnum::NLS_MAX] = {}; + for (int64_t i = 0; OB_SUCC(ret) && i < ObNLSFormatEnum::NLS_MAX; i++) { + if (OB_FAIL(tmp_string.deserialize(buf, data_len, pos))) { + LOG_WARN("fail to deserialize nls_formats_", K(ret), K(i)); + } else if (OB_ISNULL(tmp_ptr[i] = (char *)allocator_.alloc(tmp_string.length()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory!", K(ret)); + } else { + MEMCPY(tmp_ptr[i], tmp_string.ptr(), tmp_string.length()); + nls_formats_[i].assign_ptr(tmp_ptr[i], tmp_string.length()); + tmp_string.reset(); + } + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; i++) { + allocator_.free(tmp_ptr[i]); + } + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObCreateHiddenTableArg) +{ + int64_t len = 0; + int ret = OB_SUCCESS; + if (!is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret)); + } else { + LST_DO_CODE(OB_UNIS_ADD_LEN, + tenant_id_, + table_id_, + dest_tenant_id_, + session_id_, + parallelism_, + ddl_type_, + sql_mode_, + tz_info_, + tz_info_wrap_); + if (OB_SUCC(ret)) { + for (int64_t i = 0; i < ObNLSFormatEnum::NLS_MAX; i++) { + len += nls_formats_[i].get_serialize_size(); + } + } + } + if (OB_FAIL(ret)) { + len = -1; + } + return len; +} + +int ObCreateHiddenTableRes::assign(const ObCreateHiddenTableRes &res) +{ + int ret = OB_SUCCESS; + tenant_id_ = res.tenant_id_; + table_id_ = res.table_id_; + dest_tenant_id_ = res.dest_tenant_id_; + dest_table_id_ = res.dest_table_id_; + trace_id_ = res.trace_id_; + task_id_ = res.task_id_; + schema_version_ = res.schema_version_; + return ret; +} +OB_SERIALIZE_MEMBER(ObCreateHiddenTableRes, + tenant_id_, + table_id_, + dest_tenant_id_, + dest_table_id_, + trace_id_, + task_id_, + schema_version_); +OB_SERIALIZE_MEMBER(ObStartRedefTableRes, + task_id_, + tenant_id_, + schema_version_); + +OB_SERIALIZE_MEMBER(ObCopyTableDependentsArg, + task_id_, + tenant_id_, + copy_indexes_, + copy_triggers_, + copy_constraints_, + copy_foreign_keys_, + ignore_errors_); + +OB_SERIALIZE_MEMBER(ObFinishRedefTableArg, + task_id_, + tenant_id_); + +OB_SERIALIZE_MEMBER(ObAbortRedefTableArg, + task_id_, + tenant_id_); + +OB_SERIALIZE_MEMBER(ObUpdateDDLTaskActiveTimeArg, + task_id_, + tenant_id_); + int ObAlterResourceUnitArg::assign(const ObAlterResourceUnitArg &other) { int ret = OB_SUCCESS; diff --git a/src/share/ob_rpc_struct.h b/src/share/ob_rpc_struct.h index c4c7fdac1f..188b1b42f0 100644 --- a/src/share/ob_rpc_struct.h +++ b/src/share/ob_rpc_struct.h @@ -109,7 +109,6 @@ enum ObDefaultRoleFlag OB_DEFAULT_ROLE_NONE = 4, OB_DEFAULT_ROLE_MAX, }; - struct Bool { OB_UNIS_VERSION(1); @@ -1534,6 +1533,299 @@ public: common::ObSArray rename_table_items_; }; +struct ObStartRedefTableArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(orig_tenant_id), + K_(orig_table_id), + K_(target_tenant_id), + K_(target_table_id), + K_(session_id), + K_(parallelism), + K_(ddl_type), + K_(ddl_stmt_str), + K_(trace_id), + K_(sql_mode), + K_(tz_info_wrap), + "nls_formats", common::ObArrayWrap(nls_formats_, common::ObNLSFormatEnum::NLS_MAX)); + ObStartRedefTableArg(): + orig_tenant_id_(common::OB_INVALID_ID), + orig_table_id_(common::OB_INVALID_ID), + target_tenant_id_(common::OB_INVALID_ID), + target_table_id_(common::OB_INVALID_ID), + session_id_(common::OB_INVALID_ID), + ddl_type_(share::DDL_INVALID), + ddl_stmt_str_(), + trace_id_(), + sql_mode_(0), + tz_info_wrap_(), + nls_formats_{} + {} + + ~ObStartRedefTableArg() + { + allocator_.clear(); + } + + void reset() + { + orig_tenant_id_ = common::OB_INVALID_ID; + orig_table_id_ = common::OB_INVALID_ID; + target_tenant_id_ = common::OB_INVALID_ID; + target_table_id_ = common::OB_INVALID_ID; + session_id_ = common::OB_INVALID_ID; + ddl_type_ = share::DDL_INVALID; + ddl_stmt_str_.reset(); + sql_mode_ = 0; + } + + inline void set_tz_info_map(const common::ObTZInfoMap *tz_info_map) + { + tz_info_wrap_.set_tz_info_map(tz_info_map); + tz_info_.set_tz_info_map(tz_info_map); + } + int set_nls_formats(const common::ObString *nls_formats); + int set_nls_formats(const common::ObString &nls_date_format, + const common::ObString &nls_timestamp_format, + const common::ObString &nls_timestamp_tz_format) + { + ObString tmp_str[ObNLSFormatEnum::NLS_MAX] = {nls_date_format, nls_timestamp_format, + nls_timestamp_tz_format}; + return set_nls_formats(tmp_str); + } + bool is_valid() const; + int assign(const ObStartRedefTableArg &arg); +public: + uint64_t orig_tenant_id_; + uint64_t orig_table_id_; + uint64_t target_tenant_id_; + uint64_t target_table_id_; + uint64_t session_id_; + uint64_t parallelism_; + share::ObDDLType ddl_type_; + common::ObString ddl_stmt_str_; + share::ObTaskId trace_id_; + ObSQLMode sql_mode_; + common::ObArenaAllocator allocator_; + common::ObTimeZoneInfo tz_info_; + common::ObTimeZoneInfoWrap tz_info_wrap_; + common::ObString nls_formats_[common::ObNLSFormatEnum::NLS_MAX]; +}; + +struct ObStartRedefTableRes final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(task_id), + K_(tenant_id), + K_(schema_version)); + ObStartRedefTableRes() : task_id_(0), tenant_id_(common::OB_INVALID_ID), schema_version_(0){} + ~ObStartRedefTableRes() = default; + void reset() + { + task_id_ = 0; + tenant_id_ = common::OB_INVALID_ID; + schema_version_ = 0; + } + int assign(const ObStartRedefTableRes &res); +public: + int64_t task_id_; + uint64_t tenant_id_; + int64_t schema_version_; +}; + +struct ObCopyTableDependentsArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(task_id), + K_(tenant_id), + K_(copy_indexes), + K_(copy_triggers), + K_(copy_constraints), + K_(copy_foreign_keys), + K_(ignore_errors)); + ObCopyTableDependentsArg() : task_id_(0), tenant_id_(common::OB_INVALID_ID), copy_indexes_(true), copy_triggers_(true), + copy_constraints_(true), copy_foreign_keys_(true), ignore_errors_(false) {} + + ~ObCopyTableDependentsArg() = default; + bool is_valid() const; + void reset() + { + task_id_ = 0; + tenant_id_ = 0; + copy_indexes_ = false; + copy_triggers_ = false; + copy_constraints_ = false; + copy_foreign_keys_ = false; + ignore_errors_ = false; + } + int assign(const ObCopyTableDependentsArg &arg); +public: + int64_t task_id_; + uint64_t tenant_id_; + bool copy_indexes_; + bool copy_triggers_; + bool copy_constraints_; + bool copy_foreign_keys_; + bool ignore_errors_; +}; + +struct ObFinishRedefTableArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(task_id), K_(tenant_id)); + ObFinishRedefTableArg() : + task_id_(0), tenant_id_(common::OB_INVALID_ID) {} + ~ObFinishRedefTableArg() = default; + bool is_valid() const; + void reset() + { + task_id_ = 0; + tenant_id_ = common::OB_INVALID_ID; + } + int assign(const ObFinishRedefTableArg &arg); +public: + int64_t task_id_; + uint64_t tenant_id_; +}; + + +struct ObAbortRedefTableArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(task_id), K_(tenant_id)); + ObAbortRedefTableArg() : task_id_(0), tenant_id_(common::OB_INVALID_ID) {} + ~ObAbortRedefTableArg() = default; + bool is_valid() const; + void reset() + { + task_id_ = 0; + tenant_id_ = common::OB_INVALID_ID; + } + int assign(const ObAbortRedefTableArg &arg); +public: + int64_t task_id_; + uint64_t tenant_id_; +}; +struct ObUpdateDDLTaskActiveTimeArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(task_id), K_(tenant_id)); + ObUpdateDDLTaskActiveTimeArg() : task_id_(0), tenant_id_(common::OB_INVALID_ID) {} + ~ObUpdateDDLTaskActiveTimeArg() = default; + bool is_valid() const; + void reset() + { + task_id_ = 0; + tenant_id_ = common::OB_INVALID_ID; + } + int assign(const ObUpdateDDLTaskActiveTimeArg &arg); +public: + int64_t task_id_; + uint64_t tenant_id_; +}; + +struct ObCreateHiddenTableArg final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(tenant_id), + K_(table_id), + K_(dest_tenant_id), + K_(session_id), + K_(parallelism), + K_(ddl_type), + K_(ddl_stmt_str), + K_(sql_mode), + K_(tz_info_wrap), + "nls_formats", common::ObArrayWrap(nls_formats_, common::ObNLSFormatEnum::NLS_MAX)); + ObCreateHiddenTableArg() : + tenant_id_(common::OB_INVALID_ID), + table_id_(common::OB_INVALID_ID), + dest_tenant_id_(common::OB_INVALID_ID), + session_id_(common::OB_INVALID_ID), + ddl_type_(share::DDL_INVALID), + ddl_stmt_str_(), + sql_mode_(0), + tz_info_wrap_(), + nls_formats_{} + {} + ~ObCreateHiddenTableArg() + { + allocator_.clear(); + } + bool is_valid() const; + void reset() + { + tenant_id_ = common::OB_INVALID_ID; + table_id_ = common::OB_INVALID_ID; + dest_tenant_id_ = common::OB_INVALID_ID; + session_id_ = common::OB_INVALID_ID; + ddl_type_ = share::DDL_INVALID; + ddl_stmt_str_.reset(); + sql_mode_ = 0; + } + int assign(const ObCreateHiddenTableArg &arg); +public: + uint64_t tenant_id_; + int64_t table_id_; + uint64_t dest_tenant_id_; + uint64_t session_id_; + uint64_t parallelism_; + share::ObDDLType ddl_type_; + common::ObString ddl_stmt_str_; + ObSQLMode sql_mode_; + common::ObArenaAllocator allocator_; + common::ObTimeZoneInfo tz_info_; + common::ObTimeZoneInfoWrap tz_info_wrap_; + common::ObString nls_formats_[common::ObNLSFormatEnum::NLS_MAX]; +}; + +struct ObCreateHiddenTableRes final +{ + OB_UNIS_VERSION(1); +public: + TO_STRING_KV(K_(tenant_id), + K_(table_id), + K_(dest_tenant_id), + K_(dest_table_id), + K_(trace_id), + K_(task_id), + K_(schema_version)); + ObCreateHiddenTableRes() : + tenant_id_(common::OB_INVALID_ID), + table_id_(common::OB_INVALID_ID), + dest_tenant_id_(common::OB_INVALID_ID), + dest_table_id_(common::OB_INVALID_ID), + task_id_(0), + schema_version_(0) {} + ~ObCreateHiddenTableRes() = default; + void reset() + { + tenant_id_ = common::OB_INVALID_ID; + table_id_ = common::OB_INVALID_ID; + dest_tenant_id_ = common::OB_INVALID_ID; + dest_table_id_ = common::OB_INVALID_ID; + task_id_ = 0; + schema_version_ = 0; + } + int assign(const ObCreateHiddenTableRes &res); +public: + uint64_t tenant_id_; + int64_t table_id_; + uint64_t dest_tenant_id_; + int64_t dest_table_id_; + int64_t task_id_; + int64_t schema_version_; + share::ObTaskId trace_id_; +}; + + struct ObAlterTableArg : public ObDDLArg { OB_UNIS_VERSION(1); @@ -1607,7 +1899,8 @@ public: alter_constraint_type_(CONSTRAINT_NO_OPERATION), index_arg_list_(), foreign_key_arg_list_(), - alter_table_schema_(), + allocator_(), + alter_table_schema_(&allocator_), tz_info_wrap_(), nls_formats_{}, sequence_ddl_arg_(), @@ -1638,7 +1931,6 @@ public: index_arg->~ObIndexArg(); } } - allocator_.clear(); } bool is_valid() const; bool has_rename_action() const @@ -1701,8 +1993,8 @@ public: AlterConstraintType alter_constraint_type_; common::ObSArray index_arg_list_; common::ObSArray foreign_key_arg_list_; - share::schema::AlterTableSchema alter_table_schema_; common::ObArenaAllocator allocator_; + share::schema::AlterTableSchema alter_table_schema_; common::ObTimeZoneInfo tz_info_;//unused now common::ObTimeZoneInfoWrap tz_info_wrap_; common::ObString nls_formats_[common::ObNLSFormatEnum::NLS_MAX]; diff --git a/src/share/ob_tablet_autoincrement_param.cpp b/src/share/ob_tablet_autoincrement_param.cpp index 950d53aaa8..5d2494723f 100644 --- a/src/share/ob_tablet_autoincrement_param.cpp +++ b/src/share/ob_tablet_autoincrement_param.cpp @@ -40,6 +40,25 @@ int ObTabletCacheInterval::next_value(uint64_t &next_value) return ret; } +int ObTabletCacheInterval::fetch(uint64_t count, ObTabletCacheInterval &dest) +{ + int ret = OB_SUCCESS; + uint64_t start = ATOMIC_LOAD(&next_value_); + uint64_t end = 0; + uint64_t old_start = start; + while ((end = start + count - 1) <= end_ && + old_start != (start = ATOMIC_CAS(&next_value_, old_start, end + 1))) { + old_start = start; + PAUSE(); + } + if (end > end_) { + ret = OB_EAGAIN; + } else { + dest.set(start, end); + } + return ret; +} + OB_SERIALIZE_MEMBER(ObTabletAutoincParam, tenant_id_, auto_increment_cache_size_); diff --git a/src/share/ob_tablet_autoincrement_param.h b/src/share/ob_tablet_autoincrement_param.h index 2cc8d4b97d..65fd592a20 100644 --- a/src/share/ob_tablet_autoincrement_param.h +++ b/src/share/ob_tablet_autoincrement_param.h @@ -105,6 +105,8 @@ public: TO_STRING_KV(K_(tablet_id), K_(start), K_(end), K_(cache_size), K_(next_value), K_(task_id)); void set(uint64_t start, uint64_t end); int next_value(uint64_t &next_value); + int fetch(uint64_t count, ObTabletCacheInterval &dest); + uint64_t count() const { return end_ - start_ + 1; } bool operator <(const ObTabletCacheInterval &other) { return tablet_id_ < other.tablet_id_; } public: common::ObTabletID tablet_id_; diff --git a/src/share/ob_thread_define.h b/src/share/ob_thread_define.h index 8676b885f7..0437aaea6d 100644 --- a/src/share/ob_thread_define.h +++ b/src/share/ob_thread_define.h @@ -120,4 +120,6 @@ TG_DEF(DDLScanTask, DDLScanTask, "", TG_STATIC, TIMER) TG_DEF(TenantLSMetaChecker, LSMetaCh, "", TG_STATIC, TIMER) TG_DEF(TenantTabletMetaChecker, TbMetaCh, "", TG_STATIC, TIMER) TG_DEF(ServerMetaChecker, SvrMetaCh, "", TG_STATIC, TIMER) +TG_DEF(HeartBeatCheckTask, HeartBeatCheckTask, "", TG_STATIC, TIMER) +TG_DEF(RedefHeartBeatTask, RedefHeartBeatTask, "", TG_STATIC, TIMER) #endif diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 9c3e1c1d04..7ba2cfbf20 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -1326,6 +1326,9 @@ DEF_BOOL(enable_user_defined_rewrite_rules, OB_TENANT_PARAMETER, "False", DEF_TIME(_ob_plan_cache_auto_flush_interval, OB_CLUSTER_PARAMETER, "0s", "[0s,)", "time interval for auto periodic flush plan cache. Range: [0s, +∞)", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_ob_enable_direct_load, OB_CLUSTER_PARAMETER, "True", + "Enable or disable direct path load", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); DEF_BOOL(_px_join_skew_handling, OB_TENANT_PARAMETER, "True", "enables skew handling for parallel joins. The default value is True.", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); diff --git a/src/share/rc/ob_tenant_base.h b/src/share/rc/ob_tenant_base.h index 64e6ef48a0..b1588163ba 100644 --- a/src/share/rc/ob_tenant_base.h +++ b/src/share/rc/ob_tenant_base.h @@ -121,6 +121,7 @@ namespace rootserver namespace observer { class ObTenantMetaChecker; + class ObTableLoadService; } // for ObTenantSwitchGuard 临时使用>>>>>>>> @@ -216,6 +217,7 @@ namespace detector storage::ObTenantFreezeInfoMgr*, \ transaction::ObTxLoopWorker *, \ storage::ObAccessService*, \ + observer::ObTableLoadService*, \ concurrency_control::ObMultiVersionGarbageCollector*, \ sql::ObUDRMgr*, \ sql::ObFLTSpanMgr*, \ diff --git a/src/share/stat/ob_dbms_stats_executor.cpp b/src/share/stat/ob_dbms_stats_executor.cpp index 4bdf3041bc..66b3f9e7ac 100644 --- a/src/share/stat/ob_dbms_stats_executor.cpp +++ b/src/share/stat/ob_dbms_stats_executor.cpp @@ -58,12 +58,10 @@ int ObDbmsStatsExecutor::gather_table_stats(ObExecContext &ctx, /*do nothing*/ } else if (OB_FAIL(do_gather_stats(ctx, param, extra, approx_opt_part_stats, opt_stats))) { LOG_WARN("failed to gather subpartition stats", K(ret)); - } else if (OB_FAIL(buffer_opt_stat(ctx, - param.column_params_, - all_tstats, - all_cstats, - opt_stats))) { - LOG_WARN("failed to buffer opt stat", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::calssify_opt_stat(opt_stats, + all_tstats, + all_cstats))) { + LOG_WARN("failed to calssify opt stat", K(ret)); } } if (OB_SUCC(ret) && param.need_part_) { @@ -74,12 +72,10 @@ int ObDbmsStatsExecutor::gather_table_stats(ObExecContext &ctx, /*do nothing*/ } else if (OB_FAIL(do_gather_stats(ctx, param, extra, approx_opt_part_stats, opt_stats))) { LOG_WARN("failed to gather partition stats", K(ret)); - } else if (OB_FAIL(buffer_opt_stat(ctx, - param.column_params_, - all_tstats, - all_cstats, - opt_stats))) { - LOG_WARN("failed to buffer opt stat", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::calssify_opt_stat(opt_stats, + all_tstats, + all_cstats))) { + LOG_WARN("failed to calssify opt stat", K(ret)); } } if (OB_SUCC(ret) && (param.need_global_ || @@ -89,12 +85,10 @@ int ObDbmsStatsExecutor::gather_table_stats(ObExecContext &ctx, ObSEArray opt_stats; if (OB_FAIL(do_gather_stats(ctx, param, extra, approx_opt_part_stats, opt_stats))) { LOG_WARN("failed to gather table stats", K(ret)); - } else if (OB_FAIL(buffer_opt_stat(ctx, - param.column_params_, - all_tstats, - all_cstats, - opt_stats))) { - LOG_WARN("failed to buffer opt stat", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::calssify_opt_stat(opt_stats, + all_tstats, + all_cstats))) { + LOG_WARN("failed to calssify opt stat", K(ret)); } } if (OB_SUCC(ret)) { @@ -652,31 +646,6 @@ int ObDbmsStatsExecutor::init_opt_stat(ObIAllocator &allocator, return ret; } - -int ObDbmsStatsExecutor::buffer_opt_stat(ObExecContext &ctx, - const ObIArray &column_params, - ObIArray &table_stats, - ObIArray &column_stats, - ObIArray &opt_stats) -{ - int ret = OB_SUCCESS; - for (int64_t i = 0; OB_SUCC(ret) && i < opt_stats.count(); ++i) { - if (OB_FAIL(table_stats.push_back(opt_stats.at(i).table_stat_))) { - LOG_WARN("failed to push back table stat", K(ret)); - } else { - for (int64_t j = 0; OB_SUCC(ret) && j < opt_stats.at(i).column_stats_.count(); ++j) { - if (OB_ISNULL(opt_stats.at(i).column_stats_.at(j))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(opt_stats.at(i).column_stats_.at(j))); - } else if (opt_stats.at(i).column_stats_.at(j)->is_valid()) { - ret = column_stats.push_back(opt_stats.at(i).column_stats_.at(j)); - } - } - } - } - return ret; -} - ObOptStat::~ObOptStat() { if (NULL != table_stat_) { diff --git a/src/share/stat/ob_dbms_stats_executor.h b/src/share/stat/ob_dbms_stats_executor.h index a9cf77272a..b0f1473185 100644 --- a/src/share/stat/ob_dbms_stats_executor.h +++ b/src/share/stat/ob_dbms_stats_executor.h @@ -77,12 +77,6 @@ private: static int prepare_opt_stat(ObIArray &all_stats, ObOptStat *&opt_stat); - static int buffer_opt_stat(ObExecContext &ctx, - const ObIArray &column_params, - ObIArray &table_stats, - ObIArray &column_stats, - ObIArray &opt_stats); - static int try_drive_global_stat(ObExecContext &ctx, const ObTableStatParam ¶m, ObExtraParam &extra, diff --git a/src/share/stat/ob_dbms_stats_utils.cpp b/src/share/stat/ob_dbms_stats_utils.cpp index 26959ed609..cd315fbdd7 100644 --- a/src/share/stat/ob_dbms_stats_utils.cpp +++ b/src/share/stat/ob_dbms_stats_utils.cpp @@ -282,6 +282,30 @@ int ObDbmsStatsUtils::split_batch_write(sql::ObExecContext &ctx, const bool is_index_stat /*default false*/, const bool is_history_stat /*default false*/, const bool is_online_stat /*default false*/) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(ctx.get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(ctx.get_my_session())); + } else if (OB_FAIL(split_batch_write(ctx.get_virtual_table_ctx().schema_guard_, + ctx.get_my_session()->get_effective_tenant_id(), + table_stats, + column_stats, + is_index_stat, + is_history_stat, + is_online_stat))) { + LOG_WARN("failed to split batch write", K(ret)); + } else {/*do nothing*/} + return ret; +} + +int ObDbmsStatsUtils::split_batch_write(share::schema::ObSchemaGetterGuard *schema_guard, + const uint64_t tenant_id, + ObIArray &table_stats, + ObIArray &column_stats, + const bool is_index_stat/*default false*/, + const bool is_history_stat/*default false*/, + const bool is_online_stat /*default false*/) { int ret = OB_SUCCESS; int64_t idx_tab_stat = 0; @@ -291,10 +315,6 @@ int ObDbmsStatsUtils::split_batch_write(sql::ObExecContext &ctx, LOG_DEBUG("dbms stats write stats", K(table_stats), K(column_stats)); const int64_t MAX_NUM_OF_WRITE_STATS = 2000; int64_t current_time = ObTimeUtility::current_time(); - if (OB_ISNULL(ctx.get_my_session())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get unexpected null", K(ret), K(ctx.get_my_session())); - } while (OB_SUCC(ret) && (idx_tab_stat < table_stats.count() || idx_col_stat < column_stats.count())) { ObSEArray write_table_stats; @@ -331,8 +351,8 @@ int ObDbmsStatsUtils::split_batch_write(sql::ObExecContext &ctx, } } if (OB_SUCC(ret)) { - if (OB_FAIL(ObDbmsStatsUtils::batch_write(ctx.get_virtual_table_ctx().schema_guard_, - ctx.get_my_session()->get_effective_tenant_id(), + if (OB_FAIL(ObDbmsStatsUtils::batch_write(schema_guard, + tenant_id, write_table_stats, write_column_stats, current_time, @@ -429,6 +449,28 @@ int ObDbmsStatsUtils::get_dst_partition_by_tablet_id(sql::ObExecContext &ctx, return ret; } +int ObDbmsStatsUtils::calssify_opt_stat(const ObIArray &opt_stats, + ObIArray &table_stats, + ObIArray &column_stats) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < opt_stats.count(); ++i) { + if (OB_FAIL(table_stats.push_back(opt_stats.at(i).table_stat_))) { + LOG_WARN("failed to push back table stat", K(ret)); + } else { + for (int64_t j = 0; OB_SUCC(ret) && j < opt_stats.at(i).column_stats_.count(); ++j) { + if (OB_ISNULL(opt_stats.at(i).column_stats_.at(j))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(opt_stats.at(i).column_stats_.at(j))); + } else if (opt_stats.at(i).column_stats_.at(j)->is_valid()) { + ret = column_stats.push_back(opt_stats.at(i).column_stats_.at(j)); + } + } + } + } + return ret; +} + // merge history stats and online stats // for each stats in history, first search wether is in online_stats(map). // if not exists, set_refactored. diff --git a/src/share/stat/ob_dbms_stats_utils.h b/src/share/stat/ob_dbms_stats_utils.h index 9cd37b5ee1..ef7c920369 100644 --- a/src/share/stat/ob_dbms_stats_utils.h +++ b/src/share/stat/ob_dbms_stats_utils.h @@ -45,6 +45,14 @@ public: const bool is_history_stat = false, const bool is_online_stat = false); + static int split_batch_write(share::schema::ObSchemaGetterGuard *schema_guard, + const uint64_t tenant_id, + ObIArray &table_stats, + ObIArray &column_stats, + const bool is_index_stat = false, + const bool is_history_stat = false, + const bool is_online_stat = false); + static int batch_write_history_stats(sql::ObExecContext &ctx, ObIArray &history_tab_handles, ObIArray &history_col_handles); @@ -74,6 +82,9 @@ public: const ObIArray &partition_infos, int64_t &partition_id); + static int calssify_opt_stat(const ObIArray &opt_stats, + ObIArray &table_stats, + ObIArray &column_stats); static int merge_tab_stats( const ObTableStatParam ¶m, const TabStatIndMap &table_stats, diff --git a/src/share/stat/ob_incremental_stat_estimator.cpp b/src/share/stat/ob_incremental_stat_estimator.cpp index 562ddecf4a..2066de2ead 100644 --- a/src/share/stat/ob_incremental_stat_estimator.cpp +++ b/src/share/stat/ob_incremental_stat_estimator.cpp @@ -19,6 +19,9 @@ #include "share/stat/ob_dbms_stats_utils.h" #include "share/stat/ob_stat_item.h" #include "share/stat/ob_topk_hist_estimator.h" +#include "pl/sys_package/ob_dbms_stats.h" +#include "share/stat/ob_dbms_stats_history_manager.h" + namespace oceanbase { using namespace pl; namespace common { @@ -53,6 +56,111 @@ int ObIncrementalStatEstimator::try_drive_global_stat(ObExecContext &ctx, return ret; } +int ObIncrementalStatEstimator::drive_global_stat_by_direct_load(ObExecContext &ctx, + ObIArray &part_tab_stats, + ObIArray &part_column_stats) +{ + int ret = OB_SUCCESS; + const share::schema::ObTableSchema *table_schema = NULL; + share::schema::ObSchemaGetterGuard *schema_guard = ctx.get_virtual_table_ctx().schema_guard_; + ObSEArray part_opt_stats; + ObSEArray all_derive_opt_stats; + ObArenaAllocator alloc("ObIncrStats"); + ObTableStatParam param; + if (part_tab_stats.empty()) { + //do nothing + } else if (OB_ISNULL(part_tab_stats.at(0)) || OB_UNLIKELY(!part_tab_stats.at(0)->is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret), KPC(part_tab_stats.at(0))); + } else if (OB_FAIL(gen_opt_stat_param_by_direct_load(ctx, alloc, + part_tab_stats.at(0)->get_table_id(), + param))) { + LOG_WARN("failed to gen opt stat param by direct load", K(ret)); + } else if (param.part_level_ != share::schema::PARTITION_LEVEL_ONE && + param.part_level_ != share::schema::PARTITION_LEVEL_TWO) { + /*do nothing*/ + } else if (OB_FAIL(generate_all_opt_stat(part_tab_stats, part_column_stats, + param.column_params_.count(), + part_opt_stats))) { + LOG_WARN("failed to generate all opt stat", K(ret)); + } else if (OB_FAIL(param.all_part_infos_.assign(param.part_infos_))|| + OB_FAIL(param.all_subpart_infos_.assign(param.subpart_infos_))) { + LOG_WARN("failed to assign", K(ret)); + } else { + bool nee_derive_part = param.part_level_ == share::schema::PARTITION_LEVEL_TWO; + //derive part stat first + if (nee_derive_part) { + ObSEArray empty_opt_stats; + if (OB_FAIL(do_derive_part_stats_from_subpart_stats(ctx, alloc, param, empty_opt_stats, + part_opt_stats, all_derive_opt_stats))) { + LOG_WARN("failed to derive part stat by direct load", K(ret)); + } + } + //derive global stat + if (OB_SUCC(ret)) { + ObOptStat global_opt_stat; + bool need_drive_hist = false; + bool need_gather_hybrid_hist = false; + if (OB_FAIL(do_derive_global_stat(ctx, alloc, param, + nee_derive_part ? all_derive_opt_stats : part_opt_stats, + need_drive_hist, + TABLE_LEVEL, param.global_part_id_, need_gather_hybrid_hist, + global_opt_stat))) { + LOG_WARN("Failed to derive global stat from part stat", K(ret)); + } else if (OB_FAIL(all_derive_opt_stats.push_back(global_opt_stat))) { + LOG_WARN("faield to push back", K(ret)); + } + } + } + //write all stat + if (OB_SUCC(ret)) { + ObSEArray all_tstats; + ObSEArray all_cstats; + ObSEArray history_tab_handles; + ObSEArray history_col_handles; + if (OB_FAIL(append(all_tstats, part_tab_stats))) { + LOG_WARN("failed to append", K(ret)); + } else if (OB_FAIL(append(all_cstats, part_column_stats))) { + LOG_WARN("failed to append", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::calssify_opt_stat(all_derive_opt_stats, + all_tstats, + all_cstats))) { + LOG_WARN("failed to calssify opt stat", K(ret)); + } else if (OB_FAIL(write_all_opt_stats_by_dircet_load(ctx, param, all_tstats, all_cstats))) { + LOG_WARN("failed to write all opt stats by dircet load", K(ret)); + } else {/*do nothing*/} + } + LOG_TRACE("succeed to drive global stat by direct load", K(param), K(part_tab_stats), + K(part_column_stats)); + return ret; +} + +int ObIncrementalStatEstimator::write_all_opt_stats_by_dircet_load( + ObExecContext &ctx, + const ObTableStatParam ¶m, + ObIArray &all_tstats, + ObIArray &all_cstats) +{ + int ret = OB_SUCCESS; + ObSEArray history_tab_handles; + ObSEArray history_col_handles; + //before write, we need record history stats. + if (OB_FAIL(ObDbmsStatsHistoryManager::get_history_stat_handles(ctx, param, + history_tab_handles, + history_col_handles))) { + LOG_WARN("failed to get history stat handles", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::split_batch_write(ctx, all_tstats, all_cstats))) { + LOG_WARN("failed to split batch write", K(ret)); + } else if (OB_FAIL(ObDbmsStatsUtils::batch_write_history_stats(ctx, + history_tab_handles, + history_col_handles))) { + LOG_WARN("failed to batch write history stats", K(ret)); + } else if (OB_FAIL(ObBasicStatsEstimator::update_last_modified_count(ctx, param))) { + LOG_WARN("failed to update last modified count", K(ret)); + } else {/*do nothing*/} + return ret; +} + int ObIncrementalStatEstimator::drive_global_stat_from_part_stats( ObExecContext &ctx, const ObTableStatParam ¶m, @@ -107,15 +215,20 @@ int ObIncrementalStatEstimator::drive_global_stat_from_part_stats( } } if (OB_SUCC(ret)) { - if (OB_FAIL(get_no_regather_partition_stats(param, no_regather_part_ids, - table_stats, col_handles, tmp_opt_stats))) { + ObSEArray column_ids; + if (OB_FAIL(get_column_ids(param.column_params_, column_ids))) { + LOG_WARN("failed to get column ids", K(ret)); + } else if (OB_FAIL(get_no_regather_partition_stats(param.tenant_id_, param.table_id_, column_ids, + no_regather_part_ids, table_stats, + col_handles, tmp_opt_stats))) { LOG_WARN("failed to get locked partition stats", K(ret)); } else {/*do nothing*/} } } if (OB_SUCC(ret)) { - if (OB_FAIL(do_derive_global_stat(ctx, param, tmp_opt_stats, need_drive_hist, TABLE_LEVEL, -1, - need_gather_hybrid_hist, global_opt_stat))) { + if (OB_FAIL(do_derive_global_stat(ctx, ctx.get_allocator(), param, tmp_opt_stats, need_drive_hist, + TABLE_LEVEL,param.global_part_id_, need_gather_hybrid_hist, + global_opt_stat))) { LOG_WARN("Failed to derive global stat from part stat", K(ret)); } else if (OB_FAIL(opt_stats.push_back(global_opt_stat))) { LOG_WARN("failed to push back global stat", K(ret)); @@ -145,7 +258,7 @@ int ObIncrementalStatEstimator::drive_part_stats_from_subpart_stats( no_regather_col_handles, no_regather_subpart_opt_stats))) { LOG_WARN("failed to get locked partition stats", K(ret)); - } else if (OB_FAIL(do_derive_part_stats_from_subpart_stats(ctx, param, + } else if (OB_FAIL(do_derive_part_stats_from_subpart_stats(ctx, ctx.get_allocator(), param, no_regather_subpart_opt_stats, gather_opt_stats, approx_part_opt_stats))) { @@ -160,6 +273,7 @@ int ObIncrementalStatEstimator::drive_part_stats_from_subpart_stats( int ObIncrementalStatEstimator::do_derive_part_stats_from_subpart_stats( ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, const ObIArray &no_regather_subpart_opt_stats, const ObIArray &gather_opt_stats, @@ -208,8 +322,8 @@ int ObIncrementalStatEstimator::do_derive_part_stats_from_subpart_stats( ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected error", K(ret), K(subpart_opt_stats.count()), K(param.approx_part_infos_.at(i))); - } else if (OB_FAIL(do_derive_global_stat(ctx, param, subpart_opt_stats, true, PARTITION_LEVEL, - param.approx_part_infos_.at(i).part_id_, + } else if (OB_FAIL(do_derive_global_stat(ctx, alloc, param, subpart_opt_stats, true, + PARTITION_LEVEL, param.approx_part_infos_.at(i).part_id_, need_gather_hybrid_hist, opt_part_stat))) { LOG_WARN("Failed to derive global stat from part stat", K(ret)); } else if (OB_FAIL(approx_part_opt_stats.push_back(opt_part_stat))) { @@ -272,6 +386,38 @@ int ObIncrementalStatEstimator::generate_all_opt_stat(ObIArray & return ret; } +int ObIncrementalStatEstimator::generate_all_opt_stat(ObIArray &table_stats, + ObIArray &column_stats, + int64_t col_cnt, + ObIArray &all_opt_stats) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < table_stats.count(); ++i) { + ObOptStat opt_stat; + opt_stat.table_stat_ = table_stats.at(i); + for (int64_t j = 0; OB_SUCC(ret) && opt_stat.column_stats_.count() < col_cnt && j < column_stats.count(); ++j) { + if (OB_ISNULL(column_stats.at(j)) || OB_ISNULL(opt_stat.table_stat_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret), K(column_stats.at(j))); + } else if (opt_stat.table_stat_->get_partition_id() == column_stats.at(j)->get_partition_id()) { + if (OB_FAIL(opt_stat.column_stats_.push_back( + const_cast(column_stats.at(j))))) { + LOG_WARN("failed to push back col stat", K(ret)); + } else {/*do nothing*/} + } + } + if (OB_SUCC(ret)) { + if (OB_UNLIKELY(opt_stat.column_stats_.count() != col_cnt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret), K(opt_stat.column_stats_), K(col_cnt)); + } else if (OB_FAIL(all_opt_stats.push_back(opt_stat))) { + LOG_WARN("failed to push back opt stat", K(ret)); + } else {/*do nothing*/} + } + } + return ret; +} + int ObIncrementalStatEstimator::get_table_and_column_stats( ObOptStat &src_opt_stat, const ObTableStatParam ¶m, @@ -346,6 +492,7 @@ int ObIncrementalStatEstimator::get_part_ids_and_column_ids_info(ObOptStat &src_ } int ObIncrementalStatEstimator::do_derive_global_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, ObIArray &part_opt_stats, bool need_drive_hist, @@ -355,10 +502,10 @@ int ObIncrementalStatEstimator::do_derive_global_stat(ObExecContext &ctx, ObOptStat &global_opt_stat) { int ret = OB_SUCCESS; - if (OB_FAIL(derive_global_tbl_stat(ctx, param, approx_level, partition_id, + if (OB_FAIL(derive_global_tbl_stat(ctx, alloc, param, approx_level, partition_id, part_opt_stats, global_opt_stat))) { LOG_WARN("failed to derive global tbl stat from part tbl stat", K(ret)); - } else if (OB_FAIL(derive_global_col_stat(ctx, param, part_opt_stats, need_drive_hist, + } else if (OB_FAIL(derive_global_col_stat(ctx, alloc, param, part_opt_stats, need_drive_hist, approx_level, partition_id, need_gather_hybrid_hist, global_opt_stat))) { LOG_WARN("failed to derive global col stat from part col stat", K(ret)); @@ -369,6 +516,7 @@ int ObIncrementalStatEstimator::do_derive_global_stat(ObExecContext &ctx, } int ObIncrementalStatEstimator::derive_global_tbl_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, const StatLevel &approx_level, const int64_t partition_id, @@ -386,7 +534,7 @@ int ObIncrementalStatEstimator::derive_global_tbl_stat(ObExecContext &ctx, } else { ObOptTableStat *&table_stat = global_opt_stat.table_stat_; void *ptr = NULL; - if (OB_ISNULL(ptr = ctx.get_allocator().alloc(sizeof(ObOptTableStat)))) { + if (OB_ISNULL(ptr = alloc.alloc(sizeof(ObOptTableStat)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("memory is not enough", K(ret), K(ptr)); } else { @@ -424,6 +572,7 @@ int ObIncrementalStatEstimator::derive_global_tbl_stat(ObExecContext &ctx, } int ObIncrementalStatEstimator::derive_global_col_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, ObIArray &part_opt_stats, bool need_drive_hist, @@ -447,11 +596,11 @@ int ObIncrementalStatEstimator::derive_global_col_stat(ObExecContext &ctx, for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt; ++i) { ObOptColumnStat *col_stat = NULL; void *ptr = NULL; - if (OB_ISNULL(ptr = ctx.get_allocator().alloc(sizeof(ObOptColumnStat)))) { + if (OB_ISNULL(ptr = alloc.alloc(sizeof(ObOptColumnStat)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("memory is not enough", K(ret), K(ptr)); } else { - col_stat = new (ptr) ObOptColumnStat(ctx.get_allocator()); + col_stat = new (ptr) ObOptColumnStat(alloc); ObGlobalMinEval min_eval; ObGlobalMaxEval max_eval; ObGlobalNullEval null_eval; @@ -512,15 +661,15 @@ int ObIncrementalStatEstimator::derive_global_col_stat(ObExecContext &ctx, col_stat->set_collation_type(param.column_params_.at(i).cs_type_); ObObj new_min_obj, new_max_obj; //maybe the stat is from KVCACHE, need deep copy min/max obj. - if (OB_FAIL(ob_write_obj(ctx.get_allocator(), min_eval.get(), new_min_obj)) || + if (OB_FAIL(ob_write_obj(alloc, min_eval.get(), new_min_obj)) || FALSE_IT(col_stat->set_min_value(new_min_obj))) { LOG_WARN("failed to set min value", K(ret), K(min_eval.get()), K(new_min_obj)); - } else if (OB_FAIL(ob_write_obj(ctx.get_allocator(), max_eval.get(), new_max_obj)) || + } else if (OB_FAIL(ob_write_obj(alloc, max_eval.get(), new_max_obj)) || FALSE_IT(col_stat->set_max_value(new_max_obj))) { LOG_WARN("failed to set max value", K(ret), K(max_eval.get()), K(new_max_obj)); } else if (need_drive_hist && !all_part_histograms.empty() && OB_FAIL(derive_global_histogram(all_part_histograms, - ctx.get_allocator(), + alloc, max_bucket_num, global_opt_stat.table_stat_->get_row_count(), col_stat->get_num_not_null(), @@ -622,25 +771,24 @@ int ObIncrementalStatEstimator::derive_global_histogram(ObIArray &a } int ObIncrementalStatEstimator::get_no_regather_partition_stats( - const ObTableStatParam ¶m, + const uint64_t tenant_id, + const uint64_t table_id, + const ObIArray &column_ids, const ObIArray &no_regather_partition_ids, ObIArray &no_regather_table_stats, ObIArray &no_regather_col_handles, ObIArray &part_opt_stats) { int ret = OB_SUCCESS; - ObSEArray column_ids; if (no_regather_partition_ids.empty()) { /*do nothing*/ - } else if (OB_FAIL(get_column_ids(param, column_ids))) { - LOG_WARN("failed to get column ids", K(ret)); - } else if (OB_FAIL(ObOptStatManager::get_instance().get_table_stat(param.tenant_id_, - param.table_id_, + } else if (OB_FAIL(ObOptStatManager::get_instance().get_table_stat(tenant_id, + table_id, no_regather_partition_ids, no_regather_table_stats))) { LOG_WARN("failed to get table stat", K(ret)); - } else if (OB_FAIL(ObOptStatManager::get_instance().get_column_stat(param.tenant_id_, - param.table_id_, + } else if (OB_FAIL(ObOptStatManager::get_instance().get_column_stat(tenant_id, + table_id, no_regather_partition_ids, column_ids, no_regather_col_handles))) { @@ -656,12 +804,12 @@ int ObIncrementalStatEstimator::get_no_regather_partition_stats( return ret; } -int ObIncrementalStatEstimator::get_column_ids(const ObTableStatParam ¶m, +int ObIncrementalStatEstimator::get_column_ids(const ObIArray &column_params, ObIArray &column_ids) { int ret = OB_SUCCESS; - for (int64_t i = 0; OB_SUCC(ret) && i < param.column_params_.count(); ++i) { - if (OB_FAIL(column_ids.push_back(param.column_params_.at(i).column_id_))) { + for (int64_t i = 0; OB_SUCC(ret) && i < column_params.count(); ++i) { + if (OB_FAIL(column_ids.push_back(column_params.at(i).column_id_))) { LOG_WARN("failed to push back", K(ret)); } else {/*do nothing*/} } @@ -765,16 +913,70 @@ int ObIncrementalStatEstimator::get_no_regather_subpart_stats( } } if (OB_SUCC(ret)) { - if (OB_FAIL(get_no_regather_partition_stats(param, - derive_need_no_regather_subpart_ids, - no_regather_table_stats, - no_regather_col_handles, - subpart_opt_stats))) { + ObSEArray column_ids; + if (OB_FAIL(get_column_ids(param.column_params_, column_ids))) { + LOG_WARN("failed to get column ids", K(ret)); + } else if (OB_FAIL(get_no_regather_partition_stats(param.tenant_id_, + param.table_id_, + column_ids, + derive_need_no_regather_subpart_ids, + no_regather_table_stats, + no_regather_col_handles, + subpart_opt_stats))) { LOG_WARN("failed to get no regather partition stats", K(ret)); } else {/*do nothing*/} } return ret; } +int ObIncrementalStatEstimator::gen_opt_stat_param_by_direct_load(ObExecContext &ctx, + ObIAllocator &alloc, + const uint64_t table_id, + ObTableStatParam ¶m) +{ + int ret = OB_SUCCESS; + const share::schema::ObTableSchema *table_schema = NULL; + share::schema::ObSchemaGetterGuard *schema_guard = ctx.get_virtual_table_ctx().schema_guard_; + param.table_id_ = table_id; + if (OB_ISNULL(schema_guard = ctx.get_virtual_table_ctx().schema_guard_) || + OB_ISNULL(ctx.get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(schema_guard), K(ctx.get_my_session())); + } else if (OB_FAIL(schema_guard->get_table_schema(ctx.get_my_session()->get_effective_tenant_id(), + table_id, + table_schema))) { + LOG_WARN("failed to get table schema", K(ret)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret)); + } else if (OB_FAIL(pl::ObDbmsStats::get_part_infos(*table_schema, + param.part_infos_, + param.subpart_infos_, + param.part_ids_, + param.subpart_ids_))) { + LOG_WARN("failed to get partition infos", K(ret)); + } else if (table_schema->get_part_level() == share::schema::ObPartitionLevel::PARTITION_LEVEL_TWO + && OB_FAIL(param.approx_part_infos_.assign(param.part_infos_))) { + LOG_WARN("failed to assign", K(ret)); + } else if (OB_FAIL(pl::ObDbmsStats::init_column_stat_params(alloc, + *schema_guard, + *table_schema, + param.column_params_))) { + LOG_WARN("failed to init column stat params", K(ret)); + } else { + param.tenant_id_ = ctx.get_my_session()->get_effective_tenant_id(); + param.part_level_ = table_schema->get_part_level(); + param.total_part_cnt_ = table_schema->get_all_part_num(); + param.need_global_ = true; + param.need_part_ = true; + param.need_subpart_ = true; + if (OB_FAIL(pl::ObDbmsStats::set_param_global_part_id(ctx, param))) { + LOG_WARN("failed to set param globa part id", K(ret)); + } + LOG_TRACE("succeed to gen opt stat param by direct load", K(ret)); + } + return ret; +} + } // namespace common } // namespace oceanbase diff --git a/src/share/stat/ob_incremental_stat_estimator.h b/src/share/stat/ob_incremental_stat_estimator.h index 75e8a6d1a0..c43a6b6e3b 100644 --- a/src/share/stat/ob_incremental_stat_estimator.h +++ b/src/share/stat/ob_incremental_stat_estimator.h @@ -36,6 +36,10 @@ public: int64_t part_id, int64_t subpart_cnt, bool is_gather_part); + + static int drive_global_stat_by_direct_load(ObExecContext &ctx, + ObIArray &part_tab_stats, + ObIArray &part_column_stats); private: static int drive_global_stat_from_part_stats(ObExecContext &ctx, @@ -50,6 +54,7 @@ private: static int do_derive_part_stats_from_subpart_stats( ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, const ObIArray &no_regather_subpart_opt_stats, const ObIArray &gather_opt_stats, @@ -70,7 +75,13 @@ private: int64_t col_cnt, ObIArray &all_opt_stats); + static int generate_all_opt_stat(ObIArray &table_stats, + ObIArray &column_stats, + int64_t col_cnt, + ObIArray &all_opt_stats); + static int do_derive_global_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, ObIArray &part_opt_stats, bool need_drive_hist, @@ -80,6 +91,7 @@ private: ObOptStat &global_opt_stat); static int derive_global_tbl_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, const StatLevel &approx_level, const int64_t partition_id, @@ -87,6 +99,7 @@ private: ObOptStat &global_opt_stat); static int derive_global_col_stat(ObExecContext &ctx, + ObIAllocator &alloc, const ObTableStatParam ¶m, ObIArray &part_opt_stats, bool need_drive_hist, @@ -104,13 +117,15 @@ private: ObHistogram &histogram, bool &need_gather_hybrid_hist); - static int get_no_regather_partition_stats(const ObTableStatParam ¶m, + static int get_no_regather_partition_stats(const uint64_t tenant_id, + const uint64_t table_id, + const ObIArray &column_ids, const ObIArray &no_regather_partition_ids, ObIArray &no_regather_table_stats, ObIArray &no_regather_col_handles, ObIArray &part_opt_stats); - static int get_column_ids(const ObTableStatParam ¶m, + static int get_column_ids(const ObIArray &column_params, ObIArray &column_ids); static int gen_part_param(const ObTableStatParam ¶m, @@ -122,6 +137,16 @@ private: ObIArray &no_regather_col_handles, ObIArray &subpart_opt_stats); + static int gen_opt_stat_param_by_direct_load(ObExecContext &ctx, + ObIAllocator &alloc, + const uint64_t table_id, + ObTableStatParam ¶m); + + static int write_all_opt_stats_by_dircet_load(ObExecContext &ctx, + const ObTableStatParam ¶m, + ObIArray &all_tstats, + ObIArray &all_cstats); + }; } // namespace common diff --git a/src/share/stat/ob_opt_column_stat.h b/src/share/stat/ob_opt_column_stat.h index bc9fcc2e90..cd2b5c3a10 100644 --- a/src/share/stat/ob_opt_column_stat.h +++ b/src/share/stat/ob_opt_column_stat.h @@ -337,7 +337,6 @@ public: } } - int deep_copy_max_min_obj(); common::ObCollationType get_collation_type() const { return cs_type_; } diff --git a/src/share/table/ob_table_load_array.h b/src/share/table/ob_table_load_array.h new file mode 100644 index 0000000000..d86e7b3aff --- /dev/null +++ b/src/share/table/ob_table_load_array.h @@ -0,0 +1,282 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/ob_allocator.h" +#include "lib/utility/ob_print_utils.h" +#include "lib/utility/ob_unify_serialize.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace table +{ + +template +class ObTableLoadIterator +{ + typedef ObTableLoadIterator self_t; +public: + typedef typename std::random_access_iterator_tag iterator_category; + typedef int64_t difference_type; + typedef T value_type; + typedef T *value_ptr_t; + typedef T *pointer; + typedef T &reference; +public: + ObTableLoadIterator() : value_ptr_(nullptr) {} + explicit ObTableLoadIterator(value_ptr_t value_ptr) { value_ptr_ = value_ptr; } + ObTableLoadIterator(const self_t &other) { *this = other; } + ObTableLoadIterator &operator=(const self_t &other) + { + value_ptr_ = other.value_ptr_; + return *this; + } +public: + reference operator*() const { return *value_ptr_; } + value_ptr_t operator->() const { return value_ptr_; } + operator value_ptr_t() const { return value_ptr_; } + bool operator==(const self_t &other) const { return (value_ptr_ == (other.value_ptr_)); } + bool operator!=(const self_t &other) const { return (value_ptr_ != (other.value_ptr_)); } + bool operator<(const self_t &other) const { return (value_ptr_ < (other.value_ptr_)); } + difference_type operator-(const self_t &rhs) { return value_ptr_ - rhs.value_ptr_; } + self_t operator-(difference_type step) { return self_t(value_ptr_ - step); } + self_t operator+(difference_type step) { return self_t(value_ptr_ + step); } + self_t &operator+=(difference_type step) + { + value_ptr_ += step; + return *this; + } + self_t &operator-=(difference_type step) + { + value_ptr_ += step; + return *this; + } + self_t &operator++() + { + value_ptr_++; + return *this; + } + self_t operator++(int) + { + self_t tmp = *this; + value_ptr_++; + return tmp; + } + self_t &operator--() + { + value_ptr_--; + return *this; + } + self_t operator--(int) + { + self_t tmp = *this; + value_ptr_--; + return tmp; + } +private: + value_ptr_t value_ptr_; +}; + +// 由于allocator不是ObTableLoadArray自有的, 所以这里不能通过引用计数释放成员 +template +class ObTableLoadArray final +{ + OB_UNIS_VERSION(1); +public: + typedef ObTableLoadIterator iterator; + typedef const ObTableLoadIterator const_iterator; + ObTableLoadArray() : count_(0), ptr_(nullptr), allocator_(nullptr), is_ref_(false) {} + ~ObTableLoadArray() { reset(); } + + void reset() + { + if (nullptr != ptr_ && !is_ref_) { + for (int64_t i = 0; i < count_; ++i) { + ptr_[i].~T(); + } + if (nullptr != allocator_) { + allocator_->free(ptr_); + } + } + count_ = 0; + ptr_ = nullptr; + // allocator_ = nullptr; + is_ref_ = false; + } + + int create(int64_t count, common::ObIAllocator &allocator) + { + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(count <= 0)) { + ret = common::OB_INVALID_ARGUMENT; + OB_LOG(WARN, "invalid argument", KR(ret), K(count)); + } else { + T *ptr = nullptr; + if (OB_ISNULL(ptr = static_cast(allocator.alloc(sizeof(T) * count)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate memory", KR(ret)); + } else { + for (int64_t i = 0; i < count; ++i) { + new (ptr + i) T(); + } + reset(); + count_ = count; + ptr_ = ptr; + allocator_ = &allocator; + is_ref_ = false; + } + } + return ret; + } + + int assign(T *ptr, int64_t count, common::ObIAllocator &allocator) + { + int ret = common::OB_SUCCESS; + reset(); + count_ = count; + ptr_ = ptr; + allocator_ = &allocator; + is_ref_ = false; + return ret; + } + + int ref(T *ptr, int64_t count) + { + int ret = common::OB_SUCCESS; + reset(); + count_ = count; + ptr_ = ptr; + allocator_ = nullptr; + is_ref_ = true; + return ret; + } + + // 转移所有权 + int move_to(ObTableLoadArray &dest) + { + int ret = common::OB_SUCCESS; + if (OB_FAIL(dest.assign(ptr_, count_, allocator_))) { + OB_LOG(WARN, "fail to assign", KR(ret)); + } else { + is_ref_ = true; + } + return ret; + } + + // for deserialize + void set_allocator(common::ObIAllocator &allocator) + { + allocator_ = &allocator; + } + + int64_t count() const { return count_; } + bool empty() const { return 0 == count_; } + T *ptr() const { return ptr_; } + T &at(int64_t idx) + { + OB_ASSERT(idx >= 0 && idx < count_); + return ptr_[idx]; + } + const T &at(int64_t idx) const + { + OB_ASSERT(idx >= 0 && idx < count_); + return ptr_[idx]; + } + iterator begin() { return iterator(ptr_); } + iterator end() { return iterator(ptr_ + count_); } + const_iterator begin() const { return const_iterator(ptr_); } + const_iterator end() const { return const_iterator(ptr_ + count_); } + common::ObIAllocator *get_allocator() const { return allocator_; } + + // 获取一份引用 + ObTableLoadArray &operator=(const ObTableLoadArray &rhs) + { + reset(); + count_ = rhs.count_; + ptr_ = rhs.ptr_; + allocator_ = rhs.allocator_; + is_ref_ = true; + return *this; + } + + T &operator[](int64_t idx) + { + OB_ASSERT(idx >= 0 && idx < count_); + return ptr_[idx]; + } + const T &operator[](int64_t idx) const + { + OB_ASSERT(idx >= 0 && idx < count_); + return ptr_[idx]; + } + + // {"array":[xxx, xxx], "is_ref":true} + int64_t to_string(char *buf, const int64_t buf_len) const + { + int64_t pos = 0; + J_OBJ_START(); + J_NAME("array"); + J_COLON(); + J_ARRAY_START(); + if (count_ > 0) { + BUF_PRINTO(ptr_[0]); + } + for (int64_t i = 1; i < count_; ++i) { + J_COMMA(); + BUF_PRINTO(ptr_[i]); + } + J_ARRAY_END(); + J_COMMA(); + J_KV("is_ref", is_ref_); + J_OBJ_END(); + return pos; + } + +private: + int64_t count_; + T *ptr_; + common::ObIAllocator *allocator_; + bool is_ref_; // 是否是引用, 不参与序列化 +}; + +template +int ObTableLoadArray::serialize(SERIAL_PARAMS) const +{ + int ret = common::OB_SUCCESS; + OB_UNIS_ENCODE_ARRAY(ptr_, count_); + return ret; +} + +template +int ObTableLoadArray::deserialize(DESERIAL_PARAMS) +{ + int ret = common::OB_SUCCESS; + reset(); + OB_UNIS_DECODE(count_); + if (OB_SUCC(ret)) { + if (OB_ISNULL(allocator_)) { + ret = common::OB_INVALID_ARGUMENT; + OB_LOG(WARN, "allocator is null", KR(ret)); + } else if (count_ > 0) { + if (OB_FAIL(create(count_, *allocator_))) { + OB_LOG(WARN, "fail to create", KR(ret)); + } + } + } + OB_UNIS_DECODE_ARRAY(ptr_, count_); + return ret; +} + +template +int64_t ObTableLoadArray::get_serialize_size() const +{ + int64_t len = 0; + OB_UNIS_ADD_LEN_ARRAY(ptr_, count_); + return len; +} + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_define.cpp b/src/share/table/ob_table_load_define.cpp new file mode 100644 index 0000000000..937f741402 --- /dev/null +++ b/src/share/table/ob_table_load_define.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX CLIENT + +#include "ob_table_load_define.h" + +namespace oceanbase +{ +namespace table +{ + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadFlag, flag_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadConfig, + session_count_, + batch_size_, + max_error_row_count_, + flag_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadSegmentID, + id_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadTransId, + segment_id_, + trans_gid_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadPartitionId, + partition_id_, + tablet_id_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadLSIdAndPartitionId, + ls_id_, + part_tablet_id_); + +OB_SERIALIZE_MEMBER_SIMPLE(ObTableLoadResultInfo, + rows_affected_, + records_, + deleted_, + skipped_, + warnings_); + +OB_DEF_SERIALIZE(ObTableLoadSqlStatistics) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(table_stat_array_.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < table_stat_array_.count(); i++) { + if (table_stat_array_.at(i) != nullptr) { + OB_UNIS_ENCODE(*table_stat_array_.at(i)); + } + } + OB_UNIS_ENCODE(col_stat_array_.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < col_stat_array_.count(); i++) { + if (col_stat_array_.at(i) != nullptr) { + OB_UNIS_ENCODE(*col_stat_array_.at(i)); + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObTableLoadSqlStatistics) +{ + int ret = OB_SUCCESS; + reset(); + int64_t size = 0; + OB_UNIS_DECODE(size) + for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) { + ObOptTableStat table_stat; + ObOptTableStat *copied_table_stat = nullptr; + if (OB_FAIL(table_stat.deserialize(buf, data_len, pos))) { + LOG_WARN("deserialize datum store failed", K(ret), K(i)); + } else { + int64_t size = table_stat.size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(table_stat.deep_copy(new_buf, size, copied_table_stat))) { + OB_LOG(WARN, "fail to copy table stat", KR(ret)); + } else if (OB_FAIL(table_stat_array_.push_back(copied_table_stat))) { + OB_LOG(WARN, "fail to add table stat", KR(ret)); + } + if (OB_FAIL(ret)) { + if (copied_table_stat != nullptr) { + copied_table_stat->~ObOptTableStat(); + copied_table_stat = nullptr; + } + if(new_buf != nullptr) { + allocator_.free(new_buf); + new_buf = nullptr; + } + } + } + } + size = 0; + OB_UNIS_DECODE(size) + for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) { + ObArenaAllocator allocator; + ObOptColumnStat col_stat(allocator); + ObOptColumnStat *copied_col_stat = nullptr; + if (OB_FAIL(col_stat.deserialize(buf, data_len, pos))) { + LOG_WARN("deserialize datum store failed", K(ret), K(i)); + } else { + int64_t size = col_stat.size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(col_stat.deep_copy(new_buf, size, copied_col_stat))) { + OB_LOG(WARN, "fail to copy table stat", KR(ret)); + } else if (OB_FAIL(col_stat_array_.push_back(copied_col_stat))) { + OB_LOG(WARN, "fail to add table stat", KR(ret)); + } + if (OB_FAIL(ret)) { + if (copied_col_stat != nullptr) { + copied_col_stat->~ObOptColumnStat(); + copied_col_stat = nullptr; + } + if(new_buf != nullptr) { + allocator_.free(new_buf); + new_buf = nullptr; + } + } + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObTableLoadSqlStatistics) +{ + int ret = OB_SUCCESS; + int64_t len = 0; + OB_UNIS_ADD_LEN(table_stat_array_.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < table_stat_array_.count(); i++) { + if (table_stat_array_.at(i) != nullptr) { + OB_UNIS_ADD_LEN(*table_stat_array_.at(i)); + } + } + OB_UNIS_ADD_LEN(col_stat_array_.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < col_stat_array_.count(); i++) { + if (col_stat_array_.at(i) != nullptr) { + OB_UNIS_ADD_LEN(*col_stat_array_.at(i)); + } + } + return len; +} + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_define.h b/src/share/table/ob_table_load_define.h new file mode 100644 index 0000000000..2d5d442561 --- /dev/null +++ b/src/share/table/ob_table_load_define.h @@ -0,0 +1,538 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "lib/utility/ob_print_utils.h" +#include "lib/utility/ob_unify_serialize.h" +#include "share/ob_ls_id.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_print_utils.h" +#include "share/stat/ob_opt_table_stat.h" +#include "share/stat/ob_opt_column_stat.h" + +namespace oceanbase +{ +namespace table +{ + +static const int64_t TABLE_LOAD_CTX_ID = common::ObCtxIds::WORK_AREA; + +struct ObTableLoadFlag +{ + OB_UNIS_VERSION(1); +public: + static const uint64_t BIT_IS_NEED_SORT = 1; + static const uint64_t BIT_DATA_TYPE = 2; + static const uint64_t BIT_RESERVED = 61; + + union { + uint64_t flag_; + struct { + uint64_t is_need_sort_ : BIT_IS_NEED_SORT; + uint64_t data_type_ : BIT_DATA_TYPE; + uint64_t reserved_ : BIT_RESERVED; + }; + }; + + ObTableLoadFlag() : flag_(0) {} + void reset() { flag_ = 0; } + TO_STRING_KV(K_(is_need_sort), K_(data_type)); +}; + +struct ObTableLoadConfig final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfig() : session_count_(0), batch_size_(0), max_error_row_count_(0) {} + int32_t session_count_; + int32_t batch_size_; + uint64_t max_error_row_count_; + ObTableLoadFlag flag_; + + TO_STRING_KV(K_(session_count), K_(batch_size), K_(max_error_row_count), K_(flag)); +}; + +struct ObTableLoadPartitionId +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPartitionId() : partition_id_(common::OB_INVALID_ID) {} + ObTableLoadPartitionId(uint64_t partition_id, const common::ObTabletID &tablet_id) + : partition_id_(partition_id), tablet_id_(tablet_id) {} + ObTableLoadPartitionId(const ObTableLoadPartitionId &other) + : partition_id_(other.partition_id_), tablet_id_(other.tablet_id_) {} + uint64_t partition_id_; + common::ObTabletID tablet_id_; + bool is_valid() const + { + return common::OB_INVALID_ID != partition_id_ && tablet_id_.is_valid(); + } + ObTableLoadPartitionId &operator=(const ObTableLoadPartitionId &other) + { + partition_id_ = other.partition_id_; + tablet_id_ = other.tablet_id_; + return *this; + } + bool operator==(const ObTableLoadPartitionId &other) const + { + return (partition_id_ == other.partition_id_ && tablet_id_ == other.tablet_id_); + } + bool operator!=(const ObTableLoadPartitionId &other) const + { + return !(*this == other); + } + bool operator<(const ObTableLoadPartitionId &other) const + { + return (partition_id_ != other.partition_id_ ? partition_id_ < other.partition_id_ + : tablet_id_ < other.tablet_id_); + } + bool operator>(const ObTableLoadPartitionId &other) const + { + return (partition_id_ != other.partition_id_ ? partition_id_ > other.partition_id_ + : tablet_id_ > other.tablet_id_); + } + bool operator<=(const ObTableLoadPartitionId &other) const + { + return !(*this > other); + } + bool operator>=(const ObTableLoadPartitionId &other) const + { + return !(*this < other); + } + uint64_t hash() const + { + uint64_t hash_val = common::murmurhash(&partition_id_, sizeof(partition_id_), 0); + hash_val = common::murmurhash(&tablet_id_, sizeof(tablet_id_), hash_val); + return hash_val; + } + int compare(const ObTableLoadPartitionId &other) const + { + return (partition_id_ != other.partition_id_ ? partition_id_ - other.partition_id_ + : tablet_id_.compare(other.tablet_id_)); + } + TO_STRING_KV(K_(partition_id), K_(tablet_id)); +}; + +struct ObTableLoadLSIdAndPartitionId +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadLSIdAndPartitionId() {} + ObTableLoadLSIdAndPartitionId(const share::ObLSID &ls_id, const ObTableLoadPartitionId &partition_id) + : ls_id_(ls_id), part_tablet_id_(partition_id) + { + } + share::ObLSID ls_id_; + ObTableLoadPartitionId part_tablet_id_; + + ObTableLoadLSIdAndPartitionId &operator=(const ObTableLoadLSIdAndPartitionId &other) + { + ls_id_ = other.ls_id_; + part_tablet_id_ = other.part_tablet_id_; + return *this; + } + + bool is_valid() const + { + return ls_id_.is_valid() && part_tablet_id_.is_valid(); + } + + TO_STRING_KV(K_(ls_id), K_(part_tablet_id)); +}; + +struct ObTableLoadLSTabletID +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadLSTabletID() {} + ObTableLoadLSTabletID(const share::ObLSID &ls_id, const common::ObTabletID &tablet_id) + : ls_id_(ls_id), tablet_id_(tablet_id) + { + } + ObTableLoadLSTabletID &operator=(const ObTableLoadLSTabletID &other) + { + ls_id_ = other.ls_id_; + tablet_id_ = other.tablet_id_; + return *this; + } + bool is_valid() const + { + return ls_id_.is_valid() && tablet_id_.is_valid(); + } + TO_STRING_KV(K_(ls_id), K_(tablet_id)); +public: + share::ObLSID ls_id_; + common::ObTabletID tablet_id_; +}; + +enum class ObTableLoadStatusType : int64_t +{ + NONE = 0, + INITED, // 初始化 + LOADING, // 只有LOADING状态能创建trans + FROZEN, // 冻结, 不再创建trans + MERGING, // 合并中 + MERGED, // 合并完成 + COMMIT, // 完成 + ERROR, + ABORT, +}; + +struct ObTableLoadSegmentID final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadSegmentID() : id_(common::OB_INVALID_ID) {} + explicit ObTableLoadSegmentID(uint64_t id) : id_(id) {} + void reset() { id_ = common::OB_INVALID_ID; } + bool is_valid() const { return id_ != common::OB_INVALID_ID; } + ObTableLoadSegmentID &operator=(const uint64_t id) + { + id_ = id; + return *this; + } + ObTableLoadSegmentID &operator=(const ObTableLoadSegmentID &other) + { + id_ = other.id_; + return *this; + } + bool operator==(const ObTableLoadSegmentID &other) const + { + return (id_ == other.id_); + } + bool operator!=(const ObTableLoadSegmentID &other) const + { + return !(*this == other); + } + bool operator<(const ObTableLoadSegmentID &other) const + { + return (id_ < other.id_); + } + bool operator>(const ObTableLoadSegmentID &other) const + { + return (id_ > other.id_); + } + bool operator>=(const ObTableLoadSegmentID &other) const + { + return !(*this < other); + } + bool operator<=(const ObTableLoadSegmentID &other) const + { + return !(*this > other); + } + uint64_t hash() const + { + uint64_t hash_val = common::murmurhash(&id_, sizeof(id_), 0); + return hash_val; + } + int compare(const ObTableLoadSegmentID &other) const + { + return id_ - other.id_; + } + TO_STRING_KV(K_(id)); +public: + uint64_t id_; +}; + +struct ObTableLoadTransId final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadTransId() : trans_gid_(common::OB_INVALID_ID) {} + ObTableLoadTransId(const ObTableLoadSegmentID &segment_id, uint64_t trans_gid) + : segment_id_(segment_id), trans_gid_(trans_gid) + { + } + void reset() + { + segment_id_.reset(); + trans_gid_ = common::OB_INVALID_ID; + } + bool is_valid() const + { + return segment_id_.is_valid() && common::OB_INVALID_ID != trans_gid_; + } + bool operator==(const ObTableLoadTransId &other) const + { + return (segment_id_ == other.segment_id_ && trans_gid_ == other.trans_gid_); + } + bool operator!=(const ObTableLoadTransId &other) const + { + return !(*this == other); + } + bool operator<(const ObTableLoadTransId &other) const + { + return (segment_id_ != other.segment_id_ ? segment_id_ < other.segment_id_ + : trans_gid_ < other.trans_gid_); + } + bool operator>(const ObTableLoadTransId &other) const + { + return (segment_id_ != other.segment_id_ ? segment_id_ > other.segment_id_ + : trans_gid_ > other.trans_gid_); + } + bool operator>=(const ObTableLoadTransId &other) const + { + return !(*this < other); + } + bool operator<=(const ObTableLoadTransId &other) const + { + return !(*this > other); + } + uint64_t hash() const + { + uint64_t hash_val = segment_id_.hash(); + hash_val = common::murmurhash(&trans_gid_, sizeof(trans_gid_), hash_val); + return hash_val; + } + int compare(const ObTableLoadTransId &other) const + { + return (segment_id_ != other.segment_id_ ? segment_id_.compare(other.segment_id_) + : trans_gid_ - other.trans_gid_); + } + TO_STRING_KV(K_(segment_id), K_(trans_gid)); +public: + ObTableLoadSegmentID segment_id_; + uint64_t trans_gid_; +}; + +enum class ObTableLoadTransStatusType : int64_t +{ + NONE = 0, + INITED, + RUNNING, + FROZEN, + COMMIT, + ERROR, + ABORT, +}; + +static int table_load_status_to_string(ObTableLoadStatusType status, + common::ObString &status_str) +{ + int ret = OB_SUCCESS; + + switch (status) { + case ObTableLoadStatusType::NONE: + status_str = "none"; + break; + case ObTableLoadStatusType::INITED: + status_str = "inited"; + break; + case ObTableLoadStatusType::LOADING: + status_str = "loading"; + break; + case ObTableLoadStatusType::FROZEN: + status_str = "frozen"; + break; + case ObTableLoadStatusType::MERGING: + status_str = "merging"; + break; + case ObTableLoadStatusType::MERGED: + status_str = "merged"; + break; + case ObTableLoadStatusType::COMMIT: + status_str = "commit"; + break; + case ObTableLoadStatusType::ABORT: + status_str = "abort"; + break; + case ObTableLoadStatusType::ERROR: + status_str = "error"; + break; + default: + ret = OB_INVALID_ARGUMENT; + break; + } + + return ret; +} + +static int table_load_trans_status_to_string(ObTableLoadTransStatusType trans_status, + common::ObString &status_str) +{ + int ret = OB_SUCCESS; + + switch (trans_status) { + case ObTableLoadTransStatusType::NONE: + status_str = "none"; + break; + case ObTableLoadTransStatusType::INITED: + status_str = "inited"; + break; + case ObTableLoadTransStatusType::RUNNING: + status_str = "running"; + break; + case ObTableLoadTransStatusType::FROZEN: + status_str = "frozen"; + break; + case ObTableLoadTransStatusType::COMMIT: + status_str = "commit"; + break; + case ObTableLoadTransStatusType::ABORT: + status_str = "abort"; + break; + case ObTableLoadTransStatusType::ERROR: + status_str = "error"; + break; + default: + ret = OB_INVALID_ARGUMENT; + break; + } + + return ret; +} + +struct ObTableLoadResultInfo +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadResultInfo() : rows_affected_(0), records_(0), deleted_(0), skipped_(0), warnings_(0) {} + ~ObTableLoadResultInfo() {} + TO_STRING_KV(K_(rows_affected), K_(records), K_(deleted), K_(skipped), K_(warnings)); +public: + uint64_t rows_affected_ CACHE_ALIGNED; + uint64_t records_ CACHE_ALIGNED; + uint64_t deleted_ CACHE_ALIGNED; + uint64_t skipped_ CACHE_ALIGNED; + uint64_t warnings_ CACHE_ALIGNED; +}; + +struct ObTableLoadSqlStatistics +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadSqlStatistics() : allocator_("TLD_Opstat") {} + ~ObTableLoadSqlStatistics() { reset();} + void reset() { + for (int64_t i = 0; i < col_stat_array_.count(); ++i) { + ObOptColumnStat *col_stat = col_stat_array_.at(i); + if (col_stat != nullptr) { + col_stat->~ObOptColumnStat(); + } + } + col_stat_array_.reset(); + for (int64_t i = 0; i < table_stat_array_.count(); ++i) { + ObOptTableStat *table_stat = table_stat_array_.at(i); + if (table_stat != nullptr) { + table_stat->~ObOptTableStat(); + } + } + table_stat_array_.reset(); + allocator_.reset(); + }; + bool is_empty() const + { + return table_stat_array_.count() == 0 || col_stat_array_.count() == 0; + } + int allocate_table_stat(ObOptTableStat *&table_stat) + { + int ret = OB_SUCCESS; + ObOptTableStat *new_table_stat = OB_NEWx(ObOptTableStat, (&allocator_)); + if (OB_ISNULL(new_table_stat)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret)); + } else if (OB_FAIL(table_stat_array_.push_back(new_table_stat))) { + OB_LOG(WARN, "fail to push back", KR(ret)); + } else { + table_stat = new_table_stat; + } + if (OB_FAIL(ret)) { + if (new_table_stat != nullptr) { + new_table_stat->~ObOptTableStat(); + allocator_.free(new_table_stat); + new_table_stat = nullptr; + } + } + return ret; + } + int allocate_col_stat(ObOptColumnStat *&col_stat) + { + int ret = OB_SUCCESS; + ObOptColumnStat *new_col_stat = OB_NEWx(ObOptColumnStat, (&allocator_), allocator_); + if (OB_ISNULL(new_col_stat)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret)); + } else if (OB_FAIL(col_stat_array_.push_back(new_col_stat))) { + OB_LOG(WARN, "fail to push back", KR(ret)); + } else { + col_stat = new_col_stat; + } + if (OB_FAIL(ret)) { + if (new_col_stat != nullptr) { + new_col_stat->~ObOptColumnStat(); + allocator_.free(new_col_stat); + new_col_stat = nullptr; + } + } + return ret; + } + int add(const ObTableLoadSqlStatistics& other) + { + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret)&& i < other.table_stat_array_.count(); ++i) { + ObOptTableStat *table_stat = other.table_stat_array_.at(i); + if (table_stat != nullptr) { + ObOptTableStat *copied_table_stat = nullptr; + int64_t size = table_stat->size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(table_stat->deep_copy(new_buf, size, copied_table_stat))) { + OB_LOG(WARN, "fail to copy table stat", KR(ret)); + } else if (OB_FAIL(table_stat_array_.push_back(copied_table_stat))) { + OB_LOG(WARN, "fail to add table stat", KR(ret)); + } + if (OB_FAIL(ret)) { + if (copied_table_stat != nullptr) { + copied_table_stat->~ObOptTableStat(); + copied_table_stat = nullptr; + } + if(new_buf != nullptr) { + allocator_.free(new_buf); + new_buf = nullptr; + } + } + } + } + for (int64_t i = 0; OB_SUCC(ret)&& i < other.col_stat_array_.count(); ++i) { + ObOptColumnStat *col_stat = other.col_stat_array_.at(i); + if (col_stat != nullptr) { + ObOptColumnStat *copied_col_stat = nullptr; + int64_t size = col_stat->size(); + char *new_buf = nullptr;; + if (OB_ISNULL(new_buf = static_cast(allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(col_stat->deep_copy(new_buf, size, copied_col_stat))) { + OB_LOG(WARN, "fail to copy col stat", KR(ret)); + } else if (OB_FAIL(col_stat_array_.push_back(copied_col_stat))) { + OB_LOG(WARN, "fail to add col stat", KR(ret)); + } + if (OB_FAIL(ret)) { + if (copied_col_stat != nullptr) { + copied_col_stat->~ObOptColumnStat(); + copied_col_stat = nullptr; + } + if (new_buf != nullptr) { + allocator_.free(new_buf); + new_buf = nullptr; + } + } + } + } + return ret; + } + TO_STRING_KV(K_(col_stat_array), K_(table_stat_array)); +public: + common::ObSEArray table_stat_array_; + common::ObSEArray col_stat_array_; + common::ObArenaAllocator allocator_; +}; + + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_handle.h b/src/share/table/ob_table_load_handle.h new file mode 100644 index 0000000000..0cb34d862c --- /dev/null +++ b/src/share/table/ob_table_load_handle.h @@ -0,0 +1,85 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#ifndef OB_TABLE_LOAD_HANDLE_H_ +#define OB_TABLE_LOAD_HANDLE_H_ + +#include "lib/allocator/ob_malloc.h" + +namespace oceanbase +{ +namespace table +{ + +template +class ObTableLoadHandle +{ + class Object + { + public: + Object(Args... args) : ref_count_(0), object_(args...) {} + public: + int32_t ref_count_; + T object_; + }; + +public: + ObTableLoadHandle() : ptr_(nullptr) {} + virtual ~ObTableLoadHandle() { + int32_t ref_count = ATOMIC_AAF(&(ptr_->ref_count_), -1); + if (ref_count == 0) { + if (ptr_ != nullptr) { + ptr_->~Object(); + ob_free(ptr_); + } + } + } + + static ObTableLoadHandle make_handle(Args... args) + { + ObTableLoadHandle handle; + handle.ptr_ = OB_NEW(Object, "TLD_handle", args...); + handle.ptr_->ref_count_ = 1; + return handle; + } + + ObTableLoadHandle(ObTableLoadHandle &other) { + ptr_ = other.ptr_; + ATOMIC_AAF(&(ptr_->ref_count_), 1); + } + + ObTableLoadHandle(ObTableLoadHandle &&other) { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + + void operator= (ObTableLoadHandle &other) { + ptr_ = other.ptr_; + ATOMIC_AAF(&(ptr_->ref_count_), 1); + } + + operator bool() { + return ptr_ != nullptr; + } + + T *operator->() { + return &(ptr_->object_); + } + + T &operator*() { + return ptr_->object_; + } + +private: + DISALLOW_COPY_AND_ASSIGN(ObTableLoadHandle); + +private: + // data members + Object *ptr_; +}; + +} +} + +#endif /* OB_TABLE_LOAD_HANDLE_H_ */ diff --git a/src/share/table/ob_table_load_row.cpp b/src/share/table/ob_table_load_row.cpp new file mode 100644 index 0000000000..f057dbdfcc --- /dev/null +++ b/src/share/table/ob_table_load_row.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SERVER + +#include "share/table/ob_table_load_row.h" + +namespace oceanbase +{ +namespace table +{ +using namespace common; + +OB_DEF_SERIALIZE_SIMPLE(ObTableLoadTabletObjRow) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(tablet_id_); + OB_UNIS_ENCODE(obj_row_); + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObTableLoadTabletObjRow) +{ + int ret = OB_SUCCESS; + OB_UNIS_DECODE(tablet_id_); + OB_UNIS_DECODE(obj_row_); + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObTableLoadTabletObjRow) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(tablet_id_); + OB_UNIS_ADD_LEN(obj_row_); + return len; +} + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_row.h b/src/share/table/ob_table_load_row.h new file mode 100644 index 0000000000..38a2e0de43 --- /dev/null +++ b/src/share/table/ob_table_load_row.h @@ -0,0 +1,185 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "share/table/ob_table_load_shared_allocator.h" +#include "observer/table_load/ob_table_load_utils.h" +#include "lib/utility/ob_unify_serialize.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_print_utils.h" +#include "common/object/ob_object.h" +#include "common/ob_tablet_id.h" + +namespace oceanbase +{ +namespace table +{ +template +class ObTableLoadRow +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadRow() : cells_(nullptr), count_(0) {} + virtual ~ObTableLoadRow() {} + void reset(); + int init(int64_t count, const ObTableLoadSharedAllocatorHandle &allocator_handle); + int deep_copy_and_assign(const T *row, int64_t count, + const ObTableLoadSharedAllocatorHandle &allocator_handle); + // for deserialize() + void set_allocator(const ObTableLoadSharedAllocatorHandle &allocator_handle) + { + allocator_handle_ = allocator_handle; + } + TO_STRING_KV(K_(count)); + +private: + static int allocate_cells(T *&cells, int64_t count, + const ObTableLoadSharedAllocatorHandle &allocator_handle); + +public: + ObTableLoadSharedAllocatorHandle allocator_handle_; + T *cells_; + int64_t count_; +}; + +template +void ObTableLoadRow::reset() +{ + allocator_handle_.reset(); + cells_ = nullptr; + count_ = 0; +} + +template +int ObTableLoadRow::init(int64_t count, + const ObTableLoadSharedAllocatorHandle &allocator_handle) +{ + int ret = OB_SUCCESS; + T *cells = nullptr; + + reset(); + if (!allocator_handle) { + ret = OB_INVALID_ARGUMENT; + OB_LOG(WARN, "allocator is null", KR(ret)); + } else if (OB_FAIL(allocate_cells(cells, count, allocator_handle))) { + OB_LOG(WARN, "failed to alloate cells", KR(ret), K(count)); + } else { + allocator_handle_ = allocator_handle; + cells_ = cells; + count_ = count; + } + + return ret; +} + +template +int ObTableLoadRow::allocate_cells(T *&cells, int64_t count, + const ObTableLoadSharedAllocatorHandle &allocator_handle) +{ + int ret = OB_SUCCESS; + + if (OB_UNLIKELY(!allocator_handle || (count <= 0))) { + ret = OB_INVALID_ARGUMENT; + OB_LOG(WARN, "allocator is null", KR(ret)); + } else { + cells = (T *)(allocator_handle->alloc(sizeof(T) * count)); + if (OB_ISNULL(cells)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "failed to allocate cells", K(count)); + } else { + new (cells) T[count]; + } + } + + return ret; +} + +template +int ObTableLoadRow::deep_copy_and_assign(const T *row, int64_t count, + const ObTableLoadSharedAllocatorHandle &allocator_handle) +{ + + int ret = OB_SUCCESS; + T *cells = nullptr; + + reset(); + if (OB_FAIL(allocate_cells(cells, count, allocator_handle))) { + OB_LOG(WARN, "failed to allocate cells", KR(ret), K(count)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < count; i ++) { + if (OB_FAIL(observer::ObTableLoadUtils::deep_copy(row[i], + cells[i], allocator_handle->get_allocator()))) { + OB_LOG(WARN, "fail to deep copy object", KR(ret)); + } + } + if (OB_SUCC(ret)) { + allocator_handle_ = allocator_handle; + cells_ = cells; + count_ = count; + } + + return ret; +} + +template +int ObTableLoadRow::serialize(SERIAL_PARAMS) const +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE_ARRAY(cells_, count_); + return ret; +} + +template +int ObTableLoadRow::deserialize(DESERIAL_PARAMS) +{ + int ret = OB_SUCCESS; + int64_t count = 0; + OB_UNIS_DECODE(count); + if (OB_SUCC(ret) && (count > 0)) { + T *cells = nullptr; + if (OB_FAIL(allocate_cells(cells, count, allocator_handle_))) { + OB_LOG(WARN, "failed to allocate cells", KR(ret), K(count)); + } else { + OB_UNIS_DECODE_ARRAY(cells, count); + } + + if (OB_SUCC(ret)) { + cells_ = cells; + count_ = count; + } + } + + return ret; +} + +template +int64_t ObTableLoadRow::get_serialize_size() const +{ + int64_t len = 0; + OB_UNIS_ADD_LEN_ARRAY(cells_, count_); + return len; +} + +typedef ObTableLoadRow ObTableLoadObjRow; +typedef ObTableLoadRow ObTableLoadStrRow; + +class ObTableLoadTabletObjRow +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadTabletObjRow() {} + void set_allocator(const ObTableLoadSharedAllocatorHandle &allocator_handle) + { + obj_row_.set_allocator(allocator_handle); + } + TO_STRING_KV(K_(tablet_id), K_(obj_row)); + +public: + common::ObTabletID tablet_id_; + ObTableLoadObjRow obj_row_; +}; + +} // namespace table +} // namespace oceanbase \ No newline at end of file diff --git a/src/share/table/ob_table_load_row_array.h b/src/share/table/ob_table_load_row_array.h new file mode 100644 index 0000000000..548f306217 --- /dev/null +++ b/src/share/table/ob_table_load_row_array.h @@ -0,0 +1,138 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "share/table/ob_table_load_shared_allocator.h" +#include "share/table/ob_table_load_row.h" +#include "lib/utility/ob_unify_serialize.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace table +{ +template +class ObTableLoadRowArray +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadRowArray() : allocator_handle_() {} + ~ObTableLoadRowArray() {} + + int push_back(const T &obj_row); + int assign(const ObTableLoadRowArray &other); + void set_allocator(const ObTableLoadSharedAllocatorHandle &allocator_handle) + { + allocator_handle_ = allocator_handle; + } + T &at(int64_t idx); + const T &at(int64_t idx) const; + + void reset() { + array_.reset(); + allocator_handle_.reset(); + } + bool empty() const { + return array_.empty(); + } + int64_t count() const { + return array_.count(); + } + TO_STRING_KV(K(array_.count())); + +private: + ObTableLoadSharedAllocatorHandle allocator_handle_; + common::ObArray array_; +}; + +template +int ObTableLoadRowArray::serialize(SERIAL_PARAMS) const +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(array_.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < array_.count(); i ++) { + OB_UNIS_ENCODE(array_.at(i)); + } + return ret; +} + +template +int ObTableLoadRowArray::deserialize(DESERIAL_PARAMS) +{ + int ret = OB_SUCCESS; + int64_t count = 0; + OB_UNIS_DECODE(count); + if (!allocator_handle_) { + ret = OB_INVALID_ARGUMENT; + OB_LOG(WARN, "allocator handle is null", KR(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && (i < count); ++i) { + T row; + row.set_allocator(allocator_handle_); + OB_UNIS_DECODE(row); + if (OB_SUCC(ret)) { + if (OB_FAIL(array_.push_back(row))) { + OB_LOG(WARN, "fail to push back row to array", K(ret), K(row)); + } + } + } + } + return ret; +} + +template +int64_t ObTableLoadRowArray::get_serialize_size() const +{ + int len = 0; + OB_UNIS_ADD_LEN(array_.count()); + for (int64_t i = 0; i < array_.count(); i ++) { + OB_UNIS_ADD_LEN(array_.at(i)); + } + return len; +} + +template +int ObTableLoadRowArray::push_back(const T &obj_row) +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(array_.push_back(obj_row))) { + OB_LOG(WARN, "failed to push back obj_row to array", KR(ret)); + } + + return ret; +} + +template +int ObTableLoadRowArray::assign(const ObTableLoadRowArray &other) +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(array_.assign(other.array_))) { + OB_LOG(WARN, "failed to assign other array", KR(ret)); + } + + return ret; +} + +template +T &ObTableLoadRowArray::at(int64_t idx) +{ + return array_.at(idx); +} + +template +const T &ObTableLoadRowArray::at(int64_t idx) const +{ + return array_.at(idx); +} + +typedef ObTableLoadRowArray ObTableLoadObjRowArray; +typedef ObTableLoadRowArray ObTableLoadStrRowArray; +typedef ObTableLoadRowArray ObTableLoadTabletObjRowArray; + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_rpc_struct.cpp b/src/share/table/ob_table_load_rpc_struct.cpp new file mode 100644 index 0000000000..e6e392cf59 --- /dev/null +++ b/src/share/table/ob_table_load_rpc_struct.cpp @@ -0,0 +1,267 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX CLIENT + +#include "ob_table_load_rpc_struct.h" + +namespace oceanbase +{ +namespace table +{ +using namespace common; + +/** + * begin + */ + + +OB_SERIALIZE_MEMBER(ObTableLoadBeginRequest, + credential_, + table_name_, + config_); + +OB_SERIALIZE_MEMBER(ObTableLoadBeginResult, + table_id_, + column_names_, + status_, + error_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreBeginPeerRequest, + credential_, + table_id_, + target_table_id_, + config_, + column_count_, + partition_id_array_, + target_partition_id_array_, + dup_action_, + ddl_task_id_, + px_mode_, + online_opt_stat_gather_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreBeginPeerResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmBeginPeerRequest, + credential_, + table_id_) + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmBeginPeerResult, + ret_code_); + +/** + * finish + */ + +OB_SERIALIZE_MEMBER(ObTableLoadFinishRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadFinishResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreMergePeerRequest, + credential_, + table_id_, + committed_trans_id_array_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreMergePeerResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadStartMergePeerRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadStartMergePeerResult, + ret_code_); + +/** + * commit + */ + +OB_SERIALIZE_MEMBER(ObTableLoadCommitRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadCommitResult, + ret_code_, + result_info_, + sql_statistics_); + +OB_SERIALIZE_MEMBER(ObTableLoadCommitPeerRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadCommitPeerResult, + ret_code_, + result_info_, + sql_statistics_); + +/** + * abort + */ + +OB_SERIALIZE_MEMBER(ObTableLoadAbortRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbortResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbortPeerRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbortPeerResult, + ret_code_); + +/** + * get status + */ + +OB_SERIALIZE_MEMBER(ObTableLoadGetStatusRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetStatusResult, + status_, + error_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetStatusPeerRequest, + credential_, + table_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetStatusPeerResult, + status_, + error_code_); + +/** + * load + */ + +OB_SERIALIZE_MEMBER(ObTableLoadRequest, + credential_, + table_id_, + trans_id_, + session_id_, + sequence_no_, + payload_); + +OB_SERIALIZE_MEMBER(ObTableLoadResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadPeerRequest, + credential_, + table_id_, + trans_id_, + session_id_, + sequence_no_, + payload_); + +OB_SERIALIZE_MEMBER(ObTableLoadPeerResult, + ret_code_); + +/** + * start trans + */ + +OB_SERIALIZE_MEMBER(ObTableLoadStartTransRequest, + credential_, + table_id_, + segment_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadStartTransResult, + trans_id_, + trans_status_, + error_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreStartTransPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreStartTransPeerResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmStartTransPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmStartTransPeerResult, + ret_code_); + +/** + * finish trans + */ + +OB_SERIALIZE_MEMBER(ObTableLoadFinishTransRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadFinishTransResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreFinishTransPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadPreFinishTransPeerResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmFinishTransPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadConfirmFinishTransPeerResult, + ret_code_); + +/** + * abandon trans + */ + +OB_SERIALIZE_MEMBER(ObTableLoadAbandonTransRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbandonTransResult, + ret_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbandonTransPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadAbandonTransPeerResult, + ret_code_); + +/** + * get trans status + */ + +OB_SERIALIZE_MEMBER(ObTableLoadGetTransStatusRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetTransStatusResult, + trans_status_, + error_code_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetTransStatusPeerRequest, + credential_, + table_id_, + trans_id_); + +OB_SERIALIZE_MEMBER(ObTableLoadGetTransStatusPeerResult, + trans_status_, + error_code_); + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_rpc_struct.h b/src/share/table/ob_table_load_rpc_struct.h new file mode 100644 index 0000000000..dc7b669846 --- /dev/null +++ b/src/share/table/ob_table_load_rpc_struct.h @@ -0,0 +1,667 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_store_range.h" +#include "lib/net/ob_addr.h" +#include "ob_table_load_array.h" +#include "ob_table_load_define.h" +#include "share/table/ob_table_load_row_array.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" + +namespace oceanbase +{ +namespace table +{ +using common::ObString; + +/** + * begin + */ + +class ObTableLoadBeginRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadBeginRequest() {} + + ObString credential_; + ObString table_name_; + ObTableLoadConfig config_; + + TO_STRING_KV(K_(table_name), K_(config)); +}; + +class ObTableLoadBeginResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadBeginResult() + : table_id_(common::OB_INVALID_ID), + status_(ObTableLoadStatusType::NONE), + error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(table_id), K_(column_names), K_(status), K_(error_code)); +public: + uint64_t table_id_; + ObTableLoadArray column_names_; + ObTableLoadStatusType status_; + int32_t error_code_; +}; + +class ObTableLoadPreBeginPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreBeginPeerRequest() : table_id_(0), target_table_id_(0), column_count_(0), ddl_task_id_(0), px_mode_(0) {} + ObString credential_; + uint64_t table_id_; + uint64_t target_table_id_; + ObTableLoadConfig config_; + uint64_t column_count_; + ObTableLoadArray partition_id_array_;//orig table + ObTableLoadArray target_partition_id_array_;//FIXME: target table + sql::ObLoadDupActionType dup_action_; + int64_t ddl_task_id_; + bool px_mode_; + bool online_opt_stat_gather_; + TO_STRING_KV(K_(table_id), + K_(target_table_id), + K_(config), + K_(column_count), + K_(partition_id_array), + K_(target_partition_id_array), + K_(dup_action), + K_(ddl_task_id), + K_(px_mode), + K_(online_opt_stat_gather)); +}; + +class ObTableLoadPreBeginPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreBeginPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +class ObTableLoadConfirmBeginPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmBeginPeerRequest() {} + + ObString credential_; + uint64_t table_id_; + + TO_STRING_KV(K_(table_id)); +}; + +class ObTableLoadConfirmBeginPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmBeginPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * finish + */ + +class ObTableLoadFinishRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadFinishRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadFinishResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadFinishResult() : ret_code_(common::OB_SUCCESS) {} + TO_STRING_KV(K_(ret_code)); +public: + int32_t ret_code_; +}; + +class ObTableLoadPreMergePeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreMergePeerRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id), K_(committed_trans_id_array)); +public: + ObString credential_; + uint64_t table_id_; + ObTableLoadArray committed_trans_id_array_; +}; + +class ObTableLoadPreMergePeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreMergePeerResult() : ret_code_(common::OB_SUCCESS) {} + TO_STRING_KV(K_(ret_code)); +public: + int32_t ret_code_; +}; + +class ObTableLoadStartMergePeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadStartMergePeerRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadStartMergePeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadStartMergePeerResult() : ret_code_(common::OB_SUCCESS) {} + TO_STRING_KV(K_(ret_code)); +public: + int32_t ret_code_; +}; + +/** + * commit + */ + +class ObTableLoadCommitRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadCommitRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadCommitResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadCommitResult() : ret_code_(common::OB_SUCCESS) {} + TO_STRING_KV(K_(ret_code), K_(result_info), K_(sql_statistics)); +public: + int32_t ret_code_; + ObTableLoadResultInfo result_info_; + ObTableLoadSqlStatistics sql_statistics_; +}; + +class ObTableLoadCommitPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadCommitPeerRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadCommitPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadCommitPeerResult() : ret_code_(common::OB_SUCCESS) {} + TO_STRING_KV(K_(ret_code), K_(result_info), K_(sql_statistics)); +public: + int32_t ret_code_; + ObTableLoadResultInfo result_info_; + ObTableLoadSqlStatistics sql_statistics_; +}; + +/** + * abort + */ + +class ObTableLoadAbortRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbortRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + + TO_STRING_KV(K_(table_id)); +}; + +class ObTableLoadAbortResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbortResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +class ObTableLoadAbortPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbortPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + + TO_STRING_KV(K_(table_id)); +}; + +class ObTableLoadAbortPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbortPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * get status + */ + +class ObTableLoadGetStatusRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetStatusRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadGetStatusResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetStatusResult() + : status_(ObTableLoadStatusType::NONE), error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(status), K_(error_code)); +public: + ObTableLoadStatusType status_; + int32_t error_code_; +}; + +class ObTableLoadGetStatusPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetStatusPeerRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id)); +public: + ObString credential_; + uint64_t table_id_; +}; + +class ObTableLoadGetStatusPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetStatusPeerResult() + : status_(ObTableLoadStatusType::NONE), error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(status), K_(error_code)); +public: + ObTableLoadStatusType status_; + int32_t error_code_; +}; + +/** + * load + */ + +class ObTableLoadRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadRequest() + : table_id_(common::OB_INVALID_ID), session_id_(0), sequence_no_(common::OB_INVALID_ID) {} + + ObString credential_; //这个里面会包含tenant_id, database等信息 + uint64_t table_id_; + ObTableLoadTransId trans_id_; + int32_t session_id_; // 从1开始 + uint64_t sequence_no_; // 从1开始 + ObString payload_; //里面包的是ObTableLoadObjArray / ObTableLoadStrArray / Raw String + + TO_STRING_KV(K_(table_id), K_(trans_id), K_(session_id), K_(sequence_no), K(payload_.length())); +}; + +class ObTableLoadResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +class ObTableLoadPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPeerRequest() + : table_id_(common::OB_INVALID_ID), + session_id_(0), + sequence_no_(common::OB_INVALID_ID) {} + + ObString credential_; //这个里面会包含tenant_id, database等信息 + uint64_t table_id_; + ObTableLoadTransId trans_id_; + int32_t session_id_; // 从1开始 + uint64_t sequence_no_; // 从1开始 + ObString payload_; //里面包的是ObTableLoadObjArray + + TO_STRING_KV(K_(table_id), K_(trans_id), K_(session_id), K_(sequence_no)); +}; + +class ObTableLoadPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * start trans + */ + +class ObTableLoadStartTransRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadStartTransRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id), K_(segment_id)); +public: + ObString credential_; + uint64_t table_id_; + ObTableLoadSegmentID segment_id_; +}; + +class ObTableLoadStartTransResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadStartTransResult() + : trans_status_(ObTableLoadTransStatusType::NONE), error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(trans_id), K_(trans_status), K_(error_code)); +public: + ObTableLoadTransId trans_id_; + ObTableLoadTransStatusType trans_status_; + int32_t error_code_; +}; + +class ObTableLoadPreStartTransPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreStartTransPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadPreStartTransPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreStartTransPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + + +class ObTableLoadConfirmStartTransPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmStartTransPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadConfirmStartTransPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmStartTransPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * finish trans + */ + +class ObTableLoadFinishTransRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadFinishTransRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadFinishTransResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadFinishTransResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +class ObTableLoadPreFinishTransPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreFinishTransPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadPreFinishTransPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadPreFinishTransPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + + +class ObTableLoadConfirmFinishTransPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmFinishTransPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadConfirmFinishTransPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadConfirmFinishTransPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * abandon trans + */ + +class ObTableLoadAbandonTransRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbandonTransRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadAbandonTransResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbandonTransResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +class ObTableLoadAbandonTransPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbandonTransPeerRequest() : table_id_(common::OB_INVALID_ID) {} + + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; + + TO_STRING_KV(K_(table_id), K_(trans_id)); +}; + +class ObTableLoadAbandonTransPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadAbandonTransPeerResult() : ret_code_(common::OB_SUCCESS) {} + + int32_t ret_code_; + + TO_STRING_KV(K_(ret_code)); +}; + +/** + * get trans status + */ + +class ObTableLoadGetTransStatusRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetTransStatusRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id), K_(trans_id)); +public: + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; +}; + +class ObTableLoadGetTransStatusResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetTransStatusResult() + : trans_status_(ObTableLoadTransStatusType::NONE), error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(trans_status), K_(error_code)); +public: + ObTableLoadTransStatusType trans_status_; + int32_t error_code_; +}; + +class ObTableLoadGetTransStatusPeerRequest final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetTransStatusPeerRequest() : table_id_(common::OB_INVALID_ID) {} + TO_STRING_KV(K_(table_id), K_(trans_id)); +public: + ObString credential_; + uint64_t table_id_; + ObTableLoadTransId trans_id_; +}; + +class ObTableLoadGetTransStatusPeerResult final +{ + OB_UNIS_VERSION(1); +public: + ObTableLoadGetTransStatusPeerResult() + : trans_status_(ObTableLoadTransStatusType::NONE), error_code_(common::OB_SUCCESS) + { + } + TO_STRING_KV(K_(trans_status), K_(error_code)); +public: + ObTableLoadTransStatusType trans_status_; + int32_t error_code_; +}; + +} // namespace table +} // namespace oceanbase diff --git a/src/share/table/ob_table_load_shared_allocator.cpp b/src/share/table/ob_table_load_shared_allocator.cpp new file mode 100644 index 0000000000..6152ab4a42 --- /dev/null +++ b/src/share/table/ob_table_load_shared_allocator.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SERVER + +#include "share/table/ob_table_load_shared_allocator.h" +#include "share/ob_errno.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace table +{ +using namespace common; + +ObTableLoadSharedAllocator::ObTableLoadSharedAllocator() + : allocator_("TLD_share_alloc"), + ref_count_(0) +{ + allocator_.set_tenant_id(MTL_ID()); +} + +ObTableLoadSharedAllocator::~ObTableLoadSharedAllocator() +{ + OB_ASSERT(0 == get_ref_count()); +} + +void *ObTableLoadSharedAllocator::alloc(const int64_t size) +{ + return allocator_.alloc(size); +} + +void ObTableLoadSharedAllocator::free(void *ptr) +{ + allocator_.free(ptr); +} + +ObTableLoadSharedAllocatorHandle::ObTableLoadSharedAllocatorHandle( + ObTableLoadSharedAllocator *allocator) + : allocator_(allocator) +{ + if (OB_NOT_NULL(allocator_)) { + allocator_->inc_ref_count(); + } +} + +ObTableLoadSharedAllocatorHandle::ObTableLoadSharedAllocatorHandle( + const ObTableLoadSharedAllocatorHandle &other) +{ + if (other.allocator_ != allocator_) { + allocator_ = other.allocator_; + if (OB_NOT_NULL(allocator_)) { + allocator_->inc_ref_count(); + } + } +} + +ObTableLoadSharedAllocatorHandle::~ObTableLoadSharedAllocatorHandle() +{ + if (OB_NOT_NULL(allocator_)) { + if (allocator_->dec_ref_count() == 0) { + allocator_->~ObTableLoadSharedAllocator(); + ob_free(allocator_); + } + allocator_ = nullptr; + } +} + +ObTableLoadSharedAllocatorHandle &ObTableLoadSharedAllocatorHandle::operator=( + const ObTableLoadSharedAllocatorHandle &other) +{ + if (other.allocator_ != allocator_) { + allocator_ = other.allocator_; + if (OB_NOT_NULL(allocator_)) { + allocator_->inc_ref_count(); + } + } + return *this; +} + +ObTableLoadSharedAllocator *ObTableLoadSharedAllocatorHandle::operator->() +{ + return allocator_; +} + +ObTableLoadSharedAllocator *ObTableLoadSharedAllocatorHandle::operator->() const +{ + return allocator_; +} + +ObTableLoadSharedAllocator &ObTableLoadSharedAllocatorHandle::operator*() +{ + return *allocator_; +} + +ObTableLoadSharedAllocatorHandle::operator bool () const +{ + return OB_NOT_NULL(allocator_); +} + +ObTableLoadSharedAllocatorHandle ObTableLoadSharedAllocatorHandle::make_handle() +{ + int ret = OB_SUCCESS; + ObTableLoadSharedAllocator *shared_allocator = (ObTableLoadSharedAllocator *)ob_malloc( + sizeof(ObTableLoadSharedAllocator), ObMemAttr(MTL_ID(), "TLD_share_alloc")); + if (OB_ISNULL(shared_allocator)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", KR(ret)); + } else { + new (shared_allocator) ObTableLoadSharedAllocator; + } + return ObTableLoadSharedAllocatorHandle(shared_allocator); +} + +void ObTableLoadSharedAllocatorHandle::reset() +{ + if (OB_NOT_NULL(allocator_)) { + if (allocator_->dec_ref_count() == 0) { + allocator_->~ObTableLoadSharedAllocator(); + ob_free(allocator_); + } + allocator_ = nullptr; + } +} + +} // namespace table +} // namespace oceanbase \ No newline at end of file diff --git a/src/share/table/ob_table_load_shared_allocator.h b/src/share/table/ob_table_load_shared_allocator.h new file mode 100644 index 0000000000..756d406ab8 --- /dev/null +++ b/src/share/table/ob_table_load_shared_allocator.h @@ -0,0 +1,51 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "lib/allocator/page_arena.h" + +namespace oceanbase +{ +namespace table +{ +class ObTableLoadSharedAllocator +{ +public: + ObTableLoadSharedAllocator(); + ~ObTableLoadSharedAllocator(); + + void *alloc(const int64_t size); + void free(void *ptr); + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } + common::ObArenaAllocator &get_allocator() { return allocator_; } + +private: + common::ObArenaAllocator allocator_; + int64_t ref_count_; +}; + +class ObTableLoadSharedAllocatorHandle +{ +public: + ObTableLoadSharedAllocatorHandle() : allocator_(nullptr) {} + ObTableLoadSharedAllocatorHandle(ObTableLoadSharedAllocator *allocator); + ObTableLoadSharedAllocatorHandle(const ObTableLoadSharedAllocatorHandle &other); + ~ObTableLoadSharedAllocatorHandle(); + + ObTableLoadSharedAllocatorHandle &operator=(const ObTableLoadSharedAllocatorHandle &other); + ObTableLoadSharedAllocator *operator->(); + ObTableLoadSharedAllocator *operator->() const; + ObTableLoadSharedAllocator &operator*(); + operator bool () const; + static ObTableLoadSharedAllocatorHandle make_handle(); + void reset(); + +private: + ObTableLoadSharedAllocator *allocator_; +}; +} // namespace table +} // namespace oceanbase \ No newline at end of file diff --git a/src/share/table/ob_table_rpc_proxy.h b/src/share/table/ob_table_rpc_proxy.h index c32d3c45d7..48adfc0062 100644 --- a/src/share/table/ob_table_rpc_proxy.h +++ b/src/share/table/ob_table_rpc_proxy.h @@ -14,6 +14,7 @@ #define _OB_TABLE_RPC_PROXY_H 1 #include "rpc/obrpc/ob_rpc_proxy.h" #include "share/table/ob_table_rpc_struct.h" +#include "share/table/ob_table_load_rpc_struct.h" #include "share/config/ob_server_config.h" #include "observer/ob_server_struct.h" @@ -31,6 +32,36 @@ public: RPC_SS(PR5 execute_query, obrpc::OB_TABLE_API_EXECUTE_QUERY, (table::ObTableQueryRequest), table::ObTableQueryResult); RPC_S(PR5 query_and_mutate, obrpc::OB_TABLE_API_QUERY_AND_MUTATE, (table::ObTableQueryAndMutateRequest), table::ObTableQueryAndMutateResult); RPC_S(PR5 execute_query_sync, obrpc::OB_TABLE_API_EXECUTE_QUERY_SYNC, (table::ObTableQuerySyncRequest), table::ObTableQuerySyncResult); + + /** + * table load + */ + // client -> server + RPC_S(PR5 load_begin, obrpc::OB_TABLE_API_LOAD_BEGIN, (table::ObTableLoadBeginRequest), table::ObTableLoadBeginResult); + RPC_S(PR5 load_finish, obrpc::OB_TABLE_API_LOAD_FINISH, (table::ObTableLoadFinishRequest), table::ObTableLoadFinishResult); + RPC_S(PR5 load_commit, obrpc::OB_TABLE_API_LOAD_COMMIT, (table::ObTableLoadCommitRequest), table::ObTableLoadCommitResult); + RPC_S(PR5 load_abort, obrpc::OB_TABLE_API_LOAD_ABORT, (table::ObTableLoadAbortRequest), table::ObTableLoadAbortResult); + RPC_S(PR5 load_get_status, obrpc::OB_TABLE_API_LOAD_GET_STATUS, (table::ObTableLoadGetStatusRequest), table::ObTableLoadGetStatusResult); + RPC_S(PR5 load, obrpc::OB_TABLE_API_LOAD, (table::ObTableLoadRequest), table::ObTableLoadResult); + RPC_S(PR5 load_start_trans, obrpc::OB_TABLE_API_LOAD_START_TRANS, (table::ObTableLoadStartTransRequest), table::ObTableLoadStartTransResult); + RPC_S(PR5 load_finish_trans, obrpc::OB_TABLE_API_LOAD_FINISH_TRANS, (table::ObTableLoadFinishTransRequest), table::ObTableLoadFinishTransResult); + RPC_S(PR5 load_abandon_trans, obrpc::OB_TABLE_API_LOAD_ABANDON_TRANS, (table::ObTableLoadAbandonTransRequest), table::ObTableLoadAbandonTransResult); + RPC_S(PR5 load_get_trans_status, obrpc::OB_TABLE_API_LOAD_GET_TRANS_STATUS, (table::ObTableLoadGetTransStatusRequest), table::ObTableLoadGetTransStatusResult); + // coordinator -> peer + RPC_S(PR5 load_pre_begin_peer, obrpc::OB_TABLE_API_LOAD_PRE_BEGIN_PEER, (table::ObTableLoadPreBeginPeerRequest), table::ObTableLoadPreBeginPeerResult); + RPC_S(PR5 load_confirm_begin_peer, obrpc::OB_TABLE_API_LOAD_CONFIRM_BEGIN_PEER, (table::ObTableLoadConfirmBeginPeerRequest), table::ObTableLoadConfirmBeginPeerResult); + RPC_S(PR5 load_pre_merge_peer, obrpc::OB_TABLE_API_LOAD_PRE_MERGE_PEER, (table::ObTableLoadPreMergePeerRequest), table::ObTableLoadPreMergePeerResult); + RPC_S(PR5 load_start_merge_peer, obrpc::OB_TABLE_API_LOAD_START_MERGE_PEER, (table::ObTableLoadStartMergePeerRequest), table::ObTableLoadStartMergePeerResult); + RPC_S(PR5 load_commit_peer, obrpc::OB_TABLE_API_LOAD_COMMIT_PEER, (table::ObTableLoadCommitPeerRequest), table::ObTableLoadCommitPeerResult); + RPC_S(PR5 load_abort_peer, obrpc::OB_TABLE_API_LOAD_ABORT_PEER, (table::ObTableLoadAbortPeerRequest), table::ObTableLoadAbortPeerResult); + RPC_S(PR5 load_get_status_peer, obrpc::OB_TABLE_API_LOAD_GET_STATUS_PEER, (table::ObTableLoadGetStatusPeerRequest), table::ObTableLoadGetStatusPeerResult); + RPC_S(PR5 load_peer, obrpc::OB_TABLE_API_LOAD_PEER, (table::ObTableLoadPeerRequest), table::ObTableLoadPeerResult); + RPC_S(PR5 load_pre_start_trans_peer, obrpc::OB_TABLE_API_LOAD_PRE_START_TRANS_PEER, (table::ObTableLoadPreStartTransPeerRequest), table::ObTableLoadPreStartTransPeerResult); + RPC_S(PR5 load_confirm_start_trans_peer, obrpc::OB_TABLE_API_LOAD_CONFIRM_START_TRANS_PEER, (table::ObTableLoadConfirmStartTransPeerRequest), table::ObTableLoadConfirmStartTransPeerResult); + RPC_S(PR5 load_pre_finish_trans_peer, obrpc::OB_TABLE_API_LOAD_PRE_FINISH_TRANS_PEER, (table::ObTableLoadPreFinishTransPeerRequest), table::ObTableLoadPreFinishTransPeerResult); + RPC_S(PR5 load_confirm_finish_trans_peer, obrpc::OB_TABLE_API_LOAD_CONFIRM_FINISH_TRANS_PEER, (table::ObTableLoadConfirmFinishTransPeerRequest), table::ObTableLoadConfirmFinishTransPeerResult); + RPC_S(PR5 load_abandon_trans_peer, obrpc::OB_TABLE_API_LOAD_ABANDON_TRANS_PEER, (table::ObTableLoadAbandonTransPeerRequest), table::ObTableLoadAbandonTransPeerResult); + RPC_S(PR5 load_get_trans_status_peer, obrpc::OB_TABLE_API_LOAD_GET_TRANS_STATUS_PEER, (table::ObTableLoadGetTransStatusPeerRequest), table::ObTableLoadGetTransStatusPeerResult); }; }; // end namespace obrpc diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index 375582f554..32b20e9f6a 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -177,6 +177,7 @@ ob_set_subtarget(ob_sql engine_cmd engine/cmd/ob_index_executor.cpp engine/cmd/ob_kill_executor.cpp engine/cmd/ob_kill_session_arg.cpp + engine/cmd/ob_load_data_direct_impl.cpp engine/cmd/ob_load_data_executor.cpp engine/cmd/ob_load_data_impl.cpp engine/cmd/ob_load_data_parser.cpp @@ -206,6 +207,8 @@ ob_set_subtarget(ob_sql engine_cmd engine/cmd/ob_variable_set_executor.cpp engine/cmd/ob_xa_executor.cpp engine/cmd/ob_context_executor.cpp + engine/cmd/ob_table_direct_insert_ctx.cpp + engine/cmd/ob_table_direct_insert_trans.cpp ) ob_set_subtarget(ob_sql engine_dml diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 729f3ca858..4b2ce9f7eb 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -135,6 +135,9 @@ #include "sql/engine/basic/ob_stat_collector_op.h" #include "sql/engine/opt_statistics/ob_optimizer_stats_gathering_op.h" #include "lib/utility/ob_tracepoint.h" +#include "sql/engine/cmd/ob_load_data_direct_impl.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" #include "share/stat/ob_stat_define.h" namespace oceanbase @@ -1977,6 +1980,11 @@ int ObStaticEngineCG::generate_insert_with_das(ObLogInsert &op, ObTableInsertSpe spec.use_dist_das_ = op.is_multi_part_dml(); spec.gi_above_ = op.is_gi_above() && !spec.use_dist_das_; spec.is_returning_ = op.is_returning(); + // currently direct-insert does not support non-pdml situation + // if (GCONF._ob_enable_direct_load) { + // spec.plan_->set_append_table_id(op.get_append_table_id()); + // spec.plan_->set_enable_append(op.get_plan()->get_optimizer_context().get_global_hint().has_append()); + // } } } for (int64_t i = 0; OB_SUCC(ret) && i < index_dml_infos.count(); ++i) { @@ -4966,6 +4974,10 @@ int ObStaticEngineCG::generate_spec(ObLogInsert &op, spec.is_pdml_index_maintain_ = op.is_index_maintenance(); spec.table_location_uncertain_ = op.is_table_location_uncertain(); // row-movement target table spec.is_pdml_update_split_ = op.is_pdml_update_split(); + if (GCONF._ob_enable_direct_load) { + spec.plan_->set_append_table_id(op.get_append_table_id()); + spec.plan_->set_enable_append(op.get_plan()->get_optimizer_context().get_global_hint().has_append()); + } int64_t partition_expr_idx = OB_INVALID_INDEX; if (OB_FAIL(get_pdml_partition_id_column_idx(spec.get_child(0)->output_, partition_expr_idx))) { LOG_WARN("failed to get partition id column idx", K(ret)); diff --git a/src/sql/das/ob_das_dml_ctx_define.cpp b/src/sql/das/ob_das_dml_ctx_define.cpp index 4ff10d25ef..b409075b7b 100644 --- a/src/sql/das/ob_das_dml_ctx_define.cpp +++ b/src/sql/das/ob_das_dml_ctx_define.cpp @@ -74,7 +74,8 @@ OB_DEF_SERIALIZE_SIZE(ObDASDMLBaseRtDef) // add by dkz OB_SERIALIZE_MEMBER((ObDASInsRtDef, ObDASDMLBaseRtDef), - need_fetch_conflict_); + need_fetch_conflict_, + direct_insert_task_id_); OB_SERIALIZE_MEMBER((ObDASLockRtDef, ObDASDMLBaseRtDef), diff --git a/src/sql/das/ob_das_dml_ctx_define.h b/src/sql/das/ob_das_dml_ctx_define.h index 506240ef90..7f8b90c0a2 100644 --- a/src/sql/das/ob_das_dml_ctx_define.h +++ b/src/sql/das/ob_das_dml_ctx_define.h @@ -20,6 +20,7 @@ #include "share/schema/ob_table_dml_param.h" #include "storage/tx/ob_clog_encrypt_info.h" #include "sql/engine/ob_operator.h" +#include "sql/resolver/dml/ob_hint.h" namespace oceanbase { namespace sql @@ -153,18 +154,22 @@ public: ObDASInsRtDef() : ObDASDMLBaseRtDef(DAS_OP_TABLE_INSERT), need_fetch_conflict_(false), - is_duplicated_(false) + is_duplicated_(false), + direct_insert_task_id_(0) { } INHERIT_TO_STRING_KV("ObDASBaseRtDef", ObDASDMLBaseRtDef, K_(need_fetch_conflict), - K_(is_duplicated)); + K_(is_duplicated), + K_(direct_insert_task_id)); // used to check whether need to fetch_duplicate_key, will set in table_replace_op bool need_fetch_conflict_; // used to check whether duplicate_key error occurred, will be set in das_insert_op // not need to serialize bool is_duplicated_; + // used in direct-insert mode + int64_t direct_insert_task_id_; }; typedef DASDMLRtDefArray DASInsRtDefArray; diff --git a/src/sql/das/ob_das_insert_op.cpp b/src/sql/das/ob_das_insert_op.cpp index ace0df8891..5e059fbd09 100644 --- a/src/sql/das/ob_das_insert_op.cpp +++ b/src/sql/das/ob_das_insert_op.cpp @@ -52,6 +52,7 @@ int ObDASIndexDMLAdaptor::write_rows(cons { int ret = OB_SUCCESS; ObAccessService *as = MTL(ObAccessService *); + dml_param_.direct_insert_task_id_ = rtdef.direct_insert_task_id_; if (OB_FAIL(as->insert_rows(ls_id, tablet_id, *tx_desc_, diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.cpp b/src/sql/engine/aggregate/ob_aggregate_processor.cpp index 7275d8b09a..0637fa7479 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.cpp +++ b/src/sql/engine/aggregate/ob_aggregate_processor.cpp @@ -4940,7 +4940,6 @@ int ObAggregateProcessor::llc_add_value(const uint64_t value, char *llc_bitmap_b // 理论上pmax不会超过65. llc_bitmap_buf[bucket_index] = static_cast(pmax); } - LOG_DEBUG("llc add value", K(pmax), K(bucket_index)); return ret; } diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.h b/src/sql/engine/aggregate/ob_aggregate_processor.h index c29c10c05c..7b65f4acd1 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.h +++ b/src/sql/engine/aggregate/ob_aggregate_processor.h @@ -672,6 +672,8 @@ public: { io_event_observer_ = observer; } + // used in optimizer statistic gathering. + static int llc_add_value(const uint64_t value, const common::ObString &llc_bitmap_buf); inline void set_op_eval_infos(ObIArray *eval_infos) { op_eval_infos_ = eval_infos; @@ -896,7 +898,6 @@ private: static uint64_t llc_calc_hash_value(const ObChunkDatumStore::StoredRow &stored_row, const ObIArray ¶m_exprs, bool &has_null_cell); - static int llc_add_value(const uint64_t value, const common::ObString &llc_bitmap_buf); static int llc_add(ObDatum &result, const ObDatum &new_value); void set_expr_datum_null(ObExpr *expr); diff --git a/src/sql/engine/cmd/ob_ddl_executor_util.h b/src/sql/engine/cmd/ob_ddl_executor_util.h index fdf6661e16..0bf64c78b2 100644 --- a/src/sql/engine/cmd/ob_ddl_executor_util.h +++ b/src/sql/engine/cmd/ob_ddl_executor_util.h @@ -64,8 +64,8 @@ public: obrpc::ObCommonRpcProxy *common_rpc_proxy, int64_t &affected_rows); static int wait_build_index_finish(const uint64_t tenant_id, const int64_t task_id, bool &is_finish); -private: static int handle_session_exception(ObSQLSessionInfo &session); +private: static int cancel_ddl_task(const int64_t tenant_id, obrpc::ObCommonRpcProxy *common_rpc_proxy); private: DISALLOW_COPY_AND_ASSIGN(ObDDLExecutorUtil); diff --git a/src/sql/engine/cmd/ob_load_data_direct_impl.cpp b/src/sql/engine/cmd/ob_load_data_direct_impl.cpp new file mode 100644 index 0000000000..58115527a7 --- /dev/null +++ b/src/sql/engine/cmd/ob_load_data_direct_impl.cpp @@ -0,0 +1,2079 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX SQL_ENG + +#include "sql/engine/cmd/ob_load_data_direct_impl.h" +#include "observer/omt/ob_tenant.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_coordinator_ctx.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "share/schema/ob_schema_getter_guard.h" +#include "share/ob_device_manager.h" +#include "share/backup/ob_backup_io_adapter.h" + +namespace oceanbase +{ +namespace sql +{ +using namespace common; +using namespace observer; +using namespace share; +using namespace table; +using namespace omt; + +/** + * DataAccessParam + */ + +ObLoadDataDirectImpl::DataAccessParam::DataAccessParam() + : file_column_num_(0), file_cs_type_(CS_TYPE_INVALID) +{ +} + +bool ObLoadDataDirectImpl::DataAccessParam::is_valid() const +{ + return file_column_num_ > 0 && CS_TYPE_INVALID != file_cs_type_; +} + +/** + * LoadExecuteParam + */ + +ObLoadDataDirectImpl::LoadExecuteParam::LoadExecuteParam() + : tenant_id_(OB_INVALID_ID), + database_id_(OB_INVALID_ID), + table_id_(OB_INVALID_ID), + sql_mode_(0), + parallel_(0), + batch_row_count_(0), + data_mem_usage_limit_(0), + need_sort_(false), + online_opt_stat_gather_(false), + max_error_rows_(-1), + ignore_row_num_(-1), + dup_action_(ObLoadDupActionType::LOAD_INVALID_MODE) +{ +} + +bool ObLoadDataDirectImpl::LoadExecuteParam::is_valid() const +{ + return OB_INVALID_ID != tenant_id_ && OB_INVALID_ID != database_id_ && + OB_INVALID_ID != table_id_ && !database_name_.empty() && !table_name_.empty() && + !combined_name_.empty() && parallel_ > 0 && batch_row_count_ > 0 && + data_mem_usage_limit_ > 0 && max_error_rows_ >= 0 && ignore_row_num_ >= 0 && + ObLoadDupActionType::LOAD_INVALID_MODE != dup_action_ && data_access_param_.is_valid() && + !store_column_idxs_.empty(); +} + +/** + * LoadExecuteContext + */ + +ObLoadDataDirectImpl::LoadExecuteContext::LoadExecuteContext() + : direct_loader_(nullptr), + job_stat_(nullptr), + logger_(nullptr) +{ +} + +bool ObLoadDataDirectImpl::LoadExecuteContext::is_valid() const +{ + return nullptr != exec_ctx_ && nullptr != allocator_ && nullptr != direct_loader_ && + nullptr != job_stat_ && nullptr != logger_; +} + +/** + * Logger + */ + +const char *ObLoadDataDirectImpl::Logger::log_file_column_names = + "\nFile\tRow\tErrCode\tErrMsg\t\n"; +const char *ObLoadDataDirectImpl::Logger::log_file_row_fmt = "%.*s\t%ld\t%d\t%s\t\n"; + +ObLoadDataDirectImpl::Logger::Logger() + : is_oracle_mode_(false), buf_(nullptr), is_inited_(false) +{ +} + +ObLoadDataDirectImpl::Logger::~Logger() +{ + if (nullptr != buf_) { + ob_free(buf_); + buf_ = nullptr; + } +} + +int ObLoadDataDirectImpl::Logger::init(const ObString &load_info) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::Logger init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(load_info.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(load_info)); + } else { + ObString file_name; + if (OB_ISNULL( + buf_ = static_cast(ob_malloc(DEFAULT_BUF_LENGTH, ObModIds::OB_SQL_LOAD_DATA)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else if (OB_FAIL(generate_log_file_name(buf_, DEFAULT_BUF_LENGTH, file_name))) { + LOG_WARN("fail to generate log file name", KR(ret)); + } else if (OB_FAIL(file_appender_.open(file_name, false, true))) { + LOG_WARN("fail to open file", KR(ret), K(file_name)); + } else if (OB_FAIL(file_appender_.append(load_info.ptr(), load_info.length(), true))) { + LOG_WARN("fail to append log", KR(ret)); + } else if (OB_FAIL(file_appender_.append(log_file_column_names, strlen(log_file_column_names), + true))) { + LOG_WARN("fail to append log", KR(ret)); + } else { + is_oracle_mode_ = lib::is_oracle_mode(); + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::Logger::generate_log_file_name(char *buf, int64_t size, + ObString &file_name) +{ + int ret = OB_SUCCESS; + const char *dict = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const int dict_len = strlen(dict); // length of dict + const char *file_prefix = "log/obloaddata.log."; + const int64_t prefix_len = strlen(file_prefix); + const int64_t log_file_id_len = 6; + if (OB_UNLIKELY(prefix_len + log_file_id_len > size)) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("log file name buf overflow", KR(ret), K(size)); + } else { + const int64_t cur_ts = ObTimeUtil::current_time(); + uint32_t hash_ts = ::murmurhash2(&cur_ts, sizeof(cur_ts), 0); + // copy prefix + MEMCPY(buf, file_prefix, prefix_len); + // generate file id + char *id_buf = buf + prefix_len; + for (int64_t i = 0; i < log_file_id_len; ++i) { + id_buf[i] = dict[hash_ts % dict_len]; + hash_ts /= dict_len; + } + // assign string + file_name.assign(buf, prefix_len + log_file_id_len); + } + return ret; +} + +int ObLoadDataDirectImpl::Logger::log_error_line(const ObString &file_name, int64_t line_no, + int err_code) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::Logger not init", KR(ret), KP(this)); + } else { + const char *err_msg = ob_errpkt_strerror(err_code, is_oracle_mode_); + const int err_no = ob_errpkt_errno(err_code, is_oracle_mode_); + int64_t pos = 0; + lib::ObMutexGuard guard(mutex_); + if (OB_FAIL(databuff_printf(buf_, DEFAULT_BUF_LENGTH, pos, log_file_row_fmt, file_name.length(), + file_name.ptr(), line_no, err_no, err_msg))) { + LOG_WARN("fail to databuff printf", KR(ret), K(line_no), K(err_no), K(err_msg)); + } else if (OB_FAIL(file_appender_.append(buf_, pos, false))) { + LOG_WARN("fail to append log", KR(ret), K(pos), K(line_no), K(err_no), K(err_msg)); + } + } + return ret; +} + +/** + * RandomFileReader + */ + +ObLoadDataDirectImpl::RandomFileReader::RandomFileReader() : is_inited_(false) +{ +} + +ObLoadDataDirectImpl::RandomFileReader::~RandomFileReader() +{ +} + +int ObLoadDataDirectImpl::RandomFileReader::open(const DataAccessParam &data_access_param, const ObString &filename) +{ + int ret = OB_SUCCESS; + UNUSED(data_access_param); + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("RandomFileReader init twice", KR(ret), KP(this)); + } else if (OB_FAIL(file_reader_.open(filename.ptr(), false))) { + LOG_WARN("fail to open file", KR(ret), K(filename)); + } else { + filename_ = filename; + is_inited_ = true; + } + return ret; +} + +int ObLoadDataDirectImpl::RandomFileReader::pread(char *buf, int64_t count, int64_t offset, int64_t &read_size) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("RandomFileReader not init", KR(ret), KP(this)); + } else if (OB_FAIL(file_reader_.pread(buf, count, offset, read_size))) { + LOG_WARN("fail to pread file buf", KR(ret), K(count), K(offset), K(read_size)); + } + return ret; +} + +int ObLoadDataDirectImpl::RandomFileReader::get_file_size(int64_t &file_size) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("RandomFileReader not init", KR(ret), KP(this)); + } else { + file_size = ::get_file_size(filename_.ptr()); + } + return ret; +} + +/** + * RandomOSSReader + */ + +ObLoadDataDirectImpl::RandomOSSReader::RandomOSSReader() : device_handle_(nullptr), is_inited_(false) +{ +} + +ObLoadDataDirectImpl::RandomOSSReader::~RandomOSSReader() +{ + if (fd_.is_valid()) { + device_handle_->close(fd_); + fd_.reset(); + } + if (nullptr != device_handle_) { + common::ObDeviceManager::get_instance().release_device(device_handle_); + device_handle_ = nullptr; + } +} + +int ObLoadDataDirectImpl::RandomOSSReader::open(const DataAccessParam &data_access_param, + const ObString &filename) +{ + int ret = OB_SUCCESS; + ObIODOpt opt; + ObIODOpts iod_opts; + ObBackupIoAdapter util; + iod_opts.opts_ = &opt; + iod_opts.opt_cnt_ = 0; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("RandomOSSReader init twice", KR(ret), KP(this)); + } else if (OB_FAIL( + util.get_and_init_device(device_handle_, &data_access_param.access_info_, filename))) { + LOG_WARN("fail to get device manager", KR(ret), K(filename)); + } else if (OB_FAIL(util.set_access_type(&iod_opts, false, 1))) { + LOG_WARN("fail to set access type", KR(ret)); + } else if (OB_FAIL(device_handle_->open(to_cstring(filename), -1, 0, fd_, &iod_opts))) { + LOG_WARN("fail to open oss file", KR(ret), K(filename)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObLoadDataDirectImpl::RandomOSSReader::pread(char *buf, int64_t count, int64_t offset, + int64_t &read_size) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("RandomOSSReader not init", KR(ret), KP(this)); + } else if (OB_FAIL(device_handle_->pread(fd_, offset, count, buf, read_size))) { + LOG_WARN("fail to pread oss buf", KR(ret), K(offset), K(count), K(read_size)); + } + return ret; +} + +int ObLoadDataDirectImpl::RandomOSSReader::get_file_size(int64_t &file_size) +{ + int ret = OB_SUCCESS; + ObBackupIoAdapter util; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("RandomOSSReader not init", KR(ret), KP(this)); + } else if (OB_FAIL(util.get_file_size(device_handle_, fd_, file_size))) { + LOG_WARN("fail to get oss file size", KR(ret), K(file_size)); + } + return ret; +} + +/** + * SequentialDataAccessor + */ + +ObLoadDataDirectImpl::SequentialDataAccessor::SequentialDataAccessor() + : random_io_device_(nullptr), offset_(0), is_inited_(false) +{ +} + +ObLoadDataDirectImpl::SequentialDataAccessor::~SequentialDataAccessor() +{ +} + +int ObLoadDataDirectImpl::SequentialDataAccessor::init(const DataAccessParam &data_access_param, + const ObString &filename) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::SequentialDataAccessor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!data_access_param.is_valid() || filename.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(data_access_param), K(filename)); + } else { + if (data_access_param.file_location_ == ObLoadFileLocation::SERVER_DISK) { + if (OB_FAIL(random_file_reader_.open(data_access_param, filename))) { + LOG_WARN("fail to open random file reader", KR(ret), K(filename)); + } else { + random_io_device_ = &random_file_reader_; + } + } else if (data_access_param.file_location_ == ObLoadFileLocation::OSS) { + if (OB_FAIL(random_oss_reader_.open(data_access_param, filename))) { + LOG_WARN("fail to open random oss reader", KR(ret), K(filename)); + } else { + random_io_device_ = &random_oss_reader_; + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported load file location", KR(ret), K(data_access_param.file_location_)); + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::SequentialDataAccessor::read(char *buf, int64_t count, int64_t &read_size) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::SequentialDataAccessor not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == buf || count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(count)); + } else { + if (OB_FAIL(random_io_device_->pread(buf, count, offset_, read_size))) { + LOG_WARN("fail to do pread", KR(ret), K(offset_)); + } else { + offset_ += read_size; + } + } + return ret; +} + +int ObLoadDataDirectImpl::SequentialDataAccessor::get_file_size(int64_t &file_size) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::SequentialDataAccessor not init", KR(ret), KP(this)); + } else if (OB_FAIL(random_io_device_->get_file_size(file_size))) { + LOG_WARN("fail to get random io device file size", KR(ret), K(file_size)); + } + return ret; +} + +/** + * DataDescIterator + */ + +ObLoadDataDirectImpl::DataDescIterator::DataDescIterator() + : pos_(0) +{ +} + +ObLoadDataDirectImpl::DataDescIterator::~DataDescIterator() +{ +} + +int ObLoadDataDirectImpl::DataDescIterator::copy(const ObLoadFileIterator &file_iter) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!file_iter.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(file_iter)); + } else { + ObLoadFileIterator copy_file_iter; + DataDesc data_desc; + int64_t file_idx = 0; + if (OB_FAIL(copy_file_iter.copy(file_iter))) { + LOG_WARN("fail to copy file iter", KR(ret)); + } + while (OB_SUCC(ret)) { + data_desc.file_idx_ = file_idx++; + if (OB_FAIL(copy_file_iter.get_next_file(data_desc.filename_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next file", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_FAIL(data_descs_.push_back(data_desc))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + } + return ret; +} + +int ObLoadDataDirectImpl::DataDescIterator::copy(const DataDescIterator &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(0 == other.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else if (OB_FAIL(data_descs_.assign(other.data_descs_))) { + LOG_WARN("fail to assign data descs", KR(ret)); + } else { + pos_ = 0; + } + return ret; +} + +int ObLoadDataDirectImpl::DataDescIterator::add_data_desc(const DataDesc &data_desc) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(data_descs_.push_back(data_desc))) { + LOG_WARN("fail to push back", KR(ret)); + } + return ret; +} + +int ObLoadDataDirectImpl::DataDescIterator::get_next_data_desc(DataDesc &data_desc) +{ + int ret = OB_SUCCESS; + if (pos_ >= data_descs_.count()) { + ret = OB_ITER_END; + } else { + data_desc = data_descs_.at(pos_++); + } + return ret; +} + +/** + * DataBuffer + */ + +ObLoadDataDirectImpl::DataBuffer::DataBuffer() + : allocator_("MTL_DataBuffer"), file_buffer_(nullptr), pos_(0), is_end_file_(false) +{ +} + +ObLoadDataDirectImpl::DataBuffer::~DataBuffer() +{ + reset(); +} + +void ObLoadDataDirectImpl::DataBuffer::reuse() +{ + if (nullptr != file_buffer_) { + file_buffer_->reset(); + } + pos_ = 0; + is_end_file_ = false; +} + +void ObLoadDataDirectImpl::DataBuffer::reset() +{ + if (nullptr != file_buffer_) { + file_buffer_->~ObLoadFileBuffer(); + file_buffer_ = nullptr; + } + pos_ = 0; + allocator_.reset(); +} + +int ObLoadDataDirectImpl::DataBuffer::init(int64_t capacity) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr != file_buffer_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::DataBuffer init twice", KR(ret), KPC(file_buffer_)); + } else if (OB_UNLIKELY(capacity <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid buffer capacity", KR(ret), K(capacity)); + } else { + const int64_t alloc_size = + MIN(capacity + sizeof(ObLoadFileBuffer), ObLoadFileBuffer::MAX_BUFFER_SIZE); + allocator_.set_tenant_id(MTL_ID()); + void *buf = nullptr; + if (OB_ISNULL(buf = allocator_.alloc(alloc_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret), K(alloc_size)); + } else { + file_buffer_ = new (buf) ObLoadFileBuffer(alloc_size - sizeof(ObLoadFileBuffer)); + } + } + return ret; +} + +bool ObLoadDataDirectImpl::DataBuffer::is_valid() const +{ + return nullptr != file_buffer_ && pos_ >= 0 && pos_ <= file_buffer_->get_data_len(); +} + +int64_t ObLoadDataDirectImpl::DataBuffer::get_data_length() const +{ + int64_t len = 0; + if (is_valid()) { + len = file_buffer_->get_data_len() - pos_; + } + return len; +} + +int64_t ObLoadDataDirectImpl::DataBuffer::get_remain_length() const +{ + int64_t len = 0; + if (is_valid()) { + len = file_buffer_->get_remain_len(); + } + return len; +} + +bool ObLoadDataDirectImpl::DataBuffer::empty() const { return 0 == get_data_length(); } + +char *ObLoadDataDirectImpl::DataBuffer::data() const +{ + char *buf = nullptr; + if (is_valid()) { + buf = file_buffer_->begin_ptr() + pos_; + } + return buf; +} + +void ObLoadDataDirectImpl::DataBuffer::advance(int64_t length) +{ + OB_ASSERT(get_data_length() >= length); + pos_ += length; +} + +void ObLoadDataDirectImpl::DataBuffer::update_data_length(int64_t length) +{ + OB_ASSERT(get_remain_length() >= length); + file_buffer_->update_pos(length); +} + +int ObLoadDataDirectImpl::DataBuffer::squash() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid buffer", KR(ret)); + } else { + const int64_t length = file_buffer_->get_data_len() - pos_; + if (length > 0) { + MEMMOVE(file_buffer_->begin_ptr(), file_buffer_->begin_ptr() + pos_, length); + } + reuse(); + file_buffer_->update_pos(length); + } + return ret; +} + +void ObLoadDataDirectImpl::DataBuffer::swap(DataBuffer &other) +{ + std::swap(file_buffer_, other.file_buffer_); + std::swap(pos_, other.pos_); +} + +/** + * DataReader + */ + +ObLoadDataDirectImpl::DataReader::DataReader() + : execute_ctx_(nullptr), end_offset_(0), read_raw_(false), is_iter_end_(false), is_inited_(false) +{ +} + +int ObLoadDataDirectImpl::DataReader::init(const DataAccessParam &data_access_param, + LoadExecuteContext &execute_ctx, + const DataDesc &data_desc, bool read_raw) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::DataReader init twice", KR(ret), KP(this)); + } else { + execute_ctx_ = &execute_ctx; + read_raw_ = read_raw; + if (OB_FAIL(csv_parser_.init(data_access_param.file_format_, data_access_param.file_column_num_, + data_access_param.file_cs_type_))) { + LOG_WARN("fail to init csv parser", KR(ret), K(data_access_param)); + } + if (OB_SUCC(ret) && !read_raw) { + ObCSVFormats formats; + formats.init(data_access_param.file_format_); + if (OB_FAIL(data_trimer_.init(*execute_ctx_->allocator_, formats))) { + LOG_WARN("fail to init data trimer", KR(ret)); + } + } + if (OB_SUCC(ret)) { + end_offset_ = data_desc.end_; + if (OB_FAIL(io_accessor_.init(data_access_param, data_desc.filename_))) { + LOG_WARN("fail to init io device", KR(ret), K(data_desc)); + } else if (end_offset_ == -1 && OB_FAIL(io_accessor_.get_file_size(end_offset_))) { + LOG_WARN("fail to get file size", KR(ret), K(data_desc)); + } else { + io_accessor_.seek(data_desc.start_); + ATOMIC_AAF(&execute_ctx_->job_stat_->total_bytes_, (end_offset_ - data_desc.start_)); + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::DataReader::get_next_buffer(ObLoadFileBuffer &file_buffer, + int64_t &line_count, int64_t limit) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::DataReader not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(limit <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(limit)); + } else if (OB_UNLIKELY(read_raw_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected read complete line buffer", KR(ret)); + } else if (is_iter_end_) { + ret = OB_ITER_END; + } else { + file_buffer.reset(); + line_count = 0; + + // 1. 从data_trimer中恢复出上次读取留下的数据 + if (OB_FAIL(data_trimer_.recover_incomplate_data(file_buffer))) { + LOG_WARN("fail to recover incomplate data", KR(ret)); + } + // 2. 从文件里读取后续的数据 + else if (!is_end_file()) { + int64_t read_count = 0; + int64_t read_size = 0; + if (FALSE_IT(read_count = + MIN(file_buffer.get_remain_len(), end_offset_ - io_accessor_.get_offset()))) { + } else if (OB_FAIL(io_accessor_.read(file_buffer.current_ptr(), read_count, read_size))) { + LOG_WARN("fail to read file", KR(ret)); + } else if (OB_UNLIKELY(read_count != read_size)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected read size", KR(ret), K(read_count), K(read_size), K(end_offset_)); + } else { + file_buffer.update_pos(read_size); // 更新buffer中数据长度 + ATOMIC_AAF(&execute_ctx_->job_stat_->read_bytes_, read_size); + } + } + // 3. 从buffer中找出完整的行,剩下的数据缓存到data_trimer + if (OB_SUCC(ret)) { + if (!file_buffer.is_valid()) { + is_iter_end_ = true; + ret = OB_ITER_END; + } else { + int64_t complete_cnt = limit; + int64_t complete_len = 0; + if (OB_FAIL(ObLoadDataBase::pre_parse_lines(file_buffer, csv_parser_, is_end_file(), + complete_len, complete_cnt))) { + LOG_WARN("fail to fast_lines_parse", KR(ret)); + } else if (OB_UNLIKELY(0 == complete_len)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected complete len", KR(ret), K(complete_len)); + } else if (OB_FAIL(data_trimer_.backup_incomplate_data(file_buffer, complete_len))) { + LOG_WARN("fail to back up data", KR(ret)); + } else { + data_trimer_.commit_line_cnt(complete_cnt); + line_count = complete_cnt; + LOG_DEBUG("LOAD DATA backup", "data", data_trimer_.get_incomplate_data_string()); + } + } + } + } + return ret; +} + +int ObLoadDataDirectImpl::DataReader::get_next_raw_buffer(DataBuffer &data_buffer) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::DataReader not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!read_raw_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected read raw buffer", KR(ret)); + } else if (is_end_file()) { + ret = OB_ITER_END; + } else if (data_buffer.get_remain_length() > 0) { + const int64_t read_count = + MIN(data_buffer.get_remain_length(), end_offset_ - io_accessor_.get_offset()); + int64_t read_size = 0; + if (OB_FAIL(io_accessor_.read(data_buffer.data() + data_buffer.get_data_length(), read_count, + read_size))) { + LOG_WARN("fail to read file", KR(ret)); + } else if (OB_UNLIKELY(read_count != read_size)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected read size", KR(ret), K(read_count), K(read_size), K(end_offset_)); + } else { + data_buffer.update_data_length(read_size); + ATOMIC_AAF(&execute_ctx_->job_stat_->read_bytes_, read_size); + } + } + return ret; +} + +/** + * DataParser + */ + +ObLoadDataDirectImpl::DataParser::DataParser() + : data_buffer_(nullptr), + start_line_no_(0), + pos_(0), + logger_(nullptr), + is_inited_(false) +{ +} + +ObLoadDataDirectImpl::DataParser::~DataParser() +{ +} + +int ObLoadDataDirectImpl::DataParser::init(const DataAccessParam &data_access_param, Logger &logger) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::DataParser init twice", KR(ret), KP(this)); + } else { + if (OB_FAIL(csv_parser_.init(data_access_param.file_format_, data_access_param.file_column_num_, + data_access_param.file_cs_type_))) { + LOG_WARN("fail to init csv parser", KR(ret)); + } else if (OB_FAIL(escape_buffer_.init())) { + LOG_WARN("fail to init data buffer", KR(ret)); + } else { + logger_ = &logger; + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::DataParser::parse(const ObString &file_name, int64_t start_line_no, + DataBuffer &data_buffer) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::DataParser not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!data_buffer.is_valid() || data_buffer.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(data_buffer)); + } else { + file_name_ = file_name; + start_line_no_ = start_line_no; + pos_ = 0; + data_buffer_ = &data_buffer; + } + return ret; +} + +int ObLoadDataDirectImpl::DataParser::get_next_row(ObNewRow &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::DataParser not init", KR(ret), KP(this)); + } else if (OB_ISNULL(data_buffer_) || OB_ISNULL(row.cells_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(data_buffer_), K(row)); + } else if (data_buffer_->empty()) { + ret = OB_ITER_END; + } else { + const char *str = data_buffer_->data(); + const char *end = str + data_buffer_->get_data_length(); + ObSEArray err_records; + int64_t nrows = 1; + auto handle_one_line = [](ObIArray &fields_per_line) -> int { + UNUSED(fields_per_line); + return OB_SUCCESS; + }; + ret = csv_parser_.scan( + str, end, nrows, escape_buffer_.file_buffer_->begin_ptr(), + escape_buffer_.file_buffer_->begin_ptr() + escape_buffer_.file_buffer_->get_buffer_size(), + handle_one_line, err_records, data_buffer_->is_end_file_); + if (OB_FAIL(ret)) { + LOG_WARN("fail to scan", KR(ret)); + } else if (OB_UNLIKELY(!err_records.empty())) { + ret = OB_ERR_WRONG_VALUE; + LOG_WARN("parse error", KR(ret)); + } else if (0 == nrows) { + ret = OB_ITER_END; + } else { + ++pos_; + const ObIArray &field_values_in_file = + csv_parser_.get_fields_per_line(); + for (int64_t i = 0; OB_SUCC(ret) && i < row.count_; ++i) { + const ObCSVGeneralParser::FieldValue &str_v = field_values_in_file.at(i); + ObObj &obj = row.cells_[i]; + if (str_v.is_null_) { + obj.set_null(); + } else { + obj.set_string(ObVarcharType, ObString(str_v.len_, str_v.ptr_)); + obj.set_collation_type( + ObCharset::get_default_collation(csv_parser_.get_format().cs_type_)); + } + } + } + for (int64_t i = 0; i < err_records.count(); ++i) { + log_error_line(err_records.at(i).err_code, start_line_no_ + pos_ + 1); + } + data_buffer_->advance(str - data_buffer_->data()); + } + return ret; +} + +void ObLoadDataDirectImpl::DataParser::log_error_line(int err_ret, int64_t err_line_no) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(logger_->log_error_line(file_name_, err_line_no, err_ret))) { + LOG_WARN("fail to log error line", KR(ret), K(err_ret), K(err_line_no)); + } +} + +/** + * SimpleDataSplitUtils + */ + +bool ObLoadDataDirectImpl::SimpleDataSplitUtils::is_simple_format( + const ObDataInFileStruct &file_format, ObCollationType file_cs_type) +{ + bool bret = false; + ObCharsetType char_set = ObCharset::charset_type_by_coll(file_cs_type); + if (char_set == CHARSET_UTF8MB4 && file_format.line_term_str_.length() == 1 && + file_format.line_start_str_.empty() && file_format.field_term_str_.length() == 1 && + file_format.field_enclosed_char_ == INT64_MAX && + file_format.field_escaped_char_ == INT64_MAX && + file_format.line_term_str_.ptr()[0] != file_format.field_term_str_.ptr()[0]) { + bret = true; + } + return bret; +} + +int ObLoadDataDirectImpl::SimpleDataSplitUtils::split(const DataAccessParam &data_access_param, + const DataDesc &data_desc, int64_t count, + DataDescIterator &data_desc_iter) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!data_access_param.is_valid() || count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(data_access_param), K(count)); + } else if (OB_UNLIKELY(!is_simple_format(data_access_param.file_format_, + data_access_param.file_cs_type_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected data format", KR(ret), K(data_access_param)); + } else if (1 == count) { + if (OB_FAIL(data_desc_iter.add_data_desc(data_desc))) { + LOG_WARN("fail to push back", KR(ret)); + } + } else { + int64_t end_offset = data_desc.end_; + SequentialDataAccessor io_device; + if (OB_FAIL(io_device.init(data_access_param, data_desc.filename_))) { + LOG_WARN("fail to init io device", KR(ret), K(data_desc.filename_)); + } else if (-1 == end_offset && OB_FAIL(io_device.get_file_size(end_offset))) { + LOG_WARN("fail to get io device file size", KR(ret), K(end_offset)); + } else { + const int64_t file_size = end_offset - data_desc.start_; + if (file_size < count * ObLoadFileBuffer::MAX_BUFFER_SIZE * 2) { + // file is too small + if (OB_FAIL(data_desc_iter.add_data_desc(data_desc))) { + LOG_WARN("fail to push back", KR(ret)); + } + } else { + const char line_term_char = data_access_param.file_format_.line_term_str_.ptr()[0]; + const int64_t buf_size = (128LL << 10) + 1; + const int64_t split_size = file_size / count; + ObArenaAllocator allocator; + char *buf = nullptr; + int64_t read_size = 0; + DataDesc data_desc_ret; + data_desc_ret.file_idx_ = data_desc.file_idx_; + data_desc_ret.filename_ = data_desc.filename_; + data_desc_ret.start_ = data_desc.start_; + allocator.set_tenant_id(MTL_ID()); + if (OB_ISNULL(buf = static_cast(allocator.alloc(buf_size)))) { + LOG_WARN("fail to alloc memory", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < count - 1; ++i) { + int64_t read_offset = data_desc.start_ + split_size * (i + 1); + io_device.seek(read_offset); + char *found = nullptr; + while (OB_SUCC(ret) && end_offset > io_device.get_offset() && nullptr == found) { + read_offset = io_device.get_offset(); + const int64_t read_count = MIN(end_offset - read_offset, buf_size - 1); + if (OB_FAIL(io_device.read(buf, read_count, read_size))) { + LOG_WARN("fail to do read", KR(ret), K(read_offset), K(read_count)); + } else if (OB_UNLIKELY(read_count != read_size)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected read size", KR(ret), K(read_count), K(read_size)); + } else { + buf[read_size] = '\0'; + found = STRCHR(buf, line_term_char); + } + } + if (OB_SUCC(ret)) { + if (nullptr == found) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected large row", KR(ret)); + } else { + data_desc_ret.end_ = read_offset + (found - buf + 1); + if (OB_FAIL(data_desc_iter.add_data_desc(data_desc_ret))) { + LOG_WARN("fail to push back", KR(ret)); + } else { + data_desc_ret.start_ = data_desc_ret.end_; + } + } + } + } + if (OB_SUCC(ret)) { + data_desc_ret.end_ = data_desc.end_; + if (OB_FAIL(data_desc_iter.add_data_desc(data_desc_ret))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + } + } + } + return ret; +} + +/** + * FileLoadExecutor + */ + +ObLoadDataDirectImpl::FileLoadExecutor::FileLoadExecutor() + : execute_param_(nullptr), + execute_ctx_(nullptr), + task_scheduler_(nullptr), + worker_ctx_array_(nullptr), + is_inited_(false) +{ +} + +ObLoadDataDirectImpl::FileLoadExecutor::~FileLoadExecutor() +{ + if (nullptr != task_scheduler_) { + task_scheduler_->stop(); + task_scheduler_->wait(); + task_scheduler_->~ObITableLoadTaskScheduler(); + execute_ctx_->allocator_->free(task_scheduler_); + task_scheduler_ = nullptr; + } + if (nullptr != worker_ctx_array_) { + for (int64_t i = 0; i < execute_param_->parallel_; ++i) { + WorkerContext *worker_ctx = worker_ctx_array_ + i; + worker_ctx->~WorkerContext(); + } + execute_ctx_->allocator_->free(worker_ctx_array_); + worker_ctx_array_ = nullptr; + } + for (int64_t i = 0; i < handle_resource_.count(); ++i) { + TaskHandle *handle = handle_resource_.at(i); + handle->~TaskHandle(); + execute_ctx_->allocator_->free(handle); + } + handle_resource_.reset(); +} + +int ObLoadDataDirectImpl::FileLoadExecutor::inner_init(const LoadExecuteParam &execute_param, + LoadExecuteContext &execute_ctx, + int64_t handle_count) +{ + int ret = OB_SUCCESS; + execute_param_ = &execute_param; + execute_ctx_ = &execute_ctx; + // init task_allocator_ + if (OB_FAIL(task_allocator_.init("TLD_TaskPool", execute_param_->tenant_id_))) { + LOG_WARN("fail to init allocator", KR(ret)); + } + // init task_scheduler_ + else if (OB_ISNULL(task_scheduler_ = + OB_NEWx(ObTableLoadTaskThreadPoolScheduler, (execute_ctx_->allocator_), + execute_param_->parallel_, *execute_ctx_->allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObTableLoadTaskThreadPoolScheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->init())) { + LOG_WARN("fail to init task scheduler", KR(ret)); + } else if (OB_FAIL(task_scheduler_->start())) { + LOG_WARN("fail to start task scheduler", KR(ret)); + } + // init worker_ctx_array_ + else if (OB_FAIL(init_worker_ctx_array())) { + LOG_WARN("fail to init worker ctx array", KR(ret)); + } + // task ctrl + else if (OB_FAIL(task_controller_.init(handle_count))) { + LOG_WARN("fail to init task controller", KR(ret), K(handle_count)); + } else if (OB_FAIL(handle_reserve_queue_.init(handle_count))) { + LOG_WARN("fail to init handle reserve queue", KR(ret), K(handle_count)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < handle_count; ++i) { + TaskHandle *handle = nullptr; + if (OB_ISNULL(handle = OB_NEWx(TaskHandle, execute_ctx_->allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate handler", KR(ret)); + } else if (OB_FAIL(handle->data_buffer_.init())) { + LOG_WARN("fail to init data buffer", KR(ret)); + } else if (OB_FAIL(handle_reserve_queue_.push_back(handle))) { + LOG_WARN("fail to push back handle to queue", KR(ret)); + } else if (OB_FAIL(handle_resource_.push_back(handle))) { + LOG_WARN("fail to push back handle to array", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != handle) { + handle->~TaskHandle(); + execute_ctx_->allocator_->free(handle); + } + } + } + return ret; +} + +int ObLoadDataDirectImpl::FileLoadExecutor::init_worker_ctx_array() +{ + int ret = OB_SUCCESS; + void *buf = nullptr; + if (OB_ISNULL( + buf = execute_ctx_->allocator_->alloc(sizeof(WorkerContext) * execute_param_->parallel_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else { + worker_ctx_array_ = new (buf) WorkerContext[execute_param_->parallel_]; + for (int64_t i = 0; OB_SUCC(ret) && i < execute_param_->parallel_; ++i) { + WorkerContext *worker_ctx = worker_ctx_array_ + i; + if (OB_FAIL(worker_ctx->data_parser_.init(execute_param_->data_access_param_, + *execute_ctx_->logger_))) { + LOG_WARN("fail to init data parser", KR(ret), K(execute_param_->data_access_param_)); + } else if (OB_FAIL( + worker_ctx->objs_.create(execute_param_->data_access_param_.file_column_num_ * + execute_param_->batch_row_count_, + *execute_ctx_->allocator_))) { + LOG_WARN("fail to create obj array", KR(ret)); + } + } + } + return ret; +} + +int ObLoadDataDirectImpl::FileLoadExecutor::execute() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::FileLoadExecutor not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(prepare_execute())) { + LOG_WARN("fail to prepare execute", KR(ret)); + } + + while (OB_SUCC(ret) && OB_SUCC(execute_ctx_->check_status())) { + TaskHandle *handle = nullptr; + if (OB_FAIL(get_next_task_handle(handle))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next task handle", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else { + ObTableLoadTask *task = nullptr; + if (OB_FAIL(alloc_task(task))) { + LOG_WARN("fail to alloc task", KR(ret)); + } else if (OB_FAIL(fill_task(handle, task))) { + LOG_WARN("fail to fill task", KR(ret)); + } else if (OB_FAIL(task_scheduler_->add_task(handle->session_id_ - 1, task))) { + LOG_WARN("fail to add task", KR(ret), K(handle->session_id_), KPC(task)); + } + if (OB_FAIL(ret)) { + if (nullptr != task) { + free_task(task); + } + } + } + if (OB_FAIL(ret)) { + if (nullptr != handle) { + task_finished(handle); + } + } + } + + wait_all_task_finished(); + + if (OB_SUCC(ret)) { + if (OB_FAIL(handle_all_task_result())) { + LOG_WARN("fail to handle all task result", KR(ret)); + } + } + + } + return ret; +} + +int ObLoadDataDirectImpl::FileLoadExecutor::alloc_task(ObTableLoadTask *&task) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::FileLoadExecutor not init", KR(ret), KP(this)); + } else { + if (OB_ISNULL(task = task_allocator_.alloc(execute_param_->tenant_id_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc task", KR(ret)); + } + } + return ret; +} + +void ObLoadDataDirectImpl::FileLoadExecutor::free_task(ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::FileLoadExecutor not init", KR(ret), KP(this)); + } else if (OB_ISNULL(task)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(task)); + } else { + task_allocator_.free(task); + } +} + +int ObLoadDataDirectImpl::FileLoadExecutor::fetch_task_handle(TaskHandle *&handle) +{ + int ret = OB_SUCCESS; + handle = nullptr; + if (OB_FAIL(task_controller_.on_next_task())) { + LOG_WARN("fail to on next task", KR(ret)); + } else { + if (OB_FAIL(handle_reserve_queue_.pop(handle))) { + LOG_WARN("fail to pop handle", KR(ret)); + } else if (OB_ISNULL(handle)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null handle", KR(ret)); + } else if (OB_FAIL(handle_task_result(handle->task_id_, handle->result_))) { + LOG_WARN("fail to handle task result", KR(ret), KPC(handle)); + } + if (OB_FAIL(ret)) { + // 主动调用on_task_finished, 防止wait_all_task_finished卡住 + task_controller_.on_task_finished(); + } + } + return ret; +} + +void ObLoadDataDirectImpl::FileLoadExecutor::task_finished(TaskHandle *handle) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(handle)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null handle", KR(ret)); + } else { + handle->result_.finished_ts_ = ObTimeUtil::current_time(); + int ret1 = handle_reserve_queue_.push_back(handle); + MEM_BARRIER(); + int ret2 = task_controller_.on_task_finished(); + if (OB_UNLIKELY(OB_FAIL(ret1) || OB_FAIL(ret2))) { + LOG_ERROR("fail to finished task", KR(ret1), KR(ret2)); + } + } +} + +int ObLoadDataDirectImpl::FileLoadExecutor::handle_task_result(int64_t task_id, TaskResult &result) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(result.ret_)) { + LOG_WARN("task result is failed", KR(ret), K(task_id)); + } + /* + if (0 != result.created_ts_) { + int64_t wait_us = 0, proccess_us = 0; + if (0 != result.start_process_ts_) { + wait_us = result.start_process_ts_ - result.created_ts_; + proccess_us = result.finished_ts_ - result.start_process_ts_; + } else { + wait_us = result.finished_ts_ - result.created_ts_; + } + } + */ + result.reset(); + return ret; +} + +int ObLoadDataDirectImpl::FileLoadExecutor::handle_all_task_result() +{ + int ret = OB_SUCCESS; + TaskHandle *handle = nullptr; + while (handle_reserve_queue_.count() > 0) { + if (OB_FAIL(handle_reserve_queue_.pop(handle))) { + LOG_WARN("fail to pop handle", KR(ret)); + } else if (OB_ISNULL(handle)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null handle", KR(ret)); + } else if (OB_FAIL(handle_task_result(handle->task_id_, handle->result_))) { + LOG_WARN("fail to handle task result", KR(ret), KPC(handle)); + } + } + return ret; +} + +void ObLoadDataDirectImpl::FileLoadExecutor::wait_all_task_finished() +{ + const int64_t processing_task_cnt = task_controller_.get_processing_task_cnt(); + const int64_t total_task_cnt = task_controller_.get_total_task_cnt(); + LOG_INFO("LOAD DATA wait all task finish", K(processing_task_cnt), K(total_task_cnt)); + task_controller_.wait_all_task_finish(execute_param_->combined_name_.ptr(), THIS_WORKER.get_timeout_ts()); +} + +int ObLoadDataDirectImpl::FileLoadExecutor::process_task_handle(int64_t worker_idx, + TaskHandle *handle, + int64_t &total_processed_line_count) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObLoadDataDirectImpl::FileLoadExecutor not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(worker_idx < 0 || worker_idx >= execute_param_->parallel_ || + nullptr == handle)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(execute_param_), K(worker_idx), KP(handle)); + } else { + WorkerContext &worker_ctx = worker_ctx_array_[worker_idx]; + const int64_t column_count = execute_param_->data_access_param_.file_column_num_; + const int64_t data_buffer_length = handle->data_buffer_.get_data_length(); + int64_t parsed_bytes = 0; + int64_t processed_line_count = 0; + total_processed_line_count = 0; + ObNewRow row; + bool is_iter_end = false; + if (OB_FAIL(worker_ctx.data_parser_.parse(handle->data_desc_.filename_, handle->start_line_no_, + handle->data_buffer_))) { + LOG_WARN("fail to parse data", KR(ret), KPC(handle)); + } else { + row.cells_ = worker_ctx.objs_.ptr(); + row.count_ = column_count; + } + while (OB_SUCC(ret) && !is_iter_end) { + // 每个新的batch需要分配一个新的shared_allocator + ObTableLoadSharedAllocatorHandle allocator_handle = + ObTableLoadSharedAllocatorHandle::make_handle(); + if (!allocator_handle) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to make allocator handle", KR(ret)); + } + ObTableLoadObjRowArray obj_rows; + obj_rows.set_allocator(allocator_handle); + + while (OB_SUCC(ret) && (processed_line_count < execute_param_->batch_row_count_)) { + if (OB_FAIL(worker_ctx.data_parser_.get_next_row(row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } else { + ret = OB_SUCCESS; + is_iter_end = true; + break; + } + } else { + //此时row中的每个obj的内容指向的是data parser中的内存 + //因此得把它们深拷贝一遍 + ObTableLoadObjRow tmp_obj_row; + if (OB_FAIL(tmp_obj_row.deep_copy_and_assign(row.cells_, row.count_, allocator_handle))) { + LOG_WARN("failed to deep copy add assign to tmp_obj_row", KR(ret)); + } else if (OB_FAIL(obj_rows.push_back(tmp_obj_row))) { + LOG_WARN("failed to add tmp_obj_row to obj_rows", KR(ret)); + } else { + ++processed_line_count; + row.cells_ += column_count; + } + } + } // end while() + + if (OB_SUCC(ret) && (processed_line_count > 0)) { + if (OB_FAIL(execute_ctx_->direct_loader_->write(handle->session_id_, obj_rows))) { + LOG_WARN("fail to write objs", KR(ret)); + } else { + total_processed_line_count += processed_line_count; + processed_line_count = 0; + row.cells_ = worker_ctx.objs_.ptr(); + } + } + } // end while() + parsed_bytes = data_buffer_length - handle->data_buffer_.get_data_length(); + handle->result_.proccessed_row_count_ += total_processed_line_count; + handle->result_.parsed_bytes_ += parsed_bytes; + ATOMIC_AAF(&execute_ctx_->job_stat_->parsed_rows_, total_processed_line_count); + ATOMIC_AAF(&execute_ctx_->job_stat_->parsed_bytes_, parsed_bytes); + } + return ret; +} + +/** + * FileLoadTaskCallback + */ + +class ObLoadDataDirectImpl::FileLoadTaskCallback : public ObITableLoadTaskCallback +{ +public: + FileLoadTaskCallback(FileLoadExecutor *load_executor, TaskHandle *handle) + : load_executor_(load_executor), handle_(handle) + { + } + virtual ~FileLoadTaskCallback() = default; + void callback(int ret_code, ObTableLoadTask *task) override + { + handle_->result_.ret_ = ret_code; + load_executor_->task_finished(handle_); + load_executor_->free_task(task); + } +private: + FileLoadExecutor *load_executor_; + TaskHandle *handle_; +}; + +/** + * LargeFileLoadTaskProcessor + */ + +class ObLoadDataDirectImpl::LargeFileLoadTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + LargeFileLoadTaskProcessor(ObTableLoadTask &task, FileLoadExecutor *file_load_executor, + int64_t worker_idx, TaskHandle *handle) + : ObITableLoadTaskProcessor(task), + file_load_executor_(file_load_executor), + worker_idx_(worker_idx), + handle_(handle) + { + } + virtual ~LargeFileLoadTaskProcessor() = default; + int process() override; + INHERIT_TO_STRING_KV("task_processor", ObITableLoadTaskProcessor, KPC_(handle)); +private: + FileLoadExecutor *file_load_executor_; + int64_t worker_idx_; + TaskHandle *handle_; +}; + +int ObLoadDataDirectImpl::LargeFileLoadTaskProcessor::process() +{ + int ret = OB_SUCCESS; + handle_->result_.start_process_ts_ = ObTimeUtil::current_time(); + int64_t line_count = 0; + if (OB_FAIL(file_load_executor_->process_task_handle(worker_idx_, handle_, line_count))) { + LOG_WARN("fail to process task handle", KR(ret)); + } + return ret; +} + +/** + * LargeFileLoadExecutor + */ + +ObLoadDataDirectImpl::LargeFileLoadExecutor::LargeFileLoadExecutor() + : next_session_id_(1), total_line_count_(0) +{ +} + +ObLoadDataDirectImpl::LargeFileLoadExecutor::~LargeFileLoadExecutor() +{ +} + +int ObLoadDataDirectImpl::LargeFileLoadExecutor::init(const LoadExecuteParam &execute_param, + LoadExecuteContext &execute_ctx, + const DataDescIterator &data_desc_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::LargeFileLoadExecutor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!execute_param.is_valid() || !execute_ctx.is_valid() || + 1 != data_desc_iter.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(execute_param), K(execute_ctx), K(data_desc_iter)); + } else { + DataDescIterator copy_data_desc_iter; + DataDesc data_desc; + if (OB_FAIL(inner_init(execute_param, execute_ctx, execute_param.data_mem_usage_limit_))) { + LOG_WARN("fail to init inner", KR(ret)); + } + // data_desc_ + else if (OB_FAIL(copy_data_desc_iter.copy(data_desc_iter))) { + LOG_WARN("fail to copy data desc iter", KR(ret)); + } else if (OB_FAIL(copy_data_desc_iter.get_next_data_desc(data_desc))) { + LOG_WARN("fail to get next data desc", KR(ret)); + } + // expr_buffer_ + else if (OB_FAIL(expr_buffer_.init())) { + LOG_WARN("fail to init data buffer", KR(ret)); + } + // data_reader_ + else if (OB_FAIL( + data_reader_.init(execute_param_->data_access_param_, *execute_ctx_, data_desc))) { + LOG_WARN("fail to init data reader", KR(ret)); + } else { + data_desc_ = data_desc; + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::LargeFileLoadExecutor::prepare_execute() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(skip_ignore_rows())) { + LOG_WARN("fail to skip ignore rows", KR(ret)); + } + return ret; +} + +int ObLoadDataDirectImpl::LargeFileLoadExecutor::get_next_task_handle(TaskHandle *&handle) +{ + int ret = OB_SUCCESS; + int64_t current_line_count = 0; + expr_buffer_.reuse(); + if (OB_FAIL(data_reader_.get_next_buffer(*expr_buffer_.file_buffer_, current_line_count))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next buffer", KR(ret)); + } + } else if (OB_FAIL(fetch_task_handle(handle))) { + LOG_WARN("fail to fetch task handle", KR(ret)); + } else { + handle->task_id_ = task_controller_.get_next_task_id(); + handle->session_id_ = get_session_id(); + handle->data_desc_ = data_desc_; + handle->start_line_no_ = total_line_count_ + 1; + handle->result_.created_ts_ = ObTimeUtil::current_time(); + handle->data_buffer_.swap(expr_buffer_); + handle->data_buffer_.is_end_file_ = data_reader_.is_end_file(); + total_line_count_ += current_line_count; + } + return ret; +} + +int ObLoadDataDirectImpl::LargeFileLoadExecutor::fill_task(TaskHandle *handle, + ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + if (OB_FAIL( + task->set_processor(this, handle->session_id_ - 1, handle))) { + LOG_WARN("fail to set large file load task processor", KR(ret)); + } else if (OB_FAIL(task->set_callback(this, handle))) { + LOG_WARN("fail to set file load task callback", KR(ret)); + } + return ret; +} + +int32_t ObLoadDataDirectImpl::LargeFileLoadExecutor::get_session_id() +{ + if (next_session_id_ > execute_param_->parallel_) { + next_session_id_ = 1; + } + return next_session_id_++; +} + +int ObLoadDataDirectImpl::LargeFileLoadExecutor::skip_ignore_rows() +{ + int ret = OB_SUCCESS; + const int64_t ignore_row_num = execute_param_->ignore_row_num_; + if (ignore_row_num > 0) { + int64_t line_count = 0; + while (OB_SUCC(ret) && data_reader_.get_lines_count() < ignore_row_num) { + if (OB_FAIL(data_reader_.get_next_buffer(*expr_buffer_.file_buffer_, line_count, + ignore_row_num - data_reader_.get_lines_count()))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next buffer", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } + } + LOG_INFO("LOAD DATA skip ignore rows", KR(ret), K(ignore_row_num), + K(data_reader_.get_lines_count())); + } + return ret; +} + +/** + * MultiFilesLoadTaskProcessor + */ + +class ObLoadDataDirectImpl::MultiFilesLoadTaskProcessor : public ObITableLoadTaskProcessor +{ +public: + MultiFilesLoadTaskProcessor(ObTableLoadTask &task, const LoadExecuteParam *execute_param, + LoadExecuteContext *execute_ctx, FileLoadExecutor *file_load_executor, + int64_t worker_idx, TaskHandle *handle) + : ObITableLoadTaskProcessor(task), + execute_param_(execute_param), + execute_ctx_(execute_ctx), + file_load_executor_(file_load_executor), + worker_idx_(worker_idx), + handle_(handle) + { + } + virtual ~MultiFilesLoadTaskProcessor() = default; + int process() override; + INHERIT_TO_STRING_KV("task_processor", ObITableLoadTaskProcessor, KPC_(handle)); +private: + int skip_ignore_rows(int64_t &skip_line_count); +private: + const LoadExecuteParam *execute_param_; + LoadExecuteContext *execute_ctx_; + FileLoadExecutor *file_load_executor_; + int64_t worker_idx_; + TaskHandle *handle_; + DataReader data_reader_; +}; + +int ObLoadDataDirectImpl::MultiFilesLoadTaskProcessor::process() +{ + int ret = OB_SUCCESS; + handle_->result_.start_process_ts_ = ObTimeUtil::current_time(); + int64_t total_line_count = 0; + int64_t current_line_count = 0; + if (OB_FAIL(data_reader_.init(execute_param_->data_access_param_, *execute_ctx_, + handle_->data_desc_, true))) { + LOG_WARN("fail to init data reader", KR(ret)); + } else if (0 == handle_->data_desc_.file_idx_ && 0 == handle_->data_desc_.start_) { + if (OB_FAIL(skip_ignore_rows(total_line_count))) { + LOG_WARN("fail to skip ignore rows", KR(ret)); + } else if (OB_UNLIKELY(total_line_count < execute_param_->ignore_row_num_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected ignore row num", KR(ret), K(total_line_count), + K(execute_param_->ignore_row_num_)); + } else if (!handle_->data_buffer_.empty()) { + handle_->start_line_no_ = total_line_count + 1; + if (OB_FAIL( + file_load_executor_->process_task_handle(worker_idx_, handle_, current_line_count))) { + LOG_WARN("fail to process task handle", KR(ret)); + } else { + total_line_count += current_line_count; + current_line_count = 0; + } + } + } + while (OB_SUCC(ret) && OB_SUCC(execute_ctx_->check_status())) { + if (OB_FAIL(handle_->data_buffer_.squash())) { + LOG_WARN("fail to squash data buffer", KR(ret)); + } else if (OB_FAIL(data_reader_.get_next_raw_buffer(handle_->data_buffer_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next buffer", KR(ret)); + } else { + ret = OB_SUCCESS; + if (OB_UNLIKELY(!handle_->data_buffer_.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("has incomplate data", KR(ret)); + } + break; + } + } else { + handle_->data_buffer_.is_end_file_ = data_reader_.is_end_file(); + handle_->start_line_no_ = total_line_count + 1; + if (OB_FAIL( + file_load_executor_->process_task_handle(worker_idx_, handle_, current_line_count))) { + LOG_WARN("fail to process task handle", KR(ret)); + } else if (OB_UNLIKELY(0 == current_line_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected no complete line", KR(ret)); + } else { + total_line_count += current_line_count; + current_line_count = 0; + } + } + } + return ret; +} + +int ObLoadDataDirectImpl::MultiFilesLoadTaskProcessor::skip_ignore_rows(int64_t &skip_line_count) +{ + int ret = OB_SUCCESS; + const int64_t ignore_row_num = execute_param_->ignore_row_num_; + skip_line_count = 0; + if (ignore_row_num > 0) { + DataBuffer &data_buffer = handle_->data_buffer_; + data_buffer.reuse(); + while (OB_SUCC(ret) && skip_line_count < ignore_row_num) { + if (OB_FAIL(data_buffer.squash())) { + LOG_WARN("fail to squash data buffer", KR(ret)); + } else if (OB_FAIL(data_reader_.get_next_raw_buffer(data_buffer))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next buffer", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_UNLIKELY(data_buffer.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected empty data buffer", KR(ret)); + } else { + int64_t complete_cnt = ignore_row_num - skip_line_count; + int64_t complete_len = 0; + if (OB_FAIL(ObLoadDataBase::pre_parse_lines( + *data_buffer.file_buffer_, data_reader_.get_csv_parser(), data_reader_.is_end_file(), + complete_len, complete_cnt))) { + LOG_WARN("fail to fast_lines_parse", KR(ret)); + } else if (OB_UNLIKELY(0 == complete_len)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected complete len", KR(ret), K(complete_len)); + } else { + data_buffer.advance(complete_len); + skip_line_count += complete_cnt; + } + } + } + LOG_INFO("LOAD DATA skip ignore rows", KR(ret), K(ignore_row_num), K(skip_line_count)); + } + return ret; +} + +/** + * MultiFilesLoadExecutor + */ + +int ObLoadDataDirectImpl::MultiFilesLoadExecutor::init(const LoadExecuteParam &execute_param, + LoadExecuteContext &execute_ctx, + const DataDescIterator &data_desc_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObLoadDataDirectImpl::MultiFilesLoadExecutor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!execute_param.is_valid() || !execute_ctx.is_valid() || + data_desc_iter.count() <= 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(execute_param), K(execute_ctx), K(data_desc_iter)); + } else { + if (OB_FAIL(inner_init(execute_param, execute_ctx, execute_param.parallel_))) { + LOG_WARN("fail to init inner", KR(ret)); + } else if (OB_FAIL(data_desc_iter_.copy(data_desc_iter))) { + LOG_WARN("fail to copy data desc iter", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObLoadDataDirectImpl::MultiFilesLoadExecutor::prepare_execute() +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; i < handle_resource_.count(); ++i) { + handle_resource_.at(i)->session_id_ = i + 1; + } + return ret; +} + +int ObLoadDataDirectImpl::MultiFilesLoadExecutor::get_next_task_handle(TaskHandle *&handle) +{ + int ret = OB_SUCCESS; + DataDesc data_desc; + if (OB_FAIL(data_desc_iter_.get_next_data_desc(data_desc))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next data desc", KR(ret)); + } + } else if (OB_FAIL(fetch_task_handle(handle))) { + LOG_WARN("fail to fetch task handle", KR(ret)); + } else { + handle->task_id_ = task_controller_.get_next_task_id(); + handle->data_desc_ = data_desc; + handle->start_line_no_ = 0; + handle->result_.created_ts_ = ObTimeUtil::current_time(); + } + return ret; +} + +int ObLoadDataDirectImpl::MultiFilesLoadExecutor::fill_task(TaskHandle *handle, + ObTableLoadTask *task) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(task->set_processor(execute_param_, execute_ctx_, this, + handle->session_id_ - 1, handle))) { + LOG_WARN("fail to set multi files load task processor", KR(ret)); + } else if (OB_FAIL(task->set_callback(this, handle))) { + LOG_WARN("fail to set file load task callback", KR(ret)); + } + return ret; +} + +/** + * ObLoadDataDirectImpl + */ + +ObLoadDataDirectImpl::ObLoadDataDirectImpl() + : ctx_(nullptr), load_stmt_(nullptr) +{ +} + +ObLoadDataDirectImpl::~ObLoadDataDirectImpl() +{ +} + +int ObLoadDataDirectImpl::execute(ObExecContext &ctx, ObLoadDataStmt &load_stmt) +{ + int ret = OB_SUCCESS; + ctx_ = &ctx; + load_stmt_ = &load_stmt; + const ObLoadArgument &load_args = load_stmt_->get_load_arguments(); + const int64_t original_timeout_us = THIS_WORKER.get_timeout_ts(); + + if (OB_SUCC(ret)) { + int64_t query_timeout = 0; + ObSQLSessionInfo *session = nullptr; + if (OB_ISNULL(session = ctx.get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", KR(ret)); + } else if (OB_FAIL(session->get_query_timeout(query_timeout))) { + LOG_WARN("fail to get query timeout", KR(ret)); + } else { + query_timeout = MAX(query_timeout, RPC_BATCH_INSERT_TIMEOUT_US); + THIS_WORKER.set_timeout_ts(ObTimeUtility::current_time() + query_timeout); + } + } + + if (OB_FAIL(init_execute_param())) { + LOG_WARN("fail to init execute param", KR(ret), K(ctx), K(load_stmt)); + } else if (OB_FAIL(init_execute_context())) { + LOG_WARN("fail to init execute context", KR(ret), K(ctx), K(load_stmt)); + } else { + LOG_INFO("LOAD DATA init finish", K_(execute_param), "file_path", load_args.file_name_); + ObLoadDataStat *job_stat = execute_ctx_.job_stat_; + OZ(ob_write_string(job_stat->allocator_, load_args.file_name_, job_stat->file_path_)); + job_stat->file_column_ = execute_param_.data_access_param_.file_column_num_; + job_stat->load_mode_ = static_cast(execute_param_.dup_action_); + } + + if (OB_SUCC(ret)) { + FileLoadExecutor *file_load_executor = nullptr; + DataDescIterator data_desc_iter; + if (1 == load_args.file_iter_.count() && 0 == execute_param_.ignore_row_num_ && + SimpleDataSplitUtils::is_simple_format(execute_param_.data_access_param_.file_format_, + execute_param_.data_access_param_.file_cs_type_)) { + DataDesc data_desc; + data_desc.filename_ = load_args.file_name_; + if (OB_FAIL(SimpleDataSplitUtils::split(execute_param_.data_access_param_, data_desc, + execute_param_.parallel_, data_desc_iter))) { + LOG_WARN("fail to split data", KR(ret)); + } + } else { + if (OB_FAIL(data_desc_iter.copy(load_args.file_iter_))) { + LOG_WARN("fail to copy file iter", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (1 == data_desc_iter.count()) { + // large file load + if (OB_ISNULL(file_load_executor = + OB_NEWx(LargeFileLoadExecutor, execute_ctx_.allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new LargeFileLoadExecutor", KR(ret)); + } + } else if (data_desc_iter.count() > 1) { + // multi files load + if (OB_ISNULL(file_load_executor = + OB_NEWx(MultiFilesLoadExecutor, execute_ctx_.allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new MultiFilesLoadExecutor", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(file_load_executor->init(execute_param_, execute_ctx_, data_desc_iter))) { + LOG_WARN("fail to init file load executor", KR(ret)); + } else if (OB_FAIL(file_load_executor->execute())) { + LOG_WARN("fail to execute file load", KR(ret)); + } + } + if (nullptr != file_load_executor) { + file_load_executor->~FileLoadExecutor(); + file_load_executor = nullptr; + } + } + + if (OB_SUCC(ret)) { + ObTableLoadResultInfo result_info; + if (OB_FAIL(direct_loader_.commit(result_info))) { + LOG_WARN("fail to commit direct loader", KR(ret)); + } else { + ObPhysicalPlanCtx *phy_plan_ctx = execute_ctx_.exec_ctx_->get_physical_plan_ctx(); + phy_plan_ctx->set_affected_rows(result_info.rows_affected_); + phy_plan_ctx->set_row_matched_count(result_info.records_); + phy_plan_ctx->set_row_deleted_count(result_info.deleted_); + phy_plan_ctx->set_row_duplicated_count(result_info.skipped_); + } + } + + direct_loader_.destroy(); + THIS_WORKER.set_timeout_ts(original_timeout_us); + + return ret; +} + +int ObLoadDataDirectImpl::init_execute_param() +{ + int ret = OB_SUCCESS; + const ObLoadArgument &load_args = load_stmt_->get_load_arguments(); + const ObLoadDataHint &hint = load_stmt_->get_hints(); + const ObIArray &field_or_var_list = + load_stmt_->get_field_or_var_list(); + execute_param_.tenant_id_ = load_args.tenant_id_; + execute_param_.database_id_ = load_args.database_id_; + execute_param_.table_id_ = load_args.table_id_; + execute_param_.database_name_ = load_args.database_name_; + execute_param_.table_name_ = load_args.table_name_; + execute_param_.combined_name_ = load_args.combined_name_; + execute_param_.ignore_row_num_ = load_args.ignore_rows_; + execute_param_.dup_action_ = load_args.dupl_action_; + // parallel_ + if (OB_SUCC(ret)) { + ObTenant *tenant = nullptr; + int64_t hint_parallel = 0; + if (OB_FAIL(hint.get_value(ObLoadDataHint::PARALLEL_THREADS, hint_parallel))) { + LOG_WARN("fail to get value of PARALLEL_THREADS", KR(ret), K(hint)); + } else if (OB_FAIL(GCTX.omt_->get_tenant(execute_param_.tenant_id_, tenant))) { + LOG_WARN("fail to get tenant handle", KR(ret), K(execute_param_.tenant_id_)); + } else { + hint_parallel = hint_parallel > 0 ? hint_parallel : DEFAULT_PARALLEL_THREAD_COUNT; + hint_parallel = load_args.file_iter_.count() > 1 + ? MIN(hint_parallel, load_args.file_iter_.count()) + : hint_parallel; + execute_param_.parallel_ = MIN(hint_parallel, (int64_t)tenant->unit_max_cpu()); + execute_param_.data_mem_usage_limit_ = + MIN(execute_param_.parallel_ * 2, MAX_DATA_MEM_USAGE_LIMIT); + } + } + // batch_row_count_ + if (OB_SUCC(ret)) { + int64_t hint_batch_size = 0; + if (OB_FAIL(hint.get_value(ObLoadDataHint::BATCH_SIZE, hint_batch_size))) { + LOG_WARN("fail to get value of BATCH_SIZE", KR(ret), K(hint)); + } else { + execute_param_.batch_row_count_ = + hint_batch_size > 0 ? hint_batch_size : DEFAULT_BUFFERRED_ROW_COUNT; + } + } + // need_sort_ + if (OB_SUCC(ret)) { + int64_t hint_need_sort = 0; + if (OB_FAIL(hint.get_value(ObLoadDataHint::NEED_SORT, hint_need_sort))) { + LOG_WARN("fail to get value of NEED_SORT", KR(ret), K(hint)); + } else { + execute_param_.need_sort_ = hint_need_sort > 0 ? true : false; + } + } + // sql_mode_ + if (OB_SUCC(ret)) { + ObSQLSessionInfo *session = nullptr; + uint64_t sql_mode; + if (OB_ISNULL(session = ctx_->get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", KR(ret)); + } else if (OB_FAIL(session->get_sys_variable(SYS_VAR_SQL_MODE, sql_mode))) { + LOG_WARN("fail to get sys variable", K(ret)); + } else { + execute_param_.sql_mode_ = sql_mode; + } + } + // online_opt_stat_gather_ + if (OB_SUCC(ret)) { + ObSQLSessionInfo *session = nullptr; + ObObj obj; + if (OB_ISNULL(session = ctx_->get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", KR(ret)); + } else if (OB_FAIL(session->get_sys_variable(SYS_VAR_ONLINE_OPT_STAT_GATHER, obj))) { + LOG_WARN("fail to get sys variable", K(ret)); + } else { + execute_param_.online_opt_stat_gather_ = obj.get_bool(); + } + } + // max_error_rows_ + if (OB_SUCC(ret)) { + int64_t hint_error_rows = 0; + if (OB_FAIL(hint.get_value(ObLoadDataHint::ERROR_ROWS, hint_error_rows))) { + LOG_WARN("fail to get value of ERROR_ROWS", KR(ret), K(hint)); + } else { + execute_param_.max_error_rows_ = hint_error_rows; + } + } + // data_access_param_ + if (OB_SUCC(ret)) { + DataAccessParam &data_access_param = execute_param_.data_access_param_; + data_access_param.file_location_ = load_args.load_file_storage_; + data_access_param.file_column_num_ = field_or_var_list.count(); + data_access_param.file_format_ = load_stmt_->get_data_struct_in_file(); + data_access_param.file_cs_type_ = load_args.file_cs_type_; + data_access_param.access_info_ = load_args.access_info_; + } + // store_column_idxs_ + if (OB_SUCC(ret)) { + if (OB_FAIL(init_store_column_idxs(execute_param_.store_column_idxs_))) { + LOG_WARN("fail to init store column idxs", KR(ret)); + } + } + return ret; +} + +int ObLoadDataDirectImpl::init_store_column_idxs(ObIArray &store_column_idxs) +{ + int ret = OB_SUCCESS; + const ObLoadArgument &load_args = load_stmt_->get_load_arguments(); + const ObIArray &field_or_var_list = + load_stmt_->get_field_or_var_list(); + const uint64_t tenant_id = load_args.tenant_id_; + const uint64_t table_id = load_args.table_id_; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + ObSEArray column_descs; + if (OB_FAIL(ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard(tenant_id, + schema_guard))) { + LOG_WARN("fail to get tenant schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_FAIL(table_schema->get_column_ids(column_descs))) { + STORAGE_LOG(WARN, "fail to get column descs", KR(ret), KPC(table_schema)); + } else { + bool found_column = true; + for (int64_t i = 0; OB_SUCC(ret) && OB_LIKELY(found_column) && i < column_descs.count(); ++i) { + const ObColDesc &col_desc = column_descs.at(i); + const ObColumnSchemaV2 *col_schema = table_schema->get_column_schema(col_desc.col_id_); + if (OB_ISNULL(col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null column schema", KR(ret), K(col_desc)); + } else { + found_column = col_schema->is_hidden(); + } + // 在源数据的列数组中找到对应的列 + for (int64_t j = 0; OB_SUCC(ret) && OB_LIKELY(!found_column) && j < field_or_var_list.count(); + ++j) { + const ObLoadDataStmt::FieldOrVarStruct &field_or_var_struct = field_or_var_list.at(j); + if (col_desc.col_id_ == field_or_var_struct.column_id_) { + found_column = true; + if (OB_FAIL(store_column_idxs.push_back(j))) { + LOG_WARN("fail to push back column desc", KR(ret), K(store_column_idxs), K(i), + K(col_desc), K(j), K(field_or_var_struct)); + } + } + } + } + if (OB_SUCC(ret) && OB_UNLIKELY(!found_column)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported incomplete column data", KR(ret), K(store_column_idxs), + K(column_descs), K(field_or_var_list)); + } + } + return ret; +} + +int ObLoadDataDirectImpl::init_execute_context() +{ + int ret = OB_SUCCESS; + execute_ctx_.exec_ctx_ = ctx_; + execute_ctx_.allocator_ = &ctx_->get_allocator(); + ObTableLoadParam load_param; + load_param.tenant_id_ = execute_param_.tenant_id_; + load_param.database_id_ = execute_param_.database_id_; + load_param.table_id_ = execute_param_.table_id_; + load_param.session_count_ = execute_param_.parallel_; + load_param.batch_size_ = execute_param_.batch_row_count_; + load_param.max_error_row_count_ = execute_param_.max_error_rows_; + load_param.column_count_ = execute_param_.store_column_idxs_.count(); + load_param.need_sort_ = execute_param_.need_sort_; + load_param.data_type_ = ObTableLoadDataType::OBJ_ARRAY; + load_param.dup_action_ = execute_param_.dup_action_; + load_param.sql_mode_ = execute_param_.sql_mode_; + load_param.px_mode_ = false; + load_param.online_opt_stat_gather_ = execute_param_.online_opt_stat_gather_; + if (OB_FAIL(direct_loader_.init(load_param, + execute_param_.store_column_idxs_, &execute_ctx_))) { + LOG_WARN("fail to init direct loader", KR(ret)); + } else if (OB_FAIL(init_logger())) { + LOG_WARN("fail to init logger", KR(ret)); + } + if (OB_SUCC(ret)) { + execute_ctx_.direct_loader_ = &direct_loader_; + execute_ctx_.job_stat_ = direct_loader_.get_job_stat(); + execute_ctx_.logger_ = &logger_; + } + return ret; +} + +int ObLoadDataDirectImpl::init_logger() +{ + int ret = OB_SUCCESS; + ObString load_info; + char *buf = nullptr; + const int64_t buf_len = MAX_BUFFER_SIZE; + int64_t pos = 0; + ObSQLSessionInfo *session = nullptr; + if (OB_ISNULL(session = ctx_->get_my_session())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("session is null", KR(ret)); + } else if (OB_ISNULL(buf = static_cast(ctx_->get_allocator().alloc(buf_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret), K(buf_len)); + } else { + const ObString &cur_query_str = session->get_current_query_string(); + const ObLoadArgument &load_args = load_stmt_->get_load_arguments(); + int64_t current_time = ObTimeUtil::current_time(); + OZ(databuff_printf(buf, buf_len, pos, + "Tenant name:\t%.*s\n" + "File name:\t%.*s\n" + "Into table:\t%.*s\n" + "Parallel:\t%ld\n" + "Batch size:\t%ld\n" + "SQL trace:\t%s\n", + session->get_tenant_name().length(), session->get_tenant_name().ptr(), + load_args.file_name_.length(), load_args.file_name_.ptr(), + load_args.combined_name_.length(), load_args.combined_name_.ptr(), + execute_param_.parallel_, execute_param_.batch_row_count_, + ObCurTraceId::get_trace_id_str())); + OZ(databuff_printf(buf, buf_len, pos, "Start time:\t")); + OZ(ObTimeConverter::datetime_to_str(current_time, TZ_INFO(session), ObString(), + MAX_SCALE_FOR_TEMPORAL, buf, buf_len, pos, true)); + OZ(databuff_printf(buf, buf_len, pos, "\n")); + OZ(databuff_printf(buf, buf_len, pos, "Load query: \n%.*s\n", cur_query_str.length(), + cur_query_str.ptr())); + OX(load_info.assign_ptr(buf, pos)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(logger_.init(load_info))) { + LOG_WARN("fail to init logger", KR(ret)); + } + } + return ret; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/cmd/ob_load_data_direct_impl.h b/src/sql/engine/cmd/ob_load_data_direct_impl.h new file mode 100644 index 0000000000..a72c2ece8d --- /dev/null +++ b/src/sql/engine/cmd/ob_load_data_direct_impl.h @@ -0,0 +1,465 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "observer/table_load/ob_table_load_object_allocator.h" +#include "observer/table_load/ob_table_load_task.h" +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_row_array.h" +#include "share/table/ob_table_load_define.h" +#include "sql/engine/cmd/ob_load_data_impl.h" +#include "sql/engine/cmd/ob_load_data_parser.h" +#include "common/storage/ob_io_device.h" +#include "observer/table_load/ob_table_load_exec_ctx.h" +#include "observer/table_load/ob_table_load_instance.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadParam; +class ObTableLoadTableCtx; +class ObTableLoadExecCtx; +class ObTableLoadCoordinator; +class ObITableLoadTaskScheduler; +class ObTableLoadInstance; +} // namespace observer +namespace sql +{ +/** + * LOAD DATA接入direct load路径 + * + * - 输入行必须包含表的所有列数据, 除了堆表的隐藏主键列 + * - 不支持SET子句 + * - 不支持表达式 + */ +class ObLoadDataDirectImpl : public ObLoadDataBase +{ + static const int64_t MAX_DATA_MEM_USAGE_LIMIT = 64; + +public: + ObLoadDataDirectImpl(); + virtual ~ObLoadDataDirectImpl(); + int execute(ObExecContext &ctx, ObLoadDataStmt &load_stmt) override; + +private: + class Logger; + + struct DataAccessParam + { + public: + DataAccessParam(); + bool is_valid() const; + TO_STRING_KV(K_(file_location), K_(file_column_num), K_(file_cs_type)); + public: + ObLoadFileLocation file_location_; + share::ObBackupStorageInfo access_info_; + int64_t file_column_num_; // number of column in file + ObDataInFileStruct file_format_; + common::ObCollationType file_cs_type_; + }; + + struct LoadExecuteParam + { + public: + LoadExecuteParam(); + bool is_valid() const; + TO_STRING_KV(K_(tenant_id), K_(database_id), K_(table_id), K_(combined_name), K_(parallel), + K_(batch_row_count), K_(data_mem_usage_limit), K_(need_sort), K_(online_opt_stat_gather), + K_(max_error_rows), K_(ignore_row_num), K_(data_access_param), K_(store_column_idxs)); + public: + uint64_t tenant_id_; + uint64_t database_id_; + uint64_t table_id_; + uint64_t sql_mode_; + common::ObString database_name_; + common::ObString table_name_; + common::ObString combined_name_; // database name + table name + int64_t parallel_; // number of concurrent threads + int64_t batch_row_count_; + int64_t data_mem_usage_limit_; // limit = data_mem_usage_limit * MAX_BUFFER_SIZE + bool need_sort_; + bool online_opt_stat_gather_; + int64_t max_error_rows_; // max allowed error rows + int64_t ignore_row_num_; // number of rows to ignore per file + sql::ObLoadDupActionType dup_action_; + DataAccessParam data_access_param_; + common::ObSEArray + store_column_idxs_; // Mapping of stored columns to source data columns + }; + + struct LoadExecuteContext : public observer::ObTableLoadExecCtx + { + public: + LoadExecuteContext(); + bool is_valid() const; + TO_STRING_KV(KP_(exec_ctx), KP_(allocator), KP_(direct_loader), KP_(job_stat), KP_(logger)); + public: + observer::ObTableLoadInstance *direct_loader_; + sql::ObLoadDataStat *job_stat_; + Logger *logger_; + }; + +private: + class Logger + { + static const char *log_file_column_names; + static const char *log_file_row_fmt; + public: + Logger(); + ~Logger(); + int init(const common::ObString &load_info); + int log_error_line(const common::ObString &file_name, int64_t line_no, int err_code); + private: + static int generate_log_file_name(char *buf, int64_t size, common::ObString &file_name); + private: + lib::ObMutex mutex_; + ObFileAppender file_appender_; + bool is_oracle_mode_; + char *buf_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(Logger); + }; + +private: + struct DataDesc + { + public: + DataDesc() : file_idx_(0), start_(0), end_(-1) {} + ~DataDesc() {} + TO_STRING_KV(K_(file_idx), K_(filename), K_(start), K_(end)); + public: + int64_t file_idx_; + ObString filename_; + int64_t start_; + int64_t end_; + }; + + class DataDescIterator + { + public: + DataDescIterator(); + ~DataDescIterator(); + int64_t count() const { return data_descs_.count(); } + int copy(const ObLoadFileIterator &file_iter); + int copy(const DataDescIterator &desc_iter); + int add_data_desc(const DataDesc &data_desc); + int get_next_data_desc(DataDesc &data_desc); + TO_STRING_KV(K_(data_descs), K_(pos)); + private: + common::ObSEArray data_descs_; + int64_t pos_; + }; + + class IRandomIODevice + { + public: + virtual ~IRandomIODevice() = default; + virtual int open(const DataAccessParam &data_access_param, const ObString &filename) = 0; + virtual int pread(char *buf, int64_t count, int64_t offset, int64_t &read_size) = 0; + virtual int get_file_size(int64_t &file_size) = 0; + }; + + class RandomFileReader : public IRandomIODevice + { + public: + RandomFileReader(); + virtual ~RandomFileReader(); + int open(const DataAccessParam &data_access_param, const ObString &filename) override; + int pread(char *buf, int64_t count, int64_t offset, int64_t &read_size) override; + int get_file_size(int64_t &file_size) override; + private: + ObString filename_; + ObFileReader file_reader_; + bool is_inited_; + }; + + class RandomOSSReader : public IRandomIODevice + { + public: + RandomOSSReader(); + virtual ~RandomOSSReader(); + int open(const DataAccessParam &data_access_param, const ObString &filename) override; + int pread(char *buf, int64_t count, int64_t offset, int64_t &read_size) override; + int get_file_size(int64_t &file_size) override; + private: + ObIODevice *device_handle_; + ObIOFd fd_; + bool is_inited_; + }; + + class SequentialDataAccessor + { + public: + SequentialDataAccessor(); + ~SequentialDataAccessor(); + int init(const DataAccessParam &data_access_param, const ObString &filename); + int read(char *buf, int64_t count, int64_t &read_size); + int get_file_size(int64_t &file_size); + void seek(int64_t offset) { offset_ = offset; } + int64_t get_offset() const { return offset_; } + private: + RandomFileReader random_file_reader_; + RandomOSSReader random_oss_reader_; + IRandomIODevice *random_io_device_; + int64_t offset_; + bool is_inited_; + }; + + struct DataBuffer + { + public: + DataBuffer(); + ~DataBuffer(); + void reuse(); + void reset(); + int init(int64_t capacity = ObLoadFileBuffer::MAX_BUFFER_SIZE); + bool is_valid() const; + int64_t get_data_length() const; + int64_t get_remain_length() const; + bool empty() const; + char *data() const; + void advance(int64_t length); + void update_data_length(int64_t length); + int squash(); + void swap(DataBuffer &other); + TO_STRING_KV(KPC_(file_buffer), K_(pos)); + private: + common::ObArenaAllocator allocator_; + public: + ObLoadFileBuffer *file_buffer_; + int64_t pos_; // left pos + bool is_end_file_; + private: + DISALLOW_COPY_AND_ASSIGN(DataBuffer); + }; + + // Read the buffer and align it by row. + class DataReader + { + public: + DataReader(); + int init(const DataAccessParam &data_access_param, LoadExecuteContext &execute_ctx, + const DataDesc &data_desc, bool read_raw = false); + int get_next_buffer(ObLoadFileBuffer &file_buffer, int64_t &line_count, + int64_t limit = INT64_MAX); + int get_next_raw_buffer(DataBuffer &data_buffer); + int64_t get_lines_count() const { return data_trimer_.get_lines_count(); } + bool has_incomplate_data() const { return data_trimer_.has_incomplate_data(); } + bool is_end_file() const { return io_accessor_.get_offset() >= end_offset_; } + ObCSVGeneralParser &get_csv_parser() { return csv_parser_; } + private: + LoadExecuteContext *execute_ctx_; + ObCSVGeneralParser csv_parser_; // 用来计算完整行 + ObLoadFileDataTrimer data_trimer_; // 缓存不完整行的数据 + SequentialDataAccessor io_accessor_; + int64_t end_offset_; + bool read_raw_; + bool is_iter_end_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(DataReader); + }; + + // Parse the data in the buffer into a string array by column. + class DataParser + { + public: + DataParser(); + ~DataParser(); + int init(const DataAccessParam &data_access_param, Logger &logger); + int parse(const common::ObString &file_name, int64_t start_line_no, DataBuffer &data_buffer); + int get_next_row(common::ObNewRow &row); + private: + void log_error_line(int err_ret, int64_t err_line_no); + private: + ObCSVGeneralParser csv_parser_; + DataBuffer escape_buffer_; + DataBuffer *data_buffer_; + // 以下参数是为了打错误日志 + common::ObString file_name_; + int64_t start_line_no_; + int64_t pos_; + Logger *logger_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(DataParser); + }; + + class SimpleDataSplitUtils + { + public: + static bool is_simple_format(const ObDataInFileStruct &file_format, + common::ObCollationType file_cs_type); + static int split(const DataAccessParam &data_access_param, const DataDesc &data_desc, + int64_t count, DataDescIterator &data_desc_iter); + }; + + struct TaskResult + { + TaskResult() + : ret_(OB_SUCCESS), + created_ts_(0), + start_process_ts_(0), + finished_ts_(0), + proccessed_row_count_(0), + parsed_bytes_(0) + { + } + void reset() + { + ret_ = OB_SUCCESS; + created_ts_ = 0; + start_process_ts_ = 0; + finished_ts_ = 0; + proccessed_row_count_ = 0; + parsed_bytes_ = 0; + } + int ret_; + int64_t created_ts_; + int64_t start_process_ts_; + int64_t finished_ts_; + int64_t proccessed_row_count_; + int64_t parsed_bytes_; + TO_STRING_KV(K_(ret), K_(created_ts), K_(start_process_ts), K_(finished_ts), + K_(proccessed_row_count), K_(parsed_bytes)); + }; + + struct TaskHandle + { + TaskHandle() : task_id_(common::OB_INVALID_ID), session_id_(0), start_line_no_(0) {} + int64_t task_id_; + DataBuffer data_buffer_; + int32_t session_id_; + DataDesc data_desc_; + int64_t start_line_no_; // 从1开始 + TaskResult result_; + TO_STRING_KV(K_(task_id), K_(data_buffer), K_(session_id), K_(data_desc), K_(start_line_no), + K_(result)); + private: + DISALLOW_COPY_AND_ASSIGN(TaskHandle); + }; + + class FileLoadExecutor + { + public: + FileLoadExecutor(); + virtual ~FileLoadExecutor(); + virtual int init(const LoadExecuteParam &execute_param, LoadExecuteContext &execute_ctx, + const DataDescIterator &data_desc_iter) = 0; + int execute(); + int alloc_task(observer::ObTableLoadTask *&task); + void free_task(observer::ObTableLoadTask *task); + void task_finished(TaskHandle *handle); + int process_task_handle(int64_t worker_idx, TaskHandle *handle, int64_t &line_count); + protected: + virtual int prepare_execute() = 0; + virtual int get_next_task_handle(TaskHandle *&handle) = 0; + virtual int fill_task(TaskHandle *handle, observer::ObTableLoadTask *task) = 0; + protected: + int inner_init(const LoadExecuteParam &execute_param, LoadExecuteContext &execute_ctx, + int64_t handle_count); + int init_worker_ctx_array(); + int fetch_task_handle(TaskHandle *&handle); + int handle_task_result(int64_t task_id, TaskResult &result); + int handle_all_task_result(); + void wait_all_task_finished(); + protected: + struct WorkerContext + { + public: + DataParser data_parser_; + table::ObTableLoadArray objs_; + }; + protected: + const LoadExecuteParam *execute_param_; + LoadExecuteContext *execute_ctx_; + observer::ObTableLoadObjectAllocator task_allocator_; + observer::ObITableLoadTaskScheduler *task_scheduler_; + WorkerContext *worker_ctx_array_; + // task ctrl + ObParallelTaskController task_controller_; + ObConcurrentFixedCircularArray handle_reserve_queue_; + common::ObSEArray handle_resource_; // 用于释放资源 + bool is_inited_; + private: + DISALLOW_COPY_AND_ASSIGN(FileLoadExecutor); + }; + + class FileLoadTaskCallback; + +private: + /** + * Large File + */ + + class LargeFileLoadExecutor : public FileLoadExecutor + { + public: + LargeFileLoadExecutor(); + virtual ~LargeFileLoadExecutor(); + int init(const LoadExecuteParam &execute_param, LoadExecuteContext &execute_ctx, + const DataDescIterator &data_desc_iter) override; + protected: + int prepare_execute() override; + int get_next_task_handle(TaskHandle *&handle) override; + int fill_task(TaskHandle *handle, observer::ObTableLoadTask *task) override; + private: + int32_t get_session_id(); + int skip_ignore_rows(); + private: + DataDesc data_desc_; + DataBuffer expr_buffer_; + DataReader data_reader_; + int32_t next_session_id_; + int64_t total_line_count_; + DISALLOW_COPY_AND_ASSIGN(LargeFileLoadExecutor); + }; + + class LargeFileLoadTaskProcessor; + +private: + /** + * Multi Files + */ + + class MultiFilesLoadExecutor : public FileLoadExecutor + { + public: + MultiFilesLoadExecutor() = default; + virtual ~MultiFilesLoadExecutor() = default; + int init(const LoadExecuteParam &execute_param, LoadExecuteContext &execute_ctx, + const DataDescIterator &data_desc_iter) override; + protected: + int prepare_execute() override; + int get_next_task_handle(TaskHandle *&handle) override; + int fill_task(TaskHandle *handle, observer::ObTableLoadTask *task) override; + private: + DataDescIterator data_desc_iter_; + DISALLOW_COPY_AND_ASSIGN(MultiFilesLoadExecutor); + }; + + class MultiFilesLoadTaskProcessor; + +private: + int init_file_iter(); + // init execute param + int init_store_column_idxs(common::ObIArray &store_column_idxs); + int init_execute_param(); + // init execute context + int init_logger(); + int init_execute_context(); + +private: + ObExecContext *ctx_; + ObLoadDataStmt *load_stmt_; + LoadExecuteParam execute_param_; + LoadExecuteContext execute_ctx_; + observer::ObTableLoadInstance direct_loader_; + Logger logger_; + DISALLOW_COPY_AND_ASSIGN(ObLoadDataDirectImpl); +}; + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/cmd/ob_load_data_executor.cpp b/src/sql/engine/cmd/ob_load_data_executor.cpp index c0151288ee..f11ea5689d 100644 --- a/src/sql/engine/cmd/ob_load_data_executor.cpp +++ b/src/sql/engine/cmd/ob_load_data_executor.cpp @@ -16,23 +16,52 @@ #include "lib/oblog/ob_log_module.h" #include "sql/engine/cmd/ob_load_data_impl.h" +#include "sql/engine/cmd/ob_load_data_direct_impl.h" #include "sql/engine/ob_exec_context.h" namespace oceanbase { namespace sql { + +int ObLoadDataExecutor::check_is_direct_load(const ObLoadDataHint &load_hint, bool &check_ret) +{ + int ret = OB_SUCCESS; + int64_t enable_direct = 0; + if (OB_FAIL(load_hint.get_value(ObLoadDataHint::ENABLE_DIRECT, enable_direct))) { + LOG_WARN("fail to get value of ENABLE_DIRECT", K(ret)); + } else if ((enable_direct != 0) && GCONF._ob_enable_direct_load) { + check_ret = true; + } else { + check_ret = false; + } + return ret; +} + int ObLoadDataExecutor::execute(ObExecContext &ctx, ObLoadDataStmt &stmt) { int ret = OB_SUCCESS; ObLoadDataBase *load_impl = NULL; + bool is_direct_load = false; if (!stmt.get_load_arguments().is_csv_format_) { ret = OB_NOT_SUPPORTED; LOG_WARN("invalid resolver results", K(ret)); - } else if (OB_ISNULL(load_impl = OB_NEWx(ObLoadDataSPImpl, (&ctx.get_allocator())))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("allocate memory failed", K(ret)); + } else if (OB_FAIL(check_is_direct_load(stmt.get_hints(), is_direct_load))) { + LOG_WARN("fail to check is load mode", KR(ret)); } else { + if (!is_direct_load) { + if (OB_ISNULL(load_impl = OB_NEWx(ObLoadDataSPImpl, (&ctx.get_allocator())))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } + } else { + if (OB_ISNULL(load_impl = OB_NEWx(ObLoadDataDirectImpl, (&ctx.get_allocator())))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } + } + } + if (OB_SUCC(ret)) { if (OB_FAIL(load_impl->execute(ctx, stmt))) { LOG_WARN("failed to execute load data stmt", K(ret)); } diff --git a/src/sql/engine/cmd/ob_load_data_executor.h b/src/sql/engine/cmd/ob_load_data_executor.h index 24271247f6..b0398cc51d 100644 --- a/src/sql/engine/cmd/ob_load_data_executor.h +++ b/src/sql/engine/cmd/ob_load_data_executor.h @@ -25,6 +25,8 @@ public: virtual ~ObLoadDataExecutor() {} int execute(ObExecContext &ctx, ObLoadDataStmt &stmt); +private: + int check_is_direct_load(const ObLoadDataHint &load_hint, bool &check_ret); private: // disallow copy DISALLOW_COPY_AND_ASSIGN(ObLoadDataExecutor); diff --git a/src/sql/engine/cmd/ob_load_data_impl.cpp b/src/sql/engine/cmd/ob_load_data_impl.cpp index 0a73128a35..589ab212f1 100644 --- a/src/sql/engine/cmd/ob_load_data_impl.cpp +++ b/src/sql/engine/cmd/ob_load_data_impl.cpp @@ -454,7 +454,7 @@ int ObLoadDataBase::pre_parse_lines(ObLoadFileBuffer &buffer, } } } - if (is_last_buf && buffer.current_ptr() > cur_pos) { + if (is_last_buf && cur_lines < line_count && buffer.current_ptr() > cur_pos) { cur_lines++; cur_pos = buffer.current_ptr(); } @@ -901,7 +901,7 @@ void ObCSVFormats::init(const ObDataInFileStruct &file_formats) if (!file_formats.field_term_str_.empty() && file_formats.line_term_str_.empty()) { is_line_term_by_counting_field_ = true; - field_term_char_ = line_term_char_; + line_term_char_ = field_term_char_; } is_simple_format_ = !is_line_term_by_counting_field_ @@ -1670,8 +1670,8 @@ int ObLoadDataSPImpl::handle_returned_insert_task(ObExecContext &ctx, } */ - box.job_status->processed_rows_ = box.affected_rows; - box.job_status->processed_bytes_ += insert_task.data_size_; + box.job_status->parsed_rows_ = box.affected_rows; + box.job_status->parsed_bytes_ += insert_task.data_size_; box.job_status->total_insert_task_ = box.insert_task_controller.get_total_task_cnt(); box.job_status->insert_rt_sum_ = box.insert_rt_sum; box.job_status->total_wait_secs_ = box.wait_secs_for_mem_release; @@ -2991,8 +2991,10 @@ int ObLoadDataSPImpl::ToolBox::init(ObExecContext &ctx, ObLoadDataStmt &load_stm ObLoadDataGID::generate_new_id(temp_gid); job_status->tenant_id_ = tenant_id; job_status->job_id_ = temp_gid.id; - job_status->table_name_ = load_args.combined_name_; - job_status->file_path_ = load_args.file_name_; + OZ(ob_write_string(job_status->allocator_, + load_args.combined_name_, job_status->table_name_)); + OZ(ob_write_string(job_status->allocator_, + load_args.file_name_, job_status->file_path_)); job_status->file_column_ = num_of_file_column; job_status->table_column_ = num_of_table_column; job_status->batch_size_ = batch_row_count; diff --git a/src/sql/engine/cmd/ob_load_data_impl.h b/src/sql/engine/cmd/ob_load_data_impl.h index 3ddb3c916e..0d17cc89d8 100644 --- a/src/sql/engine/cmd/ob_load_data_impl.h +++ b/src/sql/engine/cmd/ob_load_data_impl.h @@ -351,6 +351,7 @@ public: int64_t get_buffer_size() { return buffer_size_; } int64_t *get_pos() { return &pos_; } void reset() { pos_ = 0; } + TO_STRING_KV(K_(pos), K_(buffer_size)); private: int64_t pos_; int64_t buffer_size_; @@ -392,8 +393,8 @@ public: int backup_incomplate_data(ObLoadFileBuffer &buffer, int64_t valid_data_len); int recover_incomplate_data(ObLoadFileBuffer &buffer); - bool has_incomplate_data() { return incomplate_data_len_ > 0; } - int64_t get_lines_count() { return lines_cnt_; } + bool has_incomplate_data() const { return incomplate_data_len_ > 0; } + int64_t get_lines_count() const { return lines_cnt_; } void commit_line_cnt(int64_t line_cnt) { lines_cnt_ += line_cnt; } private: ObCSVFormats formats_;//TODO [load data] change to ObInverseParser(formats) @@ -632,7 +633,7 @@ struct ObFileReadCursor { read_size_ = 0; is_end_file_ = false; } - bool inline is_end_file() { return is_end_file_; } + bool inline is_end_file() const { return is_end_file_; } int64_t inline get_total_read_MBs() { return file_offset_ >> 20; } int64_t inline get_total_read_GBs() { return file_offset_ >> 30; } void commit_read() { diff --git a/src/sql/engine/cmd/ob_load_data_utils.cpp b/src/sql/engine/cmd/ob_load_data_utils.cpp index e1ff19ab01..344dda0242 100644 --- a/src/sql/engine/cmd/ob_load_data_utils.cpp +++ b/src/sql/engine/cmd/ob_load_data_utils.cpp @@ -365,6 +365,52 @@ int ObLoadDataUtils::check_session_status(ObSQLSessionInfo &session, int64_t res return ret; } +///////////////// + +ObGetAllJobStatusOp::ObGetAllJobStatusOp() + : job_status_array_(), + current_job_index_(0) +{ +} + +ObGetAllJobStatusOp::~ObGetAllJobStatusOp() +{ + reset(); +} + +void ObGetAllJobStatusOp::reset() +{ + ObLoadDataStat *job_status; + for (int64_t i = 0; i < job_status_array_.count(); ++i) { + job_status = job_status_array_.at(i); + job_status->release(); + } + job_status_array_.reset(); + current_job_index_ = 0; +} + +int ObGetAllJobStatusOp::operator()(common::hash::HashMapPair &entry) +{ + int ret = OB_SUCCESS; + entry.second->aquire(); + if (OB_FAIL(job_status_array_.push_back(entry.second))) { + entry.second->release(); + LOG_WARN("push_back ObLoadDataStat failed", K(ret)); + } + return ret; +} + +int ObGetAllJobStatusOp::get_next_job_status(ObLoadDataStat *&job_status) +{ + int ret = OB_SUCCESS; + if (current_job_index_ >= job_status_array_.count()) { + ret = OB_ITER_END; + } else { + job_status = job_status_array_.at(current_job_index_++); + } + return ret; +} + int ObGlobalLoadDataStatMap::init() { int ret = OB_SUCCESS; @@ -416,63 +462,21 @@ int ObGlobalLoadDataStatMap::get_job_status(const ObLoadDataGID &id, ObLoadDataS int ObGlobalLoadDataStatMap::get_all_job_status(ObGetAllJobStatusOp &job_status_op) { int ret = OB_SUCCESS; - OZ (map_.foreach_refactored(job_status_op)); - return ret; } -ObGetAllJobStatusOp::ObGetAllJobStatusOp() - : job_status_array_(), - current_job_index_(0) -{ - -} - -ObGetAllJobStatusOp::~ObGetAllJobStatusOp() -{ - reset(); -} - -void ObGetAllJobStatusOp::reset() -{ - ObLoadDataStat *job_status; - for (int i = 0; i < job_status_array_.count(); i++) { - job_status = job_status_array_.at(i); - job_status->release(); - } - job_status_array_.reset(); - current_job_index_ = 0; -} - -int ObGetAllJobStatusOp::operator()(common::hash::HashMapPair &entry) +int ObGlobalLoadDataStatMap::get_job_stat_guard(const ObLoadDataGID &id, ObLoadDataStatGuard &guard) { int ret = OB_SUCCESS; - - entry.second->aquire(); - if (OB_FAIL(job_status_array_.push_back(entry.second))) { - entry.second->release(); - LOG_WARN("push_back ObLoadDataStat failed", K(ret)); - } - + auto get_and_add_ref = [&](hash::HashMapPair &entry) -> void + { + guard.aquire(entry.second); + }; + OZ (map_.read_atomic(id, get_and_add_ref)); return ret; } -ObLoadDataStat* ObGetAllJobStatusOp::next_job_status() -{ - ObLoadDataStat *job_status = nullptr; - if (current_job_index_ < job_status_array_.count()) { - job_status = job_status_array_.at(current_job_index_++); - } - - return job_status; -} - -bool ObGetAllJobStatusOp::end() -{ - return (current_job_index_ >= job_status_array_.count()); -} - ObGlobalLoadDataStatMap *ObGlobalLoadDataStatMap::getInstance() { return instance_; diff --git a/src/sql/engine/cmd/ob_load_data_utils.h b/src/sql/engine/cmd/ob_load_data_utils.h index c9873b7578..d9938a4446 100644 --- a/src/sql/engine/cmd/ob_load_data_utils.h +++ b/src/sql/engine/cmd/ob_load_data_utils.h @@ -284,6 +284,7 @@ struct ObLoadDataGID gid.id = ATOMIC_AAF(&GlobalLoadDataID, 1); } ObLoadDataGID() : id(-1) {} + void reset() { id = -1; } bool is_valid() const { return id > 0; } uint64_t hash() const { return common::murmurhash(&id, sizeof(id), 0); } bool operator==(const ObLoadDataGID &other) const { return id == other.id; } @@ -296,9 +297,11 @@ struct ObLoadDataGID struct ObLoadDataStat { - ObLoadDataStat() : ref_cnt_(0), + ObLoadDataStat() : allocator_(ObModIds::OB_SQL_LOAD_DATA), + ref_cnt_(0), tenant_id_(0), job_id_(0), + job_type_(), table_name_(), file_path_(), table_column_(0), @@ -310,13 +313,15 @@ struct ObLoadDataStat estimated_remaining_time_(0), total_bytes_(0), read_bytes_(0), - processed_bytes_(0), - processed_rows_(0), + parsed_bytes_(0), + parsed_rows_(0), total_shuffle_task_(0), total_insert_task_(0), shuffle_rt_sum_(0), insert_rt_sum_(0), - total_wait_secs_(0) {} + total_wait_secs_(0), + max_allowed_error_rows_(0), + detected_error_rows_(0) {} int64_t aquire() { return ATOMIC_AAF(&ref_cnt_, 1); } @@ -325,9 +330,11 @@ struct ObLoadDataStat } int64_t get_ref_cnt() { return ATOMIC_LOAD(&ref_cnt_); } + common::ObArenaAllocator allocator_; volatile int64_t ref_cnt_; int64_t tenant_id_; int64_t job_id_; + common::ObString job_type_; // normal / direct common::ObString table_name_; common::ObString file_path_; int64_t table_column_; @@ -338,16 +345,42 @@ struct ObLoadDataStat int64_t start_time_; int64_t estimated_remaining_time_; int64_t total_bytes_; - int64_t read_bytes_; //bytes read to memory - int64_t processed_bytes_; - int64_t processed_rows_; + volatile int64_t read_bytes_; //bytes read to memory + volatile int64_t parsed_bytes_; + volatile int64_t parsed_rows_; int64_t total_shuffle_task_; int64_t total_insert_task_; int64_t shuffle_rt_sum_; int64_t insert_rt_sum_; int64_t total_wait_secs_; + int64_t max_allowed_error_rows_; + int64_t detected_error_rows_; + struct { + volatile int64_t received_rows_; // received from client + int64_t last_commit_segment_id_; + common::ObString status_; // none / inited / loading / frozen / merging / commit / error / abort + common::ObString trans_status_; // none / inited / running / frozen / commit / error / abort + } coordinator; - TO_STRING_KV(K(job_id_), K(table_name_), K(total_bytes_), K(processed_bytes_)); + struct { + volatile int64_t processed_rows_; + int64_t last_commit_segment_id_; + common::ObString status_; + common::ObString trans_status_; + } store; + + TO_STRING_KV(K(tenant_id_), K(job_id_), K(job_type_), + K(table_name_), K(file_path_), K(table_column_), K(file_column_), + K(batch_size_), K(parallel_), K(load_mode_), + K(start_time_), K(estimated_remaining_time_), + K(total_bytes_), K(read_bytes_), K(parsed_bytes_), + K(parsed_rows_), K(total_shuffle_task_), K(total_insert_task_), + K(shuffle_rt_sum_), K(insert_rt_sum_), K(total_wait_secs_), + K(max_allowed_error_rows_), K(detected_error_rows_), + K(coordinator.received_rows_), K(coordinator.last_commit_segment_id_), + K(coordinator.status_), K(coordinator.trans_status_), + K(store.processed_rows_), K(store.last_commit_segment_id_), + K(store.status_), K(store.trans_status_)); }; class ObGetAllJobStatusOp @@ -359,14 +392,60 @@ public: public: void reset(); int operator()(common::hash::HashMapPair &entry); - ObLoadDataStat* next_job_status(void); - bool end(void); + int get_next_job_status(ObLoadDataStat *&job_status); private: common::ObSEArray job_status_array_; int32_t current_job_index_; }; +class ObLoadDataStatGuard +{ +public: + ObLoadDataStatGuard() : stat_(nullptr) {} + ObLoadDataStatGuard(const ObLoadDataStatGuard &rhs) : stat_(nullptr) + { + aquire(rhs.stat_); + } + ~ObLoadDataStatGuard() + { + release(); + } + + void aquire(ObLoadDataStat *stat) + { + release(); + stat_ = stat; + if (nullptr != stat_) { + stat_->aquire(); + } + } + + void release() + { + if (nullptr != stat_) { + stat_->release(); + stat_ = nullptr; + } + } + + ObLoadDataStat *get() const { return stat_; } + + // ObLoadDataStat *operator->() { return stat_; } + // const ObLoadDataStat *operator->() const { return stat_; } + + ObLoadDataStatGuard &operator=(const ObLoadDataStatGuard &rhs) + { + aquire(rhs.stat_); + return *this; + } + + TO_STRING_KV(KPC_(stat)); + +private: + ObLoadDataStat *stat_; +}; + class ObGlobalLoadDataStatMap { public: @@ -377,6 +456,7 @@ public: int unregister_job(const ObLoadDataGID &id, ObLoadDataStat *&job_status); int get_job_status(const ObLoadDataGID &id, ObLoadDataStat *&job_status); int get_all_job_status(ObGetAllJobStatusOp &job_status_op); + int get_job_stat_guard(const ObLoadDataGID &id, ObLoadDataStatGuard &guard); private: typedef common::hash::ObHashMap HASH_MAP; diff --git a/src/sql/engine/cmd/ob_table_direct_insert_ctx.cpp b/src/sql/engine/cmd/ob_table_direct_insert_ctx.cpp new file mode 100644 index 0000000000..2baf60168d --- /dev/null +++ b/src/sql/engine/cmd/ob_table_direct_insert_ctx.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SQL_ENG + +#include "sql/engine/cmd/ob_table_direct_insert_ctx.h" +#include "sql/engine/ob_exec_context.h" +#include "observer/table_load/ob_table_load_exec_ctx.h" +#include "observer/table_load/ob_table_load_struct.h" +#include "observer/table_load/ob_table_load_instance.h" +#include "share/schema/ob_schema_getter_guard.h" + +namespace oceanbase +{ +using namespace common; +using namespace observer; +using namespace storage; +using namespace share; + +namespace sql +{ +ObTableDirectInsertCtx::~ObTableDirectInsertCtx() +{ + destroy(); +} + +int ObTableDirectInsertCtx::init(ObExecContext *exec_ctx, + const uint64_t table_id, const int64_t parallel) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObTableDirectInsertCtx init twice", KR(ret)); + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("exec_ctx cannot be null", KR(ret)); + } else { + load_exec_ctx_ = (ObTableLoadExecCtx *)exec_ctx->get_allocator().alloc(sizeof(ObTableLoadExecCtx)); + table_load_instance_ = (ObTableLoadInstance *)exec_ctx->get_allocator().alloc(sizeof(ObTableLoadInstance)); + if (OB_ISNULL(load_exec_ctx_) || OB_ISNULL(table_load_instance_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", KR(ret)); + } else { + new (load_exec_ctx_) ObTableLoadExecCtx; + new (table_load_instance_) ObTableLoadInstance; + load_exec_ctx_->exec_ctx_ = exec_ctx; + load_exec_ctx_->allocator_ = &(exec_ctx->get_allocator()); + uint64_t sql_mode = 0; + ObSEArray store_column_idxs; + ObObj obj; + if (OB_FAIL(init_store_column_idxs(MTL_ID(), table_id, store_column_idxs))) { + LOG_WARN("failed to init store column idxs", KR(ret)); + } else if (OB_FAIL(exec_ctx->get_my_session()->get_sys_variable(SYS_VAR_SQL_MODE, sql_mode))) { + LOG_WARN("fail to get sys variable", KR(ret)); + } else if (OB_FAIL(exec_ctx->get_my_session()->get_sys_variable(SYS_VAR_ONLINE_OPT_STAT_GATHER, obj))) { + LOG_WARN("fail to get sys variable", K(ret)); + } else { + ObTableLoadParam param; + param.column_count_ = store_column_idxs.count(); + param.tenant_id_ = MTL_ID(); + param.database_id_ = exec_ctx->get_my_session()->get_database_id(); + param.table_id_ = table_id; + param.batch_size_ = 100; + param.session_count_ = parallel; + param.px_mode_ = true; + param.online_opt_stat_gather_ = obj.get_bool(); + param.need_sort_ = true; + param.max_error_row_count_ = 0; + param.dup_action_ = sql::ObLoadDupActionType::LOAD_STOP_ON_DUP; + param.sql_mode_ = sql_mode; + if (OB_FAIL(table_load_instance_->init(param, store_column_idxs, load_exec_ctx_))) { + LOG_WARN("failed to init direct loader", KR(ret)); + } else { + is_inited_ = true; + LOG_DEBUG("succeeded to init direct loader", K(param)); + } + } + } + } + return ret; +} + +int ObTableDirectInsertCtx::finish() +{ + int ret = OB_SUCCESS; + table::ObTableLoadResultInfo result_info; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableDirectInsertCtx is not init", KR(ret)); + } else if (OB_FAIL(table_load_instance_->commit(result_info))) { + LOG_WARN("failed to commit direct loader", KR(ret)); + } else { + table_load_instance_->destroy(); + LOG_DEBUG("succeeded to commit direct loader", K(result_info)); + } + return ret; +} + +void ObTableDirectInsertCtx::destroy() +{ + if (OB_NOT_NULL(table_load_instance_)) { + table_load_instance_->~ObTableLoadInstance(); + table_load_instance_ = nullptr; + } + if (OB_NOT_NULL(load_exec_ctx_)) { + load_exec_ctx_->~ObTableLoadExecCtx(); + load_exec_ctx_ = nullptr; + } +} + +int ObTableDirectInsertCtx::init_store_column_idxs(const uint64_t tenant_id, + const uint64_t table_id, ObIArray &store_column_idxs) +{ + int ret = OB_SUCCESS; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + ObSEArray column_descs; + + if (OB_FAIL(ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard(tenant_id, + schema_guard))) { + LOG_WARN("fail to get tenant schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_FAIL(table_schema->get_column_ids(column_descs))) { + STORAGE_LOG(WARN, "fail to get column descs", KR(ret), KPC(table_schema)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && (i < column_descs.count()); ++i) { + const ObColDesc &col_desc = column_descs.at(i); + const ObColumnSchemaV2 *col_schema = table_schema->get_column_schema(col_desc.col_id_); + if (OB_ISNULL(col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null column schema", KR(ret), K(col_desc)); + } else if (col_schema->is_hidden()) { + } else if (OB_FAIL(store_column_idxs.push_back(i))) { + LOG_WARN("failed to push back store column idxs", KR(ret), K(i)); + } + } + } + + return ret; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/cmd/ob_table_direct_insert_ctx.h b/src/sql/engine/cmd/ob_table_direct_insert_ctx.h new file mode 100644 index 0000000000..0a792f4c53 --- /dev/null +++ b/src/sql/engine/cmd/ob_table_direct_insert_ctx.h @@ -0,0 +1,43 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "lib/container/ob_iarray.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadExecCtx; +class ObTableLoadInstance; +} + +namespace sql +{ +class ObExecContext; + +class ObTableDirectInsertCtx +{ +public: + ObTableDirectInsertCtx() + : load_exec_ctx_(nullptr), + table_load_instance_(nullptr), + is_inited_(false) {} + ~ObTableDirectInsertCtx(); + TO_STRING_KV(K_(is_inited)); +public: + int init(sql::ObExecContext *exec_ctx, const uint64_t table_id, const int64_t parallel); + int finish(); + void destroy(); +private: + int init_store_column_idxs(const uint64_t tenant_id, const uint64_t table_id, + common::ObIArray &store_column_idxs); +private: + observer::ObTableLoadExecCtx *load_exec_ctx_; + observer::ObTableLoadInstance *table_load_instance_; + bool is_inited_; +}; +} // namespace observer +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/cmd/ob_table_direct_insert_trans.cpp b/src/sql/engine/cmd/ob_table_direct_insert_trans.cpp new file mode 100644 index 0000000000..7e986745b8 --- /dev/null +++ b/src/sql/engine/cmd/ob_table_direct_insert_trans.cpp @@ -0,0 +1,116 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#define USING_LOG_PREFIX SQL_ENG + +#include "sql/engine/cmd/ob_table_direct_insert_trans.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/ob_physical_plan.h" + +namespace oceanbase +{ +using namespace observer; + +namespace sql +{ +int ObTableDirectInsertTrans::try_start_direct_insert(ObExecContext &ctx, + ObPhysicalPlan &phy_plan) +{ + int ret = OB_SUCCESS; + if (phy_plan.get_enable_append() + && (0 != phy_plan.get_append_table_id())) { + if (!GCONF._ob_enable_direct_load) { // recheck + phy_plan.set_enable_append(false); + phy_plan.set_append_table_id(0); + } else { + ObSQLSessionInfo *session = GET_MY_SESSION(ctx); + CK (OB_NOT_NULL(session)); + bool auto_commit = false; + if (OB_FAIL(session->get_autocommit(auto_commit))) { + LOG_WARN("failed to get auto commit", KR(ret)); + } else if (!auto_commit || session->is_in_transaction()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("using direct-insert within a transaction is not supported", + KR(ret), K(auto_commit), K(session->is_in_transaction())); + } else { + ObTableDirectInsertCtx &table_direct_insert_ctx = ctx.get_table_direct_insert_ctx(); + uint64_t table_id = phy_plan.get_append_table_id(); + int64_t parallel = phy_plan.get_px_dop(); + if (OB_FAIL(table_direct_insert_ctx.init(&ctx, table_id, parallel))) { + LOG_WARN("failed to init table direct insert ctx", KR(ret), K(table_id), K(parallel)); + } + } + } + } + return ret; +} + +int ObTableDirectInsertTrans::try_finish_direct_insert(ObExecContext &ctx, + ObPhysicalPlan &phy_plan) +{ + int ret = OB_SUCCESS; + if (phy_plan.get_enable_append() + && (0 != phy_plan.get_append_table_id())) { + ObTableDirectInsertCtx &table_direct_insert_ctx = ctx.get_table_direct_insert_ctx(); + if (OB_FAIL(table_direct_insert_ctx.finish())) { + LOG_WARN("failed to finish table direct insert ctx", KR(ret)); + } + } + return ret; +} + +int ObTableDirectInsertTrans::start_trans(const uint64_t table_id, const int64_t task_id) +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(MTL_ID(), table_id); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key), K(table_id)); + } else { + table::ObTableLoadTransId trans_id; + trans_id.segment_id_ = task_id; + trans_id.trans_gid_ = 1; + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.px_start_trans(trans_id))) { + LOG_WARN("fail to start direct load trans", KR(ret), K(trans_id)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + return ret; +} + +int ObTableDirectInsertTrans::finish_trans(const uint64_t table_id, const int64_t task_id) +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(MTL_ID(), table_id); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key), K(table_id)); + } else { + table::ObTableLoadTransId trans_id; + trans_id.segment_id_ = task_id; + trans_id.trans_gid_ = 1; + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } else if (OB_FAIL(store.px_finish_trans(trans_id))) { + LOG_WARN("fail to finish direct load trans", KR(ret), K(trans_id)); + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + return ret; +} +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/cmd/ob_table_direct_insert_trans.h b/src/sql/engine/cmd/ob_table_direct_insert_trans.h new file mode 100644 index 0000000000..fb032071c9 --- /dev/null +++ b/src/sql/engine/cmd/ob_table_direct_insert_trans.h @@ -0,0 +1,27 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yuya.yu + +#pragma once + +#include "lib/ob_define.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExecContext; +class ObPhysicalPlan; + +class ObTableDirectInsertTrans +{ +public: + // all insert-tasks within an insert into select clause are wrapped by a single direct insert instance + static int try_start_direct_insert(ObExecContext &ctx, ObPhysicalPlan &plan); + static int try_finish_direct_insert(ObExecContext &ctx, ObPhysicalPlan &plan); + // each insert-task is processed in a single thread and is wrapped by a table load trans + static int start_trans(const uint64_t table_id, const int64_t task_id); + static int finish_trans(const uint64_t table_id, const int64_t task_id); +}; +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/dml/ob_table_insert_op.cpp b/src/sql/engine/dml/ob_table_insert_op.cpp index 2b93e58992..a25eb0d114 100644 --- a/src/sql/engine/dml/ob_table_insert_op.cpp +++ b/src/sql/engine/dml/ob_table_insert_op.cpp @@ -26,6 +26,7 @@ #include "lib/profile/ob_perf_event.h" #include "share/schema/ob_table_dml_param.h" #include "share/ob_tablet_autoincrement_service.h" +#include "sql/engine/cmd/ob_table_direct_insert_trans.h" namespace oceanbase @@ -34,6 +35,7 @@ using namespace common; using namespace storage; using namespace share; using namespace share::schema; +using namespace observer; namespace sql { @@ -133,6 +135,11 @@ OB_INLINE int ObTableInsertOp::open_table_for_each() const ObInsCtDef &ins_ctdef = *ctdefs.at(j); if (OB_FAIL(ObDMLService::init_ins_rtdef(dml_rtctx_, ins_rtdef, ins_ctdef, trigger_clear_exprs_))) { LOG_WARN("init insert rtdef failed", K(ret)); + } else { + const ObPhysicalPlan *plan = GET_PHY_PLAN_CTX(ctx_)->get_phy_plan(); + if (plan->get_enable_append() && (0 != plan->get_append_table_id())) { + ins_rtdef.das_rtdef_.direct_insert_task_id_ = 1; + } } } if (OB_SUCC(ret) && !rtdefs.empty()) { @@ -388,6 +395,16 @@ int ObTableInsertOp::inner_open() } else if (OB_FAIL(inner_open_with_das())) { LOG_WARN("inner open with das failed", K(ret)); } + if (OB_SUCC(ret)) { + const ObPhysicalPlan *plan = GET_PHY_PLAN_CTX(ctx_)->get_phy_plan(); + if (plan->get_enable_append() && (0 != plan->get_append_table_id())) { + int64_t task_id = 1; + if (OB_FAIL(ObTableDirectInsertTrans::start_trans(plan->get_append_table_id(), task_id))) { + LOG_WARN("failed to start table direct insert trans", KR(ret), + K(plan->get_append_table_id()), K(task_id)); + } + } + } return ret; } @@ -410,6 +427,14 @@ int ObTableInsertOp::inner_close() { NG_TRACE(insert_close); int ret = OB_SUCCESS; + const ObPhysicalPlan *plan = GET_PHY_PLAN_CTX(ctx_)->get_phy_plan(); + if (plan->get_enable_append() && (0 != plan->get_append_table_id())) { + int64_t task_id = 1; + if (OB_FAIL(ObTableDirectInsertTrans::finish_trans(plan->get_append_table_id(), task_id))) { + LOG_WARN("failed to finish table direct insert trans", KR(ret), + K(plan->get_append_table_id()), K(task_id)); + } + } if (OB_FAIL(close_table_for_each())) { LOG_WARN("close table for each failed", K(ret)); } diff --git a/src/sql/engine/ob_exec_context.cpp b/src/sql/engine/ob_exec_context.cpp index 8e37a4324b..1373a7ac9b 100644 --- a/src/sql/engine/ob_exec_context.cpp +++ b/src/sql/engine/ob_exec_context.cpp @@ -122,7 +122,8 @@ ObExecContext::ObExecContext(ObIAllocator &allocator) nested_level_(0), is_ps_prepare_stage_(false), register_op_id_(OB_INVALID_ID), - tmp_alloc_used_(false) + tmp_alloc_used_(false), + table_direct_insert_ctx_() { } diff --git a/src/sql/engine/ob_exec_context.h b/src/sql/engine/ob_exec_context.h index ec10a4a4b3..1e9a742ba2 100644 --- a/src/sql/engine/ob_exec_context.h +++ b/src/sql/engine/ob_exec_context.h @@ -26,6 +26,7 @@ #include "sql/engine/px/ob_px_dtl_msg.h" #include "sql/optimizer/ob_pwj_comparer.h" #include "sql/das/ob_das_context.h" +#include "sql/engine/cmd/ob_table_direct_insert_ctx.h" #include "pl/ob_pl_package_guard.h" #define GET_PHY_PLAN_CTX(ctx) ((ctx).get_physical_plan_ctx()) @@ -459,6 +460,7 @@ public: eval_res_allocator_.set_attr(attr); eval_tmp_allocator_.set_attr(attr); } + ObTableDirectInsertCtx &get_table_direct_insert_ctx() { return table_direct_insert_ctx_; } private: int build_temp_expr_ctx(const ObTempExpr &temp_expr, ObTempExprCtx *&temp_expr_ctx); int set_phy_op_ctx_ptr(uint64_t index, void *phy_op); @@ -629,6 +631,8 @@ protected: // indicate if eval_tmp_allocator_ is used bool tmp_alloc_used_; // ------------------- + // for direct insert + ObTableDirectInsertCtx table_direct_insert_ctx_; private: DISALLOW_COPY_AND_ASSIGN(ObExecContext); }; diff --git a/src/sql/engine/ob_physical_plan.cpp b/src/sql/engine/ob_physical_plan.cpp index e19cc84516..e99a267b9d 100644 --- a/src/sql/engine/ob_physical_plan.cpp +++ b/src/sql/engine/ob_physical_plan.cpp @@ -120,7 +120,9 @@ ObPhysicalPlan::ObPhysicalPlan(MemoryContext &mem_context /* = CURRENT_CONTEXT * is_packed_(false), has_instead_of_trigger_(false), min_cluster_version_(GET_MIN_CLUSTER_VERSION()), - need_record_plan_info_(false) + need_record_plan_info_(false), + enable_append_(false), + append_table_id_(0) { } @@ -202,6 +204,8 @@ void ObPhysicalPlan::reset() contain_pl_udf_or_trigger_ = false; is_packed_ = false; has_instead_of_trigger_ = false; + enable_append_ = false; + append_table_id_ = 0; stat_.expected_worker_map_.destroy(); stat_.minimal_worker_map_.destroy(); need_record_plan_info_ = false; @@ -749,7 +753,9 @@ OB_SERIALIZE_MEMBER(ObPhysicalPlan, ddl_task_id_, stat_.plan_id_, min_cluster_version_, - need_record_plan_info_); + need_record_plan_info_, + enable_append_, + append_table_id_); int ObPhysicalPlan::set_table_locations(const ObTablePartitionInfoArray &infos, ObSchemaGetterGuard &schema_guard) diff --git a/src/sql/engine/ob_physical_plan.h b/src/sql/engine/ob_physical_plan.h index 3119a24caa..cf7ee4de48 100644 --- a/src/sql/engine/ob_physical_plan.h +++ b/src/sql/engine/ob_physical_plan.h @@ -336,6 +336,10 @@ public: inline int64_t get_ddl_execution_id() const { return ddl_execution_id_; } inline void set_ddl_task_id(const int64_t ddl_task_id) { ddl_task_id_ = ddl_task_id; } inline int64_t get_ddl_task_id() const { return ddl_task_id_; } + inline void set_enable_append(const bool enable_append) { enable_append_ = enable_append; } + inline bool get_enable_append() const { return enable_append_; } + inline void set_append_table_id(const uint64_t append_table_id) { append_table_id_ = append_table_id; } + inline uint64_t get_append_table_id() const { return append_table_id_; } void set_record_plan_info(bool v) { need_record_plan_info_ = v; } bool need_record_plan_info() const { return need_record_plan_info_; } const common::ObString &get_rule_name() const { return stat_.rule_name_; } @@ -612,6 +616,8 @@ public: bool has_instead_of_trigger_; // mask if has instead of trigger on view uint64_t min_cluster_version_; // record min cluster version in code gen bool need_record_plan_info_; + bool enable_append_; // for APPEND hint + uint64_t append_table_id_; }; inline void ObPhysicalPlan::set_affected_last_insert_id(bool affected_last_insert_id) diff --git a/src/sql/engine/pdml/static/ob_px_multi_part_insert_op.cpp b/src/sql/engine/pdml/static/ob_px_multi_part_insert_op.cpp index 337953b923..5b94a6a594 100644 --- a/src/sql/engine/pdml/static/ob_px_multi_part_insert_op.cpp +++ b/src/sql/engine/pdml/static/ob_px_multi_part_insert_op.cpp @@ -15,11 +15,13 @@ #include "storage/access/ob_dml_param.h" #include "storage/tx_storage/ob_access_service.h" #include "sql/engine/dml/ob_dml_service.h" +#include "sql/engine/cmd/ob_table_direct_insert_trans.h" using namespace oceanbase::common; using namespace oceanbase::sql; using namespace oceanbase::storage; using namespace oceanbase::common::serialization; +using namespace oceanbase::observer; OB_SERIALIZE_MEMBER((ObPxMultiPartInsertOpInput, ObPxMultiPartModifyOpInput)); @@ -46,6 +48,18 @@ int ObPxMultiPartInsertOp::inner_open() nullptr, MY_SPEC.ins_ctdef_.is_heap_table_))) { LOG_WARN("failed to init data driver", K(ret)); } + if (OB_SUCC(ret)) { + const ObPhysicalPlan *plan = GET_PHY_PLAN_CTX(ctx_)->get_phy_plan(); + if (plan->get_enable_append() && (0 != plan->get_append_table_id())) { + int64_t task_id = ctx_.get_px_task_id() + 1; + if (OB_FAIL(ObTableDirectInsertTrans::start_trans(plan->get_append_table_id(), task_id))) { + LOG_WARN("failed to start table direct insert trans", KR(ret), + K(plan->get_append_table_id()), K(task_id)); + } else { + ins_rtdef_.das_rtdef_.direct_insert_task_id_ = task_id; + } + } + } LOG_TRACE("pdml static insert op", K(ret), K_(MY_SPEC.row_desc), K_(MY_SPEC.ins_ctdef)); return ret; } @@ -89,6 +103,14 @@ int ObPxMultiPartInsertOp::inner_get_next_row() int ObPxMultiPartInsertOp::inner_close() { int ret = OB_SUCCESS; + const ObPhysicalPlan *plan = GET_PHY_PLAN_CTX(ctx_)->get_phy_plan(); + if (plan->get_enable_append() && (0 != plan->get_append_table_id())) { + int64_t task_id = ctx_.get_px_task_id() + 1; + if (OB_FAIL(ObTableDirectInsertTrans::finish_trans(plan->get_append_table_id(), task_id))) { + LOG_WARN("failed to finish table direct insert trans", KR(ret), + K(plan->get_append_table_id()), K(task_id)); + } + } if (OB_FAIL(ObTableModifyOp::inner_close())) { LOG_WARN("failed to inner close table modify", K(ret)); } else { @@ -207,4 +229,4 @@ int ObPxMultiPartInsertOp::write_rows(ObExecContext &ctx, ins_rtdef_.das_rtdef_.affected_rows_ = 0; } return ret; -} +} \ No newline at end of file diff --git a/src/sql/ob_result_set.cpp b/src/sql/ob_result_set.cpp index 7cf024dd3a..538c629ef2 100644 --- a/src/sql/ob_result_set.cpp +++ b/src/sql/ob_result_set.cpp @@ -25,6 +25,7 @@ #include "sql/session/ob_sql_session_info.h" #include "sql/resolver/ob_cmd.h" #include "sql/engine/px/ob_px_admission.h" +#include "sql/engine/cmd/ob_table_direct_insert_trans.h" #include "sql/executor/ob_executor.h" #include "sql/executor/ob_cmd_executor.h" #include "sql/resolver/dml/ob_select_stmt.h" @@ -455,6 +456,13 @@ OB_INLINE int ObResultSet::do_open_plan(ObExecContext &ctx) } } + // for insert /*+ append */ into select clause + if (OB_SUCC(ret) && (stmt::T_INSERT == get_stmt_type())) { + if (OB_FAIL(ObTableDirectInsertTrans::try_start_direct_insert(ctx, *physical_plan_))) { + LOG_WARN("fail to start direct insert", KR(ret)); + } + } + if (OB_FAIL(ret)) { } else if (OB_FAIL(start_stmt())) { LOG_WARN("fail start stmt", K(ret)); @@ -682,6 +690,20 @@ OB_INLINE int ObResultSet::do_close_plan(int errcode, ObExecContext &ctx) } else if (OB_SUCCESS != (close_ret = executor_.close(ctx))) { // executor_.close里面会等到调度线程结束才返回。 SQL_LOG(WARN, "fail to close executor", K(ret), K(close_ret)); } + + ObPxAdmission::exit_query_admission(my_session_, get_exec_context(), *get_physical_plan()); + // Finishing direct-insert must be executed after ObPxTargetMgr::release_target() + if ((OB_SUCCESS == close_ret) + && (OB_SUCCESS == errcode || OB_ITER_END == errcode) + && (stmt::T_INSERT == get_stmt_type())) { + // for insert /*+ append */ into select clause + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ObTableDirectInsertTrans::try_finish_direct_insert(ctx, *physical_plan_))) { + errcode_ = tmp_ret; // record error code + errcode = tmp_ret; + LOG_WARN("fail to finish direct insert", KR(tmp_ret)); + } + } // // 必须要在executor_.execute_plan运行之后再调用exec_result_的一系列函数。 // if (OB_FAIL(exec_result_.close(ctx))) { // SQL_LOG(WARN, "fail close main query", K(ret)); @@ -716,8 +738,6 @@ OB_INLINE int ObResultSet::do_close_plan(int errcode, ObExecContext &ctx) // 无论如何都reset掉executor_,否则前面调executor_.init的时候可能会报init twice executor_.reset(); - ObPxAdmission::exit_query_admission(my_session_, get_exec_context(), *get_physical_plan()); - NG_TRACE(close_plan_end); return ret; } diff --git a/src/sql/optimizer/ob_del_upd_log_plan.cpp b/src/sql/optimizer/ob_del_upd_log_plan.cpp index 1d8d020125..2bb4abdfb7 100644 --- a/src/sql/optimizer/ob_del_upd_log_plan.cpp +++ b/src/sql/optimizer/ob_del_upd_log_plan.cpp @@ -1151,6 +1151,9 @@ int ObDelUpdLogPlan::allocate_pdml_insert_as_top(ObLogicalOperator *&top, insert_op->set_replace(insert_stmt->is_replace()); insert_op->set_ignore(insert_stmt->is_ignore()); insert_op->set_is_insert_select(insert_stmt->value_from_select()); + if (OB_NOT_NULL(insert_stmt->get_table_item(0))) { + insert_op->set_append_table_id(insert_stmt->get_table_item(0)->ref_id_); + } if (OB_FAIL(insert_stmt->get_view_check_exprs(insert_op->get_view_check_exprs()))) { LOG_WARN("failed to get view check exprs", K(ret)); } @@ -1493,9 +1496,15 @@ int ObDelUpdLogPlan::collect_related_local_index_ids(IndexDMLInfo &primary_dml_i uint64_t index_tid_array[OB_MAX_INDEX_PER_TABLE]; ObArray base_column_ids; const uint64_t tenant_id = optimizer_context_.get_session_info()->get_effective_tenant_id(); + bool is_direct_insert = false; if (OB_ISNULL(stmt) || OB_ISNULL(schema_guard = optimizer_context_.get_schema_guard())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("schema guard is nullptr", K(ret), K(stmt), K(schema_guard)); + } else if (OB_FAIL(is_direct_insert_into_select(is_direct_insert))) { + LOG_WARN("failed to check is direct insert into select", KR(ret)); + } else if (is_direct_insert) { + // no need building index + index_tid_array_size = 0; } else if (OB_FAIL(schema_guard->get_can_write_index_array(tenant_id, primary_dml_info.ref_table_id_, index_tid_array, @@ -1611,7 +1620,13 @@ int ObDelUpdLogPlan::prepare_table_dml_info_basic(const ObDmlTableInfo& table_in if (OB_SUCC(ret) && !has_tg) { uint64_t index_tid[OB_MAX_INDEX_PER_TABLE]; int64_t index_cnt = OB_MAX_INDEX_PER_TABLE; - if (OB_FAIL(schema_guard->get_can_write_index_array(session_info->get_effective_tenant_id(), + bool is_direct_insert = false; + if (OB_FAIL(is_direct_insert_into_select(is_direct_insert))) { + LOG_WARN("failed to check is direct insert into select", KR(ret)); + } else if (is_direct_insert) { + // no need building index + index_cnt = 0; + } else if (OB_FAIL(schema_guard->get_can_write_index_array(session_info->get_effective_tenant_id(), table_info.ref_table_id_, index_tid, index_cnt, true))) { LOG_WARN("failed to get can read index array", K(ret)); } @@ -2001,3 +2016,27 @@ int ObDelUpdLogPlan::check_update_part_key(const ObTableSchema* index_schema, } return ret; } + +int ObDelUpdLogPlan::is_direct_insert_into_select(bool &result) +{ + int ret = OB_SUCCESS; + const ObDelUpdStmt *stmt = get_stmt(); + ObSQLSessionInfo* session_info = optimizer_context_.get_session_info(); + if (OB_ISNULL(stmt) || OB_ISNULL(session_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", KR(ret), KP(stmt), KP(session_info)); + } else if (stmt::T_INSERT == stmt->stmt_type_ + && static_cast(stmt)->value_from_select() + && GCONF._ob_enable_direct_load + && get_optimizer_context().get_global_hint().has_append()) { + // In direct-insert mode, index will be built by direct loader + bool auto_commit = false; + if (OB_FAIL(session_info->get_autocommit(auto_commit))) { + LOG_WARN("failed to get auto commit", KR(ret)); + } else if (auto_commit && !session_info->is_in_transaction()) { + LOG_TRACE("insert into select clause in direct-insert mode, no need building index"); + result = true; + } + } + return ret; +} diff --git a/src/sql/optimizer/ob_del_upd_log_plan.h b/src/sql/optimizer/ob_del_upd_log_plan.h index c0241e5330..0ea279d3ae 100644 --- a/src/sql/optimizer/ob_del_upd_log_plan.h +++ b/src/sql/optimizer/ob_del_upd_log_plan.h @@ -223,6 +223,8 @@ public: IndexDMLInfo*& index_dml_info) const; int check_update_part_key(const ObTableSchema* index_schema, IndexDMLInfo*& index_dml_info) const; +private: + int is_direct_insert_into_select(bool &result); private: DISALLOW_COPY_AND_ASSIGN(ObDelUpdLogPlan); diff --git a/src/sql/optimizer/ob_insert_log_plan.cpp b/src/sql/optimizer/ob_insert_log_plan.cpp index 2d0f22082e..ba31f51394 100644 --- a/src/sql/optimizer/ob_insert_log_plan.cpp +++ b/src/sql/optimizer/ob_insert_log_plan.cpp @@ -368,6 +368,9 @@ int ObInsertLogPlan::allocate_insert_as_top(ObLogicalOperator *&top, insert_op->set_table_partition_info(table_partition_info); insert_op->set_lock_row_flag_expr(lock_row_flag_expr); insert_op->set_has_instead_of_trigger(insert_stmt->has_instead_of_trigger()); + if (OB_NOT_NULL(insert_stmt->get_table_item(0))) { + insert_op->set_append_table_id(insert_stmt->get_table_item(0)->ref_id_); + } if (top->is_match_all() && !is_multi_part_dml && !insert_stmt->has_instead_of_trigger()) { insert_op->set_strong_sharding(insert_sharding); } diff --git a/src/sql/optimizer/ob_log_insert.h b/src/sql/optimizer/ob_log_insert.h index 09d7a5991c..2bdf92fdf7 100644 --- a/src/sql/optimizer/ob_log_insert.h +++ b/src/sql/optimizer/ob_log_insert.h @@ -30,6 +30,7 @@ public: is_replace_(false), insert_up_(false), is_insert_select_(false), + append_table_id_(0), constraint_infos_(NULL) { } @@ -81,6 +82,11 @@ public: virtual int est_cost() override; virtual int re_est_cost(EstimateCostInfo ¶m, double &card, double &cost) override; int inner_est_cost(double child_card, double &op_cost); + inline void set_append_table_id(const uint64_t append_table_id) + { + append_table_id_ = append_table_id; + } + inline uint64_t get_append_table_id() const { return append_table_id_; } void set_constraint_infos(const common::ObIArray *constraint_infos) { constraint_infos_ = constraint_infos; @@ -105,6 +111,7 @@ protected: bool insert_up_; // insert on duplicate update statement //for SPM Pruning bool is_insert_select_; + uint64_t append_table_id_; const common::ObIArray *constraint_infos_; }; diff --git a/src/sql/optimizer/ob_table_location.cpp b/src/sql/optimizer/ob_table_location.cpp index fa666614c6..b4922b9894 100644 --- a/src/sql/optimizer/ob_table_location.cpp +++ b/src/sql/optimizer/ob_table_location.cpp @@ -1002,12 +1002,14 @@ int ObTableLocation::init_table_location(ObExecContext &exec_ctx, } if (OB_SUCC(ret)) { bool is_weak_read = false; - if (OB_FAIL(get_is_weak_read(stmt, - exec_ctx.get_my_session(), - exec_ctx.get_sql_ctx(), - is_weak_read))) { - LOG_WARN("get is weak read failed", K(ret)); - } else if (ObDuplicateScope::DUPLICATE_SCOPE_NONE != table_schema->get_duplicate_scope()) { + //if (OB_FAIL(get_is_weak_read(stmt, + // exec_ctx.get_my_session(), + // exec_ctx.get_sql_ctx(), + // is_weak_read))) { + // LOG_WARN("get is weak read failed", K(ret)); + //} else + + if (ObDuplicateScope::DUPLICATE_SCOPE_NONE != table_schema->get_duplicate_scope()) { loc_meta_.is_dup_table_ = 1; } if (is_dml_table) { @@ -1070,6 +1072,7 @@ int ObTableLocation::init_table_location_with_rowkey(ObSqlSchemaGuard &schema_gu const ObTableSchema *table_schema = NULL; ObSQLSessionInfo *session_info = NULL; ObArray column_ids; + ObSEArray column_descs; if (OB_FAIL(schema_checker.init(schema_guard))) { LOG_WARN("fail to init schema_checker", K(ret)); } else if (OB_ISNULL(session_info = exec_ctx.get_my_session())) { @@ -1081,18 +1084,34 @@ int ObTableLocation::init_table_location_with_rowkey(ObSqlSchemaGuard &schema_gu } else if (OB_ISNULL(table_schema)) { ret = OB_TABLE_NOT_EXIST; LOG_WARN("table not exist", K(table_id)); - } else if (table_schema->is_heap_table()) { + } else if (OB_FAIL(table_schema->get_column_ids(column_descs))) { + LOG_WARN("fail to get column ids", KR(ret)); + } else if (OB_UNLIKELY(column_descs.empty())) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("init heap table location with by auto increment not supported", K(ret)); - } else if (OB_FAIL(table_schema->get_rowkey_info().get_column_ids(column_ids))) { - LOG_WARN("get column ids of rowkey info failed", K(ret), K(table_schema->get_rowkey_info())); - } else if (OB_FAIL(init_table_location_with_column_ids(schema_guard, - table_id, - column_ids, - exec_ctx, - is_dml_table, - is_link))) { - LOG_WARN("init table location with column ids failed", K(ret), K(table_id), K(column_ids)); + LOG_WARN("unexpected empty column desc", KR(ret)); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < column_descs.count(); ++i) { + const ObColumnSchemaV2 *column_schema = + table_schema->get_column_schema(column_descs.at(i).col_id_); + int64_t part_key_pos = column_schema->get_part_key_pos(); + int64_t sub_part_key_pos = column_schema->get_subpart_key_pos(); + if (part_key_pos > 0 || sub_part_key_pos > 0) { + if(OB_FAIL(column_ids.push_back(column_descs.at(i).col_id_))) { + LOG_WARN("fail to push back column id", KR(ret), K(column_descs.at(i).col_id_), K(column_ids)); + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(init_table_location_with_column_ids(schema_guard, + table_id, + column_ids, + exec_ctx, + is_dml_table, + is_link))) { + LOG_WARN("init table location with column ids failed", K(ret), K(table_id), K(column_ids)); + } } return ret; } @@ -1376,6 +1395,105 @@ int ObTableLocation::calculate_candi_tablet_locations( return ret; } +int ObTableLocation::init_partition_ids_by_rowkey2(ObExecContext &exec_ctx, + ObSQLSessionInfo &session_info, + ObSchemaGetterGuard &schema_guard, + uint64_t table_id) +{ + int ret = OB_SUCCESS; + ObSqlSchemaGuard sql_schema_guard; + sql_schema_guard.set_schema_guard(&schema_guard); + exec_ctx.set_my_session(&session_info); + if (OB_UNLIKELY(is_virtual_table(table_id))) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Calculate virtual table partition id with rowkey"); + } else if (OB_FAIL(init_table_location_with_rowkey(sql_schema_guard, table_id, exec_ctx))) { + LOG_WARN("implicit init location failed", K(table_id), K(ret)); + } + return ret; +} + +//FIXME +int ObTableLocation::calculate_partition_ids_by_rows2(ObSQLSessionInfo &session_info, + ObSchemaGetterGuard &schema_guard, + uint64_t table_id, + ObIArray &part_rows, + ObIArray &tablet_ids, + ObIArray &part_ids) const +{ + int ret = OB_SUCCESS; + ObArenaAllocator allocator(ObModIds::OB_SQL_TABLE_LOCATION); + SMART_VAR(ObExecContext, exec_ctx, allocator) { + ObSqlSchemaGuard sql_schema_guard; + sql_schema_guard.set_schema_guard(&schema_guard); + exec_ctx.set_my_session(&session_info); + ObDASTabletMapper tablet_mapper; + OZ(OB_FAIL(exec_ctx.get_das_ctx().get_das_tablet_mapper(table_id, tablet_mapper, + &loc_meta_.related_table_ids_))); + if (OB_UNLIKELY(is_virtual_table(table_id))) { + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "Calculate virtual table partition id with rowkey"); + } else if (!is_partitioned_) { + ObObjectID object_id = 0; + ObTabletID tablet_id; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(sql_schema_guard.get_table_schema(table_id, table_schema))) { + LOG_WARN("fail to get table schema", K(table_id), KR(ret)); + } else if (OB_FAIL(table_schema->get_tablet_and_object_id(tablet_id, object_id))) { + LOG_WARN("fail to get tablet and object", KR(ret)); + } + if (OB_SUCC(ret)) { + for (int64_t i = 0; OB_SUCC(ret) && i < part_rows.count(); i ++) { + if (OB_FAIL(tablet_ids.push_back(tablet_id))) { + LOG_WARN("fail to push tablet id", KR(ret)); + } else if (OB_FAIL(part_ids.push_back(object_id))) { + LOG_WARN("fail to push object id", KR(ret)); + } + } + } + } else {//TODO: copied from calc_partition_ids_by_rowkey() + ObSEArray tmp_part_ids; + ObSEArray tmp_tablet_ids; + for (int64_t i = 0; OB_SUCC(ret) && i < part_rows.count(); ++i) { + tmp_part_ids.reset(); + tmp_tablet_ids.reset(); //must reset + ObNewRow &part_row = part_rows.at(i); + if (PARTITION_LEVEL_ONE == part_level_) { + if (OB_FAIL(calc_partition_id_by_row(exec_ctx, tablet_mapper, part_row, tmp_tablet_ids, tmp_part_ids))) { + LOG_WARN("calc partition id by row failed", K(ret)); + } + } else { + ObSEArray tmp_part_ids2; + ObSEArray tmp_tablet_ids2; + if (OB_FAIL(calc_partition_id_by_row(exec_ctx, + tablet_mapper, + part_row, + tmp_tablet_ids2, + tmp_part_ids2))) { + LOG_WARN("calc partition id by row failed", K(ret)); + } else if (OB_FAIL(calc_partition_id_by_row(exec_ctx, + tablet_mapper, + part_row, + tmp_tablet_ids, + tmp_part_ids, + &tmp_part_ids2))) { + LOG_WARN("calc sub partition id by row failed", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_ids.push_back(tmp_tablet_ids.at(0)))) { + LOG_WARN("fail to push tablet id", KR(ret)); + } else if (OB_FAIL(part_ids.push_back(tmp_part_ids.at(0)))) { + LOG_WARN("fail to push object id", KR(ret)); + } + } + } + } + } + + return ret; +} + int ObTableLocation::calculate_partition_ids_by_rowkey(ObSQLSessionInfo &session_info, ObSchemaGetterGuard &schema_guard, uint64_t table_id, diff --git a/src/sql/optimizer/ob_table_location.h b/src/sql/optimizer/ob_table_location.h index f4c5680636..6b865d8e47 100644 --- a/src/sql/optimizer/ob_table_location.h +++ b/src/sql/optimizer/ob_table_location.h @@ -636,6 +636,18 @@ public: ObIArray &partition_ids, const ObDataTypeCastParams &dtc_params) const; + int init_partition_ids_by_rowkey2(ObExecContext &exec_ctx, + ObSQLSessionInfo &session_info, + ObSchemaGetterGuard &schema_guard, + uint64_t table_id); + + int calculate_partition_ids_by_rows2(ObSQLSessionInfo &session_info, + ObSchemaGetterGuard &schema_guard, + uint64_t table_id, + ObIArray &part_rows, + ObIArray &tablet_ids, + ObIArray &part_ids) const;//FIXME + int calculate_partition_ids_by_rowkey(ObSQLSessionInfo &session_info, share::schema::ObSchemaGetterGuard &schema_guard, uint64_t table_id, diff --git a/src/sql/parser/sql_parser_mysql_mode.l b/src/sql/parser/sql_parser_mysql_mode.l index b455013204..16a4f83aa5 100755 --- a/src/sql/parser/sql_parser_mysql_mode.l +++ b/src/sql/parser/sql_parser_mysql_mode.l @@ -244,6 +244,16 @@ TRUE { } } +TRUE { + check_value(yylval); + ParseResult *p = (ParseResult *)yyextra; + malloc_new_node(yylval->node, p->malloc_pool_, T_BOOL, 0); + yylval->node->value_ = 1; + COPY_STRING(p->input_sql_ + yylloc->first_column - 1, yyleng, yylval->node->raw_text_); + yylval->node->text_len_ = yyleng; + return BOOL_VALUE; +} + FALSE { check_value(yylval); ParseResult *p = (ParseResult *)yyextra; @@ -258,6 +268,16 @@ FALSE { } } +FALSE { + check_value(yylval); + ParseResult *p = (ParseResult *)yyextra; + malloc_new_node(yylval->node, p->malloc_pool_, T_BOOL, 0); + yylval->node->value_ = 0; + COPY_STRING(p->input_sql_ + yylloc->first_column - 1, yyleng, yylval->node->raw_text_); + yylval->node->text_len_ = yyleng; + return BOOL_VALUE; +} + {sqbegin} { BEGIN(sq); ParseResult *p = (ParseResult *)yyextra; @@ -935,6 +955,8 @@ Timestamp{whitespace}?\"[^\"]*\" { NO_USE_LATE_MATERIALIZATION { return NO_USE_LATE_MATERIALIZATION; } TRACE_LOG { return TRACE_LOG; } LOAD_BATCH_SIZE { return LOAD_BATCH_SIZE; } +DIRECT { return DIRECT; } +APPEND { return APPEND; } TRACING { return TRACING; } DOP { return DOP; } FORCE_REFRESH_LOCATION_CACHE { return FORCE_REFRESH_LOCATION_CACHE; } diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 5121c051d4..747eaad5f0 100755 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -180,6 +180,8 @@ USE_HASH_DISTINCT NO_USE_HASH_DISTINCT DISTINCT_PUSHDOWN NO_DISTINCT_PUSHDOWN USE_HASH_SET NO_USE_HASH_SET USE_DISTRIBUTED_DML NO_USE_DISTRIBUTED_DML +// direct load data hint +DIRECT // hint related to optimizer statistics APPEND NO_GATHER_OPTIMIZER_STATISTICS GATHER_OPTIMIZER_STATISTICS // other @@ -8411,6 +8413,14 @@ READ_CONSISTENCY '(' consistency_level ')' { malloc_non_terminal_node($$, result->malloc_pool_, T_LOAD_BATCH_SIZE, 1, $3); } +| DIRECT '(' BOOL_VALUE ',' INTNUM ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_DIRECT, 2, $3, $5); +} +| APPEND +{ + malloc_terminal_node($$, result->malloc_pool_, T_APPEND); +} | ENABLE_PARALLEL_DML { malloc_terminal_node($$, result->malloc_pool_, T_ENABLE_PARALLEL_DML); @@ -8427,10 +8437,6 @@ READ_CONSISTENCY '(' consistency_level ')' { malloc_terminal_node($$, result->malloc_pool_, T_NO_COST_BASED_QUERY_TRANSFORMATION); } -| APPEND -{ - malloc_terminal_node($$, result->malloc_pool_, T_APPEND); -} | NO_GATHER_OPTIMIZER_STATISTICS { malloc_terminal_node($$, result->malloc_pool_, T_NO_GATHER_OPTIMIZER_STATISTICS); diff --git a/src/sql/resolver/cmd/ob_load_data_resolver.cpp b/src/sql/resolver/cmd/ob_load_data_resolver.cpp index 7a8ad57866..cf7b128ba7 100644 --- a/src/sql/resolver/cmd/ob_load_data_resolver.cpp +++ b/src/sql/resolver/cmd/ob_load_data_resolver.cpp @@ -116,26 +116,50 @@ int ObLoadDataResolver::resolve(const ParseNode &parse_tree) } else { ObString file_name(file_name_node->str_len_, file_name_node->str_value_); if (ObLoadFileLocation::OSS != load_args.load_file_storage_) { + load_args.file_name_ = file_name; + const char *p = nullptr; + ObString sub_file_name; + ObString cstyle_file_name; // ends with '\0' char *full_path_buf = nullptr; char *actual_path = nullptr; - if (OB_FAIL(ob_write_string(*allocator_, file_name, load_args.file_name_, true))) { - LOG_WARN("fail to write string", K(ret)); - } else if (OB_ISNULL(full_path_buf = static_cast(allocator_->alloc(DEFAULT_BUF_LENGTH)))) { + if (OB_ISNULL(full_path_buf = static_cast(allocator_->alloc(MAX_PATH_SIZE)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate memory", K(ret)); - } else if (OB_ISNULL(actual_path = realpath(file_name_node->str_value_, full_path_buf))) { - ret = OB_FILE_NOT_EXIST; - LOG_WARN("file not exist", K(ret), K(file_name)); - } else { - load_args.full_file_path_ = actual_path; } - //security check for mysql mode - if (OB_SUCC(ret) && lib::is_mysql_mode()) { - ObString secure_file_priv; - if (OB_FAIL(session_info_->get_secure_file_priv(secure_file_priv))) { - LOG_WARN("failed to get secure file priv", K(ret)); - } else if (OB_FAIL(ObResolverUtils::check_secure_path(secure_file_priv, load_args.full_file_path_))) { - LOG_WARN("failed to check secure path", K(ret), K(secure_file_priv), K(load_args)); + while (OB_SUCC(ret) && !file_name.empty()) { + p = file_name.find(','); + if (nullptr == p) { + sub_file_name = file_name; + cstyle_file_name = sub_file_name; + file_name.reset(); + } else { + sub_file_name = file_name.split_on(p); + cstyle_file_name.reset(); + } + if (!sub_file_name.empty()) { + if (cstyle_file_name.empty() && + OB_FAIL(ob_write_string(*allocator_, sub_file_name, cstyle_file_name, true))) { + LOG_WARN("fail to write string", KR(ret)); + } else if (OB_ISNULL(actual_path = realpath(cstyle_file_name.ptr(), full_path_buf))) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("file not exist", K(ret), K(cstyle_file_name)); + } + //security check for mysql mode + if (OB_SUCC(ret) && lib::is_mysql_mode()) { + ObString secure_file_priv; + if (OB_FAIL(session_info_->get_secure_file_priv(secure_file_priv))) { + LOG_WARN("failed to get secure file priv", K(ret)); + } else if (OB_FAIL( + ObResolverUtils::check_secure_path(secure_file_priv, actual_path))) { + LOG_WARN("failed to check secure path", K(ret), K(secure_file_priv), + K(actual_path)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(load_args.file_iter_.add_files(&cstyle_file_name))) { + LOG_WARN("fail to add files", KR(ret)); + } + } } } } else { @@ -150,6 +174,8 @@ int ObLoadDataResolver::resolve(const ParseNode &parse_tree) LOG_USER_ERROR(OB_INVALID_ARGUMENT, "file name or access key"); } else if (OB_FAIL(load_args.access_info_.set(load_args.file_name_.ptr(), storage_info.ptr()))) { LOG_WARN("failed to set access info", K(ret)); + } else if (OB_FAIL(load_args.file_iter_.add_files(&load_args.file_name_))) { + LOG_WARN("fail to add files", KR(ret)); } } } @@ -419,7 +445,28 @@ int ObLoadDataResolver::resolve_hints(const ParseNode &node) LOG_DEBUG("LOAD DATA resolve hint node", "type", hint_node->type_); switch (hint_node->type_) { - + case T_DIRECT: { + if (hint_node->num_child_ != 2) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected hint node", K(ret), K(hint_node->num_child_)); + } else { + int64_t need_sort = hint_node->children_[0]->value_; + int64_t error_rows_value = hint_node->children_[1]->value_; + if (error_rows_value < 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid error rows value", K(ret), K(error_rows_value)); + } else if (OB_FAIL(stmt_hints.set_value( + ObLoadDataHint::ENABLE_DIRECT, 1))) { + LOG_WARN("fail to enable direct", K(ret)); + } else if (OB_FAIL(stmt_hints.set_value( + ObLoadDataHint::NEED_SORT, need_sort))) { + LOG_WARN("fail to enable sort", K(ret)); + } else if (OB_FAIL(stmt_hints.set_value(ObLoadDataHint::ERROR_ROWS, error_rows_value))) { + LOG_WARN("fail to set error rows", K(ret), K(error_rows_value)); + } + } + break; + } case T_QUERY_TIMEOUT: { int64_t timeout_value = hint_node->children_[0]->value_; if (timeout_value > OB_MAX_USER_SPECIFIED_TIMEOUT) { diff --git a/src/sql/resolver/cmd/ob_load_data_stmt.cpp b/src/sql/resolver/cmd/ob_load_data_stmt.cpp index 87585803d3..c273b5c923 100644 --- a/src/sql/resolver/cmd/ob_load_data_stmt.cpp +++ b/src/sql/resolver/cmd/ob_load_data_stmt.cpp @@ -27,6 +27,51 @@ const int64_t ObDataInFileStruct::DEFAULT_FIELD_ESCAPED_CHAR = static_cast= files_.count()) { + ret = OB_ITER_END; + } else { + file = files_.at(pos_++); + } + return ret; +} + +int ObLoadFileIterator::copy(const ObLoadFileIterator &other) +{ + int ret = OB_SUCCESS; + if (!other.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("get invalid argument", K(ret), K(other)); + } else if (OB_FAIL(files_.assign(other.files_))) { + LOG_WARN("fail to copy array", K(ret)); + } + return ret; +} + int ObLoadDataStmt::add_column_item(ColumnItem &item) { int ret = OB_SUCCESS; if (OB_FAIL(column_items_.push_back(item))) { diff --git a/src/sql/resolver/cmd/ob_load_data_stmt.h b/src/sql/resolver/cmd/ob_load_data_stmt.h index 2538f62b6a..f2fcf16d4d 100644 --- a/src/sql/resolver/cmd/ob_load_data_stmt.h +++ b/src/sql/resolver/cmd/ob_load_data_stmt.h @@ -34,6 +34,22 @@ enum class ObLoadFileLocation { OSS, }; +class ObLoadFileIterator +{ +public: + ObLoadFileIterator() : pos_(0) {} + void reset(); + bool is_valid() const { return !files_.empty(); } + int64_t count() const { return files_.count(); } + int add_files(common::ObString *start, const int64_t count = 1); + int get_next_file(common::ObString &file); + int copy(const ObLoadFileIterator &other); + TO_STRING_KV(K_(files), K_(pos)); +private: + common::ObSEArray files_; + int64_t pos_; +}; + struct ObLoadArgument { ObLoadArgument(): load_file_storage_(ObLoadFileLocation::SERVER_DISK), @@ -63,7 +79,7 @@ struct ObLoadArgument K_(database_id), K_(table_id), K_(is_csv_format), - K_(full_file_path)); + K_(file_iter)); void assign(const ObLoadArgument &other) { load_file_storage_ = other.load_file_storage_; @@ -80,8 +96,8 @@ struct ObLoadArgument database_id_ = other.database_id_; table_id_ = other.table_id_; is_csv_format_ = other.is_csv_format_; - full_file_path_ = other.full_file_path_; part_level_ = other.part_level_; + file_iter_.copy(other.file_iter_); } ObLoadFileLocation load_file_storage_; @@ -98,8 +114,8 @@ struct ObLoadArgument uint64_t database_id_; uint64_t table_id_; // physical table id bool is_csv_format_; - common::ObString full_file_path_; share::schema::ObPartitionLevel part_level_; + ObLoadFileIterator file_iter_; }; struct ObDataInFileStruct @@ -164,6 +180,9 @@ public: PARALLEL_THREADS = 0, //parallel threads on the host server, for parsing and calc partition BATCH_SIZE, QUERY_TIMEOUT, + ENABLE_DIRECT, + NEED_SORT, + ERROR_ROWS, TOTAL_INT_ITEM }; enum StringHintItem { diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 09dda8baf3..eaef9b84fb 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -11615,6 +11615,7 @@ int ObDMLResolver::resolve_global_hint(const ParseNode &hint_node, case T_APPEND: { CHECK_HINT_PARAM(hint_node, 0) { global_hint.merge_osg_hint(ObOptimizerStatisticsGatheringHint::OB_APPEND_HINT); + global_hint.set_append(true); } break; } diff --git a/src/sql/resolver/dml/ob_hint.cpp b/src/sql/resolver/dml/ob_hint.cpp index 4fc35fd7f4..9dd1798029 100755 --- a/src/sql/resolver/dml/ob_hint.cpp +++ b/src/sql/resolver/dml/ob_hint.cpp @@ -284,6 +284,7 @@ void ObGlobalHint::reset() disable_cost_based_transform_ = false; opt_params_.reset(); ob_ddl_schema_versions_.reuse(); + enable_append_ = false; osg_hint_.flags_ = 0; } @@ -307,6 +308,7 @@ int ObGlobalHint::merge_global_hint(const ObGlobalHint &other) merge_opt_features_version_hint(other.opt_features_version_); disable_transform_ |= other.disable_transform_; disable_cost_based_transform_ |= other.disable_cost_based_transform_; + enable_append_ |= other.enable_append_; osg_hint_.flags_ |= other.osg_hint_.flags_; if (OB_FAIL(merge_monitor_hints(other.monitoring_ids_))) { LOG_WARN("failed to merge monitor hints", K(ret)); @@ -458,6 +460,9 @@ int ObGlobalHint::print_global_hint(PlanText &plan_text) const if (OB_SUCC(ret) && disable_cost_based_transform()) { PRINT_GLOBAL_HINT_STR("NO_COST_BASED_QUERY_TRANSFORMATION"); } + if (OB_SUCC(ret) && has_append()) { // APPEND + PRINT_GLOBAL_HINT_STR("APPEND"); + } if (OB_SUCC(ret) && OB_FAIL(opt_params_.print_opt_param_hint(plan_text))) { LOG_WARN("failed to print opt param hint", K(ret)); } diff --git a/src/sql/resolver/dml/ob_hint.h b/src/sql/resolver/dml/ob_hint.h index 7f2b900871..5d33e53c3b 100644 --- a/src/sql/resolver/dml/ob_hint.h +++ b/src/sql/resolver/dml/ob_hint.h @@ -158,6 +158,12 @@ struct ObGlobalHint { { return MIN_OUTLINE_ENABLE_VERSION <= version && CLUSTER_CURRENT_VERSION >= version; } bool disable_query_transform() const { return disable_transform_; } bool disable_cost_based_transform() const { return disable_cost_based_transform_; } + bool has_append() const { return enable_append_; } + void set_append(const bool enable_append) + { + enable_append_ = enable_append; + } + // wether should generate optimizer_statistics_operator. bool should_generate_osg_operator () const { @@ -197,6 +203,7 @@ struct ObGlobalHint { K_(opt_features_version), K_(disable_transform), K_(disable_cost_based_transform), + K_(enable_append), K_(opt_params), K_(ob_ddl_schema_versions), K_(osg_hint)); @@ -220,6 +227,7 @@ struct ObGlobalHint { uint64_t opt_features_version_; bool disable_transform_; bool disable_cost_based_transform_; + bool enable_append_; ObOptParamHint opt_params_; common::ObSArray ob_ddl_schema_versions_; ObOptimizerStatisticsGatheringHint osg_hint_; diff --git a/src/sql/resolver/dml/ob_insert_resolver.cpp b/src/sql/resolver/dml/ob_insert_resolver.cpp index fa5904c6cc..ab325c4b6b 100644 --- a/src/sql/resolver/dml/ob_insert_resolver.cpp +++ b/src/sql/resolver/dml/ob_insert_resolver.cpp @@ -113,6 +113,16 @@ int ObInsertResolver::resolve(const ParseNode &parse_tree) if (OB_SUCC(ret)) { if (OB_FAIL(resolve_hints(parse_tree.children_[HINT_NODE]))) { LOG_WARN("failed to resolve hints", K(ret)); + } else if ((stmt::T_INSERT == insert_stmt->stmt_type_) + && insert_stmt->value_from_select() + && GCONF._ob_enable_direct_load) { + ObQueryCtx *query_ctx = insert_stmt->get_query_ctx(); + if (OB_ISNULL(query_ctx)) { + LOG_WARN("query ctx should not be NULL", KR(ret), KP(query_ctx)); + } else if (query_ctx->get_query_hint().get_global_hint().has_append()) { + // For insert into select clause with direct-insert mode, plan cache is disabled + query_ctx->get_query_hint_for_update().global_hint_.merge_plan_cache_hint(OB_USE_PLAN_CACHE_NONE); + } } } diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt index 056eba0e9b..07b5690ef9 100644 --- a/src/storage/CMakeLists.txt +++ b/src/storage/CMakeLists.txt @@ -379,6 +379,8 @@ ob_set_subtarget(ob_storage ddl ddl/ob_direct_insert_sstable_ctx.cpp ddl/ob_tablet_barrier_log.cpp ddl/ob_tablet_ddl_kv_mgr.cpp + ddl/ob_ddl_heart_beat_task.cpp + ddl/ob_ddl_server_client.cpp ) ob_set_subtarget(ob_storage common @@ -505,6 +507,75 @@ ob_set_subtarget(ob_storage tablelock tablelock/ob_table_lock_rpc_client.cpp ) +ob_set_subtarget(ob_storage direct_load + direct_load/ob_direct_load_compare.cpp + direct_load/ob_direct_load_data_block.cpp + direct_load/ob_direct_load_data_fuse.cpp + direct_load/ob_direct_load_datum.cpp + direct_load/ob_direct_load_external_fragment.cpp + direct_load/ob_direct_load_external_multi_partition_row.cpp + direct_load/ob_direct_load_external_multi_partition_table.cpp + direct_load/ob_direct_load_external_row.cpp + direct_load/ob_direct_load_external_table.cpp + direct_load/ob_direct_load_external_table_builder.cpp + direct_load/ob_direct_load_external_table_compactor.cpp + direct_load/ob_direct_load_fast_heap_table.cpp + direct_load/ob_direct_load_fast_heap_table_builder.cpp + direct_load/ob_direct_load_fast_heap_table_ctx.cpp + direct_load/ob_direct_load_insert_table_ctx.cpp + direct_load/ob_direct_load_io_callback.cpp + direct_load/ob_direct_load_merge_ctx.cpp + direct_load/ob_direct_load_merge_task_iterator.cpp + direct_load/ob_direct_load_multiple_datum_range.cpp + direct_load/ob_direct_load_multiple_datum_row.cpp + direct_load/ob_direct_load_multiple_datum_rowkey.cpp + direct_load/ob_direct_load_multiple_external_row.cpp + direct_load/ob_direct_load_multiple_heap_table.cpp + direct_load/ob_direct_load_multiple_heap_table_builder.cpp + direct_load/ob_direct_load_multiple_heap_table_compactor.cpp + direct_load/ob_direct_load_multiple_heap_table_index_block.cpp + direct_load/ob_direct_load_multiple_heap_table_index_block_reader.cpp + direct_load/ob_direct_load_multiple_heap_table_index_block_writer.cpp + direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.cpp + direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.cpp + direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.cpp + direct_load/ob_direct_load_multiple_heap_table_index_scanner.cpp + direct_load/ob_direct_load_multiple_heap_table_scanner.cpp + direct_load/ob_direct_load_multiple_sstable.cpp + direct_load/ob_direct_load_multiple_sstable_builder.cpp + direct_load/ob_direct_load_multiple_sstable_compactor.cpp + direct_load/ob_direct_load_multiple_sstable_data_block_scanner.cpp + direct_load/ob_direct_load_multiple_sstable_index_block_compare.cpp + direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.cpp + direct_load/ob_direct_load_multiple_sstable_index_entry_compare.cpp + direct_load/ob_direct_load_multiple_sstable_scan_merge.cpp + direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.cpp + direct_load/ob_direct_load_multiple_sstable_scanner.cpp + direct_load/ob_direct_load_origin_table.cpp + direct_load/ob_direct_load_partition_merge_task.cpp + direct_load/ob_direct_load_range_splitter.cpp + direct_load/ob_direct_load_rowkey_iterator.cpp + direct_load/ob_direct_load_sstable_builder.cpp + direct_load/ob_direct_load_sstable.cpp + direct_load/ob_direct_load_sstable_compactor.cpp + direct_load/ob_direct_load_sstable_data_block.cpp + direct_load/ob_direct_load_sstable_index_block.cpp + direct_load/ob_direct_load_sstable_index_block_writer.cpp + direct_load/ob_direct_load_sstable_index_block_reader.cpp + direct_load/ob_direct_load_sstable_scan_merge.cpp + direct_load/ob_direct_load_sstable_scan_merge_loser_tree.cpp + direct_load/ob_direct_load_sstable_scanner.cpp + direct_load/ob_direct_load_table_data_desc.cpp + direct_load/ob_direct_load_table_store.cpp + direct_load/ob_direct_load_tmp_file.cpp + direct_load/ob_direct_load_mem_dump.cpp + direct_load/ob_direct_load_mem_loader.cpp + direct_load/ob_direct_load_mem_sample.cpp + direct_load/ob_direct_load_mem_context.cpp + direct_load/ob_direct_load_multiple_heap_table_map.cpp + direct_load/ob_direct_load_multiple_heap_table_sorter.cpp +) + ob_set_subtarget(ob_storage lob lob/ob_lob_meta.cpp lob/ob_lob_manager.cpp diff --git a/src/storage/access/ob_dml_param.h b/src/storage/access/ob_dml_param.h index 3ce744b4f8..31bdc605a0 100644 --- a/src/storage/access/ob_dml_param.h +++ b/src/storage/access/ob_dml_param.h @@ -21,6 +21,7 @@ #include "sql/engine/basic/ob_pushdown_filter.h" #include "storage/tx/ob_clog_encrypt_info.h" #include "storage/tx/ob_trans_define_v4.h" +#include "sql/resolver/dml/ob_hint.h" namespace oceanbase { @@ -182,6 +183,7 @@ struct ObDMLBaseParam encrypt_meta_legacy_(), spec_seq_no_(-1), snapshot_(), + direct_insert_task_id_(0), write_flag_() { } @@ -210,9 +212,11 @@ struct ObDMLBaseParam int64_t spec_seq_no_; // transaction snapshot transaction::ObTxReadSnapshot snapshot_; + int64_t direct_insert_task_id_; // 0 means no direct insert // write flag for inner write processing concurrent_control::ObWriteFlag write_flag_; bool is_valid() const { return (timeout_ > 0 && schema_version_ >= 0); } + bool is_direct_insert() const { return (direct_insert_task_id_ > 0); } DECLARE_TO_STRING; }; diff --git a/src/storage/access/ob_multiple_merge.cpp b/src/storage/access/ob_multiple_merge.cpp index 2293dcca5c..834aede7bf 100644 --- a/src/storage/access/ob_multiple_merge.cpp +++ b/src/storage/access/ob_multiple_merge.cpp @@ -1145,15 +1145,10 @@ int ObMultipleMerge::prepare_tables_from_iterator(ObTableStoreIterator &table_it } } if (OB_SUCC(ret) && need_table) { - if (table_ptr->is_sstable()) { - if (static_cast(table_ptr)->get_meta().is_empty()) { - LOG_DEBUG("cur sstable is empty", K(ret), K(*table_ptr)); - continue; - } - } else if (static_cast(table_ptr)->is_empty()) { - LOG_DEBUG("cur memtable is empty", K(ret), K(*table_ptr)); + if (table_ptr->is_empty()) { + LOG_DEBUG("cur table is empty", K(ret), KPC(table_ptr)); continue; - } else { + } else if (table_ptr->is_memtable()) { ++memtable_cnt; } if (OB_FAIL(tables_.push_back(table_ptr))) { diff --git a/src/storage/access/ob_sstable_row_whole_scanner.cpp b/src/storage/access/ob_sstable_row_whole_scanner.cpp index 85a6f9bb69..d724d1507c 100644 --- a/src/storage/access/ob_sstable_row_whole_scanner.cpp +++ b/src/storage/access/ob_sstable_row_whole_scanner.cpp @@ -256,6 +256,7 @@ int ObSSTableRowWholeScanner::open( read_info.offset_ = sstable_->get_macro_offset(); read_info.size_ = sstable_->get_macro_read_size(); read_info.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_COMPACT_READ); + read_info.io_callback_ = access_ctx_->io_callback_; if (OB_FAIL(ObBlockManager::async_read_block(read_info, scan_handle.macro_io_handle_))) { LOG_WARN("Fail to read macro block", K(ret), K(read_info)); } else { @@ -365,6 +366,7 @@ int ObSSTableRowWholeScanner::prefetch() read_info.offset_ = sstable_->get_macro_offset(); read_info.size_ = sstable_->get_macro_read_size(); read_info.io_desc_.set_wait_event(common::ObWaitEventIds::DB_FILE_COMPACT_READ); + read_info.io_callback_ = access_ctx_->io_callback_; if (OB_FAIL(ObBlockManager::async_read_block(read_info, scan_handle.macro_io_handle_))) { LOG_WARN("Fail to read macro block, ", K(ret), K(read_info)); } else { diff --git a/src/storage/access/ob_table_access_context.cpp b/src/storage/access/ob_table_access_context.cpp index 8100f70f8c..1de756506b 100644 --- a/src/storage/access/ob_table_access_context.cpp +++ b/src/storage/access/ob_table_access_context.cpp @@ -70,7 +70,8 @@ ObTableAccessContext::ObTableAccessContext() merge_scn_(), lob_locator_helper_(nullptr), iter_pool_(nullptr), - block_row_store_(nullptr) + block_row_store_(nullptr), + io_callback_(nullptr) { merge_scn_.set_max(); } diff --git a/src/storage/access/ob_table_access_context.h b/src/storage/access/ob_table_access_context.h index f1a852aa55..18cac10a59 100644 --- a/src/storage/access/ob_table_access_context.h +++ b/src/storage/access/ob_table_access_context.h @@ -20,6 +20,10 @@ namespace oceanbase { +namespace common +{ +class ObIOCallback; +} // namespace common namespace storage { class ObStoreRowIterPool; @@ -117,7 +121,8 @@ struct ObTableAccessContext K_(merge_scn), K_(lob_locator_helper), KP_(iter_pool), - KP_(block_row_store)); + KP_(block_row_store), + KP_(io_callback)) private: static const int64_t DEFAULT_COLUMN_SCALE_INFO_SIZE = 8; int build_lob_locator_helper(ObTableScanParam &scan_param, const common::ObVersionRange &trans_version_range); @@ -151,6 +156,7 @@ public: ObLobLocatorHelper *lob_locator_helper_; ObStoreRowIterPool *iter_pool_; ObBlockRowStore *block_row_store_; + common::ObIOCallback *io_callback_; #ifdef ENABLE_DEBUG_LOG transaction::ObDefensiveCheckRecordExtend defensive_check_record_; #endif diff --git a/src/storage/blocksstable/ob_sstable.h b/src/storage/blocksstable/ob_sstable.h index a3685476a3..08369657d9 100644 --- a/src/storage/blocksstable/ob_sstable.h +++ b/src/storage/blocksstable/ob_sstable.h @@ -158,6 +158,10 @@ public: const ObTableReadInfo &index_read_info, common::ObIAllocator &allocator, common::ObStoreRowkey &endkey); + bool is_empty() const override + { + return meta_.is_empty(); + } public: int dump2text( diff --git a/src/storage/blocksstable/ob_tmp_file.cpp b/src/storage/blocksstable/ob_tmp_file.cpp index 26811d6138..659b8a0162 100644 --- a/src/storage/blocksstable/ob_tmp_file.cpp +++ b/src/storage/blocksstable/ob_tmp_file.cpp @@ -48,20 +48,20 @@ bool ObTmpFileIOInfo::is_valid() const } ObTmpFileIOHandle::ObTmpFileIOHandle() - : io_handles_(), - page_cache_handles_(), - block_cache_handles_(), + : is_read_(false), + has_wait_(false), + update_offset_in_file_(false), fd_(OB_INVALID_FD), dir_id_(OB_INVALID_ID), - tenant_id_(OB_INVALID_TENANT_ID), - buf_(NULL), size_(0), - is_read_(false), - has_wait_(false), expect_read_size_(0), last_read_offset_(-1), + tenant_id_(OB_INVALID_TENANT_ID), + buf_(NULL), io_flag_(), - update_offset_in_file_(false) + io_handles_(), + page_cache_handles_(), + block_cache_handles_() { } @@ -78,7 +78,7 @@ int ObTmpFileIOHandle::prepare_read( ObTmpFile *file) { int ret = OB_SUCCESS; - if (NULL == read_buf || NULL == file) { + if (OB_ISNULL(read_buf) ||OB_ISNULL(file)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), KP_(buf)); } else { @@ -99,7 +99,7 @@ int ObTmpFileIOHandle::prepare_read( int ObTmpFileIOHandle::prepare_write(char *write_buf, const int64_t write_size, ObTmpFile *file) { int ret = OB_SUCCESS; - if (NULL == write_buf || NULL == file) { + if (OB_ISNULL(write_buf) || OB_ISNULL(file)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), KP_(buf)); } else { @@ -353,9 +353,17 @@ void ObTmpFileExtent::get_global_offset(int64_t &g_offset_start, int64_t &g_offs } ObTmpFileExtent::ObTmpFileExtent(ObTmpFile *file) - : is_alloced_(false), fd_(file->get_fd()), g_offset_start_(0), g_offset_end_(0), - owner_(file), start_page_id_(-1), page_nums_(0), block_id_(-1), offset_(0), - lock_(common::ObLatchIds::TMP_FILE_EXTENT_LOCK), is_closed_(false) + : is_alloced_(false), + is_closed_(false), + start_page_id_(-1), + page_nums_(0), + offset_(0), + fd_(file->get_fd()), + g_offset_start_(0), + g_offset_end_(0), + owner_(file), + block_id_(-1), + lock_(common::ObLatchIds::TMP_FILE_EXTENT_LOCK) { } @@ -370,8 +378,8 @@ int ObTmpFileExtent::read(const ObTmpFileIOInfo &io_info, const int64_t offset, if (OB_UNLIKELY(!is_alloced_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "ObTmpFileExtent has not been allocated", K(ret)); - } else if (offset < 0 || offset >= offset_ || size <= 0 - || offset + size > offset_ || NULL == buf) { + } else if (OB_UNLIKELY(offset < 0 || offset >= offset_ || size <= 0 + || offset + size > offset_) || OB_ISNULL(buf)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(offset), K(offset_), K(size), K(buf)); } else { @@ -397,7 +405,7 @@ int ObTmpFileExtent::write(const ObTmpFileIOInfo &io_info,int64_t &size, char *& int write_size = 0; int64_t remain = 0; bool is_write = false; - if (size <= 0 || NULL == buf) { + if (OB_UNLIKELY(size <= 0) || OB_ISNULL(buf)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret)); } else if (OB_UNLIKELY(!is_alloced_)) { @@ -459,13 +467,14 @@ bool ObTmpFileExtent::is_valid() bool ObTmpFileExtent::close(bool force) { int ret = OB_SUCCESS; - int32_t page_start_id = -1; - int32_t page_nums = 0; + uint8_t page_start_id = ObTmpFilePageBuddy::MAX_PAGE_NUMS; + uint8_t page_nums = 0; if (!is_closed_) { if (close(page_start_id, page_nums, force)) { - if (-1 == page_start_id && 0 == page_nums) { + if (ObTmpFilePageBuddy::MAX_PAGE_NUMS == page_start_id && 0 == page_nums) { //nothing to do - } else if (page_start_id < 0 || page_nums < 0) { + } else if (OB_UNLIKELY(page_start_id > ObTmpFilePageBuddy::MAX_PAGE_NUMS - 1 + || page_nums > ObTmpFilePageBuddy::MAX_PAGE_NUMS)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "fail to close the extent", K(ret), K_(block_id), K(page_start_id), K(page_nums), K_(offset)); @@ -481,9 +490,9 @@ bool ObTmpFileExtent::close(bool force) return is_closed_; } -bool ObTmpFileExtent::close(int32_t &free_page_start_id, int32_t &free_page_nums, bool force) +bool ObTmpFileExtent::close(uint8_t &free_page_start_id, uint8_t &free_page_nums, bool force) { - free_page_start_id = -1; + free_page_start_id = ObTmpFilePageBuddy::MAX_PAGE_NUMS; free_page_nums = 0; SpinWLockGuard guard(lock_); if (!is_closed_) { @@ -491,7 +500,7 @@ bool ObTmpFileExtent::close(int32_t &free_page_start_id, int32_t &free_page_nums // Nothing to do. This extent is alloced just now, so it cannot be closed. } else { if (offset_ != page_nums_ * ObTmpMacroBlock::get_default_page_size()) { - int32_t offset_page_id = common::upper_align(offset_, ObTmpMacroBlock::get_default_page_size()) + uint8_t offset_page_id = common::upper_align(offset_, ObTmpMacroBlock::get_default_page_size()) / ObTmpMacroBlock::get_default_page_size(); free_page_nums = page_nums_ - offset_page_id; free_page_start_id = start_page_id_ + offset_page_id; @@ -520,7 +529,7 @@ ObTmpFileMeta::~ObTmpFileMeta() int ObTmpFileMeta::init(const int64_t fd, const int64_t dir_id, common::ObIAllocator *allocator) { int ret = OB_SUCCESS; - if (fd < 0 || dir_id < 0 || NULL == allocator) { + if (OB_UNLIKELY(fd < 0 || dir_id < 0) || OB_ISNULL(allocator)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(fd), K(dir_id)); } else { @@ -580,17 +589,17 @@ int ObTmpFileMeta::clear() } ObTmpFile::ObTmpFile() - : file_meta_(), + : is_inited_(false), is_big_(false), - tenant_id_(-1), - offset_(0), - allocator_(NULL), last_extent_id_(0), last_extent_min_offset_(0), last_extent_max_offset_(INT64_MAX), + offset_(0), + tenant_id_(-1), extent_idx_lock_(common::ObLatchIds::TMP_FILE_LOCK), lock_(common::ObLatchIds::TMP_FILE_LOCK), - is_inited_(false) + allocator_(NULL), + file_meta_() { } @@ -622,7 +631,7 @@ int ObTmpFile::clear() int ObTmpFile::init(const int64_t fd, const int64_t dir_id, common::ObIAllocator &allocator) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else if (fd < 0) { @@ -719,7 +728,7 @@ int ObTmpFile::once_aio_read_batch( const int64_t remain_size = io_info.size_ - handle.get_data_size(); SpinWLockGuard guard(lock_); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been initialized", K(ret)); } else if (OB_UNLIKELY(offset < 0 || remain_size < 0) || OB_ISNULL(io_info.buf_)) { @@ -794,7 +803,7 @@ int ObTmpFile::once_aio_read_batch_without_lock( int ObTmpFile::aio_read(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandle &handle) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else { @@ -814,7 +823,7 @@ int ObTmpFile::aio_pread(const ObTmpFileIOInfo &io_info, const int64_t offset, ObTmpFileIOHandle &handle) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else { @@ -833,7 +842,7 @@ int ObTmpFile::seek(const int64_t offset, const int whence) { int ret = OB_SUCCESS; SpinWLockGuard guard(lock_); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else { @@ -878,7 +887,7 @@ int ObTmpFile::pread(const ObTmpFileIOInfo &io_info, const int64_t offset, const ObTmpFileIOHandle &handle) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else if (OB_FAIL(aio_pread(io_info, offset, handle))) { @@ -903,7 +912,7 @@ int ObTmpFile::aio_write(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandle &hand { // only support append at present. int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -943,8 +952,8 @@ int ObTmpFile::aio_write(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandle &hand } else { alloc_size = common::upper_align(size, big_file_prealloc_size()); } - } else if (size > OB_TMP_FILE_STORE.get_block_size()) { - alloc_size = OB_TMP_FILE_STORE.get_block_size(); + } else if (size > ObTmpMacroBlock::get_block_size()) { + alloc_size = ObTmpMacroBlock::get_block_size(); } else { alloc_size = size; } @@ -1016,16 +1025,39 @@ int ObTmpFile::sync(const int64_t timeout_ms) int ret = OB_SUCCESS; SpinWLockGuard guard(lock_); ObTmpFileExtent *tmp = file_meta_.get_last_extent(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFile has not been inited", K(ret)); - } else if (NULL == tmp) { + } else if (OB_ISNULL(tmp)) { ret = OB_BAD_NULL_ERROR; - STORAGE_LOG(WARN, "the file does not have a extent", K(timeout_ms)); - } else if (tmp->is_closed()) { - STORAGE_LOG(INFO, "the file has been closed", K(timeout_ms)); + STORAGE_LOG(WARN, "the file does not have a extent", K(ret), K(timeout_ms)); } else { + // TODO : add timeout implementation tmp->close(true/*force*/); + // all extents has been closed. + const ObIArray &extents = file_meta_.get_extents(); + common::hash::ObHashSet blk_id_set; + if (OB_FAIL(blk_id_set.create(extents.count()))){ + STORAGE_LOG(WARN, "create block id set failed", K(ret), K(timeout_ms)); + } else { + // get extents block id set. + for (int64_t i=0; OB_SUCC(ret) && i < extents.count(); ++i) { + const ObTmpFileExtent* e = extents.at(i); + const int64_t &blk_id = e->get_block_id(); + if (OB_FAIL(blk_id_set. set_refactored(blk_id))) { + STORAGE_LOG(WARN, "add block id to set failed", K(ret), K(blk_id)); + } + } + + // iter all blocks, execute sync + common::hash::ObHashSet::const_iterator iter; + for (iter = blk_id_set.begin(); OB_SUCC(ret) && iter != blk_id_set.end(); ++iter) { + const int64_t &blk_id = iter->first; + if (OB_FAIL(OB_TMP_FILE_STORE.sync(tenant_id_, blk_id))) { + STORAGE_LOG(WARN, "sync block failed", K(ret), K(blk_id)); + } + } + } } return ret; } @@ -1068,7 +1100,7 @@ int ObTmpFile::write_file_extent(const ObTmpFileIOInfo &io_info, ObTmpFileExtent int64_t &size, char *&buf) { int ret = OB_SUCCESS; - if (NULL == file_extent || size <= 0 || NULL == buf) { + if (OB_UNLIKELY(size <= 0)|| OB_ISNULL(file_extent) || OB_ISNULL(buf)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret)); } else if (OB_FAIL(file_extent->write(io_info, size, buf))) { @@ -1131,7 +1163,7 @@ ObTmpFileManager &ObTmpFileManager::get_instance() int ObTmpFileManager::init() { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(files_.init(DEFAULT_BUCKET_NUM, OB_SERVER_TENANT_ID, @@ -1153,7 +1185,7 @@ int ObTmpFileManager::init() int ObTmpFileManager::alloc_dir(int64_t &dir) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(get_next_dir(dir))) { @@ -1189,7 +1221,7 @@ int ObTmpFileManager::open(int64_t &fd, int64_t &dir) { int ret = OB_SUCCESS; ObTmpFile file; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(get_next_fd(fd))) { @@ -1228,7 +1260,7 @@ int ObTmpFileManager::aio_read(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandle int ret = OB_SUCCESS; ObTmpFileHandle file_handle; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1250,7 +1282,7 @@ int ObTmpFileManager::aio_pread(const ObTmpFileIOInfo &io_info, const int64_t of int ret = OB_SUCCESS; ObTmpFileHandle file_handle; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1272,7 +1304,7 @@ int ObTmpFileManager::read(const ObTmpFileIOInfo &io_info, const int64_t timeout int ret = OB_SUCCESS; ObTmpFileHandle file_handle; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1294,7 +1326,7 @@ int ObTmpFileManager::pread(const ObTmpFileIOInfo &io_info, const int64_t offset int ret = OB_SUCCESS; ObTmpFileHandle file_handle; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1315,7 +1347,7 @@ int ObTmpFileManager::aio_write(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandl int ret = OB_SUCCESS; ObTmpFileHandle file_handle; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1333,7 +1365,7 @@ int ObTmpFileManager::write(const ObTmpFileIOInfo &io_info, const int64_t timeou { int ret = OB_SUCCESS; ObTmpFileHandle file_handle; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (!io_info.is_valid()) { @@ -1351,7 +1383,7 @@ int ObTmpFileManager::seek(const int64_t fd, const int64_t offset, const int whe { int ret = OB_SUCCESS; ObTmpFileHandle file_handle; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(files_.get(fd, file_handle))) { @@ -1377,7 +1409,7 @@ int ObTmpFileManager::get_tmp_file_handle(const int64_t fd, ObTmpFileHandle &han int ObTmpFileManager::remove(const int64_t fd) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else{ @@ -1405,11 +1437,11 @@ int ObTmpFileManager::remove_tenant_file(const uint64_t tenant_id) int ret = OB_SUCCESS; common::ObSEArray fd_list; RmTenantTmpFileOp rm_tenant_file_op(tenant_id, &fd_list); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id)) { - ret = common::OB_INVALID_ARGUMENT; + ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(tenant_id)); } else if (OB_FAIL(files_.foreach(rm_tenant_file_op))) { STORAGE_LOG(WARN, "fail to foreach files_", K(ret), K(tenant_id)); @@ -1435,7 +1467,7 @@ int ObTmpFileManager::remove_tenant_file(const uint64_t tenant_id) int ObTmpFileManager::get_all_tenant_id(common::ObIArray &tenant_ids) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(OB_TMP_FILE_STORE.get_all_tenant_id(tenant_ids))) { @@ -1448,7 +1480,7 @@ int ObTmpFileManager::sync(const int64_t fd, const int64_t timeout_ms) { int ret = OB_SUCCESS; ObTmpFileHandle file_handle; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(files_.get(fd, file_handle))) { @@ -1460,8 +1492,11 @@ int ObTmpFileManager::sync(const int64_t fd, const int64_t timeout_ms) } ObTmpFileManager::ObTmpFileManager() - : files_(), next_fd_(-1), next_dir_(-1), - rm_file_lock_(common::ObLatchIds::TMP_FILE_MGR_LOCK), is_inited_(false) + : is_inited_(false), + next_fd_(-1), + next_dir_(-1), + rm_file_lock_(common::ObLatchIds::TMP_FILE_MGR_LOCK), + files_() { } @@ -1482,7 +1517,7 @@ void ObTmpFileManager::destroy() int ObTmpFileManager::dec_handle_ref(ObTmpFileHandle &handle) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (OB_FAIL(files_.dec_handle_ref(handle.ptr_))) { @@ -1495,7 +1530,7 @@ int ObTmpFileManager::get_tmp_file_size(const int64_t fd, int64_t &file_size) { int ret = OB_SUCCESS; ObTmpFileHandle file_handle; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileManager has not been inited", K(ret)); } else if (fd < 0) { diff --git a/src/storage/blocksstable/ob_tmp_file.h b/src/storage/blocksstable/ob_tmp_file.h index 3c73011958..b47dc1c4d8 100644 --- a/src/storage/blocksstable/ob_tmp_file.h +++ b/src/storage/blocksstable/ob_tmp_file.h @@ -14,10 +14,10 @@ #define OCEANBASE_STORAGE_BLOCKSSTABLE_OB_TMP_FILE_H_ #include "lib/container/ob_se_array.h" -#include "storage/blocksstable/ob_macro_block_handle.h" -#include "storage/blocksstable/ob_block_manager.h" -#include "storage/blocksstable/ob_tmp_file_store.h" #include "storage/ob_resource_map.h" +#include "ob_macro_block_handle.h" +#include "ob_block_manager.h" +#include "ob_tmp_file_store.h" namespace oceanbase { @@ -27,11 +27,11 @@ namespace blocksstable class ObTmpFile; class ObTmpFileExtent; -struct ObTmpFileIOInfo +struct ObTmpFileIOInfo final { public: ObTmpFileIOInfo(); - virtual ~ObTmpFileIOInfo(); + ~ObTmpFileIOInfo(); void reset(); bool is_valid() const; TO_STRING_KV(K_(fd), K_(dir_id), K_(size), K_(tenant_id), KP_(buf), K_(io_desc)); @@ -43,14 +43,14 @@ public: common::ObIOFlag io_desc_; }; -class ObTmpFileIOHandle +class ObTmpFileIOHandle final { public: - struct ObIOReadHandle { + struct ObIOReadHandle final { ObIOReadHandle(); ObIOReadHandle(const ObMacroBlockHandle ¯o_handle, char *buf, const int64_t offset, const int64_t size); - virtual ~ObIOReadHandle(); + ~ObIOReadHandle(); ObIOReadHandle(const ObIOReadHandle &other); ObIOReadHandle &operator=(const ObIOReadHandle &other); TO_STRING_KV(K_(macro_handle), K_(offset), K_(size), KP_(buf)); @@ -60,11 +60,11 @@ public: int64_t size_; }; - struct ObPageCacheHandle { + struct ObPageCacheHandle final { ObPageCacheHandle(); ObPageCacheHandle(const ObTmpPageValueHandle &page_handle, char *buf, const int64_t offset, const int64_t size); - virtual ~ObPageCacheHandle(); + ~ObPageCacheHandle(); ObPageCacheHandle(const ObPageCacheHandle &other); ObPageCacheHandle &operator=(const ObPageCacheHandle &other); TO_STRING_KV(K_(page_handle), K_(offset), K_(size), KP_(buf)); @@ -74,11 +74,11 @@ public: int64_t size_; }; - struct ObBlockCacheHandle { + struct ObBlockCacheHandle final { ObBlockCacheHandle(); ObBlockCacheHandle(const ObTmpBlockValueHandle &block_handle, char *buf, const int64_t offset, const int64_t size); - virtual ~ObBlockCacheHandle(); + ~ObBlockCacheHandle(); ObBlockCacheHandle(const ObBlockCacheHandle &other); ObBlockCacheHandle &operator=(const ObBlockCacheHandle &other); TO_STRING_KV(K_(block_handle), K_(offset), K_(size), KP_(buf)); @@ -89,7 +89,7 @@ public: }; ObTmpFileIOHandle(); - virtual ~ObTmpFileIOHandle(); + ~ObTmpFileIOHandle(); OB_INLINE char *get_buffer() { return buf_; } OB_INLINE int64_t get_data_size() { return size_; } int prepare_read( @@ -130,36 +130,36 @@ private: int do_wait(const int64_t timeout_ms); private: + bool is_read_; + bool has_wait_; + bool update_offset_in_file_; + int64_t fd_; + int64_t dir_id_; + int64_t size_; //has read or to write size. + int64_t expect_read_size_; + int64_t last_read_offset_; // only for more than 8MB read. + uint64_t tenant_id_; + char *buf_; + common::ObIOFlag io_flag_; common::ObSEArray io_handles_; common::ObSEArray page_cache_handles_; common::ObSEArray block_cache_handles_; - int64_t fd_; - int64_t dir_id_; - uint64_t tenant_id_; - char *buf_; - int64_t size_; //has read or to write size. - bool is_read_; - bool has_wait_; - int64_t expect_read_size_; - int64_t last_read_offset_; // only for more than 8MB read. - common::ObIOFlag io_flag_; - bool update_offset_in_file_; DISALLOW_COPY_AND_ASSIGN(ObTmpFileIOHandle); }; -class ObTmpFileExtent +class ObTmpFileExtent final { public: explicit ObTmpFileExtent(ObTmpFile *file); - virtual ~ObTmpFileExtent(); - virtual int read(const ObTmpFileIOInfo &io_info, const int64_t offset, const int64_t size, + ~ObTmpFileExtent(); + int read(const ObTmpFileIOInfo &io_info, const int64_t offset, const int64_t size, char *buf, ObTmpFileIOHandle &handle); - virtual int write(const ObTmpFileIOInfo &io_info, int64_t &size, char *&buf); + int write(const ObTmpFileIOInfo &io_info, int64_t &size, char *&buf); void reset(); OB_INLINE bool is_closed() const { return is_closed_; } bool is_valid(); bool close(bool force = false); - bool close(int32_t &free_page_start_id, int32_t &free_page_nums, bool force = false); + bool close(uint8_t &free_page_start_id, uint8_t &free_page_nums, bool force = false); void unclose(const int32_t page_nums = -1); bool is_alloced() const { return is_alloced_; } OB_INLINE void set_global_offset(const int64_t g_offset_start, const int64_t g_offset_end); @@ -167,10 +167,10 @@ public: OB_INLINE int64_t get_global_end() const { return g_offset_end_; } OB_INLINE int64_t get_global_start() const { return g_offset_start_; } OB_INLINE void alloced() { is_alloced_ = true; } - OB_INLINE void set_start_page_id(const int32_t start_page_id) { start_page_id_ = start_page_id; } - OB_INLINE int32_t get_start_page_id() const { return start_page_id_; } - OB_INLINE void set_page_nums(const int32_t page_nums) { page_nums_ = page_nums; } - OB_INLINE int32_t get_page_nums() const { return page_nums_; } + OB_INLINE void set_start_page_id(const uint8_t start_page_id) { start_page_id_ = start_page_id; } + OB_INLINE uint8_t get_start_page_id() const { return start_page_id_; } + OB_INLINE void set_page_nums(const uint8_t page_nums) { page_nums_ = page_nums; } + OB_INLINE uint8_t get_page_nums() const { return page_nums_; } OB_INLINE void set_block_id(const int64_t block_id) { block_id_ = block_id; } OB_INLINE int64_t get_block_id() const { return block_id_; } OB_INLINE void set_offset(const int64_t offset) { offset_ = offset; } @@ -181,24 +181,24 @@ public: private: bool is_alloced_; + bool is_closed_; // only if close, this extent cannot be used. + uint8_t start_page_id_; + uint8_t page_nums_; + int32_t offset_; int64_t fd_; int64_t g_offset_start_; int64_t g_offset_end_; ObTmpFile *owner_; - int32_t start_page_id_; - int32_t page_nums_; int64_t block_id_; - int32_t offset_; common::SpinRWLock lock_; - bool is_closed_; // only if close, this extent cannot be used. DISALLOW_COPY_AND_ASSIGN(ObTmpFileExtent); }; -class ObTmpFileMeta +class ObTmpFileMeta final { public: explicit ObTmpFileMeta() : fd_(-1), dir_id_(-1), allocator_(NULL), extents_() {} - virtual ~ObTmpFileMeta(); + ~ObTmpFileMeta(); int clear(); int init(const int64_t fd, const int64_t dir_id, common::ObIAllocator *allocator); ObTmpFileExtent *get_last_extent(); @@ -219,7 +219,7 @@ private: DISALLOW_COPY_AND_ASSIGN(ObTmpFileMeta); }; -class ObTmpFile +class ObTmpFile final { public: enum FileWhence @@ -228,7 +228,7 @@ public: CUR_SEEK, }; ObTmpFile(); - virtual ~ObTmpFile(); + ~ObTmpFile(); int init(const int64_t fd, const int64_t dir_id, common::ObIAllocator &allocator); int aio_read(const ObTmpFileIOInfo &io_info, ObTmpFileIOHandle &handle); int aio_pread(const ObTmpFileIOInfo &io_info, const int64_t offset, ObTmpFileIOHandle &handle); @@ -282,33 +282,33 @@ private: static const int64_t BIG_FILE_PREALLOC_EXTENT_SIZE = 8; static const int64_t READ_SIZE_PER_BATCH = 8 * 1024 * 1024; // 8MB - ObTmpFileMeta file_meta_; + bool is_inited_; bool is_big_; - uint64_t tenant_id_; - int64_t offset_; // read offset - common::ObIAllocator *allocator_; int64_t last_extent_id_; int64_t last_extent_min_offset_; int64_t last_extent_max_offset_; + int64_t offset_; // read offset + uint64_t tenant_id_; common::SpinRWLock extent_idx_lock_; common::SpinRWLock lock_; - bool is_inited_; + common::ObIAllocator *allocator_; + ObTmpFileMeta file_meta_; DISALLOW_COPY_AND_ASSIGN(ObTmpFile); }; -class ObTmpFileHandle : public storage::ObResourceHandle +class ObTmpFileHandle final: public storage::ObResourceHandle { public: ObTmpFileHandle(); - virtual ~ObTmpFileHandle(); + ~ObTmpFileHandle(); virtual void reset() override; private: friend class ObTmpFileManager; DISALLOW_COPY_AND_ASSIGN(ObTmpFileHandle); }; -class ObTmpFileManager +class ObTmpFileManager final { public: static ObTmpFileManager &get_instance(); @@ -383,7 +383,7 @@ private: private: ObTmpFileManager(); - virtual ~ObTmpFileManager(); + ~ObTmpFileManager(); int get_next_dir(int64_t &next_dir); int get_next_fd(int64_t &next_fd); void next_value(int64_t ¤t_val, int64_t &next_val); @@ -394,11 +394,11 @@ private: static const int64_t TOTAL_LIMIT = 15 * 1024L * 1024L * 1024L; static const int64_t HOLD_LIMIT = 8 * 1024L * 1024L; static const int64_t BLOCK_SIZE = common::OB_MALLOC_NORMAL_BLOCK_SIZE; - storage::ObResourceMap files_; + bool is_inited_; int64_t next_fd_; int64_t next_dir_; common::SpinRWLock rm_file_lock_; - bool is_inited_; + storage::ObResourceMap files_; DISALLOW_COPY_AND_ASSIGN(ObTmpFileManager); }; diff --git a/src/storage/blocksstable/ob_tmp_file_cache.cpp b/src/storage/blocksstable/ob_tmp_file_cache.cpp index dbbfc303fa..dca0f218c6 100644 --- a/src/storage/blocksstable/ob_tmp_file_cache.cpp +++ b/src/storage/blocksstable/ob_tmp_file_cache.cpp @@ -69,7 +69,7 @@ int64_t ObTmpPageCacheKey::size() const int ObTmpPageCacheKey::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", K(ret)); } else if (OB_UNLIKELY(!is_valid())) { @@ -103,7 +103,7 @@ int64_t ObTmpPageCacheValue::size() const int ObTmpPageCacheValue::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(nullptr == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(buf), K(buf_len), "request_size", size()); @@ -241,7 +241,7 @@ int ObTmpPageCache::ObITmpPageIOCallback::alloc_io_buf( aligned_offset = 0; common::align_offset_size(offset_, buf_size_, aligned_offset, io_buf_size); io_buf_size_ = io_buf_size + DIO_READ_ALIGN_SIZE; - if (OB_UNLIKELY(NULL == allocator_)) { + if (OB_ISNULL(allocator_)) { ret = OB_INVALID_DATA; STORAGE_LOG(WARN, "Invalid data, the allocator is NULL, ", K(ret)); } else if (OB_UNLIKELY(NULL == (io_buf_ = (char*) (allocator_->alloc(io_buf_size_))))) { @@ -280,7 +280,7 @@ ObTmpPageCache::ObTmpPageIOCallback::~ObTmpPageIOCallback() int ObTmpPageCache::ObTmpPageIOCallback::inner_process(const bool is_success) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == cache_)) { + if (OB_ISNULL(cache_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Invalid tmp page cache callback, ", KP_(cache), K(ret)); } else if (is_success) { @@ -306,10 +306,10 @@ int ObTmpPageCache::ObTmpPageIOCallback::inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", KP(buf), K(buf_len), K(ret)); - } else if (OB_UNLIKELY(NULL == cache_) || OB_UNLIKELY(NULL == allocator_)) { + } else if (OB_ISNULL(cache_) || OB_ISNULL(allocator_)) { ret = OB_INVALID_DATA; STORAGE_LOG(WARN, "The tmp page io callback is not valid, ", KP_(cache), KP_(allocator), K(ret)); } else { @@ -340,7 +340,7 @@ ObTmpPageCache::ObTmpMultiPageIOCallback::~ObTmpMultiPageIOCallback() int ObTmpPageCache::ObTmpMultiPageIOCallback::inner_process(const bool is_success) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == cache_)) { + if (OB_ISNULL(cache_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Invalid tmp page cache callback, ", KP_(cache), K(ret)); } else if (is_success) { @@ -373,10 +373,10 @@ int ObTmpPageCache::ObTmpMultiPageIOCallback::inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", KP(buf), K(buf_len), K(ret)); - } else if (OB_UNLIKELY(NULL == cache_) || OB_UNLIKELY(NULL == allocator_)) { + } else if (OB_ISNULL(cache_) || OB_ISNULL(allocator_)) { ret = OB_INVALID_DATA; STORAGE_LOG(WARN, "The tmp page io callback is not valid, ", KP_(cache), KP_(allocator), K(ret)); } else { @@ -509,7 +509,7 @@ int64_t ObTmpBlockCacheKey::size() const int ObTmpBlockCacheKey::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", K(ret)); } else if (OB_UNLIKELY(!is_valid())) { @@ -522,7 +522,7 @@ int ObTmpBlockCacheKey::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKe } ObTmpBlockCacheValue::ObTmpBlockCacheValue(char *buf) - : buf_(buf), size_(OB_TMP_FILE_STORE.get_block_size()) + : buf_(buf), size_(ObTmpMacroBlock::get_block_size()) { } @@ -534,7 +534,7 @@ int64_t ObTmpBlockCacheValue::size() const int ObTmpBlockCacheValue::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const { int ret = OB_SUCCESS; - if (OB_UNLIKELY(nullptr == buf || buf_len < size())) { + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(ret), KP(buf), K(buf_len), "request_size", size()); @@ -559,7 +559,7 @@ ObTmpBlockCache &ObTmpBlockCache::get_instance() int ObTmpBlockCache::init(const char *cache_name, const int64_t priority) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(NULL == cache_name) || OB_UNLIKELY(priority <= 0)) { + if (OB_ISNULL(cache_name) || OB_UNLIKELY(priority <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(cache_name), K(priority)); } else if (OB_FAIL((common::ObKVCache(handle.kvpair_->key_), @@ -632,18 +632,19 @@ void ObTmpBlockCache::destory() } ObTmpTenantMemBlockManager::ObTmpTenantMemBlockManager() - : write_handles_(), - t_mblk_map_(), - dir_to_blk_map_(), - free_page_nums_(0), - blk_nums_threshold_(0), - block_cache_(NULL), - allocator_(NULL), - tenant_id_(0), - block_write_ctx_(), + : is_inited_(false), last_access_tenant_config_ts_(0), last_tenant_mem_block_num_(1), - is_inited_(false) + free_page_nums_(0), + tenant_id_(0), + blk_nums_threshold_(0), + compare_(), + block_cache_(NULL), + allocator_(NULL), + write_handles_(), + t_mblk_map_(), + dir_to_blk_map_(), + block_write_ctx_() { } @@ -656,7 +657,7 @@ int ObTmpTenantMemBlockManager::init(const uint64_t tenant_id, double blk_nums_threshold) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpBlockCache has been inited", K(ret)); } else if (OB_UNLIKELY(blk_nums_threshold <= 0) || OB_UNLIKELY(blk_nums_threshold > 1)) { @@ -727,37 +728,109 @@ int ObTmpTenantMemBlockManager::alloc_buf(const ObTmpBlockCacheKey &key, return block_cache_->alloc_buf(key, handle); } -int ObTmpTenantMemBlockManager::try_wash(const uint64_t tenant_id, - common::ObIArray &free_blocks) +int ObTmpTenantMemBlockManager::try_sync(const int64_t block_id) { int ret = OB_SUCCESS; - const int64_t count = t_mblk_map_.size(); - if (OB_UNLIKELY(!is_inited_)) { + ObTmpMacroBlock *t_mblk = NULL; + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); - } else if (get_tenant_mem_block_num() <= count) { - int64_t wash_nums = 1; - if (OB_FAIL(wash(tenant_id, std::max(wash_nums, count - get_tenant_mem_block_num() + 1), - free_blocks))) { - STORAGE_LOG(WARN, "cannot wash a tmp macro block", K(ret), K(tenant_id)); + } else if (OB_UNLIKELY(block_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id)); + } else if (OB_FAIL(t_mblk_map_.get_refactored(block_id, t_mblk))) { + STORAGE_LOG(WARN, "the tmp macro block has been washed", K(ret), K(block_id)); + } else if (t_mblk->is_washing()){ + STORAGE_LOG(WARN, "the tmp macro block is washing", K(ret), K(block_id)); + } else if (t_mblk->is_disked()){ + STORAGE_LOG(WARN, "the tmp macro block has been disked", K(ret), K(block_id)); + } else { + t_mblk->set_washing_status(true); + common::ObIArray &extents = t_mblk->get_extents(); + for (int64_t i=0; OB_SUCC(ret) && i< extents.count(); i++){ + if (!extents.at(i)->is_closed()) { + ret = OB_STATE_NOT_MATCH; + STORAGE_LOG(WARN, "the tmp macro block's extents is not all closed", K(ret), K(block_id)); + } } + bool is_empty = false; + if (OB_SUCC(ret)) { + if (OB_FAIL(wash_block(t_mblk, is_empty))) { + STORAGE_LOG(WARN, "fail to wash", K(ret), K(tenant_id_), K(*t_mblk)); + } else if (is_empty) { + STORAGE_LOG(ERROR, "block to sync is empty", K(ret), K(tenant_id_), K(block_id)); + } else if (OB_FAIL(wait_write_io_finish())) { + STORAGE_LOG(WARN, "wait sync finish failed", K(ret), K(tenant_id_), K(block_id)); + } + } + t_mblk->set_washing_status(false); } return ret; } +int ObTmpTenantMemBlockManager::try_wash(common::ObIArray &free_blocks) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + STORAGE_LOG(WARN, "ObTmpTenantMemBlockManager has not been inited", K(ret)); + } else { + const int64_t count = t_mblk_map_.size(); + const int64_t wash_threshold = get_tenant_mem_block_num(); + const int64_t oversize = count - wash_threshold + 1; + const int64_t clean_nums = oversize > 1 ? oversize : 1; + if (OB_FAIL(wash(clean_nums, free_blocks))) { + STORAGE_LOG(WARN, "Wash tmp macro blocks failed ", K(ret), K(clean_nums)); + } + } + + return ret; + +} + int ObTmpTenantMemBlockManager::free_macro_block(const int64_t block_id) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + ObTmpMacroBlock *t_mblk = NULL; + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); - } else if (block_id <= 0) { + } else if (OB_UNLIKELY(block_id <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id)); + } else if (OB_FAIL(t_mblk_map_.get_refactored(block_id, t_mblk))) { + STORAGE_LOG(WARN, "the tmp macro block has been washed", K(ret), K(block_id)); } else if (OB_FAIL(t_mblk_map_.erase_refactored(block_id))) { STORAGE_LOG(WARN, "fail to erase tmp macro block", K(ret)); + } else if (OB_FAIL(erase_block_from_dir_map(block_id))) { + STORAGE_LOG(WARN, "fail to erase block from dir map", K(ret)); } else { - free_page_nums_ -= ObTmpFilePageBuddy::MAX_PAGE_NUMS; + free_page_nums_ -= t_mblk->get_free_page_nums(); + } + return ret; +} + +int ObTmpTenantMemBlockManager::erase_block_from_dir_map(const int64_t block_id) +{ + int ret = OB_SUCCESS; + Map::iterator iter; + int64_t dir_id = -1; + for (iter = dir_to_blk_map_.begin(); iter != dir_to_blk_map_.end(); ++iter) { + const int64_t to_erase_blk_id = iter->second; + if (to_erase_blk_id == block_id) { + dir_id = iter->first; + break; + } + } + + if (OB_UNLIKELY(-1 == dir_id)) { + // do nothing + } else if (OB_FAIL(dir_to_blk_map_.erase_refactored(dir_id))) { + if (OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } else { + STORAGE_LOG(WARN, "erase block from dir map failed", K(ret), K(dir_id)); + } } return ret; } @@ -767,9 +840,9 @@ int ObTmpTenantMemBlockManager::alloc_extent(const int64_t dir_id, const uint64_ { int ret = OB_SUCCESS; int64_t block_id = -1; - int64_t page_nums = std::ceil(size * 1.0 / ObTmpMacroBlock::get_default_page_size()); + const int64_t page_nums = std::ceil(size * 1.0 / ObTmpMacroBlock::get_default_page_size()); ObTmpMacroBlock *t_mblk = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); } else if (OB_FAIL(dir_to_blk_map_.get_refactored(dir_id, block_id))) { @@ -790,7 +863,7 @@ int ObTmpTenantMemBlockManager::alloc_extent(const int64_t dir_id, const uint64_ STORAGE_LOG(WARN, "fail to set dir_to_blk_map", K(ret)); } } else if (t_mblk->get_max_cont_page_nums() < page_nums - || t_mblk->get_tenant_id() != tenant_id) { + || t_mblk->get_tenant_id() != tenant_id_) { if (OB_FAIL(get_macro_block(dir_id, tenant_id, page_nums, t_mblk, free_blocks))) { if (OB_ITER_END != ret) { STORAGE_LOG(WARN, "fail to get macro block", K(ret)); @@ -812,14 +885,30 @@ int ObTmpTenantMemBlockManager::alloc_extent(const int64_t dir_id, const uint64_ return ret; } +int ObTmpTenantMemBlockManager::alloc_block_all_pages(ObTmpMacroBlock *t_mblk, ObTmpFileExtent &extent) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(t_mblk)) { + ret = OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected error, t_mblk is nullptr", K(ret), KP(t_mblk)); + } else if (OB_FAIL(t_mblk->alloc_all_pages(extent))){ + STORAGE_LOG(WARN, "fail to alloc tmp extent", K(ret)); + } else { + free_page_nums_ -= extent.get_page_nums(); + } + + return ret; +} + int ObTmpTenantMemBlockManager::free_extent(const int64_t free_page_nums, const ObTmpMacroBlock *t_mblk) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); - } else if (free_page_nums < 0 || free_page_nums > ObTmpFilePageBuddy::MAX_PAGE_NUMS || NULL == t_mblk) { + } else if (OB_UNLIKELY(free_page_nums < 0 || free_page_nums > ObTmpFilePageBuddy::MAX_PAGE_NUMS) + || OB_ISNULL(t_mblk)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(free_page_nums), KPC(t_mblk)); } else if (OB_FAIL(refresh_dir_to_blk_map(t_mblk->get_dir_id(), t_mblk))) { @@ -837,7 +926,7 @@ int ObTmpTenantMemBlockManager::get_macro_block(const int64_t dir_id, common::ObIArray &free_blocks) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); } else { @@ -857,14 +946,16 @@ int ObTmpTenantMemBlockManager::get_macro_block(const int64_t dir_id, } if (!is_found) { const int64_t count = t_mblk_map_.size(); + const int64_t wash_threshold = get_tenant_mem_block_num(); if (OB_UNLIKELY(t_mblk_map_.size() == 0)) { // nothing to do. + } else if (OB_UNLIKELY(free_page_nums_ < 0)) { + ret = OB_ERR_UNEXPECTED; + STORAGE_LOG(ERROR, "free page nums can not be negative", K(ret), K(free_page_nums_)); } else if ( get_tenant_mem_block_num() <= count || blk_nums_threshold_ > (free_page_nums_ * 1.0) / (t_mblk_map_.size() * ObTmpFilePageBuddy::MAX_PAGE_NUMS)) { int64_t wash_nums = 1; - if (OB_FAIL(wash(tenant_id, - std::max(wash_nums, count - get_tenant_mem_block_num() + 1), - free_blocks))) { + if (OB_FAIL(wash(std::max(wash_nums, count - wash_threshold + 1), free_blocks))) { STORAGE_LOG(WARN, "cannot wash a tmp macro block", K(ret), K(dir_id), K(tenant_id)); } } @@ -876,60 +967,83 @@ int ObTmpTenantMemBlockManager::get_macro_block(const int64_t dir_id, return ret; } -int ObTmpTenantMemBlockManager::wash(const uint64_t tenant_id, int64_t block_nums, +ObTmpTenantMemBlockManager::BlockWashScoreCompare::BlockWashScoreCompare() +{ +} + +bool ObTmpTenantMemBlockManager::BlockWashScoreCompare::operator() ( + const ObTmpTenantMemBlockManager::BlockInfo &left, + const ObTmpTenantMemBlockManager::BlockInfo &right) +{ + return left.wash_score_ < right.wash_score_; +} + +int ObTmpTenantMemBlockManager::wash(const int64_t block_nums, common::ObIArray &free_blocks) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + TmpMacroBlockMap::iterator iter; + common::ObArray blks; + if (IS_NOT_INIT) { ret = OB_NOT_INIT; - STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); + STORAGE_LOG(WARN, "ObTmpTenantMemBlockManager has not been inited", K(ret)); } else if (OB_FAIL(wait_write_io_finish())) { STORAGE_LOG(WARN, "fail to wait previous write io", K(ret)); } else { - while (OB_SUCC(ret) && block_nums--) { - int64_t count = t_mblk_map_.size(); - if (OB_SUCC(ret)) { - if (OB_UNLIKELY(count < get_tenant_mem_block_num())) { - STORAGE_LOG(WARN, "Tenant memory has not been used up, not need to wash ", K(ret), - K(count)); + Heap heap(compare_, allocator_); + int64_t cur_time = ObTimeUtility::fast_current_time(); + for (iter = t_mblk_map_.begin(); OB_SUCC(ret) && iter != t_mblk_map_.end(); ++iter) { + ObTmpMacroBlock *m_blk = iter->second; + if (OB_UNLIKELY(NULL != m_blk) && OB_UNLIKELY(m_blk->is_inited()) && OB_UNLIKELY(!m_blk->is_disked())) { + BlockInfo info; + info.block_id_ = m_blk->get_block_id(); + info.wash_score_ = m_blk->get_wash_score(cur_time); + if(OB_FAIL(heap.push(info))) { + STORAGE_LOG(WARN, "insert block to array failed", K(ret)); + } + } + } + for (int64_t wash_count = 0; OB_SUCC(ret) && wash_count < block_nums && heap.count() > 0;) { + const BlockInfo info = heap.top(); + ObTmpMacroBlock *m_blk = NULL; + if (OB_FAIL(t_mblk_map_.get_refactored(info.block_id_, m_blk))) { + STORAGE_LOG(WARN, "get block failed", K(ret)); + } else if(OB_UNLIKELY(NULL == m_blk)) { + ret = OB_ERR_UNEXPECTED; + STORAGE_LOG(ERROR, "block is NULL ", K(ret), K(*m_blk)); + } else if (m_blk->is_washing()) { + // do nothing + } else { + m_blk->set_washing_status(true); + bool is_empty = false; + if (m_blk->is_empty()) { + if (OB_FAIL(refresh_dir_to_blk_map(m_blk->get_dir_id(), m_blk))) { + STORAGE_LOG(WARN, "fail to refresh dir_to_blk_map", K(ret), K(*m_blk)); + } + } else if (OB_FAIL(wash_block(m_blk, is_empty))) { + STORAGE_LOG(WARN, "fail to wash", K(ret), K_(tenant_id), K(*m_blk)); + } else if (OB_FAIL(free_blocks.push_back(m_blk))) { + STORAGE_LOG(WARN, "fail to push back to free_blocks", K(ret), K_(tenant_id)); } else { - TmpMacroBlockMap::iterator iter; - ObTmpMacroBlock *wash_block = NULL; - for (iter = t_mblk_map_.begin(); count > 0 && iter != t_mblk_map_.end(); ++iter) { - if (iter->second->get_tenant_id() == tenant_id) { - if (!iter->second->is_washing()) { - if (NULL == wash_block - || wash_block->get_free_page_nums() > iter->second->get_free_page_nums()) { - if (NULL != wash_block) { - wash_block->set_washing_status(false); - } - wash_block = iter->second; - wash_block->set_washing_status(true); - } - } - count--; - } - } - if (NULL != wash_block && wash_block->is_inited() && !wash_block->is_disked()) { - bool is_empty = false; - if (OB_FAIL(wash_with_no_wait(tenant_id, wash_block, is_empty))) { - STORAGE_LOG(WARN, "fail to wash", K(ret), K(tenant_id), K(*wash_block)); - } else if (is_empty && OB_FAIL(free_blocks.push_back(wash_block))) { - STORAGE_LOG(WARN, "fail to push back to free_blocks", K(ret), K(tenant_id)); - } - } + wash_count++; + } + m_blk->set_washing_status(false); + } + if(OB_SUCC(ret)) { + if (OB_FAIL(heap.pop())) { + STORAGE_LOG(WARN, "pop info from heap failed", K(ret), K_(tenant_id)); } } } } + return ret; } -int ObTmpTenantMemBlockManager::add_macro_block(const uint64_t tenant_id, ObTmpMacroBlock *&t_mblk) +int ObTmpTenantMemBlockManager::add_macro_block(ObTmpMacroBlock *&t_mblk) { int ret = OB_SUCCESS; - UNUSED(tenant_id); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); } else if (OB_FAIL(t_mblk_map_.set_refactored(t_mblk->get_block_id(), t_mblk))) { @@ -945,7 +1059,7 @@ int ObTmpTenantMemBlockManager::refresh_dir_to_blk_map(const int64_t dir_id, { int ret = OB_SUCCESS; int64_t block_id = 0; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); } else if (OB_FAIL(dir_to_blk_map_.get_refactored(dir_id, block_id))) { @@ -970,26 +1084,7 @@ int ObTmpTenantMemBlockManager::refresh_dir_to_blk_map(const int64_t dir_id, return ret; } - -int ObTmpTenantMemBlockManager::wash(const uint64_t tenant_id, ObTmpMacroBlock *wash_block, - bool &is_empty) -{ - int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { - ret = OB_NOT_INIT; - STORAGE_LOG(WARN, "ObTmpBlockCache has not been inited", K(ret)); - } else if (OB_FAIL(wait_write_io_finish())) { - STORAGE_LOG(WARN, "fail to wait previous write io", K(ret)); - } else if (wash_block->is_disked()) { - // nothing to do - } else if (OB_FAIL(wash_with_no_wait(tenant_id, wash_block, is_empty))) { - STORAGE_LOG(WARN, "fail to wash", K(ret), K(tenant_id)); - } - return ret; -} - -int ObTmpTenantMemBlockManager::wash_with_no_wait(const uint64_t tenant_id, - ObTmpMacroBlock *wash_block, bool &is_empty) +int ObTmpTenantMemBlockManager::wash_block(ObTmpMacroBlock *wash_block, bool &is_empty) { int ret = OB_SUCCESS; // close all of extents in this block. @@ -1000,8 +1095,10 @@ int ObTmpTenantMemBlockManager::wash_with_no_wait(const uint64_t tenant_id, STORAGE_LOG(WARN, "The washing block is null", K(ret)); } else { bool is_all_close = false; - if (OB_FAIL(wash_block->close(is_all_close))) { + uint8_t free_page_nums = 0; + if (OB_FAIL(wash_block->close(is_all_close, free_page_nums)) ) { STORAGE_LOG(WARN, "fail to close the wash block", K(ret)); + } else if (FALSE_IT(free_page_nums_ = free_page_nums_ + free_page_nums)){ } else if (is_all_close) { if (wash_block->is_empty()) { // this block don't need to wash. @@ -1014,27 +1111,27 @@ int ObTmpTenantMemBlockManager::wash_with_no_wait(const uint64_t tenant_id, ObTmpBlockIOInfo info; ObMacroBlockHandle &mb_handle = wash_block->get_macro_block_handle(); if (OB_FAIL(wash_block->get_wash_io_info(info))) { - STORAGE_LOG(WARN, "fail to get wash io info", K(ret), K(tenant_id)); - } else if (OB_FAIL(write_io(info, wash_block->get_tmp_block_header(), mb_handle))) { - STORAGE_LOG(WARN, "fail to write tmp block", K(ret), K(tenant_id)); + STORAGE_LOG(WARN, "fail to get wash io info", K(ret), K_(tenant_id)); + } else if (OB_FAIL(write_io(info, mb_handle))) { + STORAGE_LOG(WARN, "fail to write tmp block", K(ret), K_(tenant_id)); } else if (OB_FAIL(write_handles_.push_back(&mb_handle))) { STORAGE_LOG(WARN, "fail to push back into write_handles", K(ret)); } else if (wash_block->is_disked()) { // nothing to do } else if (OB_FAIL(wash_block->give_back_buf_into_cache(true/*is_wash*/))) { - STORAGE_LOG(WARN, "fail to put tmp block cache", K(ret), K(tenant_id)); + STORAGE_LOG(WARN, "fail to put tmp block cache", K(ret), K_(tenant_id)); } else { - OB_TMP_FILE_STORE.dec_block_cache_num(tenant_id, 1); + OB_TMP_FILE_STORE.dec_block_cache_num(tenant_id_, 1); free_page_nums_ -= wash_block->get_free_page_nums(); if (OB_FAIL(t_mblk_map_.erase_refactored(wash_block->get_block_id(), &wash_block))) { STORAGE_LOG(WARN, "fail to erase t_mblk_map", K(ret)); + } else if(OB_FAIL(erase_block_from_dir_map(wash_block->get_block_id()))){ + STORAGE_LOG(WARN, "fail to erase block from dir map", K(ret)); } else { ObTaskController::get().allow_next_syslog(); STORAGE_LOG(INFO, "succeed to wash a block", K(*wash_block)); } } - } else { - STORAGE_LOG(WARN, "this block has been destoryed", K(*wash_block)); } } else { STORAGE_LOG(INFO, "this block has some the unclosed extent", K(*wash_block)); @@ -1044,11 +1141,29 @@ int ObTmpTenantMemBlockManager::wash_with_no_wait(const uint64_t tenant_id, return ret; } +int ObTmpTenantMemBlockManager::free_empty_blocks(common::ObIArray &free_blocks) +{ + int ret = OB_SUCCESS; + if (free_blocks.count() > 0) { + for (int64_t i = 0; OB_SUCC(ret) && i < free_blocks.count(); ++i) { + ObTmpMacroBlock* blk = free_blocks.at(i); + if (blk->is_empty()) { + if (OB_FAIL(free_macro_block(blk->get_block_id()))) { + STORAGE_LOG(WARN, "fail to free tmp macro block", K(ret)); + } + } + free_blocks.at(i) = NULL; + } + free_blocks.reset(); + } + return ret; +} + int ObTmpTenantMemBlockManager::wait_write_io_finish() { int ret = OB_SUCCESS; const int64_t io_timeout_ms = GCONF._data_storage_io_timeout / 1000L; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else if (write_handles_.count() > 0) { @@ -1068,14 +1183,13 @@ int ObTmpTenantMemBlockManager::wait_write_io_finish() int ObTmpTenantMemBlockManager::write_io( const ObTmpBlockIOInfo &io_info, - const ObTmpFileMacroBlockHeader &tmp_block_header, ObMacroBlockHandle &handle) { int ret = OB_SUCCESS; const int64_t buf_size = OB_SERVER_BLOCK_MGR.get_macro_block_size(); const int64_t page_size = ObTmpMacroBlock::get_default_page_size(); int64_t pos = 0; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else if (OB_FAIL(THE_IO_DEVICE->check_space_full(OB_SERVER_BLOCK_MGR.get_macro_block_size()))) { @@ -1111,8 +1225,8 @@ int64_t ObTmpTenantMemBlockManager::get_tenant_mem_block_num() } else { const int64_t bytes = common::upper_align( lib::get_tenant_memory_limit(tenant_id_) * tenant_config->_temporary_file_io_area_size / 100, - OB_TMP_FILE_STORE.get_block_size()); - tenant_mem_block_num = bytes / OB_TMP_FILE_STORE.get_block_size(); + ObTmpMacroBlock::get_block_size()); + tenant_mem_block_num = bytes / ObTmpMacroBlock::get_block_size(); } ATOMIC_STORE(&last_tenant_mem_block_num_, tenant_mem_block_num); ATOMIC_STORE(&last_access_tenant_config_ts_, common::ObClockGenerator::getClock()); diff --git a/src/storage/blocksstable/ob_tmp_file_cache.h b/src/storage/blocksstable/ob_tmp_file_cache.h index 46b5af0a29..7f9c728b26 100644 --- a/src/storage/blocksstable/ob_tmp_file_cache.h +++ b/src/storage/blocksstable/ob_tmp_file_cache.h @@ -31,17 +31,17 @@ class ObTmpMacroBlock; class ObTmpFileExtent; class ObMacroBlockHandle; -class ObTmpPageCacheKey : public common::ObIKVCacheKey +class ObTmpPageCacheKey final : public common::ObIKVCacheKey { public: ObTmpPageCacheKey(); ObTmpPageCacheKey(const int64_t block_id, const int64_t page_id, const uint64_t tenant_id); - virtual ~ObTmpPageCacheKey(); - virtual bool operator ==(const ObIKVCacheKey &other) const override; - virtual uint64_t get_tenant_id() const override; - virtual uint64_t hash() const override; - virtual int64_t size() const override; - virtual int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const override; + ~ObTmpPageCacheKey(); + bool operator ==(const ObIKVCacheKey &other) const override; + uint64_t get_tenant_id() const override; + uint64_t hash() const override; + int64_t size() const override; + int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const override; bool is_valid() const; int64_t get_page_id() const { return page_id_; } TO_STRING_KV(K_(block_id), K_(page_id), K_(tenant_id)); @@ -52,13 +52,13 @@ private: uint64_t tenant_id_; }; -class ObTmpPageCacheValue : public common::ObIKVCacheValue +class ObTmpPageCacheValue final : public common::ObIKVCacheValue { public: explicit ObTmpPageCacheValue(char *buf); - virtual ~ObTmpPageCacheValue(); - virtual int64_t size() const override; - virtual int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const override; + ~ObTmpPageCacheValue(); + int64_t size() const override; + int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const override; bool is_valid() const { return NULL != buf_ && size() > 0; } char *get_buffer() { return buf_; } void set_buffer(char *buf) { buf_ = buf;} @@ -70,11 +70,11 @@ private: DISALLOW_COPY_AND_ASSIGN(ObTmpPageCacheValue); }; -struct ObTmpPageValueHandle +struct ObTmpPageValueHandle final { public: ObTmpPageValueHandle() : value_(NULL), handle_() {} - virtual ~ObTmpPageValueHandle() = default; + ~ObTmpPageValueHandle() = default; void reset() { handle_.reset(); @@ -85,19 +85,19 @@ public: common::ObKVCacheHandle handle_; }; -struct ObTmpPageIOInfo +struct ObTmpPageIOInfo final { public: - ObTmpPageIOInfo() : key_(), offset_(0), size_(0) {} + ObTmpPageIOInfo() : offset_(0), size_(0), key_() {} ~ObTmpPageIOInfo() {} TO_STRING_KV(K_(key), K_(offset), K_(size)); - ObTmpPageCacheKey key_; int32_t offset_; int32_t size_; + ObTmpPageCacheKey key_; }; -class ObTmpPageCache : public common::ObKVCache +class ObTmpPageCache final : public common::ObKVCache { public: typedef common::ObKVCache BasePageCache; @@ -139,29 +139,29 @@ public: int64_t io_buf_size_; char *data_buf_; // actual data buffer }; - class ObTmpPageIOCallback : public ObITmpPageIOCallback + class ObTmpPageIOCallback final : public ObITmpPageIOCallback { public: ObTmpPageIOCallback(); - virtual ~ObTmpPageIOCallback(); - virtual int64_t size() const override; - virtual int inner_process(const bool is_success) override; - virtual int inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const override; - virtual const char *get_data() override; + ~ObTmpPageIOCallback(); + int64_t size() const override; + int inner_process(const bool is_success) override; + int inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const override; + const char *get_data() override; TO_STRING_KV(KP_(data_buf)); private: friend class ObTmpPageCache; ObTmpPageCacheKey key_; }; - class ObTmpMultiPageIOCallback : public ObITmpPageIOCallback + class ObTmpMultiPageIOCallback final : public ObITmpPageIOCallback { public: ObTmpMultiPageIOCallback(); - virtual ~ObTmpMultiPageIOCallback(); - virtual int64_t size() const override; - virtual int inner_process(const bool is_success) override; - virtual int inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const override; - virtual const char *get_data() override; + ~ObTmpMultiPageIOCallback(); + int64_t size() const override; + int inner_process(const bool is_success) override; + int inner_deep_copy(char *buf, const int64_t buf_len, ObIOCallback *&callback) const override; + const char *get_data() override; TO_STRING_KV(KP_(data_buf)); private: friend class ObTmpPageCache; @@ -169,7 +169,7 @@ public: }; private: ObTmpPageCache(); - virtual ~ObTmpPageCache(); + ~ObTmpPageCache(); int read_io(const ObTmpBlockIOInfo &io_info, ObITmpPageIOCallback &callback, ObMacroBlockHandle &handle); @@ -177,17 +177,17 @@ private: DISALLOW_COPY_AND_ASSIGN(ObTmpPageCache); }; -class ObTmpBlockCacheKey : public common::ObIKVCacheKey +class ObTmpBlockCacheKey final : public common::ObIKVCacheKey { public: ObTmpBlockCacheKey(const int64_t block_id, const uint64_t tenant_id); - virtual ~ObTmpBlockCacheKey() {} - virtual bool operator ==(const ObIKVCacheKey &other) const override; - virtual uint64_t get_tenant_id() const override; - virtual uint64_t hash() const override; - virtual int64_t size() const override; - virtual int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const override; - virtual int64_t get_block_id() const { return block_id_; } + ~ObTmpBlockCacheKey() {} + bool operator ==(const ObIKVCacheKey &other) const override; + uint64_t get_tenant_id() const override; + uint64_t hash() const override; + int64_t size() const override; + int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const override; + int64_t get_block_id() const { return block_id_; } bool is_valid() const { return block_id_ > 0 && tenant_id_ > 0 && size() > 0; } TO_STRING_KV(K_(block_id), K_(tenant_id)); @@ -198,13 +198,13 @@ private: DISALLOW_COPY_AND_ASSIGN(ObTmpBlockCacheKey); }; -class ObTmpBlockCacheValue : public common::ObIKVCacheValue +class ObTmpBlockCacheValue final : public common::ObIKVCacheValue { public: explicit ObTmpBlockCacheValue(char *buf); - virtual ~ObTmpBlockCacheValue() {} - virtual int64_t size() const override; - virtual int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const override; + ~ObTmpBlockCacheValue() {} + int64_t size() const override; + int deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const override; bool is_valid() const { return NULL != buf_ && size() > 0; } char *get_buffer() { return buf_; } TO_STRING_KV(K_(size)); @@ -215,12 +215,12 @@ private: DISALLOW_COPY_AND_ASSIGN(ObTmpBlockCacheValue); }; -struct ObTmpBlockValueHandle +struct ObTmpBlockValueHandle final { public: ObTmpBlockValueHandle() : value_(NULL), inst_handle_(), kvpair_(NULL), handle_(){} - virtual ~ObTmpBlockValueHandle() = default; + ~ObTmpBlockValueHandle() = default; void reset() { handle_.reset(); @@ -235,7 +235,7 @@ public: common::ObKVCacheHandle handle_; }; -class ObTmpBlockCache : public common::ObKVCache +class ObTmpBlockCache final: public common::ObKVCache { public: static ObTmpBlockCache &get_instance(); @@ -247,16 +247,16 @@ public: private: ObTmpBlockCache() {} - virtual ~ObTmpBlockCache() {} + ~ObTmpBlockCache() {} DISALLOW_COPY_AND_ASSIGN(ObTmpBlockCache); }; -class ObTmpTenantMemBlockManager +class ObTmpTenantMemBlockManager final { public: ObTmpTenantMemBlockManager(); - virtual ~ObTmpTenantMemBlockManager(); + ~ObTmpTenantMemBlockManager(); int init(const uint64_t tenant_id, common::ObIAllocator &allocator, double blk_nums_threshold = DEFAULT_MIN_FREE_BLOCK_RATIO); @@ -265,28 +265,52 @@ public: int alloc_buf(const ObTmpBlockCacheKey &key, ObTmpBlockValueHandle &handle); int alloc_extent(const int64_t dir_id, const uint64_t tenant_id, const int64_t size, ObTmpFileExtent &extent, common::ObIArray &free_blocks); + int alloc_block_all_pages(ObTmpMacroBlock *t_mblk, ObTmpFileExtent &extent); int free_macro_block(const int64_t block_id); - int try_wash(const uint64_t tenant_id, common::ObIArray &free_blocks); - int add_macro_block(const uint64_t tenant_id, ObTmpMacroBlock *&t_mblk); + int try_sync(const int64_t block_id); + int try_wash(common::ObIArray &free_blocks); + int add_macro_block(ObTmpMacroBlock *&t_mblk); int wait_write_io_finish(); OB_INLINE bool check_need_wait_write() { return write_handles_.count() > 0; } int free_extent(const int64_t free_page_nums, const ObTmpMacroBlock *t_mblk); + int free_empty_blocks(common::ObIArray &free_blocks); private: int get_macro_block(const int64_t dir_id, const uint64_t tenant_id, const int64_t page_nums, ObTmpMacroBlock *&t_mblk, common::ObIArray &free_blocks); - int wash(const uint64_t tenant_id, int64_t block_nums, + int wash(const int64_t block_nums, common::ObIArray &free_blocks); - int wash(const uint64_t tenant_id, ObTmpMacroBlock *wash_block, bool &is_empty); - int wash_with_no_wait(const uint64_t tenant_id, ObTmpMacroBlock *wash_block, bool &is_empty); + int wash(ObTmpMacroBlock *wash_block, bool &is_empty); + int wash_block(ObTmpMacroBlock *wash_block, bool &is_empty); int write_io( const ObTmpBlockIOInfo &io_info, - const ObTmpFileMacroBlockHeader &tmp_block_header, ObMacroBlockHandle &handle); int refresh_dir_to_blk_map(const int64_t dir_id, const ObTmpMacroBlock *t_mblk); + int erase_block_from_dir_map(const int64_t block_id); int64_t get_tenant_mem_block_num(); private: + struct BlockInfo final + { + public: + BlockInfo() :block_id_(0), wash_score_(INT64_MIN) {}; + ~BlockInfo() = default; + + TO_STRING_KV(K_(block_id), K_(wash_score)); + + int64_t block_id_; + double wash_score_; + }; + + class BlockWashScoreCompare final + { + public: + BlockWashScoreCompare(); + ~BlockWashScoreCompare() = default; + bool operator() (const BlockInfo &a, const BlockInfo &b); + int get_error_code() { return OB_SUCCESS; } + }; + // 1/256, only one free block each 256 block. static constexpr double DEFAULT_MIN_FREE_BLOCK_RATIO = 0.00390625; static const uint64_t DEFAULT_BUCKET_NUM = 1543L; @@ -295,19 +319,21 @@ private: typedef common::hash::ObHashMap TmpMacroBlockMap; typedef common::hash::ObHashMap Map; + typedef common::ObBinaryHeap Heap; + bool is_inited_; + int64_t last_access_tenant_config_ts_; + int64_t last_tenant_mem_block_num_; + int64_t free_page_nums_; + uint64_t tenant_id_; + double blk_nums_threshold_; // free_page_nums / total_page_nums + BlockWashScoreCompare compare_; + ObTmpBlockCache *block_cache_; + common::ObIAllocator *allocator_; common::ObSEArray write_handles_; TmpMacroBlockMap t_mblk_map_; // Map dir_to_blk_map_; // - int64_t free_page_nums_; - double blk_nums_threshold_; // free_page_nums / total_page_nums - ObTmpBlockCache *block_cache_; - common::ObIAllocator *allocator_; - uint64_t tenant_id_; ObMacroBlocksWriteCtx block_write_ctx_; - int64_t last_access_tenant_config_ts_; - int64_t last_tenant_mem_block_num_; - bool is_inited_; DISALLOW_COPY_AND_ASSIGN(ObTmpTenantMemBlockManager); }; diff --git a/src/storage/blocksstable/ob_tmp_file_store.cpp b/src/storage/blocksstable/ob_tmp_file_store.cpp index 8044de398f..272892e0d4 100644 --- a/src/storage/blocksstable/ob_tmp_file_store.cpp +++ b/src/storage/blocksstable/ob_tmp_file_store.cpp @@ -22,11 +22,12 @@ namespace blocksstable { const int64_t ObTmpMacroBlock::DEFAULT_PAGE_SIZE = 8192L; // 8kb -int64_t ObTmpTenantMacroBlockManager::next_blk_id_ = 0; ObTmpFilePageBuddy::ObTmpFilePageBuddy() - : max_cont_page_nums_(0), buf_(NULL), allocator_(NULL), - is_inited_(false) + : is_inited_(false), + max_cont_page_nums_(0), + buf_(NULL), + allocator_(NULL) { MEMSET(free_area_, 0, sizeof(free_area_)); } @@ -39,15 +40,14 @@ ObTmpFilePageBuddy::~ObTmpFilePageBuddy() int ObTmpFilePageBuddy::init(common::ObIAllocator &allocator) { int ret = OB_SUCCESS; - int64_t start_id = 0; + uint8_t start_id = 0; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpFilePageBuddy has not been inited", K(ret)); } else { allocator_ = &allocator; - buf_ = reinterpret_cast(allocator_->alloc(sizeof(ObTmpFileArea) - * (std::pow(2, MAX_ORDER) - std::pow(2, MIN_ORDER)))); - if (NULL == buf_) { + buf_ = reinterpret_cast(allocator_->alloc(sizeof(ObTmpFileArea) * MAX_PAGE_NUMS)); + if (OB_ISNULL(buf_)) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "fail to alloc a buf", K(ret)); } else { @@ -60,7 +60,7 @@ int ObTmpFilePageBuddy::init(common::ObIAllocator &allocator) * | free_area |[254,254]|[252,253]|[248,251]|[240,247]|[224,239]|[192,223]|[128,191]|[0,127]| * -------------- --------- --------- --------- --------- --------- --------- --------- ------- */ - int64_t nums = max_cont_page_nums_; + uint8_t nums = max_cont_page_nums_; for (int32_t i = MIN_ORDER - 1; i >= 0; --i) { free_area_[i] = NULL; } @@ -94,7 +94,7 @@ int ObTmpFilePageBuddy::alloc_all_pages() { int ret = OB_SUCCESS; ObTmpFileArea *tmp = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFilePageBuddy has not been inited", K(ret)); } else if (is_empty()) { @@ -114,12 +114,12 @@ int ObTmpFilePageBuddy::alloc_all_pages() return ret; } -int ObTmpFilePageBuddy::alloc(const int32_t page_nums, - int32_t &start_page_id, - int32_t &alloced_page_nums) +int ObTmpFilePageBuddy::alloc(const uint8_t page_nums, + uint8_t &start_page_id, + uint8_t &alloced_page_nums) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFilePageBuddy has not been inited", K(ret)); } else if (OB_UNLIKELY(page_nums <= 0)) { @@ -159,7 +159,7 @@ int ObTmpFilePageBuddy::alloc(const int32_t page_nums, if (NULL == free_area_[i]) { // nothing to do. } else { - max = free_area_[i]->page_nums_; + max = free_area_[i]->page_nums_; break; } } @@ -330,101 +330,23 @@ ObTmpFileArea *ObTmpFilePageBuddy::find_buddy(const int32_t page_nums, const int return tmp; } -ObTmpFileMacroBlockHeader::ObTmpFileMacroBlockHeader() - : version_(TMP_FILE_MACRO_BLOCK_HEADER_VERSION), - magic_(TMP_FILE_MACRO_BLOCK_HEADER_MAGIC), +ObTmpMacroBlock::ObTmpMacroBlock() + : is_inited_(false), + is_washing_(false), + is_disked_(false), + free_page_nums_(0), + buffer_(NULL), block_id_(-1), dir_id_(-1), tenant_id_(0), - free_page_nums_(0) -{ -} - -bool ObTmpFileMacroBlockHeader::is_valid() const -{ - return TMP_FILE_MACRO_BLOCK_HEADER_VERSION == version_ - && TMP_FILE_MACRO_BLOCK_HEADER_MAGIC == magic_ - && block_id_ >= 0 - && dir_id_ >= 0 - && tenant_id_ > 0 - && free_page_nums_ >= 0; -} - -int ObTmpFileMacroBlockHeader::serialize(char *buf, const int64_t buf_len, int64_t &pos) const -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < 0)) { - ret = OB_INVALID_ARGUMENT; - STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(buf), K(buf_len)); - } else if (OB_UNLIKELY(pos + get_serialize_size() > buf_len)) { - ret = OB_BUF_NOT_ENOUGH; - STORAGE_LOG(WARN, "data buffer is not enough", K(ret), K(pos), K(buf_len), K(*this)); - } else if (OB_UNLIKELY(!is_valid())) { - ret = OB_INVALID_ARGUMENT; - STORAGE_LOG(WARN, "tmp file macro block header is invalid", K(ret), K(*this)); - } else { - ObTmpFileMacroBlockHeader *header = reinterpret_cast(buf + pos); - header->version_ = version_; - header->magic_ = magic_; - header->block_id_ = block_id_; - header->dir_id_ = dir_id_; - header->tenant_id_ = tenant_id_; - header->free_page_nums_ = free_page_nums_; - pos += header->get_serialize_size(); - } - return ret; -} - -int ObTmpFileMacroBlockHeader::deserialize(const char *buf, const int64_t data_len, int64_t &pos) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(buf) || OB_UNLIKELY(data_len <= 0 || pos < 0)) { - ret = OB_INVALID_ARGUMENT; - STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(buf), K(data_len), K(pos)); - } else if (OB_UNLIKELY(data_len - pos < get_serialize_size())) { - ret = OB_INVALID_ARGUMENT; - STORAGE_LOG(WARN, "buffer not enough", K(ret), KP(buf), K(data_len), K(pos)); - } else { - const ObTmpFileMacroBlockHeader *ptr = reinterpret_cast(buf + pos); - version_ = ptr->version_; - magic_ = ptr->magic_; - block_id_ = ptr->block_id_; - dir_id_ = ptr->dir_id_; - tenant_id_ = ptr->tenant_id_; - free_page_nums_ = ptr->free_page_nums_; - if (OB_UNLIKELY(!is_valid())) { - ret = OB_DESERIALIZE_ERROR; - STORAGE_LOG(ERROR, "deserialize error", K(ret), K(*this)); - } else { - pos += get_serialize_size(); - } - } - return ret; -} - -void ObTmpFileMacroBlockHeader::reset() -{ - version_ = TMP_FILE_MACRO_BLOCK_HEADER_VERSION; - magic_ = TMP_FILE_MACRO_BLOCK_HEADER_MAGIC; - block_id_ = -1; - dir_id_ = -1; - tenant_id_ = 0; - free_page_nums_ = 0; -} - -ObTmpMacroBlock::ObTmpMacroBlock() - : buffer_(NULL), - handle_(), - using_extents_(), - macro_block_handle_(), - tmp_file_header_(), + alloc_time_(0), + access_time_(0), io_desc_(), lock_(common::ObLatchIds::TMP_FILE_MACRO_LOCK), - is_washing_(false), - is_disked_(false), - is_inited_(false) -{ -} + macro_block_handle_(), + handle_(), + page_buddy_(), + using_extents_() {} ObTmpMacroBlock::~ObTmpMacroBlock() { @@ -435,19 +357,21 @@ int ObTmpMacroBlock::init(const int64_t block_id, const int64_t dir_id, const ui common::ObIAllocator &allocator) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else if (OB_FAIL(page_buddy_.init(allocator))) { STORAGE_LOG(WARN, "Fail to init the page buddy", K(ret)); } else { - tmp_file_header_.block_id_ = block_id; - tmp_file_header_.dir_id_ = dir_id; - tmp_file_header_.tenant_id_ = tenant_id; - tmp_file_header_.free_page_nums_ = ObTmpFilePageBuddy::MAX_PAGE_NUMS; + block_id_ = block_id; + dir_id_ = dir_id; + tenant_id_ = tenant_id, + free_page_nums_ = ObTmpFilePageBuddy::MAX_PAGE_NUMS; is_disked_ = false; is_washing_ = false; is_inited_ = true; + alloc_time_ = 0; + ATOMIC_STORE(&access_time_, 0); } if (!is_inited_) { destroy(); @@ -460,19 +384,25 @@ void ObTmpMacroBlock::destroy() using_extents_.reset(); page_buddy_.destroy(); macro_block_handle_.reset(); - tmp_file_header_.reset(); + block_id_ = -1; + dir_id_ = -1; + tenant_id_ = 0; + free_page_nums_ = 0; buffer_ = NULL; handle_.reset(); is_disked_ = false; is_washing_ = false; is_inited_ = false; + alloc_time_ = 0; + ATOMIC_STORE(&access_time_, 0); } -int ObTmpMacroBlock::close(bool &is_all_close) +int ObTmpMacroBlock::close(bool &is_all_close, uint8_t &free_page_nums) { int ret = OB_SUCCESS; is_all_close = true; - if (OB_UNLIKELY(!is_inited_)) { + free_page_nums = 0; + if (IS_NOT_INIT) { is_all_close = false; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited"); } else { @@ -480,20 +410,24 @@ int ObTmpMacroBlock::close(bool &is_all_close) for (int32_t i = 0; OB_SUCC(ret) && i < using_extents_.count() && is_all_close; i++) { tmp = using_extents_.at(i); if (NULL != tmp && !tmp->is_closed()) { - int32_t start_id; - int32_t page_nums; + uint8_t start_id = ObTmpFilePageBuddy::MAX_PAGE_NUMS; + uint8_t page_nums = 0; if (tmp->close(start_id, page_nums)) { - if (-1 == start_id && 0 == page_nums) { + if (ObTmpFilePageBuddy::MAX_PAGE_NUMS== start_id && 0 == page_nums) { //nothing to do - } else if (start_id < 0 || page_nums < 0) { + } else if (OB_UNLIKELY(start_id > ObTmpFilePageBuddy::MAX_PAGE_NUMS - 1 + || page_nums > ObTmpFilePageBuddy::MAX_PAGE_NUMS)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "fail to close the extent", K(ret), K(start_id), K(page_nums), K(*tmp)); } else if (OB_FAIL(free(start_id, page_nums))) { STORAGE_LOG(WARN, "fail to free the extent", K(ret)); + } else { + free_page_nums += page_nums; } if (OB_FAIL(ret)) { tmp->unclose(page_nums); is_all_close = false; + free_page_nums -= page_nums; } } else { is_all_close = false; @@ -507,7 +441,7 @@ int ObTmpMacroBlock::close(bool &is_all_close) int ObTmpMacroBlock::get_block_cache_handle(ObTmpBlockValueHandle &handle) { int ret = OB_SUCCESS; - ObTmpBlockCacheKey key(tmp_file_header_.block_id_, tmp_file_header_.tenant_id_); + ObTmpBlockCacheKey key(block_id_, tenant_id_); SpinRLockGuard guard(lock_); if (!is_disked_) { handle = handle_; @@ -524,14 +458,14 @@ int ObTmpMacroBlock::get_block_cache_handle(ObTmpBlockValueHandle &handle) int ObTmpMacroBlock::get_wash_io_info(ObTmpBlockIOInfo &info) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else { - info.block_id_ = tmp_file_header_.block_id_; + info.block_id_ = block_id_; info.offset_ = 0; - info.size_ = OB_TMP_FILE_STORE.get_block_size(); - info.tenant_id_ = tmp_file_header_.tenant_id_; + info.size_ = ObTmpMacroBlock::get_block_size(); + info.tenant_id_ = tenant_id_; info.macro_block_id_ = get_macro_block_id(); info.buf_ = buffer_; info.io_desc_ = io_desc_; @@ -542,7 +476,7 @@ int ObTmpMacroBlock::get_wash_io_info(ObTmpBlockIOInfo &info) int ObTmpMacroBlock::give_back_buf_into_cache(bool is_wash) { int ret = OB_SUCCESS; - ObTmpBlockCacheKey key(tmp_file_header_.block_id_, tmp_file_header_.tenant_id_); + ObTmpBlockCacheKey key(block_id_, tenant_id_); SpinWLockGuard guard(lock_); if (OB_FAIL(ObTmpBlockCache::get_instance().put_block(key, handle_))) { STORAGE_LOG(WARN, "fail to put block into block cache", K(ret), K(key)); @@ -555,46 +489,61 @@ int ObTmpMacroBlock::give_back_buf_into_cache(bool is_wash) int ObTmpMacroBlock::alloc_all_pages(ObTmpFileExtent &extent) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else if (OB_FAIL(page_buddy_.alloc_all_pages())) { - STORAGE_LOG(WARN, "Fail to allocate the tmp extent", K(ret), K_(tmp_file_header), K_(page_buddy)); + STORAGE_LOG(WARN, "Fail to allocate the tmp extent", K(ret), K_(block_id), K_(dir_id), K_(tenant_id), + K_(free_page_nums), K_(page_buddy)); } else { extent.set_block_id(get_block_id()); extent.set_start_page_id(0); extent.set_page_nums(ObTmpFilePageBuddy::MAX_PAGE_NUMS); extent.alloced(); - tmp_file_header_.free_page_nums_ -= extent.get_page_nums(); + free_page_nums_ -= extent.get_page_nums(); if (OB_FAIL(using_extents_.push_back(&extent))) { STORAGE_LOG(WARN, "Fail to push back into using_extexts", K(ret)); } + const int64_t cur_time = ObTimeUtility::fast_current_time(); + alloc_time_ = cur_time; + ATOMIC_STORE(&access_time_, alloc_time_ + 1); } return ret; } -int ObTmpMacroBlock::alloc(const int32_t page_nums, ObTmpFileExtent &extent) +int ObTmpMacroBlock::alloc(const uint8_t page_nums, ObTmpFileExtent &extent) { int ret = OB_SUCCESS; - int32_t start_page_id = extent.get_start_page_id(); - int32_t alloced_page_nums = 0; - if (OB_UNLIKELY(!is_inited_)) { + uint8_t start_page_id = extent.get_start_page_id(); + uint8_t alloced_page_nums = 0; + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else if (OB_FAIL(page_buddy_.alloc(page_nums, start_page_id, alloced_page_nums))) { - STORAGE_LOG(WARN, "Fail to allocate the tmp extent", K(ret), K_(tmp_file_header), K_(page_buddy)); + STORAGE_LOG(WARN, "Fail to allocate the tmp extent", K(ret), K_(block_id), K_(dir_id), K_(tenant_id), + K_(free_page_nums), K_(page_buddy)); } else { - extent.set_block_id(tmp_file_header_.block_id_); + extent.set_block_id(block_id_); extent.set_page_nums(alloced_page_nums); extent.set_start_page_id(start_page_id); extent.alloced(); - tmp_file_header_.free_page_nums_ -= alloced_page_nums; + free_page_nums_ -= alloced_page_nums; if (OB_FAIL(using_extents_.push_back(&extent))) { STORAGE_LOG(WARN, "Fail to push back into using_extexts", K(ret)); page_buddy_.free(extent.get_start_page_id(), extent.get_page_nums()); - tmp_file_header_.free_page_nums_ += extent.get_page_nums(); + free_page_nums_ += extent.get_page_nums(); extent.reset(); } + const int64_t cur_time = ObTimeUtility::fast_current_time(); + if (0 == alloc_time_) { + alloc_time_ = cur_time; + } + if (OB_UNLIKELY(0 == ATOMIC_LOAD(&access_time_))) { + ATOMIC_STORE(&access_time_, + alloc_time_ + 60 * 1000000L * int64_t(alloced_page_nums) / get_max_cont_page_nums()); + } else { + ATOMIC_STORE(&access_time_, cur_time); + } } return ret; } @@ -602,18 +551,22 @@ int ObTmpMacroBlock::alloc(const int32_t page_nums, ObTmpFileExtent &extent) int ObTmpMacroBlock::free(ObTmpFileExtent &extent) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else { page_buddy_.free(extent.get_start_page_id(), extent.get_page_nums()); - tmp_file_header_.free_page_nums_ += extent.get_page_nums(); + free_page_nums_ += extent.get_page_nums(); for (int64_t i = using_extents_.count() - 1; i >= 0; --i) { if (&extent == using_extents_.at(i)) { using_extents_.remove(i); break; } } + if (free_page_nums_ == get_mblk_page_nums()) { + alloc_time_ = 0; + ATOMIC_STORE(&access_time_, 0); + } } return ret; } @@ -621,12 +574,12 @@ int ObTmpMacroBlock::free(ObTmpFileExtent &extent) int ObTmpMacroBlock::free(const int32_t start_page_id, const int32_t page_nums) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlock has not been inited", K(ret)); } else { page_buddy_.free(start_page_id, page_nums); - tmp_file_header_.free_page_nums_ += page_nums; + free_page_nums_ += page_nums; } return ret; } @@ -637,7 +590,10 @@ void ObTmpMacroBlock::set_io_desc(const common::ObIOFlag &io_desc) } ObTmpTenantMacroBlockManager::ObTmpTenantMacroBlockManager() - : allocator_(), blocks_(), is_inited_(false) + : is_inited_(false), + next_blk_id_(0), + allocator_(), + blocks_() { } @@ -649,7 +605,7 @@ ObTmpTenantMacroBlockManager::~ObTmpTenantMacroBlockManager() int ObTmpTenantMacroBlockManager::init(common::ObIAllocator &allocator) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has been inited", K(ret)); } else if (OB_FAIL(blocks_.create(MBLK_HASH_BUCKET_NUM, ObModIds::OB_TMP_BLOCK_MAP))) { @@ -669,7 +625,7 @@ int ObTmpTenantMacroBlockManager::alloc_macro_block(const int64_t dir_id, const { int ret = OB_SUCCESS; void *block_buf = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has not been inited", K(ret)); } else if (OB_ISNULL(block_buf = allocator_->alloc(sizeof(ObTmpMacroBlock)))) { @@ -699,10 +655,10 @@ int ObTmpTenantMacroBlockManager::alloc_macro_block(const int64_t dir_id, const int ObTmpTenantMacroBlockManager::get_macro_block(const int64_t block_id, ObTmpMacroBlock *&t_mblk) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has not been inited", K(ret)); - } else if (block_id <= 0) { + } else if (OB_UNLIKELY(block_id <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id)); } else if (OB_FAIL(blocks_.get_refactored(block_id, t_mblk))) { @@ -714,10 +670,10 @@ int ObTmpTenantMacroBlockManager::get_macro_block(const int64_t block_id, ObTmpM int ObTmpTenantMacroBlockManager::free_macro_block(const int64_t block_id) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has not been inited", K(ret)); - } else if (block_id <= 0) { + } else if (OB_UNLIKELY(block_id <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id)); } else if (OB_FAIL(blocks_.erase_refactored(block_id))) { @@ -730,7 +686,7 @@ int ObTmpTenantMacroBlockManager::get_disk_macro_block_list( common::ObIArray ¯o_id_list) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has not been inited", K(ret)); } else { @@ -812,16 +768,16 @@ int64_t ObTmpTenantMacroBlockManager::get_next_blk_id() } ObTmpTenantFileStore::ObTmpTenantFileStore() - : page_cache_(NULL), + : is_inited_(false), + page_cache_num_(0), + block_cache_num_(0), + ref_cnt_(0), + page_cache_(NULL), + lock_(common::ObLatchIds::TMP_FILE_STORE_LOCK), tmp_block_manager_(), allocator_(), io_allocator_(), - tmp_mem_block_manager_(), - lock_(common::ObLatchIds::TMP_FILE_STORE_LOCK), - is_inited_(false), - page_cache_num_(0), - block_cache_num_(0), - ref_cnt_(0) + tmp_mem_block_manager_() { } @@ -850,10 +806,10 @@ int64_t ObTmpTenantFileStore::dec_ref() int ObTmpTenantFileStore::init(const uint64_t tenant_id) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); - } else if (OB_FAIL(allocator_.init(BLOCK_SIZE, ObModIds::OB_TMP_BLOCK_MANAGER, tenant_id, TOTAL_LIMIT))) { + } else if (OB_FAIL(allocator_.init(BLOCK_SIZE, ObModIds::OB_TMP_BLOCK_MANAGER, tenant_id, get_memory_limit(tenant_id)))) { STORAGE_LOG(WARN, "fail to init allocator", K(ret)); } else if (OB_FAIL(io_allocator_.init(OB_MALLOC_BIG_BLOCK_SIZE, ObModIds::OB_TMP_PAGE_CACHE, tenant_id, IO_LIMIT))) { STORAGE_LOG(WARN, "Fail to init io allocator, ", K(ret)); @@ -873,6 +829,22 @@ int ObTmpTenantFileStore::init(const uint64_t tenant_id) return ret; } +int64_t ObTmpTenantFileStore::get_memory_limit(const uint64_t tenant_id) const { + int64_t memory_limit = 0; + const int64_t lower_limit = 1 << 30; // 1G memory for 500G disk + const int64_t upper_limit = int64_t(200) * (1 << 30); // 200G memory for 100T disk + const int64_t tenant_memory_limit = lib::get_tenant_memory_limit(tenant_id) * 0.7; + if (tenant_memory_limit < lower_limit) { + memory_limit = lower_limit; + } else if (tenant_memory_limit > upper_limit) { + memory_limit = upper_limit; + } else { + memory_limit = tenant_memory_limit; + } + + return memory_limit; +} + void ObTmpTenantFileStore::destroy() { tmp_mem_block_manager_.destroy(); @@ -889,18 +861,17 @@ void ObTmpTenantFileStore::destroy() block_cache_num_ = 0; } -int ObTmpTenantFileStore::alloc(const int64_t dir_id, const uint64_t tenant_id, const int64_t size, +int ObTmpTenantFileStore::alloc(const int64_t dir_id, const uint64_t tenant_id, const int64_t alloc_size, ObTmpFileExtent &extent) { int ret = OB_SUCCESS; - int64_t alloc_size = size; - int64_t block_size = tmp_block_manager_.get_block_size(); + const int64_t block_size = tmp_block_manager_.get_block_size(); // In buddy allocation, if free space in one block isn't powers of 2, need upper align. int64_t max_order = std::ceil(std::log(ObTmpFilePageBuddy::MAX_PAGE_NUMS) / std::log(2)); int64_t origin_max_cont_page_nums = std::pow(2, max_order - 1); int64_t max_cont_size_per_block = origin_max_cont_page_nums * ObTmpMacroBlock::get_default_page_size(); ObTmpMacroBlock *t_mblk = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (alloc_size <= 0 || alloc_size > block_size) { @@ -910,25 +881,17 @@ int ObTmpTenantFileStore::alloc(const int64_t dir_id, const uint64_t tenant_id, SpinWLockGuard guard(lock_); common::ObSEArray free_blocks; if (alloc_size > max_cont_size_per_block) { - if (OB_FAIL(tmp_mem_block_manager_.try_wash(tenant_id, free_blocks))) { + if (OB_FAIL(tmp_mem_block_manager_.try_wash(free_blocks))) { STORAGE_LOG(WARN, "fail to try wash tmp macro block", K(ret), K(dir_id), K(tenant_id)); - } else if (free_blocks.count() > 0) { - for (int32_t i = free_blocks.count() - 1; OB_SUCC(ret) && i >= 0; i--) { - if (free_blocks.at(i)->is_empty()) { - if (OB_FAIL(free_macro_block(free_blocks.at(i)))) { - STORAGE_LOG(WARN, "fail to free tmp macro block", K(ret)); - } - } - free_blocks.at(i) = NULL; - } - free_blocks.reset(); + } else if (OB_FAIL(tmp_mem_block_manager_.free_empty_blocks(free_blocks))) { + STORAGE_LOG(WARN, "fail to free empty blocks", K(ret), K(dir_id), K(tenant_id)); } else if (OB_FAIL(alloc_macro_block(dir_id, tenant_id, t_mblk))) { STORAGE_LOG(WARN, "cannot allocate a tmp macro block", K(ret), K(dir_id), K(tenant_id)); - } else if (OB_FAIL(t_mblk->alloc_all_pages(extent))) { + } else if (OB_FAIL(tmp_mem_block_manager_.alloc_block_all_pages(t_mblk, extent))) { STORAGE_LOG(WARN, "Fail to allocate the tmp extent", K(ret), K(t_mblk->get_block_id())); } else { if (alloc_size < block_size) { - int64_t nums = std::ceil(alloc_size * 1.0 / ObTmpMacroBlock::get_default_page_size()); + const int64_t nums = std::ceil(alloc_size * 1.0 / ObTmpMacroBlock::get_default_page_size()); if (OB_FAIL(free_extent(t_mblk->get_block_id(), nums, ObTmpFilePageBuddy::MAX_PAGE_NUMS - nums))) { STORAGE_LOG(WARN, "fail to free pages", K(ret), K(t_mblk->get_block_id())); @@ -937,50 +900,23 @@ int ObTmpTenantFileStore::alloc(const int64_t dir_id, const uint64_t tenant_id, } } } - } else { - if (OB_FAIL(tmp_mem_block_manager_.alloc_extent(dir_id, tenant_id, alloc_size, - extent, free_blocks))) { - if (OB_ITER_END == ret) { - ret = OB_SUCCESS; - if (free_blocks.count() > 0) { - for (int32_t i = free_blocks.count() - 1; OB_SUCC(ret) && i >= 0; i--) { - if (free_blocks.at(i)->is_empty()) { - if (OB_FAIL(free_macro_block(free_blocks.at(i)))) { - STORAGE_LOG(WARN, "fail to free tmp macro block", K(ret)); - } - } - free_blocks.at(i) = NULL; - } - free_blocks.reset(); - } else if (OB_FAIL(alloc_macro_block(dir_id, tenant_id, t_mblk))) { - STORAGE_LOG(WARN, "cannot allocate a tmp macro block", K(ret), K(dir_id), K(tenant_id)); - } else if (OB_FAIL(tmp_mem_block_manager_.alloc_extent(dir_id, - tenant_id, - alloc_size, - extent, - free_blocks))) { - STORAGE_LOG(WARN, "fail to alloc tmp extent", K(ret)); - int tmp_ret = OB_SUCCESS; - if (free_blocks.count() > 0) { - for (int32_t i = free_blocks.count() - 1; OB_SUCCESS == tmp_ret && i >= 0; i--) { - if (free_blocks.at(i)->is_empty()) { - if (OB_SUCCESS != (tmp_ret = free_macro_block(free_blocks.at(i)))) { - STORAGE_LOG(WARN, "fail to free tmp macro block", K(tmp_ret)); - } - } - free_blocks.at(i) = NULL; - } - free_blocks.reset(); - } - } - } else { + } else if (OB_FAIL(tmp_mem_block_manager_.alloc_extent(dir_id, tenant_id, alloc_size, extent, free_blocks))) { + if (OB_ITER_END == ret) { + if (OB_FAIL(tmp_mem_block_manager_.free_empty_blocks(free_blocks))) { + STORAGE_LOG(WARN, "fail to free empty blocks", K(ret), K(dir_id), K(tenant_id)); + } else if (OB_FAIL(alloc_macro_block(dir_id, tenant_id, t_mblk))) { + STORAGE_LOG(WARN, "cannot allocate a tmp macro block", K(ret), K(dir_id), K(tenant_id)); + } else if (OB_FAIL(tmp_mem_block_manager_.alloc_extent(dir_id, tenant_id, alloc_size, extent, free_blocks))) { STORAGE_LOG(WARN, "fail to alloc tmp extent", K(ret)); } } } } - if (OB_FAIL(ret) && OB_ALLOCATE_MEMORY_FAILED == ret) { - STORAGE_LOG(WARN, "alloc memory failed", K(ret), K(ATOMIC_LOAD(&block_cache_num_)), K(ATOMIC_LOAD(&page_cache_num_))); + if (OB_FAIL(ret)) { + STORAGE_LOG(WARN, "fail to alloc tmp extent", K(ret)); + if (OB_ALLOCATE_MEMORY_FAILED == ret) { + STORAGE_LOG(WARN, "alloc memory failed", K(ret), K(ATOMIC_LOAD(&block_cache_num_)), K(ATOMIC_LOAD(&page_cache_num_))); + } } return ret; } @@ -989,7 +925,7 @@ int ObTmpTenantFileStore::free(ObTmpFileExtent *extent) { int ret = OB_SUCCESS; SpinWLockGuard guard(lock_); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (OB_FAIL(free_extent(extent))) { @@ -1003,7 +939,7 @@ int ObTmpTenantFileStore::free(const int64_t block_id, const int32_t start_page_ { int ret = OB_SUCCESS; SpinWLockGuard guard(lock_); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (OB_FAIL(free_extent(block_id, start_page_id, page_nums))) { @@ -1017,7 +953,7 @@ int ObTmpTenantFileStore::free_extent(ObTmpFileExtent *extent) { int ret = OB_SUCCESS; ObTmpMacroBlock *t_mblk = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (OB_ISNULL(extent) || OB_UNLIKELY(!extent->is_valid())) { @@ -1048,10 +984,10 @@ int ObTmpTenantFileStore::free_extent(const int64_t block_id, const int32_t star { int ret = OB_SUCCESS; ObTmpMacroBlock *t_mblk = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); - } else if (start_page_id < 0 || page_nums < 0 || block_id <= 0) { + } else if (OB_UNLIKELY(start_page_id < 0 || page_nums < 0 || block_id <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id), K(start_page_id), K(page_nums)); } else if (OB_FAIL(tmp_block_manager_.get_macro_block(block_id, t_mblk))) { @@ -1076,10 +1012,10 @@ int ObTmpTenantFileStore::free_extent(const int64_t block_id, const int32_t star int ObTmpTenantFileStore::free_macro_block(ObTmpMacroBlock *&t_mblk) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); - } else if (NULL == t_mblk) { + } else if (OB_ISNULL(t_mblk)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret)); } else { @@ -1114,11 +1050,11 @@ int ObTmpTenantFileStore::free_macro_block(ObTmpMacroBlock *&t_mblk) } int ObTmpTenantFileStore::alloc_macro_block(const int64_t dir_id, const uint64_t tenant_id, - ObTmpMacroBlock *&t_mblk) + ObTmpMacroBlock *&t_mblk) { int ret = OB_SUCCESS; t_mblk = nullptr; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpMacroBlockManager has not been inited", K(ret)); } else if (OB_FAIL(tmp_block_manager_.alloc_macro_block(dir_id, tenant_id, t_mblk))) { @@ -1130,7 +1066,7 @@ int ObTmpTenantFileStore::alloc_macro_block(const int64_t dir_id, const uint64_t STORAGE_LOG(WARN, "fail to alloc block cache buf", K(ret)); } else { t_mblk->set_buffer(t_mblk->get_handle().value_->get_buffer()); - if (OB_FAIL(tmp_mem_block_manager_.add_macro_block(tenant_id, t_mblk))) { + if (OB_FAIL(tmp_mem_block_manager_.add_macro_block(t_mblk))) { STORAGE_LOG(WARN, "fail to put meta into block cache", K(ret), K(t_mblk)); } inc_block_cache_num(1); @@ -1156,7 +1092,7 @@ int ObTmpTenantFileStore::read(ObTmpBlockIOInfo &io_info, ObTmpFileIOHandle &han int ret = OB_SUCCESS; ObTmpBlockValueHandle tb_handle; ObTmpMacroBlock *block = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (!handle.is_valid()) { @@ -1314,12 +1250,12 @@ int ObTmpTenantFileStore::write(const ObTmpBlockIOInfo &io_info) { int ret = OB_SUCCESS; ObTmpMacroBlock *block = NULL; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (OB_FAIL(tmp_block_manager_.get_macro_block(io_info.block_id_, block))) { STORAGE_LOG(WARN, "fail to get block from tmp block manager", K(ret), K_(io_info.block_id)); - } else if (NULL == block) { + } else if (OB_ISNULL(block)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "the block is NULL", K(ret), K_(io_info.block_id)); } else if (!block->is_disked()) { @@ -1341,11 +1277,35 @@ int ObTmpTenantFileStore::write(const ObTmpBlockIOInfo &io_info) return ret; } +int ObTmpTenantFileStore::sync(const int64_t block_id) +{ + int ret = OB_SUCCESS; + SpinWLockGuard guard(lock_); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret), K(block_id)); + } else if (OB_UNLIKELY(block_id <= 0)) { + ret = OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", K(ret), K(block_id)); + } else if (OB_FAIL(tmp_mem_block_manager_.try_sync(block_id))) { + // OB_HASH_NOT_EXIST: + // if multiple file sync same block, the block may be not exist in hash map. + // OB_STATE_NOT_MATCH: + // the extents in block may be not all close and shouldn't sync it now. + if (OB_HASH_NOT_EXIST == ret || OB_STATE_NOT_MATCH == ret) { + ret = OB_SUCCESS; + } else { + STORAGE_LOG(WARN, "sync block failed", K(ret), K(block_id)); + } + } + return ret; +} + int ObTmpTenantFileStore::get_disk_macro_block_list(common::ObIArray ¯o_id_list) { int ret = OB_SUCCESS; SpinRLockGuard guard(lock_); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpTenantFileStore has not been inited", K(ret)); } else if (OB_FAIL(tmp_block_manager_.get_disk_macro_block_list(macro_id_list))) { @@ -1412,7 +1372,10 @@ ObTmpFileStore &ObTmpFileStore::get_instance() } ObTmpFileStore::ObTmpFileStore() - : tenant_file_stores_(), lock_(common::ObLatchIds::TMP_FILE_STORE_LOCK), is_inited_(false), allocator_() + : is_inited_(false), + lock_(common::ObLatchIds::TMP_FILE_STORE_LOCK), + allocator_(), + tenant_file_stores_() { } @@ -1423,7 +1386,7 @@ ObTmpFileStore::~ObTmpFileStore() int ObTmpFileStore::init() { int ret = OB_SUCCESS; - if (OB_UNLIKELY(is_inited_)) { + if (IS_INIT) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else if (OB_FAIL(allocator_.init(TOTAL_LIMIT, HOLD_LIMIT, BLOCK_SIZE))) { @@ -1535,6 +1498,18 @@ int ObTmpFileStore::dec_page_cache_num(const uint64_t tenant_id, const int64_t n return ret; } +int ObTmpFileStore::sync(const uint64_t tenant_id, const int64_t block_id) +{ + int ret = OB_SUCCESS; + ObTmpTenantFileStoreHandle store_handle; + if (OB_FAIL(get_store(tenant_id, store_handle))) { + STORAGE_LOG(WARN, "fail to get tmp tenant file store", K(ret), K(tenant_id), K(block_id)); + } else if (OB_FAIL(store_handle.get_tenant_store()->sync(block_id))) { + STORAGE_LOG(WARN, "fail to write the extent", K(ret), K(tenant_id), K(block_id)); + } + return ret; +} + int ObTmpFileStore::free(const uint64_t tenant_id, ObTmpFileExtent *extent) { int ret = OB_SUCCESS; @@ -1577,7 +1552,7 @@ int ObTmpFileStore::free_tenant_file_store(const uint64_t tenant_id) int ObTmpFileStore::get_macro_block_list(common::ObIArray ¯o_id_list) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else { @@ -1600,7 +1575,7 @@ int ObTmpFileStore::get_macro_block_list(common::ObIArray ¯o_i int ObTmpFileStore::get_macro_block_list(ObIArray &tmp_block_cnt_pairs) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else { @@ -1631,7 +1606,7 @@ int ObTmpFileStore::get_macro_block_list(ObIArray &tmp_bl int ObTmpFileStore::get_all_tenant_id(common::ObIArray &tenant_ids) { int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret)); } else { @@ -1656,7 +1631,7 @@ int ObTmpFileStore::get_store(const uint64_t tenant_id, ObTmpTenantFileStoreHand int ret = OB_SUCCESS; void *buf = NULL; handle.reset(); - if (OB_UNLIKELY(!is_inited_)) { + if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObTmpFileStore has not been inited", K(ret), K(tenant_id)); } else { diff --git a/src/storage/blocksstable/ob_tmp_file_store.h b/src/storage/blocksstable/ob_tmp_file_store.h index b7e8df28f4..5e7cdb7ab4 100644 --- a/src/storage/blocksstable/ob_tmp_file_store.h +++ b/src/storage/blocksstable/ob_tmp_file_store.h @@ -31,119 +31,99 @@ struct ObTmpBlockValueHandle; class ObTmpTenantBlockCache; class ObTmpPageCache; -typedef common::ObSEArray ExtentArray; +typedef common::ObSEArray ExtentArray; -struct ObTmpFileArea +struct ObTmpFileArea final { public: - ObTmpFileArea(const int64_t start_page_id, const int64_t page_nums) + ObTmpFileArea(const uint8_t &start_page_id, const uint8_t &page_nums) : start_page_id_(start_page_id), page_nums_(page_nums), next_(NULL) {} - virtual ~ObTmpFileArea() + ~ObTmpFileArea() { start_page_id_ = 0; page_nums_ = 0; next_ = NULL; } TO_STRING_KV(K_(start_page_id), K_(page_nums)); - int32_t start_page_id_; - int32_t page_nums_; + uint8_t start_page_id_; + uint8_t page_nums_; ObTmpFileArea *next_; -}; +} __attribute__((packed, __aligned__(1)));; -class ObTmpFilePageBuddy +class ObTmpFilePageBuddy final { public: ObTmpFilePageBuddy(); - virtual ~ObTmpFilePageBuddy(); + ~ObTmpFilePageBuddy(); int init(common::ObIAllocator &allocator); void destroy(); int alloc_all_pages(); - int alloc(const int32_t page_nums, int32_t &start_page_id, int32_t &alloced_page_nums); + int alloc(const uint8_t page_nums, uint8_t &start_page_id, uint8_t &alloced_page_nums); void free(const int32_t start_page_id, const int32_t page_nums); - OB_INLINE int64_t get_max_cont_page_nums() const { return max_cont_page_nums_; } + OB_INLINE uint8_t get_max_cont_page_nums() const { return max_cont_page_nums_; } bool is_inited() { return is_inited_; } bool is_empty() const; int64_t to_string(char* buf, const int64_t buf_len) const; - static const int64_t MAX_PAGE_NUMS = 252; // 2^MAX_ORDER - 2^MIN_ORDER + static const uint8_t MAX_PAGE_NUMS = 252; // 2^MAX_ORDER - 2^MIN_ORDER, uint8_t is only for < 256 private: void free_align(const int32_t start_page_id, const int32_t page_nums, ObTmpFileArea *&area); ObTmpFileArea *find_buddy(const int32_t page_nums, const int32_t start_page_id); private: - static const int MIN_ORDER = 2; - static const int MAX_ORDER = 8; - ObTmpFileArea *free_area_[ObTmpFilePageBuddy::MAX_ORDER]; - int64_t max_cont_page_nums_; + static const uint8_t MIN_ORDER = 2; + static const uint8_t MAX_ORDER = 8; + bool is_inited_; + uint8_t max_cont_page_nums_; ObTmpFileArea *buf_; common::ObIAllocator *allocator_; - bool is_inited_; + ObTmpFileArea *free_area_[ObTmpFilePageBuddy::MAX_ORDER]; DISALLOW_COPY_AND_ASSIGN(ObTmpFilePageBuddy); }; -struct ObTmpFileMacroBlockHeader final -{ -public: - ObTmpFileMacroBlockHeader(); - ~ObTmpFileMacroBlockHeader() = default; - bool is_valid() const; - int serialize(char *buf, const int64_t buf_len, int64_t &pos) const; - int deserialize(const char *buf, const int64_t data_len, int64_t &pos); - static int64_t get_serialize_size() { return sizeof(ObTmpFileMacroBlockHeader); } - void reset(); - - TO_STRING_KV(K_(version), K_(magic), K_(block_id), K_(dir_id), K_(tenant_id), K_(free_page_nums)); -private: - static const int32_t TMP_FILE_MACRO_BLOCK_HEADER_VERSION = 1; - static const int32_t TMP_FILE_MACRO_BLOCK_HEADER_MAGIC = 20720; -public: - int32_t version_; - int32_t magic_; - int64_t block_id_; - int64_t dir_id_; - uint64_t tenant_id_; - int64_t free_page_nums_; -}; - -struct ObTmpBlockIOInfo +struct ObTmpBlockIOInfo final { public: ObTmpBlockIOInfo() : block_id_(0), offset_(0), size_(0), tenant_id_(0), - macro_block_id_(), buf_(NULL), io_desc_() {} + buf_(NULL), io_desc_(), macro_block_id_() {} ObTmpBlockIOInfo(const int64_t block_id, const int64_t offset, const int64_t size, const uint64_t tenant_id, const MacroBlockId macro_block_id, char *buf, const common::ObIOFlag io_desc) : block_id_(block_id), offset_(offset), size_(size), tenant_id_(tenant_id), - macro_block_id_(macro_block_id), buf_(buf), io_desc_(io_desc) {} + buf_(buf), io_desc_(io_desc), macro_block_id_(macro_block_id) {} TO_STRING_KV(K_(block_id), K_(offset), K_(size), K_(tenant_id), K_(macro_block_id), KP_(buf), K_(io_desc)); int64_t block_id_; int64_t offset_; int64_t size_; uint64_t tenant_id_; - MacroBlockId macro_block_id_; char *buf_; common::ObIOFlag io_desc_; + MacroBlockId macro_block_id_; }; -class ObTmpMacroBlock +class ObTmpMacroBlock final { public: ObTmpMacroBlock(); - virtual ~ObTmpMacroBlock(); + ~ObTmpMacroBlock(); int init(const int64_t block_id, const int64_t dir_id, const uint64_t tenant_id, common::ObIAllocator &allocator); void destroy(); int alloc_all_pages(ObTmpFileExtent &extent); - int alloc(const int32_t page_nums, ObTmpFileExtent &extent); + int alloc(const uint8_t page_nums, ObTmpFileExtent &extent); int free(ObTmpFileExtent &extent); int free(const int32_t start_page_id, const int32_t page_nums); OB_INLINE void set_buffer(char *buf) { buffer_ = buf; } OB_INLINE char *get_buffer() { return buffer_; } - OB_INLINE int64_t get_max_cont_page_nums() const { return page_buddy_.get_max_cont_page_nums(); } - OB_INLINE int64_t get_free_page_nums() const { return tmp_file_header_.free_page_nums_; } + OB_INLINE uint8_t get_max_cont_page_nums() const { return page_buddy_.get_max_cont_page_nums(); } + OB_INLINE uint8_t get_free_page_nums() const { return free_page_nums_; } + OB_INLINE int64_t get_used_page_nums() const + { + return get_mblk_page_nums() - free_page_nums_; + } int get_block_cache_handle(ObTmpBlockValueHandle &handle); int get_wash_io_info(ObTmpBlockIOInfo &info); void set_io_desc(const common::ObIOFlag &io_desc); @@ -161,41 +141,62 @@ public: { return 4 * DEFAULT_PAGE_SIZE; } - OB_INLINE int64_t get_block_id() const { return tmp_file_header_.block_id_; } + OB_INLINE int64_t get_block_id() const { return block_id_; } OB_INLINE const MacroBlockId& get_macro_block_id() const { return macro_block_handle_.get_macro_id(); } OB_INLINE ObMacroBlockHandle &get_macro_block_handle() { return macro_block_handle_; } - OB_INLINE const ObTmpFileMacroBlockHeader &get_tmp_block_header() const { return tmp_file_header_; } - OB_INLINE uint64_t get_tenant_id() const { return tmp_file_header_.tenant_id_; } - OB_INLINE int64_t get_dir_id() const { return tmp_file_header_.dir_id_; } + OB_INLINE int64_t get_alloc_time() const { return alloc_time_; } + OB_INLINE int64_t get_access_time() const { return ATOMIC_LOAD(&access_time_); } + OB_INLINE uint64_t get_tenant_id() const { return tenant_id_; } + OB_INLINE int64_t get_dir_id() const { return dir_id_; } common::ObIArray &get_extents() { return using_extents_; } ObTmpBlockValueHandle &get_handle() { return handle_; } bool is_empty() const { return page_buddy_.is_empty(); } - int close(bool &is_all_close); + int close(bool &is_all_close, uint8_t &free_page_nums); int give_back_buf_into_cache(bool is_wash = false); + OB_INLINE double get_wash_score(int64_t cur_time) const { + if (get_free_page_nums() == 0) { + return INT64_MAX; + } + return (double) get_used_page_nums() * (cur_time - get_alloc_time()) / (get_access_time() - get_alloc_time()); + } - TO_STRING_KV(KP_(buffer), K_(page_buddy), K_(handle), K_(macro_block_handle), K_(tmp_file_header), - K_(io_desc), K_(is_washing), K_(is_disked), K_(is_inited)); + static int64_t get_mblk_page_nums() + { + return ObTmpFilePageBuddy::MAX_PAGE_NUMS; + } + static int64_t get_block_size() + { + return get_mblk_page_nums() * ObTmpMacroBlock::get_default_page_size(); + } + + TO_STRING_KV(KP_(buffer), K_(page_buddy), K_(handle), K_(macro_block_handle), K_(block_id), K_(dir_id), K_(tenant_id), + K_(free_page_nums), K_(io_desc), K_(is_washing), K_(is_disked), K_(is_inited), K_(alloc_time), K_(access_time)); private: static const int64_t DEFAULT_PAGE_SIZE; - char *buffer_; - ObTmpFilePageBuddy page_buddy_; - ObTmpBlockValueHandle handle_; - ExtentArray using_extents_; - ObMacroBlockHandle macro_block_handle_; - ObTmpFileMacroBlockHeader tmp_file_header_; - common::ObIOFlag io_desc_; - common::SpinRWLock lock_; + bool is_inited_; bool is_washing_; bool is_disked_; - bool is_inited_; + uint8_t free_page_nums_; + char *buffer_; + int64_t block_id_; + int64_t dir_id_; + uint64_t tenant_id_; + int64_t alloc_time_; + int64_t access_time_; + common::ObIOFlag io_desc_; + common::SpinRWLock lock_; + ObMacroBlockHandle macro_block_handle_; + ObTmpBlockValueHandle handle_; + ObTmpFilePageBuddy page_buddy_; + ExtentArray using_extents_; DISALLOW_COPY_AND_ASSIGN(ObTmpMacroBlock); }; -class ObTmpTenantMacroBlockManager +class ObTmpTenantMacroBlockManager final { public: ObTmpTenantMacroBlockManager(); - virtual ~ObTmpTenantMacroBlockManager(); + ~ObTmpTenantMacroBlockManager(); int init(common::ObIAllocator &allocator); void destroy(); int alloc_macro_block(const int64_t dir_id, const uint64_t tenant_id, ObTmpMacroBlock *&t_mblk); @@ -214,10 +215,10 @@ private: static const uint64_t MBLK_HASH_BUCKET_NUM = 10243L; typedef common::hash::ObHashMap TmpMacroBlockMap; + bool is_inited_; + int64_t next_blk_id_; common::ObIAllocator *allocator_; TmpMacroBlockMap blocks_; // all of block meta. - static int64_t next_blk_id_; - bool is_inited_; DISALLOW_COPY_AND_ASSIGN(ObTmpTenantMacroBlockManager); }; @@ -229,12 +230,13 @@ public: ~ObTmpTenantFileStore(); int init(const uint64_t tenant_id); void destroy(); - int alloc(const int64_t dir_id, const uint64_t tenant_id, const int64_t size, + int alloc(const int64_t dir_id, const uint64_t tenant_id, const int64_t alloc_size, ObTmpFileExtent &extent); int free(ObTmpFileExtent *extent); int free(const int64_t block_id, const int32_t start_page_id, const int32_t page_nums); int read(ObTmpBlockIOInfo &io_info, ObTmpFileIOHandle &handle); int write(const ObTmpBlockIOInfo &io_info); + int sync(const int64_t block_id); int get_disk_macro_block_list(common::ObIArray ¯o_id_list); void print_block_usage() { tmp_block_manager_.print_block_usage(); } OB_INLINE int64_t get_block_size() const { return tmp_block_manager_.get_block_size(); } @@ -260,6 +262,7 @@ private: int free_macro_block(ObTmpMacroBlock *&t_mblk); int alloc_macro_block(const int64_t dir_id, const uint64_t tenant_id, ObTmpMacroBlock *&t_mblk); int wait_write_io_finish_if_need(); + int64_t get_memory_limit(const uint64_t tenant_id) const; private: static const uint64_t IO_LIMIT = 4 * 1024L * 1024L * 1024L; @@ -268,16 +271,16 @@ private: static const uint64_t BLOCK_SIZE = common::OB_MALLOC_MIDDLE_BLOCK_SIZE; static constexpr double DEFAULT_PAGE_IO_MERGE_RATIO = 0.5; - ObTmpPageCache *page_cache_; - ObTmpTenantMacroBlockManager tmp_block_manager_; - common::ObConcurrentFIFOAllocator allocator_; - common::ObConcurrentFIFOAllocator io_allocator_; - ObTmpTenantMemBlockManager tmp_mem_block_manager_; - common::SpinRWLock lock_; bool is_inited_; int64_t page_cache_num_; int64_t block_cache_num_; volatile int64_t ref_cnt_; + ObTmpPageCache *page_cache_; + common::SpinRWLock lock_; + ObTmpTenantMacroBlockManager tmp_block_manager_; + common::ObConcurrentFIFOAllocator allocator_; + common::ObConcurrentFIFOAllocator io_allocator_; + ObTmpTenantMemBlockManager tmp_mem_block_manager_; DISALLOW_COPY_AND_ASSIGN(ObTmpTenantFileStore); }; @@ -301,7 +304,7 @@ private: }; -class ObTmpFileStore +class ObTmpFileStore final { public: typedef common::hash::HashMapPair TenantTmpBlockCntPair; @@ -314,6 +317,7 @@ public: ObTmpFileExtent &extent); int read(const uint64_t tenant_id, ObTmpBlockIOInfo &io_info, ObTmpFileIOHandle &handle); int write(const uint64_t tenant_id, const ObTmpBlockIOInfo &io_info); + int sync(const uint64_t tenant_id, const int64_t block_id); int free(const uint64_t tenant_id, ObTmpFileExtent *extent); int free(const uint64_t tenant_id, const int64_t block_id, const int32_t start_page_id, const int32_t page_nums); @@ -332,7 +336,7 @@ public: int dec_block_cache_num(const uint64_t tenant_id, const int64_t num); private: ObTmpFileStore(); - virtual ~ObTmpFileStore(); + ~ObTmpFileStore(); int get_store(const uint64_t tenant_id, ObTmpTenantFileStoreHandle &handle); private: @@ -344,10 +348,10 @@ private: static const int TMP_FILE_BLOCK_CACHE_PRIORITY = 1; typedef common::hash::ObHashMap TenantFileStoreMap; - TenantFileStoreMap tenant_file_stores_; - common::SpinRWLock lock_; bool is_inited_; + common::SpinRWLock lock_; common::ObConcurrentFIFOAllocator allocator_; + TenantFileStoreMap tenant_file_stores_; }; #define OB_TMP_FILE_STORE (::oceanbase::blocksstable::ObTmpFileStore::get_instance()) diff --git a/src/storage/ddl/ob_ddl_heart_beat_task.cpp b/src/storage/ddl/ob_ddl_heart_beat_task.cpp new file mode 100644 index 0000000000..f81ee5c803 --- /dev/null +++ b/src/storage/ddl/ob_ddl_heart_beat_task.cpp @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX STORAGE + +#include "ob_ddl_heart_beat_task.h" +#include "lib/oblog/ob_log_module.h" +#include "share/ob_common_rpc_proxy.h" + + +namespace oceanbase +{ +namespace storage +{ +ObRedefTableHeartBeatTask::ObRedefTableHeartBeatTask() : is_inited_(false) {} + +int ObRedefTableHeartBeatTask::init(const int tg_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(is_inited_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ObReDefTableHeartBeatTask has a already been inited", K(ret)); + } else if (OB_FAIL(TG_SCHEDULE(tg_id, *this, HEARTBEAT_INTERVAL, true))) { + LOG_WARN("fail to schedule task ObReDefTableHeartBeatTask", K(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +void ObRedefTableHeartBeatTask::runTimerTask() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObReDefTableHeartBeatTask has not been inited", K(ret)); + } else if (OB_FAIL(send_task_status_to_rs())) { + LOG_WARN("send to rs all task status failed", KR(ret)); + } else { + LOG_INFO("send to rs all task status succeed"); + } +} + +int ObRedefTableHeartBeatTask::send_task_status_to_rs() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.send_task_status_to_rs())) { + LOG_WARN("failed to send task status to RS", K(ret)); + } + return ret; +} + +ObDDLHeartBeatTaskContainer::ObDDLHeartBeatTaskContainer() : is_inited_(false), bucket_lock_() {} +ObDDLHeartBeatTaskContainer::~ObDDLHeartBeatTaskContainer() +{ + bucket_lock_.destroy(); +} +int ObDDLHeartBeatTaskContainer::init() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(is_inited_)) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDDLHeartBeatTaskContainer inited twice", K(ret)); + } else if (OB_FAIL(register_tasks_.create(BUCKET_LOCK_BUCKET_CNT, "register_tasks", "register_tasks"))) { + LOG_WARN("failed to create register_tasks map", K(ret)); + } else if (OB_FAIL(bucket_lock_.init(BUCKET_LOCK_BUCKET_CNT))) { + LOG_WARN("failed to init bucket lock", K(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObDDLHeartBeatTaskContainer::set_register_task_id(const int64_t task_id, const uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLHeartBeatTaskContainer not inited", K(ret)); + } else { + ObBucketHashWLockGuard lock_guard(bucket_lock_, task_id); + if (OB_FAIL(register_tasks_.set_refactored(task_id, tenant_id))) { + LOG_ERROR("set register task id failed", KR(ret)); + } + } + return ret; +} + +int ObDDLHeartBeatTaskContainer::remove_register_task_id(const int64_t task_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLHeartBeatTaskContainer not inited", K(ret)); + } else { + ObBucketHashWLockGuard lock_guard(bucket_lock_, task_id); + if (OB_FAIL(register_tasks_.erase_refactored(task_id))) { + LOG_ERROR("remove register task id failed", KR(ret)); + } + } + return ret; +} + +int ObDDLHeartBeatTaskContainer::send_task_status_to_rs() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDDLHeartBeatTaskContainer not inited", K(ret)); + } else { + int64_t cnt = 0; + ObArray heart_beart_task_infos; + while (OB_SUCC(ret) && cnt < RETRY_COUNT) { + ObBucketTryRLockAllGuard all_reg_task_guard(bucket_lock_); + if (OB_FAIL(all_reg_task_guard.get_ret())) { + if (OB_EAGAIN == ret) { + cnt++; + LOG_INFO("all reg task guard failed, plase try again, retry count: ", K(cnt)); + ret = OB_SUCCESS; + sleep(RETRY_TIME_INTERVAL); + } + } else { + for (common::hash::ObHashMap::iterator it = register_tasks_.begin(); OB_SUCC(ret) && it != register_tasks_.end(); it++) { + int64_t task_id = it->first; + uint64_t tenant_id = it->second; + if (OB_FAIL(heart_beart_task_infos.push_back(ObDDLHeartBeatTaskInfo(task_id, tenant_id)))) { + LOG_WARN("task_ids push_back failed", K(ret)); + } + } + break; + } + } + if (OB_SUCC(ret)) { + for (int64_t i = 0; OB_SUCC(ret) && i < heart_beart_task_infos.count(); i++) { + ObDDLHeartBeatTaskInfo heart_beart_task_info; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + obrpc::ObUpdateDDLTaskActiveTimeArg arg; + if (OB_FAIL(heart_beart_task_infos.at(i, heart_beart_task_info))) { + LOG_WARN("get task id failed", K(ret)); + } else { + int64_t task_id = heart_beart_task_info.get_task_id(); + uint64_t tenant_id = heart_beart_task_info.get_tenant_id(); + arg.task_id_ = task_id; + arg.tenant_id_ = tenant_id; + if (OB_FAIL(common_rpc_proxy->update_ddl_task_active_time(arg))) { + LOG_WARN("send to task status fail", K(ret)); + } + } + } + } + } + return ret; +} + +} // end of namespace storage +} // end of namespace oceanbase \ No newline at end of file diff --git a/src/storage/ddl/ob_ddl_heart_beat_task.h b/src/storage/ddl/ob_ddl_heart_beat_task.h new file mode 100644 index 0000000000..c4ac857af4 --- /dev/null +++ b/src/storage/ddl/ob_ddl_heart_beat_task.h @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_STORAGE_OB_DDL_HEART_BEAT_TASK_H +#define OCEANBASE_STORAGE_OB_DDL_HEART_BEAT_TASK_H + +#include "observer/ob_server_struct.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDDLHeartBeatTaskInfo final +{ +public: + TO_STRING_KV(K_(task_id), + K_(tenant_id)); + ObDDLHeartBeatTaskInfo() : task_id_(0), tenant_id_(OB_INVALID_ID) {}; + ObDDLHeartBeatTaskInfo(int64_t task_id, uint64_t tenant_id) : task_id_(task_id), tenant_id_(tenant_id) {} + ~ObDDLHeartBeatTaskInfo() = default; + inline int64_t get_task_id() {return task_id_;} + inline uint64_t get_tenant_id() {return tenant_id_;} + inline void set_task_id(int64_t task_id) {task_id_ = task_id;} + inline void set_tenant_id(uint64_t tenant_id) {tenant_id_ = tenant_id;} +private: + int64_t task_id_; + uint64_t tenant_id_; +}; +class ObDDLHeartBeatTaskContainer final +{ +public: + static ObDDLHeartBeatTaskContainer &get_instance(); + ObDDLHeartBeatTaskContainer(); + ~ObDDLHeartBeatTaskContainer(); + int init(); + int set_register_task_id(const int64_t task_id, const uint64_t tenant_id); + int remove_register_task_id(const int64_t task_id); + int send_task_status_to_rs(); +private: + static const int64_t BUCKET_LOCK_BUCKET_CNT = 10243L; + static const int64_t RETRY_COUNT = 3L; + static const int64_t RETRY_TIME_INTERVAL = 100L; + common::hash::ObHashMap register_tasks_; + bool is_inited_; + common::ObBucketLock bucket_lock_; +}; + +class ObRedefTableHeartBeatTask : public common::ObTimerTask +{ +public: + ObRedefTableHeartBeatTask(); + virtual ~ObRedefTableHeartBeatTask() = default; + int init(const int tg_id); + virtual void runTimerTask() override; +private: + int send_task_status_to_rs(); +private: + const static int64_t HEARTBEAT_INTERVAL = 30L * 1000L * 1000L;//30s + bool is_inited_; +}; + +inline ObDDLHeartBeatTaskContainer &ObDDLHeartBeatTaskContainer::get_instance() +{ + static ObDDLHeartBeatTaskContainer THE_ONE; + return THE_ONE; +} + +} // end of namespace observer +} // end of namespace oceanbase + +#define OB_DDL_HEART_BEAT_TASK_CONTAINER (::oceanbase::storage::ObDDLHeartBeatTaskContainer::get_instance()) + +#endif /*_OCEANBASE_STORAGE_OB_DDL_HEART_BEAT_TASK_H_ */ \ No newline at end of file diff --git a/src/storage/ddl/ob_ddl_merge_task.cpp b/src/storage/ddl/ob_ddl_merge_task.cpp index dbae07ffa2..590d5f0b8c 100644 --- a/src/storage/ddl/ob_ddl_merge_task.cpp +++ b/src/storage/ddl/ob_ddl_merge_task.cpp @@ -357,15 +357,17 @@ int ObDDLTableMergeTask::process() ObTabletDDLParam ddl_param; ObTableHandleV2 table_handle; bool is_data_complete = false; - const ObSSTable *latest_major_sstable = nullptr; - if (OB_FAIL(ObTabletDDLUtil::check_and_get_major_sstable(merge_param_.ls_id_, merge_param_.tablet_id_, latest_major_sstable))) { - LOG_WARN("check if major sstable exist failed", K(ret)); - } else if (nullptr != latest_major_sstable) { - LOG_INFO("major sstable has been created before", K(merge_param_), K(ddl_param.table_key_)); - sstable = static_cast(tablet_handle.get_obj()->get_table_store().get_major_sstables().get_boundary_table(false/*first*/)); - } else if (tablet_handle.get_obj()->get_tablet_meta().table_store_flag_.with_major_sstable()) { - skip_major_process = true; - LOG_INFO("tablet me says with major but no major, meaning its a migrated deleted tablet, skip"); + if (ddl_sstable_handles.empty()) { + const ObSSTable *latest_major_sstable = nullptr; + if (OB_FAIL(ObTabletDDLUtil::check_and_get_major_sstable(merge_param_.ls_id_, merge_param_.tablet_id_, latest_major_sstable))) { + LOG_WARN("check if major sstable exist failed", K(ret)); + } else if (nullptr != latest_major_sstable) { + LOG_INFO("major sstable has been created before", K(merge_param_), K(ddl_param.table_key_)); + sstable = static_cast(tablet_handle.get_obj()->get_table_store().get_major_sstables().get_boundary_table(false/*first*/)); + } else if (tablet_handle.get_obj()->get_tablet_meta().table_store_flag_.with_major_sstable()) { + skip_major_process = true; + LOG_INFO("tablet me says with major but no major, meaning its a migrated deleted tablet, skip"); + } } else if (OB_FAIL(ddl_kv_mgr_handle.get_obj()->get_ddl_param(ddl_param))) { LOG_WARN("get tablet ddl param failed", K(ret)); } else if (merge_param_.start_scn_ > SCN::min_scn() && merge_param_.start_scn_ < ddl_param.start_scn_) { diff --git a/src/storage/ddl/ob_ddl_server_client.cpp b/src/storage/ddl/ob_ddl_server_client.cpp new file mode 100644 index 0000000000..b8b5709254 --- /dev/null +++ b/src/storage/ddl/ob_ddl_server_client.cpp @@ -0,0 +1,236 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX STORAGE + +#include "ob_ddl_server_client.h" +#include "observer/ob_server_struct.h" +#include "share/ob_common_rpc_proxy.h" +#include "share/ob_ddl_common.h" +#include "storage/ddl/ob_ddl_heart_beat_task.h" +#include "lib/ob_define.h" +#include "lib/mysqlclient/ob_isql_client.h" +#include "sql/engine/cmd/ob_ddl_executor_util.h" + +namespace oceanbase +{ +namespace storage +{ + +int ObDDLServerClient::create_hidden_table(const obrpc::ObCreateHiddenTableArg &arg, obrpc::ObCreateHiddenTableRes &res, sql::ObSQLSessionInfo &session) +{ + int ret = OB_SUCCESS; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else if (OB_FAIL(common_rpc_proxy->timeout(GCONF._ob_ddl_timeout).create_hidden_table(arg, res))) { + LOG_WARN("failed to create hidden table", KR(ret), K(arg)); + } else if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.set_register_task_id(res.task_id_, res.tenant_id_))) { + LOG_WARN("failed to set register task id", K(ret), K(res)); + } else if (OB_FAIL(wait_table_lock(arg.tenant_id_, res.task_id_, *GCTX.sql_proxy_, session))) { + LOG_WARN("failed to wait table lock. remove register task id and abort redef table task.", K(ret), K(arg), K(res)); + int tmp_ret = ret; + if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.remove_register_task_id(res.task_id_))) { + LOG_ERROR("failed to remove register task id", K(ret), K(res)); + } else { + obrpc::ObAbortRedefTableArg abort_redef_table_arg; + abort_redef_table_arg.task_id_ = res.task_id_; + abort_redef_table_arg.tenant_id_ = arg.tenant_id_; + if (OB_FAIL(abort_redef_table(abort_redef_table_arg))) { + LOG_WARN("failed to abort redef table", K(ret), K(abort_redef_table_arg)); + } + } + ret = tmp_ret; + } + return ret; +} + +int ObDDLServerClient::start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res, sql::ObSQLSessionInfo &session) +{ + int ret = OB_SUCCESS; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else if (OB_FAIL(common_rpc_proxy->start_redef_table(arg, res))) { + LOG_WARN("failed to start redef table", KR(ret), K(arg)); + } else if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.set_register_task_id(res.task_id_, res.tenant_id_))) { + LOG_WARN("failed to set register task id", K(ret), K(res)); + } else if (OB_FAIL(wait_table_lock(arg.orig_tenant_id_, res.task_id_, *GCTX.sql_proxy_, session))) { + LOG_WARN("failed to wait table lock. remove register task id and abort redef table task.", K(ret), K(arg), K(res)); + int tmp_ret = ret; + if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.remove_register_task_id(res.task_id_))) { + LOG_ERROR("failed to remove register task id", K(ret), K(res)); + } else { + obrpc::ObAbortRedefTableArg abort_redef_table_arg; + abort_redef_table_arg.task_id_ = res.task_id_; + abort_redef_table_arg.tenant_id_ = arg.orig_tenant_id_; + if (OB_FAIL(abort_redef_table(abort_redef_table_arg))) { + LOG_WARN("failed to abort redef table", K(ret), K(abort_redef_table_arg)); + } + } + ret = tmp_ret; + } + return ret; +} + +int ObDDLServerClient::copy_table_dependents(const obrpc::ObCopyTableDependentsArg &arg) +{ + int ret = OB_SUCCESS; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else if (OB_FAIL(common_rpc_proxy->copy_table_dependents(arg))) { + LOG_WARN("failed to copy table dependents", KR(ret), K(arg)); + } + return ret; +} + +int ObDDLServerClient::abort_redef_table(const obrpc::ObAbortRedefTableArg &arg) +{ + int ret = OB_SUCCESS; + const int64_t retry_interval = 100 * 1000L; + ObAddr rs_leader_addr; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else { + while (OB_SUCC(ret)) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(GCTX.rs_mgr_->get_master_root_server(rs_leader_addr))) { + LOG_WARN("fail to get rootservice address", K(tmp_ret)); + } else if (OB_FAIL(common_rpc_proxy->to(rs_leader_addr).abort_redef_table(arg))) { + if (OB_ENTRY_NOT_EXIST == ret) { + break; + } else { + ret = OB_SUCCESS; + ob_usleep(retry_interval); + } + } else { + LOG_INFO("abort task success"); + break; + } + } + if (OB_ENTRY_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } + if (OB_SUCC(ret)) { + if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.remove_register_task_id(arg.task_id_))) { + if (OB_HASH_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } else { + LOG_ERROR("failed to remove register task id", K(ret), K(arg)); + } + } + } + } + return ret; +} + +int ObDDLServerClient::finish_redef_table(const obrpc::ObFinishRedefTableArg &arg) +{ + int ret = OB_SUCCESS; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else if (OB_FAIL(common_rpc_proxy->finish_redef_table(arg))) { + LOG_WARN("failed to finish redef table", K(ret), K(arg)); + } else if (OB_FAIL(OB_DDL_HEART_BEAT_TASK_CONTAINER.remove_register_task_id(arg.task_id_))) { + LOG_ERROR("failed to remove register task id", K(ret), K(arg)); + } + return ret; +} + +int ObDDLServerClient::build_ddl_single_replica_response(const obrpc::ObDDLBuildSingleReplicaResponseArg &arg) +{ + int ret = OB_SUCCESS; + obrpc::ObCommonRpcProxy *common_rpc_proxy = GCTX.rs_rpc_proxy_; + if (OB_UNLIKELY(!arg.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", K(ret), K(arg)); + } else if (OB_ISNULL(common_rpc_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("common rpc proxy is null", K(ret)); + } else if (OB_FAIL(common_rpc_proxy->build_ddl_single_replica_response(arg))) { + LOG_WARN("failed to finish redef table", K(ret), K(arg)); + } + return ret; +} + +int ObDDLServerClient::wait_table_lock(const uint64_t tenant_id, const int64_t task_id, ObMySQLProxy &sql_proxy, sql::ObSQLSessionInfo &session) +{ + int ret = OB_SUCCESS; + const int64_t retry_interval = 100 * 1000; + ObSqlString sql_string; + THIS_WORKER.set_timeout_ts(ObTimeUtility::current_time() + OB_MAX_USER_SPECIFIED_TIMEOUT); + SMART_VAR(ObMySQLProxy::MySQLResult, res) { + sqlclient::ObMySQLResult *result = NULL; + if (OB_UNLIKELY(task_id <= 0 || OB_INVALID_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(task_id), K(tenant_id)); + } else { + while (OB_SUCC(ret)) { + if (OB_FAIL(sql_string.assign_fmt("SELECT status FROM %s WHERE task_id = %lu", share::OB_ALL_DDL_TASK_STATUS_TNAME, task_id))) { + LOG_WARN("assign sql string failed", K(ret), K(task_id)); + } else if (OB_FAIL(sql_proxy.read(res, tenant_id, sql_string.ptr()))) { + LOG_WARN("fail to execute sql", K(ret), K(sql_string)); + } else if (OB_ISNULL(result = res.get_result())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error unexpected, query result must not be NULL", K(ret)); + } else if (OB_FAIL(result->next())) { + if (OB_LIKELY(OB_ITER_END == ret)) { + ret = OB_ENTRY_NOT_EXIST; + } else { + LOG_WARN("fail to get next row", K(ret)); + } + } else { + int task_status = 0; + EXTRACT_INT_FIELD_MYSQL(*result, "status", task_status, int); + if (share::ObDDLTaskStatus::REPENDING != static_cast(task_status)) { + LOG_INFO("task status not equal REPENDING, Please Keep Waiting", K(task_status)); + if (OB_FAIL(sql::ObDDLExecutorUtil::handle_session_exception(session))) { + break; + } else { + ob_usleep(retry_interval); + } + } else { + break; + } + } + } + } + } + return ret; +} + + +} // end of namespace storage +} // end of namespace oceanbase diff --git a/src/storage/ddl/ob_ddl_server_client.h b/src/storage/ddl/ob_ddl_server_client.h new file mode 100644 index 0000000000..d20a61546c --- /dev/null +++ b/src/storage/ddl/ob_ddl_server_client.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_STORAGE_OB_DDL_SERVER_CLIENT_H +#define OCEANBASE_STORAGE_OB_DDL_SERVER_CLIENT_H + +#include "share/ob_rpc_struct.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDDLServerClient final +{ +public: + static int create_hidden_table(const obrpc::ObCreateHiddenTableArg &arg, obrpc::ObCreateHiddenTableRes &res, sql::ObSQLSessionInfo &session); + static int start_redef_table(const obrpc::ObStartRedefTableArg &arg, obrpc::ObStartRedefTableRes &res, sql::ObSQLSessionInfo &session); + static int copy_table_dependents(const obrpc::ObCopyTableDependentsArg &arg); + static int finish_redef_table(const obrpc::ObFinishRedefTableArg &arg); + static int abort_redef_table(const obrpc::ObAbortRedefTableArg &arg); + static int build_ddl_single_replica_response(const obrpc::ObDDLBuildSingleReplicaResponseArg &arg); +private: + static int wait_table_lock(const uint64_t tenant_id, const int64_t task_id, ObMySQLProxy &sql_proxy, sql::ObSQLSessionInfo &session); +}; + +} // end of namespace observer +} // end of namespace oceanbase + +#endif /*_OCEANBASE_STORAGE_OB_DDL_SERVER_CLIENT_H_ */ \ No newline at end of file diff --git a/src/storage/ddl/ob_direct_insert_sstable_ctx.cpp b/src/storage/ddl/ob_direct_insert_sstable_ctx.cpp index dc0de66909..d682f1d50c 100644 --- a/src/storage/ddl/ob_direct_insert_sstable_ctx.cpp +++ b/src/storage/ddl/ob_direct_insert_sstable_ctx.cpp @@ -38,7 +38,7 @@ using namespace oceanbase::sql; /*************** ObSSTableInsertTabletParam *****************/ ObSSTableInsertTabletParam::ObSSTableInsertTabletParam() : context_id_(0), ls_id_(), tablet_id_(), table_id_(0), write_major_(false), - task_cnt_(0), schema_version_(0), snapshot_version_(0), execution_id_(-1), ddl_task_id_(0), + task_cnt_(0), schema_version_(0), snapshot_version_(0), execution_id_(1), ddl_task_id_(0), cluster_version_(0) { @@ -189,6 +189,232 @@ int ObSSTableInsertRowIterator::get_sql_mode(ObSQLMode &sql_mode) const return ret; } +/*************** ObSSTableInsertSliceWriter *****************/ + +ObSSTableInsertSliceParam::ObSSTableInsertSliceParam() + : snapshot_version_(0), + write_major_(false), + sstable_index_builder_(nullptr) +{ +} + +ObSSTableInsertSliceParam::~ObSSTableInsertSliceParam() +{ +} + +bool ObSSTableInsertSliceParam::is_valid() const +{ + return tablet_id_.is_valid() && ls_id_.is_valid() && table_key_.is_valid() && + start_seq_.is_valid() && start_scn_.is_valid() && frozen_scn_.is_valid() && + nullptr != sstable_index_builder_; +} + +ObSSTableInsertSliceWriter::ObSSTableInsertSliceWriter() + : rowkey_column_num_(0), + is_index_table_(false), + col_descs_(nullptr), + snapshot_version_(0), + allocator_(lib::ObLabel("PartInsSst")), + lob_allocator_(lib::ObLabel("PartInsSstLob")), + lob_cnt_(0), + sql_mode_for_ddl_reshape_(0), + reshape_ptr_(nullptr), + is_inited_(false) +{ +} + +ObSSTableInsertSliceWriter::~ObSSTableInsertSliceWriter() +{ + if (nullptr != reshape_ptr_) { + ObRowReshapeUtil::free_row_reshape(allocator_, reshape_ptr_, 1); + reshape_ptr_ = nullptr; + } +} + +int ObSSTableInsertSliceWriter::init(const ObSSTableInsertSliceParam &slice_param, + const ObTableSchema *table_schema) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObSSTableInsertSliceWriter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!slice_param.is_valid() || nullptr == table_schema)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(slice_param), KP(table_schema)); + } else { + const ObSQLMode sql_mode_for_ddl_reshape = SMO_TRADITIONAL; + if (OB_FAIL(sstable_redo_writer_.init(slice_param.ls_id_, slice_param.tablet_id_))) { + LOG_WARN("fail to init sstable redo writer", KR(ret), K(slice_param.ls_id_), + K(slice_param.tablet_id_)); + } else if (FALSE_IT(sstable_redo_writer_.set_start_scn(slice_param.start_scn_))) { + } else if (OB_FAIL(redo_log_writer_callback_.init(DDL_MB_DATA_TYPE, slice_param.table_key_, + &sstable_redo_writer_))) { + LOG_WARN("fail to init redo log writer callback", KR(ret)); + } else if (OB_FAIL(data_desc_.init(*table_schema, + slice_param.ls_id_, + slice_param.tablet_id_, // TODO(shuangcan): confirm this + slice_param.write_major_ ? MAJOR_MERGE : MINOR_MERGE, + slice_param.frozen_scn_.get_val_for_tx()))) { + LOG_WARN("fail to init data desc", KR(ret)); + } else { + data_desc_.sstable_index_builder_ = slice_param.sstable_index_builder_; + data_desc_.is_ddl_ = true; + if (OB_FAIL(macro_block_writer_.open(data_desc_, slice_param.start_seq_, + &redo_log_writer_callback_))) { + LOG_WARN("fail to open macro block writer", KR(ret), K_(data_desc), + K(slice_param.start_seq_)); + } + } + if (OB_SUCC(ret)) { + const ObColDescIArray &col_descs = data_desc_.col_desc_array_; + ObTableSchemaParam schema_param(allocator_); + ObRelativeTable relative_table; + // Hack to prevent row reshaping from converting empty string to null. + // + // Supposing we have a row of type varchar with some spaces and an index on this column, + // and then we convert this column to char. In this case, the DDL routine will first rebuild + // the data table and then rebuilding the index table. The row may be reshaped as follows. + // + // - without hack: ' '(varchar) => ''(char) => null(char) + // - with hack: ' '(varchar) => ''(char) => ''(char) + if (OB_FAIL(prepare_reshape(slice_param.tablet_id_, table_schema, schema_param, relative_table))) { + LOG_WARN("failed to prepare params for reshape", K(ret)); + } else if (OB_FAIL(ObRowReshapeUtil::malloc_rows_reshape_if_need( + allocator_, col_descs, 1, relative_table, sql_mode_for_ddl_reshape, + reshape_ptr_))) { + LOG_WARN("failed to malloc row reshape", KR(ret)); + } else if (OB_FAIL(datum_row_.init(allocator_, col_descs.count()))) { + LOG_WARN("fail to init datum row", KR(ret), K(col_descs)); + } + } + if (OB_SUCC(ret)) { + tablet_id_ = slice_param.tablet_id_; + ls_id_ = slice_param.ls_id_; + rowkey_column_num_ = table_schema->get_rowkey_column_num(); + is_index_table_ = table_schema->is_index_table(); + col_descs_ = &data_desc_.col_desc_array_; + snapshot_version_ = slice_param.snapshot_version_; + sql_mode_for_ddl_reshape_ = sql_mode_for_ddl_reshape; + store_row_.flag_.set_flag(ObDmlFlag::DF_INSERT); + is_inited_ = true; + } + } + return ret; +} + +int ObSSTableInsertSliceWriter::append_row(ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObSSTableInsertSliceWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!datum_row.is_valid() || + datum_row.get_column_count() != col_descs_->count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(datum_row), K(col_descs_->count())); + } else { + if (OB_FAIL(datum_row.prepare_new_row(*col_descs_))) { + LOG_WARN("fail to prepare new row", KR(ret)); + } else if (OB_FAIL(append_row(datum_row.get_new_row()))) { + LOG_WARN("fail to append row", KR(ret), K(datum_row)); + } + } + return ret; +} + +int ObSSTableInsertSliceWriter::append_row(const ObNewRow &row_val) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObSSTableInsertSliceWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!row_val.is_valid() || row_val.get_count() != col_descs_->count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(row_val), K(col_descs_->count())); + } else { + if (OB_FAIL(ObRowReshapeUtil::reshape_table_rows(&row_val, reshape_ptr_, col_descs_->count(), + &store_row_, 1, sql_mode_for_ddl_reshape_))) { + LOG_WARN("fail to reshape table rows", KR(ret)); + } else if (OB_FAIL(check_null(store_row_.row_val_))) { + LOG_WARN("fail to check null value in row", KR(ret), K(store_row_)); + } else if (OB_FAIL(datum_row_.from_store_row(store_row_))) { + LOG_WARN("fail to transfer store row ", KR(ret), K(store_row_)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < col_descs_->count(); i++) { + ObStorageDatum &datum = datum_row_.storage_datums_[i]; + if (col_descs_->at(i).col_type_.is_lob_v2() && !datum.is_nop() && !datum.is_null()) { + lob_cnt_++; + const int64_t timeout_ts = + ObTimeUtility::current_time() + ObInsertLobColumnHelper::LOB_ACCESS_TX_TIMEOUT; + if (OB_FAIL(ObInsertLobColumnHelper::insert_lob_column( + lob_allocator_, ls_id_, tablet_id_, col_descs_->at(i), datum, timeout_ts))) { + LOG_WARN("fail to insert_lob_col", KR(ret), K(datum)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(macro_block_writer_.append_row(datum_row_))) { + LOG_WARN("fail to appen row", KR(ret)); + } + } + if (lob_cnt_ % ObInsertLobColumnHelper::LOB_ALLOCATOR_RESET_CYCLE == 0) { + lob_allocator_.reuse(); // reuse after append_row to macro block to save memory + } + } + return ret; +} + +int ObSSTableInsertSliceWriter::prepare_reshape(const ObTabletID &tablet_id, + const ObTableSchema *table_schema, + ObTableSchemaParam &schema_param, + ObRelativeTable &relative_table) const +{ + int ret = OB_SUCCESS; + if (OB_FAIL(schema_param.convert(table_schema))) { + LOG_WARN("failed to convert schema param", K(ret)); + if (OB_SCHEMA_ERROR == ret) { + ret = OB_CANCELED; + } + } else if (OB_FAIL(relative_table.init(&schema_param, tablet_id))) { + LOG_WARN("fail to init relative_table", K(ret), K(schema_param), K(tablet_id)); + } + return ret; +} + +int ObSSTableInsertSliceWriter::check_null(const ObNewRow &row_val) const +{ + int ret = OB_SUCCESS; + if (is_index_table_) { + // index table is index-organized but can have null values in index column + } else if (OB_UNLIKELY(rowkey_column_num_ > row_val.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid rowkey column number", KR(ret), K_(rowkey_column_num), K(row_val)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_column_num_; i++) { + const ObObj &cell = row_val.cells_[i]; + if (cell.is_null()) { + ret = OB_ER_INVALID_USE_OF_NULL; + LOG_WARN("invalid null cell for row key column", KR(ret), K(cell)); + } + } + } + return ret; +} + +int ObSSTableInsertSliceWriter::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObSSTableInsertSliceWriter not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(macro_block_writer_.close())) { + LOG_WARN("fail to close macro block writer", K(ret)); + } + } + return ret; +} + /*************** ObSSTableInsertTabletContext *****************/ ObSSTableInsertTabletContext::ObSSTableInsertTabletContext() @@ -271,44 +497,6 @@ int ObSSTableInsertTabletContext::update(const int64_t snapshot_version) return ret; } -int ObSSTableInsertTabletContext::prepare_reshape(const ObTableSchema *table_schema, - ObTableSchemaParam &schema_param, ObRelativeTable &relative_table) const -{ - int ret = OB_SUCCESS; - if (OB_FAIL(schema_param.convert(table_schema))) { - LOG_WARN("failed to convert schema param", K(ret)); - if (OB_SCHEMA_ERROR == ret) { - ret = OB_CANCELED; - } - } else if (OB_FAIL(relative_table.init(&schema_param, - tablet_handle_.get_obj()->get_tablet_meta().tablet_id_))) { - LOG_WARN("fail to init relative_table", K(ret), K(schema_param), - K(tablet_handle_.get_obj()->get_tablet_meta())); - } - return ret; -} - -int ObSSTableInsertTabletContext::check_null( - const ObTableSchema &table_schema, const ObNewRow &row_val, const int64_t rowkey_column_num) const -{ - int ret = OB_SUCCESS; - if (table_schema.is_index_table()) { - // index table is index-organized but can have null values in index column - } else if (OB_UNLIKELY(rowkey_column_num > row_val.count_)) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid rowkey column number", K(ret), K(rowkey_column_num), K(row_val)); - } else { - for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_column_num; i++) { - const ObObj &cell = row_val.cells_[i]; - if (cell.is_null()) { - ret = OB_ER_INVALID_USE_OF_NULL; - LOG_WARN("invalid null cell for row key column", K(ret), K(cell)); - } - } - } - return ret; -} - int ObSSTableInsertTabletContext::build_sstable_slice( const ObSSTableInsertTabletParam &build_param, const blocksstable::ObMacroDataSeq &start_seq, @@ -317,16 +505,104 @@ int ObSSTableInsertTabletContext::build_sstable_slice( { int ret = OB_SUCCESS; affected_rows = 0; - ObDDLSSTableRedoWriter data_redo_writer; + const int64_t tenant_id = MTL_ID(); + const ObTabletID &tablet_id = build_param.tablet_id_; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + ObArenaAllocator allocator(lib::ObLabel("PartInsSstTmp")); + ObSSTableInsertSliceWriter *sstable_slice_writer = nullptr; + if (OB_FAIL(ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard( + tenant_id, schema_guard, build_param.schema_version_))) { + LOG_WARN("get tenant schema failed", K(ret), K(build_param)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, + build_param.table_id_, table_schema))) { + LOG_WARN("get table schema failed", K(ret), K(build_param)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", K(ret), K(build_param)); + } else if (OB_FAIL(construct_sstable_slice_writer(build_param, start_seq, sstable_slice_writer, allocator))) { + LOG_WARN("fail to construct sstable slice writer", KR(ret), K(build_param), K(start_seq)); + } else if (OB_ISNULL(sstable_slice_writer)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null sstable slce writer", KR(ret)); + } else { + const int64_t rowkey_column_num = table_schema->get_rowkey_column_num(); + const int64_t snapshot_version = sstable_slice_writer->get_snapshot_version(); + ObISSTableInsertRowIterator *tablet_row_iter = reinterpret_cast(&iter); + ObNewRow *row_val = nullptr; + ObTabletID row_tablet_id; + while (OB_SUCC(ret)) { + if (OB_FAIL(THIS_WORKER.check_status())) { + LOG_WARN("check status failed", K(ret)); + } else if (OB_FAIL(tablet_row_iter->get_next_row_with_tablet_id( + build_param.table_id_, rowkey_column_num, snapshot_version, row_val, + row_tablet_id))) { + if (OB_ITER_END != ret) { + LOG_WARN("get next row failed", K(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (tablet_id != row_tablet_id) { + ret = OB_SUCCESS; + break; + } else if (OB_FAIL(sstable_slice_writer->append_row(*row_val))) { + int tmp_ret = OB_SUCCESS; + if (OB_ERR_PRIMARY_KEY_DUPLICATE == ret && table_schema->is_unique_index()) { + LOG_USER_ERROR(OB_ERR_PRIMARY_KEY_DUPLICATE, + "", static_cast(sizeof("UNIQUE IDX") - 1), "UNIQUE IDX"); + char index_key_buffer[OB_TMP_BUF_SIZE_256]; + ObStoreRowkey index_key; + int64_t task_id = 0; + index_key.assign(row_val->cells_, rowkey_column_num); + if (OB_TMP_FAIL(ObDDLErrorMessageTableOperator::extract_index_key(*table_schema, index_key, index_key_buffer, OB_TMP_BUF_SIZE_256))) { // read the unique key that violates the unique constraint + LOG_WARN("extract unique index key failed", K(tmp_ret), K(index_key), K(index_key_buffer)); + // TODO(shuangcan): check if we need to change part_id to tablet_id + } else if (OB_TMP_FAIL(ObDDLErrorMessageTableOperator::get_index_task_id(*GCTX.sql_proxy_, *table_schema, task_id))) { + LOG_WARN("get task id of index table failed", K(tmp_ret), K(task_id), KPC(table_schema)); + } else if (OB_TMP_FAIL(ObDDLErrorMessageTableOperator::generate_index_ddl_error_message(ret, *table_schema, + task_id, row_tablet_id.id(), GCTX.self_addr(), *GCTX.sql_proxy_, index_key_buffer))) { + LOG_WARN("generate index ddl error message", K(tmp_ret), K(ret)); + } + } else { + LOG_WARN("macro block writer append row failed", K(ret)); + } + } else { + LOG_DEBUG("sstable insert op append row", KPC(row_val)); + ++affected_rows; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(sstable_slice_writer->close())) { + LOG_WARN("close writer failed", K(ret)); + } + } + } + if (OB_NOT_NULL(sstable_slice_writer)) { + sstable_slice_writer->~ObSSTableInsertSliceWriter(); + allocator.free(sstable_slice_writer); + sstable_slice_writer = nullptr; + } + return ret; +} + +int ObSSTableInsertTabletContext::construct_sstable_slice_writer( + const ObSSTableInsertTabletParam &build_param, + const ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + sstable_slice_writer = nullptr; + const int64_t tenant_id = MTL_ID(); const ObTabletID &tablet_id = build_param.tablet_id_; ObLSID ls_id; ObMySQLProxy *sql_proxy = GCTX.sql_proxy_; - ObFreezeInfoProxy freeze_info_proxy(MTL_ID()); + ObFreezeInfoProxy freeze_info_proxy(tenant_id); ObSimpleFrozenStatus frozen_status; ObSchemaGetterGuard schema_guard; const ObTableSchema *table_schema = nullptr; - ObDataStoreDesc data_desc; - const int64_t tenant_id = MTL_ID(); + ObITable::TableKey table_key; int64_t snapshot_version = 0; SCN snapshot_scn; { @@ -348,11 +624,13 @@ int ObSSTableInsertTabletContext::build_sstable_slice( LOG_WARN("table not exist", K(ret), K(build_param)); } else if (OB_FAIL(prepare_index_builder_if_need(*table_schema))) { LOG_WARN("prepare sstable index builder failed", K(ret), K(build_param)); - } else if (OB_FAIL(data_redo_writer.init(ls_id, tablet_id))) { - LOG_WARN("fail to init sstable redo writer", K(ret), K(ls_id), K(tablet_id)); + } else if (OB_FAIL(get_table_key(table_key))) { + LOG_WARN("get table key failed", K(ret), K(build_param_)); } else if (OB_FAIL(snapshot_scn.convert_for_tx(snapshot_version))) { LOG_WARN("fail to convert val to SCN", KR(ret), K(snapshot_version)); - } else if (FALSE_IT(data_redo_writer.set_start_scn(data_sstable_redo_writer_.get_start_scn()))) { + } else if (OB_UNLIKELY(!table_key.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(table_key)); } else if (OB_FAIL(freeze_info_proxy.get_frozen_info_less_than( *sql_proxy, snapshot_scn, frozen_status))) { if (OB_ENTRY_NOT_EXIST != ret) { @@ -362,138 +640,28 @@ int ObSSTableInsertTabletContext::build_sstable_slice( ret = OB_SUCCESS; } } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(data_desc.init(*table_schema, - ls_id, - tablet_id, // TODO(shuangcan): confirm this - build_param.write_major_ ? storage::MAJOR_MERGE : storage::MINOR_MERGE, - frozen_status.frozen_scn_.get_val_for_tx(), - build_param_.cluster_version_))) { - LOG_WARN("init data store desc failed", K(ret), K(tablet_id)); - } else { - // index builder is need for write macro meta block. - // maybe the index builder is better built in macro block writer - data_desc.sstable_index_builder_ = index_builder_; - data_desc.is_ddl_ = true; - ObSSTableInsertRowIterator *tablet_row_iter = reinterpret_cast(&iter); - HEAP_VAR(ObMacroBlockWriter, writer) { - ObStoreRow row; - ObNewRow *row_val = NULL; - row.flag_.set_flag(ObDmlFlag::DF_INSERT); - ObDDLRedoLogWriterCallback callback; - ObITable::TableKey table_key; - if (OB_FAIL(get_table_key(table_key))) { - LOG_WARN("get table key failed", K(ret), K(build_param_)); - } else if (OB_UNLIKELY(!table_key.is_valid())) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid argument", K(ret), K(table_key)); - } else if (OB_FAIL(callback.init(DDL_MB_DATA_TYPE, table_key, &data_redo_writer))) { - LOG_WARN("fail to init data callback", K(ret)); - } else if (OB_FAIL(writer.open(data_desc, start_seq, &callback))) { - LOG_WARN("open macro block writer failed", K(ret), K(tablet_id), K(data_desc)); - } - ObTabletID row_tablet_id; - const ObColDescIArray &col_descs = data_desc.col_desc_array_; - ObArenaAllocator allocator(lib::ObLabel("PartInsSstTmp")); - ObTableSchemaParam schema_param(allocator); - ObRelativeTable relative_table; - ObRowReshape *reshape_ptr = nullptr; - ObSQLMode sql_mode_for_ddl_reshape = SMO_TRADITIONAL; - ObDatumRow datum_row; - // Hack to prevent row reshaping from converting empty string to null. - // - // Supposing we have a row of type varchar with some spaces and an index on this column, - // and then we convert this column to char. In this case, the DDL routine will first rebuild - // the data table and then rebuilding the index table. The row may be reshaped as follows. - // - // - without hack: ' '(varchar) => ''(char) => null(char) - // - with hack: ' '(varchar) => ''(char) => ''(char) - if (OB_FAIL(ret)) { - } else if (OB_FAIL(prepare_reshape(table_schema, schema_param, relative_table))) { - LOG_WARN("failed to prepare params for reshape", K(ret)); - } else if (OB_FAIL(ObRowReshapeUtil::malloc_rows_reshape_if_need( - allocator, col_descs, 1, relative_table, sql_mode_for_ddl_reshape, reshape_ptr))) { - LOG_WARN("failed to malloc row reshape", K(ret)); - } else if (OB_FAIL(datum_row.init(allocator, col_descs.count()))) { - STORAGE_LOG(WARN, "Failed to init datum row", K(ret), K(col_descs)); - } - - int64_t rowkey_column_num = table_schema->get_rowkey_column_num(); - ObArenaAllocator lob_allocator; - int64_t lob_cnt = 0; - - while (OB_SUCC(ret)) { - if (OB_FAIL(THIS_WORKER.check_status())) { - LOG_WARN("check status failed", K(ret)); - } else if (OB_FAIL(tablet_row_iter->get_next_row_with_tablet_id( - build_param.table_id_, rowkey_column_num, snapshot_version, row_val, row_tablet_id))) { - if (OB_ITER_END != ret) { - LOG_WARN("get next row failed", K(ret)); - } else { - ret = OB_SUCCESS; - break; - } - } else if (tablet_id != row_tablet_id) { - ret = OB_SUCCESS; - break; - } else { - if (OB_FAIL(ObRowReshapeUtil::reshape_table_rows( - row_val, reshape_ptr, col_descs.count(), &row, 1, sql_mode_for_ddl_reshape))) { - LOG_WARN("failed to malloc and reshape row", K(ret)); - } else if (OB_FAIL(check_null(*table_schema, row.row_val_, rowkey_column_num))) { - LOG_WARN("unexpected null value in row", K(ret), K(row)); - } else if (OB_FAIL(datum_row.from_store_row(row))) { - STORAGE_LOG(WARN, "Failed to transfer store row ", K(ret), K(row)); - } - for (int64_t i = 0; OB_SUCC(ret) && i < col_descs.count(); i++) { - ObStorageDatum &datum = datum_row.storage_datums_[i]; - if (col_descs.at(i).col_type_.is_lob_v2() && !datum.is_nop() && !datum.is_null()) { - lob_cnt++; - const int64_t timeout_ts = ObTimeUtility::current_time() + ObInsertLobColumnHelper::LOB_ACCESS_TX_TIMEOUT; - if (OB_FAIL(ObInsertLobColumnHelper::insert_lob_column( - lob_allocator, ls_id, tablet_id, col_descs.at(i), datum, timeout_ts))) { - LOG_WARN("fail to insert_lob_col", K(ret), K(datum)); - } - } - } - - if (OB_FAIL(ret)) { - // do nothing - } else if (OB_FAIL(writer.append_row(datum_row))) { - int tmp_ret = OB_SUCCESS; - if (OB_ERR_PRIMARY_KEY_DUPLICATE == ret && table_schema->is_unique_index()) { - LOG_USER_ERROR(OB_ERR_PRIMARY_KEY_DUPLICATE, - "", static_cast(sizeof("UNIQUE IDX") - 1), "UNIQUE IDX"); - char index_key_buffer[OB_TMP_BUF_SIZE_256]; - ObStoreRowkey index_key; - int64_t task_id = 0; - index_key.assign(row.row_val_.cells_, rowkey_column_num); - if (OB_SUCCESS != ObDDLErrorMessageTableOperator::extract_index_key(*table_schema, index_key, index_key_buffer, OB_TMP_BUF_SIZE_256)) { // read the unique key that violates the unique constraint - LOG_WARN("extract unique index key failed", K(index_key), K(index_key_buffer)); - // TODO(shuangcan): check if we need to change part_id to tablet_id - } else if (OB_SUCCESS != ObDDLErrorMessageTableOperator::get_index_task_id(*GCTX.sql_proxy_, *table_schema, task_id)) { - LOG_WARN("get task id of index table failed", K(task_id), KPC(table_schema)); - } else if (OB_SUCCESS != (tmp_ret = ObDDLErrorMessageTableOperator::generate_index_ddl_error_message(ret, *table_schema, - task_id, row_tablet_id.id(), GCTX.self_addr(), *GCTX.sql_proxy_, index_key_buffer))) { - LOG_WARN("generate index ddl error message", K(tmp_ret), K(ret)); - } - } else { - LOG_WARN("macro block writer append row failed", K(ret)); - } - } else { - LOG_DEBUG("sstable insert op append row", K(row)); - ++affected_rows; - } - if (lob_cnt++ % ObInsertLobColumnHelper::LOB_ALLOCATOR_RESET_CYCLE == 0) { - lob_allocator.reuse(); // reuse after append_row to macro block to save memory - } - } - } - ObRowReshapeUtil::free_row_reshape(allocator, reshape_ptr, 1); - if (OB_SUCC(ret)) { - if (OB_FAIL(writer.close())) { - LOG_WARN("close writer failed", K(ret)); - } + if (OB_SUCC(ret)) { + ObSSTableInsertSliceParam slice_param; + slice_param.tablet_id_ = tablet_id; + slice_param.ls_id_ = ls_id; + slice_param.table_key_ = table_key; + slice_param.start_seq_ = start_seq; + slice_param.start_scn_ = data_sstable_redo_writer_.get_start_scn(); + slice_param.snapshot_version_ = snapshot_version; + slice_param.frozen_scn_ = frozen_status.frozen_scn_; + slice_param.write_major_ = build_param.write_major_; + slice_param.sstable_index_builder_ = index_builder_; + if (OB_ISNULL(sstable_slice_writer = OB_NEWx(ObSSTableInsertSliceWriter, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObSSTableInsertSliceWriter", KR(ret)); + } else if (OB_FAIL(sstable_slice_writer->init(slice_param, table_schema))) { + LOG_WARN("fail to init sstable slice writer", KR(ret), K(slice_param)); + } + if (OB_FAIL(ret)) { + if (nullptr != sstable_slice_writer) { + sstable_slice_writer->~ObSSTableInsertSliceWriter(); + allocator.free(sstable_slice_writer); + sstable_slice_writer = nullptr; } } } @@ -742,7 +910,7 @@ int ObSSTableInsertTabletContext::get_table_key(ObITable::TableKey &table_key) ObSSTableInsertTableParam::ObSSTableInsertTableParam() : exec_ctx_(nullptr), context_id_(0), dest_table_id_(OB_INVALID_ID), write_major_(false), schema_version_(0), - snapshot_version_(0), task_cnt_(0), execution_id_(-1), ddl_task_id_(0), cluster_version_(0), ls_tablet_ids_() + snapshot_version_(0), task_cnt_(0), execution_id_(1), ddl_task_id_(1), cluster_version_(0), ls_tablet_ids_() { } @@ -766,6 +934,15 @@ int ObSSTableInsertTableParam::assign(const ObSSTableInsertTableParam &other) return ret; } +int ObSSTableInsertTableParam::fast_check_status() +{ + int ret = common::OB_SUCCESS; + if (exec_ctx_ != nullptr) { + ret = exec_ctx_->fast_check_status(); + } + return ret; +} + ObSSTableInsertTableContext::ObSSTableInsertTableContext() : is_inited_(false), lock_(ObLatchIds::SSTABLE_INSERT_TABLE_CONTEXT_LOCK), param_(), allocator_(), tablet_ctx_map_(), finishing_idx_(0) { @@ -876,6 +1053,31 @@ int ObSSTableInsertTableContext::update_context(const int64_t snapshot_version) return ret; } +int ObSSTableInsertTableContext::update_tablet_context( + const ObTabletID &tablet_id, + const int64_t snapshot_version) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableInsertSSTableContext has not been inited", K(ret)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || snapshot_version <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), K(tablet_id), K(snapshot_version)); + } else { + ObSSTableInsertTabletContext *tablet_ctx = nullptr; + if (OB_FAIL(get_tablet_context(tablet_id, tablet_ctx))) { + LOG_WARN("get tablet context failed", K(ret), K(tablet_id)); + } else if (OB_ISNULL(tablet_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error unexpected, tablet ctx must not be nullptr", K(ret)); + } else if (OB_FAIL(tablet_ctx->update(snapshot_version))) { + LOG_WARN("update tablet context failed", K(ret)); + } + } + return ret; +} + int ObSSTableInsertTableContext::add_sstable_slice( const ObSSTableInsertTabletParam &build_param, const blocksstable::ObMacroDataSeq &start_seq, @@ -898,6 +1100,28 @@ int ObSSTableInsertTableContext::add_sstable_slice( return ret; } +int ObSSTableInsertTableContext::construct_sstable_slice_writer( + const ObSSTableInsertTabletParam &build_param, + const ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObSSTableInsertTabletContext *tablet_ctx = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObTableInsertSSTableContext has not been inited", K(ret)); + } else if (OB_FAIL(get_tablet_context(build_param.tablet_id_, tablet_ctx))) { + LOG_WARN("get tablet context failed", K(ret), "tablet_id", build_param.tablet_id_); + } else if (OB_ISNULL(tablet_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error unexpected, tablet ctx must not be nullptr", K(ret)); + } else if (OB_FAIL(tablet_ctx->construct_sstable_slice_writer(build_param, start_seq, sstable_slice_writer, allocator))) { + LOG_WARN("construct sstable slice writer failed", K(ret)); + } + return ret; +} + int ObSSTableInsertTableContext::get_tablet_context( const ObTabletID &tablet_id, ObSSTableInsertTabletContext *&context) @@ -1023,16 +1247,27 @@ int ObSSTableInsertTableContext::notify_tablet_end(const ObTabletID &tablet_id) int ObSSTableInsertTableContext::finish_ready_tablets(const int64_t target_count) { int ret = OB_SUCCESS; - int64_t idx = 0; - while (OB_SUCC(ret) && OB_SUCC(param_.exec_ctx_->fast_check_status()) && ready_tablets_.count() < target_count) { + int64_t cur_finishing_idx = 0; + int64_t next_finishing_idx = 0; + int64_t old_finishing_idx = 0; + while (OB_SUCC(ret) && OB_SUCC(param_.fast_check_status()) && ready_tablets_.count() < target_count) { ob_usleep(1000); if (TC_REACH_TIME_INTERVAL(1000L * 1000L * 1L)) { LOG_INFO("wait ready tablets reach target count", K(ready_tablets_.count()), K(target_count)); } } - while (OB_SUCC(ret) && OB_SUCC(param_.exec_ctx_->fast_check_status()) - && (idx = ATOMIC_FAA(&finishing_idx_, 1)) < ready_tablets_.count()) { - ObTabletID tablet_id = ready_tablets_.at(idx); + while (OB_SUCC(ret) && OB_SUCC(param_.fast_check_status())) { + old_finishing_idx = cur_finishing_idx = ATOMIC_LOAD(&finishing_idx_); + while ((next_finishing_idx = cur_finishing_idx + 1) <= target_count && + old_finishing_idx != (cur_finishing_idx = ATOMIC_CAS(&finishing_idx_, old_finishing_idx, + next_finishing_idx))) { + old_finishing_idx = cur_finishing_idx; + PAUSE(); + } + if (next_finishing_idx > target_count) { + break; + } + ObTabletID tablet_id = ready_tablets_.at(cur_finishing_idx); ObSSTableInsertTabletContext *tablet_ctx = nullptr; if (OB_FAIL(get_tablet_context(tablet_id, tablet_ctx))) { LOG_WARN("get tablet context failed", K(ret), K(tablet_id)); @@ -1042,7 +1277,7 @@ int ObSSTableInsertTableContext::finish_ready_tablets(const int64_t target_count } else if (OB_FAIL(tablet_ctx->create_sstable())) { LOG_WARN("create sstable failed", K(ret), K(tablet_id)); } else { - LOG_INFO("finish ready tablet", K(ret), K(idx), K(tablet_id), K(ready_tablets_.count())); + LOG_INFO("finish ready tablet", K(ret), K(cur_finishing_idx), K(tablet_id), K(ready_tablets_.count())); } } return ret; @@ -1175,6 +1410,29 @@ int ObSSTableInsertManager::update_table_context( return ret; } +int ObSSTableInsertManager::update_table_tablet_context( + const int64_t context_id, + const ObTabletID &tablet_id, + const int64_t snapshot_version) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectInsertSSTableManager has not been inited", K(ret)); + } else if (OB_UNLIKELY(context_id <= 0 || !tablet_id.is_valid() || snapshot_version <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arguments", K(ret), K(context_id), K(tablet_id), K(snapshot_version)); + } else { + ObSSTableInsertTableContext *table_context = nullptr; + if (OB_FAIL(get_context(context_id, table_context))) { + LOG_WARN("get context failed", K(ret)); + } else if (OB_FAIL(table_context->update_tablet_context(tablet_id, snapshot_version))) { + LOG_WARN("update tablet context failed", K(ret)); + } + } + return ret; +} + uint64_t ObSSTableInsertManager::get_context_id_hash(const int64_t context_id) { return common::murmurhash(&context_id, sizeof(context_id), 0L); @@ -1218,6 +1476,25 @@ int ObSSTableInsertManager::add_sstable_slice( return ret; } +int ObSSTableInsertManager::construct_sstable_slice_writer( + const ObSSTableInsertTabletParam ¶m, + const ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObSSTableInsertTableContext *table_ctx = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectInsertSSTableManager has not been inited", K(ret)); + } else if (OB_FAIL(get_context(param.context_id_, table_ctx))) { + LOG_WARN("get context failed", K(ret)); + } else if (OB_FAIL(table_ctx->construct_sstable_slice_writer(param, start_seq, sstable_slice_writer, allocator))) { + LOG_WARN("construct sstable slice writer failed", K(ret)); + } + return ret; +} + int ObSSTableInsertManager::notify_tablet_end(const int64_t context_id, const ObTabletID &tablet_id) { int ret = OB_SUCCESS; diff --git a/src/storage/ddl/ob_direct_insert_sstable_ctx.h b/src/storage/ddl/ob_direct_insert_sstable_ctx.h index ae4e8742a1..db3a418246 100644 --- a/src/storage/ddl/ob_direct_insert_sstable_ctx.h +++ b/src/storage/ddl/ob_direct_insert_sstable_ctx.h @@ -73,7 +73,20 @@ public: typedef std::pair LSTabletIDPair; -class ObSSTableInsertRowIterator : public common::ObNewRowIterator +class ObISSTableInsertRowIterator : public common::ObNewRowIterator +{ +public: + ObISSTableInsertRowIterator() {} + virtual ~ObISSTableInsertRowIterator() {} + virtual int get_next_row_with_tablet_id( + const uint64_t table_id, + const int64_t rowkey_count, + const int64_t snapshot_version, + common::ObNewRow *&row, + common::ObTabletID &tablet_id) = 0; +}; + +class ObSSTableInsertRowIterator : public ObISSTableInsertRowIterator { public: ObSSTableInsertRowIterator(sql::ObExecContext &exec_ctx, sql::ObPxMultiPartSSTableInsertOp *op); @@ -86,7 +99,7 @@ public: const int64_t rowkey_count, const int64_t snapshot_version, common::ObNewRow *&row, - common::ObTabletID &tablet_id); + common::ObTabletID &tablet_id) override; common::ObTabletID get_current_tablet_id() const; private: sql::ObExecContext &exec_ctx_; @@ -96,6 +109,68 @@ private: bool is_next_row_cached_; }; +struct ObSSTableInsertSliceParam final +{ +public: + ObSSTableInsertSliceParam(); + ~ObSSTableInsertSliceParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(ls_id), K_(table_key), K_(start_seq), K_(start_scn), + K_(snapshot_version), K_(frozen_scn), K_(write_major), KP_(sstable_index_builder)); +public: + common::ObTabletID tablet_id_; + share::ObLSID ls_id_; + ObITable::TableKey table_key_; + blocksstable::ObMacroDataSeq start_seq_; + share::SCN start_scn_; + int64_t snapshot_version_; + share::SCN frozen_scn_; + bool write_major_; + blocksstable::ObSSTableIndexBuilder *sstable_index_builder_; +}; + +class ObSSTableInsertSliceWriter final +{ +public: + ObSSTableInsertSliceWriter(); + ~ObSSTableInsertSliceWriter(); + int init(const ObSSTableInsertSliceParam &slice_param, + const share::schema::ObTableSchema *table_schema); + int append_row(blocksstable::ObDatumRow &datum_row); + int append_row(const common::ObNewRow &row_val); + int close(); + OB_INLINE int64_t get_snapshot_version() const { return snapshot_version_; } + TO_STRING_KV(K_(tablet_id), K_(ls_id), K_(rowkey_column_num), K_(is_index_table), KP_(col_descs), + K_(snapshot_version), K_(data_desc), K_(lob_cnt), K_(sql_mode_for_ddl_reshape), + KP_(reshape_ptr)); +private: + int prepare_reshape( + const common::ObTabletID &tablet_id, + const share::schema::ObTableSchema *table_schema, + share::schema::ObTableSchemaParam &schema_param, + ObRelativeTable &relative_table) const; + int check_null(const common::ObNewRow &row_val) const; +private: + common::ObTabletID tablet_id_; + share::ObLSID ls_id_; + int64_t rowkey_column_num_; + bool is_index_table_; + const blocksstable::ObColDescIArray *col_descs_; + int64_t snapshot_version_; + ObDDLSSTableRedoWriter sstable_redo_writer_; + ObDDLRedoLogWriterCallback redo_log_writer_callback_; + blocksstable::ObDataStoreDesc data_desc_; + blocksstable::ObMacroBlockWriter macro_block_writer_; + common::ObArenaAllocator allocator_; + common::ObArenaAllocator lob_allocator_; + int64_t lob_cnt_; + ObSQLMode sql_mode_for_ddl_reshape_; + ObRowReshape *reshape_ptr_; + ObStoreRow store_row_; + blocksstable::ObDatumRow datum_row_; + bool is_inited_; +}; + class ObSSTableInsertTabletContext final { public: @@ -108,19 +183,15 @@ public: const blocksstable::ObMacroDataSeq &start_seq, common::ObNewRowIterator &iter, int64_t &affected_rows); + int construct_sstable_slice_writer(const ObSSTableInsertTabletParam &build_param, + const blocksstable::ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + common::ObIAllocator &allocator); int create_sstable(); int inc_finish_count(bool &is_ready); int get_tablet_cache_interval(share::ObTabletCacheInterval &interval); TO_STRING_KV(K(build_param_), K(sstable_created_)); private: - int prepare_reshape( - const share::schema::ObTableSchema *table_schema, - share::schema::ObTableSchemaParam &schema_param, - ObRelativeTable &relative_table) const; - int check_null( - const share::schema::ObTableSchema &table_schema, - const ObNewRow &row, - const int64_t rowkey_column_num) const; int create_sstable_with_clog( ObTablet *tablet, const ObITable::TableKey &table_key, @@ -148,7 +219,8 @@ public: ObSSTableInsertTableParam(); ~ObSSTableInsertTableParam() = default; int assign(const ObSSTableInsertTableParam &other); - bool is_valid() const { return exec_ctx_ != nullptr && OB_INVALID_ID != dest_table_id_ + int fast_check_status(); + bool is_valid() const { return OB_INVALID_ID != dest_table_id_ && schema_version_ >= 0 && snapshot_version_ >= 0 && task_cnt_ >= 0 && execution_id_ >= 0 && ddl_task_id_ > 0 && cluster_version_ > 0 && ls_tablet_ids_.count() > 0; } TO_STRING_KV(K_(context_id), K_(dest_table_id), K_(write_major), K_(schema_version), K_(snapshot_version), @@ -174,11 +246,16 @@ public: ~ObSSTableInsertTableContext(); int init(const ObSSTableInsertTableParam ¶m); int update_context(const int64_t snapshot_version); + int update_tablet_context(const ObTabletID &tablet_id, const int64_t snapshot_version); int add_sstable_slice( const ObSSTableInsertTabletParam &build_param, const blocksstable::ObMacroDataSeq &start_seq, common::ObNewRowIterator &iter, int64_t &affected_rows); + int construct_sstable_slice_writer(const ObSSTableInsertTabletParam &build_param, + const blocksstable::ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + common::ObIAllocator &allocator); int finish(const bool need_commit); int get_tablet_ids(common::ObIArray &tablet_ids); int notify_tablet_end(const ObTabletID &tablet_id); @@ -217,11 +294,19 @@ public: int update_table_context( const int64_t context_id, const int64_t snapshot_version); + int update_table_tablet_context( + const int64_t context_id, + const ObTabletID &tablet_id, + const int64_t snapshot_version); int add_sstable_slice( const ObSSTableInsertTabletParam &build_param, const blocksstable::ObMacroDataSeq &start_seq, common::ObNewRowIterator &iter, int64_t &affected_rows); + int construct_sstable_slice_writer(const ObSSTableInsertTabletParam &build_param, + const blocksstable::ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&sstable_slice_writer, + common::ObIAllocator &allocator); void destroy(); int get_tablet_ids(const int64_t context_id, common::ObIArray &tablet_ids); int notify_tablet_end(const int64_t context_id, const ObTabletID &tablet_id); diff --git a/src/storage/direct_load/ob_direct_load_compare.cpp b/src/storage/direct_load/ob_direct_load_compare.cpp new file mode 100644 index 0000000000..4ae262f783 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_compare.cpp @@ -0,0 +1,307 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_compare.h" +#include "storage/blocksstable/ob_datum_row.h" +#include "storage/direct_load/ob_direct_load_datum.h" +#include "storage/direct_load/ob_direct_load_external_multi_partition_row.h" +#include "storage/direct_load/ob_direct_load_external_row.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadDatumRowkeyCompare + */ + +int ObDirectLoadDatumRowkeyCompare::init(const ObStorageDatumUtils &datum_utils) +{ + int ret = OB_SUCCESS; + datum_utils_ = &datum_utils; + return ret; +} + +bool ObDirectLoadDatumRowkeyCompare::operator()(const ObDatumRowkey *lhs, + const ObDatumRowkey *rhs) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_ISNULL(datum_utils_) || OB_ISNULL(lhs) || OB_ISNULL(rhs) || + OB_UNLIKELY(!lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datum_utils_), KP(lhs), KP(rhs)); + } else { + if (OB_FAIL(lhs->compare(*rhs, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret), KP(lhs), K(rhs), K(datum_utils_)); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } + return cmp_ret < 0; +} + +/** + * ObDirectLoadDatumRowCompare + */ + +int ObDirectLoadDatumRowCompare::init(const ObStorageDatumUtils &datum_utils, int64_t rowkey_size) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDatumRowCompare init twice", KR(ret), KP(this)); + } + if (OB_UNLIKELY(rowkey_size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(rowkey_size)); + } else { + if (OB_FAIL(rowkey_compare_.init(datum_utils))) { + LOG_WARN("fail to init rowkey compare", KR(ret)); + } else { + rowkey_size_ = rowkey_size; + is_inited_ = true; + } + } + return ret; +} + +bool ObDirectLoadDatumRowCompare::operator()(const ObDatumRow *lhs, const ObDatumRow *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDatumRowCompare not init", KR(ret), KP(this)); + } else if (OB_ISNULL(lhs) || OB_ISNULL(rhs) || + OB_UNLIKELY(!lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else if (OB_UNLIKELY(lhs->get_column_count() < rowkey_size_ || + rhs->get_column_count() < rowkey_size_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected row column cnt", KR(ret), K(lhs), K(rhs), K_(rowkey_size)); + } else { + if (OB_FAIL(lhs_rowkey_.assign(lhs->storage_datums_, rowkey_size_))) { + LOG_WARN("Failed to assign datum rowkey", KR(ret), K(lhs), K_(rowkey_size)); + } else if (OB_FAIL(rhs_rowkey_.assign(rhs->storage_datums_, rowkey_size_))) { + LOG_WARN("Failed to assign datum rowkey", KR(ret), K(rhs), K_(rowkey_size)); + } else { + bret = rowkey_compare_.operator()(&lhs_rowkey_, &rhs_rowkey_); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(rowkey_compare_.get_error_code())) { + result_code_ = rowkey_compare_.get_error_code(); + } + return bret; +} + +/** + * ObDirectLoadDatumArrayCompare + */ + +int ObDirectLoadDatumArrayCompare::init(const ObStorageDatumUtils &datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDatumArrayCompare init twice", KR(ret), KP(this)); + } else { + if (OB_FAIL(rowkey_compare_.init(datum_utils))) { + LOG_WARN("fail to init rowkey compare", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +bool ObDirectLoadDatumArrayCompare::operator()(const ObDirectLoadDatumArray *lhs, + const ObDirectLoadDatumArray *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDatumArrayCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || !rhs->is_valid() || + lhs->count_ != rhs->count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else if (lhs->count_ > 0) { + if (OB_FAIL(lhs_rowkey_.assign(lhs->datums_, lhs->count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else if (OB_FAIL(rhs_rowkey_.assign(rhs->datums_, rhs->count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else { + bret = rowkey_compare_.operator()(&lhs_rowkey_, &rhs_rowkey_); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(rowkey_compare_.get_error_code())) { + result_code_ = rowkey_compare_.get_error_code(); + } + return bret; +} + +bool ObDirectLoadDatumArrayCompare::operator()(const ObDirectLoadConstDatumArray *lhs, + const ObDirectLoadConstDatumArray *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDatumArrayCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || !rhs->is_valid() || + lhs->count_ != rhs->count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else if (lhs->count_ > 0) { + if (OB_FAIL(lhs_rowkey_.assign(lhs->datums_, lhs->count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else if (OB_FAIL(rhs_rowkey_.assign(rhs->datums_, rhs->count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else { + bret = rowkey_compare_.operator()(&lhs_rowkey_, &rhs_rowkey_); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(rowkey_compare_.get_error_code())) { + result_code_ = rowkey_compare_.get_error_code(); + } + return bret; +} + +/** + * ObDirectLoadExternalRowCompare + */ + +int ObDirectLoadExternalRowCompare::init(const ObStorageDatumUtils &datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDatumRowCompare init twice", KR(ret), KP(this)); + } else { + if (OB_FAIL(datum_array_compare_.init(datum_utils))) { + LOG_WARN("fail to init datum array compare", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +bool ObDirectLoadExternalRowCompare::operator()(const ObDirectLoadExternalRow *lhs, + const ObDirectLoadExternalRow *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDatumRowCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || + !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else { + bret = datum_array_compare_.operator()(&lhs->rowkey_datum_array_, &rhs->rowkey_datum_array_); + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(datum_array_compare_.get_error_code())) { + result_code_ = datum_array_compare_.get_error_code(); + } + return bret; +} + +/** + * ObDirectLoadExternalMultiPartitionRowCompare + */ + +int ObDirectLoadExternalMultiPartitionRowCompare::init(const ObStorageDatumUtils &datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadExternalMultiPartitionRowCompare init twice", KR(ret), KP(this)); + } else { + if (OB_FAIL(datum_array_compare_.init(datum_utils))) { + LOG_WARN("fail to init datum array compare", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +bool ObDirectLoadExternalMultiPartitionRowCompare::operator()( + const ObDirectLoadExternalMultiPartitionRow *lhs, + const ObDirectLoadExternalMultiPartitionRow *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalMultiPartitionRowCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || + !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else { + if (lhs->tablet_id_ != rhs->tablet_id_) { + bret = lhs->tablet_id_ < rhs->tablet_id_; + } else { + bret = datum_array_compare_.operator()(&lhs->external_row_.rowkey_datum_array_, + &rhs->external_row_.rowkey_datum_array_); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(datum_array_compare_.get_error_code())) { + result_code_ = datum_array_compare_.get_error_code(); + } + return bret; +} + +bool ObDirectLoadExternalMultiPartitionRowCompare::operator()( + const ObDirectLoadConstExternalMultiPartitionRow *lhs, + const ObDirectLoadConstExternalMultiPartitionRow *rhs) +{ + int ret = OB_SUCCESS; + bool bret = false; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalMultiPartitionRowCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || + !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(lhs), KP(rhs)); + } else { + if (lhs->tablet_id_ != rhs->tablet_id_) { + bret = lhs->tablet_id_ < rhs->tablet_id_; + } else { + bret = datum_array_compare_.operator()(&lhs->rowkey_datum_array_, &rhs->rowkey_datum_array_); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } else if (OB_FAIL(datum_array_compare_.get_error_code())) { + result_code_ = datum_array_compare_.get_error_code(); + } + return bret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_compare.h b/src/storage/direct_load/ob_direct_load_compare.h new file mode 100644 index 0000000000..c7ff06d3b0 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_compare.h @@ -0,0 +1,104 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/ob_define.h" +#include "lib/ob_errno.h" +#include "storage/blocksstable/ob_datum_rowkey.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatumUtils; +class ObDatumRowkey; +class ObDatumRow; +} // namespace blocksstable +namespace storage +{ +class ObDirectLoadDatumArray; +class ObDirectLoadConstDatumArray; +class ObDirectLoadExternalRow; +class ObDirectLoadExternalMultiPartitionRow; +class ObDirectLoadConstExternalMultiPartitionRow; + +class ObDirectLoadDatumRowkeyCompare +{ +public: + ObDirectLoadDatumRowkeyCompare() : datum_utils_(nullptr), result_code_(common::OB_SUCCESS) {} + int init(const blocksstable::ObStorageDatumUtils &datum_utils); + bool operator()(const blocksstable::ObDatumRowkey *lhs, const blocksstable::ObDatumRowkey *rhs); + int get_error_code() const { return result_code_; } +public: + const blocksstable::ObStorageDatumUtils *datum_utils_; + int result_code_; +}; + +class ObDirectLoadDatumRowCompare +{ +public: + ObDirectLoadDatumRowCompare() + : rowkey_size_(0), result_code_(common::OB_SUCCESS), is_inited_(false) {} + int init(const blocksstable::ObStorageDatumUtils &datum_utils, int64_t rowkey_size); + bool operator()(const blocksstable::ObDatumRow *lhs, const blocksstable::ObDatumRow *rhs); + int get_error_code() const { return result_code_; } +public: + blocksstable::ObDatumRowkey lhs_rowkey_; + blocksstable::ObDatumRowkey rhs_rowkey_; + ObDirectLoadDatumRowkeyCompare rowkey_compare_; + int64_t rowkey_size_; + int result_code_; + bool is_inited_; +}; + +class ObDirectLoadDatumArrayCompare +{ +public: + ObDirectLoadDatumArrayCompare() + : result_code_(common::OB_SUCCESS), is_inited_(false) {} + int init(const blocksstable::ObStorageDatumUtils &datum_utils); + bool operator()(const ObDirectLoadDatumArray *lhs, const ObDirectLoadDatumArray *rhs); + bool operator()(const ObDirectLoadConstDatumArray *lhs, const ObDirectLoadConstDatumArray *rhs); + int get_error_code() const { return result_code_; } +public: + blocksstable::ObDatumRowkey lhs_rowkey_; + blocksstable::ObDatumRowkey rhs_rowkey_; + ObDirectLoadDatumRowkeyCompare rowkey_compare_; + int result_code_; + bool is_inited_; +}; + +class ObDirectLoadExternalRowCompare +{ +public: + ObDirectLoadExternalRowCompare() : result_code_(common::OB_SUCCESS), is_inited_(false) {} + int init(const blocksstable::ObStorageDatumUtils &datum_utils); + bool operator()(const ObDirectLoadExternalRow *lhs, const ObDirectLoadExternalRow *rhs); + int get_error_code() const { return result_code_; } +public: + ObDirectLoadDatumArrayCompare datum_array_compare_; + int result_code_; + bool is_inited_; +}; + +class ObDirectLoadExternalMultiPartitionRowCompare +{ +public: + ObDirectLoadExternalMultiPartitionRowCompare() + : result_code_(common::OB_SUCCESS), is_inited_(false) {} + int init(const blocksstable::ObStorageDatumUtils &datum_utils); + bool operator()(const ObDirectLoadExternalMultiPartitionRow *lhs, + const ObDirectLoadExternalMultiPartitionRow *rhs); + bool operator()(const ObDirectLoadConstExternalMultiPartitionRow *lhs, + const ObDirectLoadConstExternalMultiPartitionRow *rhs); + int get_error_code() const { return result_code_; } +public: + ObDirectLoadDatumArrayCompare datum_array_compare_; + int result_code_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block.cpp b/src/storage/direct_load/ob_direct_load_data_block.cpp new file mode 100644 index 0000000000..435e96d78f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_data_block.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadDataBlock::Header::Header() + : occupy_size_(0), data_size_(0), checksum_(0) +{ +} + +ObDirectLoadDataBlock::Header::~Header() +{ +} + +void ObDirectLoadDataBlock::Header::reset() +{ + occupy_size_ = 0; + data_size_ = 0; + checksum_ = 0; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadDataBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, occupy_size_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(occupy_size_)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, data_size_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(data_size_)); + } else if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, checksum_))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(checksum_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadDataBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &occupy_size_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(occupy_size_)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &data_size_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(data_size_)); + } else if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &checksum_))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(checksum_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadDataBlock::Header) +{ + int64_t len = 0; + len += NS_::encoded_length_i32(occupy_size_); + len += NS_::encoded_length_i32(data_size_); + len += NS_::encoded_length_i64(checksum_); + return len; +} + +int64_t ObDirectLoadDataBlock::get_header_size() +{ + Header header; + return header.get_serialize_size(); +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block.h b/src/storage/direct_load/ob_direct_load_data_block.h new file mode 100644 index 0000000000..1a8c565d62 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block.h @@ -0,0 +1,37 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/utility/ob_print_utils.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadDataBlock +{ +public: + static const int64_t DEFAULT_DATA_BLOCK_SIZE = 128 * 1024; // 128K + struct Header + { + OB_UNIS_VERSION(1); + public: + Header(); + ~Header(); + void reset(); + TO_STRING_KV(K_(occupy_size), K_(data_size), K_(checksum)); + public: + int32_t occupy_size_; // occupy size of data block, include header + int32_t data_size_; // size of raw data, include header + int64_t checksum_; // checksum of valid data + }; +public: + static int64_t get_header_size(); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block_decoder.h b/src/storage/direct_load/ob_direct_load_data_block_decoder.h new file mode 100644 index 0000000000..3a3fc7e16c --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block_decoder.h @@ -0,0 +1,232 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/checksum/ob_crc64.h" +#include "lib/compress/ob_compressor.h" +#include "lib/compress/ob_compressor_pool.h" +#include "lib/utility/ob_print_utils.h" +#include "share/ob_errno.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadDataBlockDecoder +{ +public: + ObDirectLoadDataBlockDecoder(); + ~ObDirectLoadDataBlockDecoder(); + void reuse(); + void reset(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + int prepare_data_block(char *buf, int64_t buf_size, int64_t &data_size); + int set_pos(int64_t pos); + template + int read_next_item(T &item); + template + int read_item(int64_t pos, T &item); + OB_INLINE const Header &get_header() const { return header_; } + OB_INLINE int64_t get_end_pos() const { return buf_size_; } + TO_STRING_KV(K_(header), K_(compressor_type), KP_(compressor), KP_(buf), K_(buf_size), K_(pos), + KP_(decompress_buf), KP_(decompress_buf_size)); +protected: + Header header_; + common::ObCompressorType compressor_type_; + common::ObCompressor *compressor_; + common::ObArenaAllocator allocator_; + char *buf_; + int64_t buf_size_; + int64_t pos_; + char *decompress_buf_; + int64_t decompress_buf_size_; // buf capacity + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockDecoder); +}; + +template +ObDirectLoadDataBlockDecoder
::ObDirectLoadDataBlockDecoder() + : compressor_type_(ObCompressorType::INVALID_COMPRESSOR), + compressor_(nullptr), + allocator_("TLD_DBDecoder"), + buf_(nullptr), + buf_size_(0), + pos_(0), + decompress_buf_(nullptr), + decompress_buf_size_(0), + is_inited_(false) +{ +} + +template +ObDirectLoadDataBlockDecoder
::~ObDirectLoadDataBlockDecoder() +{ + reset(); +} + +template +void ObDirectLoadDataBlockDecoder
::reuse() +{ + header_.reset(); + buf_ = nullptr; + buf_size_ = 0; + pos_ = 0; +} + +template +void ObDirectLoadDataBlockDecoder
::reset() +{ + header_.reset(); + compressor_type_ = common::ObCompressorType::INVALID_COMPRESSOR; + compressor_ = nullptr; + buf_ = nullptr; + buf_size_ = 0; + pos_ = 0; + decompress_buf_ = nullptr; + decompress_buf_size_ = 0; + allocator_.reset(); + is_inited_ = false; +} + +template +int ObDirectLoadDataBlockDecoder
::init(int64_t data_block_size, + common::ObCompressorType compressor_type) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockEncoder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(data_block_size), K(compressor_type)); + } else { + allocator_.set_tenant_id(MTL_ID()); + if (common::ObCompressorType::NONE_COMPRESSOR != compressor_type) { + char *buf = nullptr; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(data_block_size)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to alloc buf", KR(ret), K(data_block_size)); + } else if (OB_FAIL(common::ObCompressorPool::get_instance().get_compressor(compressor_type, + compressor_))) { + STORAGE_LOG(WARN, "fail to get compressor, ", KR(ret), K(compressor_type)); + } else { + decompress_buf_ = buf; + decompress_buf_size_ = data_block_size; + } + } + if (OB_SUCC(ret)) { + compressor_type_ = compressor_type; + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockDecoder
::prepare_data_block(char *buf, int64_t buf_size, + int64_t &data_size) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockDecoder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == buf || buf_size <= 0)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), KP(buf), K(buf_size)); + } else if (buf_size <= header_.get_serialize_size()) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected buf size", KR(ret), K(buf_size)); + } else { + pos_ = 0; + // deserialize header + if (OB_FAIL(header_.deserialize(buf, buf_size, pos_))) { + STORAGE_LOG(WARN, "fail to deserialize header", KR(ret), K(buf_size), K(pos_)); + } else { + data_size = header_.occupy_size_; + if (OB_UNLIKELY(data_size > buf_size)) { + ret = common::OB_BUF_NOT_ENOUGH; + } else { + buf_ = buf; + buf_size_ = header_.occupy_size_; + } + } + // valid checksum + if (OB_SUCC(ret)) { + const int64_t checksum = ob_crc64_sse42(0, buf + pos_, header_.occupy_size_ - pos_); + if (OB_UNLIKELY(checksum != header_.checksum_)) { + ret = common::OB_CHECKSUM_ERROR; + STORAGE_LOG(WARN, "fail to valid checksum", KR(ret), K(header_), K(checksum)); + } + } + // do decompress + if (OB_SUCC(ret) && header_.occupy_size_ != header_.data_size_) { + int64_t decompress_size = 0; + if (OB_UNLIKELY(common::ObCompressorType::NONE_COMPRESSOR == compressor_type_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected compressor type", KR(ret)); + } else if (OB_FAIL(compressor_->decompress(buf + pos_, buf_size - pos_, + decompress_buf_ + pos_, + decompress_buf_size_ - pos_, decompress_size))) { + STORAGE_LOG(WARN, "fail to decompress", KR(ret)); + } else if (OB_UNLIKELY(decompress_size + pos_ != header_.data_size_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected decompress size", KR(ret), K(header_), K(decompress_size)); + } else { + buf_ = decompress_buf_; + buf_size_ = decompress_size + pos_; + } + } + } + return ret; +} + +template +int ObDirectLoadDataBlockDecoder
::set_pos(int64_t pos) +{ + int ret = common::OB_SUCCESS; + const int64_t header_size = header_.get_serialize_size(); + if (OB_UNLIKELY(pos < header_size || pos > buf_size_)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(pos), K(header_size), K(buf_size_)); + } else { + pos_ = pos; + } + return ret; +} + +template +template +int ObDirectLoadDataBlockDecoder
::read_next_item(T &item) +{ + int ret = common::OB_SUCCESS; + if (pos_ >= buf_size_) { + ret = common::OB_ITER_END; + } else if (OB_FAIL(item.deserialize(buf_, buf_size_, pos_))) { + STORAGE_LOG(WARN, "fail to deserialize item", KR(ret), K(buf_size_), K(pos_)); + } + return ret; +} + +template +template +int ObDirectLoadDataBlockDecoder
::read_item(int64_t pos, T &item) +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(pos >= buf_size_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected read pos", KR(ret)); + } else if (OB_FAIL(item.deserialize(buf_, buf_size_, pos))) { + STORAGE_LOG(WARN, "fail to deserialize item", KR(ret), K(buf_size_), K(pos)); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block_encoder.h b/src/storage/direct_load/ob_direct_load_data_block_encoder.h new file mode 100644 index 0000000000..831a4d8025 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block_encoder.h @@ -0,0 +1,234 @@ + +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/checksum/ob_crc64.h" +#include "lib/compress/ob_compressor.h" +#include "lib/compress/ob_compressor_pool.h" +#include "lib/utility/ob_print_utils.h" +#include "share/ob_errno.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadDataBlockEncoder +{ + static const int64_t APPLY_COMPRESSION_THRESHOLD = 90; // compression ratio to apply compression +public: + ObDirectLoadDataBlockEncoder(); + ~ObDirectLoadDataBlockEncoder(); + void reuse(); + void reset(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + template + int write_item(const T &item); + bool has_item() const { return pos_ > header_size_; } + int64_t get_pos() const { return pos_; } + Header &get_header() { return header_; } + int build_data_block(char *&buf, int64_t &buf_size); + template + int build_data_block(const T &item, char *buf, int64_t buf_size, int64_t &data_size); + TO_STRING_KV(K_(header), K_(header_size), K_(compressor_type), KP_(compressor), KP_(buf), + K_(buf_size), K_(pos), KP_(compress_buf), K_(compress_buf_size)); +protected: + Header header_; + int64_t header_size_; + common::ObCompressorType compressor_type_; + common::ObCompressor *compressor_; + common::ObArenaAllocator allocator_; + char *buf_; + int64_t buf_size_; // buf capacity + int64_t pos_; + char *compress_buf_; + int64_t compress_buf_size_; // buf capacity + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockEncoder); +}; + +template +ObDirectLoadDataBlockEncoder
::ObDirectLoadDataBlockEncoder() + : header_size_(0), + compressor_type_(common::ObCompressorType::INVALID_COMPRESSOR), + compressor_(nullptr), + allocator_("TLD_DBEncoder"), + buf_(nullptr), + buf_size_(0), + pos_(0), + compress_buf_(nullptr), + compress_buf_size_(0), + is_inited_(false) +{ +} + +template +ObDirectLoadDataBlockEncoder
::~ObDirectLoadDataBlockEncoder() +{ + reset(); +} + +template +void ObDirectLoadDataBlockEncoder
::reuse() +{ + header_.reset(); + pos_ = header_size_; +} + +template +void ObDirectLoadDataBlockEncoder
::reset() +{ + header_.reset(); + header_size_ = 0; + compressor_type_ = common::ObCompressorType::INVALID_COMPRESSOR; + compressor_ = nullptr; + buf_ = nullptr; + buf_size_ = 0; + pos_ = 0; + compress_buf_ = nullptr; + compress_buf_size_ = 0; + allocator_.reset(); + is_inited_ = false; +} + +template +int ObDirectLoadDataBlockEncoder
::init(int64_t data_block_size, + common::ObCompressorType compressor_type) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockEncoder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(data_block_size), K(compressor_type)); + } else { + allocator_.set_tenant_id(MTL_ID()); + const int64_t alloc_buf_size = + data_block_size + + (compressor_type != common::ObCompressorType::NONE_COMPRESSOR ? data_block_size : 0); + char *buf = nullptr; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(alloc_buf_size)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to alloc buf", KR(ret), K(alloc_buf_size)); + } else if (common::ObCompressorType::NONE_COMPRESSOR != compressor_type && + OB_FAIL(common::ObCompressorPool::get_instance().get_compressor(compressor_type, + compressor_))) { + STORAGE_LOG(WARN, "fail to get compressor, ", KR(ret), K(compressor_type)); + } else { + header_size_ = header_.get_serialize_size(); + compressor_type_ = compressor_type; + buf_ = buf; + buf_size_ = data_block_size; + pos_ = header_size_; + if (ObCompressorType::NONE_COMPRESSOR != compressor_type_) { + compress_buf_ = buf + data_block_size; + compress_buf_size_ = data_block_size; + } + is_inited_ = true; + } + } + return ret; +} + +template +template +int ObDirectLoadDataBlockEncoder
::write_item(const T &item) +{ + int ret = common::OB_SUCCESS; + const int64_t item_size = item.get_serialize_size(); + if (item_size > buf_size_ - header_size_) { + ret = common::OB_SIZE_OVERFLOW; + } else if (item.get_serialize_size() + pos_ > buf_size_) { + ret = common::OB_BUF_NOT_ENOUGH; + } else if (OB_FAIL(item.serialize(buf_, buf_size_, pos_))) { + STORAGE_LOG(WARN, "fail to serialize item", KR(ret)); + } + return ret; +} + +template +int ObDirectLoadDataBlockEncoder
::build_data_block(char *&buf, int64_t &buf_size) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockEncoder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!has_item())) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "unexpected build empty data block", KR(ret)); + } else { + buf = buf_; + buf_size = pos_; + // do compression + if (common::ObCompressorType::NONE_COMPRESSOR != compressor_type_) { + const int64_t data_size = pos_ - header_size_; + int64_t compress_size = 0; + if (OB_FAIL(compressor_->compress(buf_ + header_size_, data_size, + compress_buf_ + header_size_, + compress_buf_size_ - header_size_, compress_size))) { + ret = common::OB_SUCCESS; // give up compression + } else if (compress_size * 100 < data_size * APPLY_COMPRESSION_THRESHOLD) { + // apply compression + buf = compress_buf_; + buf_size = compress_size + header_size_; + } + } + // serialize header + if (OB_SUCC(ret)) { + int64_t pos = 0; + header_.data_size_ = pos_; + header_.occupy_size_ = buf_size; + header_.checksum_ = ob_crc64_sse42(0, buf + header_size_, pos_ - header_size_); + if (OB_FAIL(header_.serialize(buf, buf_size, pos))) { + STORAGE_LOG(WARN, "fail to serialize header", KR(ret)); + } + } + } + return ret; +} + +template +template +int ObDirectLoadDataBlockEncoder
::build_data_block(const T &item, char *buf, + int64_t buf_size, int64_t &data_size) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockEncoder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == buf || buf_size <= 0)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), KP(buf), K(buf_size)); + } else if (OB_UNLIKELY(item.get_serialize_size() + header_size_ > buf_size)) { + ret = common::OB_BUF_NOT_ENOUGH; + STORAGE_LOG(WARN, "buf not enough", KR(ret), K(buf_size), K(item.get_serialize_size())); + } else { + // serialize item + if (OB_FAIL(item.serialize(buf, buf_size, pos_))) { + STORAGE_LOG(WARN, "fail to serialize item", KR(ret)); + } + // serialize header + else { + int64_t pos = 0; + data_size = pos_; + header_.data_size_ = data_size; + header_.occupy_size_ = data_size; + header_.checksum_ = ob_crc64_sse42(0, buf + header_size_, data_size - header_size_); + if (OB_FAIL(header_.serialize(buf, buf_size, pos))) { + STORAGE_LOG(WARN, "fail to serialize header", KR(ret)); + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block_reader.h b/src/storage/direct_load/ob_direct_load_data_block_reader.h new file mode 100644 index 0000000000..55d925ddd8 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block_reader.h @@ -0,0 +1,264 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_stat.h" +#include "share/config/ob_server_config.h" +#include "storage/direct_load/ob_direct_load_data_block_decoder.h" +#include "storage/direct_load/ob_direct_load_external_interface.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadDataBlockReader : public ObDirectLoadExternalIterator +{ +public: + ObDirectLoadDataBlockReader(); + virtual ~ObDirectLoadDataBlockReader(); + void reuse(); + void reset(); + int init(int64_t data_block_size, int64_t buf_size, common::ObCompressorType compressor_type); + int open(const ObDirectLoadTmpFileHandle &file_handle, int64_t offset, int64_t size); + int get_next_item(const T *&item) override; + OB_INLINE int64_t get_block_count() const { return block_count_; } +protected: + virtual int prepare_read_block() { return common::OB_SUCCESS; } +private: + int read_next_buffer(); + int switch_next_block(); +protected: + common::ObArenaAllocator allocator_; + int64_t data_block_size_; + char *buf_; + int64_t buf_capacity_; + int64_t buf_size_; + int64_t buf_pos_; + int64_t io_timeout_ms_; + ObDirectLoadDataBlockDecoder
data_block_reader_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + T curr_item_; + int64_t offset_; + int64_t read_size_; + int64_t block_count_; + bool is_opened_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockReader); +}; + +template +ObDirectLoadDataBlockReader::ObDirectLoadDataBlockReader() + : allocator_("TLD_DBReader"), + data_block_size_(0), + buf_(nullptr), + buf_capacity_(0), + buf_size_(0), + buf_pos_(0), + io_timeout_ms_(0), + offset_(0), + read_size_(0), + block_count_(0), + is_opened_(false), + is_inited_(false) +{ +} + +template +ObDirectLoadDataBlockReader::~ObDirectLoadDataBlockReader() +{ + reset(); +} + +template +void ObDirectLoadDataBlockReader::reuse() +{ + buf_size_ = 0; + buf_pos_ = 0; + data_block_reader_.reuse(); + file_io_handle_.reset(); + curr_item_.reuse(); + offset_ = 0; + read_size_ = 0; + block_count_ = 0; + is_opened_ = false; +} + +template +void ObDirectLoadDataBlockReader::reset() +{ + data_block_size_ = 0; + buf_ = nullptr; + buf_capacity_ = 0; + buf_size_ = 0; + buf_pos_ = 0; + io_timeout_ms_ = 0; + allocator_.reset(); + data_block_reader_.reset(); + file_io_handle_.reset(); + curr_item_.reset(); + offset_ = 0; + read_size_ = 0; + block_count_ = 0; + is_opened_ = false; + is_inited_ = false; +} + +template +int ObDirectLoadDataBlockReader::init(int64_t data_block_size, int64_t buf_size, + common::ObCompressorType compressor_type) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockReader init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + buf_size <= 0 || buf_size % DIO_ALIGN_SIZE != 0 || + data_block_size > buf_size || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(data_block_size), K(buf_size), K(compressor_type)); + } else { + allocator_.set_tenant_id(MTL_ID()); + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to allocate memory", KR(ret), K(buf_size)); + } else if (OB_FAIL(data_block_reader_.init(buf_size, compressor_type))) { + STORAGE_LOG(WARN, "fail to init data block reader", KR(ret)); + } else { + data_block_size_ = data_block_size; + buf_capacity_ = buf_size; + io_timeout_ms_ = std::max(GCONF._data_storage_io_timeout / 1000, DEFAULT_IO_WAIT_TIME_MS); + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockReader::open(const ObDirectLoadTmpFileHandle &file_handle, + int64_t offset, int64_t size) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockReader not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_opened_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "external block reader already opened", KR(ret)); + } else if (OB_UNLIKELY(!file_handle.is_valid() || offset < 0 || size <= 0)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(file_handle), K(offset), K(size)); + } else { + reuse(); + offset_ = offset; + read_size_ = size; + if (OB_FAIL(file_io_handle_.open(file_handle))) { + STORAGE_LOG(WARN, "fail to open file handle", KR(ret)); + } else if (OB_FAIL(switch_next_block())) { + STORAGE_LOG(WARN, "fail to switch next block", KR(ret)); + } else { + is_opened_ = true; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockReader::read_next_buffer() +{ + int ret = common::OB_SUCCESS; + if (0 == read_size_) { + ret = common::OB_ITER_END; + } else { + // squash buf + const int64_t data_size = buf_size_ - buf_pos_; + if (data_size > 0) { + MEMMOVE(buf_, buf_ + buf_pos_, data_size); + } + buf_pos_ = 0; + buf_size_ = data_size; + // read buffer + const int64_t read_size = MIN(buf_capacity_ - buf_size_, read_size_); + if (OB_FAIL(file_io_handle_.aio_pread(buf_ + buf_size_, read_size, offset_))) { + STORAGE_LOG(WARN, "fail to do aio read from tmp file", KR(ret)); + } else if (OB_FAIL(file_io_handle_.wait(io_timeout_ms_))) { + STORAGE_LOG(WARN, "fail to wait io finish", KR(ret), K(io_timeout_ms_)); + } else { + buf_size_ += read_size; + offset_ += read_size; + read_size_ -= read_size; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockReader::switch_next_block() +{ + int ret = common::OB_SUCCESS; + int64_t data_size = 0; + if (buf_size_ - buf_pos_ == 0 && OB_FAIL(read_next_buffer())) { // empty buf + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to read next buffer", KR(ret)); + } + } else if (OB_FAIL(data_block_reader_.prepare_data_block(buf_ + buf_pos_, buf_size_ - buf_pos_, + data_size))) { + if (OB_UNLIKELY(common::OB_BUF_NOT_ENOUGH != ret)) { + STORAGE_LOG(WARN, "fail to prepare data block", KR(ret), K(buf_pos_), K(buf_size_)); + } else { + if (OB_FAIL(read_next_buffer())) { + STORAGE_LOG(WARN, "fail to read next buffer", KR(ret)); + } else if (OB_FAIL(data_block_reader_.prepare_data_block(buf_ + buf_pos_, + buf_size_ - buf_pos_, data_size))) { + STORAGE_LOG(WARN, "fail to prepare data block", KR(ret), K(buf_pos_), K(buf_size_)); + } + } + } + if (OB_SUCC(ret)) { + const int64_t data_block_size = ALIGN_UP(data_size, DIO_ALIGN_SIZE); + buf_pos_ += MAX(data_block_size_, data_block_size); + ++block_count_; + if (OB_FAIL(prepare_read_block())) { + STORAGE_LOG(WARN, "fail to prepare read block", KR(ret)); + } + } + return ret; +} + +template +int ObDirectLoadDataBlockReader::get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + item = nullptr; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockReader not init", KR(ret), KP(this)); + } else { + curr_item_.reuse(); + if (OB_FAIL(data_block_reader_.read_next_item(curr_item_))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + if (OB_FAIL(switch_next_block())) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to switch next block", KR(ret)); + } + } else if (OB_FAIL(data_block_reader_.read_next_item(curr_item_))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + item = &curr_item_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_block_writer.h b/src/storage/direct_load/ob_direct_load_data_block_writer.h new file mode 100644 index 0000000000..a9a7d8792a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_block_writer.h @@ -0,0 +1,280 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_data_block_encoder.h" +#include "storage/direct_load/ob_direct_load_external_interface.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObIDirectLoadDataBlockFlushCallback +{ +public: + virtual ~ObIDirectLoadDataBlockFlushCallback() = default; + virtual int write(char *buf, int64_t buf_size, int64_t offset) = 0; +}; + +template +class ObDirectLoadDataBlockWriter : public ObDirectLoadExternalWriter +{ +public: + ObDirectLoadDataBlockWriter(); + virtual ~ObDirectLoadDataBlockWriter(); + void reuse(); + void reset(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type, char *extra_buf, + int64_t extra_buf_size, ObIDirectLoadDataBlockFlushCallback *callback); + int open(const ObDirectLoadTmpFileHandle &file_handle) override; + int write_item(const T &item) override; + int close() override; + OB_INLINE int64_t get_file_size() const { return offset_; } + OB_INLINE int64_t get_block_count() const { return block_count_; } + OB_INLINE int64_t get_max_block_size() const { return max_block_size_; } +protected: + virtual int pre_write_item() { return common::OB_SUCCESS; } + virtual int pre_flush_buffer() { return common::OB_SUCCESS; } + int flush_buffer(); + int flush_extra_buffer(const T &item); +protected: + int64_t data_block_size_; + char *extra_buf_; + int64_t extra_buf_size_; + ObDirectLoadDataBlockEncoder
data_block_writer_; + int64_t io_timeout_ms_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + int64_t offset_; + int64_t block_count_; + int64_t max_block_size_; + ObIDirectLoadDataBlockFlushCallback *callback_; + bool is_opened_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockWriter); +}; + +template +ObDirectLoadDataBlockWriter::ObDirectLoadDataBlockWriter() + : data_block_size_(0), + extra_buf_(nullptr), + extra_buf_size_(0), + io_timeout_ms_(0), + offset_(0), + block_count_(0), + max_block_size_(0), + is_opened_(false), + is_inited_(false) +{ +} + +template +ObDirectLoadDataBlockWriter::~ObDirectLoadDataBlockWriter() +{ + reset(); +} + +template +void ObDirectLoadDataBlockWriter::reuse() +{ + data_block_writer_.reuse(); + file_io_handle_.reset(); + offset_ = 0; + block_count_ = 0; + max_block_size_ = 0; + is_opened_ = false; +} + +template +void ObDirectLoadDataBlockWriter::reset() +{ + data_block_size_ = 0; + extra_buf_ = nullptr; + extra_buf_size_ = 0; + data_block_writer_.reset(); + io_timeout_ms_ = 0; + file_io_handle_.reset(); + offset_ = 0; + block_count_ = 0; + max_block_size_ = 0; + callback_ = nullptr; + is_opened_ = false; + is_inited_ = false; +} + +template +int ObDirectLoadDataBlockWriter::init(int64_t data_block_size, + common::ObCompressorType compressor_type, + char *extra_buf, int64_t extra_buf_size, + ObIDirectLoadDataBlockFlushCallback *callback) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockWriter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(data_block_size), K(compressor_type)); + } else { + if (OB_FAIL(data_block_writer_.init(data_block_size, compressor_type))) { + STORAGE_LOG(WARN, "fail to init data block writer", KR(ret)); + } else { + data_block_size_ = data_block_size; + extra_buf_ = extra_buf; + extra_buf_size_ = extra_buf_size; + io_timeout_ms_ = std::max(GCONF._data_storage_io_timeout / 1000, DEFAULT_IO_WAIT_TIME_MS); + callback_ = callback; + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockWriter::open(const ObDirectLoadTmpFileHandle &file_handle) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_opened_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "external block writer already opened", KR(ret)); + } else if (OB_UNLIKELY(!file_handle.is_valid())) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(file_handle)); + } else { + reuse(); + if (OB_FAIL(file_io_handle_.open(file_handle))) { + STORAGE_LOG(WARN, "fail to assign file handle", KR(ret)); + } else { + is_opened_ = true; + } + } + return ret; +} + +template +int ObDirectLoadDataBlockWriter::write_item(const T &item) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_opened_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "external block writer not open", KR(ret)); + } else { + if (OB_FAIL(pre_write_item())) { + STORAGE_LOG(WARN, "fail to pre write item", KR(ret)); + } else if (OB_FAIL(data_block_writer_.write_item(item))) { + if (OB_LIKELY(common::OB_BUF_NOT_ENOUGH == ret)) { + if (OB_FAIL(flush_buffer())) { + STORAGE_LOG(WARN, "fail to flush buffer", KR(ret)); + } else if (OB_FAIL(pre_write_item())) { + STORAGE_LOG(WARN, "fail to pre write item", KR(ret)); + } else if (OB_FAIL(data_block_writer_.write_item(item))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } + } else if (common::OB_SIZE_OVERFLOW == ret && nullptr != extra_buf_) { + if (data_block_writer_.has_item() && OB_FAIL(flush_buffer())) { + STORAGE_LOG(WARN, "fail to flush buffer", KR(ret)); + } else if (OB_FAIL(pre_write_item())) { + STORAGE_LOG(WARN, "fail to pre write item", KR(ret)); + } else if (OB_FAIL(flush_extra_buffer(item))) { + STORAGE_LOG(WARN, "fail to flush extra buffer", KR(ret)); + } + } else { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } + } + } + return ret; +} + +template +int ObDirectLoadDataBlockWriter::flush_buffer() +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_flush_buffer_time_us); + int ret = common::OB_SUCCESS; + if (OB_FAIL(pre_flush_buffer())) { + STORAGE_LOG(WARN, "fail to pre flush buffer", KR(ret)); + } else { + char *buf = nullptr; + int64_t buf_size = 0; + if (OB_FAIL(data_block_writer_.build_data_block(buf, buf_size))) { + STORAGE_LOG(WARN, "fail to build data block", KR(ret)); + } else if (OB_FAIL(file_io_handle_.aio_write(buf, data_block_size_))) { + STORAGE_LOG(WARN, "fail to do aio write tmp file", KR(ret)); + } else if (nullptr != callback_ && OB_FAIL(callback_->write(buf, data_block_size_, offset_))) { + STORAGE_LOG(WARN, "fail to callback write", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_INC(external_write_bytes, data_block_size_); + data_block_writer_.reuse(); + offset_ += data_block_size_; + ++block_count_; + max_block_size_ = MAX(max_block_size_, data_block_size_); + } + } + return ret; +} + +template +int ObDirectLoadDataBlockWriter::flush_extra_buffer(const T &item) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_flush_buffer_time_us); + int ret = common::OB_SUCCESS; + if (OB_FAIL(pre_flush_buffer())) { + STORAGE_LOG(WARN, "fail to pre flush buffer", KR(ret)); + } else { + int64_t data_size = 0; + int64_t data_block_size = 0; + if (OB_FAIL( + data_block_writer_.build_data_block(item, extra_buf_, extra_buf_size_, data_size))) { + STORAGE_LOG(WARN, "fail to build data block", KR(ret)); + } else if (FALSE_IT(data_block_size = ALIGN_UP(data_size, DIO_ALIGN_SIZE))) { + } else if (OB_FAIL(file_io_handle_.aio_write(extra_buf_, data_block_size))) { + STORAGE_LOG(WARN, "fail to do aio write tmp file", KR(ret)); + } else if (nullptr != callback_ && + OB_FAIL(callback_->write(extra_buf_, data_block_size, offset_))) { + STORAGE_LOG(WARN, "fail to callback write", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_INC(external_write_bytes, data_block_size); + data_block_writer_.reuse(); + offset_ += data_block_size; + ++block_count_; + max_block_size_ = MAX(max_block_size_, data_block_size); + } + } + return ret; +} + +template +int ObDirectLoadDataBlockWriter::close() +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadDataBlockWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_opened_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "external block writer not open", KR(ret)); + } else { + if (data_block_writer_.has_item() && OB_FAIL(flush_buffer())) { + STORAGE_LOG(WARN, "fail to flush buffer", KR(ret)); + } else if (OB_FAIL(file_io_handle_.wait(io_timeout_ms_))) { + STORAGE_LOG(WARN, "fail to wait io finish", KR(ret), K(io_timeout_ms_)); + } else { + is_opened_ = false; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_fuse.cpp b/src/storage/direct_load/ob_direct_load_data_fuse.cpp new file mode 100644 index 0000000000..071d7b0016 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_fuse.cpp @@ -0,0 +1,422 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_data_fuse.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace share; +using namespace sql; + +/** + * ObDirectLoadSSTableScanMergeParam + */ + +ObDirectLoadDataFuseParam::ObDirectLoadDataFuseParam() + : datum_utils_(nullptr), error_row_handler_(nullptr), result_info_(nullptr) +{ +} + +ObDirectLoadDataFuseParam::~ObDirectLoadDataFuseParam() +{ +} + +bool ObDirectLoadDataFuseParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != datum_utils_ && + nullptr != error_row_handler_ && nullptr != result_info_; +} + +/** + * TwoRowsMerger + */ +ObDirectLoadDataFuse::TwoRowsMerger::TwoRowsMerger() + : rowkey_column_num_(0), item_cnt_(0), is_unique_champion_(false), is_inited_(false) +{ +} + +ObDirectLoadDataFuse::TwoRowsMerger::~TwoRowsMerger() +{ +} + +int ObDirectLoadDataFuse::TwoRowsMerger::init(int64_t rowkey_column_num, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("TwoRowsMerger init twice", KR(ret), KP(this)); + } else { + rowkey_column_num_ = rowkey_column_num; + datum_utils_ = datum_utils; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadDataFuse::TwoRowsMerger::compare(const ObDatumRow &first_row, + const ObDatumRow &second_row, int &cmp_ret) +{ + int ret = OB_SUCCESS; + ObDatumRowkey first_key(first_row.storage_datums_, rowkey_column_num_); + ObDatumRowkey second_key(second_row.storage_datums_, rowkey_column_num_); + if (OB_FAIL(first_key.compare(second_key, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare", KR(ret)); + } + return ret; +} + +int ObDirectLoadDataFuse::TwoRowsMerger::push(const Item &item) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("TwoRowsMerger not init", KR(ret)); + } else if (item_cnt_ >= ITER_COUNT) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to push", KR(ret)); + } else { + items_[item_cnt_++] = item; + } + return ret; +} + +int ObDirectLoadDataFuse::TwoRowsMerger::top(const Item *&item) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("TwoRowsMerger not init", KR(ret)); + } else if (item_cnt_ <= 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to top", KR(ret)); + } else { + item = &(items_[item_cnt_ - 1]); + } + return ret; +} + +int ObDirectLoadDataFuse::TwoRowsMerger::pop() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("TwoRowsMerger not init", KR(ret)); + } else if (item_cnt_ <= 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to top", KR(ret)); + } else { + --item_cnt_; + } + return ret; +} + +int ObDirectLoadDataFuse::TwoRowsMerger::rebuild() +{ + int ret = OB_SUCCESS; + is_unique_champion_ = true; + if (item_cnt_ == 2) { + int cmp_ret = 0; + if (OB_FAIL(compare(*items_[0].datum_row_, *items_[1].datum_row_, cmp_ret))) { + LOG_WARN("compare failed", KR(ret)); + } else if (cmp_ret == 0) { + is_unique_champion_ = false; + } else if (cmp_ret < 0) { + std::swap(items_[0], items_[1]); + } + } + return ret; +} +/** + * ObDirectLoadDataFuse + */ + +ObDirectLoadDataFuse::ObDirectLoadDataFuse() + : consumer_cnt_(0), is_inited_(false) +{ +} + +ObDirectLoadDataFuse::~ObDirectLoadDataFuse() +{ +} + +int ObDirectLoadDataFuse::init(const ObDirectLoadDataFuseParam ¶m, + ObIStoreRowIterator *origin_iter, ObIStoreRowIterator *load_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDataFuse init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() || nullptr == origin_iter || nullptr == load_iter)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", K(ret), K(param), KP(origin_iter), KP(load_iter)); + } else { + param_ = param; + if (OB_FAIL(rows_merger_.init(param.table_data_desc_.rowkey_column_num_, param.datum_utils_))) { + LOG_WARN("fail to init rows merger", KR(ret)); + } else { + iters_[ORIGIN_IDX] = origin_iter; + iters_[LOAD_IDX] = load_iter; + consumers_[consumer_cnt_++] = ORIGIN_IDX; + consumers_[consumer_cnt_++] = LOAD_IDX; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadDataFuse::supply_consume() +{ + int ret = OB_SUCCESS; + Item item; + for (int64_t i = 0; OB_SUCC(ret) && i < consumer_cnt_; ++i) { + const int64_t iter_idx = consumers_[i]; + ObIStoreRowIterator *iter = iters_[iter_idx]; + if (OB_FAIL(iter->get_next_row(item.datum_row_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from scanner", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } else { + item.iter_idx_ = iter_idx; + if (OB_FAIL(rows_merger_.push(item))) { + LOG_WARN("fail to push item", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + consumer_cnt_ = 0; + if (OB_FAIL(rows_merger_.rebuild())) { + LOG_WARN("fail to rebuild", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadDataFuse::inner_get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (rows_merger_.empty()) { + ret = OB_ITER_END; + } else if (rows_merger_.is_unique_champion()) { + const Item *item = nullptr; + if (OB_FAIL(rows_merger_.top(item))) { + LOG_WARN("fail to rebuild", KR(ret)); + } else { + datum_row = item->datum_row_; + consumers_[consumer_cnt_++] = item->iter_idx_; + if (OB_FAIL(rows_merger_.pop())) { + LOG_WARN("fail to pop item", KR(ret)); + } else if (item->iter_idx_ == LOAD_IDX) { + ATOMIC_INC(¶m_.result_info_->rows_affected_); + } + } + } else { + const Item *item = nullptr; + while (OB_SUCC(ret) && !rows_merger_.empty()) { + if (OB_FAIL(rows_merger_.top(item))) { + LOG_WARN("fail to rebuild", KR(ret)); + } else { + if (ObLoadDupActionType::LOAD_STOP_ON_DUP == param_.dup_action_) { + if (item->iter_idx_ == ORIGIN_IDX) { + datum_row = item->datum_row_; + } else { + ObTableLoadErrorRowHandler *error_row_handler = param_.error_row_handler_; + if (OB_FAIL(error_row_handler->append_error_row(*item->datum_row_))) { + LOG_WARN("fail to append row to error row handler", KR(ret), K(item->datum_row_)); + } + } + } else if (ObLoadDupActionType::LOAD_IGNORE == param_.dup_action_) { + if (item->iter_idx_ == ORIGIN_IDX) { + datum_row = item->datum_row_; + } else { + ATOMIC_INC(¶m_.result_info_->skipped_); + } + } else if (ObLoadDupActionType::LOAD_REPLACE == param_.dup_action_) { + if (item->iter_idx_ == ORIGIN_IDX) { + ATOMIC_INC(¶m_.result_info_->deleted_); + ATOMIC_AAF(¶m_.result_info_->rows_affected_, 2); + } else { + datum_row = item->datum_row_; + } + } + if (OB_SUCC(ret)) { + consumers_[consumer_cnt_++] = item->iter_idx_; + if (OB_FAIL(rows_merger_.pop())) { + LOG_WARN("fail to pop item", KR(ret)); + } + } + } + } + } + return ret; +} + +int ObDirectLoadDataFuse::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDataFuse not init", KR(ret), KP(this)); + } else { + if (consumer_cnt_ > 0 && OB_FAIL(supply_consume())) { + LOG_WARN("fail to supply consume", KR(ret)); + } else if (OB_FAIL(inner_get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do inner get next row", KR(ret)); + } + } + } + return ret; +} + +/** + * ObDirectLoadSSTableDataFuse + */ + +ObDirectLoadSSTableDataFuse::ObDirectLoadSSTableDataFuse() + : allocator_("TLD_DataFuse"), origin_iter_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadSSTableDataFuse::~ObDirectLoadSSTableDataFuse() +{ + if (nullptr != origin_iter_) { + origin_iter_->~ObIStoreRowIterator(); + allocator_.free(origin_iter_); + origin_iter_ = nullptr; + } +} + +int ObDirectLoadSSTableDataFuse::init(const ObDirectLoadDataFuseParam ¶m, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableDataFuse init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid()) || OB_ISNULL(origin_table) || !range.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", K(ret), K(param), KP(origin_table), K(range)); + } else { + // construct iters + if (OB_FAIL(origin_table->scan(range, allocator_, origin_iter_))) { + LOG_WARN("fail to scan origin table", KR(ret)); + } else { + ObDirectLoadSSTableScanMergeParam scan_merge_param; + scan_merge_param.tablet_id_ = param.tablet_id_; + scan_merge_param.table_data_desc_ = param.table_data_desc_; + scan_merge_param.datum_utils_ = param.datum_utils_; + scan_merge_param.error_row_handler_ = param.error_row_handler_; + scan_merge_param.result_info_ = param.result_info_; + if (OB_FAIL(scan_merge_.init(scan_merge_param, sstable_array, range))) { + LOG_WARN("fail to init scan merge", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(data_fuse_.init(param, origin_iter_, &scan_merge_))) { + LOG_WARN("fail to init data fuse", KR(ret)); + } else { + is_inited_ = true; + } + } + } + return ret; +} + +int ObDirectLoadSSTableDataFuse::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableDataFuse not init", KR(ret), KP(this)); + } else { + ret = data_fuse_.get_next_row(datum_row); + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableDataFuse + */ + +ObDirectLoadMultipleSSTableDataFuse::ObDirectLoadMultipleSSTableDataFuse() + : allocator_("TLD_DataFuse"), origin_iter_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableDataFuse::~ObDirectLoadMultipleSSTableDataFuse() +{ + if (nullptr != origin_iter_) { + origin_iter_->~ObIStoreRowIterator(); + allocator_.free(origin_iter_); + origin_iter_ = nullptr; + } +} + +int ObDirectLoadMultipleSSTableDataFuse::init( + const ObDirectLoadDataFuseParam ¶m, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableDataFuse init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid()) || OB_ISNULL(origin_table) || !range.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", K(ret), K(param), KP(origin_table), K(range)); + } else { + if (OB_FAIL(range_.assign(param.tablet_id_, range))) { + LOG_WARN("fail to assign range", KR(ret)); + } + // construct iters + else if (OB_FAIL(origin_table->scan(range, allocator_, origin_iter_))) { + LOG_WARN("fail to scan origin table", KR(ret)); + } else { + ObDirectLoadMultipleSSTableScanMergeParam scan_merge_param; + scan_merge_param.table_data_desc_ = param.table_data_desc_; + scan_merge_param.datum_utils_ = param.datum_utils_; + scan_merge_param.error_row_handler_ = param.error_row_handler_; + scan_merge_param.result_info_ = param.result_info_; + if (OB_FAIL(scan_merge_.init(scan_merge_param, sstable_array, range_))) { + LOG_WARN("fail to init scan merge", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(data_fuse_.init(param, origin_iter_, &scan_merge_))) { + LOG_WARN("fail to init data fuse", KR(ret)); + } else { + is_inited_ = true; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableDataFuse::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableDataFuse not init", KR(ret), KP(this)); + } else { + ret = data_fuse_.get_next_row(datum_row); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_data_fuse.h b/src/storage/direct_load/ob_direct_load_data_fuse.h new file mode 100644 index 0000000000..ecc0807736 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_data_fuse.h @@ -0,0 +1,129 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "share/table/ob_table_load_define.h" +#include "sql/resolver/cmd/ob_load_data_stmt.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h" +#include "storage/direct_load/ob_direct_load_origin_table.h" +#include "storage/direct_load/ob_direct_load_sstable_scan_merge.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadSSTable; +class ObDirectLoadMultipleSSTable; + +struct ObDirectLoadDataFuseParam +{ +public: + ObDirectLoadDataFuseParam(); + ~ObDirectLoadDataFuseParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(datum_utils), KP_(error_row_handler), + KP_(result_info)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + sql::ObLoadDupActionType dup_action_; + table::ObTableLoadResultInfo *result_info_; +}; + +class ObDirectLoadDataFuse +{ +public: + ObDirectLoadDataFuse(); + virtual ~ObDirectLoadDataFuse(); + int init(const ObDirectLoadDataFuseParam ¶m, ObIStoreRowIterator *origin_iter, + ObIStoreRowIterator *load_iter); + int get_next_row(const blocksstable::ObDatumRow *&datum_row); +protected: + int supply_consume(); + int inner_get_next_row(const blocksstable::ObDatumRow *&datum_row); +protected: + static const int64_t ITER_COUNT = 2; + static const int64_t ORIGIN_IDX = 0; + static const int64_t LOAD_IDX = 1; + struct Item + { + public: + const blocksstable::ObDatumRow *datum_row_; + int64_t iter_idx_; + TO_STRING_KV(K_(iter_idx), KPC_(datum_row)); + }; + class TwoRowsMerger + { + public: + TwoRowsMerger(); + ~TwoRowsMerger(); + int init(int64_t rowkey_column_num, const blocksstable::ObStorageDatumUtils *datum_utils); + int push(const Item &item); + int top(const Item *&item); + int pop(); + int rebuild(); + bool empty() const { return item_cnt_ == 0; } + bool is_unique_champion() const { return is_unique_champion_; } + private: + int compare(const blocksstable::ObDatumRow &first_row, + const blocksstable::ObDatumRow &second_row, int &cmp_ret); + private: + int64_t rowkey_column_num_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + Item items_[2]; + int64_t item_cnt_; + bool is_unique_champion_; + bool is_inited_; + }; +protected: + ObDirectLoadDataFuseParam param_; + ObIStoreRowIterator *iters_[ITER_COUNT]; + TwoRowsMerger rows_merger_; + int64_t consumers_[ITER_COUNT]; + int64_t consumer_cnt_; + bool is_inited_; +}; + +class ObDirectLoadSSTableDataFuse +{ +public: + ObDirectLoadSSTableDataFuse(); + ~ObDirectLoadSSTableDataFuse(); + int init(const ObDirectLoadDataFuseParam ¶m, ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range); + int get_next_row(const blocksstable::ObDatumRow *&datum_row); +private: + common::ObArenaAllocator allocator_; + ObIStoreRowIterator *origin_iter_; + ObDirectLoadSSTableScanMerge scan_merge_; + ObDirectLoadDataFuse data_fuse_; + bool is_inited_; +}; + +class ObDirectLoadMultipleSSTableDataFuse +{ +public: + ObDirectLoadMultipleSSTableDataFuse(); + ~ObDirectLoadMultipleSSTableDataFuse(); + int init(const ObDirectLoadDataFuseParam ¶m, ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range); + int get_next_row(const blocksstable::ObDatumRow *&datum_row); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMultipleDatumRange range_; + ObIStoreRowIterator *origin_iter_; + ObDirectLoadMultipleSSTableScanMerge scan_merge_; + ObDirectLoadDataFuse data_fuse_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_datum.cpp b/src/storage/direct_load/ob_direct_load_datum.cpp new file mode 100644 index 0000000000..817375d9d9 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_datum.cpp @@ -0,0 +1,347 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_datum.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +int ObDirectLoadDatumSerialization::serialize(char *buf, const int64_t buf_len, int64_t &pos, + const ObStorageDatum &datum) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(datum.pack_); + if (OB_NOT_NULL(datum.ptr_)) { + if (datum.len_ > 0) { + MEMCPY(buf + pos, datum.ptr_, datum.len_); + pos += datum.len_; + } + } + return ret; +} + +int ObDirectLoadDatumSerialization::deserialize(const char *buf, const int64_t data_len, + int64_t &pos, ObStorageDatum &datum) +{ + int ret = OB_SUCCESS; + uint32_t pack = datum.pack_; + OB_UNIS_DECODE(pack); + if (OB_SUCC(ret)) { + datum.pack_ = pack; + datum.ptr_ = buf + pos; + pos += datum.len_; + } + return ret; +} + +int64_t ObDirectLoadDatumSerialization::get_serialize_size(const ObStorageDatum &datum) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(datum.pack_); + len += datum.len_; + return len; +} + +/** + * ObDirectLoadDatumArray + */ + +ObDirectLoadDatumArray::ObDirectLoadDatumArray() + : allocator_("TLD_DatumArray"), capacity_(0), count_(0), datums_(nullptr) +{ + allocator_.set_tenant_id(MTL_ID()); +} + +ObDirectLoadDatumArray::~ObDirectLoadDatumArray() +{ + reset(); +} + +void ObDirectLoadDatumArray::reset() +{ + capacity_ = 0; + count_ = 0; + datums_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadDatumArray::reuse() +{ + count_ = 0; +} + +int ObDirectLoadDatumArray::assign(ObStorageDatum *datums, int32_t count) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(count > 0 && nullptr == datums)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(count)); + } else { + reset(); + capacity_ = count; + count_ = count; + datums_ = (count > 0 ? datums : nullptr); + } + return ret; +} + +int ObDirectLoadDatumArray::assign(const ObDirectLoadDatumArray &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + capacity_ = other.capacity_; + count_ = other.count_; + datums_ = other.datums_; + } + return ret; +} + +ObDirectLoadDatumArray &ObDirectLoadDatumArray::operator=(const ObDirectLoadDatumArray &other) +{ + if (this != &other) { + reset(); + capacity_ = other.capacity_; + count_ = other.count_; + datums_ = other.datums_; + } + return *this; +} + +int64_t ObDirectLoadDatumArray::get_deep_copy_size() const +{ + int64_t size = 0; + if (OB_LIKELY(is_valid())) { + size = count_ * sizeof(ObStorageDatum); + for (int64_t i = 0; i < count_; ++i) { + size += datums_[i].get_deep_copy_size(); + } + } + return size; +} + +int ObDirectLoadDatumArray::deep_copy(const ObDirectLoadDatumArray &src, char *buf, + const int64_t len, int64_t &pos) +{ + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reset(); + ObStorageDatum *datums = nullptr; + const int64_t datum_cnt = src.count_; + if (datum_cnt > 0) { + datums = new (buf + pos) ObStorageDatum[datum_cnt]; + pos += sizeof(ObStorageDatum) * datum_cnt; + } + for (int64_t i = 0; OB_SUCC(ret) && i < datum_cnt; i++) { + if (OB_FAIL(datums[i].deep_copy(src.datums_[i], buf, len, pos))) { + LOG_WARN("fail to deep copy storage datum", K(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + capacity_ = datum_cnt; + count_ = datum_cnt; + datums_ = datums; + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadDatumArray) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(count_); + for (int64_t i = 0; OB_SUCC(ret) && i < count_; ++i) { + if (OB_FAIL(ObDirectLoadDatumSerialization::serialize(buf, buf_len, pos, datums_[i]))) { + LOG_WARN("fail to serialize datum", KR(ret)); + } + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadDatumArray) +{ + int ret = OB_SUCCESS; + reuse(); + OB_UNIS_DECODE(count_); + if (OB_SUCC(ret) && count_ > capacity_) { + allocator_.reuse(); + void *buf = nullptr; + if (OB_ISNULL(buf = allocator_.alloc(sizeof(ObStorageDatum) * count_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else { + datums_ = new (buf) ObStorageDatum[count_]; + capacity_ = count_; + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < count_; ++i) { + if (OB_FAIL(ObDirectLoadDatumSerialization::deserialize(buf, data_len, pos, datums_[i]))) { + LOG_WARN("fail to deserialize datum", KR(ret)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadDatumArray) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(count_); + for (int64_t i = 0; i < count_; ++i) { + len += ObDirectLoadDatumSerialization::get_serialize_size(datums_[i]); + } + return len; +} + +DEF_TO_STRING(ObDirectLoadDatumArray) +{ + int64_t pos = 0; + J_OBJ_START(); + J_KV(K_(count)); + if (nullptr != buf && buf_len >= 0) { + if (nullptr != datums_) { + J_ARRAY_START(); + for (int64_t i = 0; i < count_; ++i) { + databuff_printf(buf, buf_len, pos, "col_id=%ld:", i); + pos += datums_[i].storage_to_string(buf + pos, buf_len - pos); + databuff_printf(buf, buf_len, pos, ","); + } + J_ARRAY_END(); + } + } + J_OBJ_END(); + return pos; +} + +/** + * ObDirectLoadConstDatumArray + */ + +ObDirectLoadConstDatumArray::ObDirectLoadConstDatumArray() + : count_(0), datums_(nullptr) +{ +} + +ObDirectLoadConstDatumArray::~ObDirectLoadConstDatumArray() +{ +} + +void ObDirectLoadConstDatumArray::reset() +{ + count_ = 0; + datums_ = nullptr; +} + +void ObDirectLoadConstDatumArray::reuse() +{ + reset(); +} + +int ObDirectLoadConstDatumArray::assign(ObStorageDatum *datums, int32_t count) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(count > 0 && nullptr == datums)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(count)); + } else { + count_ = count; + datums_ = (count > 0 ? datums : nullptr); + } + return ret; +} + +ObDirectLoadConstDatumArray &ObDirectLoadConstDatumArray::operator=( + const ObDirectLoadConstDatumArray &other) +{ + if (this != &other) { + count_ = other.count_; + datums_ = other.datums_; + } + return *this; +} + +ObDirectLoadConstDatumArray &ObDirectLoadConstDatumArray::operator=( + const ObDirectLoadDatumArray &other) +{ + count_ = other.count_; + datums_ = other.datums_; + return *this; +} + +int64_t ObDirectLoadConstDatumArray::get_deep_copy_size() const +{ + int64_t size = 0; + if (OB_LIKELY(is_valid())) { + size = count_ * sizeof(ObStorageDatum); + for (int64_t i = 0; i < count_; ++i) { + size += datums_[i].get_deep_copy_size(); + } + } + return size; +} + +int ObDirectLoadConstDatumArray::deep_copy(const ObDirectLoadConstDatumArray &src, char *buf, + const int64_t len, int64_t &pos) +{ + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reset(); + ObStorageDatum *datums = nullptr; + const int64_t datum_cnt = src.count_; + if (datum_cnt > 0) { + datums = new (buf + pos) ObStorageDatum[datum_cnt]; + pos += sizeof(ObStorageDatum) * datum_cnt; + } + for (int64_t i = 0; OB_SUCC(ret) && i < datum_cnt; i++) { + if (OB_FAIL(datums[i].deep_copy(src.datums_[i], buf, len, pos))) { + LOG_WARN("fail to deep copy storage datum", K(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + count_ = datum_cnt; + datums_ = datums; + } + } + return ret; +} + +DEF_TO_STRING(ObDirectLoadConstDatumArray) +{ + int64_t pos = 0; + J_OBJ_START(); + J_KV(K_(count)); + if (nullptr != buf && buf_len >= 0) { + if (nullptr != datums_) { + J_ARRAY_START(); + for (int64_t i = 0; i < count_; ++i) { + databuff_printf(buf, buf_len, pos, "col_id=%ld:", i); + pos += datums_[i].storage_to_string(buf + pos, buf_len - pos); + databuff_printf(buf, buf_len, pos, ","); + } + J_ARRAY_END(); + } + } + J_OBJ_END(); + return pos; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_datum.h b/src/storage/direct_load/ob_direct_load_datum.h new file mode 100644 index 0000000000..365179b865 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_datum.h @@ -0,0 +1,67 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_row.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadDatumSerialization +{ +public: + static int serialize(char *buf, const int64_t buf_len, int64_t &pos, + const blocksstable::ObStorageDatum &datum); + static int deserialize(const char *buf, const int64_t data_len, int64_t &pos, + blocksstable::ObStorageDatum &datum); + static int64_t get_serialize_size(const blocksstable::ObStorageDatum &datum); +}; + +struct ObDirectLoadDatumArray +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadDatumArray(); + ObDirectLoadDatumArray(const ObDirectLoadDatumArray &other) = delete; + ~ObDirectLoadDatumArray(); + void reset(); + void reuse(); + int assign(blocksstable::ObStorageDatum *datums, int32_t count); + int assign(const ObDirectLoadDatumArray &other); + ObDirectLoadDatumArray &operator=(const ObDirectLoadDatumArray &other); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadDatumArray &src, char *buf, const int64_t len, int64_t &pos); + bool is_valid() const { return 0 == count_ || nullptr != datums_; } + DECLARE_TO_STRING; +public: + common::ObArenaAllocator allocator_; + int64_t capacity_; + int64_t count_; + blocksstable::ObStorageDatum *datums_; +}; + +struct ObDirectLoadConstDatumArray +{ +public: + ObDirectLoadConstDatumArray(); + ObDirectLoadConstDatumArray(const ObDirectLoadConstDatumArray &other) = delete; + ~ObDirectLoadConstDatumArray(); + void reset(); + void reuse(); + int assign(blocksstable::ObStorageDatum *datums, int32_t count); + ObDirectLoadConstDatumArray &operator=(const ObDirectLoadConstDatumArray &other); + ObDirectLoadConstDatumArray &operator=(const ObDirectLoadDatumArray &other); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadConstDatumArray &src, char *buf, const int64_t len, int64_t &pos); + OB_INLINE bool is_valid() const { return 0 == count_ || nullptr != datums_; } + DECLARE_TO_STRING; +public: + int64_t count_; + blocksstable::ObStorageDatum *datums_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_easy_queue.h b/src/storage/direct_load/ob_direct_load_easy_queue.h new file mode 100644 index 0000000000..af09dd1373 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_easy_queue.h @@ -0,0 +1,63 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_se_array.h" +#include "lib/lock/ob_mutex.h" +#include "lib/list/ob_list.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadEasyQueue //性能很差的一个queue,主要为了方便使用 +{ +public: + ObDirectLoadEasyQueue() : malloc_("TLD_easy_queue"), queue_(malloc_) {} + + int push(const T &e) { + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(mutex_); + if (OB_FAIL(queue_.push_back(e))) { + SERVER_LOG(WARN, "fail to push back queue", KR(ret)); + } + return ret; + } + + int64_t size() { + lib::ObMutexGuard guard(mutex_); + return queue_.size(); + } + + void pop_one(T &value) { + value = nullptr; + lib::ObMutexGuard guard(mutex_); + if (!queue_.empty()) { + value = queue_.get_first(); + queue_.pop_front(); + } + } + + void pop_all(common::ObIArray &values) { + lib::ObMutexGuard guard(mutex_); + while (!queue_.empty()) { + T &e = queue_.get_first(); + values.push_back(e); + queue_.pop_front(); + } + } + +private: + ObMalloc malloc_; + common::ObList queue_; + lib::ObMutex mutex_; +}; + + +} // namespace observer +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_block_reader.h b/src/storage/direct_load/ob_direct_load_external_block_reader.h new file mode 100644 index 0000000000..2a1916e36d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_block_reader.h @@ -0,0 +1,20 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" +#include "storage/direct_load/ob_direct_load_data_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ + +template +using ObDirectLoadExternalBlockReader = + ObDirectLoadDataBlockReader; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_block_writer.h b/src/storage/direct_load/ob_direct_load_external_block_writer.h new file mode 100644 index 0000000000..7adae17e7d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_block_writer.h @@ -0,0 +1,33 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" +#include "storage/direct_load/ob_direct_load_data_block_writer.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadExternalBlockWriter + : public ObDirectLoadDataBlockWriter +{ + typedef ObDirectLoadDataBlockWriter ParentType; +public: + ObDirectLoadExternalBlockWriter() {} + virtual ~ObDirectLoadExternalBlockWriter() {} + int init(int64_t data_block_size, common::ObCompressorType compressor_type, char *extra_buf, + int64_t extra_buf_size) + { + return ParentType::init(data_block_size, compressor_type, extra_buf, extra_buf_size, nullptr); + } +private: + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadExternalBlockWriter); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_fragment.cpp b/src/storage/direct_load/ob_direct_load_external_fragment.cpp new file mode 100644 index 0000000000..b0e98670e7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_fragment.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_fragment.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadExternalFragment + */ + +ObDirectLoadExternalFragment::ObDirectLoadExternalFragment() + : file_size_(0), row_count_(0), max_data_block_size_(0) +{ +} + +ObDirectLoadExternalFragment::~ObDirectLoadExternalFragment() +{ + reset(); +} + +void ObDirectLoadExternalFragment::reset() +{ + file_handle_.reset(); + file_size_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; +} + +bool ObDirectLoadExternalFragment::is_valid() const +{ + return file_size_ > 0 && row_count_ > 0 && max_data_block_size_ > 0 && file_handle_.is_valid(); +} + +int ObDirectLoadExternalFragment::assign(const ObDirectLoadExternalFragment &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(file_handle_.assign(other.file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else { + file_size_ = other.file_size_; + row_count_ = other.row_count_; + max_data_block_size_ = other.max_data_block_size_; + } + return ret; +} + +/** + * ObDirectLoadExternalFragmentArray + */ + +ObDirectLoadExternalFragmentArray::ObDirectLoadExternalFragmentArray() +{ +} + +ObDirectLoadExternalFragmentArray::~ObDirectLoadExternalFragmentArray() +{ + reset(); +} + +void ObDirectLoadExternalFragmentArray::reset() +{ + fragments_.reset(); +} + +int ObDirectLoadExternalFragmentArray::assign(const ObDirectLoadExternalFragmentArray &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(fragments_.assign(other.fragments_))) { + LOG_WARN("fail to assign vector", KR(ret)); + } + return ret; +} + +int ObDirectLoadExternalFragmentArray::push_back(const ObDirectLoadExternalFragment &fragment) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(fragments_.push_back(fragment))) { + LOG_WARN("fail to push back fragment", KR(ret)); + } + return ret; +} + +int ObDirectLoadExternalFragmentArray::push_back(const ObDirectLoadExternalFragmentArray &other) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < other.count(); ++i) { + if (OB_FAIL(fragments_.push_back(other.at(i)))) { + LOG_WARN("fail to push back fragment", KR(ret)); + } + } + return ret; +} + +/** + * ObDirectLoadExternalFragmentCompare + */ + +ObDirectLoadExternalFragmentCompare::ObDirectLoadExternalFragmentCompare() + : result_code_(OB_SUCCESS) +{ +} + +ObDirectLoadExternalFragmentCompare::~ObDirectLoadExternalFragmentCompare() +{ +} + +bool ObDirectLoadExternalFragmentCompare::operator()(const ObDirectLoadExternalFragment *lhs, + const ObDirectLoadExternalFragment *rhs) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_UNLIKELY(nullptr == lhs || nullptr == rhs || !lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(lhs), KPC(rhs)); + } else { + cmp_ret = lhs->row_count_ - rhs->row_count_; + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } + return cmp_ret < 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_fragment.h b/src/storage/direct_load/ob_direct_load_external_fragment.h new file mode 100644 index 0000000000..68586f44f7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_fragment.h @@ -0,0 +1,65 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadExternalFragment +{ +public: + ObDirectLoadExternalFragment(); + ~ObDirectLoadExternalFragment(); + void reset(); + bool is_valid() const; + int assign(const ObDirectLoadExternalFragment &fragment); + TO_STRING_KV(K_(file_size), K_(row_count), K_(max_data_block_size), K_(file_handle)); +public: + int64_t file_size_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadTmpFileHandle file_handle_; +}; + +class ObDirectLoadExternalFragmentArray +{ +public: + ObDirectLoadExternalFragmentArray(); + ~ObDirectLoadExternalFragmentArray(); + void reset(); + int assign(const ObDirectLoadExternalFragmentArray &other); + int push_back(const ObDirectLoadExternalFragment &fragment); + int push_back(const ObDirectLoadExternalFragmentArray &other); + int64_t count() const { return fragments_.count(); } + bool empty() const { return fragments_.empty(); } + ObDirectLoadExternalFragment &at(int64_t idx) + { + return fragments_.at(idx); + } + const ObDirectLoadExternalFragment &at(int64_t idx) const + { + return fragments_.at(idx); + } + TO_STRING_KV(K_(fragments)); +private: + common::ObArray fragments_; +}; + +class ObDirectLoadExternalFragmentCompare +{ +public: + ObDirectLoadExternalFragmentCompare(); + ~ObDirectLoadExternalFragmentCompare(); + bool operator()(const ObDirectLoadExternalFragment *lhs, const ObDirectLoadExternalFragment *rhs); + int get_error_code() const { return result_code_; } + int result_code_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_fragment_builder.h b/src/storage/direct_load/ob_direct_load_external_fragment_builder.h new file mode 100644 index 0000000000..50897de4a5 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_fragment_builder.h @@ -0,0 +1,166 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_vector.h" +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_external_interface.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadExternalFragmentBuilder +{ + typedef ObDirectLoadExternalIterator ExternalIterator; + typedef ObDirectLoadExternalWriter ExternalWriter; +public: + ObDirectLoadExternalFragmentBuilder(); + ~ObDirectLoadExternalFragmentBuilder(); + void reuse(); + void reset(); + int init(ObDirectLoadTmpFileManager *file_mgr, ExternalWriter *external_writer); + int build_fragment(const common::ObVector &item_list); + int build_fragment(ExternalIterator &iter); + const ObDirectLoadExternalFragmentArray &get_fragments() const { return fragments_; } +protected: + ObDirectLoadTmpFileManager *file_mgr_; + int64_t dir_id_; + ExternalWriter *external_writer_; + ObDirectLoadExternalFragmentArray fragments_; + bool is_inited_; +}; + +template +ObDirectLoadExternalFragmentBuilder::ObDirectLoadExternalFragmentBuilder() + : file_mgr_(nullptr), dir_id_(-1), external_writer_(nullptr), is_inited_(false) +{ +} + +template +ObDirectLoadExternalFragmentBuilder::~ObDirectLoadExternalFragmentBuilder() +{ + reset(); +} + +template +void ObDirectLoadExternalFragmentBuilder::reuse() +{ + fragments_.reset(); +} + +template +void ObDirectLoadExternalFragmentBuilder::reset() +{ + file_mgr_ = nullptr; + dir_id_ = -1; + external_writer_ = nullptr; + fragments_.reset(); + is_inited_ = false; +} + +template +int ObDirectLoadExternalFragmentBuilder::init(ObDirectLoadTmpFileManager *file_mgr, + ExternalWriter *external_writer) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadExternalSortRound init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == file_mgr || nullptr == external_writer)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), KP(file_mgr), KP(external_writer)); + } else { + if (OB_FAIL(file_mgr->alloc_dir(dir_id_))) { + STORAGE_LOG(WARN, "fail to alloc dir", KR(ret)); + } else { + file_mgr_ = file_mgr; + external_writer_ = external_writer; + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadExternalFragmentBuilder::build_fragment(const common::ObVector &item_list) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadExternalFragmentBuilder not init", KR(ret)); + } else { + ObDirectLoadExternalFragment fragment; + if (OB_FAIL(file_mgr_->alloc_file(dir_id_, fragment.file_handle_))) { + STORAGE_LOG(WARN, "fail to alloc file", KR(ret)); + } else if (OB_FAIL(external_writer_->open(fragment.file_handle_))) { + STORAGE_LOG(WARN, "fail to open tmp file", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < item_list.size(); ++i) { + if (OB_FAIL(external_writer_->write_item(*item_list[i]))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(external_writer_->close())) { + STORAGE_LOG(WARN, "fail to close external writer", KR(ret)); + } + } + if (OB_SUCC(ret)) { + fragment.file_size_ = external_writer_->get_file_size(); + fragment.row_count_ = item_list.size(); + fragment.max_data_block_size_ = external_writer_->get_max_block_size(); + if (OB_FAIL(fragments_.push_back(fragment))) { + STORAGE_LOG(WARN, "fail to push back fragment", KR(ret)); + } + } + } + return ret; +} + +template +int ObDirectLoadExternalFragmentBuilder::build_fragment(ExternalIterator &iter) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadExternalFragmentBuilder not init", KR(ret)); + } else { + ObDirectLoadExternalFragment fragment; + const T *item = nullptr; + if (OB_FAIL(file_mgr_->alloc_file(dir_id_, fragment.file_handle_))) { + STORAGE_LOG(WARN, "fail to alloc file", KR(ret)); + } else if (OB_FAIL(external_writer_->open(fragment.file_handle_))) { + STORAGE_LOG(WARN, "fail to open tmp file", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(iter.get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } else { + ret = common::OB_SUCCESS; + break; + } + } else if (OB_FAIL(external_writer_->write_item(*item))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } else { + ++fragment.row_count_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(external_writer_->close())) { + STORAGE_LOG(WARN, "fail to close external writer", KR(ret)); + } else if (OB_FAIL(fragments_.push_back(fragment))) { + STORAGE_LOG(WARN, "fail to push back fragment", KR(ret)); + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_interface.h b/src/storage/direct_load/ob_direct_load_external_interface.h new file mode 100644 index 0000000000..9843e0eb9d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_interface.h @@ -0,0 +1,36 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTmpFileHandle; + +template +class ObDirectLoadExternalIterator +{ +public: + virtual ~ObDirectLoadExternalIterator() = default; + virtual int get_next_item(const T *&item) = 0; + TO_STRING_EMPTY(); +}; + +template +class ObDirectLoadExternalWriter +{ +public: + virtual ~ObDirectLoadExternalWriter() = default; + virtual int open(const ObDirectLoadTmpFileHandle &file_handle) = 0; + virtual int write_item(const T &item) = 0; + virtual int close() = 0; + TO_STRING_EMPTY(); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_merger.h b/src/storage/direct_load/ob_direct_load_external_merger.h new file mode 100644 index 0000000000..c60a16682b --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_merger.h @@ -0,0 +1,256 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_heap.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/ob_errno.h" +#include "storage/direct_load/ob_direct_load_external_interface.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadExternalMerger +{ + static const int64_t DEFAULT_ITERATOR_NUM = 64; + typedef ObDirectLoadExternalIterator ExternalIterator; +public: + ObDirectLoadExternalMerger(); + virtual ~ObDirectLoadExternalMerger() = default; + int init(const common::ObIArray &iters, Compare *compare); + int get_next_item(const T *&item); + void reset(); + bool is_inited() const { return is_inited_; } +private: + int direct_get_next_item(const T *&item); + int heap_get_next_item(const T *&item); + int build_heap(); +private: + struct HeapItem + { + const T *item_; + int64_t idx_; + HeapItem() : item_(nullptr), idx_(0) {} + void reset() + { + item_ = nullptr; + idx_ = 0; + } + TO_STRING_KV(K_(item), K_(idx)); + }; + class HeapCompare + { + public: + explicit HeapCompare() : compare_(nullptr), error_code_(common::OB_SUCCESS) {} + bool operator()(const HeapItem &left_item, const HeapItem &right_item); + void set_compare(Compare *compare) { compare_ = compare; } + int get_error_code() const { return error_code_; } + void reset() + { + compare_ = nullptr; + error_code_ = common::OB_SUCCESS; + } + private: + Compare *compare_; + int error_code_; + }; +private: + HeapCompare compare_; + const common::ObIArray *iters_; + common::ObBinaryHeap heap_; + int64_t last_iter_idx_; + bool is_inited_; +}; + +template +bool ObDirectLoadExternalMerger::HeapCompare::operator()(const HeapItem &left_item, + const HeapItem &right_item) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_heap_compare_time_us); + int ret = common::OB_SUCCESS; + bool bret = false; + if (OB_ISNULL(compare_)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), KP(compare_)); + } else if (OB_ISNULL(left_item.item_) || OB_ISNULL(right_item.item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid compare items", KR(ret), KP(left_item.item_), KP(right_item.item_)); + } else { + bret = !compare_->operator()(left_item.item_, right_item.item_); + } + if (OB_FAIL(ret)) { + error_code_ = ret; + } else if (OB_FAIL(compare_->get_error_code())) { + error_code_ = compare_->get_error_code(); + } + return bret; +} + +template +ObDirectLoadExternalMerger::ObDirectLoadExternalMerger() + : iters_(nullptr), heap_(compare_), last_iter_idx_(-1), is_inited_(false) +{ +} + +template +void ObDirectLoadExternalMerger::reset() +{ + is_inited_ = false; + last_iter_idx_ = -1; + compare_.reset(); + iters_ = nullptr; + heap_.reset(); +} + +template +int ObDirectLoadExternalMerger::init(const common::ObIArray &iters, + Compare *compare) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadExternalMerger init twice", KR(ret), KP(this)); + } else if (0 == iters.count() || OB_ISNULL(compare)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters.count()), KP(compare)); + } else { + compare_.set_compare(compare); + iters_ = &iters; + if (iters.count() > 1 && OB_FAIL(build_heap())) { + STORAGE_LOG(WARN, "fail to build heap", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadExternalMerger::build_heap() +{ + int ret = common::OB_SUCCESS; + const T *item = nullptr; + HeapItem heap_item; + for (int64_t i = 0; OB_SUCC(ret) && i < iters_->count(); ++i) { + if (OB_FAIL(iters_->at(i)->get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret), K(i)); + } else { + ret = common::OB_SUCCESS; + } + } else if (OB_ISNULL(item)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid item", KR(ret), KP(item)); + } else { + heap_item.item_ = item; + heap_item.idx_ = i; + if (OB_FAIL(heap_.push(heap_item))) { + STORAGE_LOG(WARN, "fail to push heap", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } + } + } + return ret; +} + +template +int ObDirectLoadExternalMerger::get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + item = nullptr; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadExternalMerger not init", KR(ret), KP(this)); + } else if (1 == iters_->count()) { + if (OB_FAIL(direct_get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to directly get next item", KR(ret)); + } + } + } else if (OB_FAIL(heap_get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item from heap", KR(ret)); + } + } + return ret; +} + +template +int ObDirectLoadExternalMerger::direct_get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + item = nullptr; + if (OB_UNLIKELY(1 != iters_->count())) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters_->count())); + } else if (OB_FAIL(iters_->at(0)->get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } + } + return ret; +} + +template +int ObDirectLoadExternalMerger::heap_get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(iters_->count() <= 1)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters_->count())); + } else if (last_iter_idx_ >= 0 && last_iter_idx_ < iters_->count()) { + ExternalIterator *iter = iters_->at(last_iter_idx_); + HeapItem heap_item; + heap_item.idx_ = last_iter_idx_; + if (OB_FAIL(iter->get_next_item(heap_item.item_))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } else { + if (OB_FAIL(heap_.pop())) { + STORAGE_LOG(WARN, "fail to pop heap item", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } + } + } else if (OB_ISNULL(heap_item.item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid item", KR(ret), KP(heap_item.item_)); + } else { + if (OB_FAIL(heap_.replace_top(heap_item))) { + STORAGE_LOG(WARN, "fail to replace heap top", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } + } + last_iter_idx_ = -1; + } + + if (OB_SUCC(ret) && heap_.empty()) { + ret = common::OB_ITER_END; + } + + if (OB_SUCC(ret)) { + const HeapItem *head_item = nullptr; + if (OB_FAIL(heap_.top(head_item))) { + STORAGE_LOG(WARN, "fail to get heap top item", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } else if (OB_ISNULL(head_item) || OB_ISNULL(head_item->item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid heap item", KR(ret), KP(head_item)); + } else { + item = head_item->item_; + last_iter_idx_ = head_item->idx_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_multi_partition_row.cpp b/src/storage/direct_load/ob_direct_load_external_multi_partition_row.cpp new file mode 100644 index 0000000000..0d377ac837 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_multi_partition_row.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_multi_partition_row.h" +#include "observer/table_load/ob_table_load_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadExternalMultiPartitionRow + */ + +void ObDirectLoadExternalMultiPartitionRow::reset() +{ + tablet_id_.reset(); + external_row_.reset(); +} + +void ObDirectLoadExternalMultiPartitionRow::reuse() +{ + tablet_id_.reset(); + external_row_.reuse(); +} + +int64_t ObDirectLoadExternalMultiPartitionRow::get_deep_copy_size() const +{ + return external_row_.get_deep_copy_size(); +} + +int ObDirectLoadExternalMultiPartitionRow::deep_copy( + const ObDirectLoadExternalMultiPartitionRow &src, char *buf, const int64_t len, int64_t &pos) +{ + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reuse(); + tablet_id_ = src.tablet_id_; + if (OB_FAIL(external_row_.deep_copy(src.external_row_, buf, len, pos))) { + LOG_WARN("fail to deep copy external row", KR(ret)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadExternalMultiPartitionRow) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, tablet_id_.id(), external_row_); + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadExternalMultiPartitionRow) +{ + int ret = OB_SUCCESS; + uint64_t id = 0; + LST_DO_CODE(OB_UNIS_DECODE, id, external_row_); + if (OB_SUCC(ret)) { + tablet_id_ = id; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadExternalMultiPartitionRow) +{ + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, tablet_id_.id(), external_row_); + return len; +} + +/** + * ObDirectLoadConstExternalMultiPartitionRow + */ + +ObDirectLoadConstExternalMultiPartitionRow::ObDirectLoadConstExternalMultiPartitionRow() + : buf_size_(0), buf_(nullptr) +{ +} + +ObDirectLoadConstExternalMultiPartitionRow::~ObDirectLoadConstExternalMultiPartitionRow() +{ +} + +void ObDirectLoadConstExternalMultiPartitionRow::reset() +{ + tablet_id_.reset(); + rowkey_datum_array_.reset(); + buf_size_ = 0; + buf_ = nullptr; +} + +ObDirectLoadConstExternalMultiPartitionRow &ObDirectLoadConstExternalMultiPartitionRow::operator=( + const ObDirectLoadConstExternalMultiPartitionRow &other) +{ + if (this != &other) { + reset(); + tablet_id_ = other.tablet_id_; + rowkey_datum_array_ = other.rowkey_datum_array_; + buf_size_ = other.buf_size_; + buf_ = other.buf_; + } + return *this; +} + +ObDirectLoadConstExternalMultiPartitionRow &ObDirectLoadConstExternalMultiPartitionRow::operator=( + const ObDirectLoadExternalMultiPartitionRow &other) +{ + tablet_id_ = other.tablet_id_; + rowkey_datum_array_ = other.external_row_.rowkey_datum_array_; + buf_size_ = other.external_row_.buf_size_; + buf_ = other.external_row_.buf_; + return *this; +} + +int64_t ObDirectLoadConstExternalMultiPartitionRow::get_deep_copy_size() const +{ + int64_t size = 0; + if (OB_LIKELY(is_valid())) { + size += rowkey_datum_array_.get_deep_copy_size(); + size += buf_size_; + } + return size; +} + +int ObDirectLoadConstExternalMultiPartitionRow::deep_copy( + const ObDirectLoadConstExternalMultiPartitionRow &src, char *buf, const int64_t len, int64_t &pos) +{ + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reset(); + tablet_id_ = src.tablet_id_; + if (OB_FAIL(rowkey_datum_array_.deep_copy(src.rowkey_datum_array_, buf, len, pos))) { + LOG_WARN("fail to deep copy datum array", KR(ret)); + } else { + buf_size_ = src.buf_size_; + buf_ = buf + pos; + MEMCPY(buf + pos, src.buf_, buf_size_); + pos += buf_size_; + } + } + return ret; +} + +int ObDirectLoadConstExternalMultiPartitionRow::to_datums(ObStorageDatum *datums, + int64_t column_count) const +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_datum_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid row", KR(ret), KPC(this)); + } else if (OB_UNLIKELY(nullptr == datums || column_count < rowkey_datum_array_.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count), K(rowkey_datum_array_.count_)); + } else { + // from rowkey datum array + for (int64_t i = 0; i < rowkey_datum_array_.count_; ++i) { + datums[i] = rowkey_datum_array_.datums_[i]; + } + // from deserialize datum array + ObDirectLoadDatumArray deserialize_datum_array; + int64_t pos = 0; + if (OB_FAIL(deserialize_datum_array.assign(datums + rowkey_datum_array_.count_, + column_count - rowkey_datum_array_.count_))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else if (OB_FAIL(deserialize_datum_array.deserialize(buf_, buf_size_, pos))) { + LOG_WARN("fail to deserialize datum array", KR(ret)); + } else if (OB_UNLIKELY(rowkey_datum_array_.count_ + deserialize_datum_array.count_ != + column_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected column count", KR(ret), K(rowkey_datum_array_.count_), + K(deserialize_datum_array.count_), K(column_count)); + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_multi_partition_row.h b/src/storage/direct_load/ob_direct_load_external_multi_partition_row.h new file mode 100644 index 0000000000..4aa564dc69 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_multi_partition_row.h @@ -0,0 +1,62 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_external_row.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadExternalMultiPartitionRow +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadExternalMultiPartitionRow() = default; + void reset(); + void reuse(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadExternalMultiPartitionRow &src, char *buf, const int64_t len, + int64_t &pos); + OB_INLINE bool is_valid() const { return tablet_id_.is_valid() && external_row_.is_valid(); } + TO_STRING_KV(K_(tablet_id), K_(external_row)); + int64_t get_raw_size() const { return external_row_.get_raw_size(); } +public: + common::ObTabletID tablet_id_; + ObDirectLoadExternalRow external_row_; +}; + +class ObDirectLoadConstExternalMultiPartitionRow +{ +public: + ObDirectLoadConstExternalMultiPartitionRow(); + ObDirectLoadConstExternalMultiPartitionRow( + const ObDirectLoadConstExternalMultiPartitionRow &other) = delete; + ~ObDirectLoadConstExternalMultiPartitionRow(); + void reset(); + ObDirectLoadConstExternalMultiPartitionRow &operator=( + const ObDirectLoadConstExternalMultiPartitionRow &other); + ObDirectLoadConstExternalMultiPartitionRow &operator=( + const ObDirectLoadExternalMultiPartitionRow &other); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadConstExternalMultiPartitionRow &src, char *buf, const int64_t len, + int64_t &pos); + int to_datums(blocksstable::ObStorageDatum *datums, int64_t column_count) const; + bool is_valid() const + { + return tablet_id_.is_valid() && rowkey_datum_array_.is_valid() && buf_size_ > 0 && + nullptr != buf_; + } + TO_STRING_KV(K_(tablet_id), K_(rowkey_datum_array), K_(buf_size), KP_(buf)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadConstDatumArray rowkey_datum_array_; + int64_t buf_size_; + const char *buf_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_multi_partition_table.cpp b/src/storage/direct_load/ob_direct_load_external_multi_partition_table.cpp new file mode 100644 index 0000000000..73562daa64 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_multi_partition_table.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_multi_partition_table.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_external_table.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; + +/** + * ObDirectLoadExternalMultiPartitionTableBuildParam + */ + +ObDirectLoadExternalMultiPartitionTableBuildParam:: + ObDirectLoadExternalMultiPartitionTableBuildParam() + : datum_utils_(nullptr), file_mgr_(nullptr), extra_buf_(nullptr), extra_buf_size_(0) +{ +} + +ObDirectLoadExternalMultiPartitionTableBuildParam:: + ~ObDirectLoadExternalMultiPartitionTableBuildParam() +{ +} + +bool ObDirectLoadExternalMultiPartitionTableBuildParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != datum_utils_ && nullptr != file_mgr_ && + nullptr != extra_buf_ && extra_buf_size_ > 0 && extra_buf_size_ % DIO_ALIGN_SIZE == 0; +} + +/** + * ObDirectLoadExternalMultiPartitionTableBuilder + */ + +ObDirectLoadExternalMultiPartitionTableBuilder::ObDirectLoadExternalMultiPartitionTableBuilder() + : allocator_("TLD_EMPTBuilder"), row_count_(0), is_closed_(false), is_inited_(false) +{ +} + +ObDirectLoadExternalMultiPartitionTableBuilder::~ObDirectLoadExternalMultiPartitionTableBuilder() +{ +} + +int ObDirectLoadExternalMultiPartitionTableBuilder::init( + const ObDirectLoadExternalMultiPartitionTableBuildParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadExternalMultiPartitionTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + allocator_.set_tenant_id(MTL_ID()); + int64_t dir_id = -1; + if (OB_FAIL(param.file_mgr_->alloc_dir(dir_id))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } else if (OB_FAIL(param.file_mgr_->alloc_file(dir_id, file_handle_))) { + LOG_WARN("fail to alloc fragment", KR(ret)); + } else if (OB_FAIL(external_writer_.init(param_.table_data_desc_.external_data_block_size_, + param_.table_data_desc_.compressor_type_, + param_.extra_buf_, param_.extra_buf_size_))) { + LOG_WARN("fail to init external writer", KR(ret)); + } else if (OB_FAIL(external_writer_.open(file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadExternalMultiPartitionTableBuilder::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalMultiPartitionTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external multi partition table is closed", KR(ret)); + } else if (OB_UNLIKELY(!datum_row.is_valid() || + datum_row.get_column_count() != param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(datum_row)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_append_row_time_us); + row_.tablet_id_ = tablet_id; + if (OB_FAIL(row_.external_row_.from_datums(datum_row.storage_datums_, datum_row.count_, + param_.table_data_desc_.rowkey_column_num_))) { + LOG_WARN("fail to from datums", KR(ret)); + } else if (OB_FAIL(external_writer_.write_item(row_))) { + LOG_WARN("fail to write item", KR(ret)); + } else { + ++row_count_; + } + } + return ret; +} + +int ObDirectLoadExternalMultiPartitionTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external multi partition table is closed", KR(ret)); + } else { + if (OB_FAIL(external_writer_.close())) { + LOG_WARN("fail to close external writer", KR(ret)); + } else { + is_closed_ = true; + } + } + return ret; +} + +int ObDirectLoadExternalMultiPartitionTableBuilder::get_tables( + ObIArray &table_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external table not closed", KR(ret)); + } else { + ObDirectLoadExternalTableCreateParam create_param; + create_param.tablet_id_ = 0; //因为包含了所有的tablet_id,设置为一个无效值 + create_param.data_block_size_ = param_.table_data_desc_.external_data_block_size_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = external_writer_.get_max_block_size(); + ObDirectLoadExternalFragment fragment; + fragment.file_size_ = external_writer_.get_file_size(); + fragment.row_count_ = row_count_; + fragment.max_data_block_size_ = external_writer_.get_max_block_size(); + if (OB_FAIL(fragment.file_handle_.assign(file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(create_param.fragments_.push_back(fragment))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_SUCC(ret)) { + ObDirectLoadExternalTable *external_table = nullptr; + if (OB_ISNULL(external_table = OB_NEWx(ObDirectLoadExternalTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadExternalTable", KR(ret)); + } else if (OB_FAIL(external_table->init(create_param))) { + LOG_WARN("fail to init external table", KR(ret)); + } else if (OB_FAIL(table_array.push_back(external_table))) { + LOG_WARN("fail to push back external table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != external_table) { + external_table->~ObDirectLoadExternalTable(); + allocator.free(external_table); + external_table = nullptr; + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_multi_partition_table.h b/src/storage/direct_load/ob_direct_load_external_multi_partition_table.h new file mode 100644 index 0000000000..30435e1b28 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_multi_partition_table.h @@ -0,0 +1,61 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "storage/direct_load/ob_direct_load_external_block_writer.h" +#include "storage/direct_load/ob_direct_load_external_multi_partition_row.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadExternalMultiPartitionTableBuildParam +{ +public: + ObDirectLoadExternalMultiPartitionTableBuildParam(); + ~ObDirectLoadExternalMultiPartitionTableBuildParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(datum_utils), KP_(file_mgr), KP_(extra_buf), + K_(extra_buf_size)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadTmpFileManager *file_mgr_; + char *extra_buf_; + int64_t extra_buf_size_; +}; + +class ObDirectLoadExternalMultiPartitionTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ + typedef ObDirectLoadExternalMultiPartitionRow RowType; + typedef ObDirectLoadExternalBlockWriter ExternalWriter; +public: + ObDirectLoadExternalMultiPartitionTableBuilder(); + virtual ~ObDirectLoadExternalMultiPartitionTableBuilder(); + int init(const ObDirectLoadExternalMultiPartitionTableBuildParam ¶m); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int close() override; + int64_t get_row_count() const override { return row_count_; } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + ObDirectLoadExternalMultiPartitionTableBuildParam param_; + common::ObArenaAllocator allocator_; + ObDirectLoadTmpFileHandle file_handle_; + ExternalWriter external_writer_; + RowType row_; + int64_t row_count_; + bool is_closed_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadExternalMultiPartitionTableBuilder); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_row.cpp b/src/storage/direct_load/ob_direct_load_external_row.cpp new file mode 100644 index 0000000000..ab32ffa674 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_row.cpp @@ -0,0 +1,187 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_row.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadExternalRow::ObDirectLoadExternalRow() + : allocator_("TLD_ext_row"), buf_size_(0), buf_(nullptr) +{ + allocator_.set_tenant_id(MTL_ID()); +} + +void ObDirectLoadExternalRow::reset() +{ + rowkey_datum_array_.reset(); + buf_size_ = 0; + buf_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadExternalRow::reuse() +{ + rowkey_datum_array_.reuse(); + buf_size_ = 0; + buf_ = nullptr; + allocator_.reuse(); +} + +int64_t ObDirectLoadExternalRow::get_deep_copy_size() const +{ + int64_t size = 0; + if (OB_LIKELY(is_valid())) { + size += rowkey_datum_array_.get_deep_copy_size(); + size += buf_size_; + } + return size; +} + +int ObDirectLoadExternalRow::deep_copy(const ObDirectLoadExternalRow &src, char *buf, + const int64_t len, int64_t &pos) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deep_copy_time_us); + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reuse(); + if (OB_FAIL(rowkey_datum_array_.deep_copy(src.rowkey_datum_array_, buf, len, pos))) { + LOG_WARN("fail to deep copy datum array", KR(ret)); + } else { + buf_size_ = src.buf_size_; + buf_ = buf + pos; + MEMCPY(buf + pos, src.buf_, buf_size_); + pos += buf_size_; + } + } + return ret; +} + +int ObDirectLoadExternalRow::from_datums(ObStorageDatum *datums, int64_t column_count, + int64_t rowkey_column_count) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_external_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == datums || column_count < rowkey_column_count)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count), K(rowkey_column_count)); + } else { + reuse(); + ObDirectLoadDatumArray serialize_datum_array; + if (OB_FAIL(rowkey_datum_array_.assign(datums, rowkey_column_count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else if (OB_FAIL(serialize_datum_array.assign(datums + rowkey_column_count, + column_count - rowkey_column_count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else { + const int64_t buf_size = serialize_datum_array.get_serialize_size(); + char *buf = nullptr; + int64_t pos = 0; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret), K(buf_size)); + } else if (OB_FAIL(serialize_datum_array.serialize(buf, buf_size, pos))) { + LOG_WARN("fail to serialize datum array", KR(ret)); + } else { + buf_ = buf; + buf_size_ = buf_size; + } + } + } + return ret; +} + +int ObDirectLoadExternalRow::to_datums(ObStorageDatum *datums, int64_t column_count) const +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_datum_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid row", KR(ret), KPC(this)); + } else if (OB_UNLIKELY(nullptr == datums || column_count < rowkey_datum_array_.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count), K(rowkey_datum_array_.count_)); + } else { + // from rowkey datum array + for (int64_t i = 0; i < rowkey_datum_array_.count_; ++i) { + datums[i] = rowkey_datum_array_.datums_[i]; + } + // from deserialize datum array + ObDirectLoadDatumArray deserialize_datum_array; + int64_t pos = 0; + if (OB_FAIL(deserialize_datum_array.assign(datums + rowkey_datum_array_.count_, + column_count - rowkey_datum_array_.count_))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else if (OB_FAIL(deserialize_datum_array.deserialize(buf_, buf_size_, pos))) { + LOG_WARN("fail to deserialize datum array", KR(ret)); + } else if (OB_UNLIKELY(rowkey_datum_array_.count_ + deserialize_datum_array.count_ != + column_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected column count", KR(ret), K(rowkey_datum_array_.count_), + K(deserialize_datum_array.count_), K(column_count)); + } + } + return ret; +} + +int ObDirectLoadExternalRow::get_rowkey(ObDatumRowkey &rowkey) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid row", KR(ret), KPC(this)); + } else if (OB_FAIL(rowkey.assign(rowkey_datum_array_.datums_, rowkey_datum_array_.count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, rowkey_datum_array_, buf_size_); + if (OB_SUCC(ret) && OB_NOT_NULL(buf_)) { + MEMCPY(buf + pos, buf_, buf_size_); + pos += buf_size_; + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deserialize_time_us); + int ret = OB_SUCCESS; + reuse(); + LST_DO_CODE(OB_UNIS_DECODE, rowkey_datum_array_, buf_size_); + if (OB_SUCC(ret)) { + buf_ = buf + pos; + pos += buf_size_; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, rowkey_datum_array_, buf_size_); + len += buf_size_; + return len; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_row.h b/src/storage/direct_load/ob_direct_load_external_row.h new file mode 100644 index 0000000000..0e9507bc7e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_row.h @@ -0,0 +1,44 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_datum.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadExternalRow +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadExternalRow(); + void reset(); + void reuse(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadExternalRow &src, char *buf, const int64_t len, int64_t &pos); + // not deep copy + int from_datums(blocksstable::ObStorageDatum *datums, int64_t column_count, + int64_t rowkey_column_count); + int to_datums(blocksstable::ObStorageDatum *datums, int64_t column_count) const; + int get_rowkey(blocksstable::ObDatumRowkey &rowkey) const; + bool is_valid() const + { + return rowkey_datum_array_.is_valid() && buf_size_ > 0 && nullptr != buf_; + } + OB_INLINE int64_t get_raw_size() const { return buf_size_; } + TO_STRING_KV(K_(rowkey_datum_array), K_(buf_size), KP_(buf)); +public: + common::ObArenaAllocator allocator_; + ObDirectLoadDatumArray rowkey_datum_array_; + int64_t buf_size_; + const char *buf_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_scanner.h b/src/storage/direct_load/ob_direct_load_external_scanner.h new file mode 100644 index 0000000000..8aa3e0a44f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_scanner.h @@ -0,0 +1,256 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_external_block_reader.h" +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_external_merger.h" + +namespace oceanbase +{ +namespace storage +{ + +/** + * external sequential scanner + */ + +template +class ObDirectLoadExternalSequentialScanner : public ObDirectLoadExternalIterator +{ + typedef ObDirectLoadExternalBlockReader ExternalReader; +public: + ObDirectLoadExternalSequentialScanner(); + virtual ~ObDirectLoadExternalSequentialScanner(); + void reuse(); + void reset(); + int init(int64_t data_block_size, int64_t buf_size, common::ObCompressorType compressor_type, + const ObDirectLoadExternalFragmentArray &fragments); + int get_next_item(const T *&item) override; +private: + int switch_next_fragment(); +private: + ObDirectLoadExternalFragmentArray fragments_; + ExternalReader reader_; + int64_t next_pos_; + bool is_inited_; +}; + +template +ObDirectLoadExternalSequentialScanner::ObDirectLoadExternalSequentialScanner() + : next_pos_(0), is_inited_(false) +{ +} + +template +ObDirectLoadExternalSequentialScanner::~ObDirectLoadExternalSequentialScanner() +{ + reset(); +} + +template +void ObDirectLoadExternalSequentialScanner::reuse() +{ + reset(); +} + +template +void ObDirectLoadExternalSequentialScanner::reset() +{ + next_pos_ = 0; + reader_.reset(); + fragments_.reset(); + is_inited_ = false; +} + +template +int ObDirectLoadExternalSequentialScanner::init( + int64_t data_block_size, int64_t buf_size, common::ObCompressorType compressor_type, + const ObDirectLoadExternalFragmentArray &fragments) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadExternalSequentialScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + buf_size <= 0 || buf_size % DIO_ALIGN_SIZE != 0 || + data_block_size > buf_size || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR || + fragments.empty())) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(buf_size), K(compressor_type), K(fragments)); + } else { + if (OB_FAIL(fragments_.assign(fragments))) { + STORAGE_LOG(WARN, "fail to assign fragments", KR(ret)); + } else if (OB_FAIL(reader_.init(data_block_size, buf_size, compressor_type))) { + STORAGE_LOG(WARN, "fail to init fragment reader", KR(ret)); + } else if (OB_FAIL(switch_next_fragment())) { + STORAGE_LOG(WARN, "fail to switch next fragment", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadExternalSequentialScanner::get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadExternalSequentialScanner not init", KR(ret), KP(this)); + } else { + item = nullptr; + while (OB_SUCC(ret) && nullptr == item) { + if (OB_FAIL(reader_.get_next_item(item))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } else { + if (OB_FAIL(switch_next_fragment())) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to switch next fragment", KR(ret)); + } + } + } + } + } + } + return ret; +} + +template +int ObDirectLoadExternalSequentialScanner::switch_next_fragment() +{ + int ret = common::OB_SUCCESS; + if (next_pos_ >= fragments_.count()) { + ret = common::OB_ITER_END; + } else { + reader_.reuse(); + const ObDirectLoadExternalFragment &fragment = fragments_.at(next_pos_); + if (OB_FAIL(reader_.open(fragment.file_handle_, 0, fragment.file_size_))) { + STORAGE_LOG(WARN, "fail to open file", KR(ret)); + } else { + next_pos_++; + } + } + return ret; +} + +/** + * external sort scanner + */ + +template +class ObDirectLoadExternalSortScanner : public ObDirectLoadExternalIterator +{ + typedef ObDirectLoadExternalIterator ExternalIterator; + typedef ObDirectLoadExternalBlockReader ExternalReader; +public: + ObDirectLoadExternalSortScanner(); + virtual ~ObDirectLoadExternalSortScanner(); + int init(int64_t data_block_size, int64_t buf_size, common::ObCompressorType compressor_type, + const ObDirectLoadExternalFragmentArray &fragments, Compare *compare); + int get_next_item(const T *&item) override; + void reuse(); +private: + common::ObArenaAllocator allocator_; + common::ObSEArray iters_; + ObDirectLoadExternalMerger merger_; + bool is_inited_; +}; + +template +ObDirectLoadExternalSortScanner::ObDirectLoadExternalSortScanner() + : allocator_("TLD_ESScanner"), is_inited_(false) +{ +} + +template +ObDirectLoadExternalSortScanner::~ObDirectLoadExternalSortScanner() +{ + reuse(); +} + +template +void ObDirectLoadExternalSortScanner::reuse() +{ + is_inited_ = false; + merger_.reset(); + for (int64_t i = 0; i < iters_.count(); ++i) { + ExternalIterator *iter = iters_[i]; + iter->~ExternalIterator(); + allocator_.free(iter); + } + iters_.reset(); + allocator_.reset(); +} + +template +int ObDirectLoadExternalSortScanner::init( + int64_t data_block_size, int64_t buf_size, common::ObCompressorType compressor_type, + const ObDirectLoadExternalFragmentArray &fragments, Compare *compare) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadExternalSortScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(data_block_size <= 0 || data_block_size % DIO_ALIGN_SIZE != 0 || + buf_size <= 0 || buf_size % DIO_ALIGN_SIZE != 0 || + data_block_size > buf_size || + compressor_type <= common::ObCompressorType::INVALID_COMPRESSOR || + fragments.empty() || nullptr == compare)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(buf_size), K(compressor_type), K(fragments), + KP(compare)); + } else { + allocator_.set_tenant_id(MTL_ID()); + for (int64_t i = 0; OB_SUCC(ret) && i < fragments.count(); ++i) { + const ObDirectLoadExternalFragment &fragment = fragments.at(i); + ExternalReader *reader = nullptr; + if (OB_ISNULL(reader = OB_NEWx(ExternalReader, (&allocator_)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to new fragment reader", KR(ret)); + } else if (OB_FAIL(reader->init(data_block_size, buf_size, compressor_type))) { + STORAGE_LOG(WARN, "fail to init fragment reader", KR(ret)); + } else if (OB_FAIL(reader->open(fragment.file_handle_, 0, fragment.file_size_))) { + STORAGE_LOG(WARN, "fail to open fragment", KR(ret)); + } else if (OB_FAIL(iters_.push_back(reader))) { + STORAGE_LOG(WARN, "fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != reader) { + reader->~ExternalReader(); + allocator_.free(reader); + reader = nullptr; + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(merger_.init(iters_, compare))) { + STORAGE_LOG(WARN, "fail to init merger", KR(ret)); + } else { + is_inited_ = true; + } + } + } + return ret; +} + +template +int ObDirectLoadExternalSortScanner::get_next_item(const T *&item) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadExternalSortScanner not init", KR(ret), KP(this)); + } else { + ret = merger_.get_next_item(item); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table.cpp b/src/storage/direct_load/ob_direct_load_external_table.cpp new file mode 100644 index 0000000000..05b4a620c1 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_table.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadExternalTableCreateParam + */ + +ObDirectLoadExternalTableCreateParam::ObDirectLoadExternalTableCreateParam() + : data_block_size_(0), row_count_(0), max_data_block_size_(0) +{ +} + +ObDirectLoadExternalTableCreateParam::~ObDirectLoadExternalTableCreateParam() +{ +} + +bool ObDirectLoadExternalTableCreateParam::is_valid() const +{ + return data_block_size_ > 0 && data_block_size_ % DIO_ALIGN_SIZE == 0 && row_count_ > 0 && + max_data_block_size_ > 0 && max_data_block_size_ % DIO_ALIGN_SIZE == 0 && + !fragments_.empty(); +} + +/** + * ObDirectLoadExternalTableMeta + */ + +ObDirectLoadExternalTableMeta::ObDirectLoadExternalTableMeta() + : data_block_size_(0), row_count_(0), max_data_block_size_(0) +{ +} + +ObDirectLoadExternalTableMeta::~ObDirectLoadExternalTableMeta() +{ +} + +void ObDirectLoadExternalTableMeta::reset() +{ + tablet_id_.reset(); + data_block_size_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; +} + +/** + * ObDirectLoadExternalTable + */ + +ObDirectLoadExternalTable::ObDirectLoadExternalTable() + : is_inited_(false) +{ +} + +ObDirectLoadExternalTable::~ObDirectLoadExternalTable() +{ +} + +void ObDirectLoadExternalTable::reset() +{ + meta_.reset(); + fragments_.reset(); + is_inited_ = false; +} + +int ObDirectLoadExternalTable::init(const ObDirectLoadExternalTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadExternalTable init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + meta_.tablet_id_ = param.tablet_id_; + meta_.data_block_size_ = param.data_block_size_; + meta_.row_count_ = param.row_count_; + meta_.max_data_block_size_ = param.max_data_block_size_; + if (OB_FAIL(fragments_.assign(param.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadExternalTable::copy(const ObDirectLoadExternalTable &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + meta_ = other.meta_; + if (OB_FAIL(fragments_.assign(other.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table.h b/src/storage/direct_load/ob_direct_load_external_table.h new file mode 100644 index 0000000000..71e0ed0555 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table.h @@ -0,0 +1,67 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_i_table.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadExternalTableCreateParam +{ +public: + ObDirectLoadExternalTableCreateParam(); + ~ObDirectLoadExternalTableCreateParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(data_block_size), K_(row_count), K_(max_data_block_size), + K_(fragments)); +public: + common::ObTabletID tablet_id_; + int64_t data_block_size_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadExternalFragmentArray fragments_; +}; + +struct ObDirectLoadExternalTableMeta +{ +public: + ObDirectLoadExternalTableMeta(); + ~ObDirectLoadExternalTableMeta(); + void reset(); + TO_STRING_KV(K_(tablet_id), K_(data_block_size), K_(row_count), K_(max_data_block_size)); +public: + common::ObTabletID tablet_id_; + int64_t data_block_size_; + int64_t row_count_; + int64_t max_data_block_size_; +}; + +class ObDirectLoadExternalTable : public ObIDirectLoadPartitionTable +{ +public: + ObDirectLoadExternalTable(); + virtual ~ObDirectLoadExternalTable(); + void reset(); + int init(const ObDirectLoadExternalTableCreateParam ¶m); + const common::ObTabletID &get_tablet_id() const override { return meta_.tablet_id_; } + int64_t get_row_count() const override { return meta_.row_count_; } + bool is_valid() const override { return is_inited_; } + int copy(const ObDirectLoadExternalTable &other); + const ObDirectLoadExternalTableMeta &get_meta() const { return meta_; } + const ObDirectLoadExternalFragmentArray &get_fragments() const { return fragments_; } + TO_STRING_KV(K_(meta), K_(fragments)); +private: + ObDirectLoadExternalTableMeta meta_; + ObDirectLoadExternalFragmentArray fragments_; + bool is_inited_; + DISABLE_COPY_ASSIGN(ObDirectLoadExternalTable); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table_builder.cpp b/src/storage/direct_load/ob_direct_load_external_table_builder.cpp new file mode 100644 index 0000000000..88061cd4e1 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table_builder.cpp @@ -0,0 +1,178 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_table_builder.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_external_table.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadExternalTableBuildParam + */ + +ObDirectLoadExternalTableBuildParam::ObDirectLoadExternalTableBuildParam() + : datum_utils_(nullptr), file_mgr_(nullptr), extra_buf_(nullptr), extra_buf_size_(0) +{ +} + +ObDirectLoadExternalTableBuildParam::~ObDirectLoadExternalTableBuildParam() +{ +} + +bool ObDirectLoadExternalTableBuildParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != datum_utils_ && + nullptr != file_mgr_ && nullptr != extra_buf_ && extra_buf_size_ > 0 && + extra_buf_size_ % DIO_ALIGN_SIZE == 0; +} + +/** + * ObDirectLoadExternalTableBuilder + */ + +ObDirectLoadExternalTableBuilder::ObDirectLoadExternalTableBuilder() + : row_count_(0), is_closed_(false), is_inited_(false) +{ +} + +ObDirectLoadExternalTableBuilder::~ObDirectLoadExternalTableBuilder() +{ +} + +int ObDirectLoadExternalTableBuilder::init(const ObDirectLoadExternalTableBuildParam &build_param) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadExternalTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!build_param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(build_param)); + } else { + build_param_ = build_param; + int64_t dir_id = -1; + if (OB_FAIL(build_param_.file_mgr_->alloc_dir(dir_id))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } else if (OB_FAIL(build_param_.file_mgr_->alloc_file(dir_id, file_handle_))) { + LOG_WARN("fail to alloc fragment", KR(ret)); + } else if (OB_FAIL( + external_writer_.init(build_param_.table_data_desc_.external_data_block_size_, + build_param_.table_data_desc_.compressor_type_, + build_param_.extra_buf_, build_param_.extra_buf_size_))) { + LOG_WARN("fail to init external writer", KR(ret)); + } else if (OB_FAIL(external_writer_.open(file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadExternalTableBuilder::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external table is closed", KR(ret)); + } else if (OB_UNLIKELY(tablet_id != build_param_.tablet_id_ || !datum_row.is_valid() || + datum_row.get_column_count() != + build_param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(build_param_), K(tablet_id), K(datum_row)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_append_row_time_us); + if (OB_FAIL(external_row_.from_datums(datum_row.storage_datums_, datum_row.count_, + build_param_.table_data_desc_.rowkey_column_num_))) { + LOG_WARN("fail to from datums", KR(ret)); + } else if (OB_FAIL(external_writer_.write_item(external_row_))) { + LOG_WARN("fail to write item", KR(ret)); + } else { + ++row_count_; + } + } + return ret; +} + +int ObDirectLoadExternalTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external table is closed", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_append_row_time_us); + if (OB_FAIL(external_writer_.close())) { + LOG_WARN("fail to close external writer", KR(ret)); + } else { + is_closed_ = true; + } + } + return ret; +} + +int ObDirectLoadExternalTableBuilder::get_tables( + ObIArray &table_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load external table not closed", KR(ret)); + } else { + ObDirectLoadExternalTableCreateParam create_param; + create_param.tablet_id_ = build_param_.tablet_id_; + create_param.data_block_size_ = build_param_.table_data_desc_.external_data_block_size_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = external_writer_.get_max_block_size(); + ObDirectLoadExternalFragment fragment; + fragment.file_size_ = external_writer_.get_file_size(); + fragment.row_count_ = row_count_; + fragment.max_data_block_size_ = external_writer_.get_max_block_size(); + if (OB_FAIL(fragment.file_handle_.assign(file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(create_param.fragments_.push_back(fragment))) { + LOG_WARN("fail to push back fragment", KR(ret)); + } + if (OB_SUCC(ret)) { + ObDirectLoadExternalTable *external_table = nullptr; + if (OB_ISNULL(external_table = OB_NEWx(ObDirectLoadExternalTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadExternalTable", KR(ret)); + } else if (OB_FAIL(external_table->init(create_param))) { + LOG_WARN("fail to init external table", KR(ret)); + } else if (OB_FAIL(table_array.push_back(external_table))) { + LOG_WARN("fail to push back external table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != external_table) { + external_table->~ObDirectLoadExternalTable(); + allocator.free(external_table); + external_table = nullptr; + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table_builder.h b/src/storage/direct_load/ob_direct_load_external_table_builder.h new file mode 100644 index 0000000000..04981f5f61 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table_builder.h @@ -0,0 +1,62 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "storage/direct_load/ob_direct_load_external_block_writer.h" +#include "storage/direct_load/ob_direct_load_external_row.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadExternalTableBuildParam +{ +public: + ObDirectLoadExternalTableBuildParam(); + ~ObDirectLoadExternalTableBuildParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(datum_utils), KP_(file_mgr), KP_(extra_buf), + K_(extra_buf_size)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadTmpFileManager *file_mgr_; + char *extra_buf_; + int64_t extra_buf_size_; +}; + +class ObDirectLoadExternalTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ + typedef ObDirectLoadExternalRow RowType; + typedef ObDirectLoadExternalBlockWriter ExternalWriter; +public: + ObDirectLoadExternalTableBuilder(); + virtual ~ObDirectLoadExternalTableBuilder(); + int init(const ObDirectLoadExternalTableBuildParam &build_param); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int close() override; + int64_t get_row_count() const override { return row_count_; } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + ObDirectLoadExternalTableBuildParam build_param_; + ObDirectLoadTmpFileHandle file_handle_; + ExternalWriter external_writer_; + RowType external_row_; + int64_t row_count_; + bool is_closed_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadExternalTableBuilder); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table_compactor.cpp b/src/storage/direct_load/ob_direct_load_external_table_compactor.cpp new file mode 100644 index 0000000000..f623e1ab4b --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table_compactor.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_external_table_compactor.h" +#include "storage/direct_load/ob_direct_load_external_table.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadExternalTableCompactParam + */ + +ObDirectLoadExternalTableCompactParam::ObDirectLoadExternalTableCompactParam() +{ +} + +ObDirectLoadExternalTableCompactParam::~ObDirectLoadExternalTableCompactParam() +{ +} + +bool ObDirectLoadExternalTableCompactParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() ; +} + +/** + * ObDirectLoadExternalTableCompactor + */ + +ObDirectLoadExternalTableCompactor::ObDirectLoadExternalTableCompactor() + : row_count_(0), max_data_block_size_(0), is_inited_(false) +{ +} + +ObDirectLoadExternalTableCompactor::~ObDirectLoadExternalTableCompactor() +{ +} + +int ObDirectLoadExternalTableCompactor::init(const ObDirectLoadExternalTableCompactParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadExternalTableCompactor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadExternalTableCompactor::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableCompactor not init", KR(ret), KP(this)); + } else { + ObDirectLoadExternalTable *external_table = dynamic_cast(table); + if (OB_ISNULL(external_table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(table), KP(external_table)); + } else if (OB_FAIL(check_table_compactable(external_table))) { + LOG_WARN("fail to check table compactable", KR(ret), KPC(external_table)); + } else { + row_count_ += external_table->get_meta().row_count_; + max_data_block_size_ = MAX(max_data_block_size_, external_table->get_meta().max_data_block_size_); + if (OB_FAIL(fragments_.push_back(external_table->get_fragments()))) { + LOG_WARN("fail to push back fragments", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadExternalTableCompactor::check_table_compactable( + ObDirectLoadExternalTable *external_table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == external_table || !external_table->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(external_table)); + } else { + const ObDirectLoadExternalTableMeta &table_meta = external_table->get_meta(); + if (OB_UNLIKELY(table_meta.tablet_id_ != param_.tablet_id_ || + table_meta.data_block_size_ != param_.table_data_desc_.external_data_block_size_ || + table_meta.row_count_ <= 0)) { + ret = OB_ITEM_NOT_MATCH; + LOG_WARN("table meta not match", KR(ret), K(param_), K(table_meta)); + } + } + return ret; +} + +int ObDirectLoadExternalTableCompactor::compact() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableCompactor not init", KR(ret), KP(this)); + } else { + // do nothing + } + return ret; +} + +int ObDirectLoadExternalTableCompactor::get_table(ObIDirectLoadPartitionTable *&table, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadExternalTableCompactor not init", KR(ret), KP(this)); + } else { + ObDirectLoadExternalTable *external_table = nullptr; + ObDirectLoadExternalTableCreateParam create_param; + create_param.tablet_id_ = param_.tablet_id_; + create_param.data_block_size_ = param_.table_data_desc_.external_data_block_size_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = max_data_block_size_; + if (OB_FAIL(create_param.fragments_.assign(fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else if (OB_ISNULL(external_table = OB_NEWx(ObDirectLoadExternalTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadExternalTable", KR(ret)); + } else if (OB_FAIL(external_table->init(create_param))) { + LOG_WARN("fail to init external table", KR(ret)); + } else { + table = external_table; + } + if (OB_FAIL(ret)) { + if (nullptr != external_table) { + external_table->~ObDirectLoadExternalTable(); + allocator.free(external_table); + external_table = nullptr; + } + } + } + return ret; +} + +void ObDirectLoadExternalTableCompactor::stop() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_external_table_compactor.h b/src/storage/direct_load/ob_direct_load_external_table_compactor.h new file mode 100644 index 0000000000..1a390fb121 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_external_table_compactor.h @@ -0,0 +1,50 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadExternalTable; + +struct ObDirectLoadExternalTableCompactParam +{ +public: + ObDirectLoadExternalTableCompactParam(); + ~ObDirectLoadExternalTableCompactParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; +}; + +class ObDirectLoadExternalTableCompactor : public ObIDirectLoadTabletTableCompactor +{ +public: + ObDirectLoadExternalTableCompactor(); + virtual ~ObDirectLoadExternalTableCompactor(); + int init(const ObDirectLoadExternalTableCompactParam ¶m); + int add_table(ObIDirectLoadPartitionTable *table) override; + int compact() override; + int get_table(ObIDirectLoadPartitionTable *&table, common::ObIAllocator &allocator) override; + void stop() override; +private: + int check_table_compactable(ObDirectLoadExternalTable *external_table); +private: + ObDirectLoadExternalTableCompactParam param_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadExternalFragmentArray fragments_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table.cpp b/src/storage/direct_load/ob_direct_load_fast_heap_table.cpp new file mode 100644 index 0000000000..fdf3da4240 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table.cpp @@ -0,0 +1,104 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_fast_heap_table.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadFastHeapTableCreateParam + */ + +ObDirectLoadFastHeapTableCreateParam::ObDirectLoadFastHeapTableCreateParam() + : row_count_(0) , column_stat_array_(nullptr) +{ +} + +ObDirectLoadFastHeapTableCreateParam::~ObDirectLoadFastHeapTableCreateParam() +{ +} + +bool ObDirectLoadFastHeapTableCreateParam::is_valid() const +{ + return tablet_id_.is_valid() && row_count_ >= 0 && nullptr != column_stat_array_ ; +} + +/** + * ObDirectLoadFastHeapTable + */ + +ObDirectLoadFastHeapTable::ObDirectLoadFastHeapTable() + : allocator_("TLD_FastHTable"), is_inited_(false) +{ +} + +ObDirectLoadFastHeapTable::~ObDirectLoadFastHeapTable() +{ + for (int64_t i = 0; i < column_stat_array_.count(); ++i) { + ObOptColumnStat *col_stat = column_stat_array_.at(i); + col_stat->~ObOptColumnStat(); + col_stat = nullptr; + } +} + +int ObDirectLoadFastHeapTable::copy_col_stat(const ObDirectLoadFastHeapTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret)&& i < param.column_stat_array_->count(); ++i) { + ObOptColumnStat *col_stat = param.column_stat_array_->at(i); + if (col_stat != nullptr) { + ObOptColumnStat *copied_col_stat = nullptr; + int64_t size = col_stat->size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(col_stat->deep_copy(new_buf, size, copied_col_stat))) { + LOG_WARN("fail to copy colstat", KR(ret)); + } else if (OB_FAIL(column_stat_array_.push_back(copied_col_stat))) { + LOG_WARN("fail to add table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (copied_col_stat != nullptr) { + copied_col_stat->~ObOptColumnStat(); + copied_col_stat = nullptr; + } + if(new_buf != nullptr) { + allocator_.free(new_buf); + new_buf = nullptr; + } + } + } + } + return ret; +} + + +int ObDirectLoadFastHeapTable::init(const ObDirectLoadFastHeapTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadFastHeapTable init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else if (OB_FAIL(copy_col_stat(param))){ + LOG_WARN("fail to inner init", KR(ret), K(param)); + } else { + meta_.tablet_id_ = param.tablet_id_; + meta_.row_count_ = param.row_count_; + is_inited_ = true; + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table.h b/src/storage/direct_load/ob_direct_load_fast_heap_table.h new file mode 100644 index 0000000000..5a045de63c --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table.h @@ -0,0 +1,62 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "share/stat/ob_opt_column_stat.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadFastHeapTableCreateParam +{ +public: + ObDirectLoadFastHeapTableCreateParam(); + ~ObDirectLoadFastHeapTableCreateParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(row_count)); +public: + common::ObTabletID tablet_id_; + int64_t row_count_; + common::ObArray *column_stat_array_; +}; + +struct ObDirectLoadFastHeapTableMeta +{ + common::ObTabletID tablet_id_; + int64_t row_count_; + TO_STRING_KV(K_(tablet_id), K_(row_count)); +}; + +class ObDirectLoadFastHeapTable : public ObIDirectLoadPartitionTable +{ +public: + ObDirectLoadFastHeapTable(); + virtual ~ObDirectLoadFastHeapTable(); + int init(const ObDirectLoadFastHeapTableCreateParam ¶m); + const common::ObIArray &get_column_stat_array() const + { + return column_stat_array_; + } + const common::ObTabletID &get_tablet_id() const override { return meta_.tablet_id_; } + int64_t get_row_count() const override { return meta_.row_count_; } + bool is_valid() const override { return is_inited_; } + const ObDirectLoadFastHeapTableMeta &get_meta() const { return meta_; } + TO_STRING_KV(K_(meta)); +private: + int copy_col_stat(const ObDirectLoadFastHeapTableCreateParam ¶m); +private: + ObDirectLoadFastHeapTableMeta meta_; + common::ObArenaAllocator allocator_; + common::ObArray column_stat_array_; + bool is_inited_; + DISABLE_COPY_ASSIGN(ObDirectLoadFastHeapTable); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.cpp b/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.cpp new file mode 100644 index 0000000000..cf3bbcc4d9 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.cpp @@ -0,0 +1,282 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_fast_heap_table_builder.h" +#include "share/stat/ob_opt_column_stat.h" +#include "share/table/ob_table_load_define.h" +#include "storage/ddl/ob_direct_insert_sstable_ctx.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table.h" +#include "storage/direct_load/ob_direct_load_insert_table_ctx.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace share; + +/** + * ObDirectLoadFastHeapTableBuildParam + */ + +ObDirectLoadFastHeapTableBuildParam::ObDirectLoadFastHeapTableBuildParam() + : col_descs_(nullptr), + insert_table_ctx_(nullptr), + fast_heap_table_ctx_(nullptr), + result_info_(nullptr), + online_opt_stat_gather_(false) +{ +} + +ObDirectLoadFastHeapTableBuildParam::~ObDirectLoadFastHeapTableBuildParam() +{ +} + +bool ObDirectLoadFastHeapTableBuildParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != col_descs_ && + nullptr != insert_table_ctx_ && nullptr != fast_heap_table_ctx_ && nullptr != result_info_; +} + +/** + * ObDirectLoadFastHeapTableBuilder + */ + +ObDirectLoadFastHeapTableBuilder::ObDirectLoadFastHeapTableBuilder() + : allocator_("TLD_FastHTable"), + fast_heap_table_tablet_ctx_(nullptr), + slice_writer_(nullptr), + row_count_(0), + is_closed_(false), + is_inited_(false) +{ +} + +ObDirectLoadFastHeapTableBuilder::~ObDirectLoadFastHeapTableBuilder() +{ + if (nullptr != slice_writer_) { + slice_writer_->~ObSSTableInsertSliceWriter(); + allocator_.free(slice_writer_); + slice_writer_ = nullptr; + } + for (int64_t i = 0; i < column_stat_array_.count(); ++i) { + ObOptColumnStat *col_stat = column_stat_array_.at(i); + col_stat->~ObOptColumnStat(); + col_stat = nullptr; + } +} + +int ObDirectLoadFastHeapTableBuilder::init_sql_statistics() +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < param_.table_data_desc_.column_count_; ++i) { + ObOptColumnStat *col_stat = OB_NEWx(ObOptColumnStat, (&allocator_), allocator_); + if (OB_ISNULL(col_stat)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret)); + } else if (OB_FAIL(column_stat_array_.push_back(col_stat))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (col_stat != nullptr) { + col_stat->~ObOptColumnStat(); + allocator_.free(col_stat); + col_stat = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::collect_obj(const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < param_.table_data_desc_.column_count_; i++) { + const ObStorageDatum &datum = + datum_row.storage_datums_[i + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt() + 1]; + const ObColDesc &col_desc = param_.col_descs_->at(i + 1); + ObOptColumnStat *col_stat = column_stat_array_.at(i); + if (col_stat != nullptr) { + ObObj obj; + if (OB_FAIL(datum.to_obj_enhance(obj, col_desc.col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(datum_row.storage_datums_[i])); + } else if (OB_FAIL(col_stat->merge_obj(obj))) { + LOG_WARN("Failed to merge obj", K(ret), K(obj), KP(col_stat)); + } + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::init(const ObDirectLoadFastHeapTableBuildParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadFastHeapTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + if (param_.online_opt_stat_gather_ && OB_FAIL(init_sql_statistics())) { + LOG_WARN("fail to inner init sql statistics", KR(ret)); + } else if (OB_FAIL(param_.fast_heap_table_ctx_->get_tablet_context( + param_.tablet_id_, fast_heap_table_tablet_ctx_))) { + LOG_WARN("fail to get tablet context", KR(ret)); + } else if (OB_FAIL(init_sstable_slice_ctx())) { + LOG_WARN("fail to init sstable slice ctx", KR(ret)); + } else if (OB_FAIL(datum_row_.init(param.table_data_desc_.column_count_ + + HIDDEN_ROWKEY_COLUMN_NUM + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + datum_row_.storage_datums_[HIDDEN_ROWKEY_COLUMN_NUM].set_int(-1); // fill trans_version + datum_row_.storage_datums_[HIDDEN_ROWKEY_COLUMN_NUM + 1].set_int(0); // fill sql_no + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::init_sstable_slice_ctx() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(fast_heap_table_tablet_ctx_->get_write_ctx(write_ctx_))) { + LOG_WARN("fail to get write ctx", KR(ret)); + } else if (OB_FAIL(param_.insert_table_ctx_->construct_sstable_slice_writer( + fast_heap_table_tablet_ctx_->get_target_tablet_id(), + write_ctx_.start_seq_, + slice_writer_, + allocator_))) { + LOG_WARN("fail to construct sstable slice writer", KR(ret)); + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::switch_sstable_slice() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(slice_writer_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null slice builder", KR(ret)); + } else if (OB_FAIL(slice_writer_->close())) { + LOG_WARN("fail to close sstable slice builder", KR(ret)); + } else { + slice_writer_->~ObSSTableInsertSliceWriter(); + allocator_.reuse(); + if (OB_FAIL(init_sstable_slice_ctx())) { + LOG_WARN("fail to init sstable slice ctx", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + UNUSED(tablet_id); + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadFastHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fast heap table builder is closed", KR(ret)); + } else if (OB_FAIL(!datum_row.is_valid() || + datum_row.get_column_count() != param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(datum_row), K(param_.table_data_desc_.column_count_)); + } else { + uint64_t pk_seq = OB_INVALID_ID; + if (OB_FAIL(write_ctx_.pk_interval_.next_value(pk_seq))) { + if (OB_UNLIKELY(OB_EAGAIN != ret)) { + LOG_WARN("fail to get next pk seq", KR(ret)); + } else if (OB_FAIL(switch_sstable_slice())) { + LOG_WARN("fail to switch sstable slice", KR(ret)); + } else if (OB_FAIL(write_ctx_.pk_interval_.next_value(pk_seq))) { + LOG_WARN("fail to get next pk seq", KR(ret)); + } + } + if (OB_SUCC(ret)) { + datum_row_.storage_datums_[0].set_int(pk_seq); + for (int64_t i = 0, j = HIDDEN_ROWKEY_COLUMN_NUM + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + i < datum_row.count_; ++i, ++j) { + datum_row_.storage_datums_[j] = datum_row.storage_datums_[i]; + } + if (OB_FAIL(slice_writer_->append_row(datum_row_))) { + LOG_WARN("fail to append row", KR(ret)); + } else if (param_.online_opt_stat_gather_ && OB_FAIL(collect_obj(datum_row_))) { + LOG_WARN("fail to collect", KR(ret)); + } else { + ++row_count_; + ATOMIC_INC(¶m_.result_info_->rows_affected_); + } + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadFastHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fast heap table builder is closed", KR(ret)); + } else { + if (OB_FAIL(slice_writer_->close())) { + LOG_WARN("fail to close sstable slice writer", KR(ret)); + } else { + is_closed_ = true; + } + } + return ret; +} + +int ObDirectLoadFastHeapTableBuilder::get_tables( + ObIArray &table_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadFastHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fast heap table builder not closed", KR(ret)); + } else { + ObDirectLoadFastHeapTableCreateParam create_param; + create_param.tablet_id_ = param_.tablet_id_; + create_param.row_count_ = row_count_; + create_param.column_stat_array_ = &column_stat_array_; + ObDirectLoadFastHeapTable *fast_heap_table = nullptr; + if (OB_ISNULL(fast_heap_table = OB_NEWx(ObDirectLoadFastHeapTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadFastHeapTable", KR(ret)); + } else if (OB_FAIL(fast_heap_table->init(create_param))) { + LOG_WARN("fail to init sstable", KR(ret), K(create_param)); + } else if (OB_FAIL(table_array.push_back(fast_heap_table))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != fast_heap_table) { + fast_heap_table->~ObDirectLoadFastHeapTable(); + allocator.free(fast_heap_table); + fast_heap_table = nullptr; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.h b/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.h new file mode 100644 index 0000000000..d0c3d8d028 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table_builder.h @@ -0,0 +1,78 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table_ctx.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace table +{ +class ObTableLoadResultInfo; +} // namespace table +namespace common +{ +class ObOptColumnStat; +} // namespace common +namespace storage +{ +class ObDirectLoadInsertTableContext; +class ObSSTableInsertSliceWriter; + +struct ObDirectLoadFastHeapTableBuildParam +{ +public: + ObDirectLoadFastHeapTableBuildParam(); + ~ObDirectLoadFastHeapTableBuildParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(insert_table_ctx), KP_(fast_heap_table_ctx), + KP_(result_info), K_(online_opt_stat_gather)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const common::ObIArray *col_descs_; + ObDirectLoadInsertTableContext *insert_table_ctx_; + ObDirectLoadFastHeapTableContext *fast_heap_table_ctx_; + table::ObTableLoadResultInfo *result_info_; + bool online_opt_stat_gather_; +}; + +class ObDirectLoadFastHeapTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ + static const int64_t HIDDEN_ROWKEY_COLUMN_NUM = 1; +public: + ObDirectLoadFastHeapTableBuilder(); + virtual ~ObDirectLoadFastHeapTableBuilder(); + int init(const ObDirectLoadFastHeapTableBuildParam ¶m); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int close() override; + int64_t get_row_count() const override { return row_count_; } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + int init_sql_statistics(); + int collect_obj(const blocksstable::ObDatumRow &datum_row); + int init_sstable_slice_ctx(); + int switch_sstable_slice(); +private: + ObDirectLoadFastHeapTableBuildParam param_; + common::ObArenaAllocator allocator_; + ObDirectLoadFastHeapTableTabletContext *fast_heap_table_tablet_ctx_; + ObSSTableInsertSliceWriter *slice_writer_; + ObDirectLoadFastHeapTableTabletWriteCtx write_ctx_; + blocksstable::ObDatumRow datum_row_; + common::ObArray column_stat_array_; + int64_t row_count_; + bool is_closed_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadFastHeapTableBuilder); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.cpp b/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.cpp new file mode 100644 index 0000000000..56bef24a13 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.cpp @@ -0,0 +1,197 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_fast_heap_table_ctx.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/ob_tablet_autoincrement_service.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace lib; +using namespace share; +using namespace table; + +ObDirectLoadFastHeapTableContext::ObDirectLoadFastHeapTableContext() + : allocator_("TLD_FHTableCtx"), is_inited_(false) +{ +} + +ObDirectLoadFastHeapTableContext::~ObDirectLoadFastHeapTableContext() +{ + for (TABLET_CTX_MAP::iterator iter = tablet_ctx_map_.begin(); iter != tablet_ctx_map_.end(); + ++iter) { + ObDirectLoadFastHeapTableTabletContext *tablet_ctx = iter->second; + tablet_ctx->~ObDirectLoadFastHeapTableTabletContext(); + allocator_.free(tablet_ctx); + } + tablet_ctx_map_.reuse(); +} + +int ObDirectLoadFastHeapTableContext::init(uint64_t tenant_id, + const ObIArray &ls_partition_ids, + const ObIArray &target_ls_partition_ids, + int64_t reserved_parallel) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadFastHeapTableContext init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id + || ls_partition_ids.empty() + || (ls_partition_ids.count() != target_ls_partition_ids.count()))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tenant_id), K(ls_partition_ids), K(target_ls_partition_ids)); + } else { + if (OB_FAIL(create_all_tablet_contexts(tenant_id, ls_partition_ids, target_ls_partition_ids, reserved_parallel))) { + LOG_WARN("fail to create all tablet contexts", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadFastHeapTableContext::create_all_tablet_contexts( + uint64_t tenant_id, + const ObIArray &ls_partition_ids, + const ObIArray &target_ls_partition_ids, + int64_t reserved_parallel) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(ls_partition_ids.empty() + || target_ls_partition_ids.empty() + || (ls_partition_ids.count() != target_ls_partition_ids.count()))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(ls_partition_ids), K(target_ls_partition_ids)); + } else if (OB_FAIL( + tablet_ctx_map_.create(ls_partition_ids.count(), "TLD_TabInsCtx", "TLD_TabInsCtx"))) { + LOG_WARN("fail to create tablet ctx map", KR(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < ls_partition_ids.count(); ++i) { + const ObTabletID &tablet_id = ls_partition_ids.at(i).part_tablet_id_.tablet_id_; + const ObTabletID &target_tablet_id = target_ls_partition_ids.at(i).part_tablet_id_.tablet_id_; + ObDirectLoadFastHeapTableTabletContext *tablet_ctx = nullptr; + if (OB_ISNULL(tablet_ctx = OB_NEWx(ObDirectLoadFastHeapTableTabletContext, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadFastHeapTableTabletContext", KR(ret)); + } else if (OB_FAIL(tablet_ctx->init(tenant_id, tablet_id, target_tablet_id, reserved_parallel))) { + LOG_WARN("fail to init fast heap table tablet ctx", KR(ret)); + } else if (OB_FAIL(tablet_ctx_map_.set_refactored(tablet_id, tablet_ctx))) { + LOG_WARN("fail to set tablet ctx map", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != tablet_ctx) { + tablet_ctx->~ObDirectLoadFastHeapTableTabletContext(); + allocator_.free(tablet_ctx); + tablet_ctx = nullptr; + } + } + } + } + return ret; +} + +int ObDirectLoadFastHeapTableContext::get_tablet_context( + const ObTabletID &tablet_id, ObDirectLoadFastHeapTableTabletContext *&tablet_ctx) const +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadFastHeapTableContext not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id)); + } else if (OB_FAIL(tablet_ctx_map_.get_refactored(tablet_id, tablet_ctx))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get tablet ctx map", KR(ret), K(tablet_id)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } + return ret; +} + +/** + * ObDirectLoadFastHeapTableTabletContext + */ + +ObDirectLoadFastHeapTableTabletContext::ObDirectLoadFastHeapTableTabletContext() + : tenant_id_(OB_INVALID_ID), is_inited_(false) +{ +} + +int ObDirectLoadFastHeapTableTabletContext::init(uint64_t tenant_id, + const ObTabletID &tablet_id, const ObTabletID &target_tablet_id, int64_t reserved_parallel) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadFastHeapTableTabletContext init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id + || !tablet_id.is_valid() + || !target_tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tenant_id), K(tablet_id), K(target_tablet_id)); + } else { + tenant_id_ = tenant_id; + tablet_id_ = tablet_id; + target_tablet_id_ = target_tablet_id; + start_seq_.set_parallel_degree(reserved_parallel); + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadFastHeapTableTabletContext::get_write_ctx( + ObDirectLoadFastHeapTableTabletWriteCtx &write_ctx) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadFastHeapTableTabletContext not init", KR(ret), KP(this)); + } else { + ObMutexGuard guard(mutex_); + if (OB_FAIL(pk_cache_.fetch(WRITE_BATCH_SIZE, write_ctx.pk_interval_))) { + if (OB_UNLIKELY(OB_EAGAIN != ret)) { + LOG_WARN("fail to fetch from pk cache", KR(ret)); + } else { + if (OB_FAIL(refresh_pk_cache())) { + LOG_WARN("fail to refresh pk cache", KR(ret)); + } else if (OB_FAIL(pk_cache_.fetch(WRITE_BATCH_SIZE, write_ctx.pk_interval_))) { + LOG_WARN("fail to fetch from pk cache", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + write_ctx.start_seq_.macro_data_seq_ = start_seq_.macro_data_seq_; + start_seq_.macro_data_seq_ += WRITE_BATCH_SIZE; + } + } + return ret; +} + +int ObDirectLoadFastHeapTableTabletContext::refresh_pk_cache() +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(fast_heap_table_refresh_pk_cache); + int ret = OB_SUCCESS; + ObTabletAutoincrementService &auto_inc = ObTabletAutoincrementService::get_instance(); + pk_cache_.tablet_id_ = tablet_id_; + pk_cache_.cache_size_ = PK_CACHE_SIZE; + if (OB_FAIL(auto_inc.get_tablet_cache_interval(tenant_id_, pk_cache_))) { + LOG_WARN("get_autoinc_seq fail", K(ret), K_(tenant_id), K_(tablet_id)); + } else if (OB_UNLIKELY(PK_CACHE_SIZE > pk_cache_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected autoincrement value count", K(ret), K(pk_cache_)); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.h b/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.h new file mode 100644 index 0000000000..c8c7c8d805 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_fast_heap_table_ctx.h @@ -0,0 +1,77 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/hash/ob_hashmap.h" +#include "lib/lock/ob_mutex.h" +#include "share/ob_tablet_autoincrement_param.h" +#include "share/table/ob_table_load_define.h" +#include "storage/blocksstable/ob_block_sstable_struct.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadFastHeapTableTabletContext; + +class ObDirectLoadFastHeapTableContext +{ +public: + ObDirectLoadFastHeapTableContext(); + ~ObDirectLoadFastHeapTableContext(); + int init(uint64_t tenant_id, + const common::ObIArray &ls_partition_ids, + const common::ObIArray &target_ls_partition_ids, + int64_t reserved_parallel); + int get_tablet_context(const common::ObTabletID &tablet_id, + ObDirectLoadFastHeapTableTabletContext *&tablet_ctx) const; +private: + int create_all_tablet_contexts(uint64_t tenant_id, + const common::ObIArray &ls_partition_ids, + const common::ObIArray &target_ls_partition_ids, + int64_t reserved_parallel); + typedef common::hash::ObHashMap + TABLET_CTX_MAP; + common::ObArenaAllocator allocator_; + TABLET_CTX_MAP tablet_ctx_map_; + bool is_inited_; +}; + +struct ObDirectLoadFastHeapTableTabletWriteCtx +{ + blocksstable::ObMacroDataSeq start_seq_; + share::ObTabletCacheInterval pk_interval_; + TO_STRING_KV(K_(start_seq), K_(pk_interval)); +}; + +class ObDirectLoadFastHeapTableTabletContext +{ + static const int64_t PK_CACHE_SIZE = 1000000; + static const int64_t WRITE_BATCH_SIZE = 100000; +public: + ObDirectLoadFastHeapTableTabletContext(); + int init(uint64_t tenant_id, + const common::ObTabletID &tablet_id, + const common::ObTabletID &target_tablet_id, + int64_t reserved_parallel); + int get_write_ctx(ObDirectLoadFastHeapTableTabletWriteCtx &write_ctx); + const common::ObTabletID &get_target_tablet_id() + { + return target_tablet_id_; + } +private: + int refresh_pk_cache(); +private: + uint64_t tenant_id_; + common::ObTabletID tablet_id_; + common::ObTabletID target_tablet_id_; + lib::ObMutex mutex_; + blocksstable::ObMacroDataSeq start_seq_; + share::ObTabletCacheInterval pk_cache_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_i_table.h b/src/storage/direct_load/ob_direct_load_i_table.h new file mode 100644 index 0000000000..469136ca63 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_i_table.h @@ -0,0 +1,52 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_row.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObIDirectLoadPartitionTable +{ +public: + ObIDirectLoadPartitionTable() = default; + virtual ~ObIDirectLoadPartitionTable() = default; + virtual const common::ObTabletID &get_tablet_id() const = 0; + virtual int64_t get_row_count() const = 0; + virtual bool is_valid() const = 0; + TO_STRING_EMPTY(); +}; + +class ObIDirectLoadPartitionTableBuilder +{ +public: + ObIDirectLoadPartitionTableBuilder() = default; + virtual ~ObIDirectLoadPartitionTableBuilder() = default; + virtual int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) = 0; + virtual int close() = 0; + virtual int64_t get_row_count() const = 0; + virtual int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) = 0; + TO_STRING_EMPTY(); +}; + +class ObIDirectLoadTabletTableCompactor +{ +public: + ObIDirectLoadTabletTableCompactor() = default; + virtual ~ObIDirectLoadTabletTableCompactor() = default; + virtual int add_table(ObIDirectLoadPartitionTable *table) = 0; + virtual int compact() = 0; + virtual int get_table(ObIDirectLoadPartitionTable *&table, common::ObIAllocator &allocator) = 0; + virtual void stop() = 0; + TO_STRING_EMPTY(); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_insert_table_ctx.cpp b/src/storage/direct_load/ob_direct_load_insert_table_ctx.cpp new file mode 100644 index 0000000000..8d081f6abe --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_insert_table_ctx.cpp @@ -0,0 +1,218 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_insert_table_ctx.h" +#include "storage/ddl/ob_direct_insert_sstable_ctx.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace table; + +/** + * ObDirectLoadInsertTableParam + */ + +ObDirectLoadInsertTableParam::ObDirectLoadInsertTableParam() + : table_id_(OB_INVALID_ID), schema_version_(0), snapshot_version_(0), execution_id_(0), ddl_task_id_(0) +{ +} + +ObDirectLoadInsertTableParam::~ObDirectLoadInsertTableParam() +{ +} + +bool ObDirectLoadInsertTableParam::is_valid() const +{ + return OB_INVALID_ID != table_id_ && schema_version_ >= 0 && snapshot_version_ >= 0 && + ls_partition_ids_.count() > 0; +} + +int ObDirectLoadInsertTableParam::assign(const ObDirectLoadInsertTableParam &other) +{ + int ret = OB_SUCCESS; + table_id_ = other.table_id_; + schema_version_ = other.schema_version_; + snapshot_version_ = other.snapshot_version_; + if (OB_FAIL(ls_partition_ids_.assign(other.ls_partition_ids_))) { + LOG_WARN("fail to assign ls tablet ids", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadInsertTableContext + */ + +ObDirectLoadInsertTableContext::ObDirectLoadInsertTableContext() + : tablet_finish_count_(0), is_inited_(false) +{ +} + +ObDirectLoadInsertTableContext::~ObDirectLoadInsertTableContext() +{ + reset(); +} + +void ObDirectLoadInsertTableContext::reset() +{ + int ret = OB_SUCCESS; + if (0 != ddl_ctrl_.context_id_) { + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + if (OB_FAIL(sstable_insert_mgr.finish_table_context(ddl_ctrl_.context_id_, false))) { + LOG_WARN("fail to finish table context", KR(ret), K_(ddl_ctrl)); + } + ddl_ctrl_.context_id_ = 0; + } + is_inited_ = false; +} + +int ObDirectLoadInsertTableContext::init(const ObDirectLoadInsertTableParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadInsertTableContext init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + ObSSTableInsertTableParam table_insert_param; + table_insert_param.dest_table_id_ = param.table_id_; + table_insert_param.snapshot_version_ = 0; + table_insert_param.schema_version_ = param.schema_version_; + table_insert_param.task_cnt_ = 1; + table_insert_param.write_major_ = true; + table_insert_param.execution_id_ = param.execution_id_; + table_insert_param.ddl_task_id_ = param.ddl_task_id_; + table_insert_param.cluster_version_ = 1; + for (int64_t i = 0; i < param.ls_partition_ids_.count(); ++i) { + const ObTableLoadLSIdAndPartitionId &ls_partition_id = param.ls_partition_ids_.at(i); + if (OB_FAIL(table_insert_param.ls_tablet_ids_.push_back( + std::make_pair(ls_partition_id.ls_id_, ls_partition_id.part_tablet_id_.tablet_id_)))) { + LOG_WARN("fail to push back ls tablet id", KR(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(param_.assign(param))) { + LOG_WARN("fail to assign param", KR(ret)); + } else if (OB_FAIL(sstable_insert_mgr.create_table_context(table_insert_param, + ddl_ctrl_.context_id_))) { + LOG_WARN("fail to create table context", KR(ret), K(table_insert_param)); + } else { + is_inited_ = true; + } + if (OB_FAIL(ret)) { + reset(); + } + } + return ret; +} + +int ObDirectLoadInsertTableContext::add_sstable_slice(const ObTabletID &tablet_id, + const ObMacroDataSeq &start_seq, + ObNewRowIterator &iter, + int64_t &affected_rows) +{ + int ret = OB_SUCCESS; + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + ObSSTableInsertTabletParam tablet_insert_param; + tablet_insert_param.context_id_ = ddl_ctrl_.context_id_; + tablet_insert_param.table_id_ = param_.table_id_; + tablet_insert_param.tablet_id_ = tablet_id; + tablet_insert_param.write_major_ = true; + tablet_insert_param.task_cnt_ = 1; + tablet_insert_param.schema_version_ = param_.schema_version_; + tablet_insert_param.snapshot_version_ = param_.snapshot_version_; + tablet_insert_param.execution_id_ = param_.execution_id_; + tablet_insert_param.ddl_task_id_ = param_.ddl_task_id_; + if (OB_FAIL(sstable_insert_mgr.update_table_tablet_context(ddl_ctrl_.context_id_, tablet_id, + param_.snapshot_version_))) { + LOG_WARN("fail to update table context", KR(ret), K_(ddl_ctrl), K(tablet_id)); + } else if (OB_FAIL(sstable_insert_mgr.add_sstable_slice(tablet_insert_param, start_seq, iter, + affected_rows))) { + LOG_WARN("fail to add sstable slice", KR(ret)); + } + return ret; +} + +int ObDirectLoadInsertTableContext::construct_sstable_slice_writer( + const ObTabletID &tablet_id, const ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&slice_writer, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadInsertTableContext not init", KR(ret), KP(this)); + } else { + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + ObSSTableInsertTabletParam tablet_insert_param; + tablet_insert_param.context_id_ = ddl_ctrl_.context_id_; + tablet_insert_param.table_id_ = param_.table_id_; + tablet_insert_param.tablet_id_ = tablet_id; + tablet_insert_param.write_major_ = true; + tablet_insert_param.task_cnt_ = 1; + tablet_insert_param.schema_version_ = param_.schema_version_; + tablet_insert_param.snapshot_version_ = param_.snapshot_version_; + tablet_insert_param.execution_id_ = param_.execution_id_; + tablet_insert_param.ddl_task_id_ = param_.ddl_task_id_; + if (OB_FAIL(sstable_insert_mgr.update_table_tablet_context(ddl_ctrl_.context_id_, tablet_id, + param_.snapshot_version_))) { + LOG_WARN("fail to update table context", KR(ret), K_(ddl_ctrl), K(tablet_id)); + } else if (OB_FAIL(sstable_insert_mgr.construct_sstable_slice_writer( + tablet_insert_param, start_seq, slice_writer, allocator))) { + LOG_WARN("fail to construct sstable slice writer", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadInsertTableContext::notify_tablet_finish(const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadInsertTableContext not init", KR(ret), KP(this)); + } else { + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + int64_t tablet_finish_count = 0; + if (OB_FAIL(sstable_insert_mgr.notify_tablet_end(ddl_ctrl_.context_id_, tablet_id))) { + LOG_WARN("fail to notify tablet end", KR(ret), K_(ddl_ctrl), K(tablet_id)); + } else if (FALSE_IT(tablet_finish_count = ATOMIC_AAF(&tablet_finish_count_, 1))) { + } else if (OB_FAIL(sstable_insert_mgr.finish_ready_tablets(ddl_ctrl_.context_id_, + tablet_finish_count))) { + LOG_WARN("fail to finish ready tablets", KR(ret), K_(ddl_ctrl), K(tablet_finish_count)); + } + } + return ret; +} + +int ObDirectLoadInsertTableContext::commit() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadInsertTableContext not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(tablet_finish_count_ != param_.ls_partition_ids_.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected finished tablet count", KR(ret), K(tablet_finish_count_), + K(param_.ls_partition_ids_.count())); + } else { + ObSSTableInsertManager &sstable_insert_mgr = ObSSTableInsertManager::get_instance(); + if (OB_FAIL(sstable_insert_mgr.finish_table_context(ddl_ctrl_.context_id_, true))) { + LOG_WARN("fail to finish table context", KR(ret), K_(ddl_ctrl)); + } else { + ddl_ctrl_.context_id_ = 0; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_insert_table_ctx.h b/src/storage/direct_load/ob_direct_load_insert_table_ctx.h new file mode 100644 index 0000000000..8141cf8cef --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_insert_table_ctx.h @@ -0,0 +1,59 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "share/table/ob_table_load_define.h" +#include "sql/engine/px/ob_sub_trans_ctrl.h" + +namespace oceanbase +{ +namespace storage +{ +class ObSSTableInsertSliceWriter; + +struct ObDirectLoadInsertTableParam +{ +public: + ObDirectLoadInsertTableParam(); + ~ObDirectLoadInsertTableParam(); + int assign(const ObDirectLoadInsertTableParam &other); + bool is_valid() const; + TO_STRING_KV(K_(table_id), K_(schema_version), K_(snapshot_version), K_(ls_partition_ids), K_(execution_id), K_(ddl_task_id)); +public: + uint64_t table_id_; + int64_t schema_version_; + int64_t snapshot_version_; + int64_t execution_id_; + int64_t ddl_task_id_; + common::ObArray ls_partition_ids_; +}; + +class ObDirectLoadInsertTableContext +{ +public: + ObDirectLoadInsertTableContext(); + ~ObDirectLoadInsertTableContext(); + void reset(); + int init(const ObDirectLoadInsertTableParam ¶m); + int add_sstable_slice(const common::ObTabletID &tablet_id, + const blocksstable::ObMacroDataSeq &start_seq, + common::ObNewRowIterator &iter, + int64_t &affected_rows); + int construct_sstable_slice_writer(const common::ObTabletID &tablet_id, + const blocksstable::ObMacroDataSeq &start_seq, + ObSSTableInsertSliceWriter *&slice_writer, + common::ObIAllocator &allocator); + int notify_tablet_finish(const common::ObTabletID &tablet_id); + int commit(); + TO_STRING_KV(K_(param), K_(ddl_ctrl)); +private: + ObDirectLoadInsertTableParam param_; + sql::ObDDLCtrl ddl_ctrl_; + int64_t tablet_finish_count_ CACHE_ALIGNED; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_io_callback.cpp b/src/storage/direct_load/ob_direct_load_io_callback.cpp new file mode 100644 index 0000000000..ed92c0bcc5 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_io_callback.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_io_callback.h" +#include "lib/allocator/ob_malloc.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_utility.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadIOCallback::ObDirectLoadIOCallback(uint64_t tenant_id) + : tenant_id_(tenant_id), io_buf_(nullptr), data_buf_(nullptr) +{ +} + +ObDirectLoadIOCallback::~ObDirectLoadIOCallback() +{ + if (nullptr != io_buf_) { + ob_free_align(io_buf_); + io_buf_ = nullptr; + } + data_buf_ = nullptr; +} + +int ObDirectLoadIOCallback::alloc_io_buf(char *&io_buf, int64_t &size, int64_t &offset) +{ + int ret = OB_SUCCESS; + const int64_t aligned_offset = lower_align(offset, DIO_READ_ALIGN_SIZE); + const int64_t aligned_size = upper_align(size + offset - aligned_offset, DIO_READ_ALIGN_SIZE); + ObMemAttr attr; + attr.tenant_id_ = tenant_id_; + attr.label_ = ObModIds::OB_SQL_LOAD_DATA; + if (OB_ISNULL(io_buf_ = + static_cast(ob_malloc_align(DIO_READ_ALIGN_SIZE, aligned_size, attr)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret), K(aligned_size)); + } else { + data_buf_ = io_buf_ + (offset - aligned_offset); + io_buf = io_buf_; + size = aligned_size; + offset = aligned_offset; + } + return ret; +} + +int ObDirectLoadIOCallback::inner_process(const bool is_success) +{ + return OB_SUCCESS; +} + +int ObDirectLoadIOCallback::inner_deep_copy(char *buf, const int64_t buf_len, + ObIOCallback *&copied_callback) const +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(buf) || OB_UNLIKELY(buf_len < size())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(buf_len)); + } else { + copied_callback = new (buf) ObDirectLoadIOCallback(tenant_id_); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_io_callback.h b/src/storage/direct_load/ob_direct_load_io_callback.h new file mode 100644 index 0000000000..f5acb03f84 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_io_callback.h @@ -0,0 +1,35 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "share/io/ob_io_define.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadIOCallback : public common::ObIOCallback +{ +public: + ObDirectLoadIOCallback(uint64_t tenant_id = common::OB_SERVER_TENANT_ID); + virtual ~ObDirectLoadIOCallback(); + const char *get_data() override { return data_buf_; } + int64_t size() const override { return sizeof(*this); } + int alloc_io_buf(char *&io_buf, int64_t &size, int64_t &offset) override; + void set_tenant_id(uint64_t tenant_id) { tenant_id_ = tenant_id; } + TO_STRING_KV(K_(io_buf), K_(data_buf)); +protected: + int inner_process(const bool is_success) override; + int inner_deep_copy(char *buf, const int64_t buf_len, + ObIOCallback *&copied_callback) const override; +private: + uint64_t tenant_id_; + char *io_buf_; + char *data_buf_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_chunk.h b/src/storage/direct_load/ob_direct_load_mem_chunk.h new file mode 100644 index 0000000000..43fa866a1e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_chunk.h @@ -0,0 +1,196 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/container/ob_vector.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_external_scanner.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadMemChunk; + +template +class ObDirectLoadMemChunkIter : public ObDirectLoadExternalIterator +{ +public: + ObDirectLoadMemChunkIter() : chunk_(nullptr), start_(-1), end_(-1) {} + ObDirectLoadMemChunkIter(ObDirectLoadMemChunk *chunk, + int64_t start, + int64_t end) : + chunk_(chunk), start_(start), end_(end) {} + + int get_next_item(const T *&item); + +private: + ObDirectLoadMemChunk *chunk_; + int64_t start_; + int64_t end_; +}; + +template +class ObDirectLoadMemChunk +{ + friend class ObDirectLoadMemChunkIter; +public: + static const constexpr int64_t MIN_MEMORY_LIMIT = 8 * 1024LL * 1024LL; // min memory limit is 8M + + ObDirectLoadMemChunk(); + int init(uint64_t tenant_id, int64_t mem_limit); + int add_item(const T &item); + int64_t get_size() const { + return item_list_.size(); + } + + T *get_item(int64_t idx) { + return item_list_[idx]; + } + + // start如果是nullptr,表示min + // end如果是nullptr,表示max + ObDirectLoadMemChunkIter scan(T *start, T *end, Compare &compare) { //左开右闭 + int64_t start_idx = 0; + int64_t end_idx = 0; + if (start != nullptr) { + auto iter = std::upper_bound(item_list_.begin(), item_list_.end(), start, compare); + start_idx = (iter - item_list_.begin()); + } else { + start_idx = 0; + } + if (end != nullptr) { + auto iter2 = std::upper_bound(item_list_.begin(), item_list_.end(), end, compare); + end_idx = iter2 - item_list_.begin() - 1; + } else { + end_idx = item_list_.size() - 1; + } + return ObDirectLoadMemChunkIter(this, start_idx, end_idx); + } + + void reuse(); + void reset(); + int sort(Compare &compare); + TO_STRING_KV(K(buf_mem_limit_), "size", item_list_.size()); +private: + int64_t buf_mem_limit_; + common::ObArenaAllocator allocator_; + common::ObVector item_list_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMemChunk); +}; + +template +int ObDirectLoadMemChunkIter::get_next_item(const T *&item) { + int ret = common::OB_SUCCESS; + if (start_ > end_) { + ret = common::OB_ITER_END; + } else { + item = chunk_->item_list_[start_ ++]; + } + return ret; +} + +template +int ObDirectLoadMemChunk::sort(Compare &compare) +{ + int ret = common::OB_SUCCESS; + if (item_list_.size() > 1) { + OB_TABLE_LOAD_STATISTICS_TIME_COST(memory_sort_item_time_us); + std::sort(item_list_.begin(), item_list_.end(), compare); + if (OB_FAIL(compare.get_error_code())) { + ret = compare.get_error_code(); + STORAGE_LOG(WARN, "fail to sort memory item list", KR(ret)); + } + } + return ret; +} + +template +ObDirectLoadMemChunk::ObDirectLoadMemChunk() + : buf_mem_limit_(0), + allocator_("TLD_MemChunk"), + is_inited_(false) +{ +} + +template +int ObDirectLoadMemChunk::init(uint64_t tenant_id, int64_t mem_limit) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadMemChunk init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(mem_limit < MIN_MEMORY_LIMIT)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(mem_limit)); + } else { + buf_mem_limit_ = mem_limit; + allocator_.set_tenant_id(tenant_id); + is_inited_ = true; + } + return ret; +} + +template +int ObDirectLoadMemChunk::add_item(const T &item) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadMemChunk not init", KR(ret), KP(this)); + } else { + const int64_t item_size = sizeof(T) + item.get_deep_copy_size(); + if (item_size > buf_mem_limit_) { + ret = common::OB_SIZE_OVERFLOW; + STORAGE_LOG(WARN, "invalid item size, must not larger than buf memory limit", KR(ret), + K(item_size), K(buf_mem_limit_)); + } else if (allocator_.used() + item_size > buf_mem_limit_) { + return OB_BUF_NOT_ENOUGH; + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(memory_add_item_time_us); + char *buf = nullptr; + T *new_item = nullptr; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(item_size)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to allocate memory", KR(ret), K(item_size)); + } else { + new_item = new (buf) T(); + int64_t buf_pos = sizeof(T); + if (OB_FAIL(new_item->deep_copy(item, buf, item_size, buf_pos))) { + STORAGE_LOG(WARN, "fail to deep copy item", KR(ret)); + } else if (OB_FAIL(item_list_.push_back(new_item))) { + STORAGE_LOG(WARN, "fail to push back new item", KR(ret)); + } + } + } + } + return ret; +} + +template +void ObDirectLoadMemChunk::reuse() +{ + for (int64_t i = 0; i < item_list_.size(); ++i) { + item_list_[i]->~T(); + } + item_list_.reset(); + allocator_.reuse(); +} + +template +void ObDirectLoadMemChunk::reset() +{ + reuse(); + allocator_.reset(); + is_inited_ = false; +} + + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_context.cpp b/src/storage/direct_load/ob_direct_load_mem_context.cpp new file mode 100644 index 0000000000..379a0150a8 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_context.cpp @@ -0,0 +1,157 @@ +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_mem_loader.h" + +namespace oceanbase +{ +namespace storage +{ + +int ObMemDumpQueue::push(void *p) +{ + int ret = OB_SUCCESS; + Item *item = op_alloc_args(Item, p); + int32_t count = 0; + while (OB_SUCC(ret)) { + ret = queue_.push(item, 10000000); + if (OB_TIMEOUT == ret) { + ret = OB_SUCCESS; + count ++; + STORAGE_LOG(WARN, "the push operation has been timeout n times", K(count)); + continue; + } else if (OB_FAIL(ret)) { + STORAGE_LOG(WARN, "fail to push item", KR(ret)); + } else { + break; + } + } + return ret; +} + +int ObMemDumpQueue::pop(void *&p) +{ + int ret = OB_SUCCESS; + void *tmp = nullptr; + int32_t count = 0; + while (OB_SUCC(ret)) { + ret = queue_.pop(tmp, 10000000); + if (OB_SUCCESS == ret) { + Item *item_ptr = (Item *)tmp; + p = item_ptr->ptr_; + op_free(item_ptr); + break; + } else if (ret == OB_ENTRY_NOT_EXIST) { //queue超时返回的错误码是这个,只能将错就错了 + ret = OB_SUCCESS; //防止超时 + count ++; + STORAGE_LOG(WARN, "the pop operation has been timeout n times", K(count)); + continue; + } else { + STORAGE_LOG(WARN, "fail to pop queue", KR(ret)); + } + } + return ret; +} + +ObMemDumpQueue::~ObMemDumpQueue() +{ + for (int64_t i = 0; i < queue_.size(); i ++) { + void *tmp = nullptr; + queue_.pop(tmp); + if (tmp != nullptr) { + Item *item_ptr = (Item *)tmp; + op_free(item_ptr); + } + } +} + +void ObDirectLoadMemContext::reset() +{ + table_data_desc_.reset(); + datum_utils_ = nullptr; + need_sort_ = false; + mem_load_task_count_ = 0; + column_count_ = 0; + file_mgr_ = nullptr; + fly_mem_chunk_count_ = 0; + finish_compact_count_ = 0; + mem_dump_task_count_ = 0; + has_error_ = false; + + ObArray loader_array; + mem_loader_queue_.pop_all(loader_array); + for (int64_t i = 0; i < loader_array.count(); i ++) { + ObDirectLoadMemWorker *tmp = loader_array.at(i); + if (tmp != nullptr) { + tmp->~ObDirectLoadMemWorker(); //是由area_allocator分配的,所以不需要free + } + } + + ObArray chunk_array; + mem_chunk_queue_.pop_all(chunk_array); + for (int64_t i = 0; i < chunk_array.count(); i ++) { + ObDirectLoadExternalMultiPartitionRowChunk *chunk = chunk_array.at(i); + if (chunk != nullptr) { + chunk->~ObDirectLoadExternalMultiPartitionRowChunk(); + ob_free(chunk); + } + } + + for (int64_t i = 0; i < tables_.count(); i ++) { + ObIDirectLoadPartitionTable *table = tables_.at(i); + if (table != nullptr) { + table->~ObIDirectLoadPartitionTable(); //table是由allocator_分配的,是area allocator,不用free + } + } + tables_.reset(); + allocator_.reset(); +} + +ObDirectLoadMemContext::~ObDirectLoadMemContext() +{ + reset(); +} + +int ObDirectLoadMemContext::init() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(mem_dump_queue_.init(1024))) { + STORAGE_LOG(WARN, "fail to init mem dump queue", KR(ret)); + } + return ret; +} + +int ObDirectLoadMemContext::add_tables_from_table_builder(ObIDirectLoadPartitionTableBuilder &builder) +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(mutex_); + ObArray table_array; + if (OB_SUCC(ret)) { + if (OB_FAIL(builder.get_tables(table_array, allocator_))) { + LOG_WARN("fail to get tables", KR(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < table_array.count(); i ++) { + if (OB_FAIL(tables_.push_back(table_array.at(i)))) { + LOG_WARN("fail to push table", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMemContext::add_tables_from_table_compactor( + ObIDirectLoadTabletTableCompactor &compactor) +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(mutex_); + ObIDirectLoadPartitionTable *table = nullptr; + if (OB_FAIL(compactor.get_table(table, allocator_))) { + LOG_WARN("fail to get table", KR(ret)); + } else if (OB_FAIL(tables_.push_back(table))) { + LOG_WARN("fail to push table", KR(ret)); + } + return ret; +} + +} +} diff --git a/src/storage/direct_load/ob_direct_load_mem_context.h b/src/storage/direct_load/ob_direct_load_mem_context.h new file mode 100644 index 0000000000..954c2fb6b3 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_context.h @@ -0,0 +1,98 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#ifndef OB_DIRECT_LOAD_MEM_CONTEXT_H_ +#define OB_DIRECT_LOAD_MEM_CONTEXT_H_ + +#include "storage/direct_load/ob_direct_load_easy_queue.h" +#include "storage/direct_load/ob_direct_load_mem_define.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMemWorker; + +class ObMemDumpQueue +{ + struct Item + { + void *ptr_; + Item() : ptr_(nullptr) {} + Item(void *ptr) : ptr_(ptr) {} + }; +public: + ~ObMemDumpQueue(); + int push(void *p); + int pop(void *&p); + int init(int64_t capacity) { + return queue_.init(capacity); + } +private: + common::LightyQueue queue_; +}; + + + +class ObDirectLoadMemContext +{ +public: + ObDirectLoadMemContext() : datum_utils_(nullptr), + need_sort_(false), + mem_load_task_count_(0), + column_count_(0), + file_mgr_(nullptr), + result_info_(nullptr), + fly_mem_chunk_count_(0), + finish_compact_count_(0), + mem_dump_task_count_(0), + running_dump_count_(0), + allocator_("TLD_mem_ctx"), + has_error_(false) {} + + ~ObDirectLoadMemContext(); + +public: + int init(); + void reset(); + int add_tables_from_table_builder(ObIDirectLoadPartitionTableBuilder &builder); + int add_tables_from_table_compactor(ObIDirectLoadTabletTableCompactor &compactor); + +public: + static const int64_t MIN_MEM_LIMIT = 8LL * 1024 * 1024; // 8MB + +public: + + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + bool need_sort_; // false: sstable, true: external_table + int32_t mem_load_task_count_; + int32_t column_count_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + ObDirectLoadTmpFileManager *file_mgr_; + table::ObTableLoadResultInfo *result_info_; + ObDirectLoadEasyQueue mem_chunk_queue_; + int64_t fly_mem_chunk_count_; + + ObDirectLoadEasyQueue mem_loader_queue_; + int64_t finish_compact_count_; + int64_t mem_dump_task_count_; + int64_t running_dump_count_; + ObMemDumpQueue mem_dump_queue_; + + ObArenaAllocator allocator_; + ObArray tables_; + lib::ObMutex mutex_; + + volatile bool has_error_; +}; + +} +} + +#endif /* OB_DIRECT_LOAD_MEM_CONTEXT_H_ */ diff --git a/src/storage/direct_load/ob_direct_load_mem_define.h b/src/storage/direct_load/ob_direct_load_mem_define.h new file mode 100644 index 0000000000..4629adb987 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_define.h @@ -0,0 +1,37 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_compare.h" +#include "storage/direct_load/ob_direct_load_external_multi_partition_row.h" +#include "storage/direct_load/ob_direct_load_mem_chunk.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadExternalMultiPartitionRowRange +{ +public: + ObDirectLoadExternalMultiPartitionRowRange() : start_(nullptr), end_(nullptr) {} + ObDirectLoadExternalMultiPartitionRowRange(ObDirectLoadConstExternalMultiPartitionRow *start, + ObDirectLoadConstExternalMultiPartitionRow *end) + : start_(start), end_(end) + { + } + TO_STRING_KV(KP_(start), KP_(end)); + +public: + ObDirectLoadConstExternalMultiPartitionRow *start_; + ObDirectLoadConstExternalMultiPartitionRow *end_; +}; + +typedef ObDirectLoadMemChunk + ObDirectLoadExternalMultiPartitionRowChunk; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_dump.cpp b/src/storage/direct_load/ob_direct_load_mem_dump.cpp new file mode 100644 index 0000000000..62837a6d36 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_dump.cpp @@ -0,0 +1,451 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_mem_dump.h" +#include "observer/table_load/ob_table_load_mem_compactor.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_external_table_builder.h" +#include "storage/direct_load/ob_direct_load_external_table_compactor.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_builder.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_compactor.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace table; +using namespace sql; + +/** + * Context + */ + +ObDirectLoadMemDump::Context::Context() + : allocator_("TLD_MemDumpCtx"), + safe_allocator_(allocator_), + finished_sub_dump_count_(0), + sub_dump_count_(0) +{ +} + +ObDirectLoadMemDump::Context::~Context() +{ + for (int64_t i = 0; i < all_tables_.count(); i++) { + ObIDirectLoadPartitionTable *table = all_tables_.at(i); + if (table != nullptr) { + table->~ObIDirectLoadPartitionTable(); + } + } + for (int64_t i = 0; i < mem_chunk_array_.count(); i++) { + ChunkType *chunk = mem_chunk_array_.at(i); + if (chunk != nullptr) { + chunk->~ChunkType(); + ob_free(chunk); + } + } +} + +int ObDirectLoadMemDump::Context::add_table(const ObTabletID &tablet_id, int64_t range_idx, + ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + lib::ObMutexGuard guard(mutex_); + if (OB_FAIL(all_tables_.push_back(table))) { + LOG_WARN("fail to push table", KR(ret)); + } else if (OB_FAIL(tables_.add(tablet_id, std::make_pair(range_idx, table)))) { + LOG_WARN("fail to add table", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMemDump + */ + +ObDirectLoadMemDump::ObDirectLoadMemDump(ObDirectLoadMemContext *mem_ctx, + const RangeType &range, + ObTableLoadHandle context_ptr, int64_t range_idx) + : allocator_("TLD_MemDump"), + mem_ctx_(mem_ctx), + range_(range), + context_ptr_(context_ptr), + range_idx_(range_idx), + extra_buf_(nullptr), + extra_buf_size_(0) +{ +} + +ObDirectLoadMemDump::~ObDirectLoadMemDump() {} + +int ObDirectLoadMemDump::new_table_builder(const ObTabletID &tablet_id, + ObIDirectLoadPartitionTableBuilder *&table_builder) +{ + int ret = OB_SUCCESS; + if (mem_ctx_->table_data_desc_.is_heap_table_) { + ret = new_external_table_builder(tablet_id, table_builder); + } else { + ret = new_sstable_builder(tablet_id, table_builder); + } + return ret; +} + +int ObDirectLoadMemDump::new_sstable_builder(const ObTabletID &tablet_id, + ObIDirectLoadPartitionTableBuilder *&table_builder) +{ + UNUSED(tablet_id); + int ret = OB_SUCCESS; + if (nullptr == table_builder) { + ObDirectLoadMultipleSSTableBuilder *sstable_builder = nullptr; + ObDirectLoadMultipleSSTableBuildParam sstable_build_param; + sstable_build_param.table_data_desc_ = mem_ctx_->table_data_desc_; + sstable_build_param.file_mgr_ = mem_ctx_->file_mgr_; + sstable_build_param.datum_utils_ = mem_ctx_->datum_utils_; + sstable_build_param.extra_buf_ = extra_buf_; + sstable_build_param.extra_buf_size_ = extra_buf_size_; + if (OB_ISNULL(sstable_builder = OB_NEWx(ObDirectLoadMultipleSSTableBuilder, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate sstable builder", KR(ret)); + } else if (OB_FAIL(sstable_builder->init(sstable_build_param))) { + LOG_WARN("fail to init sstable builder", KR(ret)); + } else { + table_builder = sstable_builder; + } + if (OB_FAIL(ret)) { + if (nullptr != sstable_builder) { + sstable_builder->~ObDirectLoadMultipleSSTableBuilder(); + allocator_.free(sstable_builder); + sstable_builder = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMemDump::new_external_table_builder( + const ObTabletID &tablet_id, ObIDirectLoadPartitionTableBuilder *&table_builder) +{ + int ret = OB_SUCCESS; + ObDirectLoadExternalTableBuilder *external_table_builder = nullptr; + ObDirectLoadExternalTableBuildParam external_build_param; + external_build_param.table_data_desc_ = mem_ctx_->table_data_desc_; + external_build_param.file_mgr_ = mem_ctx_->file_mgr_; + external_build_param.tablet_id_ = tablet_id; + external_build_param.datum_utils_ = mem_ctx_->datum_utils_; + external_build_param.extra_buf_ = extra_buf_; + external_build_param.extra_buf_size_ = extra_buf_size_; + if (OB_ISNULL(external_table_builder = + OB_NEWx(ObDirectLoadExternalTableBuilder, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate external table builder", KR(ret)); + } else if (OB_FAIL(external_table_builder->init(external_build_param))) { + LOG_WARN("fail to init external table builder", KR(ret)); + } else { + table_builder = external_table_builder; + } + if (OB_FAIL(ret)) { + if (nullptr != external_table_builder) { + external_table_builder->~ObDirectLoadExternalTableBuilder(); + allocator_.free(external_table_builder); + external_table_builder = nullptr; + } + } + return ret; +} + +int ObDirectLoadMemDump::close_table_builder(ObIDirectLoadPartitionTableBuilder *table_builder, + ObTabletID tablet_id, bool is_final) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table_builder)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table_builder)); + } else { + const bool need_close = (mem_ctx_->table_data_desc_.is_heap_table_ || is_final); + if (need_close && table_builder->get_row_count() > 0) { //暂时因为simple file有问题 + ObSEArray table_array; + if (OB_FAIL(table_builder->close())) { + LOG_WARN("fail to close sstable builder", KR(ret)); + } else if (OB_FAIL(table_builder->get_tables(table_array, context_ptr_->safe_allocator_))) { + LOG_WARN("fail to get tables", KR(ret)); + } else if (OB_UNLIKELY(1 != table_array.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table count not equal 1", KR(ret)); + } else { + ObIDirectLoadPartitionTable *table = table_array.at(0); + if (OB_FAIL(context_ptr_->add_table(table->get_tablet_id(), range_idx_, table))) { + LOG_WARN("fail to add table", K(tablet_id), K(range_idx_), KR(ret)); + } + } + if (OB_FAIL(ret)) { + for (int64_t i = 0; i < table_array.count(); ++i) { + ObIDirectLoadPartitionTable *table = table_array.at(i); + table->~ObIDirectLoadPartitionTable(); + } + } + } + if (OB_SUCC(ret) && need_close) { + table_builder->~ObIDirectLoadPartitionTableBuilder(); + table_builder = nullptr; + } + } + return ret; +} + +int ObDirectLoadMemDump::dump_tables() +{ + typedef ObDirectLoadExternalIterator ExternalIterator; + int ret = OB_SUCCESS; + ObArray iters; + ObArray> chunk_iters; //用于暂存iters + ObDirectLoadExternalMerger merger; + CompareType compare; + + const RowType *external_row = nullptr; + ObDatumRow datum_row; + + ObIDirectLoadPartitionTableBuilder *table_builder = nullptr; + + allocator_.set_tenant_id(MTL_ID()); + extra_buf_size_ = mem_ctx_->table_data_desc_.extra_buf_size_; + if (OB_ISNULL(extra_buf_ = static_cast(allocator_.alloc(extra_buf_size_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", KR(ret)); + } else if (OB_FAIL(compare.init(*(mem_ctx_->datum_utils_)))) { + LOG_WARN("fail to init compare", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < context_ptr_->mem_chunk_array_.count(); i++) { + ChunkType *chunk = context_ptr_->mem_chunk_array_[i]; + auto iter = chunk->scan(range_.start_, range_.end_, compare); + if (OB_FAIL(chunk_iters.push_back(iter))) { + LOG_WARN("fail to push iter", KR(ret)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < chunk_iters.size(); i++) { + if (OB_FAIL(iters.push_back(&(chunk_iters[i])))) { + LOG_WARN("fail to push iters", KR(ret)); + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(merger.init(iters, &compare))) { + LOG_WARN("fail to init merger", KR(ret)); + } else if (OB_FAIL(datum_row.init(mem_ctx_->column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row.mvcc_row_flag_.set_last_multi_version_row(true); + } + } + ObTabletID last_tablet_id; + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + if (OB_FAIL(merger.get_next_item(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row"); + } else { + ret = OB_SUCCESS; + break; + } + } else if (external_row->tablet_id_ != last_tablet_id) { + if (nullptr != table_builder && + OB_FAIL(close_table_builder(table_builder, last_tablet_id, false /*is_final*/))) { + LOG_WARN("fail to close table builder", KR(ret)); + } else if (OB_FAIL(new_table_builder(external_row->tablet_id_, table_builder))) { + LOG_WARN("fail to new table builder", KR(ret)); + } else { + last_tablet_id = external_row->tablet_id_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(external_row->to_datums(datum_row.storage_datums_, datum_row.count_))) { + LOG_WARN("fail to transfer dataum row", KR(ret)); + } else if (OB_FAIL(table_builder->append_row(external_row->tablet_id_, datum_row))) { + if (OB_LIKELY(OB_ERR_PRIMARY_KEY_DUPLICATE == ret)) { + int tmp_ret = OB_SUCCESS; + if (mem_ctx_->error_row_handler_->get_action() == ObLoadDupActionType::LOAD_REPLACE) { + ATOMIC_AAF(&mem_ctx_->result_info_->rows_affected_, 2); + ATOMIC_INC(&mem_ctx_->result_info_->deleted_); + } else if (mem_ctx_->error_row_handler_->get_action() == ObLoadDupActionType::LOAD_IGNORE) { + ATOMIC_INC(&mem_ctx_->result_info_->skipped_); + } else if (mem_ctx_->error_row_handler_->get_action() == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + if (OB_TMP_FAIL(mem_ctx_->error_row_handler_->append_error_row(datum_row))) { + LOG_WARN("failed to append row to error row handler", K(tmp_ret), K(datum_row)); + } + } + if (OB_LIKELY(OB_SUCCESS == tmp_ret)) { + ret = OB_SUCCESS; + } + } else { + LOG_WARN("fail to append row", K(ret), K(datum_row)); + } + } + } + } + if (OB_SUCC(ret)) { + if (nullptr != table_builder && + OB_FAIL(close_table_builder(table_builder, last_tablet_id, true /*is_final*/))) { + LOG_WARN("fail to close table builder", KR(ret)); + } else { + table_builder = nullptr; + } + } + if (OB_FAIL(ret)) { + if (nullptr != table_builder) { + table_builder->~ObIDirectLoadPartitionTableBuilder(); + table_builder = nullptr; + } + } + return ret; +} + +int ObDirectLoadMemDump::new_table_compactor(const ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor) +{ + int ret = OB_SUCCESS; + if (mem_ctx_->table_data_desc_.is_heap_table_) { + ret = new_external_table_compactor(tablet_id, compactor); + } else { + ret = new_sstable_compactor(tablet_id, compactor); + } + return ret; +} + +int ObDirectLoadMemDump::new_sstable_compactor(const ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor) +{ + UNUSED(tablet_id); + int ret = OB_SUCCESS; + ObDirectLoadMultipleSSTableCompactor *sstable_compactor = nullptr; + ObDirectLoadMultipleSSTableCompactParam param; + param.table_data_desc_ = mem_ctx_->table_data_desc_; + param.datum_utils_ = mem_ctx_->datum_utils_; + if (OB_ISNULL(sstable_compactor = OB_NEWx(ObDirectLoadMultipleSSTableCompactor, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableCompactor", KR(ret)); + } else if (OB_FAIL(sstable_compactor->init(param))) { + LOG_WARN("fail to init compactor", KR(ret)); + } else { + compactor = sstable_compactor; + } + if (OB_FAIL(ret)) { + if (nullptr != sstable_compactor) { + sstable_compactor->~ObDirectLoadMultipleSSTableCompactor(); + sstable_compactor = nullptr; + } + } + return ret; +} + +int ObDirectLoadMemDump::new_external_table_compactor(const ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor) +{ + int ret = OB_SUCCESS; + ObDirectLoadExternalTableCompactor *external_table_compactor = nullptr; + ObDirectLoadExternalTableCompactParam param; + param.tablet_id_ = tablet_id; + param.table_data_desc_ = mem_ctx_->table_data_desc_; + if (OB_ISNULL(external_table_compactor = + OB_NEWx(ObDirectLoadExternalTableCompactor, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadExternalTableCompactor", KR(ret)); + } else if (OB_FAIL(external_table_compactor->init(param))) { + LOG_WARN("fail to init compactor", KR(ret)); + } else { + compactor = external_table_compactor; + } + if (OB_FAIL(ret)) { + if (nullptr != external_table_compactor) { + external_table_compactor->~ObDirectLoadExternalTableCompactor(); + external_table_compactor = nullptr; + } + } + return ret; +} + +int ObDirectLoadMemDump::compact_tables() +{ + int ret = OB_SUCCESS; + ObArray keys; + if (OB_FAIL(context_ptr_->tables_.get_all_key(keys))) { + LOG_WARN("fail to get all keys", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < keys.count(); i++) { + if (OB_FAIL(compact_tablet_tables(keys.at(i)))) { + LOG_WARN("fail to compact tablet tables", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMemDump::compact_tablet_tables(const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + ObIDirectLoadTabletTableCompactor *compactor = nullptr; + + ObArray> table_array; + if (OB_FAIL(context_ptr_->tables_.get(tablet_id, table_array))) { + LOG_WARN("fail to get table array", K(tablet_id), KR(ret)); + } else { + std::sort( + table_array.begin(), table_array.end(), + [](const std::pair &a, + const std::pair &b) { return a.first < b.first; }); + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(new_table_compactor(tablet_id, compactor))) { + LOG_WARN("fail to new table compactor", KR(ret)); + } + } + + for (int64_t i = 0; OB_SUCC(ret) && i < table_array.count(); i++) { + if (OB_FAIL(compactor->add_table(table_array[i].second))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + + if (OB_SUCC(ret)) { + ObIDirectLoadPartitionTable *table = nullptr; + if (OB_FAIL(compactor->compact())) { + LOG_WARN("fail to compact tables", KR(ret)); + } else if (OB_FAIL(compactor->get_table(table, mem_ctx_->allocator_))) { + LOG_WARN("fail to get table", KR(ret)); + } else if (OB_FAIL(mem_ctx_->tables_.push_back(table))) { + LOG_WARN("fail to add table", KR(ret)); + } + } + + if (nullptr != compactor) { + compactor->~ObIDirectLoadTabletTableCompactor(); + compactor = nullptr; + } + return ret; +} + +int ObDirectLoadMemDump::do_dump() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(dump_tables())) { + LOG_WARN("fail to dump tables", KR(ret)); + } else { + int64_t finished = ATOMIC_AAF(&(context_ptr_->finished_sub_dump_count_), 1); + if (finished == context_ptr_->sub_dump_count_) { + if (OB_FAIL(compact_tables())) { + LOG_WARN("fail to compact tables", KR(ret)); + } + ATOMIC_AAF(&(mem_ctx_->fly_mem_chunk_count_), -context_ptr_->mem_chunk_array_.count()); + } + } + ATOMIC_AAF(&(mem_ctx_->running_dump_count_), -1); + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_dump.h b/src/storage/direct_load/ob_direct_load_mem_dump.h new file mode 100644 index 0000000000..26b8221e79 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_dump.h @@ -0,0 +1,96 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/lock/ob_mutex.h" +#include "share/table/ob_table_load_handle.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_mem_define.h" +#include "storage/direct_load/ob_direct_load_multi_map.h" +#include "storage/direct_load/ob_direct_load_sstable_builder.h" + +namespace oceanbase +{ +namespace storage +{ +class ObIDirectLoadPartitionTable; + +class ObDirectLoadMemDump +{ + typedef ObDirectLoadConstExternalMultiPartitionRow RowType; + typedef ObDirectLoadExternalMultiPartitionRowChunk ChunkType; + typedef ObDirectLoadExternalMultiPartitionRowRange RangeType; + typedef ObDirectLoadExternalMultiPartitionRowCompare CompareType; +public: + class Context + { + public: + Context(); + ~Context(); + int add_table(const common::ObTabletID &tablet_id, int64_t range_idx, + ObIDirectLoadPartitionTable *table); + + int init() + { + return tables_.init(); + } + + private: + ObArenaAllocator allocator_; // just for safe_allocator_ + public: + ObSafeArenaAllocator safe_allocator_; + //注意,如果这个tables_会被多线程操作,必须加锁 + ObDirectLoadMultiMap> + tables_; + common::ObArray mem_chunk_array_; + int64_t finished_sub_dump_count_; + int64_t sub_dump_count_; + + private: + lib::ObMutex mutex_; + ObArray all_tables_; + }; + +public: + ObDirectLoadMemDump(ObDirectLoadMemContext *mem_ctx, + const RangeType &range, + table::ObTableLoadHandle context_ptr, int64_t range_idx); + ~ObDirectLoadMemDump(); + int do_dump(); + +private: + // dump tables + int new_table_builder(const ObTabletID &tablet_id, + ObIDirectLoadPartitionTableBuilder *&table_builder); + int new_sstable_builder(const ObTabletID &tablet_id, + ObIDirectLoadPartitionTableBuilder *&table_builder); + int new_external_table_builder(const ObTabletID &tablet_id, + ObIDirectLoadPartitionTableBuilder *&table_builder); + int close_table_builder(ObIDirectLoadPartitionTableBuilder *table_builder, + common::ObTabletID tablet_id, bool is_final); + int dump_tables(); + // compact tables + int new_table_compactor(const common::ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor); + int new_sstable_compactor(const common::ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor); + int new_external_table_compactor(const common::ObTabletID &tablet_id, + ObIDirectLoadTabletTableCompactor *&compactor); + int compact_tables(); + int compact_tablet_tables(const common::ObTabletID &tablet_id); + +private: + // data members + ObArenaAllocator allocator_; + ObDirectLoadMemContext *mem_ctx_; + RangeType range_; + table::ObTableLoadHandle context_ptr_; + int64_t range_idx_; + char *extra_buf_; + int64_t extra_buf_size_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_loader.cpp b/src/storage/direct_load/ob_direct_load_mem_loader.cpp new file mode 100644 index 0000000000..5b0f053b38 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_loader.cpp @@ -0,0 +1,156 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_mem_loader.h" +#include "storage/direct_load/ob_direct_load_external_block_reader.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_mem_sample.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMemLoader + */ + +ObDirectLoadMemLoader::ObDirectLoadMemLoader(ObDirectLoadMemContext *mem_ctx) + : mem_ctx_(mem_ctx) +{ +} + +ObDirectLoadMemLoader::~ObDirectLoadMemLoader() +{ +} + +int ObDirectLoadMemLoader::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + ObDirectLoadExternalTable *external_table = nullptr; + if (OB_ISNULL(external_table = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table)); + } else if (OB_UNLIKELY(external_table->get_fragments().count() != 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("files handle should only have one handle", KR(ret)); + } else if (OB_FAIL(fragments_.push_back(external_table->get_fragments()))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMemLoader::work() +{ + typedef ObDirectLoadExternalBlockReader ExternalReader; + int ret = OB_SUCCESS; + const ObDirectLoadExternalMultiPartitionRow *external_row = nullptr; + ChunkType *chunk = nullptr; + RowType row; + for (int64_t i = 0; OB_SUCC(ret) && i < fragments_.count(); i++) { + const ObDirectLoadExternalFragment &fragment = fragments_.at(i); + ExternalReader external_reader; + if (OB_FAIL(external_reader.init(mem_ctx_->table_data_desc_.external_data_block_size_, + fragment.max_data_block_size_, + mem_ctx_->table_data_desc_.compressor_type_))) { + LOG_WARN("fail to init external reader", KR(ret)); + } else if (OB_FAIL(external_reader.open(fragment.file_handle_, 0, fragment.file_size_))) { + LOG_WARN("fail to open file", KR(ret)); + } + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + if (external_row == nullptr) { + if (OB_FAIL(external_reader.get_next_item(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next item", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } + } + if (OB_SUCC(ret) && chunk == nullptr) { + //等待内存空出 + while (mem_ctx_->fly_mem_chunk_count_ >= mem_ctx_->table_data_desc_.max_mem_chunk_count_ && + !(mem_ctx_->has_error_)) { + usleep(500000); + } + if (mem_ctx_->has_error_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("some error ocurr", KR(ret)); + } + if (OB_SUCC(ret)) { + chunk = OB_NEW(ChunkType, "TLD_row_chunk"); + if (chunk == nullptr) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate mem", KR(ret)); + } else { + ATOMIC_AAF(&(mem_ctx_->fly_mem_chunk_count_), 1); + if (OB_FAIL(chunk->init(MTL_ID(), mem_ctx_->table_data_desc_.mem_chunk_size_))) { + LOG_WARN("fail to init external sort", KR(ret)); + } + } + } + } + + if (OB_SUCC(ret)) { + row = *external_row; + ret = chunk->add_item(row); + if (ret == OB_BUF_NOT_ENOUGH) { + ret = OB_SUCCESS; + if (OB_FAIL(close_chunk(chunk))) { + LOG_WARN("fail to close chunk", KR(ret)); + } + } else if (ret != OB_SUCCESS) { + LOG_WARN("fail to add item", KR(ret)); + } else { + external_row = nullptr; + } + } + } + } + + if (OB_SUCC(ret)) { + if (chunk != nullptr) { + if (OB_FAIL(close_chunk(chunk))) { + LOG_WARN("fail to close chunk", KR(ret)); + } + } + } + + return ret; +} + +int ObDirectLoadMemLoader::close_chunk(ChunkType *&chunk) +{ + int ret = OB_SUCCESS; + CompareType compare; + if (OB_FAIL(compare.init(*(mem_ctx_->datum_utils_)))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(chunk->sort(compare))) { + LOG_WARN("fail to sort chunk", KR(ret)); + } else if (OB_FAIL(mem_ctx_->mem_chunk_queue_.push(chunk))) { + LOG_WARN("fail to push", KR(ret)); + } else { + chunk = nullptr; + } + + if (chunk != nullptr) { + chunk->~ChunkType(); + ob_free(chunk); + chunk = nullptr; + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_loader.h b/src/storage/direct_load/ob_direct_load_mem_loader.h new file mode 100644 index 0000000000..461f611059 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_loader.h @@ -0,0 +1,36 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_mem_worker.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMemLoader : public ObDirectLoadMemWorker +{ + typedef ObDirectLoadConstExternalMultiPartitionRow RowType; + typedef ObDirectLoadExternalMultiPartitionRowChunk ChunkType; + typedef ObDirectLoadExternalMultiPartitionRowCompare CompareType; +public: + ObDirectLoadMemLoader(ObDirectLoadMemContext *mem_ctx); + virtual ~ObDirectLoadMemLoader(); + int add_table(ObIDirectLoadPartitionTable *table) override; + int work() override; + VIRTUAL_TO_STRING_KV(KP(mem_ctx_), K_(fragments)); +private: + int close_chunk(ChunkType *&chunk); +private: + ObDirectLoadMemContext *mem_ctx_; + ObDirectLoadExternalFragmentArray fragments_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_sample.cpp b/src/storage/direct_load/ob_direct_load_mem_sample.cpp new file mode 100644 index 0000000000..d646dcb75e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_sample.cpp @@ -0,0 +1,176 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "observer/table_load/ob_table_load_partition_location.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_mem_sample.h" +#include "observer/table_load/ob_table_load_store_ctx.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_task.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_task_scheduler.h" +#include "share/table/ob_table_load_handle.h" +#include "observer/table_load/ob_table_load_mem_compactor.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace table; + +ObDirectLoadMemSample::ObDirectLoadMemSample(ObDirectLoadMemContext *mem_ctx) + : mem_ctx_(mem_ctx), range_count_(mem_ctx_->mem_dump_task_count_) {} + + +int ObDirectLoadMemSample::gen_ranges(ObIArray &chunks, ObIArray &ranges) +{ + int ret = OB_SUCCESS; + ObArray sample_rows; + for (int64_t i = 0; OB_SUCC(ret) && i < DEFAULT_SAMPLE_TIMES; i ++) { + int idx = abs(rand()) % chunks.count(); + ChunkType *chunk = chunks.at(idx); + int idx2 = abs(rand()) % chunk->get_size(); + RowType *row = chunk->get_item(idx2); + if (OB_FAIL(sample_rows.push_back(row))) { + LOG_WARN("fail to push row", KR(ret)); + } + } + if (OB_SUCC(ret)) { + CompareType compare; + if (OB_FAIL(compare.init(*(mem_ctx_->datum_utils_)))) { + LOG_WARN("fail to init compare", KR(ret)); + } else { + std::sort(sample_rows.begin(), sample_rows.end(), compare); + } + } + + int64_t step = DEFAULT_SAMPLE_TIMES / range_count_; + + RowType *last_row = nullptr; + for (int64_t i = 1; OB_SUCC(ret) && i <= range_count_; i ++) { + if (i != range_count_) { + if (OB_FAIL(ranges.push_back(RangeType(last_row, sample_rows[i * step])))) { + LOG_WARN("fail to push range", KR(ret)); + } else { + last_row = sample_rows[i * step]; + } + } else { + if (OB_FAIL(ranges.push_back(RangeType(last_row, nullptr)))) { + LOG_WARN("fail to push range", KR(ret)); + } else { + last_row = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMemSample::do_work() +{ + int ret = OB_SUCCESS; + ObArray chunks; + ObArray ranges; + auto context_ptr = ObTableLoadHandle::make_handle(); + context_ptr->sub_dump_count_ = range_count_; + + mem_ctx_->mem_chunk_queue_.pop_all(chunks); + + if (OB_FAIL(context_ptr->init())) { + LOG_WARN("fail to init context", KR(ret)); + } else if (OB_FAIL(context_ptr->mem_chunk_array_.assign(chunks))) { + LOG_WARN("fail to assgin chunks", KR(ret)); + + //出错以后释放chunks + context_ptr->mem_chunk_array_.reset(); + for (int64_t i = 0; i < chunks.count(); i ++) { + ChunkType *chunk = chunks.at(i); + if (chunk != nullptr) { + chunk->~ChunkType(); + ob_free(chunk); + } + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(gen_ranges(chunks, ranges))) { + LOG_WARN("fail to gen ranges", KR(ret)); + } else { + ATOMIC_AAF(&(mem_ctx_->running_dump_count_), range_count_); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < range_count_; i ++) { + if (OB_FAIL(add_dump(i, chunks, ranges[i], context_ptr))) { + LOG_WARN("fail to start dump", KR(ret)); + } + } + + return ret; +} + +int ObDirectLoadMemSample::add_dump(int64_t idx, + common::ObArray &mem_chunk_array, + const RangeType &range, + ObTableLoadHandle context_ptr) +{ + int ret = OB_SUCCESS; + storage::ObDirectLoadMemDump *mem_dump = OB_NEW(ObDirectLoadMemDump, "TLD_mem_dump", mem_ctx_, range, context_ptr, idx); + if (mem_dump == nullptr) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate mem dump", KR(ret)); + } else if (OB_FAIL(mem_ctx_->mem_dump_queue_.push(mem_dump))) { + LOG_WARN("fail to push mem dump", KR(ret)); + } + return ret; +} + +int ObDirectLoadMemSample::do_sample() +{ + int ret = OB_SUCCESS; + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + if (mem_ctx_->finish_compact_count_ >= mem_ctx_->mem_load_task_count_ - mem_ctx_->mem_dump_task_count_) { + if (mem_ctx_->mem_chunk_queue_.size() > 0) { + if (OB_FAIL(do_work())) { + LOG_WARN("fail to do work", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(mem_ctx_->mem_dump_queue_.push(nullptr))) { + LOG_WARN("fail to push queue", KR(ret)); + } + } + if (OB_SUCC(ret)) { + while (mem_ctx_->running_dump_count_ > 0 && !(mem_ctx_->has_error_)) { //等待所有的merge做完 + usleep(100000); + } + } + break; + } + int64_t mem_chunk_dump_count = mem_ctx_->table_data_desc_.max_mem_chunk_count_ / 2; + if (mem_chunk_dump_count <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", K(mem_ctx_->table_data_desc_.max_mem_chunk_count_)); + } + if (OB_SUCC(ret)) { + if (mem_ctx_->mem_chunk_queue_.size() < mem_chunk_dump_count) { + usleep(100000); + continue; + } + if (OB_FAIL(do_work())) { + LOG_WARN("fail to do work", KR(ret)); + } + } + } + if (ret != OB_SUCCESS || mem_ctx_->has_error_) { + mem_ctx_->mem_dump_queue_.push(nullptr); //出错了,让dump结束,避免卡死 + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_sample.h b/src/storage/direct_load/ob_direct_load_mem_sample.h new file mode 100644 index 0000000000..33a3561fb0 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_sample.h @@ -0,0 +1,50 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_sstable_builder.h" +#include "share/table/ob_table_load_define.h" +#include "storage/direct_load/ob_direct_load_compare.h" +#include +#include "storage/direct_load/ob_direct_load_mem_dump.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMemSample +{ + static const constexpr int64_t DEFAULT_SAMPLE_TIMES = 50000; + typedef ObDirectLoadConstExternalMultiPartitionRow RowType; + typedef ObDirectLoadExternalMultiPartitionRowChunk ChunkType; + typedef ObDirectLoadExternalMultiPartitionRowRange RangeType; + typedef ObDirectLoadExternalMultiPartitionRowCompare CompareType; +public: + ObDirectLoadMemSample(ObDirectLoadMemContext *mem_ctx); + virtual ~ObDirectLoadMemSample() {} + + int do_sample(); + +private: + int do_work(); + int add_dump(int64_t idx, + common::ObArray &mem_chunk_array, + const RangeType &range, + table::ObTableLoadHandle sample_ptr); + int gen_ranges(common::ObIArray &chunks, + common::ObIArray &ranges); + +private: + // data members + ObDirectLoadMemContext *mem_ctx_; + int64_t range_count_; +}; + + + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_mem_worker.h b/src/storage/direct_load/ob_direct_load_mem_worker.h new file mode 100644 index 0000000000..49082e37d8 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_mem_worker.h @@ -0,0 +1,28 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObIDirectLoadPartitionTable; + +class ObDirectLoadMemWorker +{ +public: + virtual ~ObDirectLoadMemWorker() {} + + virtual int add_table(ObIDirectLoadPartitionTable *table) = 0; + virtual int work() = 0; + + DECLARE_PURE_VIRTUAL_TO_STRING; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_memory_writer.h b/src/storage/direct_load/ob_direct_load_memory_writer.h new file mode 100644 index 0000000000..50e8db1a4a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_memory_writer.h @@ -0,0 +1,178 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "lib/container/ob_vector.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadMemoryWriter +{ + static const int64_t MIN_MEMORY_LIMIT = 8 * 1024LL * 1024LL; // min memory limit is 8M +public: + ObDirectLoadMemoryWriter(); + ~ObDirectLoadMemoryWriter(); + void reuse(); + void reset(); + int init(uint64_t tenant_id, int64_t mem_limit, Compare *compare, + FramgentBuilder *fragment_builder); + int add_item(const T &item); + int close(); + TO_STRING_KV(K(is_inited_), K(buf_mem_limit_), KP(compare_), KP(fragment_builder_)); +private: + int build_fragment(); +private: + int64_t buf_mem_limit_; + Compare *compare_; + FramgentBuilder *fragment_builder_; + common::ObArenaAllocator allocator_; + common::ObVector item_list_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMemoryWriter); +}; + +template +ObDirectLoadMemoryWriter::ObDirectLoadMemoryWriter() + : buf_mem_limit_(0), + compare_(nullptr), + fragment_builder_(nullptr), + allocator_("TLD_MemWriter"), + is_inited_(false) +{ +} + +template +ObDirectLoadMemoryWriter::~ObDirectLoadMemoryWriter() +{ + reset(); +} + +template +void ObDirectLoadMemoryWriter::reuse() +{ + for (int64_t i = 0; i < item_list_.size(); ++i) { + item_list_[i]->~T(); + } + item_list_.reset(); + allocator_.reset(); +} + +template +void ObDirectLoadMemoryWriter::reset() +{ + buf_mem_limit_ = 0; + compare_ = nullptr; + fragment_builder_ = nullptr; + for (int64_t i = 0; i < item_list_.size(); ++i) { + item_list_[i]->~T(); + } + item_list_.reset(); + allocator_.reset(); + is_inited_ = false; +} + +template +int ObDirectLoadMemoryWriter::init(uint64_t tenant_id, + int64_t mem_limit, Compare *compare, + FramgentBuilder *fragment_builder) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadMemoryWriter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(common::OB_INVALID_ID == tenant_id || mem_limit < MIN_MEMORY_LIMIT || + nullptr == compare || nullptr == fragment_builder)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(mem_limit), KP(compare), KP(fragment_builder)); + } else { + buf_mem_limit_ = mem_limit; + compare_ = compare; + fragment_builder_ = fragment_builder; + allocator_.set_tenant_id(tenant_id); + is_inited_ = true; + } + return ret; +} + +template +int ObDirectLoadMemoryWriter::add_item(const T &item) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadMemoryWriter not init", KR(ret), KP(this)); + } else { + const int64_t item_size = sizeof(T) + item.get_deep_copy_size(); + if (item_size > buf_mem_limit_) { + ret = common::OB_SIZE_OVERFLOW; + STORAGE_LOG(WARN, "invalid item size, must not larger than buf memory limit", KR(ret), + K(item_size), K(buf_mem_limit_)); + } else if (allocator_.used() + item_size > buf_mem_limit_ && OB_FAIL(build_fragment())) { + STORAGE_LOG(WARN, "fail to build fragment", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(memory_add_item_time_us); + char *buf = nullptr; + T *new_item = nullptr; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(item_size)))) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + STORAGE_LOG(WARN, "fail to allocate memory", KR(ret), K(item_size)); + } else { + new_item = new (buf) T(); + int64_t buf_pos = sizeof(T); + if (OB_FAIL(new_item->deep_copy(item, buf, item_size, buf_pos))) { + STORAGE_LOG(WARN, "fail to deep copy item", KR(ret)); + } else if (OB_FAIL(item_list_.push_back(new_item))) { + STORAGE_LOG(WARN, "fail to push back new item", KR(ret)); + } + } + } + } + return ret; +} + +template +int ObDirectLoadMemoryWriter::build_fragment() +{ + int ret = common::OB_SUCCESS; + if (item_list_.size() > 1) { + OB_TABLE_LOAD_STATISTICS_TIME_COST(memory_sort_item_time_us); + std::sort(item_list_.begin(), item_list_.end(), *compare_); + if (OB_FAIL(compare_->get_error_code())) { + ret = compare_->get_error_code(); + STORAGE_LOG(WARN, "fail to sort memory item list", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(fragment_builder_->build_fragment(item_list_))) { + STORAGE_LOG(WARN, "fail to build fragment", KR(ret)); + } else { + reuse(); + } + } + return ret; +} + +template +int ObDirectLoadMemoryWriter::close() +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadMemoryWriter not init", KR(ret), KP(this)); + } else if (item_list_.size() > 0 && OB_FAIL(build_fragment())) { + STORAGE_LOG(WARN, "fail to build fragment", KR(ret)); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_merge_ctx.cpp b/src/storage/direct_load/ob_direct_load_merge_ctx.cpp new file mode 100644 index 0000000000..234327c1a5 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_merge_ctx.cpp @@ -0,0 +1,725 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_merge_ctx.h" +#include "share/ob_tablet_autoincrement_service.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_partition_merge_task.h" +#include "storage/direct_load/ob_direct_load_range_splitter.h" +#include "observer/table_load/ob_table_load_schema.h" +#include "share/stat/ob_opt_table_stat.h" +#include "share/stat/ob_opt_stat_monitor_manager.h" +#include "share/stat/ob_opt_stat_manager.h" +#include "share/stat/ob_opt_column_stat.h" +#include "share/stat/ob_stat_item.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace blocksstable; +using namespace common; +using namespace share; +using namespace table; +using namespace sql; +using namespace observer; + +/** + * ObDirectLoadMergeParam + */ + +ObDirectLoadMergeParam::ObDirectLoadMergeParam() + : table_id_(OB_INVALID_ID), + target_table_id_(OB_INVALID_ID), + rowkey_column_num_(0), + schema_column_count_(0), + datum_utils_(nullptr), + col_descs_(nullptr), + is_heap_table_(false), + is_fast_heap_table_(false), + online_opt_stat_gather_(false), + insert_table_ctx_(nullptr), + error_row_handler_(nullptr), + result_info_(nullptr) +{ +} + +ObDirectLoadMergeParam::~ObDirectLoadMergeParam() +{ +} + +bool ObDirectLoadMergeParam::is_valid() const +{ + return OB_INVALID_ID != table_id_ && 0 < rowkey_column_num_ && 0 < schema_column_count_ && + table_data_desc_.is_valid() && nullptr != datum_utils_ && nullptr != col_descs_ && + nullptr != insert_table_ctx_ && nullptr != error_row_handler_; +} + +/** + * ObDirectLoadMergeCtx + */ + +ObDirectLoadMergeCtx::ObDirectLoadMergeCtx() + : allocator_("TLD_MergeCtx"), is_inited_(false) +{ +} + +ObDirectLoadMergeCtx::~ObDirectLoadMergeCtx() +{ + for (int64_t i = 0; i < tablet_merge_ctx_array_.count(); ++i) { + ObDirectLoadTabletMergeCtx *tablet_ctx = tablet_merge_ctx_array_.at(i); + tablet_ctx->~ObDirectLoadTabletMergeCtx(); + allocator_.free(tablet_ctx); + } + tablet_merge_ctx_array_.reset(); +} + +int ObDirectLoadMergeCtx::init(const ObDirectLoadMergeParam ¶m, + const ObIArray &ls_partition_ids, + const ObIArray &target_ls_partition_ids) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMerger init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() + || ls_partition_ids.empty() + || target_ls_partition_ids.empty() + || (ls_partition_ids.count() != target_ls_partition_ids.count()))) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(ls_partition_ids), K(target_ls_partition_ids)); + } else { + allocator_.set_tenant_id(MTL_ID()); + param_ = param; + if (OB_FAIL(create_all_tablet_ctxs(ls_partition_ids, target_ls_partition_ids))) { + LOG_WARN("fail to create all tablet ctxs", KR(ret)); + } else { + std::sort(tablet_merge_ctx_array_.begin(), tablet_merge_ctx_array_.end(), + [](const ObDirectLoadTabletMergeCtx *lhs, const ObDirectLoadTabletMergeCtx *rhs) { + return lhs->get_tablet_id().compare(rhs->get_tablet_id()) < 0; + }); + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMergeCtx::create_all_tablet_ctxs( + const ObIArray &ls_partition_ids, + const ObIArray &target_ls_partition_ids) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < ls_partition_ids.count(); ++i) { + const ObTableLoadLSIdAndPartitionId &ls_partition_id = ls_partition_ids.at(i); + const ObTableLoadLSIdAndPartitionId &target_ls_partition_id = target_ls_partition_ids.at(i); + ObDirectLoadTabletMergeCtx *partition_ctx = nullptr; + if (OB_ISNULL(partition_ctx = OB_NEWx(ObDirectLoadTabletMergeCtx, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadTabletMergeCtx", KR(ret)); + } else if (OB_FAIL(partition_ctx->init(param_, ls_partition_id, target_ls_partition_id))) { + LOG_WARN("fail to init tablet ctx", KR(ret), K(param_), K(ls_partition_id), K(target_ls_partition_id)); + } else if (OB_FAIL(tablet_merge_ctx_array_.push_back(partition_ctx))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != partition_ctx) { + partition_ctx->~ObDirectLoadTabletMergeCtx(); + allocator_.free(partition_ctx); + partition_ctx = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadTabletMergeCtx + */ + +ObDirectLoadTabletMergeCtx::ObDirectLoadTabletMergeCtx() + : allocator_("TLD_MegTbtCtx"), task_finish_count_(0), is_inited_(false) +{ +} + +ObDirectLoadTabletMergeCtx::~ObDirectLoadTabletMergeCtx() +{ + for (int64_t i = 0; i < task_array_.count(); ++i) { + ObDirectLoadPartitionMergeTask *task = task_array_.at(i); + task->~ObDirectLoadPartitionMergeTask(); + allocator_.free(task); + } + task_array_.reset(); +} + +int ObDirectLoadTabletMergeCtx::init(const ObDirectLoadMergeParam ¶m, + const ObTableLoadLSIdAndPartitionId &ls_partition_id, + const ObTableLoadLSIdAndPartitionId &target_ls_partition_id) + +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadTabletMergeCtx init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() + || !ls_partition_id.is_valid() + || !target_ls_partition_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(ls_partition_id)); + } else { + ObDirectLoadOriginTableCreateParam origin_table_param; + origin_table_param.table_id_ = param.table_id_; + origin_table_param.tablet_id_ = ls_partition_id.part_tablet_id_.tablet_id_; + origin_table_param.ls_id_ = ls_partition_id.ls_id_; + if (OB_FAIL(origin_table_.init(origin_table_param))) { + LOG_WARN("fail to init origin sstable", KR(ret)); + } else { + allocator_.set_tenant_id(MTL_ID()); + param_ = param; + target_partition_id_ = target_ls_partition_id.part_tablet_id_.partition_id_; + tablet_id_ = ls_partition_id.part_tablet_id_.tablet_id_; + target_tablet_id_ = target_ls_partition_id.part_tablet_id_.tablet_id_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::collect_sql_statistics( + const ObIArray &fast_heap_table_array, ObTableLoadSqlStatistics &sql_statistics) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTabletMergeCtx not init", KR(ret), KP(this)); + } else if (OB_FAIL(ObTableLoadSchema::get_table_schema(tenant_id, param_.target_table_id_, schema_guard, + table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(param_)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected error", K(ret)); + } else { + int64_t table_row_cnt = 0; + int64_t table_avg_len = 0; + int64_t col_cnt = + param_.is_fast_heap_table_ ? param_.schema_column_count_ - 1 : param_.schema_column_count_; + ObOptTableStat *table_stat = nullptr; + ObOptDmlStat dml_stat; + StatLevel stat_level; + if (table_schema->get_part_level() == PARTITION_LEVEL_ZERO) { + stat_level = TABLE_LEVEL; + } else if (table_schema->get_part_level() == PARTITION_LEVEL_ONE) { + stat_level = PARTITION_LEVEL; + } else if (table_schema->get_part_level() == PARTITION_LEVEL_TWO) { + stat_level = SUBPARTITION_LEVEL; + } else { + stat_level = INVALID_LEVEL; + } + if (OB_FAIL(sql_statistics.allocate_table_stat(table_stat))) { + LOG_WARN("fail to allocate table stat", KR(ret)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < col_cnt; ++i) { + int64_t col_id = param_.is_fast_heap_table_ ? i + 1 : i; + int64_t row_count = 0; + int64_t avg_len = 0; + ObOptColumnStat *col_stat = nullptr; + if (OB_FAIL(sql_statistics.allocate_col_stat(col_stat))) { + LOG_WARN("fail to allocate table stat", KR(ret)); + } + // scan task_array + for (int64_t j = 0; OB_SUCC(ret) && j < task_array_.count(); ++j) { + ObOptColumnStat *tmp_col_stat = task_array_.at(j)->get_column_stat_array().at(i); + if (tmp_col_stat != nullptr) { + ObOptColumnStat *copied_col_stat = nullptr; + int64_t size = tmp_col_stat->size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(sql_statistics.allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(tmp_col_stat->deep_copy(new_buf, size, copied_col_stat))) { + LOG_WARN("fail to copy colstat", KR(ret)); + } else if (OB_FAIL(col_stat->merge_column_stat(*copied_col_stat))) { + LOG_WARN("fail to merge column stat", KR(ret)); + } else { + row_count += task_array_.at(j)->get_row_count(); + avg_len += col_stat->get_avg_len(); + } + } + } + // scan fast heap table + for (int64_t j = 0; OB_SUCC(ret) && j < fast_heap_table_array.count(); ++j) { + ObOptColumnStat *tmp_col_stat = fast_heap_table_array.at(j)->get_column_stat_array().at(i); + if (tmp_col_stat != nullptr) { + ObOptColumnStat *copied_col_stat = nullptr; + int64_t size = tmp_col_stat->size(); + char *new_buf = nullptr; + if (OB_ISNULL(new_buf = static_cast(sql_statistics.allocator_.alloc(size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(size)); + } else if (OB_FAIL(tmp_col_stat->deep_copy(new_buf, size, copied_col_stat))) { + LOG_WARN("fail to copy colstat", KR(ret)); + } else if (OB_FAIL(col_stat->merge_column_stat(*copied_col_stat))) { + LOG_WARN("fail to merge column stat", KR(ret)); + } else { + row_count += fast_heap_table_array.at(j)->get_row_count(); + avg_len += col_stat->get_avg_len(); + } + } + } + if (OB_SUCC(ret)) { + table_row_cnt = row_count; + table_avg_len += avg_len; + col_stat->set_table_id(param_.target_table_id_); + col_stat->set_partition_id(target_partition_id_); + col_stat->set_stat_level(stat_level); + col_stat->set_column_id(param_.col_descs_->at(col_id).col_id_); + col_stat->set_num_distinct(ObGlobalNdvEval::get_ndv_from_llc(col_stat->get_llc_bitmap())); + } + } + if (OB_SUCC(ret)) { + table_stat->set_table_id(param_.target_table_id_); + table_stat->set_partition_id(target_partition_id_); + table_stat->set_object_type(stat_level); + table_stat->set_row_count(table_row_cnt); + table_stat->set_avg_row_size(table_avg_len); + dml_stat.tenant_id_ = tenant_id; + dml_stat.table_id_ = param_.target_table_id_; + dml_stat.tablet_id_ = get_target_tablet_id().id(); + dml_stat.insert_row_count_ = table_row_cnt; + if (OB_FAIL(ObOptStatMonitorManager::get_instance().update_local_cache(tenant_id, dml_stat))) { + LOG_WARN("failed to update dml stat local cache", K(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_merge_task( + const ObIArray &table_array, + const ObIArray &col_descs, + int64_t max_parallel_degree, + bool is_multiple_mode) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTabletMergeCtx not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(max_parallel_degree <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(max_parallel_degree)); + } else { + if (table_array.empty()) { + if (OB_FAIL(build_empty_data_merge_task(col_descs, max_parallel_degree))) { + LOG_WARN("fail to build empty data merge task", KR(ret)); + } + } else if (!param_.is_heap_table_) { + if (!is_multiple_mode) { + if (OB_FAIL(build_pk_table_merge_task(table_array, col_descs, max_parallel_degree))) { + LOG_WARN("fail to build pk table merge task", KR(ret)); + } + } else { + if (OB_FAIL( + build_pk_table_multiple_merge_task(table_array, col_descs, max_parallel_degree))) { + LOG_WARN("fail to build pk table multiple merge task", KR(ret)); + } + } + } else { + if (!is_multiple_mode) { + if (OB_FAIL(build_heap_table_merge_task(table_array, col_descs, max_parallel_degree))) { + LOG_WARN("fail to build heap table merge task", KR(ret)); + } + } else { + if (OB_FAIL( + build_heap_table_multiple_merge_task(table_array, col_descs, max_parallel_degree))) { + LOG_WARN("fail to build heap table multiple merge task", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_empty_data_merge_task(const ObIArray &col_descs, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + // only existing data, construct task by split range + if (OB_SUCC(ret)) { + ObDirectLoadMergeRangeSplitter range_splitter; + if (OB_FAIL( + range_splitter.init(&origin_table_, sstable_array_, param_.datum_utils_, col_descs))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(range_array_, max_parallel_degree, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = OB_NEWx(ObDirectLoadPartitionRangeMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, sstable_array_, range, i))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_pk_table_merge_task( + const ObIArray &table_array, + const ObIArray &col_descs, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + // split range + for (int64_t i = 0; OB_SUCC(ret) && i < table_array.count(); ++i) { + ObDirectLoadSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table_array.at(i)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), K(table_array)); + } else if (OB_FAIL(sstable_array_.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObDirectLoadMergeRangeSplitter range_splitter; + if (OB_FAIL( + range_splitter.init(&origin_table_, sstable_array_, param_.datum_utils_, col_descs))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(range_array_, max_parallel_degree, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + } + // construct task per range + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = OB_NEWx(ObDirectLoadPartitionRangeMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, sstable_array_, range, i))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_pk_table_multiple_merge_task( + const ObIArray &table_array, + const ObIArray &col_descs, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + // split range + for (int64_t i = 0; OB_SUCC(ret) && i < table_array.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = dynamic_cast(table_array.at(i)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), K(table_array)); + } else if (OB_FAIL(multiple_sstable_array_.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleMergeTabletRangeSplitter range_splitter; + if (OB_FAIL(range_splitter.init(tablet_id_, &origin_table_, multiple_sstable_array_, + param_.table_data_desc_, param_.datum_utils_, col_descs))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(range_array_, max_parallel_degree, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + } + // construct task per range + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMultipleMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = + OB_NEWx(ObDirectLoadPartitionRangeMultipleMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMultipleMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, multiple_sstable_array_, + range, i))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMultipleMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_merge_task_for_multiple_pk_table( + const ObIArray &multiple_sstable_array, + ObDirectLoadMultipleMergeRangeSplitter &range_splitter, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTabletMergeCtx not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(max_parallel_degree <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(max_parallel_degree)); + } else { + if (OB_FAIL(multiple_sstable_array_.assign(multiple_sstable_array))) { + LOG_WARN("fail to assign multiple sstable array", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(tablet_id_, &origin_table_, max_parallel_degree, + range_array_, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + // construct task per range + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMultipleMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = + OB_NEWx(ObDirectLoadPartitionRangeMultipleMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMultipleMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, multiple_sstable_array_, + range, i))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMultipleMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_heap_table_merge_task( + const ObIArray &table_array, + const ObIArray &col_descs, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + int64_t parallel_idx = 0; + // for existing data, construct task by split range + if (OB_SUCC(ret)) { + ObDirectLoadMergeRangeSplitter range_splitter; + if (OB_FAIL( + range_splitter.init(&origin_table_, sstable_array_, param_.datum_utils_, col_descs))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(range_array_, max_parallel_degree, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = OB_NEWx(ObDirectLoadPartitionRangeMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, sstable_array_, range, + parallel_idx++))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + // for imported data, construct task per external table + for (int64_t i = 0; OB_SUCC(ret) && !param_.is_fast_heap_table_ && i < table_array.count(); ++i) { + ObDirectLoadExternalTable *external_table = nullptr; + ObDirectLoadPartitionHeapTableMergeTask *merge_task = nullptr; + ObTabletCacheInterval pk_interval; + if (OB_ISNULL(external_table = dynamic_cast(table_array.at(i)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), K(table_array)); + } else if (OB_FAIL(get_autoincrement_value(external_table->get_row_count(), pk_interval))) { + LOG_WARN("fail to get autoincrement value", KR(ret), K(external_table->get_row_count())); + } else if (OB_ISNULL(merge_task = + OB_NEWx(ObDirectLoadPartitionHeapTableMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionHeapTableMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, external_table, pk_interval, + parallel_idx++))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionHeapTableMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::build_heap_table_multiple_merge_task( + const ObIArray &table_array, + const ObIArray &col_descs, + int64_t max_parallel_degree) +{ + int ret = OB_SUCCESS; + int64_t parallel_idx = 0; + // for existing data, construct task by split range + if (OB_SUCC(ret)) { + ObDirectLoadMergeRangeSplitter range_splitter; + if (OB_FAIL( + range_splitter.init(&origin_table_, sstable_array_, param_.datum_utils_, col_descs))) { + LOG_WARN("fail to init range splitter", KR(ret)); + } else if (OB_FAIL(range_splitter.split_range(range_array_, max_parallel_degree, allocator_))) { + LOG_WARN("fail to split range", KR(ret)); + } else if (OB_UNLIKELY(range_array_.count() > max_parallel_degree)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected range count", KR(ret), K(max_parallel_degree), K(range_array_.count())); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < range_array_.count(); ++i) { + const ObDatumRange &range = range_array_.at(i); + ObDirectLoadPartitionRangeMergeTask *merge_task = nullptr; + if (OB_ISNULL(merge_task = OB_NEWx(ObDirectLoadPartitionRangeMergeTask, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionRangeMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, &origin_table_, sstable_array_, range, + parallel_idx++))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionRangeMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + // for imported data, construct task by multiple heap table + for (int64_t i = 0; OB_SUCC(ret) && !param_.is_fast_heap_table_ && i < table_array.count(); ++i) { + ObDirectLoadMultipleHeapTable *heap_table = nullptr; + ObDirectLoadPartitionHeapTableMultipleMergeTask *merge_task = nullptr; + int64_t row_count = 0; + ObTabletCacheInterval pk_interval; + if (OB_ISNULL(heap_table = dynamic_cast(table_array.at(i)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), K(i), K(table_array)); + } else if (OB_FAIL(heap_table->get_tablet_row_count(tablet_id_, param_.table_data_desc_, + row_count))) { + LOG_WARN("fail to get tablet row count", KR(ret), K(tablet_id_)); + } else if (0 == row_count) { + // ignore + } else if (OB_FAIL(get_autoincrement_value(row_count, pk_interval))) { + LOG_WARN("fail to get autoincrement value", KR(ret), K(row_count)); + } else if (OB_ISNULL(merge_task = OB_NEWx(ObDirectLoadPartitionHeapTableMultipleMergeTask, + (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadPartitionHeapTableMultipleMergeTask", KR(ret)); + } else if (OB_FAIL(merge_task->init(param_, this, heap_table, pk_interval, parallel_idx++))) { + LOG_WARN("fail to init merge task", KR(ret)); + } else if (OB_FAIL(task_array_.push_back(merge_task))) { + LOG_WARN("fail to push back merge task", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != merge_task) { + merge_task->~ObDirectLoadPartitionHeapTableMultipleMergeTask(); + allocator_.free(merge_task); + merge_task = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::get_autoincrement_value(uint64_t count, + ObTabletCacheInterval &interval) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(count)); + } else { + const uint64_t tenant_id = MTL_ID(); + ObTabletAutoincrementService &auto_inc = ObTabletAutoincrementService::get_instance(); + interval.tablet_id_ = tablet_id_; + interval.cache_size_ = count; + if (OB_FAIL(auto_inc.get_tablet_cache_interval(tenant_id, interval))) { + LOG_WARN("fail to get tablet cache interval", K(ret), K(tenant_id), K_(tablet_id)); + } else if (OB_UNLIKELY(count > interval.count())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected autoincrement value count", K(ret), K(count), K(interval)); + } + } + return ret; +} + +int ObDirectLoadTabletMergeCtx::inc_finish_count(bool &is_ready) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTabletMergeCtx not init", KR(ret), KP(this)); + } else { + const int64_t finish_count = ATOMIC_AAF(&task_finish_count_, 1); + is_ready = (finish_count >= task_array_.count()); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_merge_ctx.h b/src/storage/direct_load/ob_direct_load_merge_ctx.h new file mode 100644 index 0000000000..2a3d046e72 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_merge_ctx.h @@ -0,0 +1,147 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/ob_allocator.h" +#include "share/ob_tablet_autoincrement_param.h" +#include "share/schema/ob_table_param.h" +#include "share/stat/ob_stat_define.h" +#include "share/stat/ob_opt_column_stat.h" +#include "share/stat/ob_opt_table_stat.h" +#include "share/table/ob_table_load_define.h" +#include "storage/direct_load/ob_direct_load_origin_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table.h" + +namespace oceanbase +{ +namespace observer +{ +class ObTableLoadErrorRowHandler; +class ObTableLoadSchema; +} // namespace observer +namespace common { +class ObOptColumnStat; +class ObOptTableStat; +} // namespace common +namespace storage +{ +class ObDirectLoadInsertTableContext; +class ObDirectLoadPartitionMergeTask; +class ObDirectLoadTabletMergeCtx; +class ObIDirectLoadPartitionTable; +class ObDirectLoadSSTable; +class ObDirectLoadMultipleSSTable; +class ObDirectLoadMultipleMergeRangeSplitter; + +struct ObDirectLoadMergeParam +{ +public: + ObDirectLoadMergeParam(); + ~ObDirectLoadMergeParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_id), K_(target_table_id), K_(rowkey_column_num), K_(schema_column_count), + K_(table_data_desc), KP_(datum_utils), K_(is_heap_table), K_(is_fast_heap_table), + K_(online_opt_stat_gather), KP_(insert_table_ctx), KP_(error_row_handler), + KP_(result_info)); +public: + uint64_t table_id_; + uint64_t target_table_id_; + int64_t rowkey_column_num_; + int64_t schema_column_count_; + storage::ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + const common::ObIArray *col_descs_; + bool is_heap_table_; + bool is_fast_heap_table_; + bool online_opt_stat_gather_; + ObDirectLoadInsertTableContext *insert_table_ctx_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + table::ObTableLoadResultInfo *result_info_; +}; + +class ObDirectLoadMergeCtx +{ +public: + ObDirectLoadMergeCtx(); + ~ObDirectLoadMergeCtx(); + int init(const ObDirectLoadMergeParam ¶m, + const common::ObIArray &ls_partition_ids, + const common::ObIArray &target_ls_partition_ids); + const common::ObIArray &get_tablet_merge_ctxs() const + { + return tablet_merge_ctx_array_; + } +private: + int create_all_tablet_ctxs(const common::ObIArray &ls_partition_ids, + const common::ObIArray &target_ls_partition_ids); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMergeParam param_; + common::ObSEArray tablet_merge_ctx_array_; + bool is_inited_; +}; + +class ObDirectLoadTabletMergeCtx +{ +public: + ObDirectLoadTabletMergeCtx(); + ~ObDirectLoadTabletMergeCtx(); + int init(const ObDirectLoadMergeParam ¶m, const table::ObTableLoadLSIdAndPartitionId &ls_partition_id, + const table::ObTableLoadLSIdAndPartitionId &target_ls_partition_id); + int build_merge_task(const common::ObIArray &table_array, + const common::ObIArray &col_descs, + int64_t max_parallel_degree, bool is_multiple_mode); + int build_merge_task_for_multiple_pk_table( + const common::ObIArray &multiple_sstable_array, + ObDirectLoadMultipleMergeRangeSplitter &range_splitter, + int64_t max_parallel_degree); + int inc_finish_count(bool &is_ready); + int collect_sql_statistics( + const common::ObIArray &fast_heap_table_array, table::ObTableLoadSqlStatistics &sql_statistics); + const ObDirectLoadMergeParam &get_param() const { return param_; } + const common::ObTabletID &get_tablet_id() const { return tablet_id_; } + const common::ObTabletID &get_target_tablet_id() const { return target_tablet_id_; } + const common::ObIArray &get_tasks() const + { + return task_array_; + } + TO_STRING_KV(K_(param), K_(target_partition_id), K_(tablet_id), K_(target_tablet_id)); +private: + int build_empty_data_merge_task(const common::ObIArray &col_descs, + int64_t max_parallel_degree); + int build_pk_table_merge_task(const common::ObIArray &table_array, + const common::ObIArray &col_descs, + int64_t max_parallel_degree); + int build_pk_table_multiple_merge_task( + const common::ObIArray &table_array, + const common::ObIArray &col_descs, + int64_t max_parallel_degree); + int build_heap_table_merge_task( + const common::ObIArray &table_array, + const common::ObIArray &col_descs, + int64_t max_parallel_degree); + int build_heap_table_multiple_merge_task( + const common::ObIArray &table_array, + const common::ObIArray &col_descs, + int64_t max_parallel_degree); + int get_autoincrement_value(uint64_t count, share::ObTabletCacheInterval &interval); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMergeParam param_; + uint64_t target_partition_id_; + common::ObTabletID tablet_id_; + common::ObTabletID target_tablet_id_; + ObDirectLoadOriginTable origin_table_; + common::ObSEArray sstable_array_; + common::ObSEArray multiple_sstable_array_; + common::ObSEArray range_array_; + common::ObSEArray task_array_; + int64_t task_finish_count_ CACHE_ALIGNED; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_merge_task_iterator.cpp b/src/storage/direct_load/ob_direct_load_merge_task_iterator.cpp new file mode 100644 index 0000000000..93f53db3ef --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_merge_task_iterator.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_merge_task_iterator.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadMergeTaskIterator::ObDirectLoadMergeTaskIterator() + : merge_ctx_(nullptr), + tablet_merge_ctx_(nullptr), + tablet_pos_(0), + task_pos_(0), + is_inited_(false) +{ +} + +ObDirectLoadMergeTaskIterator::~ObDirectLoadMergeTaskIterator() +{ +} + +int ObDirectLoadMergeTaskIterator::init(ObDirectLoadMergeCtx *merge_ctx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMergeTaskIterator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == merge_ctx)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(merge_ctx)); + } else { + merge_ctx_ = merge_ctx; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMergeTaskIterator::get_next_task(ObDirectLoadPartitionMergeTask *&task) +{ + int ret = OB_SUCCESS; + task = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMergeTaskIterator not init", KR(ret), KP(this)); + } else { + while (OB_SUCC(ret) && nullptr == task) { + if (nullptr == tablet_merge_ctx_) { + // get next partition merge ctx + const ObIArray &tablet_merge_ctxs = + merge_ctx_->get_tablet_merge_ctxs(); + if (tablet_pos_ >= tablet_merge_ctxs.count()) { + ret = OB_ITER_END; + } else { + tablet_merge_ctx_ = tablet_merge_ctxs.at(tablet_pos_++); + task_pos_ = 0; + } + } + if (OB_SUCC(ret)) { + const ObIArray &tasks = tablet_merge_ctx_->get_tasks(); + if (task_pos_ >= tasks.count()) { + // try next partition + tablet_merge_ctx_ = nullptr; + } else { + task = tasks.at(task_pos_++); + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_merge_task_iterator.h b/src/storage/direct_load/ob_direct_load_merge_task_iterator.h new file mode 100644 index 0000000000..88306e399d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_merge_task_iterator.h @@ -0,0 +1,30 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_merge_ctx.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMergeTaskIterator +{ +public: + ObDirectLoadMergeTaskIterator(); + ~ObDirectLoadMergeTaskIterator(); + int init(storage::ObDirectLoadMergeCtx *merge_ctx); + int get_next_task(storage::ObDirectLoadPartitionMergeTask *&task); +private: + storage::ObDirectLoadMergeCtx *merge_ctx_; + storage::ObDirectLoadTabletMergeCtx *tablet_merge_ctx_; + int64_t tablet_pos_; + int64_t task_pos_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multi_map.h b/src/storage/direct_load/ob_direct_load_multi_map.h new file mode 100644 index 0000000000..03be87543e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multi_map.h @@ -0,0 +1,170 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#ifndef OB_DIRECT_LOAD_MULTI_MAP_H_ +#define OB_DIRECT_LOAD_MULTI_MAP_H_ + +#include "lib/hash/ob_concurrent_hash_map.h" +#include "lib/lock/ob_mutex.h" +#include "lib/container/ob_array.h" +#include "share/ob_errno.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadMultiMapNoLock +{ + typedef common::hash::ObHashMap *, common::hash::NoPthreadDefendMode> MapType; + typedef common::hash::HashMapPair *> MapTypePair; +public: + ObDirectLoadMultiMapNoLock() + { + } + + int init() + { + return map_.create(1024, "TLD_multi_map", "TLD_multi_map"); + } + + virtual ~ObDirectLoadMultiMapNoLock() + { + destroy(); + } + + int add(const Key &key, const Value &value) + { + int ret = common::OB_SUCCESS; + common::ObArray *bag = nullptr; + ret = map_.get_refactored(key, bag); + if (ret == common::OB_HASH_NOT_EXIST) { + ret = OB_SUCCESS; + bag = OB_NEW(common::ObArray, "TLD_MM_bag"); + if (OB_FAIL(map_.set_refactored(key, bag))) { + STORAGE_LOG(WARN, "fail to put bag", KR(ret)); + } + } else if (ret != OB_SUCCESS) { + STORAGE_LOG(WARN, "fail to get bag", KR(ret)); + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(bag->push_back(value))) { + STORAGE_LOG(WARN, "fail to push back value", KR(ret)); + } + } + return ret; + } + + int get_all_key(common::ObIArray &keys) + { + int ret = OB_SUCCESS; + auto fn = [&keys] (MapTypePair &p) { + int ret = OB_SUCCESS; + if (OB_FAIL(keys.push_back(p.first))) { + STORAGE_LOG(WARN, "fail to push key", KR(ret)); + } + return ret; + }; + if (OB_FAIL(map_.foreach_refactored(fn))) { + STORAGE_LOG(WARN, "fail to traverse map", KR(ret)); + } + return ret; + } + + int get(const Key &key, common::ObIArray &out_bag) + { + int ret = OB_SUCCESS; + common::ObArray *bag = nullptr; + if (OB_FAIL(map_.get_refactored(key, bag))) { + if (ret == common::OB_HASH_NOT_EXIST) { + bag = nullptr; + ret = common::OB_SUCCESS; + } else { + STORAGE_LOG(WARN, "fail to get bag", KR(ret)); + } + } + if (bag != nullptr) { + for (int64_t i = 0; OB_SUCC(ret) && i < bag->count(); i ++) { + if (OB_FAIL(out_bag.push_back(bag->at(i)))) { + STORAGE_LOG(WARN, "fail to push item", KR(ret)); + } + } + } + return ret; + } + +private: + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultiMapNoLock); + void destroy() + { + auto fn = [] (MapTypePair &p) { + int ret = OB_SUCCESS; + if (p.second != nullptr) { + p.second->~ObArray(); + ob_free(p.second); + } + return ret; + }; + map_.foreach_refactored(fn); + } + +private: + // data members + MapType map_; +}; + +template +class ObDirectLoadMultiMap +{ +public: + ObDirectLoadMultiMap() + { + } + + int init() + { + return multi_map_.init(); + } + + virtual ~ObDirectLoadMultiMap() + { + } + + int add(const Key &key, const Value &value) + { + lib::ObMutexGuard guard(mutex_); + return multi_map_.add(key, value); + } + + int get_all_key(common::ObIArray &keys) + { + lib::ObMutexGuard guard(mutex_); + return multi_map_.get_all_key(keys); + } + + int get(const Key &key, common::ObIArray &out_bag) + { + lib::ObMutexGuard guard(mutex_); + return multi_map_.get(key, out_bag); + } + +private: + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultiMap); + +private: + // data members + ObDirectLoadMultiMapNoLock multi_map_; + lib::ObMutex mutex_; +}; + + + + + +} +} + +#endif /* OB_DIRECT_LOAD_MULTI_MAP_H_ */ diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_range.cpp b/src/storage/direct_load/ob_direct_load_multiple_datum_range.cpp new file mode 100644 index 0000000000..b4f568e097 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_range.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "share/schema/ob_table_param.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleDatumRange::ObDirectLoadMultipleDatumRange() +{ +} + +ObDirectLoadMultipleDatumRange::~ObDirectLoadMultipleDatumRange() +{ +} + +void ObDirectLoadMultipleDatumRange::reset() +{ + start_key_.reset(); + end_key_.reset(); + border_flag_.set_data(0); +} + +int ObDirectLoadMultipleDatumRange::deep_copy(const ObDirectLoadMultipleDatumRange &src, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!src.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src)); + } else { + reset(); + if (OB_FAIL(start_key_.deep_copy(src.start_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(end_key_.deep_copy(src.end_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else { + border_flag_ = src.border_flag_; + } + } + + return ret; +} + +ObDirectLoadMultipleDatumRange &ObDirectLoadMultipleDatumRange::operator=( + const ObDirectLoadMultipleDatumRange &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(other.is_valid())) { + reset(); + start_key_ = other.start_key_; + end_key_ = other.end_key_; + border_flag_ = other.border_flag_; + } + return *this; +} + +int ObDirectLoadMultipleDatumRange::assign(const ObDirectLoadMultipleDatumRange &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + start_key_ = other.start_key_; + end_key_ = other.end_key_; + border_flag_ = other.border_flag_; + } + return ret; +} + +int ObDirectLoadMultipleDatumRange::assign(const ObTabletID &tablet_id, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tablet_id.is_valid() || !range.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), K(range)); + } else { + reset(); + if (OB_FAIL( + start_key_.assign(tablet_id, range.start_key_.datums_, range.start_key_.datum_cnt_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else if (OB_FAIL( + end_key_.assign(tablet_id, range.end_key_.datums_, range.end_key_.datum_cnt_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else { + border_flag_ = range.border_flag_; + } + } + return ret; +} + +void ObDirectLoadMultipleDatumRange::set_whole_range() +{ + start_key_.set_min_rowkey(); + end_key_.set_max_rowkey(); + border_flag_.set_all_open(); +} + +int ObDirectLoadMultipleDatumRange::set_tablet_whole_range(const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + reset(); + if (OB_FAIL(start_key_.set_tablet_min_rowkey(tablet_id))) { + LOG_WARN("fail to set tablet min rowkey", KR(ret)); + } else if (OB_FAIL(end_key_.set_tablet_max_rowkey(tablet_id))) { + LOG_WARN("fail to set tablet max rowkey", KR(ret)); + } else { + border_flag_.set_all_open(); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_range.h b/src/storage/direct_load/ob_direct_load_multiple_datum_range.h new file mode 100644 index 0000000000..cd3a1f7614 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_range.h @@ -0,0 +1,46 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleDatumRange +{ +public: + ObDirectLoadMultipleDatumRange(); + ObDirectLoadMultipleDatumRange(const ObDirectLoadMultipleDatumRange &other) = delete; + ~ObDirectLoadMultipleDatumRange(); + void reset(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadMultipleDatumRange &src, common::ObIAllocator &allocator); + ObDirectLoadMultipleDatumRange &operator=(const ObDirectLoadMultipleDatumRange &other); + int assign(const ObDirectLoadMultipleDatumRange &other); + int assign(const common::ObTabletID &tablet_id, const blocksstable::ObDatumRange &range); + OB_INLINE bool is_valid() const { return start_key_.is_valid() && end_key_.is_valid(); } + void set_whole_range(); + int set_tablet_whole_range(const common::ObTabletID &tablet_id); + OB_INLINE bool is_left_open() const { return !border_flag_.inclusive_start(); } + OB_INLINE bool is_left_closed() const { return border_flag_.inclusive_start(); } + OB_INLINE bool is_right_open() const { return !border_flag_.inclusive_end(); } + OB_INLINE bool is_right_closed() const { return border_flag_.inclusive_end(); } + OB_INLINE void set_left_open() { border_flag_.unset_inclusive_start(); } + OB_INLINE void set_left_closed() { border_flag_.set_inclusive_start(); } + OB_INLINE void set_right_open() { border_flag_.unset_inclusive_end(); } + OB_INLINE void set_right_closed() { border_flag_.set_inclusive_end(); } + TO_STRING_KV(K_(start_key), K_(end_key), K_(border_flag)); +public: + ObDirectLoadMultipleDatumRowkey start_key_; + ObDirectLoadMultipleDatumRowkey end_key_; + common::ObBorderFlag border_flag_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_row.cpp b/src/storage/direct_load/ob_direct_load_multiple_datum_row.cpp new file mode 100644 index 0000000000..3e44b3c33a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_row.cpp @@ -0,0 +1,181 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleDatumRow::ObDirectLoadMultipleDatumRow() + : allocator_("TLD_MultiRow"), buf_size_(0), buf_(nullptr) +{ + allocator_.set_tenant_id(MTL_ID()); +} + +ObDirectLoadMultipleDatumRow::~ObDirectLoadMultipleDatumRow() +{ +} + +void ObDirectLoadMultipleDatumRow::reset() +{ + rowkey_.reset(); + buf_size_ = 0; + buf_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadMultipleDatumRow::reuse() +{ + rowkey_.reuse(); + buf_size_ = 0; + buf_ = nullptr; + allocator_.reuse(); +} + +int64_t ObDirectLoadMultipleDatumRow::get_deep_copy_size() const +{ + int64_t size = 0; + if (OB_LIKELY(is_valid())) { + size += rowkey_.get_deep_copy_size(); + size += buf_size_; + } + return size; +} + +int ObDirectLoadMultipleDatumRow::deep_copy(const ObDirectLoadMultipleDatumRow &src, char *buf, + const int64_t len, int64_t &pos) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deep_copy_time_us); + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reuse(); + if (OB_FAIL(rowkey_.deep_copy(src.rowkey_, buf, len, pos))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else { + buf_size_ = src.buf_size_; + buf_ = buf + pos; + MEMCPY(buf + pos, src.buf_, buf_size_); + pos += buf_size_; + } + } + return ret; +} + +int ObDirectLoadMultipleDatumRow::from_datums(const ObTabletID &tablet_id, ObStorageDatum *datums, + int64_t column_count, int64_t rowkey_column_count) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_external_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tablet_id.is_valid() || nullptr == datums || + column_count < rowkey_column_count)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), KP(datums), K(column_count), + K(rowkey_column_count)); + } else { + reuse(); + ObDirectLoadDatumArray serialize_datum_array; + if (OB_FAIL(rowkey_.assign(tablet_id, datums, rowkey_column_count))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } else if (OB_FAIL(serialize_datum_array.assign(datums + rowkey_column_count, + column_count - rowkey_column_count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else { + const int64_t buf_size = serialize_datum_array.get_serialize_size(); + char *buf = nullptr; + int64_t pos = 0; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret), K(buf_size)); + } else if (OB_FAIL(serialize_datum_array.serialize(buf, buf_size, pos))) { + LOG_WARN("fail to serialize datum array", KR(ret)); + } else { + buf_ = buf; + buf_size_ = buf_size; + } + } + } + return ret; +} + +int ObDirectLoadMultipleDatumRow::to_datums(ObStorageDatum *datums, int64_t column_count) const +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_datum_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid row", KR(ret), KPC(this)); + } else if (OB_UNLIKELY(nullptr == datums || column_count < rowkey_.datum_array_.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count), K(rowkey_.datum_array_.count_)); + } else { + // from rowkey datum array + for (int64_t i = 0; i < rowkey_.datum_array_.count_; ++i) { + datums[i] = rowkey_.datum_array_.datums_[i]; + } + // from deserialize datum array + ObDirectLoadDatumArray deserialize_datum_array; + int64_t pos = 0; + if (OB_FAIL(deserialize_datum_array.assign(datums + rowkey_.datum_array_.count_, + column_count - rowkey_.datum_array_.count_))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else if (OB_FAIL(deserialize_datum_array.deserialize(buf_, buf_size_, pos))) { + LOG_WARN("fail to deserialize datum array", KR(ret)); + } else if (OB_UNLIKELY(rowkey_.datum_array_.count_ + deserialize_datum_array.count_ != + column_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected column count", KR(ret), K(rowkey_.datum_array_.count_), + K(deserialize_datum_array.count_), K(column_count)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadMultipleDatumRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, rowkey_, buf_size_); + if (OB_SUCC(ret) && OB_NOT_NULL(buf_)) { + MEMCPY(buf + pos, buf_, buf_size_); + pos += buf_size_; + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadMultipleDatumRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deserialize_time_us); + int ret = OB_SUCCESS; + reuse(); + LST_DO_CODE(OB_UNIS_DECODE, rowkey_, buf_size_); + if (OB_SUCC(ret)) { + buf_ = buf + pos; + pos += buf_size_; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadMultipleDatumRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, rowkey_, buf_size_); + len += buf_size_; + return len; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_row.h b/src/storage/direct_load/ob_direct_load_multiple_datum_row.h new file mode 100644 index 0000000000..ae2069c7d7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_row.h @@ -0,0 +1,40 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleDatumRow +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadMultipleDatumRow(); + ~ObDirectLoadMultipleDatumRow(); + void reset(); + void reuse(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadMultipleDatumRow &src, char *buf, const int64_t len, + int64_t &pos); + // not deep copy + int from_datums(const common::ObTabletID &tablet_id, blocksstable::ObStorageDatum *datums, + int64_t column_count, int64_t rowkey_column_count); + int to_datums(blocksstable::ObStorageDatum *datums, int64_t column_count) const; + OB_INLINE bool is_valid() const { return rowkey_.is_valid() && buf_size_ > 0 && nullptr != buf_; } + OB_INLINE int64_t get_raw_size() const { return buf_size_; } + TO_STRING_KV(K_(rowkey), K_(buf_size), KP_(buf)); +public: + common::ObArenaAllocator allocator_; + ObDirectLoadMultipleDatumRowkey rowkey_; + int64_t buf_size_; + const char *buf_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.cpp b/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.cpp new file mode 100644 index 0000000000..3e542d5468 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" +#include "observer/table_load/ob_table_load_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleDatumRowkey::ObDirectLoadMultipleDatumRowkey() +{ +} + +ObDirectLoadMultipleDatumRowkey::~ObDirectLoadMultipleDatumRowkey() +{ +} + +void ObDirectLoadMultipleDatumRowkey::reset() +{ + tablet_id_.reset(); + datum_array_.reset(); +} + +void ObDirectLoadMultipleDatumRowkey::reuse() +{ + tablet_id_.reset(); + datum_array_.reuse(); +} + +int64_t ObDirectLoadMultipleDatumRowkey::get_deep_copy_size() const +{ + int64_t size = 0; + size += datum_array_.get_deep_copy_size(); + return size; +} + +int ObDirectLoadMultipleDatumRowkey::deep_copy(const ObDirectLoadMultipleDatumRowkey &src, + char *buf, const int64_t len, int64_t &pos) +{ + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reuse(); + tablet_id_ = src.tablet_id_; + if (OB_FAIL(datum_array_.deep_copy(src.datum_array_, buf, len, pos))) { + LOG_WARN("fail to deep copy datum array", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleDatumRowkey::deep_copy(const ObDirectLoadMultipleDatumRowkey &src, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!src.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src)); + } else { + const int64_t deep_copy_size = src.get_deep_copy_size(); + char *buf = nullptr; + int64_t pos = 0; + if (deep_copy_size > 0 && + OB_ISNULL(buf = static_cast(allocator.alloc(deep_copy_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret), K(deep_copy_size)); + } else if (OB_FAIL(deep_copy(src, buf, deep_copy_size, pos))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } + + return ret; +} + +int ObDirectLoadMultipleDatumRowkey::assign(const ObTabletID &tablet_id, ObStorageDatum *datums, + int64_t count) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tablet_id.is_valid() || nullptr == datums || count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), KP(datums), K(count)); + } else { + reset(); + tablet_id_ = tablet_id; + if (OB_FAIL(datum_array_.assign(datums, count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } + } + return ret; +} + +bool ObDirectLoadMultipleDatumRowkey::is_valid() const { + return is_min_rowkey() || is_max_rowkey() || (datum_array_.is_valid() && datum_array_.count_ > 0); +} + +int ObDirectLoadMultipleDatumRowkey::get_rowkey(ObDatumRowkey &rowkey) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid() || 0 == datum_array_.count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid rowkey", KR(ret), KPC(this)); + } else if (OB_FAIL(rowkey.assign(datum_array_.datums_, datum_array_.count_))) { + LOG_WARN("fail to assign rowkey", KR(ret)); + } + return ret; +} + +int ObDirectLoadMultipleDatumRowkey::compare(const ObDirectLoadMultipleDatumRowkey &rhs, + const blocksstable::ObStorageDatumUtils &datum_utils, + int &cmp_ret) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid() || !rhs.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(*this), K(rhs)); + } else { + cmp_ret = tablet_id_.compare(rhs.tablet_id_); + if (0 == cmp_ret && (!is_min_rowkey() && !is_max_rowkey())) { + ObDatumRowkey lhs_rowkey; + ObDatumRowkey rhs_rowkey; + if (OB_FAIL(get_rowkey(lhs_rowkey))) { + LOG_WARN("fail to assign rowkey", KR(ret), KPC(this)); + } else if (OB_FAIL(rhs.get_rowkey(rhs_rowkey))) { + LOG_WARN("fail to assign rowkey", KR(ret), K(rhs)); + } else if (OB_FAIL(lhs_rowkey.compare(rhs_rowkey, datum_utils, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadMultipleDatumRowkey::set_tablet_min_rowkey(const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id)); + } else { + reset(); + const ObDatumRowkey &min_rowkey = ObDatumRowkey::MIN_ROWKEY; + if (OB_FAIL(datum_array_.assign(min_rowkey.datums_, min_rowkey.datum_cnt_))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else { + tablet_id_ = tablet_id; + } + } + return ret; +} + +int ObDirectLoadMultipleDatumRowkey::set_tablet_max_rowkey(const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id)); + } else { + reset(); + const ObDatumRowkey &max_rowkey = ObDatumRowkey::MAX_ROWKEY; + if (OB_FAIL(datum_array_.assign(max_rowkey.datums_, max_rowkey.datum_cnt_))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else { + tablet_id_ = tablet_id; + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadMultipleDatumRowkey) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, tablet_id_.id(), datum_array_); + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadMultipleDatumRowkey) +{ + int ret = OB_SUCCESS; + reuse(); + uint64_t id = 0; + LST_DO_CODE(OB_UNIS_DECODE, id, datum_array_); + if (OB_SUCC(ret)) { + tablet_id_ = id; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadMultipleDatumRowkey) +{ + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, tablet_id_.id(), datum_array_); + return len; +} + +/** + * ObDirectLoadMultipleDatumRowkeyCompare + */ + +ObDirectLoadMultipleDatumRowkeyCompare::ObDirectLoadMultipleDatumRowkeyCompare() + : datum_utils_(nullptr), result_code_(OB_SUCCESS) +{ +} + +int ObDirectLoadMultipleDatumRowkeyCompare::init(const ObStorageDatumUtils &datum_utils) +{ + int ret = OB_SUCCESS; + datum_utils_ = &datum_utils; + return ret; +} + +bool ObDirectLoadMultipleDatumRowkeyCompare::operator()(const ObDirectLoadMultipleDatumRowkey *lhs, + const ObDirectLoadMultipleDatumRowkey *rhs) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_ISNULL(datum_utils_) || OB_ISNULL(lhs) || OB_ISNULL(rhs) || + OB_UNLIKELY(!lhs->is_valid() || !rhs->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datum_utils_), KP(lhs), KP(rhs)); + } else { + if (OB_FAIL(lhs->compare(*rhs, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret), KP(lhs), K(rhs), K(datum_utils_)); + } + } + if (OB_FAIL(ret)) { + result_code_ = ret; + } + return cmp_ret < 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.h b/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.h new file mode 100644 index 0000000000..d9af034bd4 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_datum_rowkey.h @@ -0,0 +1,60 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_datum.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleDatumRowkey +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadMultipleDatumRowkey(); + ObDirectLoadMultipleDatumRowkey(const ObDirectLoadMultipleDatumRowkey &other) = delete; + ~ObDirectLoadMultipleDatumRowkey(); + void reset(); + void reuse(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadMultipleDatumRowkey &src, char *buf, const int64_t len, + int64_t &pos); + int deep_copy(const ObDirectLoadMultipleDatumRowkey &src, common::ObIAllocator &allocator); + int assign(const common::ObTabletID &tablet_id, blocksstable::ObStorageDatum *datums, + int64_t count); + int get_rowkey(blocksstable::ObDatumRowkey &rowkey) const; + int compare(const ObDirectLoadMultipleDatumRowkey &rhs, + const blocksstable::ObStorageDatumUtils &datum_utils, int &cmp_ret) const; + void set_min_rowkey() { tablet_id_ = 0; datum_array_.reset(); } + void set_max_rowkey() { tablet_id_ = UINT64_MAX; datum_array_.reset(); } + OB_INLINE bool is_min_rowkey() const { return tablet_id_.id() == 0; } + OB_INLINE bool is_max_rowkey() const { return tablet_id_.id() == UINT64_MAX; } + int set_tablet_min_rowkey(const common::ObTabletID &tablet_id); + int set_tablet_max_rowkey(const common::ObTabletID &tablet_id); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(datum_array)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadDatumArray datum_array_; +}; + +class ObDirectLoadMultipleDatumRowkeyCompare +{ +public: + ObDirectLoadMultipleDatumRowkeyCompare(); + int init(const blocksstable::ObStorageDatumUtils &datum_utils); + bool operator()(const ObDirectLoadMultipleDatumRowkey *lhs, + const ObDirectLoadMultipleDatumRowkey *rhs); + int get_error_code() const { return result_code_; } +public: + const blocksstable::ObStorageDatumUtils *datum_utils_; + int result_code_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_external_row.cpp b/src/storage/direct_load/ob_direct_load_multiple_external_row.cpp new file mode 100644 index 0000000000..dc127a0338 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_external_row.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_external_row.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "share/rc/ob_tenant_base.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleExternalRow::ObDirectLoadMultipleExternalRow() + : allocator_("TLD_ME_Row"), buf_size_(0), buf_(nullptr) +{ + allocator_.set_tenant_id(MTL_ID()); +} + +void ObDirectLoadMultipleExternalRow::reset() +{ + buf_size_ = 0; + buf_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadMultipleExternalRow::reuse() +{ + buf_size_ = 0; + buf_ = nullptr; + allocator_.reuse(); +} + +int64_t ObDirectLoadMultipleExternalRow::get_deep_copy_size() const +{ + int64_t size = 0; + size += buf_size_; + return size; +} + +int ObDirectLoadMultipleExternalRow::deep_copy(const ObDirectLoadMultipleExternalRow &src, + char *buf, const int64_t len, int64_t &pos) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deep_copy_time_us); + int ret = OB_SUCCESS; + const int64_t deep_copy_size = src.get_deep_copy_size(); + if (OB_UNLIKELY(!src.is_valid() || len - pos < deep_copy_size)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(src), K(len), K(deep_copy_size)); + } else { + reuse(); + buf_size_ = src.buf_size_; + buf_ = buf + pos; + MEMCPY(buf + pos, src.buf_, buf_size_); + pos += buf_size_; + } + return ret; +} + +int ObDirectLoadMultipleExternalRow::from_datums(ObStorageDatum *datums, int64_t column_count) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_external_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == datums || column_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count)); + } else { + reuse(); + ObDirectLoadDatumArray serialize_datum_array; + if (OB_FAIL(serialize_datum_array.assign(datums, column_count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else { + const int64_t buf_size = serialize_datum_array.get_serialize_size(); + char *buf = nullptr; + int64_t pos = 0; + if (OB_ISNULL(buf = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret), K(buf_size)); + } else if (OB_FAIL(serialize_datum_array.serialize(buf, buf_size, pos))) { + LOG_WARN("fail to serialize datum array", KR(ret)); + } else { + buf_ = buf; + buf_size_ = buf_size; + } + } + } + return ret; +} + +int ObDirectLoadMultipleExternalRow::to_datums(ObStorageDatum *datums, int64_t column_count) const +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(transfer_datum_row_time_us); + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected invalid row", KR(ret), KPC(this)); + } else if (OB_UNLIKELY(nullptr == datums || column_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datums), K(column_count)); + } else { + int64_t pos = 0; + ObDirectLoadDatumArray deserialize_datum_array; + if (OB_FAIL(deserialize_datum_array.assign(datums, column_count))) { + LOG_WARN("fail to assign datum array", KR(ret)); + } else if (OB_FAIL(deserialize_datum_array.deserialize(buf_, buf_size_, pos))) { + LOG_WARN("fail to deserialize datum array", KR(ret)); + } else if (OB_UNLIKELY(deserialize_datum_array.count_ != column_count)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected column count", KR(ret), K(deserialize_datum_array.count_), + K(column_count)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadMultipleExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, tablet_id_.id(), buf_size_); + if (OB_SUCC(ret) && OB_NOT_NULL(buf_)) { + MEMCPY(buf + pos, buf_, buf_size_); + pos += buf_size_; + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadMultipleExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_deserialize_time_us); + int ret = OB_SUCCESS; + reset(); + uint64_t id = 0; + LST_DO_CODE(OB_UNIS_DECODE, id, buf_size_); + if (OB_SUCC(ret)) { + tablet_id_ = id; + buf_ = buf + pos; + pos += buf_size_; + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadMultipleExternalRow) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(external_row_serialize_time_us); + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, tablet_id_.id(), buf_size_); + len += buf_size_; + return len; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_external_row.h b/src/storage/direct_load/ob_direct_load_multiple_external_row.h new file mode 100644 index 0000000000..8b314ad4de --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_external_row.h @@ -0,0 +1,41 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/allocator/page_arena.h" +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_datum.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleExternalRow +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadMultipleExternalRow(); + void reset(); + void reuse(); + int64_t get_deep_copy_size() const; + int deep_copy(const ObDirectLoadMultipleExternalRow &src, char *buf, const int64_t len, + int64_t &pos); + int from_datums(blocksstable::ObStorageDatum *datums, int64_t column_count); + int to_datums(blocksstable::ObStorageDatum *datums, int64_t column_count) const; + OB_INLINE bool is_valid() const + { + return tablet_id_.is_valid() && buf_size_ > 0 && nullptr != buf_; + } + TO_STRING_KV(K_(tablet_id), K_(buf_size), KP_(buf)); +public: + common::ObArenaAllocator allocator_; + common::ObTabletID tablet_id_; + int64_t buf_size_; + const char *buf_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table.cpp new file mode 100644 index 0000000000..4605ad0510 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table.cpp @@ -0,0 +1,233 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleHeapTableDataFragment + */ + +ObDirectLoadMultipleHeapTableDataFragment::ObDirectLoadMultipleHeapTableDataFragment() + : block_count_(0), file_size_(0), row_count_(0), max_block_size_(0) +{ +} + +ObDirectLoadMultipleHeapTableDataFragment::~ObDirectLoadMultipleHeapTableDataFragment() +{ +} + +int ObDirectLoadMultipleHeapTableDataFragment::assign( + const ObDirectLoadMultipleHeapTableDataFragment &other) +{ + int ret = OB_SUCCESS; + block_count_ = other.block_count_; + file_size_ = other.file_size_; + row_count_ = other.row_count_; + max_block_size_ = other.max_block_size_; + if (OB_FAIL(file_handle_.assign(other.file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMultipleHeapTableCreateParam + */ + +ObDirectLoadMultipleHeapTableCreateParam::ObDirectLoadMultipleHeapTableCreateParam() + : column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_block_count_(0), + data_block_count_(0), + index_file_size_(0), + data_file_size_(0), + index_entry_count_(0), + row_count_(0), + max_data_block_size_(0) +{ +} + +ObDirectLoadMultipleHeapTableCreateParam::~ObDirectLoadMultipleHeapTableCreateParam() +{ +} + +bool ObDirectLoadMultipleHeapTableCreateParam::is_valid() const +{ + return column_count_ > 0 && index_block_size_ > 0 && index_block_size_ % DIO_ALIGN_SIZE == 0 && + data_block_size_ > 0 && data_block_size_ % DIO_ALIGN_SIZE == 0 && index_block_count_ > 0 && + data_block_count_ > 0 && index_file_size_ > 0 && data_file_size_ > 0 && + index_entry_count_ > 0 && row_count_ > 0 && max_data_block_size_ > 0 && + max_data_block_size_ % DIO_ALIGN_SIZE == 0 && index_file_handle_.is_valid() && + !data_fragments_.empty(); +} + +/** + * ObDirectLoadMultipleHeapTableMeta + */ + +ObDirectLoadMultipleHeapTableMeta::ObDirectLoadMultipleHeapTableMeta() + : column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_block_count_(0), + data_block_count_(0), + index_file_size_(0), + data_file_size_(0), + index_entry_count_(0), + row_count_(0), + max_data_block_size_(0) +{ +} + +ObDirectLoadMultipleHeapTableMeta::~ObDirectLoadMultipleHeapTableMeta() +{ +} + +void ObDirectLoadMultipleHeapTableMeta::reset() +{ + column_count_ = 0; + index_block_size_ = 0; + data_block_size_ = 0; + index_block_count_ = 0; + data_block_count_ = 0; + index_file_size_ = 0; + data_file_size_ = 0; + index_entry_count_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; +} + +/** + * ObDirectLoadMultipleSSTable + */ + +ObDirectLoadMultipleHeapTable::ObDirectLoadMultipleHeapTable() + : is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTable::~ObDirectLoadMultipleHeapTable() +{ +} + +void ObDirectLoadMultipleHeapTable::reset() +{ + meta_.reset(); + index_file_handle_.reset(); + data_fragments_.reset(); + is_inited_ = false; +} + +int ObDirectLoadMultipleHeapTable::init(const ObDirectLoadMultipleHeapTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTable init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + meta_.column_count_ = param.column_count_; + meta_.index_block_size_ = param.index_block_size_; + meta_.data_block_size_ = param.data_block_size_; + meta_.index_block_count_ = param.index_block_count_; + meta_.data_block_count_ = param.data_block_count_; + meta_.index_file_size_ = param.index_file_size_; + meta_.data_file_size_ = param.data_file_size_; + meta_.index_entry_count_ = param.index_entry_count_; + meta_.row_count_ = param.row_count_; + meta_.max_data_block_size_ = param.max_data_block_size_; + if (OB_FAIL(index_file_handle_.assign(param.index_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(data_fragments_.assign(param.data_fragments_))) { + LOG_WARN("fail to assign data fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTable::copy(const ObDirectLoadMultipleHeapTable &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + meta_ = other.meta_; + if (OB_FAIL(index_file_handle_.assign(other.index_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(data_fragments_.assign(other.data_fragments_))) { + LOG_WARN("fail to assign data fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +ObDirectLoadMultipleHeapTable::IndexEntryIterator ObDirectLoadMultipleHeapTable::index_entry_begin() +{ + IndexEntryIterator iter; + iter.table_ = this; + iter.index_entry_idx_ = 0; + return iter; +} + +ObDirectLoadMultipleHeapTable::IndexEntryIterator ObDirectLoadMultipleHeapTable::index_entry_end() +{ + IndexEntryIterator iter; + iter.table_ = this; + iter.index_entry_idx_ = meta_.index_entry_count_; + return iter; +} + +int ObDirectLoadMultipleHeapTable::get_tablet_row_count( + const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + int64_t &row_count) +{ + int ret = OB_SUCCESS; + row_count = 0; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTable not init", KR(ret), KP(this)); + } else { + const ObDirectLoadMultipleHeapTableTabletIndex *tablet_index = nullptr; + ObDirectLoadMultipleHeapTableTabletIndexWholeScanner index_scanner; + if (OB_FAIL(index_scanner.init(this, tablet_id, table_data_desc))) { + LOG_WARN("fail to init index scanner", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(index_scanner.get_next_index(tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else { + row_count += tablet_index->row_count_; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table.h new file mode 100644 index 0000000000..e0495b5381 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table.h @@ -0,0 +1,113 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_iterator.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObDirectLoadMultipleHeapTableTabletIndex; + +struct ObDirectLoadMultipleHeapTableDataFragment +{ +public: + ObDirectLoadMultipleHeapTableDataFragment(); + ~ObDirectLoadMultipleHeapTableDataFragment(); + int assign(const ObDirectLoadMultipleHeapTableDataFragment &other); + TO_STRING_KV(K_(block_count), K_(file_size), K_(row_count), K_(max_block_size), K_(file_handle)); +public: + int64_t block_count_; + int64_t file_size_; + int64_t row_count_; + int64_t max_block_size_; + ObDirectLoadTmpFileHandle file_handle_; +}; + +struct ObDirectLoadMultipleHeapTableCreateParam +{ +public: + ObDirectLoadMultipleHeapTableCreateParam(); + ~ObDirectLoadMultipleHeapTableCreateParam(); + bool is_valid() const; + TO_STRING_KV(K_(column_count), K_(index_block_size), K_(data_block_size), K_(index_block_count), + K_(data_block_count), K_(index_file_size), K_(data_file_size), K_(index_entry_count), + K_(row_count), K_(max_data_block_size), K_(index_file_handle), K_(data_fragments)); +public: + int64_t column_count_; + int64_t index_block_size_; + int64_t data_block_size_; + int64_t index_block_count_; + int64_t data_block_count_; + int64_t index_file_size_; + int64_t data_file_size_; + int64_t index_entry_count_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadTmpFileHandle index_file_handle_; + common::ObArray data_fragments_; +}; + +struct ObDirectLoadMultipleHeapTableMeta +{ +public: + ObDirectLoadMultipleHeapTableMeta(); + ~ObDirectLoadMultipleHeapTableMeta(); + void reset(); + TO_STRING_KV(K_(column_count), K_(index_block_size), K_(data_block_size), K_(index_block_count), + K_(data_block_count), K_(index_file_size), K_(data_file_size), K_(index_entry_count), + K_(row_count), K_(max_data_block_size)); +public: + int64_t column_count_; + int64_t index_block_size_; + int64_t data_block_size_; + int64_t index_block_count_; + int64_t data_block_count_; + int64_t index_file_size_; + int64_t data_file_size_; + int64_t index_entry_count_; + int64_t row_count_; + int64_t max_data_block_size_; +}; + +class ObDirectLoadMultipleHeapTable : public ObIDirectLoadPartitionTable +{ +public: + typedef ObDirectLoadMultipleHeapTableIndexEntryIterator + IndexEntryIterator; + ObDirectLoadMultipleHeapTable(); + virtual ~ObDirectLoadMultipleHeapTable(); + void reset(); + int init(const ObDirectLoadMultipleHeapTableCreateParam ¶m); + const common::ObTabletID &get_tablet_id() const override { return tablet_id_; } + int64_t get_row_count() const override { return meta_.row_count_; } + bool is_valid() const override { return is_inited_; } + int copy(const ObDirectLoadMultipleHeapTable &other); + const ObDirectLoadMultipleHeapTableMeta &get_meta() const { return meta_; } + const ObDirectLoadTmpFileHandle &get_index_file_handle() const { return index_file_handle_; } + const common::ObIArray &get_data_fragments() const + { + return data_fragments_; + } + IndexEntryIterator index_entry_begin(); + IndexEntryIterator index_entry_end(); + int get_tablet_row_count(const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + int64_t &row_count); + TO_STRING_KV(K_(meta), K_(index_file_handle), K_(data_fragments)); +private: + common::ObTabletID tablet_id_; // invalid + ObDirectLoadMultipleHeapTableMeta meta_; + ObDirectLoadTmpFileHandle index_file_handle_; + common::ObArray data_fragments_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.cpp new file mode 100644 index 0000000000..1ebf6c772d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.cpp @@ -0,0 +1,245 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_builder.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/* + * ObDirectLoadMultipleHeapTableBuildParam + */ + +ObDirectLoadMultipleHeapTableBuildParam::ObDirectLoadMultipleHeapTableBuildParam() + : file_mgr_(nullptr), extra_buf_(nullptr), extra_buf_size_(0), index_dir_id_(-1), data_dir_id_(-1) +{ +} + +ObDirectLoadMultipleHeapTableBuildParam::~ObDirectLoadMultipleHeapTableBuildParam() +{ +} + +bool ObDirectLoadMultipleHeapTableBuildParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != file_mgr_ && nullptr != extra_buf_ && + extra_buf_size_ > 0 && extra_buf_size_ % DIO_ALIGN_SIZE == 0 && index_dir_id_ > 0 && + data_dir_id_ > 0; +} + +/** + * ObDirectLoadMultipleHeapTableBuilder + */ + +ObDirectLoadMultipleHeapTableBuilder::ObDirectLoadMultipleHeapTableBuilder() + : index_entry_count_(0), row_count_(0), is_closed_(false), is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableBuilder::~ObDirectLoadMultipleHeapTableBuilder() +{ +} + +int ObDirectLoadMultipleHeapTableBuilder::init(const ObDirectLoadMultipleHeapTableBuildParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + if (OB_FAIL(param_.file_mgr_->alloc_file(param_.index_dir_id_, index_file_handle_))) { + LOG_WARN("fail to alloc file", KR(ret)); + } else if (OB_FAIL(param_.file_mgr_->alloc_file(param_.data_dir_id_, data_file_handle_))) { + LOG_WARN("fail to alloc file", KR(ret)); + } else if (OB_FAIL(index_block_writer_.init(param_.table_data_desc_.sstable_index_block_size_, + param_.table_data_desc_.compressor_type_))) { + LOG_WARN("fail to init index block writer", KR(ret)); + } else if (OB_FAIL(data_block_writer_.init(param_.table_data_desc_.sstable_data_block_size_, + param_.table_data_desc_.compressor_type_, + param_.extra_buf_, param_.extra_buf_size_, + &callback_))) { + LOG_WARN("fail to init data block writer", KR(ret)); + } else if (OB_FAIL(index_block_writer_.open(index_file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else if (OB_FAIL(data_block_writer_.open(data_file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableBuilder::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple heap table builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!datum_row.is_valid() || + datum_row.get_column_count() != param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(datum_row)); + } else { + row_.tablet_id_ = tablet_id; + if (OB_FAIL(row_.from_datums(datum_row.storage_datums_, datum_row.count_))) { + LOG_WARN("fail to from datum row", KR(ret)); + } else if (OB_FAIL(append_row(row_))) { + LOG_WARN("fail to append row", KR(ret), K(row_)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableBuilder::append_row(const RowType &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple heap table builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!row.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(row)); + } else { + if (row.tablet_id_ != last_tablet_index_.tablet_id_) { + if (last_tablet_index_.tablet_id_.is_valid()) { + // check tablet is in order + int cmp_ret = row.tablet_id_.compare(last_tablet_index_.tablet_id_); + if (cmp_ret < 0) { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_WARN("unexpected tablet id", KR(ret), K(last_tablet_index_.tablet_id_), + K(row.tablet_id_)); + } else { + // save last tablet index + if (OB_FAIL(index_block_writer_.append_index(last_tablet_index_))) { + LOG_WARN("fail to append tablet index", KR(ret)); + } else { + ++index_entry_count_; + } + } + } + if (OB_SUCC(ret)) { + last_tablet_index_.tablet_id_ = row.tablet_id_; + last_tablet_index_.row_count_ = 0; + last_tablet_index_.fragment_idx_ = 0; + last_tablet_index_.offset_ = callback_.get_data_block_offset(); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(data_block_writer_.write_item(row))) { + LOG_WARN("fail to append row", KR(ret)); + } else { + ++last_tablet_index_.row_count_; + ++row_count_; + } + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple heap table builder is closed", KR(ret)); + } else { + if (last_tablet_index_.tablet_id_.is_valid()) { + // save last tablet index + if (OB_FAIL(index_block_writer_.append_index(last_tablet_index_))) { + LOG_WARN("fail to append tablet index", KR(ret)); + } else { + ++index_entry_count_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(data_block_writer_.close())) { + LOG_WARN("fail to close data block writer", KR(ret)); + } else if (OB_FAIL(index_block_writer_.close())) { + LOG_WARN("fail to close index block writer", KR(ret)); + } else { + is_closed_ = true; + } + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableBuilder::get_tables( + ObIArray &table_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple heap table builder is not closed", KR(ret)); + } else { + ObDirectLoadMultipleHeapTableDataFragment data_fragment; + ObDirectLoadMultipleHeapTableCreateParam create_param; + data_fragment.block_count_ = data_block_writer_.get_block_count(); + data_fragment.file_size_ = data_block_writer_.get_file_size(); + data_fragment.row_count_ = row_count_; + data_fragment.max_block_size_ = data_block_writer_.get_max_block_size(); + create_param.column_count_ = param_.table_data_desc_.column_count_; + create_param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + create_param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + create_param.index_block_count_ = index_block_writer_.get_block_count(); + create_param.data_block_count_ = data_block_writer_.get_block_count(); + create_param.index_file_size_ = index_block_writer_.get_file_size(); + create_param.data_file_size_ = data_block_writer_.get_file_size(); + create_param.index_entry_count_ = index_entry_count_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = data_block_writer_.get_max_block_size(); + if (OB_FAIL(data_fragment.file_handle_.assign(data_file_handle_))) { + LOG_WARN("fail to assign data file handle", KR(ret)); + } else if (OB_FAIL(create_param.index_file_handle_.assign(index_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(create_param.data_fragments_.push_back(data_fragment))) { + LOG_WARN("fail to push back data fragment", KR(ret)); + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleHeapTable *heap_table = nullptr; + if (OB_ISNULL(heap_table = OB_NEWx(ObDirectLoadMultipleHeapTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleHeapTable", KR(ret)); + } else if (OB_FAIL(heap_table->init(create_param))) { + LOG_WARN("fail to init heap_table", KR(ret), K(create_param)); + } else if (OB_FAIL(table_array.push_back(heap_table))) { + LOG_WARN("fail to push back heap table", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != heap_table) { + heap_table->~ObDirectLoadMultipleHeapTable(); + allocator.free(heap_table); + heap_table = nullptr; + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.h new file mode 100644 index 0000000000..72b7cc697b --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_builder.h @@ -0,0 +1,86 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_data_block.h" +#include "storage/direct_load/ob_direct_load_data_block_writer.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_external_row.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTmpFileManager; + +struct ObDirectLoadMultipleHeapTableBuildParam +{ +public: + ObDirectLoadMultipleHeapTableBuildParam(); + ~ObDirectLoadMultipleHeapTableBuildParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(file_mgr), KP_(extra_buf), K_(extra_buf_size), + K_(index_dir_id), K_(data_dir_id)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + ObDirectLoadTmpFileManager *file_mgr_; + char *extra_buf_; + int64_t extra_buf_size_; + int64_t index_dir_id_; + int64_t data_dir_id_; +}; + +class ObDirectLoadMultipleHeapTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ + typedef ObDirectLoadMultipleExternalRow RowType; + typedef ObDirectLoadMultipleHeapTableIndexBlockWriter IndexBlockWriter; + typedef ObDirectLoadDataBlockWriter DataBlockWriter; +public: + ObDirectLoadMultipleHeapTableBuilder(); + virtual ~ObDirectLoadMultipleHeapTableBuilder(); + int init(const ObDirectLoadMultipleHeapTableBuildParam ¶m); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int append_row(const RowType &row); + int close() override; + int64_t get_row_count() const override { return row_count_; } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + class DataBlockFlushCallback : public ObIDirectLoadDataBlockFlushCallback + { + public: + DataBlockFlushCallback() : data_block_offset_(0) {} + virtual ~DataBlockFlushCallback() = default; + int write(char *buf, int64_t buf_size, int64_t offset) override + { + data_block_offset_ = offset + buf_size; + return common::OB_SUCCESS; + } + int64_t get_data_block_offset() const { return data_block_offset_; } + private: + int64_t data_block_offset_; + }; +private: + ObDirectLoadMultipleHeapTableBuildParam param_; + RowType row_; + ObDirectLoadTmpFileHandle index_file_handle_; + ObDirectLoadTmpFileHandle data_file_handle_; + IndexBlockWriter index_block_writer_; + DataBlockWriter data_block_writer_; + DataBlockFlushCallback callback_; + ObDirectLoadMultipleHeapTableTabletIndex last_tablet_index_; + int64_t index_entry_count_; + int64_t row_count_; + bool is_closed_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.cpp new file mode 100644 index 0000000000..1cac354ff4 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.cpp @@ -0,0 +1,337 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleHeapTableCompactParam + */ + +ObDirectLoadMultipleHeapTableCompactParam::ObDirectLoadMultipleHeapTableCompactParam() + : file_mgr_(nullptr), index_dir_id_(-1) +{ +} + +ObDirectLoadMultipleHeapTableCompactParam::~ObDirectLoadMultipleHeapTableCompactParam() +{ +} + +void ObDirectLoadMultipleHeapTableCompactParam::reset() +{ + table_data_desc_.reset(); + file_mgr_ = nullptr; + index_dir_id_ = -1; +} + +bool ObDirectLoadMultipleHeapTableCompactParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != file_mgr_ && index_dir_id_ > 0; +} + +/** + * ObDirectLoadMultipleHeapTableCompactor + */ + +ObDirectLoadMultipleHeapTableCompactor::ObDirectLoadMultipleHeapTableCompactor() + : allocator_("TLD_MHT_Comp"), + index_block_count_(0), + data_block_count_(0), + index_file_size_(0), + data_file_size_(0), + index_entry_count_(0), + row_count_(0), + max_data_block_size_(0), + is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableCompactor::~ObDirectLoadMultipleHeapTableCompactor() +{ + reset(); +} + +void ObDirectLoadMultipleHeapTableCompactor::reset() +{ + param_.reset(); + index_block_count_ = 0; + data_block_count_ = 0; + index_file_size_ = 0; + data_file_size_ = 0; + index_entry_count_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; + for (int64_t i = 0; i < index_scanners_.count(); ++i) { + ObIDirectLoadMultipleHeapTableIndexScanner *scanner = index_scanners_.at(i); + scanner->~ObIDirectLoadMultipleHeapTableIndexScanner(); + allocator_.free(scanner); + } + index_scanners_.reset(); + base_data_fragment_idxs_.reset(); + data_fragments_.reset(); + compacted_index_file_handle_.reset(); + allocator_.reset(); + is_inited_ = false; +} + +void ObDirectLoadMultipleHeapTableCompactor::reuse() +{ + index_block_count_ = 0; + data_block_count_ = 0; + index_file_size_ = 0; + data_file_size_ = 0; + index_entry_count_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; + for (int64_t i = 0; i < index_scanners_.count(); ++i) { + ObIDirectLoadMultipleHeapTableIndexScanner *scanner = index_scanners_.at(i); + scanner->~ObIDirectLoadMultipleHeapTableIndexScanner(); + allocator_.free(scanner); + } + index_scanners_.reset(); + base_data_fragment_idxs_.reset(); + data_fragments_.reset(); + compacted_index_file_handle_.reset(); + allocator_.reuse(); +} + +int ObDirectLoadMultipleHeapTableCompactor::init( + const ObDirectLoadMultipleHeapTableCompactParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableCompactor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + allocator_.set_tenant_id(MTL_ID()); + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMultipleHeapTableCompactor::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableCompactor not init", KR(ret), KP(this)); + } else { + int cmp_ret = 0; + ObDirectLoadMultipleHeapTable *heap_table = + dynamic_cast(table); + if (OB_ISNULL(heap_table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(table)); + } else if (OB_FAIL(check_table_compactable(heap_table))) { + LOG_WARN("fail to check table compactable", KR(ret), KPC(heap_table)); + } else if (OB_FAIL(construct_index_scanner(heap_table))) { + LOG_WARN("fail to construct index scanner", KR(ret), KPC(heap_table)); + } else { + const ObDirectLoadMultipleHeapTableMeta &table_meta = heap_table->get_meta(); + const ObIArray &data_fragments = + heap_table->get_data_fragments(); + data_block_count_ += table_meta.data_block_count_; + data_file_size_ += table_meta.data_file_size_; + index_entry_count_ += table_meta.index_entry_count_; + row_count_ += table_meta.row_count_; + max_data_block_size_ = MAX(max_data_block_size_, table_meta.max_data_block_size_); + if (OB_FAIL(base_data_fragment_idxs_.push_back(data_fragments_.count()))) { + LOG_WARN("fail to push back index fragment", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < data_fragments.count(); ++i) { + if (OB_FAIL(data_fragments_.push_back(data_fragments.at(i)))) { + LOG_WARN("fail to push back data fragment", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableCompactor::check_table_compactable( + ObDirectLoadMultipleHeapTable *heap_table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == heap_table || !heap_table->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(heap_table)); + } else { + const ObDirectLoadMultipleHeapTableMeta &table_meta = heap_table->get_meta(); + if (OB_UNLIKELY( + table_meta.column_count_ != param_.table_data_desc_.column_count_ || + table_meta.index_block_size_ != param_.table_data_desc_.sstable_index_block_size_ || + table_meta.data_block_size_ != param_.table_data_desc_.sstable_data_block_size_)) { + ret = OB_ITEM_NOT_MATCH; + LOG_WARN("table meta not match", KR(ret), K(param_), K(table_meta)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableCompactor::construct_index_scanner( + ObDirectLoadMultipleHeapTable *heap_table) +{ + int ret = OB_SUCCESS; + ObDirectLoadMultipleHeapTableIndexWholeScanner *index_whole_scanner = nullptr; + if (OB_ISNULL(index_whole_scanner = + OB_NEWx(ObDirectLoadMultipleHeapTableIndexWholeScanner, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleHeapTableIndexWholeScanner", KR(ret)); + } else if (OB_FAIL(index_whole_scanner->init(heap_table->get_index_file_handle(), + heap_table->get_meta().index_file_size_, + param_.table_data_desc_))) { + LOG_WARN("fail to init index whole scanner", KR(ret)); + } else if (OB_FAIL(index_scanners_.push_back(index_whole_scanner))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != index_whole_scanner) { + index_whole_scanner->~ObDirectLoadMultipleHeapTableIndexWholeScanner(); + allocator_.free(index_whole_scanner); + index_whole_scanner = nullptr; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableCompactor::compact() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableCompactor not init", KR(ret), KP(this)); + } else { + ObTabletID last_tablet_id; + int64_t idx = -1; + const ObDirectLoadMultipleHeapTableTabletIndex *tablet_index = nullptr; + ObDirectLoadMultipleHeapTableTabletIndex compacted_tablet_index; + ObDirectLoadMultipleHeapTableIndexScanMerge scan_merge; + ObDirectLoadMultipleHeapTableIndexBlockWriter index_block_writer; + int64_t index_entry_count = 0; + if (OB_FAIL(param_.file_mgr_->alloc_file(param_.index_dir_id_, compacted_index_file_handle_))) { + LOG_WARN("fail to alloc file", KR(ret)); + } else if (OB_FAIL(index_block_writer.init(param_.table_data_desc_.sstable_index_block_size_, + param_.table_data_desc_.compressor_type_))) { + LOG_WARN("fail to init index block writer", KR(ret)); + } else if (OB_FAIL(index_block_writer.open(compacted_index_file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else if (OB_FAIL(scan_merge.init(index_scanners_))) { + LOG_WARN("fail to init scan merge", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(scan_merge.get_next_index(idx, tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } + // check tablet id order + else if (last_tablet_id != tablet_index->tablet_id_) { + if (last_tablet_id.is_valid() && + OB_UNLIKELY(last_tablet_id.compare(tablet_index->tablet_id_) > 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet index", KR(ret), K(last_tablet_id), KPC(tablet_index)); + } else { + last_tablet_id = tablet_index->tablet_id_; + } + } + // append index + if (OB_SUCC(ret)) { + const int64_t base_data_fragment_idx = base_data_fragment_idxs_.at(idx); + compacted_tablet_index.tablet_id_ = tablet_index->tablet_id_; + compacted_tablet_index.row_count_ = tablet_index->row_count_; + compacted_tablet_index.fragment_idx_ = base_data_fragment_idx + tablet_index->fragment_idx_; + compacted_tablet_index.offset_ = tablet_index->offset_; + if (OB_FAIL(index_block_writer.append_index(compacted_tablet_index))) { + LOG_WARN("fail to append index", KR(ret)); + } else { + ++index_entry_count; + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(index_block_writer.close())) { + LOG_WARN("fail to close index block writer", KR(ret)); + } else if (OB_UNLIKELY(index_entry_count != index_entry_count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected index entry count", KR(ret), K(index_entry_count_), + K(index_entry_count)); + } else { + index_block_count_ = index_block_writer.get_block_count(); + index_file_size_ = index_block_writer.get_file_size(); + } + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableCompactor::get_table(ObIDirectLoadPartitionTable *&table, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableCompactor not init", KR(ret), KP(this)); + } else { + ObDirectLoadMultipleHeapTableCreateParam create_param; + create_param.column_count_ = param_.table_data_desc_.column_count_; + create_param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + create_param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + create_param.index_block_count_ = index_block_count_; + create_param.data_block_count_ = data_block_count_; + create_param.index_file_size_ = index_file_size_; + create_param.data_file_size_ = data_file_size_; + create_param.index_entry_count_ = index_entry_count_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = max_data_block_size_; + if (OB_FAIL(create_param.index_file_handle_.assign(compacted_index_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(create_param.data_fragments_.assign(data_fragments_))) { + LOG_WARN("fail to assign data fragments", KR(ret)); + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleHeapTable *heap_table = nullptr; + if (OB_ISNULL(heap_table = OB_NEWx(ObDirectLoadMultipleHeapTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleHeapTable", KR(ret)); + } else if (OB_FAIL(heap_table->init(create_param))) { + LOG_WARN("fail to init multiple heap table table", KR(ret)); + } else { + table = heap_table; + } + if (OB_FAIL(ret)) { + if (nullptr != heap_table) { + heap_table->~ObDirectLoadMultipleHeapTable(); + allocator.free(heap_table); + heap_table = nullptr; + } + } + } + } + return ret; +} + +void ObDirectLoadMultipleHeapTableCompactor::stop() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h new file mode 100644 index 0000000000..e4bd6004b6 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_compactor.h @@ -0,0 +1,64 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObIDirectLoadMultipleHeapTableIndexScanner; + +struct ObDirectLoadMultipleHeapTableCompactParam +{ +public: + ObDirectLoadMultipleHeapTableCompactParam(); + ~ObDirectLoadMultipleHeapTableCompactParam(); + void reset(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(file_mgr), K_(index_dir_id)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + ObDirectLoadTmpFileManager *file_mgr_; + int64_t index_dir_id_; +}; + +class ObDirectLoadMultipleHeapTableCompactor : public ObIDirectLoadTabletTableCompactor +{ +public: + ObDirectLoadMultipleHeapTableCompactor(); + virtual ~ObDirectLoadMultipleHeapTableCompactor(); + void reset(); + void reuse(); + int init(const ObDirectLoadMultipleHeapTableCompactParam ¶m); + int add_table(ObIDirectLoadPartitionTable *table) override; + int compact() override; + int get_table(ObIDirectLoadPartitionTable *&table, common::ObIAllocator &allocator) override; + void stop() override; +private: + int check_table_compactable(ObDirectLoadMultipleHeapTable *heap_table); + int construct_index_scanner(ObDirectLoadMultipleHeapTable *heap_table); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMultipleHeapTableCompactParam param_; + int64_t index_block_count_; + int64_t data_block_count_; + int64_t index_file_size_; + int64_t data_file_size_; + int64_t index_entry_count_; + int64_t row_count_; + int64_t max_data_block_size_; + common::ObArray index_scanners_; + common::ObArray base_data_fragment_idxs_; + common::ObArray data_fragments_; + ObDirectLoadTmpFileHandle compacted_index_file_handle_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.cpp new file mode 100644 index 0000000000..228adeee22 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.cpp @@ -0,0 +1,165 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * Header + */ + +ObDirectLoadMultipleHeapTableIndexBlock::Header::Header() + : count_(0), last_entry_pos_(0) +{ +} + +ObDirectLoadMultipleHeapTableIndexBlock::Header::~Header() +{ +} + +void ObDirectLoadMultipleHeapTableIndexBlock::Header::reset() +{ + ObDirectLoadDataBlock::Header::reset(); + count_ = 0; + last_entry_pos_ = 0; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::serialize(buf, buf_len, pos))) { + LOG_WARN("fail to encode header", KR(ret), K(buf_len), K(pos)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, count_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(count_)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, last_entry_pos_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(last_entry_pos_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::deserialize(buf, data_len, pos))) { + LOG_WARN("fail to decode header", KR(ret), K(data_len), K(pos)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &count_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(count_)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &last_entry_pos_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(last_entry_pos_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Header) +{ + int64_t len = 0; + len += ObDirectLoadDataBlock::Header::get_serialize_size(); + len += NS_::encoded_length_i32(count_); + len += NS_::encoded_length_i32(last_entry_pos_); + return len; +} + +/* + * Entry + */ + +ObDirectLoadMultipleHeapTableIndexBlock::Entry::Entry() + : tablet_id_(0), row_count_(0), offset_val_(0) +{ +} + +ObDirectLoadMultipleHeapTableIndexBlock::Entry::~Entry() +{ +} + +void ObDirectLoadMultipleHeapTableIndexBlock::Entry::reset() +{ + tablet_id_ = 0; + row_count_ = 0; + offset_val_ = 0; +} + +void ObDirectLoadMultipleHeapTableIndexBlock::Entry::reuse() +{ + reset(); +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Entry) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, static_cast(tablet_id_)))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(tablet_id_)); + } else if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, row_count_))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(row_count_)); + } else if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, offset_val_))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(offset_val_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Entry) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, reinterpret_cast(&tablet_id_)))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(tablet_id_)); + } else if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &row_count_))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(row_count_)); + } else if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &offset_val_))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(offset_val_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadMultipleHeapTableIndexBlock::Entry) +{ + int64_t len = 0; + len += NS_::encoded_length_i64(static_cast(tablet_id_)); + len += NS_::encoded_length_i64(row_count_); + len += NS_::encoded_length_i64(offset_val_); + return len; +} + +/** + * ObDirectLoadMultipleHeapTableIndexBlock + */ + +int64_t ObDirectLoadMultipleHeapTableIndexBlock::get_header_size() +{ + static int64_t size = Header().get_serialize_size(); + return size; +} + +int64_t ObDirectLoadMultipleHeapTableIndexBlock::get_entry_size() +{ + static int64_t size = Entry().get_serialize_size(); + return size; +} + +int64_t ObDirectLoadMultipleHeapTableIndexBlock::get_entries_per_block(int64_t block_size) +{ + return (block_size - get_header_size()) / get_entry_size(); +} + +/** + * ObDirectLoadMultipleHeapTableTabletIndex + */ + +ObDirectLoadMultipleHeapTableTabletIndex::ObDirectLoadMultipleHeapTableTabletIndex() + : row_count_(0), fragment_idx_(0), offset_(0) +{ +} + +ObDirectLoadMultipleHeapTableTabletIndex::~ObDirectLoadMultipleHeapTableTabletIndex() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h new file mode 100644 index 0000000000..5454485eb0 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h @@ -0,0 +1,73 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleHeapTableIndexBlock +{ +public: + static const int64_t DEFAULT_INDEX_BLOCK_SIZE = 4 * 1024; // 4K + struct Header : public ObDirectLoadDataBlock::Header + { + OB_UNIS_VERSION(1); + public: + Header(); + ~Header(); + void reset(); + TO_STRING_KV(K_(count), K_(last_entry_pos)); + public: + int32_t count_; + int32_t last_entry_pos_; + }; + struct Entry + { + OB_UNIS_VERSION(1); + public: + Entry(); + ~Entry(); + void reuse(); + void reset(); + TO_STRING_KV(K_(tablet_id), K_(row_count), K_(offset)); + public: + uint64_t tablet_id_; + int64_t row_count_; + union + { + struct + { + int64_t fragment_idx_ : 16; + int64_t offset_ : 48; + }; + int64_t offset_val_; + }; + }; +public: + static int64_t get_header_size(); + static int64_t get_entry_size(); + static int64_t get_entries_per_block(int64_t block_size); +}; + +struct ObDirectLoadMultipleHeapTableTabletIndex +{ +public: + ObDirectLoadMultipleHeapTableTabletIndex(); + ~ObDirectLoadMultipleHeapTableTabletIndex(); + TO_STRING_KV(K_(tablet_id), K_(row_count), K_(fragment_idx), K_(offset)); +public: + common::ObTabletID tablet_id_; + int64_t row_count_; + int64_t fragment_idx_; + int64_t offset_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.cpp new file mode 100644 index 0000000000..0647bb019a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.cpp @@ -0,0 +1,111 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadMultipleHeapTableIndexBlockReader::ObDirectLoadMultipleHeapTableIndexBlockReader() +{ +} + +ObDirectLoadMultipleHeapTableIndexBlockReader::~ObDirectLoadMultipleHeapTableIndexBlockReader() +{ +} + +int ObDirectLoadMultipleHeapTableIndexBlockReader::init(int64_t data_block_size, + ObCompressorType compressor_type) +{ + return ParentType::init(data_block_size, data_block_size, compressor_type); +} + +int ObDirectLoadMultipleHeapTableIndexBlockReader::get_next_index( + const ObDirectLoadMultipleHeapTableTabletIndex *&index) +{ + int ret = OB_SUCCESS; + index = nullptr; + const Entry *item = nullptr; + if (OB_FAIL(this->get_next_item(item))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } + } else { + index_.tablet_id_ = item->tablet_id_; + index_.row_count_ = item->row_count_; + index_.fragment_idx_ = item->fragment_idx_; + index_.offset_ = item->offset_; + index = &index_; + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexBlockReader::get_last_index( + const ObDirectLoadMultipleHeapTableTabletIndex *&index) +{ + int ret = OB_SUCCESS; + index = nullptr; + const Header &header = this->data_block_reader_.get_header(); + Entry item; + if (OB_FAIL(this->data_block_reader_.read_item(header.last_entry_pos_, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + index_.tablet_id_ = item.tablet_id_; + index_.row_count_ = item.row_count_; + index_.fragment_idx_ = item.fragment_idx_; + index_.offset_ = item.offset_; + index = &index_; + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexBlockReader::get_index( + int64_t idx, const ObDirectLoadMultipleHeapTableTabletIndex *&index) +{ + int ret = OB_SUCCESS; + const Header &header = this->data_block_reader_.get_header(); + if (OB_UNLIKELY(idx >= header.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(header), K(idx)); + } else { + const int64_t pos = ObDirectLoadMultipleHeapTableIndexBlock::get_header_size() + + ObDirectLoadMultipleHeapTableIndexBlock::get_entry_size() * idx; + Entry item; + if (OB_FAIL(this->data_block_reader_.read_item(pos, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + index_.tablet_id_ = item.tablet_id_; + index_.row_count_ = item.row_count_; + index_.fragment_idx_ = item.fragment_idx_; + index_.offset_ = item.offset_; + index = &index_; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexBlockReader::seek_index(int64_t idx) +{ + int ret = OB_SUCCESS; + const Header &header = this->data_block_reader_.get_header(); + if (OB_UNLIKELY(idx >= header.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(header), K(idx)); + } else { + const int64_t pos = ObDirectLoadMultipleHeapTableIndexBlock::get_header_size() + + ObDirectLoadMultipleHeapTableIndexBlock::get_entry_size() * idx; + if (OB_FAIL(this->data_block_reader_.set_pos(pos))) { + STORAGE_LOG(WARN, "fail to set pos", KR(ret)); + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h new file mode 100644 index 0000000000..8b74859466 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h @@ -0,0 +1,37 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleHeapTableIndexBlockReader + : public ObDirectLoadDataBlockReader +{ + typedef ObDirectLoadMultipleHeapTableIndexBlock::Header Header; + typedef ObDirectLoadMultipleHeapTableIndexBlock::Entry Entry; + typedef ObDirectLoadDataBlockReader ParentType; +public: + ObDirectLoadMultipleHeapTableIndexBlockReader(); + virtual ~ObDirectLoadMultipleHeapTableIndexBlockReader(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + int get_next_index(const ObDirectLoadMultipleHeapTableTabletIndex *&index); + int get_last_index(const ObDirectLoadMultipleHeapTableTabletIndex *&entry); + int get_index(int64_t idx, const ObDirectLoadMultipleHeapTableTabletIndex *&entry); + int seek_index(int64_t idx); + const Header &get_header() const { return this->data_block_reader_.get_header(); } +private: + ObDirectLoadMultipleHeapTableTabletIndex index_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultipleHeapTableIndexBlockReader); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.cpp new file mode 100644 index 0000000000..180c249598 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadMultipleHeapTableIndexBlockWriter::ObDirectLoadMultipleHeapTableIndexBlockWriter() + : entry_count_(0), last_entry_pos_(-1), cur_entry_pos_(-1) +{ +} + +ObDirectLoadMultipleHeapTableIndexBlockWriter::~ObDirectLoadMultipleHeapTableIndexBlockWriter() +{ +} + +int ObDirectLoadMultipleHeapTableIndexBlockWriter::init(int64_t data_block_size, + ObCompressorType compressor_type) +{ + return ObDirectLoadDataBlockWriter::init(data_block_size, compressor_type, nullptr, 0, nullptr); +} + +int ObDirectLoadMultipleHeapTableIndexBlockWriter::append_index( + const ObDirectLoadMultipleHeapTableTabletIndex &tablet_index) +{ + int ret = OB_SUCCESS; + ObDirectLoadMultipleHeapTableIndexBlock::Entry item; + item.tablet_id_ = tablet_index.tablet_id_.id(); + item.row_count_ = tablet_index.row_count_; + item.fragment_idx_ = tablet_index.fragment_idx_; + item.offset_ = tablet_index.offset_; + if (OB_FAIL(this->write_item(item))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } else { + ++entry_count_; + last_entry_pos_ = cur_entry_pos_; + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexBlockWriter::pre_write_item() +{ + cur_entry_pos_ = this->data_block_writer_.get_pos(); + return OB_SUCCESS; +} + +int ObDirectLoadMultipleHeapTableIndexBlockWriter::pre_flush_buffer() +{ + ObDirectLoadMultipleHeapTableIndexBlock::Header &header = this->data_block_writer_.get_header(); + header.count_ = entry_count_; + header.last_entry_pos_ = (last_entry_pos_ != -1 ? last_entry_pos_ : cur_entry_pos_); + entry_count_ = 0; + last_entry_pos_ = -1; + cur_entry_pos_ = -1; + return OB_SUCCESS; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h new file mode 100644 index 0000000000..3081051674 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_block_writer.h @@ -0,0 +1,35 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_writer.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleHeapTableIndexBlockWriter + : public ObDirectLoadDataBlockWriter +{ +public: + ObDirectLoadMultipleHeapTableIndexBlockWriter(); + virtual ~ObDirectLoadMultipleHeapTableIndexBlockWriter(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + int append_index(const ObDirectLoadMultipleHeapTableTabletIndex &tablet_index); +private: + int pre_write_item() override; + int pre_flush_buffer() override; +private: + int64_t entry_count_; + int32_t last_entry_pos_; + int32_t cur_entry_pos_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultipleHeapTableIndexBlockWriter); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.cpp new file mode 100644 index 0000000000..e2b0ac657d --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadMultipleSSTableIndexEntryCompare + */ + +ObDirectLoadMultipleSSTableIndexEntryCompare::ObDirectLoadMultipleSSTableIndexEntryCompare( + int &ret, ObDirectLoadMultipleHeapTable *heap_table, IndexBlockReader &index_block_reader) + : ret_(ret), + heap_table_(heap_table), + index_block_reader_(index_block_reader), + entries_per_block_(ObDirectLoadMultipleHeapTableIndexBlock::get_entries_per_block( + heap_table->get_meta().index_block_size_)) +{ +} + +bool ObDirectLoadMultipleSSTableIndexEntryCompare::operator()( + const ObTabletID &tablet_id, const ObDirectLoadMultipleHeapTable::IndexEntryIterator &iter) +{ + int &ret = ret_; + int cmp_ret = 0; + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = heap_table_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadMultipleHeapTableTabletIndex *entry = nullptr; + index_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(heap_table_->get_index_file_handle(), + index_block_offset, + heap_table_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_index(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else { + cmp_ret = tablet_id.compare(entry->tablet_id_); + } + return cmp_ret < 0; +} + +bool ObDirectLoadMultipleSSTableIndexEntryCompare::operator()( + const ObDirectLoadMultipleHeapTable::IndexEntryIterator &iter, const ObTabletID &tablet_id) +{ + int &ret = ret_; + int cmp_ret = 0; + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = heap_table_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadMultipleHeapTableTabletIndex *entry = nullptr; + index_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(heap_table_->get_index_file_handle(), + index_block_offset, + heap_table_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_index(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else { + cmp_ret = entry->tablet_id_.compare(tablet_id); + } + return cmp_ret < 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h new file mode 100644 index 0000000000..e927caa92f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h @@ -0,0 +1,35 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMultipleHeapTableIndexBlockReader; + +class ObDirectLoadMultipleSSTableIndexEntryCompare +{ + typedef ObDirectLoadMultipleHeapTableIndexBlockReader IndexBlockReader; +public: + ObDirectLoadMultipleSSTableIndexEntryCompare(int &ret, ObDirectLoadMultipleHeapTable *heap_table, + IndexBlockReader &index_block_reader); + // for upper_bound + bool operator()(const common::ObTabletID &tablet_id, + const ObDirectLoadMultipleHeapTable::IndexEntryIterator &iter); + // for lower_bound + bool operator()(const ObDirectLoadMultipleHeapTable::IndexEntryIterator &iter, + const common::ObTabletID &tablet_id); +private: + int &ret_; + ObDirectLoadMultipleHeapTable *heap_table_; + IndexBlockReader &index_block_reader_; + const int64_t entries_per_block_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_iterator.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_iterator.h new file mode 100644 index 0000000000..aa796fa833 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_iterator.h @@ -0,0 +1,113 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadMultipleHeapTableIndexEntryIterator +{ + typedef ObDirectLoadMultipleHeapTableIndexEntryIterator self_t; +public: + typedef typename std::random_access_iterator_tag iterator_category; + typedef int64_t difference_type; + typedef self_t value_type; + typedef self_t *value_ptr_t; + typedef self_t *pointer; + typedef self_t &reference; +public: + ObDirectLoadMultipleHeapTableIndexEntryIterator() : table_(nullptr), index_entry_idx_(0) {} + ObDirectLoadMultipleHeapTableIndexEntryIterator(const self_t &other) { *this = other; } + ~ObDirectLoadMultipleHeapTableIndexEntryIterator() {} + self_t &operator=(const self_t &other) + { + table_ = other.table_; + index_entry_idx_ = other.index_entry_idx_; + return *this; + } +public: + reference operator*() { return *this; } + value_ptr_t operator->() { return this; } + operator value_ptr_t() { return this; } + bool operator==(const self_t &other) const + { + abort_unless(table_ == other.table_); + return index_entry_idx_ == other.index_entry_idx_; + } + bool operator!=(const self_t &other) const { return !(*this == other); } + bool operator<(const self_t &other) const + { + abort_unless(table_ == other.table_); + return index_entry_idx_ < other.index_entry_idx_; + } + bool operator>=(const self_t &other) const { return !(*this < other); } + bool operator>(const self_t &other) const + { + abort_unless(table_ == other.table_); + return index_entry_idx_ > other.index_entry_idx_; + } + bool operator<=(const self_t &other) const { return !(*this > other); } + difference_type operator-(const self_t &rhs) const + { + abort_unless(table_ == rhs.table_); + return index_entry_idx_ - rhs.index_entry_idx_; + } + self_t &operator+=(difference_type step) + { + abort_unless(index_entry_idx_ + step <= table_->get_meta().index_entry_count_); + index_entry_idx_ += step; + return *this; + } + self_t operator+(difference_type step) const + { + self_t value(*this); + return (value += step); + } + self_t &operator-=(difference_type step) + { + abort_unless(index_entry_idx_ - step >= 0); + index_entry_idx_ -= step; + return *this; + } + self_t operator-(difference_type step) const + { + self_t value(*this); + return (value -= step); + } + self_t &operator++() + { + *this += 1; + return *this; + } + self_t operator++(int) + { + self_t tmp = *this; + *this += 1; + return tmp; + } + self_t &operator--() + { + *this -= 1; + return *this; + } + self_t operator--(int) + { + self_t tmp = *this; + *this -= 1; + return tmp; + } + TO_STRING_KV(KP_(table), K_(index_entry_idx)); +public: + Table *table_; + int64_t index_entry_idx_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.cpp new file mode 100644 index 0000000000..9d6ae3a63c --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.cpp @@ -0,0 +1,180 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadMultipleHeapTableIndexScanMerge::ObDirectLoadMultipleHeapTableIndexScanMerge() + : scanners_(nullptr), + consumers_(nullptr), + consumer_cnt_(0), + simple_merge_(nullptr), + loser_tree_(nullptr), + rows_merger_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableIndexScanMerge::~ObDirectLoadMultipleHeapTableIndexScanMerge() +{ +} + +int ObDirectLoadMultipleHeapTableIndexScanMerge::init( + const ObIArray &scanners) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableIndexScanMerge init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(scanners.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(scanners.count())); + } else { + if (scanners.count() > 1) { + // init consumers + if (OB_ISNULL(consumers_ = static_cast( + allocator_.alloc(sizeof(int64_t) * scanners.count())))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + for (int64_t i = 0; i < scanners.count(); ++i) { + consumers_[i] = i; + } + consumer_cnt_ = scanners.count(); + } + // init rows merger + if (OB_FAIL(ret)) { + } else if (OB_FAIL(init_rows_merger(scanners.count()))) { + LOG_WARN("fail to init rows merger", KR(ret)); + } + } + if (OB_SUCC(ret)) { + scanners_ = &scanners; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexScanMerge::init_rows_merger(int64_t count) +{ + int ret = OB_SUCCESS; + if (count <= ObScanSimpleMerger::USE_SIMPLE_MERGER_MAX_TABLE_CNT) { + if (OB_ISNULL(simple_merge_ = OB_NEWx(ScanSimpleMerger, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanSimpleMerger", KR(ret)); + } else { + rows_merger_ = simple_merge_; + } + } else { + if (OB_ISNULL(loser_tree_ = OB_NEWx(ScanMergeLoserTree, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanMergeLoserTree", KR(ret)); + } else { + rows_merger_ = loser_tree_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(rows_merger_->init(count, allocator_))) { + LOG_WARN("fail to init rows merger", KR(ret), K(count)); + } else if (FALSE_IT(rows_merger_->reuse())) { + } else if (OB_FAIL(rows_merger_->open(count))) { + LOG_WARN("fail to open rows merger", KR(ret), K(count)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexScanMerge::supply_consume() +{ + int ret = OB_SUCCESS; + LoserTreeItem item; + for (int64_t i = 0; OB_SUCC(ret) && i < consumer_cnt_; ++i) { + const int64_t iter_idx = consumers_[i]; + ObIDirectLoadMultipleHeapTableIndexScanner *scanner = scanners_->at(iter_idx); + if (OB_FAIL(scanner->get_next_index(item.index_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index from scanner", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } else { + item.iter_idx_ = iter_idx; + if (OB_FAIL(rows_merger_->push(item))) { + LOG_WARN("fail to push to loser tree", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + // no worry, if no new items pushed, the rebuild will quickly exit + if (OB_FAIL(rows_merger_->rebuild())) { + LOG_WARN("fail to rebuild loser tree", KR(ret), K(consumer_cnt_)); + } else { + consumer_cnt_ = 0; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexScanMerge::inner_get_next_index( + int64_t &idx, const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) +{ + int ret = OB_SUCCESS; + tablet_index = nullptr; + if (rows_merger_->empty()) { + ret = OB_ITER_END; + } else { + const LoserTreeItem *top_item = nullptr; + if (OB_FAIL(rows_merger_->top(top_item))) { + LOG_WARN("fail to get top item", KR(ret)); + } else { + idx = top_item->iter_idx_; + tablet_index = top_item->index_; + consumers_[consumer_cnt_++] = top_item->iter_idx_; + if (OB_FAIL(rows_merger_->pop())) { + LOG_WARN("fail to pop item", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexScanMerge::get_next_index( + int64_t &idx, const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableIndexScanMerge not init", KR(ret), KP(this)); + } else if (1 == scanners_->count()) { + // direct get next row from scanner + idx = 0; + if (OB_FAIL(scanners_->at(0)->get_next_index(tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index from scanner", KR(ret)); + } + } + } else { + // get next row from loser tree + if (consumer_cnt_ > 0 && OB_FAIL(supply_consume())) { + LOG_WARN("fail to supply consume", KR(ret)); + } else if (OB_FAIL(inner_get_next_index(idx, tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do inner get next index", KR(ret)); + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h new file mode 100644 index 0000000000..15e7d0daec --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge.h @@ -0,0 +1,49 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_loser_tree.h" +#include "storage/access/ob_simple_rows_merger.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h" + +namespace oceanbase +{ +namespace storage +{ +class ObIDirectLoadMultipleHeapTableIndexScanner; + +class ObDirectLoadMultipleHeapTableIndexScanMerge +{ +public: + static const int64_t MAX_SCANNER_COUNT = 1024; + typedef ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem LoserTreeItem; + typedef ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare LoserTreeCompare; + typedef ObSimpleRowsMerger ScanSimpleMerger; + typedef common::ObLoserTree + ScanMergeLoserTree; +public: + ObDirectLoadMultipleHeapTableIndexScanMerge(); + ~ObDirectLoadMultipleHeapTableIndexScanMerge(); + int init(const common::ObIArray &scanners); + int get_next_index(int64_t &idx, const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index); +private: + int init_rows_merger(int64_t count); + int supply_consume(); + int inner_get_next_index(int64_t &idx, + const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index); +private: + common::ObArenaAllocator allocator_; + const common::ObIArray *scanners_; + int64_t *consumers_; + int64_t consumer_cnt_; + LoserTreeCompare compare_; + ScanSimpleMerger *simple_merge_; + ScanMergeLoserTree *loser_tree_; + common::ObRowsMerger *rows_merger_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.cpp new file mode 100644 index 0000000000..0633b0228f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare + */ + +ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare:: + ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare() +{ +} + +ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare:: + ~ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare() +{ +} + +int ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare::cmp( + const ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem &lhs, + const ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem &rhs, + int64_t &cmp_ret) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == lhs.index_ || nullptr == rhs.index_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(lhs), K(rhs)); + } else { + cmp_ret = lhs.index_->tablet_id_.compare(rhs.index_->tablet_id_); + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h new file mode 100644 index 0000000000..b174b44e08 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scan_merge_loser_tree.h @@ -0,0 +1,46 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem +{ +public: + ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem() + : index_(nullptr), iter_idx_(0), equal_with_next_(false) + { + } + ~ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem() = default; + void reset() + { + index_ = nullptr; + iter_idx_ = 0; + equal_with_next_ = false; + } + TO_STRING_KV(KPC_(index), K_(iter_idx), K_(equal_with_next)); +public: + const ObDirectLoadMultipleHeapTableTabletIndex *index_; + int64_t iter_idx_; + bool equal_with_next_; // for simple row merger +}; + +class ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare +{ +public: + ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare(); + ~ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeCompare(); + int cmp(const ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem &lhs, + const ObDirectLoadMultipleHeapTableIndexScanMergeLoserTreeItem &rhs, + int64_t &cmp_ret); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.cpp new file mode 100644 index 0000000000..395674da52 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.cpp @@ -0,0 +1,206 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_entry_compare.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleHeapTableIndexWholeScanner + */ + +ObDirectLoadMultipleHeapTableIndexWholeScanner::ObDirectLoadMultipleHeapTableIndexWholeScanner() + : is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableIndexWholeScanner::~ObDirectLoadMultipleHeapTableIndexWholeScanner() +{ +} + +int ObDirectLoadMultipleHeapTableIndexWholeScanner::init( + ObDirectLoadMultipleHeapTable *heap_table, + const ObDirectLoadTableDataDesc &table_data_desc) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableIndexWholeScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == heap_table || !heap_table->is_valid() || + !table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(heap_table), K(table_data_desc)); + } else { + if (OB_FAIL(index_block_reader_.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else if (OB_FAIL(index_block_reader_.open(heap_table->get_index_file_handle(), 0, + heap_table->get_meta().index_file_size_))) { + LOG_WARN("fail to open index file", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexWholeScanner::init( + const ObDirectLoadTmpFileHandle &index_file_handle, + int64_t file_size, + const ObDirectLoadTableDataDesc &table_data_desc) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableIndexWholeScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!index_file_handle.is_valid() || file_size <= 0 || + !table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(index_file_handle), K(file_size), K(table_data_desc)); + } else { + if (OB_FAIL(index_block_reader_.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else if (OB_FAIL(index_block_reader_.open(index_file_handle, 0, file_size))) { + LOG_WARN("fail to open index file", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableIndexWholeScanner::get_next_index( + const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableIndexWholeScanner not init", KR(ret), KP(this)); + } else { + tablet_index = nullptr; + if (OB_FAIL(index_block_reader_.get_next_index(tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index", KR(ret)); + } + } + } + return ret; +} + +/** + * ObDirectLoadMultipleHeapTableTabletIndexWholeScanner + */ + +ObDirectLoadMultipleHeapTableTabletIndexWholeScanner:: + ObDirectLoadMultipleHeapTableTabletIndexWholeScanner() + : heap_table_(nullptr), is_iter_end_(false), is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableTabletIndexWholeScanner:: + ~ObDirectLoadMultipleHeapTableTabletIndexWholeScanner() +{ +} + +int ObDirectLoadMultipleHeapTableTabletIndexWholeScanner::init( + ObDirectLoadMultipleHeapTable *heap_table, + const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableTabletIndexWholeScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == heap_table || !heap_table->is_valid() || + !tablet_id.is_valid() || !table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(heap_table), K(tablet_id), K(table_data_desc)); + } else { + heap_table_ = heap_table; + tablet_id_ = tablet_id; + if (OB_FAIL(index_block_reader_.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else if (OB_FAIL(locate_left_border())) { + LOG_WARN("fail to locate left border", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableTabletIndexWholeScanner::locate_left_border() +{ + int ret = OB_SUCCESS; + // locate index entry + ObDirectLoadMultipleSSTableIndexEntryCompare compare(ret, heap_table_, index_block_reader_); + ObDirectLoadMultipleHeapTable::IndexEntryIterator found_iter = std::lower_bound( + heap_table_->index_entry_begin(), heap_table_->index_entry_end(), tablet_id_, compare); + if (OB_FAIL(ret)) { + } else if (found_iter == heap_table_->index_entry_end()) { + is_iter_end_ = true; + } else { + // seek pos + const int64_t entries_per_block = + ObDirectLoadMultipleHeapTableIndexBlock::get_entries_per_block( + heap_table_->get_meta().index_block_size_); + const int64_t index_block_idx = found_iter.index_entry_idx_ / entries_per_block; + const int64_t index_block_offset = heap_table_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = found_iter.index_entry_idx_ % entries_per_block; + index_block_reader_.reuse(); + if (OB_FAIL(index_block_reader_.open( + heap_table_->get_index_file_handle(), index_block_offset, + heap_table_->get_meta().index_file_size_ - index_block_offset))) { + LOG_WARN("fail to open index file", KR(ret), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.seek_index(index_entry_idx))) { + LOG_WARN("fail to get entry", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableTabletIndexWholeScanner::get_next_index( + const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableTabletIndexWholeScanner not init", KR(ret), KP(this)); + } else if (is_iter_end_) { + ret = OB_ITER_END; + } else { + tablet_index = nullptr; + if (OB_FAIL(index_block_reader_.get_next_index(tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index", KR(ret)); + } + } else { + int cmp_ret = tablet_index->tablet_id_.compare(tablet_id_); + if (OB_UNLIKELY(cmp_ret < 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet index", KR(ret), K(tablet_id_), KPC(tablet_index)); + } else if (cmp_ret > 0) { + ret = OB_ITER_END; + is_iter_end_ = true; + tablet_index = nullptr; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h new file mode 100644 index 0000000000..9b39b2e809 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h @@ -0,0 +1,63 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObDirectLoadMultipleHeapTable; + +class ObIDirectLoadMultipleHeapTableIndexScanner +{ +public: + virtual ~ObIDirectLoadMultipleHeapTableIndexScanner() = default; + virtual int get_next_index(const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) = 0; + TO_STRING_EMPTY(); +}; + +class ObDirectLoadMultipleHeapTableIndexWholeScanner + : public ObIDirectLoadMultipleHeapTableIndexScanner +{ +public: + ObDirectLoadMultipleHeapTableIndexWholeScanner(); + virtual ~ObDirectLoadMultipleHeapTableIndexWholeScanner(); + int init(ObDirectLoadMultipleHeapTable *heap_table, + const ObDirectLoadTableDataDesc &table_data_desc); + int init(const ObDirectLoadTmpFileHandle &index_file_handle, + int64_t file_size, + const ObDirectLoadTableDataDesc &table_data_desc); + int get_next_index(const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) override; +private: + ObDirectLoadMultipleHeapTableIndexBlockReader index_block_reader_; + bool is_inited_; +}; + +class ObDirectLoadMultipleHeapTableTabletIndexWholeScanner + : public ObIDirectLoadMultipleHeapTableIndexScanner +{ +public: + ObDirectLoadMultipleHeapTableTabletIndexWholeScanner(); + virtual ~ObDirectLoadMultipleHeapTableTabletIndexWholeScanner(); + int init(ObDirectLoadMultipleHeapTable *heap_table, + const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc); + int get_next_index(const ObDirectLoadMultipleHeapTableTabletIndex *&tablet_index) override; + TO_STRING_KV(KP_(heap_table), K_(tablet_id)); +private: + int locate_left_border(); +private: + ObDirectLoadMultipleHeapTable *heap_table_; + common::ObTabletID tablet_id_; + ObDirectLoadMultipleHeapTableIndexBlockReader index_block_reader_; + bool is_iter_end_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.cpp new file mode 100644 index 0000000000..d921e2119c --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_map.h" +#include "share/rc/ob_tenant_base.h" +#include "lib/container/ob_array.h" +#include "lib/container/ob_array_iterator.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace storage +{ + +ObDirectLoadMultipleHeapTableMap::ObDirectLoadMultipleHeapTableMap(int64_t mem_limit) : + allocator_("TLD_HT_map"), + mem_limit_(mem_limit) +{ +} + +int ObDirectLoadMultipleHeapTableMap::init() +{ + int ret = OB_SUCCESS; + allocator_.set_tenant_id(MTL_ID()); + ret = tablet_map_.init(); + return ret; +} + +int ObDirectLoadMultipleHeapTableMap::deep_copy_row(const RowType &row, RowType *&result_row) +{ + int ret = OB_SUCCESS; + if (allocator_.used() >= mem_limit_) { //到达内存上限 + ret = OB_BUF_NOT_ENOUGH; + } + if (OB_SUCC(ret)) { + result_row = OB_NEWx(RowType, (&allocator_)); + if (result_row == nullptr) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate row", K(ret)); + } + } + if (OB_SUCC(ret)) { + int64_t size = row.get_deep_copy_size(); + char *buf = (char *)allocator_.alloc(size); + int64_t pos = 0; + if (buf == nullptr) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc buf", K(size), KR(ret)); + } else if (OB_FAIL(result_row->deep_copy(row, buf, size, pos))) { + LOG_WARN("fail to copy row", KR(ret)); + } + } + if (OB_FAIL(ret)) { + if (result_row != nullptr) { + result_row->~RowType(); + result_row = nullptr; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableMap::get_all_key_sorted(ObArray &key_array) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(tablet_map_.get_all_key(key_array))) { + LOG_WARN("fail to get all keys", KR(ret)); + } + if (OB_SUCC(ret)) { + std::sort(key_array.begin(), key_array.end()); + } + return ret; +} + + +int ObDirectLoadMultipleHeapTableMap::add_row(const KeyType &key, const RowType &row) +{ + int ret = OB_SUCCESS; + RowType *result_row = nullptr; + if (OB_FAIL(deep_copy_row(row, result_row))) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to copy row", KR(ret)); + } + } else if (OB_FAIL(tablet_map_.add(key, result_row))) { + LOG_WARN("fail to add row", KR(ret)); + } + return ret; +} + +} +} diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.h new file mode 100644 index 0000000000..1d8cd16945 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_map.h @@ -0,0 +1,49 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#ifndef OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_MAP_H_ +#define OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_MAP_H_ + +#include "lib/hash/ob_hashmap.h" +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_external_multi_partition_row.h" +#include "storage/direct_load/ob_direct_load_multi_map.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleHeapTableMap +{ + typedef ObDirectLoadConstExternalMultiPartitionRow RowType; + typedef common::ObTabletID KeyType; + typedef common::ObArray BagType; + typedef common::hash::ObHashMap MapType; +public: + ObDirectLoadMultipleHeapTableMap(int64_t mem_limit); + virtual ~ObDirectLoadMultipleHeapTableMap() {} + + int init(); + int add_row(const KeyType &key, const RowType &row); + int get_all_key_sorted(common::ObArray &key_array); + int get(const KeyType &key, BagType &out_bag) { + return tablet_map_.get(key, out_bag); + } + +private: + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultipleHeapTableMap); + int deep_copy_row(const RowType &row, RowType *&result_row); + +private: + // data members + ObDirectLoadMultiMapNoLock tablet_map_; + common::ObArenaAllocator allocator_; + int64_t mem_limit_; +}; + +} +} + +#endif /* OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_MAP_H_ */ diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.cpp new file mode 100644 index 0000000000..8849ccf0e8 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.cpp @@ -0,0 +1,126 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadMultipleHeapTableTabletWholeScanner::ObDirectLoadMultipleHeapTableTabletWholeScanner() + : heap_table_(nullptr), is_iter_end_(false), is_inited_(false) +{ +} + +ObDirectLoadMultipleHeapTableTabletWholeScanner::~ObDirectLoadMultipleHeapTableTabletWholeScanner() +{ +} + +int ObDirectLoadMultipleHeapTableTabletWholeScanner::init( + ObDirectLoadMultipleHeapTable *heap_table, + const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleHeapTableTabletWholeScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == heap_table || !heap_table->is_valid() || + !tablet_id.is_valid() || !table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(heap_table), K(tablet_id), K(table_data_desc)); + } else { + heap_table_ = heap_table; + tablet_id_ = tablet_id; + if (OB_FAIL(index_scanner_.init(heap_table, tablet_id, table_data_desc))) { + LOG_WARN("fail to init index scanner", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(table_data_desc.sstable_data_block_size_, + heap_table->get_meta().max_data_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else if (OB_FAIL(switch_next_fragment())) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to switch next fragment", KR(ret)); + } else { + ret = OB_SUCCESS; + is_iter_end_ = true; + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableTabletWholeScanner::switch_next_fragment() +{ + int ret = OB_SUCCESS; + const ObDirectLoadMultipleHeapTableTabletIndex *tablet_index = nullptr; + if (OB_FAIL(index_scanner_.get_next_index(tablet_index))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index", KR(ret)); + } + } else { + const ObDirectLoadMultipleHeapTableDataFragment &data_fragment = + heap_table_->get_data_fragments().at(tablet_index->fragment_idx_); + data_block_reader_.reuse(); + if (OB_FAIL(data_block_reader_.open(data_fragment.file_handle_, tablet_index->offset_, + data_fragment.file_size_ - tablet_index->offset_))) { + LOG_WARN("fail to open file", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableTabletWholeScanner::get_next_row(const RowType *&external_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleHeapTableTabletWholeScanner not init", KR(ret), KP(this)); + } else if (is_iter_end_) { + ret = OB_ITER_END; + } else { + external_row = nullptr; + while (OB_SUCC(ret) && nullptr == external_row) { + // get next row from current fragment + if (OB_FAIL(data_block_reader_.get_next_item(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next item", KR(ret)); + } + } else { + int cmp_ret = external_row->tablet_id_.compare(tablet_id_); + if (cmp_ret < 0) { + // ignore + external_row = nullptr; + } else if (cmp_ret > 0) { + ret = OB_ITER_END; + external_row = nullptr; + } + } + // switch next fragment + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + if (OB_FAIL(switch_next_fragment())) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to switch next fragment", KR(ret)); + } else { + is_iter_end_ = true; + } + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h new file mode 100644 index 0000000000..d5fd063140 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h @@ -0,0 +1,42 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" +#include "storage/direct_load/ob_direct_load_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_multiple_external_row.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_index_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObDirectLoadMultipleHeapTable; + +class ObDirectLoadMultipleHeapTableTabletWholeScanner +{ + typedef ObDirectLoadMultipleExternalRow RowType; + typedef ObDirectLoadDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleHeapTableTabletWholeScanner(); + ~ObDirectLoadMultipleHeapTableTabletWholeScanner(); + int init(ObDirectLoadMultipleHeapTable *heap_table, const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc); + int get_next_row(const RowType *&external_row); + TO_STRING_KV(KP_(heap_table), K_(tablet_id)); +private: + int switch_next_fragment(); +private: + ObDirectLoadMultipleHeapTable *heap_table_; + common::ObTabletID tablet_id_; + ObDirectLoadMultipleHeapTableTabletIndexWholeScanner index_scanner_; + DataBlockReader data_block_reader_; + bool is_iter_end_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.cpp b/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.cpp new file mode 100644 index 0000000000..cc2afeb011 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.cpp @@ -0,0 +1,235 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h" +#include "storage/direct_load/ob_direct_load_external_block_reader.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_mem_sample.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_map.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_builder.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleHeapTableSorter::ObDirectLoadMultipleHeapTableSorter( + ObDirectLoadMemContext *mem_ctx) + : mem_ctx_(mem_ctx), + extra_buf_(nullptr), + index_dir_id_(-1), + data_dir_id_(-1), + heap_table_array_(nullptr), + heap_table_allocator_(nullptr) +{ +} + +ObDirectLoadMultipleHeapTableSorter::~ObDirectLoadMultipleHeapTableSorter() +{ +} + +int ObDirectLoadMultipleHeapTableSorter::init() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(extra_buf_ = static_cast(allocator_.alloc(mem_ctx_->table_data_desc_.extra_buf_size_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate extra buf", KR(ret)); + } + return ret; +} + +int ObDirectLoadMultipleHeapTableSorter::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == table)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(table)); + } else { + ObDirectLoadExternalTable *external_table = nullptr; + if (OB_ISNULL(external_table = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table)); + } else if (OB_UNLIKELY(external_table->get_fragments().count() != 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("files handle should only have one handle", KR(ret)); + } else if (OB_FAIL(fragments_.push_back(external_table->get_fragments()))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableSorter::close_chunk(ObDirectLoadMultipleHeapTableMap *&chunk) +{ + int ret = OB_SUCCESS; + ObArray keys; + ObDirectLoadMultipleHeapTableBuilder table_builder; + ObDirectLoadMultipleHeapTableBuildParam table_builder_param; + table_builder_param.table_data_desc_ = mem_ctx_->table_data_desc_; + table_builder_param.file_mgr_ = mem_ctx_->file_mgr_; + table_builder_param.extra_buf_size_ = mem_ctx_->table_data_desc_.extra_buf_size_; + table_builder_param.extra_buf_ = extra_buf_; + table_builder_param.index_dir_id_ = index_dir_id_; + table_builder_param.data_dir_id_ = data_dir_id_; + if (chunk == nullptr) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("chunk is null", KR(ret)); + } else if (OB_FAIL(table_builder.init(table_builder_param))) { + LOG_WARN("fail to init table builder", KR(ret)); + } else if (OB_FAIL(chunk->get_all_key_sorted(keys))) { + LOG_WARN("fail to get keys", KR(ret)); + } + ObDatumRow datum_row; + + if (OB_SUCC(ret)) { + if (OB_FAIL(datum_row.init(mem_ctx_->column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row.mvcc_row_flag_.set_last_multi_version_row(true); + } + } + + for (int64_t i = 0; OB_SUCC(ret) && i < keys.count(); i ++) { + ObArray bag; + if (OB_FAIL(chunk->get(keys.at(i), bag))) { + LOG_WARN("fail to get bag", KR(ret)); + } + for (int64_t j = 0; OB_SUCC(ret) && j < bag.count(); j ++) { + if (OB_FAIL(bag.at(j)->to_datums(datum_row.storage_datums_, datum_row.count_))) { + LOG_WARN("fail to transfer dataum row", KR(ret)); + } else if (OB_FAIL(table_builder.append_row(keys.at(i), datum_row))) { + LOG_WARN("fail to append row", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(table_builder.close())) { + LOG_WARN("fail to close table builder", KR(ret)); + } else if (OB_FAIL(get_tables(table_builder))) { + LOG_WARN("fail to get tables", KR(ret)); + } + } + + if (chunk != nullptr) { + chunk->~ObDirectLoadMultipleHeapTableMap(); + ob_free(chunk); + chunk = nullptr; + } + return ret; +} + +int ObDirectLoadMultipleHeapTableSorter::get_tables( + ObIDirectLoadPartitionTableBuilder &table_builder) +{ + int ret = OB_SUCCESS; + ObArray table_array; + if (OB_FAIL(table_builder.get_tables(table_array, *heap_table_allocator_))) { + LOG_WARN("fail to get tables", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < table_array.count(); ++i) { + ObIDirectLoadPartitionTable *table = table_array.at(i); + ObDirectLoadMultipleHeapTable *heap_table = nullptr; + if (OB_ISNULL(heap_table = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected table", KR(ret), KPC(table)); + } else if (OB_FAIL(heap_table_array_->push_back(heap_table))) { + LOG_WARN("fail to push back heap table", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleHeapTableSorter::work() +{ + typedef ObDirectLoadExternalMultiPartitionRow RowType; + typedef ObDirectLoadMultipleHeapTableMap ChunkType; + typedef ObDirectLoadExternalBlockReader ExternalReader; + int ret = OB_SUCCESS; + const RowType *row = nullptr; + ObDirectLoadConstExternalMultiPartitionRow const_row; + ChunkType *chunk = nullptr; + + if (OB_UNLIKELY(index_dir_id_ <= 0 || data_dir_id_ <= 0 || nullptr == heap_table_array_ || + nullptr == heap_table_allocator_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K_(index_dir_id), K_(data_dir_id), KP_(heap_table_array), + KP_(heap_table_allocator)); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < fragments_.count(); i++) { + const ObDirectLoadExternalFragment &fragment = fragments_.at(i); + ExternalReader external_reader; + if (OB_FAIL(external_reader.init(mem_ctx_->table_data_desc_.external_data_block_size_, + fragment.max_data_block_size_, + mem_ctx_->table_data_desc_.compressor_type_))) { + LOG_WARN("fail to init external reader", KR(ret)); + } else if (OB_FAIL(external_reader.open(fragment.file_handle_, 0, fragment.file_size_))) { + LOG_WARN("fail to open file", KR(ret)); + } + while (OB_SUCC(ret) && !(mem_ctx_->has_error_)) { + if (row == nullptr) { + if (OB_FAIL(external_reader.get_next_item(row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next item", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } + } + if (OB_SUCC(ret) && chunk == nullptr) { + if (mem_ctx_->has_error_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("some error ocurr", KR(ret)); + } + if (OB_SUCC(ret)) { + chunk = OB_NEW(ChunkType, "TLD_row_chunk", mem_ctx_->table_data_desc_.heap_table_mem_chunk_size_); + if (chunk == nullptr) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate mem", KR(ret)); + } else if (OB_FAIL(chunk->init())) { + LOG_WARN("fail to init external sort", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + const_row = *row; + ret = chunk->add_row(row->tablet_id_, const_row); + if (ret == OB_BUF_NOT_ENOUGH) { + ret = OB_SUCCESS; + if (OB_FAIL(close_chunk(chunk))) { + LOG_WARN("fail to close chunk", KR(ret)); + } + } else if (ret != OB_SUCCESS) { + LOG_WARN("fail to add item", KR(ret)); + } else { + row = nullptr; + } + } + } + } + + if (OB_SUCC(ret)) { + if (chunk != nullptr && OB_FAIL(close_chunk(chunk))) { + LOG_WARN("fail to close chunk", KR(ret)); + } + } + + if (chunk != nullptr) { + chunk->~ObDirectLoadMultipleHeapTableMap(); + ob_free(chunk); + chunk = nullptr; + } + + return ret; +} + + +} +} diff --git a/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h b/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h new file mode 100644 index 0000000000..3f61b9307e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_heap_table_sorter.h @@ -0,0 +1,61 @@ +// Copyright (c) 2018-present Alibaba Inc. All Rights Reserved. +// Author: +// Junquan Chen + +#ifndef OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_SORTER_H_ +#define OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_SORTER_H_ + +#include "storage/direct_load/ob_direct_load_external_fragment.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_mem_context.h" +#include "storage/direct_load/ob_direct_load_mem_worker.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMultipleHeapTable; +class ObDirectLoadMultipleHeapTableMap; + +class ObDirectLoadMultipleHeapTableSorter : public ObDirectLoadMemWorker +{ +public: + ObDirectLoadMultipleHeapTableSorter(ObDirectLoadMemContext *mem_ctx); + virtual ~ObDirectLoadMultipleHeapTableSorter(); + + int init(); + int add_table(ObIDirectLoadPartitionTable *table) override; + void set_work_param(int64_t index_dir_id, int64_t data_dir_id, + common::ObIArray &heap_table_array, + common::ObIAllocator &heap_table_allocator) + { + index_dir_id_ = index_dir_id; + data_dir_id_ = data_dir_id; + heap_table_array_ = &heap_table_array; + heap_table_allocator_ = &heap_table_allocator; + } + int work() override; + VIRTUAL_TO_STRING_KV(KP(mem_ctx_), K_(fragments)); + +private: + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadMultipleHeapTableSorter); + + int close_chunk(ObDirectLoadMultipleHeapTableMap *&chunk); + int get_tables(ObIDirectLoadPartitionTableBuilder &table_builder); + +private: + // data members + ObDirectLoadMemContext *mem_ctx_; + ObDirectLoadExternalFragmentArray fragments_; + ObArenaAllocator allocator_; + char *extra_buf_; + int64_t index_dir_id_; + int64_t data_dir_id_; + common::ObIArray *heap_table_array_; + common::ObIAllocator *heap_table_allocator_; +}; + +} +} + +#endif /* OB_DIRECT_LOAD_MULTIPLE_HEAP_TABLE_SORTER_H_ */ diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable.cpp new file mode 100644 index 0000000000..8ed48ad586 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable.cpp @@ -0,0 +1,334 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleSSTableFragment + */ + +ObDirectLoadMultipleSSTableFragment::ObDirectLoadMultipleSSTableFragment() + : index_block_count_(0), + data_block_count_(0), + index_file_size_(0), + data_file_size_(0), + row_count_(0), + max_data_block_size_(0) +{ +} + +ObDirectLoadMultipleSSTableFragment::~ObDirectLoadMultipleSSTableFragment() +{ +} + +int ObDirectLoadMultipleSSTableFragment::assign(const ObDirectLoadMultipleSSTableFragment &other) +{ + int ret = OB_SUCCESS; + index_block_count_ = other.index_block_count_; + data_block_count_ = other.data_block_count_; + index_file_size_ = other.index_file_size_; + data_file_size_ = other.data_file_size_; + row_count_ = other.row_count_; + max_data_block_size_ = other.max_data_block_size_; + if (OB_FAIL(index_file_handle_.assign(other.index_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else if (OB_FAIL(data_file_handle_.assign(other.data_file_handle_))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableCreateParam + */ + +ObDirectLoadMultipleSSTableCreateParam::ObDirectLoadMultipleSSTableCreateParam() + : rowkey_column_num_(0), + column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_block_count_(0), + data_block_count_(0), + row_count_(0), + max_data_block_size_(0) +{ +} + +ObDirectLoadMultipleSSTableCreateParam::~ObDirectLoadMultipleSSTableCreateParam() +{ +} + +bool ObDirectLoadMultipleSSTableCreateParam::is_valid() const +{ + return column_count_ > 0 && index_block_size_ > 0 && index_block_size_ % DIO_ALIGN_SIZE == 0 && + data_block_size_ > 0 && data_block_size_ % DIO_ALIGN_SIZE == 0 && + max_data_block_size_ > 0 && max_data_block_size_ % DIO_ALIGN_SIZE == 0 && row_count_ > 0 && + !start_key_.is_min_rowkey() && start_key_.is_valid() && !end_key_.is_min_rowkey() && + end_key_.is_valid(); +} + +/** + * ObDirectLoadMultipleSSTableMeta + */ + +ObDirectLoadMultipleSSTableMeta::ObDirectLoadMultipleSSTableMeta() + : rowkey_column_num_(0), + column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_block_count_(0), + data_block_count_(0), + row_count_(0), + max_data_block_size_(0) +{ +} + +ObDirectLoadMultipleSSTableMeta::~ObDirectLoadMultipleSSTableMeta() +{ +} + +void ObDirectLoadMultipleSSTableMeta::reset() +{ + rowkey_column_num_ = 0; + column_count_ = 0; + index_block_size_ = 0; + data_block_size_ = 0; + index_block_count_ = 0; + data_block_count_ = 0; + row_count_ = 0; + max_data_block_size_ = 0; +} + +/** + * ObDirectLoadMultipleSSTable + */ + +ObDirectLoadMultipleSSTable::ObDirectLoadMultipleSSTable() + : allocator_("TLD_MSSTable"), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTable::~ObDirectLoadMultipleSSTable() +{ +} + +void ObDirectLoadMultipleSSTable::reset() +{ + meta_.reset(); + start_key_.reset(); + end_key_.reset(); + fragments_.reset(); + is_inited_ = false; +} + +int ObDirectLoadMultipleSSTable::init(const ObDirectLoadMultipleSSTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTable init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + allocator_.set_tenant_id(MTL_ID()); + meta_.rowkey_column_num_ = param.rowkey_column_num_; + meta_.column_count_ = param.column_count_; + meta_.index_block_size_ = param.index_block_size_; + meta_.data_block_size_ = param.data_block_size_; + meta_.index_block_count_ = param.index_block_count_; + meta_.data_block_count_ = param.data_block_count_; + meta_.row_count_ = param.row_count_; + meta_.max_data_block_size_ = param.max_data_block_size_; + if (OB_FAIL(start_key_.deep_copy(param.start_key_, allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(end_key_.deep_copy(param.end_key_, allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(fragments_.assign(param.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTable::copy(const ObDirectLoadMultipleSSTable &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + meta_ = other.meta_; + if (OB_FAIL(start_key_.deep_copy(other.start_key_, allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(end_key_.deep_copy(other.end_key_, allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(fragments_.assign(other.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +ObDirectLoadMultipleSSTable::IndexBlockIterator ObDirectLoadMultipleSSTable::index_block_begin() +{ + IndexBlockIterator iter; + iter.sstable_ = this; + iter.fragment_idx_ = 0; + iter.index_block_idx_ = 0; + return iter; +} + +ObDirectLoadMultipleSSTable::IndexBlockIterator ObDirectLoadMultipleSSTable::index_block_end() +{ + IndexBlockIterator iter; + iter.sstable_ = this; + iter.fragment_idx_ = fragments_.count(); + iter.index_block_idx_ = 0; + return iter; +} + +ObDirectLoadMultipleSSTable::IndexEntryIterator ObDirectLoadMultipleSSTable::index_entry_begin() +{ + IndexEntryIterator iter; + iter.sstable_ = this; + iter.fragment_idx_ = 0; + iter.index_entry_idx_ = 0; + return iter; +} + +ObDirectLoadMultipleSSTable::IndexEntryIterator ObDirectLoadMultipleSSTable::index_entry_end() +{ + IndexEntryIterator iter; + iter.sstable_ = this; + iter.fragment_idx_ = fragments_.count(); + iter.index_entry_idx_ = 0; + return iter; +} + +int ObDirectLoadMultipleSSTable::scan(const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, + const ObStorageDatumUtils *datum_utils, + ObIAllocator &allocator, + ObDirectLoadMultipleSSTableScanner *&scanner) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTable not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!table_data_desc.is_valid() || !range.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(table_data_desc), K(range), KP(datum_utils)); + } else { + scanner = nullptr; + if (OB_ISNULL(scanner = OB_NEWx(ObDirectLoadMultipleSSTableScanner, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableScanner", KR(ret)); + } else if (OB_FAIL(scanner->init(this, table_data_desc, range, datum_utils))) { + LOG_WARN("fail to init multiple sstable scanner", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != scanner) { + scanner->~ObDirectLoadMultipleSSTableScanner(); + allocator.free(scanner); + scanner = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTable::scan_whole_index_block_meta( + const ObDirectLoadTableDataDesc &table_data_desc, + ObIAllocator &allocator, + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *&meta_iter) +{ + int ret = OB_SUCCESS; + meta_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTable not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(table_data_desc)); + } else { + ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner *whole_scanner = nullptr; + if (OB_ISNULL(whole_scanner = + OB_NEWx(ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner", KR(ret)); + } else if (OB_FAIL(whole_scanner->init(this, table_data_desc))) { + LOG_WARN("fail to init multiple sstable index block meta scanner", KR(ret)); + } else { + meta_iter = whole_scanner; + } + if (OB_FAIL(ret)) { + if (nullptr != whole_scanner) { + whole_scanner->~ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner(); + allocator.free(whole_scanner); + whole_scanner = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTable::scan_tablet_whole_index_block_meta( + const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils, + ObIAllocator &allocator, + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *&meta_iter) +{ + int ret = OB_SUCCESS; + meta_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTable not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || !table_data_desc.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), K(table_data_desc), KP(datum_utils)); + } else { + ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner *tablet_whole_scanner = nullptr; + if (OB_ISNULL(tablet_whole_scanner = OB_NEWx( + ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner", KR(ret)); + } else if (OB_FAIL(tablet_whole_scanner->init(this, tablet_id, table_data_desc, datum_utils))) { + LOG_WARN("fail to init multiple sstable index block meta scanner", KR(ret)); + } else { + meta_iter = tablet_whole_scanner; + } + if (OB_FAIL(ret)) { + if (nullptr != tablet_whole_scanner) { + tablet_whole_scanner->~ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner(); + allocator.free(tablet_whole_scanner); + tablet_whole_scanner = nullptr; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable.h b/src/storage/direct_load/ob_direct_load_multiple_sstable.h new file mode 100644 index 0000000000..6086296562 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable.h @@ -0,0 +1,134 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_iterator.h" +#include "storage/direct_load/ob_direct_load_sstable_index_entry_iterator.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObDirectLoadMultipleDatumRange; +class ObDirectLoadMultipleSSTableScanner; +class ObDirectLoadMultipleSSTableIndexBlockMetaIterator; + +struct ObDirectLoadMultipleSSTableFragment +{ +public: + ObDirectLoadMultipleSSTableFragment(); + ~ObDirectLoadMultipleSSTableFragment(); + int assign(const ObDirectLoadMultipleSSTableFragment &other); + TO_STRING_KV(K_(index_block_count), K_(data_block_count), K_(index_file_size), K_(data_file_size), + K_(row_count), K_(max_data_block_size), K_(index_file_handle), K_(data_file_handle)); +public: + int64_t index_block_count_; + int64_t data_block_count_; + int64_t index_file_size_; + int64_t data_file_size_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadTmpFileHandle index_file_handle_; + ObDirectLoadTmpFileHandle data_file_handle_; +}; + +struct ObDirectLoadMultipleSSTableCreateParam +{ +public: + ObDirectLoadMultipleSSTableCreateParam(); + ~ObDirectLoadMultipleSSTableCreateParam(); + bool is_valid() const; + TO_STRING_KV(K_(rowkey_column_num), K_(column_count), K_(index_block_size), K_(data_block_size), + K_(index_block_count), K_(data_block_count), K_(row_count), K_(max_data_block_size), + K_(start_key), K_(end_key), K_(fragments)); +public: + int64_t rowkey_column_num_; + int64_t column_count_; + int64_t index_block_size_; + int64_t data_block_size_; + int64_t index_block_count_; + int64_t data_block_count_; + int64_t row_count_; + int64_t max_data_block_size_; + ObDirectLoadMultipleDatumRowkey start_key_; + ObDirectLoadMultipleDatumRowkey end_key_; + common::ObArray fragments_; +}; + +struct ObDirectLoadMultipleSSTableMeta +{ +public: + ObDirectLoadMultipleSSTableMeta(); + ~ObDirectLoadMultipleSSTableMeta(); + void reset(); + TO_STRING_KV(K_(rowkey_column_num), K_(column_count), K_(index_block_size), K_(data_block_size), + K_(index_block_count), K_(data_block_count), K_(row_count), K_(max_data_block_size)); +public: + int64_t rowkey_column_num_; + int64_t column_count_; + int64_t index_block_size_; + int64_t data_block_size_; + int64_t index_block_count_; + int64_t data_block_count_; // same as index entry count + int64_t row_count_; + int64_t max_data_block_size_; +}; + +class ObDirectLoadMultipleSSTable : public ObIDirectLoadPartitionTable +{ +public: + typedef ObDirectLoadMultipleSSTableFragment Fragment; + typedef ObDirectLoadSSTableIndexBlockIterator IndexBlockIterator; + typedef ObDirectLoadSSTableIndexEntryIterator IndexEntryIterator; + ObDirectLoadMultipleSSTable(); + virtual ~ObDirectLoadMultipleSSTable(); + void reset(); + int init(const ObDirectLoadMultipleSSTableCreateParam ¶m); + const common::ObTabletID &get_tablet_id() const override { return tablet_id_; } + int64_t get_row_count() const override { return meta_.row_count_; } + bool is_valid() const override { return is_inited_; } + int copy(const ObDirectLoadMultipleSSTable &other); + bool is_empty() const { return 0 == meta_.row_count_; } + const ObDirectLoadMultipleSSTableMeta &get_meta() const { return meta_; } + const ObDirectLoadMultipleDatumRowkey &get_start_key() const { return start_key_; } + const ObDirectLoadMultipleDatumRowkey &get_end_key() const { return end_key_; } + const common::ObIArray &get_fragments() const + { + return fragments_; + } + IndexBlockIterator index_block_begin(); + IndexBlockIterator index_block_end(); + IndexEntryIterator index_entry_begin(); + IndexEntryIterator index_entry_end(); + int scan(const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, + const blocksstable::ObStorageDatumUtils *datum_utils, common::ObIAllocator &allocator, + ObDirectLoadMultipleSSTableScanner *&scanner); + int scan_whole_index_block_meta(const ObDirectLoadTableDataDesc &table_data_desc, + common::ObIAllocator &allocator, + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *&meta_iter); + int scan_tablet_whole_index_block_meta( + const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils, + common::ObIAllocator &allocator, + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *&meta_iter); + TO_STRING_KV(K_(meta), K_(start_key), K_(end_key), K_(fragments)); +private: + common::ObArenaAllocator allocator_; + common::ObTabletID tablet_id_; // invalid + ObDirectLoadMultipleSSTableMeta meta_; + ObDirectLoadMultipleDatumRowkey start_key_; + ObDirectLoadMultipleDatumRowkey end_key_; + common::ObArray fragments_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.cpp new file mode 100644 index 0000000000..a03148c241 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.cpp @@ -0,0 +1,305 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_builder.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/* + * ObDirectLoadMultipleSSTableBuildParam + */ + +ObDirectLoadMultipleSSTableBuildParam::ObDirectLoadMultipleSSTableBuildParam() + : datum_utils_(nullptr), file_mgr_(nullptr), extra_buf_(nullptr), extra_buf_size_(0) +{ +} + +ObDirectLoadMultipleSSTableBuildParam::~ObDirectLoadMultipleSSTableBuildParam() +{ +} + +bool ObDirectLoadMultipleSSTableBuildParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != datum_utils_ && nullptr != file_mgr_ && + nullptr != extra_buf_ && extra_buf_size_ > 0 && extra_buf_size_ % DIO_ALIGN_SIZE == 0; +} + +/** + * DataBlockFlushCallback + */ + +ObDirectLoadMultipleSSTableBuilder::DataBlockFlushCallback::DataBlockFlushCallback() + : index_block_writer_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableBuilder::DataBlockFlushCallback::~DataBlockFlushCallback() +{ +} + +int ObDirectLoadMultipleSSTableBuilder::DataBlockFlushCallback::init( + ObDirectLoadSSTableIndexBlockWriter *index_block_writer) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("DataBlockFlushCallback init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == index_block_writer)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(index_block_writer)); + } else { + index_block_writer_ = index_block_writer; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::DataBlockFlushCallback::write(char *buf, int64_t buf_size, + int64_t offset) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("DataBlockFlushCallback not init", KR(ret), KP(this)); + } else { + ObDirectLoadSSTableIndexEntry entry; + entry.offset_ = offset; + entry.size_ = buf_size; + if (OB_FAIL(index_block_writer_->append_entry(entry))) { + LOG_WARN("fail to append entry", KR(ret)); + } + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableBuilder + */ + +ObDirectLoadMultipleSSTableBuilder::ObDirectLoadMultipleSSTableBuilder() + : allocator_("TLD_MSST_Build"), + last_rowkey_allocator_("TLD_LastPK"), + row_count_(0), + is_closed_(false), + is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableBuilder::~ObDirectLoadMultipleSSTableBuilder() +{ +} + +int ObDirectLoadMultipleSSTableBuilder::init(const ObDirectLoadMultipleSSTableBuildParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + allocator_.set_tenant_id(MTL_ID()); + last_rowkey_allocator_.set_tenant_id(MTL_ID()); + int64_t dir_id = -1; + if (OB_FAIL(param_.file_mgr_->alloc_dir(dir_id))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } else if (OB_FAIL(param_.file_mgr_->alloc_file(dir_id, index_file_handle_))) { + LOG_WARN("fail to alloc file", KR(ret)); + } else if (OB_FAIL(param_.file_mgr_->alloc_file(dir_id, data_file_handle_))) { + LOG_WARN("fail to alloc file", KR(ret)); + } else if (OB_FAIL(index_block_writer_.init(param_.table_data_desc_.sstable_index_block_size_, + ObCompressorType::NONE_COMPRESSOR))) { + LOG_WARN("fail to init index block writer", KR(ret)); + } else if (OB_FAIL(callback_.init(&index_block_writer_))) { + LOG_WARN("fail to init data block callback", KR(ret)); + } else if (OB_FAIL(data_block_writer_.init(param_.table_data_desc_.sstable_data_block_size_, + param_.table_data_desc_.compressor_type_, + param_.extra_buf_, param_.extra_buf_size_, + &callback_))) { + LOG_WARN("fail to init data block writer", KR(ret)); + } else if (OB_FAIL(index_block_writer_.open(index_file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else if (OB_FAIL(data_block_writer_.open(data_file_handle_))) { + LOG_WARN("fail to open file", KR(ret)); + } else { + first_rowkey_.set_min_rowkey(); + last_rowkey_.set_min_rowkey(); + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple sstable builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!datum_row.is_valid() || + datum_row.get_column_count() != param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(datum_row)); + } else { + if (OB_FAIL(row_.from_datums(tablet_id, datum_row.storage_datums_, datum_row.count_, + param_.table_data_desc_.rowkey_column_num_))) { + LOG_WARN("fail to from datum row", KR(ret)); + } else if (OB_FAIL(append_row(row_))) { + LOG_WARN("fail to append row", KR(ret), K(row_)); + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::append_row(const RowType &row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple sstable builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!row.is_valid() || row.rowkey_.datum_array_.count_ != + param_.table_data_desc_.rowkey_column_num_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(row)); + } else { + if (OB_FAIL(check_rowkey_order(row.rowkey_))) { + LOG_WARN("fail to check rowkey order", KR(ret), K(row.rowkey_)); + } else if (OB_FAIL(data_block_writer_.append_row(row))) { + LOG_WARN("fail to append row", KR(ret)); + } else if (OB_FAIL(save_last_rowkey(row.rowkey_))) { + LOG_WARN("fail to save rowkey", KR(ret), K(row.rowkey_)); + } else if (first_rowkey_.is_min_rowkey() && + OB_FAIL(first_rowkey_.deep_copy(row.rowkey_, allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else { + ++row_count_; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::check_rowkey_order(const RowkeyType &rowkey) const +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (OB_FAIL(rowkey.compare(last_rowkey_, *param_.datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (OB_UNLIKELY(0 == cmp_ret)) { + ret = OB_ERR_PRIMARY_KEY_DUPLICATE; + LOG_WARN("rowkey duplicate", KR(ret), K(last_rowkey_), K(rowkey)); + } else if (OB_UNLIKELY(cmp_ret < 0)) { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_WARN("rowkey order error", KR(ret), K(last_rowkey_), K(rowkey)); + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::save_last_rowkey(const RowkeyType &rowkey) +{ + int ret = OB_SUCCESS; + last_rowkey_allocator_.reuse(); + if (OB_FAIL(last_rowkey_.deep_copy(rowkey, last_rowkey_allocator_))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple sstable builder is closed", KR(ret)); + } else { + if (OB_FAIL(data_block_writer_.close())) { + LOG_WARN("fail to close data block writer", KR(ret)); + } else if (OB_FAIL(index_block_writer_.close())) { + LOG_WARN("fail to close index block writer", KR(ret)); + } else { + is_closed_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableBuilder::get_tables( + ObIArray &table_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("multiple sstable builder is not closed", KR(ret)); + } else { + ObDirectLoadMultipleSSTableFragment fragment; + ObDirectLoadMultipleSSTableCreateParam create_param; + fragment.index_block_count_ = index_block_writer_.get_block_count(); + fragment.data_block_count_ = data_block_writer_.get_block_count(); + fragment.index_file_size_ = index_block_writer_.get_file_size(); + fragment.data_file_size_ = data_block_writer_.get_file_size(); + fragment.row_count_ = row_count_; + fragment.max_data_block_size_ = data_block_writer_.get_max_block_size(); + create_param.rowkey_column_num_ = param_.table_data_desc_.rowkey_column_num_; + create_param.column_count_ = param_.table_data_desc_.column_count_; + create_param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + create_param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + create_param.index_block_count_ = index_block_writer_.get_block_count(); + create_param.data_block_count_ = data_block_writer_.get_block_count(); + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = data_block_writer_.get_max_block_size(); + create_param.start_key_ = first_rowkey_; + create_param.end_key_ = last_rowkey_; + if (OB_FAIL(fragment.index_file_handle_.assign(index_file_handle_))) { + LOG_WARN("fail to assign index file handle", KR(ret)); + } else if (OB_FAIL(fragment.data_file_handle_.assign(data_file_handle_))) { + LOG_WARN("fail to assign data file handle", KR(ret)); + } else if (OB_FAIL(create_param.fragments_.push_back(fragment))) { + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_SUCC(ret)) { + ObDirectLoadMultipleSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = OB_NEWx(ObDirectLoadMultipleSSTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTable", KR(ret)); + } else if (OB_FAIL(sstable->init(create_param))) { + LOG_WARN("fail to init sstable", KR(ret), K(create_param)); + } else if (OB_FAIL(table_array.push_back(sstable))) { + LOG_WARN("fail to push back ssstable", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != sstable) { + sstable->~ObDirectLoadMultipleSSTable(); + allocator.free(sstable); + sstable = nullptr; + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.h new file mode 100644 index 0000000000..8451725d9f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_builder.h @@ -0,0 +1,83 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "common/ob_tablet_id.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_writer.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_writer.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTmpFileManager; + +struct ObDirectLoadMultipleSSTableBuildParam +{ +public: + ObDirectLoadMultipleSSTableBuildParam(); + ~ObDirectLoadMultipleSSTableBuildParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(datum_utils), KP_(file_mgr)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadTmpFileManager *file_mgr_; + char *extra_buf_; + int64_t extra_buf_size_; +}; + +class ObDirectLoadMultipleSSTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ + typedef ObDirectLoadMultipleDatumRowkey RowkeyType; + typedef ObDirectLoadMultipleDatumRow RowType; +public: + ObDirectLoadMultipleSSTableBuilder(); + virtual ~ObDirectLoadMultipleSSTableBuilder(); + int init(const ObDirectLoadMultipleSSTableBuildParam ¶m); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int append_row(const RowType &row); + int close() override; + int64_t get_row_count() const override { return row_count_; } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + int check_rowkey_order(const RowkeyType &rowkey) const; + int save_last_rowkey(const RowkeyType &rowkey); +private: + class DataBlockFlushCallback : public ObIDirectLoadDataBlockFlushCallback + { + public: + DataBlockFlushCallback(); + virtual ~DataBlockFlushCallback(); + int init(ObDirectLoadSSTableIndexBlockWriter *index_block_writer); + int write(char *buf, int64_t buf_size, int64_t offset) override; + private: + ObDirectLoadSSTableIndexBlockWriter *index_block_writer_; + bool is_inited_; + }; +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMultipleSSTableBuildParam param_; + RowType row_; + RowkeyType first_rowkey_; + RowkeyType last_rowkey_; + common::ObArenaAllocator last_rowkey_allocator_; + ObDirectLoadTmpFileHandle index_file_handle_; + ObDirectLoadTmpFileHandle data_file_handle_; + ObDirectLoadSSTableIndexBlockWriter index_block_writer_; + ObDirectLoadSSTableDataBlockWriter data_block_writer_; + DataBlockFlushCallback callback_; + int64_t row_count_; + bool is_closed_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.cpp new file mode 100644 index 0000000000..c12bb0d71e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_compactor.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleSSTableCompactParam + */ + +ObDirectLoadMultipleSSTableCompactParam::ObDirectLoadMultipleSSTableCompactParam() + : datum_utils_(nullptr) +{ +} + +ObDirectLoadMultipleSSTableCompactParam::~ObDirectLoadMultipleSSTableCompactParam() +{ +} + +bool ObDirectLoadMultipleSSTableCompactParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != datum_utils_; +} + +/** + * ObDirectLoadMultipleSSTableCompactor + */ + +ObDirectLoadMultipleSSTableCompactor::ObDirectLoadMultipleSSTableCompactor() + : index_block_count_(0), + data_block_count_(0), + row_count_(0), + max_data_block_size_(0), + is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableCompactor::~ObDirectLoadMultipleSSTableCompactor() +{ +} + +int ObDirectLoadMultipleSSTableCompactor::init(const ObDirectLoadMultipleSSTableCompactParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableCompactor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + start_key_.set_min_rowkey(); + end_key_.set_min_rowkey(); + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMultipleSSTableCompactor::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableCompactor not init", KR(ret), KP(this)); + } else { + int cmp_ret = 0; + ObDirectLoadMultipleSSTable *sstable = dynamic_cast(table); + if (OB_ISNULL(sstable)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(sstable)); + } else if (OB_FAIL(check_table_compactable(sstable))) { + LOG_WARN("fail to check table compactable", KR(ret), KPC(sstable)); + } else if (!sstable->is_empty()) { + const ObDirectLoadMultipleSSTableMeta &table_meta = sstable->get_meta(); + index_block_count_ += table_meta.index_block_count_; + data_block_count_ += table_meta.data_block_count_; + row_count_ += table_meta.row_count_; + max_data_block_size_ = MAX(max_data_block_size_, table_meta.max_data_block_size_); + for (int64_t i = 0; OB_SUCC(ret) && i < sstable->get_fragments().count(); ++i) { + if (OB_FAIL(fragments_.push_back(sstable->get_fragments().at(i)))) { + LOG_WARN("fail to push back table fragment", KR(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + end_key_allocator_.reuse(); + if (start_key_.is_min_rowkey() && + OB_FAIL(start_key_.deep_copy(sstable->get_start_key(), start_key_allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(end_key_.deep_copy(sstable->get_end_key(), end_key_allocator_))) { + LOG_WARN("fail to deep copy end key", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableCompactor::check_table_compactable( + ObDirectLoadMultipleSSTable *sstable) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + const ObDirectLoadMultipleSSTableMeta &table_meta = sstable->get_meta(); + if (OB_UNLIKELY( + table_meta.rowkey_column_num_ != param_.table_data_desc_.rowkey_column_num_ || + table_meta.column_count_ != param_.table_data_desc_.column_count_ || + table_meta.index_block_size_ != param_.table_data_desc_.sstable_index_block_size_ || + table_meta.data_block_size_ != param_.table_data_desc_.sstable_data_block_size_)) { + ret = OB_ITEM_NOT_MATCH; + LOG_WARN("table meta not match", KR(ret), K(param_), K(table_meta)); + } else if (!sstable->is_empty()) { + int cmp_ret = 0; + if (OB_FAIL(end_key_.compare(sstable->get_start_key(), *param_.datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret >= 0) { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_WARN("sstable is not contiguous", KR(ret), K(end_key_), K(sstable->get_start_key())); + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableCompactor::compact() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableCompactor not init", KR(ret), KP(this)); + } else { + // do nothing + } + return ret; +} + +int ObDirectLoadMultipleSSTableCompactor::get_table(ObIDirectLoadPartitionTable *&table, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableCompactor not init", KR(ret), KP(this)); + } else { + ObDirectLoadMultipleSSTable *sstable = nullptr; + ObDirectLoadMultipleSSTableCreateParam create_param; + create_param.rowkey_column_num_ = param_.table_data_desc_.rowkey_column_num_; + create_param.column_count_ = param_.table_data_desc_.column_count_; + create_param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + create_param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + create_param.index_block_count_ = index_block_count_; + create_param.data_block_count_ = data_block_count_; + create_param.row_count_ = row_count_; + create_param.max_data_block_size_ = max_data_block_size_; + create_param.start_key_ = start_key_; + create_param.end_key_ = end_key_; + if (OB_FAIL(create_param.fragments_.assign(fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else if (OB_ISNULL(sstable = OB_NEWx(ObDirectLoadMultipleSSTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTable", KR(ret)); + } else if (OB_FAIL(sstable->init(create_param))) { + LOG_WARN("fail to init sstable table", KR(ret)); + } else { + table = sstable; + } + if (OB_FAIL(ret)) { + if (nullptr != sstable) { + sstable->~ObDirectLoadMultipleSSTable(); + allocator.free(sstable); + sstable = nullptr; + } + } + } + return ret; +} + +void ObDirectLoadMultipleSSTableCompactor::stop() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.h new file mode 100644 index 0000000000..b92846bdd6 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_compactor.h @@ -0,0 +1,55 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadMultipleSSTableCompactParam +{ +public: + ObDirectLoadMultipleSSTableCompactParam(); + ~ObDirectLoadMultipleSSTableCompactParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(datum_utils)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; +}; + +class ObDirectLoadMultipleSSTableCompactor : public ObIDirectLoadTabletTableCompactor +{ +public: + ObDirectLoadMultipleSSTableCompactor(); + virtual ~ObDirectLoadMultipleSSTableCompactor(); + int init(const ObDirectLoadMultipleSSTableCompactParam ¶m); + int add_table(ObIDirectLoadPartitionTable *table) override; + int compact() override; + int get_table(ObIDirectLoadPartitionTable *&table, common::ObIAllocator &allocator) override; + void stop() override; +private: + int check_table_compactable(ObDirectLoadMultipleSSTable *sstable); +private: + ObDirectLoadMultipleSSTableCompactParam param_; + int64_t index_block_count_; + int64_t data_block_count_; + int64_t row_count_; + int64_t max_data_block_size_; + common::ObArenaAllocator start_key_allocator_; + common::ObArenaAllocator end_key_allocator_; + ObDirectLoadMultipleDatumRowkey start_key_; + ObDirectLoadMultipleDatumRowkey end_key_; + common::ObArray fragments_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.cpp new file mode 100644 index 0000000000..fb28afc170 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.cpp @@ -0,0 +1,239 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleSSTableDataBlockScanner::ObDirectLoadMultipleSSTableDataBlockScanner() + : sstable_(nullptr), + range_(nullptr), + datum_utils_(nullptr), + left_data_block_offset_(0), + right_data_block_offset_(0), + is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableDataBlockScanner::~ObDirectLoadMultipleSSTableDataBlockScanner() +{ +} + +int ObDirectLoadMultipleSSTableDataBlockScanner::init( + ObDirectLoadMultipleSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableDataBlockScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid() || + !table_data_desc.is_valid() || !range.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable), K(table_data_desc), K(range), KP(datum_utils)); + } else { + sstable_ = sstable; + range_ = ⦥ + datum_utils_ = datum_utils; + IndexBlockReader index_block_reader; + DataBlockReader data_block_reader; + if (OB_FAIL(index_block_reader.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to index block reader", KR(ret)); + } else if (OB_FAIL(data_block_reader.init(table_data_desc.sstable_data_block_size_, + sstable->get_meta().max_data_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to data block reader", KR(ret)); + } else if (OB_FAIL(locate_left_border(index_block_reader, data_block_reader))) { + LOG_WARN("fail to locate left border", KR(ret)); + } else if (OB_FAIL(locate_right_border(index_block_reader, data_block_reader))) { + LOG_WARN("fail to locate right border", KR(ret)); + } else if (OB_UNLIKELY(left_index_entry_iter_ > right_index_entry_iter_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected locate result", KR(ret), K(left_index_entry_iter_), + K(right_index_entry_iter_)); + } else { + current_index_entry_iter_ = left_index_entry_iter_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableDataBlockScanner::locate_left_border( + IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (range_->start_key_.is_min_rowkey()) { + left_index_entry_iter_ = sstable_->index_entry_begin(); + left_data_block_offset_ = 0; + } else if (OB_FAIL( + range_->start_key_.compare(sstable_->get_start_key(), *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret < 0 || + (cmp_ret == 0 && range_->is_left_closed())) { // range.start_key_ < sstable + left_index_entry_iter_ = sstable_->index_entry_begin(); + left_data_block_offset_ = 0; + } else if (OB_FAIL(range_->start_key_.compare(sstable_->get_end_key(), *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret > 0 || + (cmp_ret == 0 && range_->is_left_open())) { // range.start_key_ > sstable + left_index_entry_iter_ = sstable_->index_entry_end(); + left_data_block_offset_ = 0; + } else { + // locate left border index entry + ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare compare( + ret, sstable_, datum_utils_, index_block_reader, data_block_reader); + if (range_->is_left_open()) { + // start_key < entry_last_key + left_index_entry_iter_ = std::upper_bound( + sstable_->index_entry_begin(), sstable_->index_entry_end(), range_->start_key_, compare); + } else { + // start_key <= entry_last_key + left_index_entry_iter_ = std::lower_bound( + sstable_->index_entry_begin(), sstable_->index_entry_end(), range_->start_key_, compare); + } + if (OB_FAIL(ret)) { + } else if (left_index_entry_iter_ == sstable_->index_entry_end()) { + left_data_block_offset_ = 0; + } else { + // read entry + const int64_t entries_per_block = ObDirectLoadSSTableIndexBlock::get_entries_per_block( + sstable_->get_meta().index_block_size_); + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(left_index_entry_iter_.fragment_idx_); + const int64_t index_block_idx = left_index_entry_iter_.index_entry_idx_ / entries_per_block; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = left_index_entry_iter_.index_entry_idx_ % entries_per_block; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + index_block_reader.reuse(); + if (OB_FAIL(index_block_reader.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else { + left_data_block_offset_ = entry->offset_; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableDataBlockScanner::locate_right_border( + IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader) +{ + int ret = OB_SUCCESS; + int cmp_ret = 0; + if (range_->end_key_.is_max_rowkey()) { + right_index_entry_iter_ = sstable_->index_entry_end(); + right_data_block_offset_ = 0; + } else if (OB_FAIL(range_->end_key_.compare(sstable_->get_start_key(), *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret < 0 || (cmp_ret == 0 && range_->is_right_open())) { // range.end_key_ < sstable + right_index_entry_iter_ = sstable_->index_entry_begin(); + right_data_block_offset_ = 0; + } else if (OB_FAIL(range_->end_key_.compare(sstable_->get_end_key(), *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret > 0 || + (cmp_ret == 0 && range_->is_right_closed())) { // range.end_key_ > sstable + right_index_entry_iter_ = sstable_->index_entry_end(); + right_data_block_offset_ = 0; + } else { + // locate right border index entry + ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare compare( + ret, sstable_, datum_utils_, index_block_reader, data_block_reader); + if (range_->is_right_closed()) { + // range.end_key < entry_first_key + right_index_entry_iter_ = std::upper_bound( + sstable_->index_entry_begin(), sstable_->index_entry_end(), range_->end_key_, compare); + } else { + // range.end_key <= entry_first_key + right_index_entry_iter_ = std::lower_bound( + sstable_->index_entry_begin(), sstable_->index_entry_end(), range_->end_key_, compare); + } + if (OB_FAIL(ret)) { + } else if (right_index_entry_iter_ == sstable_->index_entry_end()) { + right_data_block_offset_ = 0; + } else { + // read entry + const int64_t entries_per_block = ObDirectLoadSSTableIndexBlock::get_entries_per_block( + sstable_->get_meta().index_block_size_); + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(right_index_entry_iter_.fragment_idx_); + const int64_t index_block_idx = right_index_entry_iter_.index_entry_idx_ / entries_per_block; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = right_index_entry_iter_.index_entry_idx_ % entries_per_block; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + index_block_reader.reuse(); + if (OB_FAIL(index_block_reader.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else { + right_data_block_offset_ = entry->offset_; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableDataBlockScanner::get_next_data_block( + ObDirectLoadSSTableDataBlockDesc &data_block_desc) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableDataBlockScanner not init", KR(ret), KP(this)); + } else if (current_index_entry_iter_ == right_index_entry_iter_) { + ret = OB_ITER_END; + } else { + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(current_index_entry_iter_.fragment_idx_); + ObDirectLoadMultipleSSTable::IndexEntryIterator next_index_entry_iter; + if (current_index_entry_iter_.fragment_idx_ + 1 > right_index_entry_iter_.fragment_idx_) { + next_index_entry_iter = right_index_entry_iter_; + } else { + next_index_entry_iter.sstable_ = sstable_; + next_index_entry_iter.fragment_idx_ = current_index_entry_iter_.fragment_idx_ + 1; + next_index_entry_iter.index_entry_idx_ = 0; + } + // set data_block_desc + data_block_desc.fragment_idx_ = current_index_entry_iter_.fragment_idx_; + data_block_desc.offset_ = + (current_index_entry_iter_.fragment_idx_ == left_index_entry_iter_.fragment_idx_ + ? left_data_block_offset_ + : 0); + data_block_desc.size_ = + (current_index_entry_iter_.fragment_idx_ == right_index_entry_iter_.fragment_idx_ + ? right_data_block_offset_ + : fragment.data_file_size_) - + data_block_desc.offset_; + data_block_desc.block_count_ = (next_index_entry_iter - current_index_entry_iter_); + data_block_desc.is_left_border_ = (current_index_entry_iter_ == left_index_entry_iter_); + data_block_desc.is_right_border_ = (next_index_entry_iter == right_index_entry_iter_); + // next fragment + current_index_entry_iter_ = next_index_entry_iter; + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h new file mode 100644 index 0000000000..cfacf553e7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h @@ -0,0 +1,48 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMultipleDatumRange; +class ObDirectLoadMultipleDatumRow; +class ObDirectLoadSSTableDataBlockDesc; + +class ObDirectLoadMultipleSSTableDataBlockScanner +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleSSTableDataBlockScanner(); + ~ObDirectLoadMultipleSSTableDataBlockScanner(); + int init(ObDirectLoadMultipleSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, + const blocksstable::ObStorageDatumUtils *datum_utils); + int get_next_data_block(ObDirectLoadSSTableDataBlockDesc &data_block_desc); +private: + int locate_left_border(IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader); + int locate_right_border(IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader); +private: + ObDirectLoadMultipleSSTable *sstable_; + const ObDirectLoadMultipleDatumRange *range_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + // [left, right) + ObDirectLoadMultipleSSTable::IndexEntryIterator left_index_entry_iter_; + int64_t left_data_block_offset_; + ObDirectLoadMultipleSSTable::IndexEntryIterator right_index_entry_iter_; + int64_t right_data_block_offset_; + ObDirectLoadMultipleSSTable::IndexEntryIterator current_index_entry_iter_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.cpp new file mode 100644 index 0000000000..b078fc8abd --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare::ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader) + : ret_(ret), + sstable_(sstable), + datum_utils_(datum_utils), + index_block_reader_(index_block_reader), + data_block_reader_(data_block_reader) +{ +} + +bool ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare::operator()( + const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexBlockIterator &iter) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * iter.index_block_idx_; + const ObDirectLoadSSTableIndexEntry *last_index_entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_last_entry(last_index_entry))) { + LOG_WARN("fail to get last entry", KR(ret)); + } else if (OB_FAIL(data_block_reader_.open(fragment.data_file_handle_, last_index_entry->offset_, + last_index_entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(last_index_entry)); + } else if (OB_FAIL(data_block_reader_.get_last_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else if (OB_FAIL(rowkey.compare(row->rowkey_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +bool ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare::operator()( + const ObDirectLoadMultipleSSTable::IndexBlockIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * iter.index_block_idx_; + const ObDirectLoadSSTableIndexEntry *first_index_entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_next_entry(first_index_entry))) { + LOG_WARN("fail to get last entry", KR(ret)); + } else if (OB_FAIL(data_block_reader_.open(fragment.data_file_handle_, first_index_entry->offset_, + first_index_entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(first_index_entry)); + } else if (OB_FAIL(data_block_reader_.get_next_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else if (OB_FAIL(row->rowkey_.compare(rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h new file mode 100644 index 0000000000..24ae36b64e --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h @@ -0,0 +1,44 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const blocksstable::ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader); + // for upper_bound + bool operator()(const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexBlockIterator &iter); + // for lower_bound + bool operator()(const ObDirectLoadMultipleSSTable::IndexBlockIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey); +private: + int &ret_; + ObDirectLoadMultipleSSTable *sstable_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + IndexBlockReader &index_block_reader_; + DataBlockReader &data_block_reader_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.cpp new file mode 100644 index 0000000000..2f74a2ec50 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.cpp @@ -0,0 +1,343 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_block_compare.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleSSTableIndexBlockMeta::ObDirectLoadMultipleSSTableIndexBlockMeta() + : count_(0) +{ +} + +ObDirectLoadMultipleSSTableIndexBlockMeta::~ObDirectLoadMultipleSSTableIndexBlockMeta() +{ +} + +/** + * ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner + */ + +ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner:: + ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner() + : sstable_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner:: + ~ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner() +{ +} + +int ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner::init( + ObDirectLoadMultipleSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid() || + !table_data_desc.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable), K(table_data_desc)); + } else { + if (OB_FAIL(index_block_reader_.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to index block reader", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(table_data_desc.sstable_data_block_size_, + sstable->get_meta().max_data_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to data block reader", KR(ret)); + } else { + sstable_ = sstable; + current_index_block_iter_ = sstable->index_block_begin(); + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner::get_next_meta( + ObDirectLoadMultipleSSTableIndexBlockMeta &index_block_meta) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner not init", KR(ret), KP(this)); + } else if (current_index_block_iter_ == sstable_->index_block_end()) { + ret = OB_ITER_END; + } else { + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(current_index_block_iter_.fragment_idx_); + int64_t index_block_offset = + sstable_->get_meta().index_block_size_ * current_index_block_iter_.index_block_idx_; + const ObDirectLoadSSTableIndexEntry *last_index_entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_last_entry(last_index_entry))) { + LOG_WARN("fail to get last entry", KR(ret)); + } else if (OB_FAIL(data_block_reader_.open( + fragment.data_file_handle_, last_index_entry->offset_, last_index_entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(last_index_entry)); + } else if (OB_FAIL(data_block_reader_.get_last_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else { + index_block_meta.count_ = index_block_reader_.get_header().count_; + index_block_meta.end_key_ = row->rowkey_; + ++current_index_block_iter_; + } + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner + */ + +ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner:: + ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner() + : sstable_(nullptr), is_iter_end_(false), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner:: + ~ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner() +{ +} + +int ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner::init( + ObDirectLoadMultipleSSTable *sstable, const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner init twice", KR(ret), + KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid() || !tablet_id.is_valid() || + !table_data_desc.is_valid() || nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable), K(table_data_desc), K(tablet_id), + KP(datum_utils)); + } else { + sstable_ = sstable; + tablet_id_ = tablet_id; + datum_utils_ = datum_utils; + if (OB_FAIL(index_block_reader_.init(table_data_desc.sstable_index_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to index block reader", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(table_data_desc.sstable_data_block_size_, + sstable->get_meta().max_data_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to data block reader", KR(ret)); + } else if (OB_FAIL(locate_left_border(index_block_reader_, data_block_reader_))) { + LOG_WARN("fail to locate left border", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner::locate_left_border( + IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader) +{ + int ret = OB_SUCCESS; + if (tablet_id_.compare(sstable_->get_start_key().tablet_id_) < 0) { // tablet_id < sstable + current_index_block_iter_ = sstable_->index_block_end(); + } else if (tablet_id_.compare(sstable_->get_end_key().tablet_id_) > 0) { // tablet_id > sstable + current_index_block_iter_ = sstable_->index_block_end(); + } else { + ObDirectLoadMultipleDatumRowkey tablet_min_rowkey; + if (OB_FAIL(tablet_min_rowkey.set_tablet_min_rowkey(tablet_id_))) { + LOG_WARN("fail to set tablet min rowkey", KR(ret)); + } else { + ObDirectLoadMultipleSSTableIndexBlockEndKeyCompare compare( + ret, sstable_, datum_utils_, index_block_reader, data_block_reader); + // tablet_min_rowkey < block_last_key + current_index_block_iter_ = std::upper_bound( + sstable_->index_block_begin(), sstable_->index_block_end(), tablet_min_rowkey, compare); + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner::get_next_meta( + ObDirectLoadMultipleSSTableIndexBlockMeta &index_block_meta) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner not init", KR(ret), + KP(this)); + } else if (is_iter_end_ || current_index_block_iter_ == sstable_->index_block_end()) { + ret = OB_ITER_END; + } else { + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(current_index_block_iter_.fragment_idx_); + int64_t index_block_offset = + sstable_->get_meta().index_block_size_ * current_index_block_iter_.index_block_idx_; + const ObDirectLoadSSTableIndexEntry *last_index_entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_last_entry(last_index_entry))) { + LOG_WARN("fail to get last entry", KR(ret)); + } else if (OB_FAIL(data_block_reader_.open( + fragment.data_file_handle_, last_index_entry->offset_, last_index_entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(last_index_entry)); + } else if (OB_FAIL(data_block_reader_.get_last_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else { + int cmp_ret = tablet_id_.compare(row->rowkey_.tablet_id_); + if (OB_UNLIKELY(cmp_ret > 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected rowkey", KR(ret), K(tablet_id_), K(row->rowkey_)); + } else if (cmp_ret < 0) { + ret = OB_ITER_END; + is_iter_end_ = true; + } else { + index_block_meta.count_ = index_block_reader_.get_header().count_; + index_block_meta.end_key_ = row->rowkey_; + ++current_index_block_iter_; + } + } + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator + */ + +ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator:: + ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator() + : index_block_meta_iter_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator:: + ~ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator() +{ + if (nullptr != index_block_meta_iter_) { + index_block_meta_iter_->~ObDirectLoadMultipleSSTableIndexBlockMetaIterator(); + index_block_meta_iter_ = nullptr; + } +} + +int ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator::init( + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator init twice", KR(ret), KP(this)); + } else if (OB_ISNULL(index_block_meta_iter)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(index_block_meta_iter)); + } else { + index_block_meta_iter_ = index_block_meta_iter; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator::get_next_rowkey( + const ObDirectLoadMultipleDatumRowkey *&rowkey) +{ + int ret = OB_SUCCESS; + rowkey = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMacroBlockEndKeyIterator not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(index_block_meta_iter_->get_next_meta(index_block_meta_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index block meta", KR(ret)); + } + } else { + rowkey = &index_block_meta_.end_key_; + } + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator + */ + +ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator:: + ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator() + : index_block_meta_iter_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator:: + ~ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator() +{ + if (nullptr != index_block_meta_iter_) { + index_block_meta_iter_->~ObDirectLoadMultipleSSTableIndexBlockMetaIterator(); + index_block_meta_iter_ = nullptr; + } +} + +int ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator::init( + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator init twice", KR(ret), + KP(this)); + } else if (OB_ISNULL(index_block_meta_iter)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(index_block_meta_iter)); + } else { + index_block_meta_iter_ = index_block_meta_iter; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator::get_next_rowkey( + const ObDatumRowkey *&rowkey) +{ + int ret = OB_SUCCESS; + rowkey = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMacroBlockEndKeyIterator not init", KR(ret), KP(this)); + } else { + ObDirectLoadMultipleSSTableIndexBlockMeta index_block_meta; + if (OB_FAIL(index_block_meta_iter_->get_next_meta(index_block_meta))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next index block meta", KR(ret)); + } + } else if (OB_FAIL(index_block_meta.end_key_.get_rowkey(rowkey_))) { + LOG_WARN("fail to get rowkey", KR(ret)); + } else { + rowkey = &rowkey_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h new file mode 100644 index 0000000000..86f9cef8e0 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h @@ -0,0 +1,115 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_rowkey_iterator.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_reader.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMultipleSSTable; +class ObDirectLoadMultipleDatumRange; + +struct ObDirectLoadMultipleSSTableIndexBlockMeta +{ +public: + ObDirectLoadMultipleSSTableIndexBlockMeta(); + ~ObDirectLoadMultipleSSTableIndexBlockMeta(); + TO_STRING_KV(K_(count), K_(end_key)); +public: + int64_t count_; // count of entries + ObDirectLoadMultipleDatumRowkey end_key_; +}; + +class ObDirectLoadMultipleSSTableIndexBlockMetaIterator +{ +public: + virtual ~ObDirectLoadMultipleSSTableIndexBlockMetaIterator() = default; + virtual int get_next_meta(ObDirectLoadMultipleSSTableIndexBlockMeta &index_block_meta) = 0; +}; + +class ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner + : public ObDirectLoadMultipleSSTableIndexBlockMetaIterator +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner(); + virtual ~ObDirectLoadMultipleSSTableIndexBlockMetaWholeScanner(); + int init(ObDirectLoadMultipleSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc); + int get_next_meta(ObDirectLoadMultipleSSTableIndexBlockMeta &index_block_meta) override; +private: + ObDirectLoadMultipleSSTable *sstable_; + IndexBlockReader index_block_reader_; + DataBlockReader data_block_reader_; + ObDirectLoadMultipleSSTable::IndexBlockIterator current_index_block_iter_; + bool is_inited_; +}; + +class ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner + : public ObDirectLoadMultipleSSTableIndexBlockMetaIterator +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; + +public: + ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner(); + virtual ~ObDirectLoadMultipleSSTableIndexBlockMetaTabletWholeScanner(); + int init(ObDirectLoadMultipleSSTable *sstable, const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils); + int get_next_meta(ObDirectLoadMultipleSSTableIndexBlockMeta &index_block_meta) override; +private: + int locate_left_border(IndexBlockReader &index_block_reader, DataBlockReader &data_block_reader); +private: + ObDirectLoadMultipleSSTable *sstable_; + common::ObTabletID tablet_id_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + IndexBlockReader index_block_reader_; + DataBlockReader data_block_reader_; + ObDirectLoadMultipleSSTable::IndexBlockIterator current_index_block_iter_; + bool is_iter_end_; + bool is_inited_; +}; + +class ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator + : public ObIDirectLoadMultipleDatumRowkeyIterator +{ +public: + ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator(); + virtual ~ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator(); + int init(ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter); + int get_next_rowkey(const ObDirectLoadMultipleDatumRowkey *&rowkey) override; +private: + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter_; + ObDirectLoadMultipleSSTableIndexBlockMeta index_block_meta_; + bool is_inited_; +}; + +class ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator + : public ObIDirectLoadDatumRowkeyIterator +{ +public: + ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator(); + virtual ~ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator(); + int init(ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter); + int get_next_rowkey(const blocksstable::ObDatumRowkey *&rowkey) override; +private: + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter_; + blocksstable::ObDatumRowkey rowkey_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.cpp new file mode 100644 index 0000000000..02632faaaf --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.cpp @@ -0,0 +1,191 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare + */ + +ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare:: + ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const blocksstable::ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader) + : ret_(ret), + sstable_(sstable), + datum_utils_(datum_utils), + index_block_reader_(index_block_reader), + data_block_reader_(data_block_reader), + entries_per_block_( + ObDirectLoadSSTableIndexBlock::get_entries_per_block(sstable->get_meta().index_block_size_)) +{ +} + +bool ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare::operator()( + const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else if (OB_FAIL( + data_block_reader_.open(fragment.data_file_handle_, entry->offset_, entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(entry)); + } else if (OB_FAIL(data_block_reader_.get_next_row(row))) { + LOG_WARN("fail to get first row", KR(ret)); + } else if (OB_FAIL(rowkey.compare(row->rowkey_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +bool ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare::operator()( + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else if (OB_FAIL( + data_block_reader_.open(fragment.data_file_handle_, entry->offset_, entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(entry)); + } else if (OB_FAIL(data_block_reader_.get_next_row(row))) { + LOG_WARN("fail to get first row", KR(ret)); + } else if (OB_FAIL(row->rowkey_.compare(rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +/* + * ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare + */ + +ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare:: + ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const blocksstable::ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader) + : ret_(ret), + sstable_(sstable), + datum_utils_(datum_utils), + index_block_reader_(index_block_reader), + data_block_reader_(data_block_reader), + entries_per_block_( + ObDirectLoadSSTableIndexBlock::get_entries_per_block(sstable->get_meta().index_block_size_)) +{ +} + +bool ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare::operator()( + const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else if (OB_FAIL( + data_block_reader_.open(fragment.data_file_handle_, entry->offset_, entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(entry)); + } else if (OB_FAIL(data_block_reader_.get_last_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else if (OB_FAIL(rowkey.compare(row->rowkey_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +bool ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare::operator()( + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey) +{ + int &ret = ret_; + int cmp_ret = 0; + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(iter.fragment_idx_); + const int64_t index_block_idx = iter.index_entry_idx_ / entries_per_block_; + const int64_t index_block_offset = sstable_->get_meta().index_block_size_ * index_block_idx; + const int64_t index_entry_idx = iter.index_entry_idx_ % entries_per_block_; + const ObDirectLoadSSTableIndexEntry *entry = nullptr; + const RowType *row = nullptr; + index_block_reader_.reuse(); + data_block_reader_.reuse(); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(index_block_reader_.open(fragment.index_file_handle_, index_block_offset, + sstable_->get_meta().index_block_size_))) { + LOG_WARN("fail to open index file", KR(ret), K(fragment), K(index_block_offset)); + } else if (OB_FAIL(index_block_reader_.get_entry(index_entry_idx, entry))) { + LOG_WARN("fail to get entry", KR(ret)); + } else if (OB_FAIL( + data_block_reader_.open(fragment.data_file_handle_, entry->offset_, entry->size_))) { + LOG_WARN("fail to open data file", KR(ret), K(fragment), KPC(entry)); + } else if (OB_FAIL(data_block_reader_.get_last_row(row))) { + LOG_WARN("fail to get last row", KR(ret)); + } else if (OB_FAIL(row->rowkey_.compare(rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } + return cmp_ret < 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h new file mode 100644 index 0000000000..cc3043a064 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_index_entry_compare.h @@ -0,0 +1,72 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleSSTableIndexEntryStartKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const blocksstable::ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader); + // for upper_bound + bool operator()(const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter); + // for lower_bound + bool operator()(const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey); +private: + int &ret_; + ObDirectLoadMultipleSSTable *sstable_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + IndexBlockReader &index_block_reader_; + DataBlockReader &data_block_reader_; + const int64_t entries_per_block_; +}; + +class ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableIndexBlockReader IndexBlockReader; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; +public: + ObDirectLoadMultipleSSTableIndexEntryEndKeyCompare( + int &ret, + ObDirectLoadMultipleSSTable *sstable, + const blocksstable::ObStorageDatumUtils *datum_utils, + IndexBlockReader &index_block_reader, + DataBlockReader &data_block_reader); + // for upper_bound + bool operator()(const ObDirectLoadMultipleDatumRowkey &rowkey, + const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter); + // for lower_bound + bool operator()(const ObDirectLoadMultipleSSTable::IndexEntryIterator &iter, + const ObDirectLoadMultipleDatumRowkey &rowkey); +private: + int &ret_; + ObDirectLoadMultipleSSTable *sstable_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + IndexBlockReader &index_block_reader_; + DataBlockReader &data_block_reader_; + const int64_t entries_per_block_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.cpp new file mode 100644 index 0000000000..3fe2f836e9 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.cpp @@ -0,0 +1,297 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h" +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "storage/blocksstable/ob_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace sql; + +/** + * ObDirectLoadMultipleSSTableScanMergeParam + */ + +ObDirectLoadMultipleSSTableScanMergeParam::ObDirectLoadMultipleSSTableScanMergeParam() + : datum_utils_(nullptr), error_row_handler_(nullptr), result_info_(nullptr) +{ +} + +ObDirectLoadMultipleSSTableScanMergeParam::~ObDirectLoadMultipleSSTableScanMergeParam() {} + +bool ObDirectLoadMultipleSSTableScanMergeParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != datum_utils_ && nullptr != error_row_handler_ && + nullptr != result_info_; +} + +/** + * ObDirectLoadMultipleSSTableScanMerge + */ + +ObDirectLoadMultipleSSTableScanMerge::ObDirectLoadMultipleSSTableScanMerge() + : datum_utils_(nullptr), + error_row_handler_(nullptr), + range_(nullptr), + consumers_(nullptr), + consumer_cnt_(0), + simple_merge_(nullptr), + loser_tree_(nullptr), + rows_merger_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableScanMerge::~ObDirectLoadMultipleSSTableScanMerge() { reset(); } + +void ObDirectLoadMultipleSSTableScanMerge::reset() +{ + table_data_desc_.reset(); + datum_utils_ = nullptr; + error_row_handler_ = nullptr; + range_ = nullptr; + for (int64_t i = 0; i < scanners_.count(); ++i) { + scanners_[i]->~ObDirectLoadMultipleSSTableScanner(); + } + scanners_.reset(); + consumers_ = nullptr; + consumer_cnt_ = 0; + if (nullptr != simple_merge_) { + simple_merge_->~ScanSimpleMerger(); + simple_merge_ = nullptr; + } + if (nullptr != loser_tree_) { + loser_tree_->~ScanMergeLoserTree(); + loser_tree_ = nullptr; + } + loser_tree_ = nullptr; + allocator_.reset(); + is_inited_ = false; +} + +int ObDirectLoadMultipleSSTableScanMerge::init( + const ObDirectLoadMultipleSSTableScanMergeParam ¶m, + const ObIArray &sstable_array, + const ObDirectLoadMultipleDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableScanMerge init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() || sstable_array.count() > MAX_SSTABLE_COUNT || + !range.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(sstable_array), K(range)); + } else { + // construct scanners + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstable_array.at(i); + ObDirectLoadMultipleSSTableScanner *scanner = nullptr; + if (sstable->is_empty()) { + } else if (OB_FAIL(sstable->scan(param.table_data_desc_, range, param.datum_utils_, + allocator_, scanner))) { + LOG_WARN("fail to scan sstable", KR(ret)); + } else if (OB_FAIL(scanners_.push_back(scanner))) { + LOG_WARN("fail to push back scanner", KR(ret)); + } + } + if (OB_SUCC(ret) && !scanners_.empty()) { + // init consumers + if (OB_ISNULL(consumers_ = static_cast( + allocator_.alloc(sizeof(int64_t) * scanners_.count())))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + for (int64_t i = 0; i < scanners_.count(); ++i) { + consumers_[i] = i; + } + consumer_cnt_ = scanners_.count(); + } + // init rows merger + if (OB_FAIL(ret)) { + } else if (OB_FAIL(compare_.init(param.datum_utils_))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(init_rows_merger(scanners_.count()))) { + LOG_WARN("fail to init rows merger", KR(ret)); + } else if (OB_FAIL(datum_row_.init(param.table_data_desc_.column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } + } + if (OB_SUCC(ret)) { + table_data_desc_ = param.table_data_desc_; + datum_utils_ = param.datum_utils_; + error_row_handler_ = param.error_row_handler_; + result_info_ = param.result_info_; + range_ = ⦥ + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMerge::init_rows_merger(int64_t sstable_count) +{ + int ret = OB_SUCCESS; + if (sstable_count <= ObScanSimpleMerger::USE_SIMPLE_MERGER_MAX_TABLE_CNT) { + if (OB_ISNULL(simple_merge_ = OB_NEWx(ScanSimpleMerger, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanSimpleMerger", KR(ret)); + } else { + rows_merger_ = simple_merge_; + } + } else { + if (OB_ISNULL(loser_tree_ = OB_NEWx(ScanMergeLoserTree, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanMergeLoserTree", KR(ret)); + } else { + rows_merger_ = loser_tree_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(rows_merger_->init(sstable_count, allocator_))) { + LOG_WARN("fail to init rows merger", KR(ret), K(sstable_count)); + } else if (FALSE_IT(rows_merger_->reuse())) { + } else if (OB_FAIL(rows_merger_->open(sstable_count))) { + LOG_WARN("fail to open rows merger", KR(ret), K(sstable_count)); + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMerge::supply_consume() +{ + int ret = OB_SUCCESS; + LoserTreeItem item; + for (int64_t i = 0; OB_SUCC(ret) && i < consumer_cnt_; ++i) { + const int64_t iter_idx = consumers_[i]; + ObDirectLoadMultipleSSTableScanner *scanner = scanners_.at(iter_idx); + if (OB_FAIL(scanner->get_next_row(item.row_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from scanner", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } else { + item.iter_idx_ = iter_idx; + if (OB_FAIL(rows_merger_->push(item))) { + LOG_WARN("fail to push to loser tree", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + // no worry, if no new items pushed, the rebuild will quickly exit + if (OB_FAIL(rows_merger_->rebuild())) { + LOG_WARN("fail to rebuild loser tree", KR(ret), K(consumer_cnt_)); + } else { + consumer_cnt_ = 0; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMerge::inner_get_next_row( + const ObDirectLoadMultipleDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (rows_merger_->empty()) { + ret = OB_ITER_END; + } else { + const LoserTreeItem *top_item = nullptr; + datum_row = nullptr; + while (OB_SUCC(ret) && !rows_merger_->empty() && nullptr == datum_row) { + if (OB_FAIL(rows_merger_->top(top_item))) { + LOG_WARN("fail to get top item", KR(ret)); + } else if (OB_LIKELY(rows_merger_->is_unique_champion())) { + datum_row = top_item->row_; + } else { + // record same rowkey row + if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_REPLACE) { + ATOMIC_AAF(&result_info_->rows_affected_, 2); + ATOMIC_INC(&result_info_->deleted_); + } else if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_IGNORE) { + ATOMIC_INC(&result_info_->skipped_); + } else if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(top_item->row_->to_datums(datum_row_.storage_datums_, + datum_row_.count_))) { + LOG_WARN("fail to transfer external row to datums", KR(tmp_ret)); + } else if (OB_TMP_FAIL(error_row_handler_->append_error_row(datum_row_))) { + LOG_WARN("fail to append row to error row handler", KR(tmp_ret), K(datum_row_)); + } + } + } + if (OB_SUCC(ret)) { + consumers_[consumer_cnt_++] = top_item->iter_idx_; + if (OB_FAIL(rows_merger_->pop())) { + LOG_WARN("fail to pop item", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMerge::get_next_row( + const ObDirectLoadMultipleDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableScanMerge not init", KR(ret), KP(this)); + } else if (scanners_.empty()) { + ret = OB_ITER_END; + } else if (1 == scanners_.count()) { + // direct get next row from scanner + if (OB_FAIL(scanners_.at(0)->get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from scanner", KR(ret)); + } + } + } else { + // get next row from loser tree + if (consumer_cnt_ > 0 && OB_FAIL(supply_consume())) { + LOG_WARN("fail to supply consume", KR(ret)); + } else if (OB_FAIL(inner_get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do inner get next row", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMerge::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableScanMerge not init", KR(ret), KP(this)); + } else { + const ObDirectLoadMultipleDatumRow *multiple_datum_row = nullptr; + if (OB_FAIL(get_next_row(multiple_datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next external row", KR(ret)); + } + } else if (OB_FAIL( + multiple_datum_row->to_datums(datum_row_.storage_datums_, datum_row_.count_))) { + LOG_WARN("fail to transfer datum row", KR(ret)); + } else { + datum_row = &datum_row_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h new file mode 100644 index 0000000000..6d12325965 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge.h @@ -0,0 +1,84 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_loser_tree.h" +#include "lib/container/ob_se_array.h" +#include "storage/access/ob_simple_rows_merger.h" +#include "storage/access/ob_store_row_iterator.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatumUtils; +} // namespace blocksstable +namespace observer +{ +class ObTableLoadErrorRowHandler; +} // namespace observer +namespace storage +{ + +struct ObDirectLoadMultipleSSTableScanMergeParam +{ +public: + ObDirectLoadMultipleSSTableScanMergeParam(); + ~ObDirectLoadMultipleSSTableScanMergeParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(datum_utils), KP_(error_row_handler), KP_(result_info)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + table::ObTableLoadResultInfo *result_info_; +}; + +class ObDirectLoadMultipleSSTableScanMerge : public ObIStoreRowIterator +{ +public: + static const int64_t MAX_SSTABLE_COUNT = 1024; + typedef ObDirectLoadMultipleSSTableScanMergeLoserTreeItem LoserTreeItem; + typedef ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare LoserTreeCompare; + typedef ObSimpleRowsMerger ScanSimpleMerger; + typedef common::ObLoserTree + ScanMergeLoserTree; +public: + ObDirectLoadMultipleSSTableScanMerge(); + ~ObDirectLoadMultipleSSTableScanMerge(); + void reset(); + int init(const ObDirectLoadMultipleSSTableScanMergeParam ¶m, + const common::ObIArray &sstable_array, + const ObDirectLoadMultipleDatumRange &range); + int get_next_row(const ObDirectLoadMultipleDatumRow *&external_row); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; +private: + int init_rows_merger(int64_t sstable_count); + int supply_consume(); + int inner_get_next_row(const ObDirectLoadMultipleDatumRow *&external_row); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + table::ObTableLoadResultInfo *result_info_; + const ObDirectLoadMultipleDatumRange *range_; + common::ObSEArray scanners_; + int64_t *consumers_; + int64_t consumer_cnt_; + LoserTreeCompare compare_; + ScanSimpleMerger *simple_merge_; + ScanMergeLoserTree *loser_tree_; + common::ObRowsMerger *rows_merger_; + blocksstable::ObDatumRow datum_row_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.cpp new file mode 100644 index 0000000000..2704039488 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare + */ + +ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare:: + ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare() + : datum_utils_(nullptr) +{ +} + +ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare:: + ~ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare() +{ +} + +int ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare::init( + const blocksstable::ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datum_utils)); + } else { + datum_utils_ = datum_utils; + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare::cmp( + const ObDirectLoadMultipleSSTableScanMergeLoserTreeItem &lhs, + const ObDirectLoadMultipleSSTableScanMergeLoserTreeItem &rhs, + int64_t &cmp_ret) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == datum_utils_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs.row_ || nullptr == rhs.row_ || !lhs.row_->is_valid() || + !rhs.row_->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(lhs), K(rhs)); + } else { + int tmp_cmp_ret = 0; + if (OB_FAIL(lhs.row_->rowkey_.compare(rhs.row_->rowkey_, *datum_utils_, tmp_cmp_ret))) { + LOG_WARN("fail to compare rowkey", K(ret), K(lhs.row_->rowkey_), K(rhs.row_->rowkey_), + KPC(datum_utils_)); + } else { + cmp_ret = tmp_cmp_ret; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h new file mode 100644 index 0000000000..069339b0a9 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scan_merge_loser_tree.h @@ -0,0 +1,55 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatumUtils; +} // namespace blocksstable +namespace storage +{ + +struct ObDirectLoadMultipleSSTableScanMergeLoserTreeItem +{ +public: + ObDirectLoadMultipleSSTableScanMergeLoserTreeItem() + : row_(nullptr), iter_idx_(0), equal_with_next_(false) + { + } + ~ObDirectLoadMultipleSSTableScanMergeLoserTreeItem() = default; + void reset() + { + row_ = nullptr; + iter_idx_ = 0; + equal_with_next_ = false; + } + TO_STRING_KV(KPC_(row), K_(iter_idx), K_(equal_with_next)); +public: + const ObDirectLoadMultipleDatumRow *row_; + int64_t iter_idx_; + bool equal_with_next_; // for simple row merger +}; + +class ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare +{ +public: + ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare(); + ~ObDirectLoadMultipleSSTableScanMergeLoserTreeCompare(); + int init(const blocksstable::ObStorageDatumUtils *datum_utils); + int cmp(const ObDirectLoadMultipleSSTableScanMergeLoserTreeItem &lhs, + const ObDirectLoadMultipleSSTableScanMergeLoserTreeItem &rhs, + int64_t &cmp_ret); +public: + const blocksstable::ObStorageDatumUtils *datum_utils_; + blocksstable::ObDatumRowkey lhs_rowkey_; + blocksstable::ObDatumRowkey rhs_rowkey_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.cpp b/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.cpp new file mode 100644 index 0000000000..9136af4604 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_multiple_sstable_scanner.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +ObDirectLoadMultipleSSTableScanner::ObDirectLoadMultipleSSTableScanner() + : sstable_(nullptr), + range_(nullptr), + datum_utils_(nullptr), + is_iter_start_(false), + is_iter_end_(false), + is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableScanner::~ObDirectLoadMultipleSSTableScanner() +{ +} + +int ObDirectLoadMultipleSSTableScanner::init(ObDirectLoadMultipleSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid() || + !table_data_desc.is_valid() || !range.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable), K(table_data_desc), K(range), KP(datum_utils)); + } else { + sstable_ = sstable; + table_data_desc_ = table_data_desc; + range_ = ⦥ + datum_utils_ = datum_utils; + if (OB_FAIL(data_block_scanner_.init(sstable, table_data_desc, range, datum_utils))) { + LOG_WARN("fail to init data block scanner", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(table_data_desc.sstable_data_block_size_, + sstable->get_meta().max_data_block_size_, + table_data_desc.compressor_type_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanner::switch_next_fragment() +{ + int ret = OB_SUCCESS; + if (OB_FAIL(data_block_scanner_.get_next_data_block(data_block_desc_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next data block", KR(ret)); + } + } else { + const ObDirectLoadMultipleSSTableFragment &fragment = + sstable_->get_fragments().at(data_block_desc_.fragment_idx_); + data_block_reader_.reuse(); + if (OB_FAIL(data_block_reader_.open(fragment.data_file_handle_, data_block_desc_.offset_, + data_block_desc_.size_))) { + LOG_WARN("fail to open data file", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableScanner::get_next_row(const ObDirectLoadMultipleDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableScanner not init", KR(ret), KP(this)); + } else if (is_iter_end_) { + ret = OB_ITER_END; + } else { + datum_row = nullptr; + while (OB_SUCC(ret) && nullptr == datum_row) { + if (OB_FAIL(data_block_reader_.get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } else { + ret = OB_SUCCESS; + if (OB_FAIL(switch_next_fragment())) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to switch next fragment", KR(ret)); + } else { + is_iter_end_ = true; + } + } + } + } else { + if (!is_iter_start_) { + int cmp_ret = 0; + if (OB_FAIL(datum_row->rowkey_.compare(range_->start_key_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret < 0 || (cmp_ret == 0 && range_->is_left_open())) { + datum_row = nullptr; + } else { + is_iter_start_ = true; + } + } + if (OB_SUCC(ret) && nullptr != datum_row && data_block_desc_.is_right_border_ && + data_block_reader_.get_block_count() == data_block_desc_.block_count_) { + int cmp_ret = 0; + if (OB_FAIL(datum_row->rowkey_.compare(range_->end_key_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret > 0 || (cmp_ret == 0 && range_->is_right_open())) { + datum_row = nullptr; + ret = OB_ITER_END; + is_iter_end_ = true; + } + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.h b/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.h new file mode 100644 index 0000000000..fa32326865 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_multiple_sstable_scanner.h @@ -0,0 +1,54 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_row.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_data_block_scanner.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadMultipleSSTable; +class ObDirectLoadMultipleDatumRange; +class ObDirectLoadMultipleDatumRow; + +class ObDirectLoadMultipleSSTableScanner +{ + typedef ObDirectLoadMultipleDatumRow RowType; + typedef ObDirectLoadSSTableDataBlockReader DataBlockReader; + +public: + ObDirectLoadMultipleSSTableScanner(); + ~ObDirectLoadMultipleSSTableScanner(); + int init(ObDirectLoadMultipleSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc, + const ObDirectLoadMultipleDatumRange &range, + const blocksstable::ObStorageDatumUtils *datum_utils); + int get_next_row(const ObDirectLoadMultipleDatumRow *&datum_row); + TO_STRING_KV(KPC_(sstable), KPC_(range)); + +private: + int switch_next_fragment(); + +private: + common::ObArenaAllocator allocator_; + ObDirectLoadMultipleSSTable *sstable_; + ObDirectLoadTableDataDesc table_data_desc_; + const ObDirectLoadMultipleDatumRange *range_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadMultipleSSTableDataBlockScanner data_block_scanner_; + ObDirectLoadSSTableDataBlockDesc data_block_desc_; + DataBlockReader data_block_reader_; + bool is_iter_start_; + bool is_iter_end_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_origin_table.cpp b/src/storage/direct_load/ob_direct_load_origin_table.cpp new file mode 100644 index 0000000000..d982d6d47b --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_origin_table.cpp @@ -0,0 +1,312 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_origin_table.h" +#include "storage/tablet/ob_tablet.h" +#include "storage/tx_storage/ob_ls_handle.h" +#include "storage/tx_storage/ob_ls_service.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace share; +using namespace share::schema; + +/** + * ObDirectLoadOriginTableCreateParam + */ + +ObDirectLoadOriginTableCreateParam::ObDirectLoadOriginTableCreateParam() + : table_id_(OB_INVALID_ID) +{ +} + +ObDirectLoadOriginTableCreateParam::~ObDirectLoadOriginTableCreateParam() +{ +} + +bool ObDirectLoadOriginTableCreateParam::is_valid() const +{ + return OB_INVALID_ID != table_id_ && tablet_id_.is_valid() && ls_id_.is_valid(); +} + +/** + * ObDirectLoadOriginTableMeta + */ + +ObDirectLoadOriginTableMeta::ObDirectLoadOriginTableMeta() + : table_id_(OB_INVALID_ID) +{ +} + +ObDirectLoadOriginTableMeta::~ObDirectLoadOriginTableMeta() +{ +} + +/** + * ObDirectLoadOriginTable + */ + +ObDirectLoadOriginTable::ObDirectLoadOriginTable() + : major_sstable_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadOriginTable::~ObDirectLoadOriginTable() +{ +} + +int ObDirectLoadOriginTable::init(const ObDirectLoadOriginTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadOriginTable init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + const ObTabletID &tablet_id = param.tablet_id_; + const ObLSID &ls_id = param.ls_id_; + ObLSService *ls_svr = nullptr; + ObLSHandle ls_handle; + ObLS *ls = nullptr; + if (OB_ISNULL(ls_svr = MTL(ObLSService *))) { + ret = OB_ERR_SYS; + LOG_WARN("MTL ObLSService is null", KR(ret), "tenant_id", MTL_ID()); + } else if (OB_FAIL(ls_svr->get_ls(ls_id, ls_handle, ObLSGetMod::STORAGE_MOD))) { + LOG_WARN("fail to get ls", KR(ret), K(ls)); + } else if (OB_ISNULL(ls = ls_handle.get_ls())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected ls is nullptr", KR(ret)); + } else if (OB_FAIL(ls->get_tablet(tablet_id, tablet_handle_))) { + LOG_WARN("fail to get tablet", KR(ret), K(tablet_id)); + } else if (OB_FAIL(prepare_tables())) { + LOG_WARN("fail to prepare tables", KR(ret)); + } else { + meta_.ls_id_ = param.ls_id_; + meta_.table_id_ = param.table_id_; + meta_.tablet_id_ = param.tablet_id_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadOriginTable::prepare_tables() +{ + int ret = OB_SUCCESS; + ObITable *table = nullptr; + ObSSTable *major_sstable = nullptr; + ObTabletTableIterator tablet_table_iter; + tablet_table_iter.tablet_handle_ = tablet_handle_; + if (OB_FAIL(tablet_handle_.get_obj()->get_read_tables(INT64_MAX, tablet_table_iter, + false /*allow_not_ready*/))) { + LOG_WARN("fail to get read tables", KR(ret), K(tablet_handle_)); + } + // find major sstable + while (OB_SUCC(ret)) { + if (OB_FAIL(tablet_table_iter.table_iter_.get_next(table))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next table", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (table->is_major_sstable()) { + if (nullptr != major_sstable) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected multi major sstable", KR(ret), KPC(major_sstable), KPC(table)); + } else if (OB_ISNULL(major_sstable = dynamic_cast(table))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected not major sstable", KR(ret), KPC(table)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_ISNULL(major_sstable)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected not found major sstable", KR(ret), KPC(table)); + } else if (OB_FAIL(table_iter_.copy(tablet_table_iter.table_iter_))) { + LOG_WARN("fail to copy table iter", KR(ret)); + } else { + major_sstable_ = major_sstable; + } + } + return ret; +} + +int ObDirectLoadOriginTable::scan(const blocksstable::ObDatumRange &key_range, + common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadOriginTable not init", KR(ret), KP(this)); + } else if (!key_range.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", KR(ret), K(key_range)); + } else { + ObDirectLoadOriginTableScanner *row_scanner = nullptr; + if (OB_ISNULL(row_scanner = OB_NEWx(ObDirectLoadOriginTableScanner, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadOriginTableScanner", KR(ret)); + } else if (OB_FAIL(row_scanner->init(this, key_range))) { + LOG_WARN("Fail to open row scanner", KR(ret), K(key_range), K(*this)); + } else { + row_iter = row_scanner; + } + if (OB_FAIL(ret)) { + if (nullptr != row_scanner) { + row_scanner->~ObDirectLoadOriginTableScanner(); + allocator.free(row_scanner); + row_scanner = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadOriginTableScanner + */ + +ObDirectLoadOriginTableScanner::ObDirectLoadOriginTableScanner() + : allocator_("TLD_OriSSTScan"), origin_table_(nullptr), schema_param_(allocator_), is_inited_(false) +{ +} + +ObDirectLoadOriginTableScanner::~ObDirectLoadOriginTableScanner() +{ +} + +int ObDirectLoadOriginTableScanner::init(ObDirectLoadOriginTable *origin_table, + const blocksstable::ObDatumRange &query_range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadOriginIterator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == origin_table || !origin_table->is_valid() || + !query_range.is_valid() || !query_range.is_memtable_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", KR(ret), KPC(origin_table), K(query_range)); + } else { + origin_table_ = origin_table; + allocator_.set_tenant_id(MTL_ID()); + if (OB_FAIL((init_table_access_param()))) { + LOG_WARN("fail to init query range", KR(ret)); + } else if (OB_FAIL(init_table_access_ctx())) { + LOG_WARN("fail to init table access param", KR(ret)); + } else if (OB_FAIL(init_get_table_param())) { + LOG_WARN("fail to init get table param", KR(ret)); + } else if (OB_FAIL( + scan_merge_.init(table_access_param_, table_access_ctx_, get_table_param_))) { + LOG_WARN("fail to init multi merge", KR(ret)); + } else if (OB_FAIL(scan_merge_.open(query_range))) { + LOG_WARN("fail to open multi merge", KR(ret), K(query_range)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadOriginTableScanner::init_table_access_param() +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + const uint64_t table_id = origin_table_->get_meta().table_id_; + ObSchemaGetterGuard schema_guard; + const ObTableSchema *table_schema = nullptr; + if (OB_FAIL(ObMultiVersionSchemaService::get_instance().get_tenant_schema_guard(tenant_id, + schema_guard))) { + LOG_WARN("fail to get tenant schema guard", KR(ret), K(tenant_id)); + } else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table_schema))) { + LOG_WARN("fail to get table schema", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("table not exist", KR(ret), K(tenant_id), K(table_id)); + } else if (OB_FAIL(schema_param_.convert(table_schema))) { + LOG_WARN("fail to convert schema para", KR(ret)); + } else if (OB_FAIL(table_access_param_.init_merge_param(origin_table_->get_meta().table_id_, + origin_table_->get_meta().tablet_id_, + schema_param_.get_read_info()))) { + LOG_WARN("fail to init merge param", KR(ret)); + } + for (int64_t i = 0; OB_SUCC(ret) && i < schema_param_.get_read_info().get_schema_column_count(); ++i) { + if (OB_FAIL(col_ids_.push_back(i))) { + LOG_WARN("fail to push back col id", KR(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + table_access_param_.iter_param_.out_cols_project_ = &col_ids_; + } + return ret; +} + +int ObDirectLoadOriginTableScanner::init_table_access_ctx() +{ + int ret = OB_SUCCESS; + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + false /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/); //whole_macro_scan use false,otherwise query range is not overlap with sstable range will report error + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + share::SCN snapshot_scn; + if (OB_FAIL(snapshot_scn.convert_for_tx(snapshot_version))) { + LOG_WARN("fail to convert scn", KR(ret)); + } else if (OB_FAIL(store_ctx_.init_for_read(origin_table_->get_meta().ls_id_, INT64_MAX, -1, + snapshot_scn))) { + LOG_WARN("fail to init for read", KR(ret)); + } else if (OB_FAIL(table_access_ctx_.init(query_flag, store_ctx_, allocator_, allocator_, + trans_version_range))) { + LOG_WARN("fail to init table access context", KR(ret)); + } else { + table_access_ctx_.io_callback_ = &io_callback_; + } + return ret; +} + +int ObDirectLoadOriginTableScanner::init_get_table_param() +{ + int ret = OB_SUCCESS; + get_table_param_.tablet_iter_.tablet_handle_ = origin_table_->get_tablet_handle(); + if (OB_FAIL(get_table_param_.tablet_iter_.table_iter_.copy(origin_table_->get_table_iter()))) { + LOG_WARN("fail to copy table iter", KR(ret)); + } + return ret; +} + +int ObDirectLoadOriginTableScanner::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadOriginTableScanner not init", KR(ret), KP(this)); + } else { + ObDatumRow *result_row = nullptr; + if (OB_FAIL(scan_merge_.get_next_row(result_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("get next row failed", KR(ret)); + } + } else { + datum_row = result_row; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_origin_table.h b/src/storage/direct_load/ob_direct_load_origin_table.h new file mode 100644 index 0000000000..3f001a77a0 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_origin_table.h @@ -0,0 +1,92 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "share/schema/ob_table_dml_param.h" +#include "storage/access/ob_multiple_scan_merge.h" +#include "storage/access/ob_store_row_iterator.h" +#include "storage/direct_load/ob_direct_load_io_callback.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadOriginTableCreateParam +{ +public: + ObDirectLoadOriginTableCreateParam(); + ~ObDirectLoadOriginTableCreateParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_id), K_(tablet_id), K_(ls_id)); +public: + uint64_t table_id_; + common::ObTabletID tablet_id_; + share::ObLSID ls_id_; +}; + +struct ObDirectLoadOriginTableMeta +{ +public: + ObDirectLoadOriginTableMeta(); + ~ObDirectLoadOriginTableMeta(); + TO_STRING_KV( K_(table_id), K_(tablet_id), K_(ls_id)); +public: + uint64_t table_id_; + common::ObTabletID tablet_id_; + share::ObLSID ls_id_; +}; + +class ObDirectLoadOriginTable +{ +public: + ObDirectLoadOriginTable(); + virtual ~ObDirectLoadOriginTable(); + int init(const ObDirectLoadOriginTableCreateParam ¶m); + int scan(const blocksstable::ObDatumRange &key_range, common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter); + bool is_valid() const { return is_inited_; } + const ObDirectLoadOriginTableMeta &get_meta() const {return meta_; } + const ObTabletHandle &get_tablet_handle() const { return tablet_handle_; } + const ObTableStoreIterator &get_table_iter() const { return table_iter_; } + blocksstable::ObSSTable *get_major_sstable() const { return major_sstable_; } + TO_STRING_KV(K_(meta), K_(tablet_handle), K_(table_iter), KP_(major_sstable)); +private: + int prepare_tables(); +private: + ObDirectLoadOriginTableMeta meta_; + ObTabletHandle tablet_handle_; + ObTableStoreIterator table_iter_; + blocksstable::ObSSTable *major_sstable_; + bool is_inited_; +}; + +class ObDirectLoadOriginTableScanner : public ObIStoreRowIterator +{ +public: + ObDirectLoadOriginTableScanner(); + virtual ~ObDirectLoadOriginTableScanner(); + int init(ObDirectLoadOriginTable *table, + const blocksstable::ObDatumRange &query_range); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; +private: + int init_table_access_param(); + int init_table_access_ctx(); + int init_get_table_param(); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadOriginTable *origin_table_; + ObSEArray col_ids_; + share::schema::ObTableSchemaParam schema_param_; + ObTableAccessParam table_access_param_; + ObDirectLoadIOCallback io_callback_; + ObStoreCtx store_ctx_; + ObTableAccessContext table_access_ctx_; + ObGetTableParam get_table_param_; + ObMultipleScanMerge scan_merge_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase \ No newline at end of file diff --git a/src/storage/direct_load/ob_direct_load_partition_merge_task.cpp b/src/storage/direct_load/ob_direct_load_partition_merge_task.cpp new file mode 100644 index 0000000000..8c2b970bd6 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_partition_merge_task.cpp @@ -0,0 +1,816 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_partition_merge_task.h" +#include "storage/ddl/ob_direct_insert_sstable_ctx.h" +#include "storage/direct_load/ob_direct_load_external_table.h" +#include "storage/direct_load/ob_direct_load_insert_table_ctx.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table.h" +#include "storage/direct_load/ob_direct_load_merge_ctx.h" +#include "share/stat/ob_opt_column_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace share; + +/** + * ObDirectLoadPartitionMergeTask + */ + +ObDirectLoadPartitionMergeTask::ObDirectLoadPartitionMergeTask() + : merge_param_(nullptr), + merge_ctx_(nullptr), + parallel_idx_(-1), + affected_rows_(0), + allocator_("TLD_ParMT"), + is_stop_(false), + is_inited_(false) +{ +} + +ObDirectLoadPartitionMergeTask::~ObDirectLoadPartitionMergeTask() +{ + for (int64_t i = 0; i < column_stat_array_.count(); ++i) { + ObOptColumnStat *col_stat = column_stat_array_.at(i); + if (col_stat != nullptr) { + col_stat->~ObOptColumnStat(); + col_stat = nullptr; + } + } +} + +int ObDirectLoadPartitionMergeTask::process() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionMergeTask not init", KR(ret), KP(this)); + } else { + const ObTabletID &tablet_id = merge_ctx_->get_tablet_id(); + const ObTabletID &target_tablet_id = merge_ctx_->get_target_tablet_id(); + ObArenaAllocator allocator("TLD_MergeTask"); + ObIStoreRowIterator *row_iter = nullptr; + ObSSTableInsertSliceWriter *writer = nullptr; + ObMacroDataSeq block_start_seq; + allocator.set_tenant_id(MTL_ID()); + block_start_seq.set_parallel_degree(parallel_idx_); + if (merge_param_->online_opt_stat_gather_ && OB_FAIL(init_sql_statistics())) { + LOG_WARN("fail to init sql statistics", KR(ret)); + } else if (OB_FAIL(construct_row_iter(allocator, row_iter))) { + LOG_WARN("fail to construct row iter", KR(ret)); + } else if (OB_FAIL(merge_param_->insert_table_ctx_->construct_sstable_slice_writer( + target_tablet_id, block_start_seq, writer, allocator))) { + LOG_WARN("fail to construct sstable slice writer", KR(ret), K(target_tablet_id), + K(block_start_seq)); + } else { + LOG_INFO("add sstable slice begin", K(target_tablet_id), K(parallel_idx_)); + const ObDatumRow *datum_row = nullptr; + while (OB_SUCC(ret)) { + if (OB_FAIL(row_iter->get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (OB_FAIL(writer->append_row(*const_cast(datum_row)))) { + LOG_WARN("fail to append row", KR(ret), KPC(datum_row)); + } else if (merge_param_->online_opt_stat_gather_ && OB_FAIL(collect_obj(*datum_row))) { + LOG_WARN("fail to collect statistics", KR(ret)); + } else { + ++affected_rows_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(writer->close())) { + LOG_WARN("fail to close writer", KR(ret)); + } + } + LOG_INFO("add sstable slice end", KR(ret), K(target_tablet_id), K(tablet_id), + K(parallel_idx_), K(affected_rows_)); + } + if (OB_NOT_NULL(row_iter)) { + row_iter->~ObIStoreRowIterator(); + allocator.free(row_iter); + row_iter = nullptr; + } + if (OB_NOT_NULL(writer)) { + writer->~ObSSTableInsertSliceWriter(); + allocator.free(writer); + writer = nullptr; + } + if (OB_SUCC(ret)) { + bool is_ready = false; + if (OB_FAIL(merge_ctx_->inc_finish_count(is_ready))) { + LOG_WARN("fail to inc finish count", KR(ret)); + } else if (is_ready && + OB_FAIL(merge_param_->insert_table_ctx_->notify_tablet_finish(target_tablet_id))) { + LOG_WARN("fail to notify tablet finish", KR(ret), K(target_tablet_id)); + } + } + } + return ret; +} + +int ObDirectLoadPartitionMergeTask::init_sql_statistics() +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret)&& i < merge_param_->table_data_desc_.column_count_; ++i) { + ObOptColumnStat *col_stat = OB_NEWx(ObOptColumnStat, (&allocator_), allocator_); + if (OB_ISNULL(col_stat)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret)); + } else if (OB_FAIL(column_stat_array_.push_back(col_stat))){ + LOG_WARN("fail to push back", KR(ret)); + } + if (OB_FAIL(ret)) { + if (col_stat != nullptr) { + col_stat->~ObOptColumnStat(); + allocator_.free(col_stat); + col_stat = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadPartitionMergeTask::collect_obj(const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + const int64_t extra_rowkey_cnt = ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + if (merge_param_->is_fast_heap_table_ ) { + for (int64_t i = 0; OB_SUCC(ret) && i < merge_param_->table_data_desc_.column_count_; i++) { + const ObStorageDatum &datum = datum_row.storage_datums_[i + extra_rowkey_cnt + 1]; + const ObColDesc &col_desc = merge_param_->col_descs_->at(i + 1); + ObOptColumnStat *col_stat = column_stat_array_.at(i); + if (col_stat != nullptr) { + ObObj obj; + if (OB_FAIL(datum.to_obj_enhance(obj, col_desc.col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(datum_row.storage_datums_[i])); + } else if (OB_FAIL(col_stat->merge_obj(obj))) { + LOG_WARN("Failed to merge obj", K(ret), K(obj), KP(col_stat)); + } + } + } + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < merge_param_->rowkey_column_num_; i++) { + const ObStorageDatum &datum = datum_row.storage_datums_[i]; + const ObColDesc &col_desc = merge_param_->col_descs_->at(i); + ObOptColumnStat *col_stat = column_stat_array_.at(i); + if (col_stat != nullptr) { + ObObj obj; + if (OB_FAIL(datum.to_obj_enhance(obj, col_desc.col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(datum_row.storage_datums_[i])); + } else if (OB_FAIL(col_stat->merge_obj(obj))) { + LOG_WARN("Failed to merge obj", K(ret), K(obj), KP(col_stat)); + } + } + } + for (int64_t i = merge_param_->rowkey_column_num_; OB_SUCC(ret) && i < merge_param_->table_data_desc_.column_count_; i++) { + const ObStorageDatum &datum = datum_row.storage_datums_[i + extra_rowkey_cnt]; + const ObColDesc &col_desc = merge_param_->col_descs_->at(i); + ObOptColumnStat *col_stat = column_stat_array_.at(i); + if (col_stat != nullptr) { + ObObj obj; + if (OB_FAIL(datum.to_obj_enhance(obj, col_desc.col_type_))) { + LOG_WARN("Failed to transform datum to obj", K(ret), K(i), K(datum_row.storage_datums_[i])); + } else if (OB_FAIL(col_stat->merge_obj(obj))) { + LOG_WARN("Failed to merge obj", K(ret), K(obj), KP(col_stat)); + } + } + } + } + return ret; +} + +void ObDirectLoadPartitionMergeTask::stop() +{ + is_stop_ = true; +} + +/** + * ObDirectLoadPartitionRangeMergeTask + */ + +ObDirectLoadPartitionRangeMergeTask::RowIterator::RowIterator() + : rowkey_column_num_(0), is_inited_(false) +{ +} + +ObDirectLoadPartitionRangeMergeTask::RowIterator::~RowIterator() +{ +} + +int ObDirectLoadPartitionRangeMergeTask::RowIterator::init( + const ObDirectLoadMergeParam &merge_param, + const ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionRangeMergeTask::RowIterator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || !tablet_id.is_valid() || + nullptr == origin_table || !range.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), K(tablet_id), K(sstable_array), K(range)); + } else { + // init data_fuse_ + ObDirectLoadDataFuseParam data_fuse_param; + data_fuse_param.tablet_id_ = tablet_id; + data_fuse_param.table_data_desc_ = merge_param.table_data_desc_; + data_fuse_param.datum_utils_ = merge_param.datum_utils_; + data_fuse_param.error_row_handler_ = merge_param.error_row_handler_; + data_fuse_param.dup_action_ = merge_param.error_row_handler_->get_action(); + data_fuse_param.result_info_ = merge_param.result_info_; + if (OB_FAIL(data_fuse_.init(data_fuse_param, origin_table, sstable_array, range))) { + LOG_WARN("fail to init data fuse", KR(ret)); + } + // init datum_row_ + else if (OB_FAIL(datum_row_.init(merge_param.schema_column_count_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + datum_row_.storage_datums_[merge_param.rowkey_column_num_].set_int(-1); // fill trans_version + datum_row_.storage_datums_[merge_param.rowkey_column_num_ + 1].set_int(0); // fill sql_no + rowkey_column_num_ = merge_param.rowkey_column_num_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadPartitionRangeMergeTask::RowIterator::get_next_row(const ObDatumRow *&result_row) +{ + int ret = OB_SUCCESS; + result_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionRangeMergeTask::RowIterator not init", KR(ret), KP(this)); + } else { + const ObDatumRow *datum_row = nullptr; + if (OB_FAIL(data_fuse_.get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } + } else { + // copy rowkey columns + for (int64_t i = 0; i < rowkey_column_num_; ++i) { + datum_row_.storage_datums_[i] = datum_row->storage_datums_[i]; + } + // copy normal columns + for (int64_t i = rowkey_column_num_, + j = rowkey_column_num_ + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + i < datum_row->count_; ++i, ++j) { + datum_row_.storage_datums_[j] = datum_row->storage_datums_[i]; + } + result_row = &datum_row_; + } + } + return ret; +} + +ObDirectLoadPartitionRangeMergeTask::ObDirectLoadPartitionRangeMergeTask() + : origin_table_(nullptr), sstable_array_(nullptr), range_(nullptr) +{ +} + +ObDirectLoadPartitionRangeMergeTask::~ObDirectLoadPartitionRangeMergeTask() +{ +} + +int ObDirectLoadPartitionRangeMergeTask::init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range, + int64_t parallel_idx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionRangeMergeTask init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || nullptr == merge_ctx || + nullptr == origin_table || !range.is_valid() || parallel_idx < 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), KP(merge_ctx), K(sstable_array), K(range), + K(parallel_idx)); + } else { + merge_param_ = &merge_param; + merge_ctx_ = merge_ctx; + parallel_idx_ = parallel_idx; + origin_table_ = origin_table; + sstable_array_ = &sstable_array; + range_ = ⦥ + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadPartitionRangeMergeTask::construct_row_iter(ObIAllocator &allocator, + ObIStoreRowIterator *&result_row_iter) +{ + int ret = OB_SUCCESS; + result_row_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionRangeMergeTask not init", KR(ret), KP(this)); + } else { + RowIterator *row_iter = nullptr; + if (OB_ISNULL(row_iter = OB_NEWx(RowIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new RowIterator", KR(ret)); + } else if (OB_FAIL(row_iter->init(*merge_param_, merge_ctx_->get_tablet_id(), origin_table_, + *sstable_array_, *range_))) { + LOG_WARN("fail to init row iter", KR(ret)); + } else { + result_row_iter = row_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != row_iter) { + row_iter->~RowIterator(); + allocator.free(row_iter); + row_iter = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadPartitionRangeMultipleMergeTask + */ + +ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator::RowIterator() + : rowkey_column_num_(0), is_inited_(false) +{ +} + +ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator::~RowIterator() +{ +} + +int ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator::init( + const ObDirectLoadMergeParam &merge_param, + const ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator init twice", KR(ret), + KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || !tablet_id.is_valid() || + nullptr == origin_table || !range.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), K(tablet_id), K(sstable_array), K(range)); + } else { + // init data_fuse_ + ObDirectLoadDataFuseParam data_fuse_param; + data_fuse_param.tablet_id_ = tablet_id; + data_fuse_param.table_data_desc_ = merge_param.table_data_desc_; + data_fuse_param.datum_utils_ = merge_param.datum_utils_; + data_fuse_param.error_row_handler_ = merge_param.error_row_handler_; + data_fuse_param.dup_action_ = merge_param.error_row_handler_->get_action(); + data_fuse_param.result_info_ = merge_param.result_info_; + if (OB_FAIL(data_fuse_.init(data_fuse_param, origin_table, sstable_array, range))) { + LOG_WARN("fail to init data fuse", KR(ret)); + } + // init datum_row_ + else if (OB_FAIL(datum_row_.init(merge_param.schema_column_count_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + datum_row_.storage_datums_[merge_param.rowkey_column_num_].set_int(-1); // fill trans_version + datum_row_.storage_datums_[merge_param.rowkey_column_num_ + 1].set_int(0); // fill sql_no + rowkey_column_num_ = merge_param.rowkey_column_num_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator::get_next_row( + const ObDatumRow *&result_row) +{ + int ret = OB_SUCCESS; + result_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionRangeMultipleMergeTask::RowIterator not init", KR(ret), + KP(this)); + } else { + const ObDatumRow *datum_row = nullptr; + if (OB_FAIL(data_fuse_.get_next_row(datum_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } + } else { + // copy rowkey columns + for (int64_t i = 0; i < rowkey_column_num_; ++i) { + datum_row_.storage_datums_[i] = datum_row->storage_datums_[i]; + } + // copy normal columns + for (int64_t i = rowkey_column_num_, + j = rowkey_column_num_ + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + i < datum_row->count_; ++i, ++j) { + datum_row_.storage_datums_[j] = datum_row->storage_datums_[i]; + } + result_row = &datum_row_; + } + } + return ret; +} + +ObDirectLoadPartitionRangeMultipleMergeTask::ObDirectLoadPartitionRangeMultipleMergeTask() + : origin_table_(nullptr), sstable_array_(nullptr), range_(nullptr) +{ +} + +ObDirectLoadPartitionRangeMultipleMergeTask::~ObDirectLoadPartitionRangeMultipleMergeTask() +{ +} + +int ObDirectLoadPartitionRangeMultipleMergeTask::init( + const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDatumRange &range, + int64_t parallel_idx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionRangeMultipleMergeTask init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || nullptr == merge_ctx || + nullptr == origin_table || !range.is_valid() || parallel_idx < 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), KP(merge_ctx), K(sstable_array), K(range), + K(parallel_idx)); + } else { + merge_param_ = &merge_param; + merge_ctx_ = merge_ctx; + parallel_idx_ = parallel_idx; + origin_table_ = origin_table; + sstable_array_ = &sstable_array; + range_ = ⦥ + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadPartitionRangeMultipleMergeTask::construct_row_iter( + ObIAllocator &allocator, ObIStoreRowIterator *&result_row_iter) +{ + int ret = OB_SUCCESS; + result_row_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionRangeMultipleMergeTask not init", KR(ret), KP(this)); + } else { + RowIterator *row_iter = nullptr; + if (OB_ISNULL(row_iter = OB_NEWx(RowIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new RowIterator", KR(ret)); + } else if (OB_FAIL(row_iter->init(*merge_param_, merge_ctx_->get_tablet_id(), origin_table_, + *sstable_array_, *range_))) { + LOG_WARN("fail to init row iter", KR(ret)); + } else { + result_row_iter = row_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != row_iter) { + row_iter->~RowIterator(); + allocator.free(row_iter); + row_iter = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadPartitionHeapTableMergeTask + */ + +ObDirectLoadPartitionHeapTableMergeTask::RowIterator::RowIterator() + : deserialize_datums_(nullptr), + deserialize_datum_cnt_(0), + result_info_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadPartitionHeapTableMergeTask::RowIterator::~RowIterator() +{ +} + +int ObDirectLoadPartitionHeapTableMergeTask::RowIterator::init( + const ObDirectLoadMergeParam &merge_param, + const ObTabletID &tablet_id, + ObDirectLoadExternalTable *external_table, + const ObTabletCacheInterval &pk_interval) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionHeapTableMergeTask::RowIterator init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || !tablet_id.is_valid() || + nullptr == external_table || 0 == pk_interval.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), K(tablet_id), KP(external_table), + K(pk_interval)); + } else { + // init scanner_ + if (OB_FAIL(scanner_.init(merge_param.table_data_desc_.external_data_block_size_, + external_table->get_meta().max_data_block_size_, + merge_param.table_data_desc_.compressor_type_, + external_table->get_fragments()))) { + LOG_WARN("fail to init fragment scanner", KR(ret)); + } + // init datum_row_ + else if (OB_FAIL(datum_row_.init(merge_param.schema_column_count_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + datum_row_.storage_datums_[merge_param.rowkey_column_num_].set_int(-1); // fill trans_version + datum_row_.storage_datums_[merge_param.rowkey_column_num_ + 1].set_int(0); // fill sql_no + deserialize_datums_ = datum_row_.storage_datums_ + merge_param.rowkey_column_num_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + deserialize_datum_cnt_ = merge_param.schema_column_count_ - merge_param.rowkey_column_num_; + pk_interval_ = pk_interval; + result_info_ = merge_param.result_info_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadPartitionHeapTableMergeTask::RowIterator::get_next_row( + const ObDatumRow *&result_row) +{ + int ret = OB_SUCCESS; + result_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionRangeMergeTask::RowIterator not init", KR(ret), KP(this)); + } else { + const ObDirectLoadExternalRow *external_row = nullptr; + uint64_t pk_seq = OB_INVALID_ID; + if (OB_FAIL(scanner_.get_next_item(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from merge_sort", KR(ret)); + } + } else if (OB_FAIL(external_row->to_datums(deserialize_datums_, deserialize_datum_cnt_))) { + LOG_WARN("fail to transfer datum row", KR(ret)); + } else if (OB_FAIL(pk_interval_.next_value(pk_seq))) { + LOG_WARN("fail to get next pk seq", KR(ret)); + } else { + // fill hide pk + datum_row_.storage_datums_[0].set_int(pk_seq); + result_row = &datum_row_; + ATOMIC_INC(&result_info_->rows_affected_); + } + } + return ret; +} + +ObDirectLoadPartitionHeapTableMergeTask::ObDirectLoadPartitionHeapTableMergeTask() + : external_table_(nullptr) +{ +} + +ObDirectLoadPartitionHeapTableMergeTask::~ObDirectLoadPartitionHeapTableMergeTask() +{ +} + +int ObDirectLoadPartitionHeapTableMergeTask::init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadExternalTable *external_table, + const ObTabletCacheInterval &pk_interval, + int64_t parallel_idx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionHeapTableMergeTask init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || nullptr == merge_ctx || + nullptr == external_table || parallel_idx < 0 || + 0 == pk_interval.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), KP(merge_ctx), KP(external_table), + K(parallel_idx), K(pk_interval)); + } else { + merge_param_ = &merge_param; + merge_ctx_ = merge_ctx; + parallel_idx_ = parallel_idx; + external_table_ = external_table; + pk_interval_ = pk_interval; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadPartitionHeapTableMergeTask::construct_row_iter( + ObIAllocator &allocator, ObIStoreRowIterator *&result_row_iter) +{ + int ret = OB_SUCCESS; + result_row_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionHeapTableMergeTask not init", KR(ret), KP(this)); + } else { + RowIterator *row_iter = nullptr; + if (OB_ISNULL(row_iter = OB_NEWx(RowIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new RowIterator", KR(ret)); + } else if (OB_FAIL(row_iter->init(*merge_param_, merge_ctx_->get_tablet_id(), external_table_, + pk_interval_))) { + LOG_WARN("fail to init row iter", KR(ret)); + } else { + result_row_iter = row_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != row_iter) { + row_iter->~RowIterator(); + allocator.free(row_iter); + row_iter = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadPartitionHeapTableMultipleMergeTask + */ + +ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator::RowIterator() + : deserialize_datums_(nullptr), + deserialize_datum_cnt_(0), + result_info_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator::~RowIterator() +{ +} + +int ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator::init( + const ObDirectLoadMergeParam &merge_param, + const ObTabletID &tablet_id, + ObDirectLoadMultipleHeapTable *heap_table, + const ObTabletCacheInterval &pk_interval) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator init twice", KR(ret), + KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || !tablet_id.is_valid() || + nullptr == heap_table || 0 == pk_interval.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), K(tablet_id), KPC(heap_table), + K(pk_interval)); + } else { + // init scanner_ + if (OB_FAIL(scanner_.init(heap_table, tablet_id, merge_param.table_data_desc_))) { + LOG_WARN("fail to init tablet whole scanner", KR(ret)); + } + // init datum_row_ + else if (OB_FAIL(datum_row_.init(merge_param.schema_column_count_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + datum_row_.storage_datums_[merge_param.rowkey_column_num_].set_int(-1); // fill trans_version + datum_row_.storage_datums_[merge_param.rowkey_column_num_ + 1].set_int(0); // fill sql_no + deserialize_datums_ = datum_row_.storage_datums_ + merge_param.rowkey_column_num_ + + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt(); + deserialize_datum_cnt_ = merge_param.schema_column_count_ - merge_param.rowkey_column_num_; + pk_interval_ = pk_interval; + result_info_ = merge_param.result_info_; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator::get_next_row( + const ObDatumRow *&result_row) +{ + int ret = OB_SUCCESS; + result_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionHeapTableMultipleMergeTask::RowIterator not init", KR(ret), + KP(this)); + } else { + const ObDirectLoadMultipleExternalRow *external_row = nullptr; + uint64_t pk_seq = OB_INVALID_ID; + if (OB_FAIL(scanner_.get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } + } else if (OB_FAIL(external_row->to_datums(deserialize_datums_, deserialize_datum_cnt_))) { + LOG_WARN("fail to transfer datum row", KR(ret)); + } else if (OB_FAIL(pk_interval_.next_value(pk_seq))) { + LOG_WARN("fail to get next pk seq", KR(ret)); + } else { + // fill hide pk + datum_row_.storage_datums_[0].set_int(pk_seq); + result_row = &datum_row_; + ATOMIC_INC(&result_info_->rows_affected_); + } + } + return ret; +} + +ObDirectLoadPartitionHeapTableMultipleMergeTask::ObDirectLoadPartitionHeapTableMultipleMergeTask() +{ +} + +ObDirectLoadPartitionHeapTableMultipleMergeTask::~ObDirectLoadPartitionHeapTableMultipleMergeTask() +{ +} + +int ObDirectLoadPartitionHeapTableMultipleMergeTask::init( + const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadMultipleHeapTable *heap_table, + const ObTabletCacheInterval &pk_interval, + int64_t parallel_idx) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadPartitionHeapTableMultipleMergeTask init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!merge_param.is_valid() || nullptr == merge_ctx || nullptr == heap_table || + parallel_idx < 0 || 0 == pk_interval.count())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(merge_param), KP(merge_ctx), KPC(heap_table), + K(parallel_idx), K(pk_interval)); + } else { + merge_param_ = &merge_param; + merge_ctx_ = merge_ctx; + parallel_idx_ = parallel_idx; + heap_table_ = heap_table; + pk_interval_ = pk_interval; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadPartitionHeapTableMultipleMergeTask::construct_row_iter( + ObIAllocator &allocator, ObIStoreRowIterator *&result_row_iter) +{ + int ret = OB_SUCCESS; + result_row_iter = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadPartitionHeapTableMultipleMergeTask not init", KR(ret), KP(this)); + } else { + RowIterator *row_iter = nullptr; + if (OB_ISNULL(row_iter = OB_NEWx(RowIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new RowIterator", KR(ret)); + } else if (OB_FAIL(row_iter->init(*merge_param_, merge_ctx_->get_tablet_id(), heap_table_, + pk_interval_))) { + LOG_WARN("fail to init row iter", KR(ret)); + } else { + result_row_iter = row_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != row_iter) { + row_iter->~RowIterator(); + allocator.free(row_iter); + row_iter = nullptr; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_partition_merge_task.h b/src/storage/direct_load/ob_direct_load_partition_merge_task.h new file mode 100644 index 0000000000..3d0b0b9251 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_partition_merge_task.h @@ -0,0 +1,210 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/list/ob_dlist.h" +#include "share/ob_tablet_autoincrement_param.h" +#include "storage/direct_load/ob_direct_load_data_fuse.h" +#include "storage/direct_load/ob_direct_load_external_scanner.h" +#include "storage/direct_load/ob_direct_load_merge_ctx.h" +#include "storage/direct_load/ob_direct_load_multiple_heap_table_scanner.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObDatumRange; +} // namespace blocksstable +namespace common +{ +class ObOptColumnStat; +} // namespace common +namespace storage +{ +class ObDirectLoadOriginTable; +class ObDirectLoadExternalTable; +class ObDirectLoadMultipleSSTable; +class ObDirectLoadMultipleHeapTable; + +class ObDirectLoadPartitionMergeTask : public common::ObDLinkBase +{ +public: + ObDirectLoadPartitionMergeTask(); + virtual ~ObDirectLoadPartitionMergeTask(); + int process(); + const common::ObIArray &get_column_stat_array() const + { + return column_stat_array_; + } + int64_t get_row_count() const { return affected_rows_; } + void stop(); + TO_STRING_KV(KPC_(merge_param), KPC_(merge_ctx), K_(parallel_idx)); +protected: + virtual int construct_row_iter(common::ObIAllocator &allocator, + ObIStoreRowIterator *&row_iter) = 0; +private: + int init_sql_statistics(); + int collect_obj(const blocksstable::ObDatumRow &datum_row); +protected: + const ObDirectLoadMergeParam *merge_param_; + ObDirectLoadTabletMergeCtx *merge_ctx_; + int64_t parallel_idx_; + int64_t affected_rows_; + common::ObArray column_stat_array_; + common::ObArenaAllocator allocator_; + volatile bool is_stop_; + bool is_inited_; +}; + +class ObDirectLoadPartitionRangeMergeTask : public ObDirectLoadPartitionMergeTask +{ +public: + ObDirectLoadPartitionRangeMergeTask(); + virtual ~ObDirectLoadPartitionRangeMergeTask(); + int init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range, + int64_t parallel_idx); +protected: + int construct_row_iter(common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter) override; +private: + class RowIterator : public ObIStoreRowIterator + { + public: + RowIterator(); + virtual ~RowIterator(); + int init(const ObDirectLoadMergeParam &merge_param, + const common::ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; + private: + ObDirectLoadSSTableDataFuse data_fuse_; + blocksstable::ObDatumRow datum_row_; + int64_t rowkey_column_num_; + bool is_inited_; + }; +private: + ObDirectLoadOriginTable *origin_table_; + const ObIArray *sstable_array_; + const blocksstable::ObDatumRange *range_; +}; + +class ObDirectLoadPartitionRangeMultipleMergeTask : public ObDirectLoadPartitionMergeTask +{ +public: + ObDirectLoadPartitionRangeMultipleMergeTask(); + virtual ~ObDirectLoadPartitionRangeMultipleMergeTask(); + int init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range, + int64_t parallel_idx); +protected: + int construct_row_iter(common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter) override; +private: + class RowIterator : public ObIStoreRowIterator + { + public: + RowIterator(); + virtual ~RowIterator(); + int init(const ObDirectLoadMergeParam &merge_param, + const common::ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; + private: + ObDirectLoadMultipleSSTableDataFuse data_fuse_; + blocksstable::ObDatumRow datum_row_; + int64_t rowkey_column_num_; + bool is_inited_; + }; +private: + ObDirectLoadOriginTable *origin_table_; + const ObIArray *sstable_array_; + const blocksstable::ObDatumRange *range_; +}; + +class ObDirectLoadPartitionHeapTableMergeTask : public ObDirectLoadPartitionMergeTask +{ +public: + ObDirectLoadPartitionHeapTableMergeTask(); + virtual ~ObDirectLoadPartitionHeapTableMergeTask(); + int init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadExternalTable *external_table, + const share::ObTabletCacheInterval &pk_interval, + int64_t parallel_idx); +protected: + int construct_row_iter(common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter) override; +private: + class RowIterator : public ObIStoreRowIterator + { + public: + RowIterator(); + virtual ~RowIterator(); + int init(const ObDirectLoadMergeParam &merge_param, + const common::ObTabletID &tablet_id, + ObDirectLoadExternalTable *external_table, + const share::ObTabletCacheInterval &pk_interval); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; + private: + ObDirectLoadExternalSequentialScanner scanner_; + blocksstable::ObDatumRow datum_row_; + blocksstable::ObStorageDatum *deserialize_datums_; + int64_t deserialize_datum_cnt_; + share::ObTabletCacheInterval pk_interval_; + table::ObTableLoadResultInfo *result_info_; + bool is_inited_; + }; +private: + ObDirectLoadExternalTable *external_table_; + share::ObTabletCacheInterval pk_interval_; +}; + +class ObDirectLoadPartitionHeapTableMultipleMergeTask : public ObDirectLoadPartitionMergeTask +{ +public: + ObDirectLoadPartitionHeapTableMultipleMergeTask(); + virtual ~ObDirectLoadPartitionHeapTableMultipleMergeTask(); + int init(const ObDirectLoadMergeParam &merge_param, + ObDirectLoadTabletMergeCtx *merge_ctx, + ObDirectLoadMultipleHeapTable *heap_table, + const share::ObTabletCacheInterval &pk_interval, + int64_t parallel_idx); +protected: + int construct_row_iter(common::ObIAllocator &allocator, ObIStoreRowIterator *&row_iter) override; +private: + class RowIterator : public ObIStoreRowIterator + { + public: + RowIterator(); + virtual ~RowIterator(); + int init(const ObDirectLoadMergeParam &merge_param, + const common::ObTabletID &tablet_id, + ObDirectLoadMultipleHeapTable *heap_table, + const share::ObTabletCacheInterval &pk_interval); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; + private: + ObDirectLoadMultipleHeapTableTabletWholeScanner scanner_; + blocksstable::ObDatumRow datum_row_; + blocksstable::ObStorageDatum *deserialize_datums_; + int64_t deserialize_datum_cnt_; + share::ObTabletCacheInterval pk_interval_; + table::ObTableLoadResultInfo *result_info_; + bool is_inited_; + }; +private: + ObDirectLoadMultipleHeapTable *heap_table_; + share::ObTabletCacheInterval pk_interval_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_range_splitter.cpp b/src/storage/direct_load/ob_direct_load_range_splitter.cpp new file mode 100644 index 0000000000..9f8534a97f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_range_splitter.cpp @@ -0,0 +1,1153 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_range_splitter.h" +#include "storage/blocksstable/ob_sstable.h" +#include "storage/blocksstable/ob_sstable_sec_meta_iterator.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable.h" +#include "storage/direct_load/ob_direct_load_multiple_sstable_index_block_meta_scanner.h" +#include "storage/direct_load/ob_direct_load_origin_table.h" +#include "storage/direct_load/ob_direct_load_sstable.h" +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" +#include "storage/tablet/ob_tablet.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadRangeSplitUtils + */ + +int ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + ObDirectLoadSSTable *sstable, + ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + ObDirectLoadIndexBlockMetaIterator *index_block_meta_iter = nullptr; + ObDirectLoadIndexBlockEndKeyIterator *end_key_iter = nullptr; + if (OB_FAIL(sstable->scan_index_block_meta(allocator, index_block_meta_iter))) { + LOG_WARN("fail to scan index block meta", KR(ret)); + } else if (OB_ISNULL(end_key_iter = + OB_NEWx(ObDirectLoadIndexBlockEndKeyIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadIndexBlockEndKeyIterator", KR(ret)); + } else if (OB_FAIL(end_key_iter->init(index_block_meta_iter))) { + LOG_WARN("fail to init end key iter", KR(ret)); + } else { + rowkey_iter = end_key_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != index_block_meta_iter) { + index_block_meta_iter->~ObDirectLoadIndexBlockMetaIterator(); + allocator.free(index_block_meta_iter); + index_block_meta_iter = nullptr; + } + if (nullptr != end_key_iter) { + end_key_iter->~ObDirectLoadIndexBlockEndKeyIterator(); + allocator.free(end_key_iter); + end_key_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + ObSSTable *sstable, + const ObDatumRange &scan_range, + const ObTableReadInfo &index_read_info, + ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter) +{ + int ret = OB_SUCCESS; + ObSSTableSecMetaIterator *macro_meta_iter = nullptr; + ObDirectLoadMacroBlockEndKeyIterator *end_key_iter = nullptr; + if (OB_FAIL(sstable->scan_secondary_meta(allocator, scan_range, index_read_info, + ObMacroBlockMetaType::DATA_BLOCK_META, + macro_meta_iter))) { + LOG_WARN("fail to scan secondary meta", KR(ret)); + } else if (OB_ISNULL(end_key_iter = + OB_NEWx(ObDirectLoadMacroBlockEndKeyIterator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMacroBlockEndKeyIterator", KR(ret)); + } else if (OB_FAIL(end_key_iter->init(macro_meta_iter))) { + LOG_WARN("fail to init rowkey iter", KR(ret)); + } else { + rowkey_iter = end_key_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != macro_meta_iter) { + macro_meta_iter->~ObSSTableSecMetaIterator(); + allocator.free(macro_meta_iter); + macro_meta_iter = nullptr; + } + if (nullptr != end_key_iter) { + end_key_iter->~ObDirectLoadMacroBlockEndKeyIterator(); + allocator.free(end_key_iter); + end_key_iter = nullptr; + } + } + return ret; +} + +int ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + ObDirectLoadMultipleSSTable *sstable, + const ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils, + ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter = nullptr; + ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator *end_key_iter = nullptr; + if (OB_FAIL(sstable->scan_tablet_whole_index_block_meta(tablet_id, table_data_desc, datum_utils, + allocator, index_block_meta_iter))) { + LOG_WARN("fail to scan index block meta", KR(ret)); + } else if (OB_ISNULL(end_key_iter = + OB_NEWx(ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator, + (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator", KR(ret)); + } else if (OB_FAIL(end_key_iter->init(index_block_meta_iter))) { + LOG_WARN("fail to init end key iter", KR(ret)); + } else { + rowkey_iter = end_key_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != index_block_meta_iter) { + index_block_meta_iter->~ObDirectLoadMultipleSSTableIndexBlockMetaIterator(); + allocator.free(index_block_meta_iter); + index_block_meta_iter = nullptr; + } + if (nullptr != end_key_iter) { + end_key_iter->~ObDirectLoadMultipleSSTableIndexBlockTabletEndKeyIterator(); + allocator.free(end_key_iter); + end_key_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadRangeSplitUtils::construct_multiple_rowkey_iter( + ObDirectLoadMultipleSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + ObIAllocator &allocator, + ObIDirectLoadMultipleDatumRowkeyIterator *&rowkey_iter) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + ObDirectLoadMultipleSSTableIndexBlockMetaIterator *index_block_meta_iter = nullptr; + ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator *end_key_iter = nullptr; + if (OB_FAIL(sstable->scan_whole_index_block_meta(table_data_desc, allocator, + index_block_meta_iter))) { + LOG_WARN("fail to scan index block meta", KR(ret)); + } else if (OB_ISNULL(end_key_iter = OB_NEWx(ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator, + (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator", KR(ret)); + } else if (OB_FAIL(end_key_iter->init(index_block_meta_iter))) { + LOG_WARN("fail to init end key iter", KR(ret)); + } else { + rowkey_iter = end_key_iter; + } + if (OB_FAIL(ret)) { + if (nullptr != index_block_meta_iter) { + index_block_meta_iter->~ObDirectLoadMultipleSSTableIndexBlockMetaIterator(); + allocator.free(index_block_meta_iter); + index_block_meta_iter = nullptr; + } + if (nullptr != end_key_iter) { + end_key_iter->~ObDirectLoadMultipleSSTableIndexBlockEndKeyIterator(); + allocator.free(end_key_iter); + end_key_iter = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadRowkeyMergeRangeSplitter + */ + +ObDirectLoadRowkeyMergeRangeSplitter::ObDirectLoadRowkeyMergeRangeSplitter() + : total_rowkey_count_(0), + datum_utils_(nullptr), + is_memtable_valid_(false), + col_descs_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadRowkeyMergeRangeSplitter::~ObDirectLoadRowkeyMergeRangeSplitter() +{ +} + +int ObDirectLoadRowkeyMergeRangeSplitter::init( + const ObIArray &rowkey_iters, + int64_t total_rowkey_count, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadRowkeyMergeRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(rowkey_iters.empty() || nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(rowkey_iters.count()), K(total_rowkey_count), + KP(datum_utils)); + } else { + if (OB_FAIL(compare_.init(*datum_utils))) { + LOG_WARN("fail to init rowkey compare", KR(ret)); + } else if (OB_FAIL(rowkey_merger_.init(rowkey_iters, &compare_))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else { + total_rowkey_count_ = total_rowkey_count; + datum_utils_ = datum_utils; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadRowkeyMergeRangeSplitter::set_memtable_valid(const ObIArray &col_descs) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadRowkeyMergeRangeSplitter not init", KR(ret), KP(this)); + } else { + col_descs_ = &col_descs; + is_memtable_valid_ = true; + } + return ret; +} + +int ObDirectLoadRowkeyMergeRangeSplitter::check_range_memtable_valid(ObDatumRange &range, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (is_memtable_valid_) { + if (!range.start_key_.is_memtable_valid() && + OB_FAIL(range.start_key_.prepare_memtable_readable(*col_descs_, allocator))) { + LOG_WARN("fail to prepare memtable readable", KR(ret), K(range)); + } else if (!range.end_key_.is_memtable_valid() && + OB_FAIL(range.end_key_.prepare_memtable_readable(*col_descs_, allocator))) { + LOG_WARN("fail to prepare memtable readable", KR(ret), K(range)); + } + } + return ret; +} + +int ObDirectLoadRowkeyMergeRangeSplitter::split_range(ObIArray &range_array, + int64_t max_range_count, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadRowkeyMergeRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(max_range_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(max_range_count)); + } else { + range_array.reset(); + const int64_t range_count = MIN(total_rowkey_count_, max_range_count); + if (range_count > 1) { + const int64_t block_count_per_range = (total_rowkey_count_ + range_count - 1) / range_count; + ObDatumRange range; + range.end_key_.set_min_rowkey(); + range.set_left_open(); + range.set_right_closed(); + int64_t count = 0; + const ObDatumRowkey *rowkey = nullptr; + while (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_merger_.get_next_rowkey(rowkey))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + if (count > 0) { + range.start_key_ = range.end_key_; + range.end_key_.set_max_rowkey(); + range.set_right_open(); + if (OB_FAIL(check_range_memtable_valid(range, allocator))) { + LOG_WARN("fail to check range memtable valid", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back datum ranges", KR(ret)); + } + } else { + ObDatumRange &last_range = range_array.at(range_array.count() - 1); + last_range.end_key_.set_max_rowkey(); + last_range.set_right_open(); + } + break; + } + } else if (++count >= block_count_per_range) { + bool rowkey_equal = false; + if (OB_FAIL(rowkey->equal(range.end_key_, *datum_utils_, rowkey_equal))) { + LOG_WARN("fail to compare euqal rowkey", KR(ret)); + } else if (rowkey_equal) { + // next rowkey + } else { + range.start_key_ = range.end_key_; + if (OB_FAIL(rowkey->deep_copy(range.end_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret), K(rowkey)); + } else if (OB_FAIL(check_range_memtable_valid(range, allocator))) { + LOG_WARN("fail to check range memtable valid", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back datum ranges", KR(ret)); + } else { + count = 0; + } + } + } + } + } + if (OB_SUCC(ret) && range_array.empty()) { + ObDatumRange range; + range.set_whole_range(); + if (OB_FAIL(check_range_memtable_valid(range, allocator))) { + LOG_WARN("fail to check range memtable valid", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back range", KR(ret)); + } + } + } + return ret; +} + +/** + * ObDirectLoadSSTableRangeSplitter + */ + +ObDirectLoadSSTableRangeSplitter::ObDirectLoadSSTableRangeSplitter() + : allocator_("TLD_SSTRGSplit"), total_block_count_(0), is_inited_(false) +{ +} + +ObDirectLoadSSTableRangeSplitter::~ObDirectLoadSSTableRangeSplitter() +{ + for (int64_t i = 0; i < rowkey_iters_.count(); ++i) { + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = rowkey_iters_.at(i); + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + } + rowkey_iters_.reset(); +} + +int ObDirectLoadSSTableRangeSplitter::init(const ObIArray &sstable_array, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(sstable_array.empty() || nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(sstable_array), KP(datum_utils)); + } else { + if (OB_FAIL(construct_rowkey_iters(sstable_array))) { + LOG_WARN("fail to construct rowkey itres", KR(ret)); + } else if (OB_FAIL( + rowkey_merge_splitter_.init(rowkey_iters_, total_block_count_, datum_utils))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadSSTableRangeSplitter::construct_rowkey_iters( + const ObIArray &sstable_array) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadSSTable *sstable = sstable_array.at(i); + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + total_block_count_ += sstable->get_meta().index_block_count_; + if (OB_FAIL( + ObDirectLoadRangeSplitUtils::construct_rowkey_iter(sstable, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + rowkey_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadSSTableRangeSplitter::split_range(ObIArray &range_array, + int64_t max_range_count, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_FAIL(rowkey_merge_splitter_.split_range(range_array, max_range_count, allocator))) { + LOG_WARN("fail to split range", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMergeRangeSplitter + */ + +ObDirectLoadMergeRangeSplitter::ObDirectLoadMergeRangeSplitter() + : allocator_("TLD_MegRGSplit"), total_block_count_(0), is_inited_(false) +{ +} + +ObDirectLoadMergeRangeSplitter::~ObDirectLoadMergeRangeSplitter() +{ + for (int64_t i = 0; i < rowkey_iters_.count(); ++i) { + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = rowkey_iters_.at(i); + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + } + rowkey_iters_.reset(); +} + +int ObDirectLoadMergeRangeSplitter::init(ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObStorageDatumUtils *datum_utils, + const ObIArray &col_descs) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMergeRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == origin_table || !origin_table->is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(origin_table), K(sstable_array), KP(datum_utils)); + } else { + scan_range_.set_whole_range(); + if (OB_FAIL(construct_origin_table_rowkey_iter(origin_table))) { + LOG_WARN("fail to construct origin sstable rowkey itre", KR(ret)); + } else if (OB_FAIL(construct_sstable_rowkey_iters(sstable_array))) { + LOG_WARN("fail to construct sstable rowkey itres", KR(ret)); + } else if (OB_FAIL( + rowkey_merge_splitter_.init(rowkey_iters_, total_block_count_, datum_utils))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else if (OB_FAIL(rowkey_merge_splitter_.set_memtable_valid(col_descs))) { + LOG_WARN("fail to set memtable valid", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMergeRangeSplitter::construct_origin_table_rowkey_iter( + ObDirectLoadOriginTable *origin_table) +{ + int ret = OB_SUCCESS; + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + origin_table->get_major_sstable(), scan_range_, + origin_table->get_tablet_handle().get_obj()->get_index_read_info(), allocator_, + rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } else { + total_block_count_ += + origin_table->get_major_sstable()->get_meta().get_basic_meta().data_macro_block_count_; + } + return ret; +} + +int ObDirectLoadMergeRangeSplitter::construct_sstable_rowkey_iters( + const ObIArray &sstable_array) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadSSTable *sstable = sstable_array.at(i); + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL( + ObDirectLoadRangeSplitUtils::construct_rowkey_iter(sstable, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } else { + total_block_count_ += sstable->get_meta().index_block_count_; + } + if (OB_FAIL(ret)) { + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + rowkey_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMergeRangeSplitter::split_range(ObIArray &range_array, + int64_t max_range_count, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMergeRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_FAIL(rowkey_merge_splitter_.split_range(range_array, max_range_count, allocator))) { + LOG_WARN("fail to split range", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMultipleMergeTabletRangeSplitter + */ + +ObDirectLoadMultipleMergeTabletRangeSplitter::ObDirectLoadMultipleMergeTabletRangeSplitter() + : allocator_("TLD_MulMegTRS"), total_block_count_(0), is_inited_(false) +{ +} + +ObDirectLoadMultipleMergeTabletRangeSplitter::~ObDirectLoadMultipleMergeTabletRangeSplitter() +{ + for (int64_t i = 0; i < rowkey_iters_.count(); ++i) { + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = rowkey_iters_.at(i); + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + } + rowkey_iters_.reset(); +} + +int ObDirectLoadMultipleMergeTabletRangeSplitter::init( + const ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils, + const ObIArray &col_descs) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleMergeTabletRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || nullptr == origin_table || + !origin_table->is_valid() || !table_data_desc.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), KPC(origin_table), K(sstable_array), + K(table_data_desc), KP(datum_utils)); + } else { + tablet_id_ = tablet_id; + scan_range_.set_whole_range(); + if (OB_FAIL(construct_origin_table_rowkey_iter(origin_table))) { + LOG_WARN("fail to construct origin sstable rowkey itre", KR(ret)); + } else if (OB_FAIL( + construct_sstable_rowkey_iters(sstable_array, table_data_desc, datum_utils))) { + LOG_WARN("fail to construct sstable rowkey itres", KR(ret)); + } else if (OB_FAIL( + rowkey_merge_splitter_.init(rowkey_iters_, total_block_count_, datum_utils))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else if (OB_FAIL(rowkey_merge_splitter_.set_memtable_valid(col_descs))) { + LOG_WARN("fail to set memtable valid", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleMergeTabletRangeSplitter::construct_origin_table_rowkey_iter( + ObDirectLoadOriginTable *origin_table) +{ + int ret = OB_SUCCESS; + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + origin_table->get_major_sstable(), scan_range_, + origin_table->get_tablet_handle().get_obj()->get_index_read_info(), allocator_, + rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } else { + total_block_count_ += + origin_table->get_major_sstable()->get_meta().get_basic_meta().data_macro_block_count_; + } + return ret; +} + +int ObDirectLoadMultipleMergeTabletRangeSplitter::construct_sstable_rowkey_iters( + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstable_array.at(i); + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + int64_t block_count = 0; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + sstable, tablet_id_, table_data_desc, datum_utils, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } else if (OB_FAIL(get_sstable_index_block_count(sstable, table_data_desc, datum_utils, + block_count))) { + LOG_WARN("fail to get sstable index block count", KR(ret)); + } else { + total_block_count_ += block_count; + } + if (OB_FAIL(ret)) { + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + rowkey_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMultipleMergeTabletRangeSplitter::get_sstable_index_block_count( + ObDirectLoadMultipleSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils, + int64_t &block_count) +{ + int ret = OB_SUCCESS; + block_count = 0; + const ObDatumRowkey *rowkey = nullptr; + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + sstable, tablet_id_, table_data_desc, datum_utils, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } + while (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_iter->get_next_rowkey(rowkey))) { + if (OB_FAIL(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else { + ++block_count; + } + } + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + rowkey_iter = nullptr; + } + return ret; +} + +int ObDirectLoadMultipleMergeTabletRangeSplitter::split_range(ObIArray &range_array, + int64_t max_range_count, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleMergeTabletRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_FAIL(rowkey_merge_splitter_.split_range(range_array, max_range_count, allocator))) { + LOG_WARN("fail to split range", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadMultipleMergeRangeSplitter + */ + +ObDirectLoadMultipleMergeRangeSplitter::ObDirectLoadMultipleMergeRangeSplitter() + : allocator_("TLD_MulMegRS"), + datum_utils_(nullptr), + col_descs_(nullptr), + last_rowkey_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadMultipleMergeRangeSplitter::~ObDirectLoadMultipleMergeRangeSplitter() +{ + for (int64_t i = 0; i < rowkey_iters_.count(); ++i) { + ObIDirectLoadMultipleDatumRowkeyIterator *rowkey_iter = rowkey_iters_.at(i); + rowkey_iter->~ObIDirectLoadMultipleDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + } + rowkey_iters_.reset(); +} + +int ObDirectLoadMultipleMergeRangeSplitter::init( + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils, + const ObIArray &col_descs) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleMergeRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(sstable_array.empty() || !table_data_desc.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(sstable_array), K(table_data_desc), KP(datum_utils)); + } else { + allocator_.set_tenant_id(MTL_ID()); + if (OB_FAIL(construct_rowkey_iters(sstable_array, table_data_desc, datum_utils))) { + LOG_WARN("fail to construct sstable rowkey itres", KR(ret)); + } else if (OB_FAIL(compare_.init(*datum_utils))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(rowkey_merger_.init(rowkey_iters_, &compare_))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else { + datum_utils_ = datum_utils; + col_descs_ = &col_descs; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::construct_rowkey_iters( + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstable_array.at(i); + ObIDirectLoadMultipleDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_multiple_rowkey_iter( + sstable, table_data_desc, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadMultipleDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + rowkey_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::prepare_range_memtable_readable( + ObDatumRange &range, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (!range.start_key_.is_memtable_valid() && + OB_FAIL(range.start_key_.prepare_memtable_readable(*col_descs_, allocator))) { + LOG_WARN("fail to prepare memtable readable", KR(ret), K(range)); + } else if (!range.end_key_.is_memtable_valid() && + OB_FAIL(range.end_key_.prepare_memtable_readable(*col_descs_, allocator))) { + LOG_WARN("fail to prepare memtable readable", KR(ret), K(range)); + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::get_rowkeys_by_origin( + ObDirectLoadOriginTable *origin_table, + ObIArray &rowkey_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObIDirectLoadDatumRowkeyIterator *rowkey_iter = nullptr; + ObDatumRange scan_range; + scan_range.set_whole_range(); + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_rowkey_iter( + origin_table->get_major_sstable(), scan_range, + origin_table->get_tablet_handle().get_obj()->get_index_read_info(), allocator, + rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else { + const ObDatumRowkey *datum_rowkey = nullptr; + ObDatumRowkey copied_rowkey; + int64_t count = 0; + while (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_iter->get_next_rowkey(datum_rowkey))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (++count >= BLOCK_COUNT_PER_RANGE) { + if (OB_FAIL(datum_rowkey->deep_copy(copied_rowkey, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(rowkey_array.push_back(copied_rowkey))) { + LOG_WARN("fail to push back", KR(ret)); + } else { + count = 0; + } + } + } + } + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadDatumRowkeyIterator(); + allocator.free(rowkey_iter); + rowkey_iter = nullptr; + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::get_rowkeys_by_multiple( + ObTabletID &tablet_id, ObIArray &rowkey_array, ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (nullptr == last_rowkey_ && OB_FAIL(rowkey_merger_.get_next_rowkey(last_rowkey_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + last_rowkey_ = nullptr; + } + } + if (OB_SUCC(ret) && nullptr != last_rowkey_) { + if (last_rowkey_->tablet_id_.compare(tablet_id) == 0) { + // the same tablet + ObDatumRowkey rowkey; + ObDatumRowkey copied_rowkey; + int count = 0; + while (OB_SUCC(ret)) { + if (++count >= BLOCK_COUNT_PER_RANGE) { + if (OB_FAIL(last_rowkey_->get_rowkey(rowkey))) { + LOG_WARN("fail to get rowkey", KR(ret)); + } else if (OB_FAIL(rowkey.deep_copy(copied_rowkey, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(rowkey_array.push_back(copied_rowkey))) { + LOG_WARN("fail to push back", KR(ret)); + } else { + count = 0; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_merger_.get_next_rowkey(last_rowkey_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + last_rowkey_ = nullptr; + break; + } + } else if (last_rowkey_->tablet_id_.compare(tablet_id) != 0) { + break; + } + } + } + } else { + // the different tablet + abort_unless(last_rowkey_->tablet_id_.compare(tablet_id) > 0); + } + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::combine_final_ranges( + const ObIArray &rowkey_array1, + const ObIArray &rowkey_array2, + int64_t max_range_count, + ObIArray &range_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (rowkey_array1.empty() && rowkey_array2.empty()) { + ObDatumRange range; + range.set_whole_range(); + if (OB_FAIL(prepare_range_memtable_readable(range, allocator))) { + LOG_WARN("fail to prepare range memtable readable", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back range", KR(ret)); + } + } else { + ObDirectLoadDatumRowkeyArrayIterator rowkey_range_iters[2]; + ObSEArray rowkey_iters; + ObDirectLoadDatumRowkeyCompare compare; + RowkeyMerger rowkey_merger; + if (OB_FAIL(rowkey_range_iters[0].init(rowkey_array1))) { + LOG_WARN("fail to init rowkey range iter", KR(ret)); + } else if (OB_FAIL(rowkey_range_iters[1].init(rowkey_array2))) { + LOG_WARN("fail to init rowkey range iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters.push_back(&rowkey_range_iters[0]))) { + LOG_WARN("fail to push back", KR(ret)); + } else if (OB_FAIL(rowkey_iters.push_back(&rowkey_range_iters[1]))) { + LOG_WARN("fail to push back", KR(ret)); + } else if (OB_FAIL(compare.init(*datum_utils_))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(rowkey_merger.init(rowkey_iters, &compare))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else { + const int64_t rowkey_count_per_range = + (rowkey_array1.count() + rowkey_array2.count() + max_range_count - 1) / max_range_count; + ObDatumRange range; + range.end_key_.set_min_rowkey(); + range.set_left_open(); + range.set_right_closed(); + const ObDatumRowkey *datum_rowkey = nullptr; + int64_t count = 0; + while (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_merger.get_next_rowkey(datum_rowkey))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + break; + } + } else if (++count >= rowkey_count_per_range) { + int cmp_ret = 0; + if (OB_FAIL(datum_rowkey->compare(range.end_key_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (OB_LIKELY(cmp_ret > 0)) { + range.start_key_ = range.end_key_; + if (OB_FAIL(datum_rowkey->deep_copy(range.end_key_, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret)); + } else if (OB_FAIL(prepare_range_memtable_readable(range, allocator))) { + LOG_WARN("fail to prepare range memtable readable", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back range", KR(ret)); + } else { + count = 0; + } + } else { + abort_unless(0 == cmp_ret); + } + } + } + if (OB_SUCC(ret)) { + if (count > 0 || range_array.empty()) { + range.start_key_ = range.end_key_; + range.end_key_.set_max_rowkey(); + range.set_right_open(); + if (OB_FAIL(prepare_range_memtable_readable(range, allocator))) { + LOG_WARN("fail to prepare range memtable readable", KR(ret)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back range", KR(ret)); + } + } else { + ObDatumRange &last_range = range_array.at(range_array.count() - 1); + last_range.end_key_.set_max_rowkey(); + last_range.set_right_open(); + } + } + } + } + return ret; +} + +int ObDirectLoadMultipleMergeRangeSplitter::split_range(ObTabletID &tablet_id, + ObDirectLoadOriginTable *origin_table, + int64_t max_range_count, + ObIArray &range_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + range_array.reset(); + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleMergeRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || nullptr == origin_table || + !origin_table->is_valid() || max_range_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), KPC(origin_table), K(max_range_count)); + } else if (last_tablet_id_.is_valid() && OB_UNLIKELY(last_tablet_id_.compare(tablet_id) >= 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected tablet id", KR(ret), K(tablet_id), K(last_tablet_id_)); + } else { + ObArenaAllocator tmp_allocator("MTL_MulMRS_Tmp"); + ObArray origin_rowkey_array; + ObArray multiple_rowkey_array; + tmp_allocator.set_tenant_id(MTL_ID()); + if (OB_FAIL(get_rowkeys_by_origin(origin_table, origin_rowkey_array, tmp_allocator))) { + LOG_WARN("fail to get rowkeys by origin", KR(ret)); + } else if (OB_FAIL(get_rowkeys_by_multiple(tablet_id, multiple_rowkey_array, tmp_allocator))) { + LOG_WARN("fail to get rowkeys by multiple", KR(ret)); + } else if (OB_FAIL(combine_final_ranges(origin_rowkey_array, multiple_rowkey_array, + max_range_count, range_array, allocator))) { + LOG_WARN("fail to combine final range", KR(ret)); + } else { + last_tablet_id_ = tablet_id; + } + } + return ret; +} + +/** + * ObDirectLoadMultipleSSTableRangeSplitter + */ + +ObDirectLoadMultipleSSTableRangeSplitter::ObDirectLoadMultipleSSTableRangeSplitter() + : allocator_("TLD_MulSSTRS"), datum_utils_(nullptr), total_block_count_(0), is_inited_(false) +{ +} + +ObDirectLoadMultipleSSTableRangeSplitter::~ObDirectLoadMultipleSSTableRangeSplitter() +{ + for (int64_t i = 0; i < rowkey_iters_.count(); ++i) { + ObIDirectLoadMultipleDatumRowkeyIterator *rowkey_iter = rowkey_iters_.at(i); + rowkey_iter->~ObIDirectLoadMultipleDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + } + rowkey_iters_.reset(); +} + +int ObDirectLoadMultipleSSTableRangeSplitter::init( + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMultipleSSTableRangeSplitter init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(sstable_array.empty() || !table_data_desc.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(sstable_array), K(table_data_desc), KP(datum_utils)); + } else { + datum_utils_ = datum_utils; + if (OB_FAIL(construct_rowkey_iters(sstable_array, table_data_desc, datum_utils))) { + LOG_WARN("fail to construct rowkey iters", KR(ret)); + } else if (OB_FAIL(compare_.init(*datum_utils))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(rowkey_merger_.init(rowkey_iters_, &compare_))) { + LOG_WARN("fail to init rowkey merger", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableRangeSplitter::construct_rowkey_iters( + const ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadMultipleSSTable *sstable = sstable_array.at(i); + ObIDirectLoadMultipleDatumRowkeyIterator *rowkey_iter = nullptr; + if (OB_FAIL(ObDirectLoadRangeSplitUtils::construct_multiple_rowkey_iter( + sstable, table_data_desc, allocator_, rowkey_iter))) { + LOG_WARN("fail to construct rowkey iter", KR(ret)); + } else if (OB_FAIL(rowkey_iters_.push_back(rowkey_iter))) { + LOG_WARN("fail to push back rowkey iter", KR(ret)); + } else { + total_block_count_ += sstable->get_meta().index_block_count_; + } + if (OB_FAIL(ret)) { + if (nullptr != rowkey_iter) { + rowkey_iter->~ObIDirectLoadMultipleDatumRowkeyIterator(); + allocator_.free(rowkey_iter); + rowkey_iter = nullptr; + } + } + } + return ret; +} + +int ObDirectLoadMultipleSSTableRangeSplitter::split_range( + ObIArray &range_array, + int64_t max_range_count, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMultipleSSTableRangeSplitter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(max_range_count <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(max_range_count)); + } else { + range_array.reset(); + const int64_t range_count = MIN(total_block_count_, max_range_count); + if (range_count <= 1) { + ObDirectLoadMultipleDatumRange range; + range.set_whole_range(); + if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back range", KR(ret)); + } + } else { + const int64_t block_count_per_range = (total_block_count_ + range_count - 1) / range_count; + ObDirectLoadMultipleDatumRange range; + range.end_key_.set_min_rowkey(); + range.set_left_open(); + range.set_right_closed(); + int64_t count = 0; + const ObDirectLoadMultipleDatumRowkey *rowkey = nullptr; + while (OB_SUCC(ret)) { + if (OB_FAIL(rowkey_merger_.get_next_rowkey(rowkey))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next rowkey", KR(ret)); + } else { + ret = OB_SUCCESS; + if (count > 0) { + range.start_key_ = range.end_key_; + range.end_key_.set_max_rowkey(); + range.set_right_open(); + if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back datum ranges", KR(ret)); + } + } else { + ObDirectLoadMultipleDatumRange &last_range = range_array.at(range_array.count() - 1); + last_range.end_key_.set_max_rowkey(); + last_range.set_right_open(); + } + break; + } + } else if (++count >= block_count_per_range) { + int cmp_ret = 0; + if (OB_FAIL(rowkey->compare(range.end_key_, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare euqal rowkey", KR(ret)); + } else if (cmp_ret == 0) { + // next rowkey + } else { + range.start_key_ = range.end_key_; + if (OB_FAIL(range.end_key_.deep_copy(*rowkey, allocator))) { + LOG_WARN("fail to deep copy rowkey", KR(ret), K(rowkey)); + } else if (OB_FAIL(range_array.push_back(range))) { + LOG_WARN("fail to push back datum ranges", KR(ret)); + } else { + count = 0; + } + } + } + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_range_splitter.h b/src/storage/direct_load/ob_direct_load_range_splitter.h new file mode 100644 index 0000000000..184d9676eb --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_range_splitter.h @@ -0,0 +1,223 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_range.h" +#include "storage/direct_load/ob_direct_load_compare.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_range.h" +#include "storage/direct_load/ob_direct_load_rowkey_merger.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObSSTable; +} // namespace blocksstable +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObTableReadInfo; +class ObDirectLoadOriginTable; +class ObDirectLoadSSTable; +class ObDirectLoadMultipleSSTable; + +class ObDirectLoadRangeSplitUtils +{ +public: + static int construct_rowkey_iter(ObDirectLoadSSTable *sstable, common::ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter); + static int construct_rowkey_iter(blocksstable::ObSSTable *sstable, + const blocksstable::ObDatumRange &scan_range, + const ObTableReadInfo &index_read_info, + common::ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter); + static int construct_rowkey_iter(ObDirectLoadMultipleSSTable *sstable, + const common::ObTabletID &tablet_id, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils, + common::ObIAllocator &allocator, + ObIDirectLoadDatumRowkeyIterator *&rowkey_iter); + static int construct_multiple_rowkey_iter(ObDirectLoadMultipleSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + common::ObIAllocator &allocator, + ObIDirectLoadMultipleDatumRowkeyIterator *&rowkey_iter); +}; + +class ObDirectLoadRowkeyMergeRangeSplitter +{ + typedef ObDirectLoadRowkeyMerger + RowkeyMerger; +public: + ObDirectLoadRowkeyMergeRangeSplitter(); + virtual ~ObDirectLoadRowkeyMergeRangeSplitter(); + int init(const common::ObIArray &rowkey_iters, + int64_t total_rowkey_count, const blocksstable::ObStorageDatumUtils *datum_utils); + int set_memtable_valid(const common::ObIArray &col_descs); + int split_range(common::ObIArray &range_array, + int64_t max_range_count, common::ObIAllocator &allocator); +private: + int check_range_memtable_valid(blocksstable::ObDatumRange &range, + common::ObIAllocator &allocator); +private: + int64_t total_rowkey_count_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadDatumRowkeyCompare compare_; + RowkeyMerger rowkey_merger_; + bool is_memtable_valid_; + const common::ObIArray *col_descs_; + bool is_inited_; +}; + +class ObDirectLoadSSTableRangeSplitter +{ +public: + ObDirectLoadSSTableRangeSplitter(); + ~ObDirectLoadSSTableRangeSplitter(); + int init(const common::ObIArray &sstable_array, + const blocksstable::ObStorageDatumUtils *datum_utils); + int split_range(common::ObIArray &range_array, + int64_t max_range_count, common::ObIAllocator &allocator); +private: + int construct_rowkey_iters(const common::ObIArray &sstable_array); +private: + common::ObArenaAllocator allocator_; + ObSEArray rowkey_iters_; + int64_t total_block_count_; + ObDirectLoadRowkeyMergeRangeSplitter rowkey_merge_splitter_; + bool is_inited_; +}; + +class ObDirectLoadMergeRangeSplitter +{ +public: + ObDirectLoadMergeRangeSplitter(); + ~ObDirectLoadMergeRangeSplitter(); + int init(ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const blocksstable::ObStorageDatumUtils *datum_utils, + const common::ObIArray &col_descs); + int split_range(common::ObIArray &range_array, + int64_t max_range_count, common::ObIAllocator &allocator); +private: + int construct_origin_table_rowkey_iter(ObDirectLoadOriginTable *origin_table); + int construct_sstable_rowkey_iters(const common::ObIArray &sstable_array); +private: + common::ObArenaAllocator allocator_; + blocksstable::ObDatumRange scan_range_; + ObSEArray rowkey_iters_; + int64_t total_block_count_; + ObDirectLoadRowkeyMergeRangeSplitter rowkey_merge_splitter_; + bool is_inited_; +}; + +class ObDirectLoadMultipleMergeTabletRangeSplitter +{ +public: + ObDirectLoadMultipleMergeTabletRangeSplitter(); + ~ObDirectLoadMultipleMergeTabletRangeSplitter(); + int init(const common::ObTabletID &tablet_id, ObDirectLoadOriginTable *origin_table, + const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils, + const common::ObIArray &col_descs); + int split_range(common::ObIArray &range_array, + int64_t max_range_count, common::ObIAllocator &allocator); +private: + int construct_origin_table_rowkey_iter(ObDirectLoadOriginTable *origin_table); + int construct_sstable_rowkey_iters( + const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils); + int get_sstable_index_block_count(ObDirectLoadMultipleSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils, + int64_t &block_count); +private: + common::ObArenaAllocator allocator_; + common::ObTabletID tablet_id_; + blocksstable::ObDatumRange scan_range_; + ObSEArray rowkey_iters_; + int64_t total_block_count_; + ObDirectLoadRowkeyMergeRangeSplitter rowkey_merge_splitter_; + bool is_inited_; +}; + +class ObDirectLoadMultipleMergeRangeSplitter +{ + static const int64_t BLOCK_COUNT_PER_RANGE = 16; + typedef ObDirectLoadRowkeyMerger + MultipleRowkeyMerger; + typedef ObDirectLoadRowkeyMerger + RowkeyMerger; +public: + ObDirectLoadMultipleMergeRangeSplitter(); + ~ObDirectLoadMultipleMergeRangeSplitter(); + int init(const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils, + const common::ObIArray &col_descs); + int split_range(common::ObTabletID &tablet_id, ObDirectLoadOriginTable *origin_table, + int64_t max_range_count, + common::ObIArray &range_array, + common::ObIAllocator &allocator); +private: + int construct_rowkey_iters(const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils); + int prepare_range_memtable_readable(blocksstable::ObDatumRange &range, + common::ObIAllocator &allocator); + int get_rowkeys_by_origin(ObDirectLoadOriginTable *origin_table, + common::ObIArray &rowkey_array, + common::ObIAllocator &allocator); + int get_rowkeys_by_multiple(common::ObTabletID &tablet_id, + common::ObIArray &rowkey_array, + common::ObIAllocator &allocator); + int combine_final_ranges(const common::ObIArray &rowkey_array1, + const common::ObIArray &rowkey_array2, + int64_t max_range_count, + common::ObIArray &range_array, + common::ObIAllocator &allocator); +private: + common::ObArenaAllocator allocator_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + const common::ObIArray *col_descs_; + common::ObArray rowkey_iters_; + ObDirectLoadMultipleDatumRowkeyCompare compare_; + MultipleRowkeyMerger rowkey_merger_; + common::ObTabletID last_tablet_id_; + const ObDirectLoadMultipleDatumRowkey *last_rowkey_; + bool is_inited_; +}; + +class ObDirectLoadMultipleSSTableRangeSplitter +{ + typedef ObDirectLoadRowkeyMerger + RowkeyMerger; +public: + ObDirectLoadMultipleSSTableRangeSplitter(); + ~ObDirectLoadMultipleSSTableRangeSplitter(); + int init(const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils); + int split_range(common::ObIArray &range_array, + int64_t max_range_count, common::ObIAllocator &allocator); +private: + int construct_rowkey_iters(const common::ObIArray &sstable_array, + const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObStorageDatumUtils *datum_utils); +private: + common::ObArenaAllocator allocator_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObSEArray rowkey_iters_; + int64_t total_block_count_; + ObDirectLoadMultipleDatumRowkeyCompare compare_; + RowkeyMerger rowkey_merger_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_rowkey_iterator.cpp b/src/storage/direct_load/ob_direct_load_rowkey_iterator.cpp new file mode 100644 index 0000000000..473e0e51ac --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_rowkey_iterator.cpp @@ -0,0 +1,116 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_rowkey_iterator.h" +#include "storage/blocksstable/ob_sstable_sec_meta_iterator.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadDatumRowkeyArrayIterator + */ + +ObDirectLoadDatumRowkeyArrayIterator::ObDirectLoadDatumRowkeyArrayIterator() + : rowkey_array_(nullptr), pos_(0), is_inited_(false) +{ +} + +ObDirectLoadDatumRowkeyArrayIterator::~ObDirectLoadDatumRowkeyArrayIterator() +{ +} + +int ObDirectLoadDatumRowkeyArrayIterator::init(const ObIArray &rowkey_array) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDatumRowkeyArrayIterator init twice", KR(ret), KP(this)); + } else { + rowkey_array_ = &rowkey_array; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadDatumRowkeyArrayIterator::get_next_rowkey(const ObDatumRowkey *&rowkey) +{ + int ret = OB_SUCCESS; + rowkey = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDatumRowkeyArrayIterator not init", KR(ret), KP(this)); + } else if (pos_ >= rowkey_array_->count()) { + ret = OB_ITER_END; + } else { + rowkey = &rowkey_array_->at(pos_++); + } + return ret; +} + +/** + * ObDirectLoadMacroBlockEndKeyIterator + */ + +ObDirectLoadMacroBlockEndKeyIterator::ObDirectLoadMacroBlockEndKeyIterator() + : macro_meta_iter_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadMacroBlockEndKeyIterator::~ObDirectLoadMacroBlockEndKeyIterator() +{ + if (nullptr != macro_meta_iter_) { + macro_meta_iter_->~ObSSTableSecMetaIterator(); + macro_meta_iter_ = nullptr; + } +} + +int ObDirectLoadMacroBlockEndKeyIterator::init(ObSSTableSecMetaIterator *macro_meta_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadMacroBlockEndKeyIterator init twice", KR(ret), KP(this)); + } else if (OB_ISNULL(macro_meta_iter)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(macro_meta_iter)); + } else { + macro_meta_iter_ = macro_meta_iter; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadMacroBlockEndKeyIterator::get_next_rowkey(const ObDatumRowkey *&rowkey) +{ + int ret = OB_SUCCESS; + rowkey = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadMacroBlockEndKeyIterator not init", KR(ret), KP(this)); + } else { + ObDataMacroBlockMeta macro_meta; + if (OB_FAIL(macro_meta_iter_->get_next(macro_meta))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next macro block meta", KR(ret)); + } + } else if (OB_FAIL(rowkey_.assign(macro_meta.end_key_.datums_, + macro_meta.val_.rowkey_count_ - + ObMultiVersionRowkeyHelpper::get_extra_rowkey_col_cnt()))) { + LOG_WARN("fail to get datum rowkey", KR(ret)); + } else { + rowkey = &rowkey_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_rowkey_iterator.h b/src/storage/direct_load/ob_direct_load_rowkey_iterator.h new file mode 100644 index 0000000000..997b196932 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_rowkey_iterator.h @@ -0,0 +1,61 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_heap.h" +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_multiple_datum_rowkey.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatumUtils; +class ObSSTableSecMetaIterator; +} // namespace blocksstable +namespace storage +{ + +template +class ObIDirectLoadRowkeyIterator +{ +public: + virtual ~ObIDirectLoadRowkeyIterator() = default; + virtual int get_next_rowkey(const Rowkey *&rowkey) = 0; + TO_STRING_EMPTY(); +}; + +typedef ObIDirectLoadRowkeyIterator ObIDirectLoadDatumRowkeyIterator; +typedef ObIDirectLoadRowkeyIterator + ObIDirectLoadMultipleDatumRowkeyIterator; + +class ObDirectLoadDatumRowkeyArrayIterator : public ObIDirectLoadDatumRowkeyIterator +{ +public: + ObDirectLoadDatumRowkeyArrayIterator(); + virtual ~ObDirectLoadDatumRowkeyArrayIterator(); + int init(const common::ObIArray &rowkey_array); + int get_next_rowkey(const blocksstable::ObDatumRowkey *&rowkey) override; +private: + const common::ObIArray *rowkey_array_; + int64_t pos_; + bool is_inited_; +}; + +class ObDirectLoadMacroBlockEndKeyIterator : public ObIDirectLoadDatumRowkeyIterator +{ +public: + ObDirectLoadMacroBlockEndKeyIterator(); + virtual ~ObDirectLoadMacroBlockEndKeyIterator(); + int init(blocksstable::ObSSTableSecMetaIterator *macro_meta_iter); + int get_next_rowkey(const blocksstable::ObDatumRowkey *&rowkey) override; +private: + blocksstable::ObSSTableSecMetaIterator *macro_meta_iter_; + blocksstable::ObDatumRowkey rowkey_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_rowkey_merger.h b/src/storage/direct_load/ob_direct_load_rowkey_merger.h new file mode 100644 index 0000000000..5c845a491b --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_rowkey_merger.h @@ -0,0 +1,240 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_rowkey_iterator.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadRowkeyMerger : public ObIDirectLoadRowkeyIterator +{ + typedef ObIDirectLoadRowkeyIterator RowkeyIterator; +public: + ObDirectLoadRowkeyMerger(); + virtual ~ObDirectLoadRowkeyMerger() = default; + int init(const common::ObIArray &iters, Compare *compare); + int get_next_rowkey(const Rowkey *&rowkey); +private: + int direct_get_next_rowkey(const Rowkey *&rowkey); + int build_heap(); + int heap_get_next_rowkey(const Rowkey *&rowkey); +private: + struct HeapItem + { + const Rowkey *item_; + int64_t idx_; + HeapItem() : item_(nullptr), idx_(0) {} + void reset() + { + item_ = nullptr; + idx_ = 0; + } + TO_STRING_KV(K_(item), K_(idx)); + }; + struct HeapCompare + { + HeapCompare() : compare_(nullptr), error_code_(common::OB_SUCCESS) {} + bool operator()(const HeapItem &lhs, const HeapItem &rhs); + int get_error_code() const { return error_code_; } + Compare *compare_; + int error_code_; + }; +private: + HeapCompare compare_; + common::ObBinaryHeap heap_; + const common::ObIArray *iters_; + int64_t last_iter_idx_; + bool is_inited_; +}; + +template +bool ObDirectLoadRowkeyMerger::HeapCompare::operator()(const HeapItem &lhs, + const HeapItem &rhs) +{ + int ret = common::OB_SUCCESS; + bool bret = false; + if (OB_ISNULL(compare_)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), KP(compare_)); + } else if (OB_ISNULL(lhs.item_) || OB_ISNULL(rhs.item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid compare items", KR(ret), KP(lhs.item_), KP(rhs.item_)); + } else { + bret = !compare_->operator()(lhs.item_, rhs.item_); + } + if (OB_FAIL(ret)) { + error_code_ = ret; + } else if (OB_FAIL(compare_->get_error_code())) { + error_code_ = compare_->get_error_code(); + } + return bret; +} + +template +ObDirectLoadRowkeyMerger::ObDirectLoadRowkeyMerger() + : heap_(compare_), iters_(nullptr), last_iter_idx_(-1), is_inited_(false) +{ +} + +template +int ObDirectLoadRowkeyMerger::init(const common::ObIArray &iters, + Compare *compare) +{ + int ret = common::OB_SUCCESS; + if (IS_INIT) { + ret = common::OB_INIT_TWICE; + STORAGE_LOG(WARN, "ObDirectLoadMacroBlockEndRowkeyMerger init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(iters.empty() || OB_ISNULL(compare))) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid args", KR(ret), K(iters.count()), KP(compare)); + } else { + compare_.compare_ = compare; + iters_ = &iters; + if (iters_->count() > 1 && OB_FAIL(build_heap())) { + STORAGE_LOG(WARN, "fail to build heap", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +template +int ObDirectLoadRowkeyMerger::get_next_rowkey(const Rowkey *&rowkey) +{ + int ret = common::OB_SUCCESS; + if (IS_NOT_INIT) { + ret = common::OB_NOT_INIT; + STORAGE_LOG(WARN, "ObDirectLoadRowkeyMerger not init", KR(ret), KP(this)); + } else { + if (1 == iters_->count()) { + if (OB_FAIL(direct_get_next_rowkey(rowkey))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to direct get next rowkey", KR(ret)); + } + } + } else { + if (OB_FAIL(heap_get_next_rowkey(rowkey))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to heap get next rowkey", KR(ret)); + } + } + } + } + return ret; +} + +template +int ObDirectLoadRowkeyMerger::direct_get_next_rowkey(const Rowkey *&rowkey) +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(1 != iters_->count())) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters_->count())); + } else { + ret = iters_->at(0)->get_next_rowkey(rowkey); + } + return ret; +} + +template +int ObDirectLoadRowkeyMerger::build_heap() +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(iters_->count() <= 1)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters_->count())); + } else { + const Rowkey *rowkey = nullptr; + HeapItem heap_item; + for (int64_t i = 0; OB_SUCC(ret) && i < iters_->count(); ++i) { + if (OB_FAIL(iters_->at(i)->get_next_rowkey(rowkey))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret), K(i)); + } else { + ret = common::OB_SUCCESS; + } + } else if (OB_ISNULL(rowkey)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid rowkey", KR(ret), KP(rowkey)); + } else { + heap_item.item_ = rowkey; + heap_item.idx_ = i; + if (OB_FAIL(heap_.push(heap_item))) { + STORAGE_LOG(WARN, "fail to push heap", KR(ret), K(i)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } + } + } + } + return ret; +} + +template +int ObDirectLoadRowkeyMerger::heap_get_next_rowkey(const Rowkey *&rowkey) +{ + int ret = common::OB_SUCCESS; + if (OB_UNLIKELY(iters_->count() <= 1)) { + ret = common::OB_INVALID_ARGUMENT; + STORAGE_LOG(WARN, "invalid argument", KR(ret), K(iters_->count())); + } else if (last_iter_idx_ >= 0 && last_iter_idx_ < iters_->count()) { + RowkeyIterator *iter = iters_->at(last_iter_idx_); + HeapItem heap_item; + heap_item.idx_ = last_iter_idx_; + if (OB_FAIL(iter->get_next_rowkey(heap_item.item_))) { + if (OB_UNLIKELY(common::OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next rowkey", KR(ret)); + } else { + if (OB_FAIL(heap_.pop())) { + STORAGE_LOG(WARN, "fail to pop heap item", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } else { + STORAGE_LOG(DEBUG, "pop a heap item"); + } + } + } else if (OB_ISNULL(heap_item.item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid item", KR(ret), KP(heap_item.item_)); + } else { + if (OB_FAIL(heap_.replace_top(heap_item))) { + STORAGE_LOG(WARN, "fail to replace heap top", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } else { + STORAGE_LOG(DEBUG, "replace heap item", K(*heap_item.item_), K(last_iter_idx_)); + } + } + last_iter_idx_ = -1; + } + + if (OB_SUCC(ret) && heap_.empty()) { + ret = common::OB_ITER_END; + } + + if (OB_SUCC(ret)) { + const HeapItem *head_item = nullptr; + if (OB_FAIL(heap_.top(head_item))) { + STORAGE_LOG(WARN, "fail to get heap top item", KR(ret)); + } else if (OB_FAIL(compare_.get_error_code())) { + STORAGE_LOG(WARN, "fail to compare items", KR(ret)); + } else if (OB_ISNULL(head_item) || OB_ISNULL(head_item->item_)) { + ret = common::OB_ERR_UNEXPECTED; + STORAGE_LOG(WARN, "invalid heap item", KR(ret), KP(head_item)); + } else { + rowkey = head_item->item_; + last_iter_idx_ = head_item->idx_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable.cpp b/src/storage/direct_load/ob_direct_load_sstable.cpp new file mode 100644 index 0000000000..0b08bfe527 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable.cpp @@ -0,0 +1,348 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" +#include "storage/direct_load/ob_direct_load_sstable.h" +#include "observer/table_load/ob_table_load_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace share; +using namespace share::schema; + +/** + * ObDirectLoadSSTableFragmentMeta + */ + +ObDirectLoadSSTableFragmentMeta::ObDirectLoadSSTableFragmentMeta() + : index_item_count_(0), index_block_count_(0), row_count_(0), occupy_size_(0) +{ +} + +ObDirectLoadSSTableFragmentMeta::~ObDirectLoadSSTableFragmentMeta() {} + +void ObDirectLoadSSTableFragmentMeta::reset() +{ + index_item_count_ = 0; + index_block_count_ = 0; + row_count_ = 0; + occupy_size_ = 0; +} + +bool ObDirectLoadSSTableFragmentMeta::is_valid() const +{ + return index_item_count_ > 0 && index_block_count_ > 0 && row_count_ > 0 && occupy_size_ > 0; +} + +/** + * ObDirectLoadSSTableFragment + */ + +ObDirectLoadSSTableFragment::ObDirectLoadSSTableFragment() {} + +ObDirectLoadSSTableFragment::~ObDirectLoadSSTableFragment() { reset(); } + +void ObDirectLoadSSTableFragment::reset() +{ + meta_.reset(); + index_file_handle_.reset(); + data_file_handle_.reset(); +} + +bool ObDirectLoadSSTableFragment::is_valid() const +{ + return meta_.is_valid() && index_file_handle_.is_valid() && data_file_handle_.is_valid(); +} + +int ObDirectLoadSSTableFragment::assign(const ObDirectLoadSSTableFragment &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + meta_ = other.meta_; + if (OB_FAIL(index_file_handle_.assign(other.index_file_handle_))) { + LOG_WARN("fail to assign index file", KR(ret)); + } else if (OB_FAIL(data_file_handle_.assign(other.data_file_handle_))) { + LOG_WARN("fail to assign data file", KR(ret)); + } + } + return ret; +} + +/** + * ObDirectLoadSSTableMeta + */ + +void ObDirectLoadSSTableMeta::reset() +{ + tablet_id_.reset(); + rowkey_column_count_ = 0; + column_count_ = 0; + index_block_size_ = 0; + data_block_size_ = 0; + index_item_count_ = 0; + index_block_count_ = 0; + row_count_ = 0; +} + +/** + * ObDirectLoadSSTable + */ + +ObDirectLoadSSTable::ObDirectLoadSSTable() + : allocator_("TLD_SSTable"), is_inited_(false) +{ +} + +ObDirectLoadSSTable::~ObDirectLoadSSTable() {} + +void ObDirectLoadSSTable::reset() +{ + meta_.reset(); + start_key_.reset(); + end_key_.reset(); + fragments_.reset(); + allocator_.reset(); + is_inited_ = false; +} + +int ObDirectLoadSSTable::init(ObDirectLoadSSTableCreateParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTable init twice", KR(ret), KP(this)); + } else { + allocator_.set_tenant_id(MTL_ID()); + meta_.tablet_id_ = param.tablet_id_; + meta_.rowkey_column_count_ = param.rowkey_column_count_; + meta_.column_count_ = param.column_count_; + meta_.index_block_size_ = param.index_block_size_; + meta_.data_block_size_ = param.data_block_size_; + meta_.index_item_count_ = param.index_item_count_; + meta_.index_block_count_ = param.index_block_count_; + meta_.row_count_ = param.row_count_; + if (param.row_count_ > 0) { + if (OB_UNLIKELY(param.fragments_.empty())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else if (OB_FAIL(param.start_key_.deep_copy(start_key_, allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(param.end_key_.deep_copy(end_key_, allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(fragments_.assign(param.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadSSTable::copy(const ObDirectLoadSSTable &other) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!other.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(other)); + } else { + reset(); + allocator_.set_tenant_id(MTL_ID()); + meta_ = other.meta_; + if (meta_.row_count_ > 0) { + if (OB_FAIL(other.start_key_.deep_copy(start_key_, allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(other.end_key_.deep_copy(end_key_, allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(fragments_.assign(other.fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadSSTable::scan_index_block_meta(ObIAllocator &allocator, + ObDirectLoadIndexBlockMetaIterator *&meta_iter) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTable not init", KR(ret), KP(this)); + } else { + void *buf = nullptr; + ObDirectLoadIndexBlockMetaIterator *iter = nullptr; + if (OB_ISNULL(buf = allocator.alloc(sizeof(ObDirectLoadIndexBlockMetaIterator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("Fail to allocate memory", K(ret)); + } else if (OB_ISNULL(iter = new (buf) ObDirectLoadIndexBlockMetaIterator())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected null pointer of secondary meta iterator", K(ret)); + } else if (OB_FAIL(iter->init(this))) { + LOG_WARN("Fail to open index block meta iterator", K(ret)); + } else { + meta_iter = iter; + } + if (OB_FAIL(ret)) { + if (OB_NOT_NULL(iter)) { + iter->~ObDirectLoadIndexBlockMetaIterator(); + } + if (OB_NOT_NULL(buf)) { + allocator.free(buf); + } + } + } + return ret; +} + +int ObDirectLoadSSTable::scan(const ObDirectLoadTableDataDesc &table_data_desc, + const ObDatumRange &key_range, + const ObStorageDatumUtils *datum_utils, ObIAllocator &allocator, + ObDirectLoadSSTableScanner *&scanner) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTable not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!table_data_desc.is_valid() || !key_range.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(table_data_desc), K(key_range), KP(datum_utils)); + } else { + scanner = nullptr; + // check param + if (OB_UNLIKELY(meta_.rowkey_column_count_ != table_data_desc.rowkey_column_num_ || + meta_.column_count_ != table_data_desc.column_count_ || + meta_.index_block_size_ != table_data_desc.sstable_index_block_size_ || + meta_.data_block_size_ != table_data_desc.sstable_data_block_size_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected sstable", KR(ret), K(meta_), K(table_data_desc)); + } else if (OB_ISNULL(scanner = OB_NEWx(ObDirectLoadSSTableScanner, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadSSTableScanner", KR(ret)); + } else if (OB_FAIL(scanner->init(this, table_data_desc, key_range, datum_utils))) { + LOG_WARN("fail to init sstable scanner", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != scanner) { + scanner->~ObDirectLoadSSTableScanner(); + allocator.free(scanner); + scanner = nullptr; + } + } + } + return ret; +} + +/** + * ObDirectLoadSSTableFragmentOperator + */ + +int ObDirectLoadSSTableFragmentOperator::init(ObDirectLoadSSTable *sstable) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("The ObDirectLoadIndexBlockMetaIterator has been inited", K(ret)); + } else if (OB_ISNULL(sstable) || !sstable->is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", K(ret), KP(sstable)); + } else { + sstable_ = sstable; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadSSTableFragmentOperator::get_fragment( + int64_t idx, ObDirectLoadSSTableFragment &fragment) +{ + int ret = OB_SUCCESS; + if (idx >= sstable_->get_fragment_array().count()) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("no fragment", K(ret), K(idx), K(sstable_->get_fragment_array().count())); + } else if (OB_FAIL(fragment.assign(sstable_->get_fragment_array().at(idx)))) { + LOG_WARN("fail to assign fragment", K(ret)); + } + return ret; +} + +int ObDirectLoadSSTableFragmentOperator::get_next_fragment( + int64_t &curr_fragment_idx, ObDirectLoadSSTableFragment &fragment) +{ + int ret = OB_SUCCESS; + if (curr_fragment_idx >= sstable_->get_fragment_array().count() - 1) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("no next fragment", K(ret), K(curr_fragment_idx), + K(sstable_->get_fragment_array().count())); + } else if (OB_FAIL(fragment.assign(sstable_->get_fragment_array().at(curr_fragment_idx + 1)))) { + LOG_WARN("fail to assign fragment", K(ret)); + } else { + curr_fragment_idx++; + } + return ret; +} + +//索引项重新映射到对应文件的对应索引项 +int ObDirectLoadSSTableFragmentOperator::get_fragment_item_idx(int64_t idx, + int64_t &locate_fragment_idx, + int64_t &new_idx) +{ + int ret = OB_SUCCESS; + if (idx >= sstable_->get_meta().index_item_count_) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("no other fragment", K(ret), K(idx), K(sstable_->get_meta().index_item_count_)); + } else { + for (int64_t i = 0; i < sstable_->get_fragment_array().count(); ++i) { + if (idx <= (sstable_->get_fragment_array().at(i).meta_.index_item_count_ - 1)) { + new_idx = idx; + locate_fragment_idx = i; + break; + } else { + idx = idx - sstable_->get_fragment_array().at(i).meta_.index_item_count_; + } + } + } + return ret; +} + +int ObDirectLoadSSTableFragmentOperator::get_fragment_block_idx(int64_t idx, + int64_t &locate_fragment_idx, + int64_t &new_idx) +{ + int ret = OB_SUCCESS; + if (idx >= sstable_->get_meta().index_block_count_) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("no other fragment", K(ret), K(idx), K(sstable_->get_meta().index_block_count_)); + } else { + for (int64_t i = 0; i < sstable_->get_fragment_array().count(); ++i) { + if (idx <= (sstable_->get_fragment_array().at(i).meta_.index_block_count_ - 1)) { + new_idx = idx; + locate_fragment_idx = i; + break; + } else { + idx = idx - sstable_->get_fragment_array().at(i).meta_.index_block_count_; + } + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable.h b/src/storage/direct_load/ob_direct_load_sstable.h new file mode 100644 index 0000000000..6aa8b97167 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable.h @@ -0,0 +1,182 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "storage/access/ob_store_row_iterator.h" +#include "storage/access/ob_table_access_context.h" +#include "storage/access/ob_table_access_param.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/ob_i_store.h" +#include "ob_direct_load_tmp_file.h" +#include "storage/direct_load/ob_direct_load_rowkey_iterator.h" +#include "storage/direct_load/ob_direct_load_external_row.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +static const int64_t DIRECT_LOAD_DEFAULT_SSTABLE_DATA_BLOCK_SIZE = 16 * 1024LL; // data_buffer is 16K; +static const int64_t DIRECT_LOAD_DEFAULT_SSTABLE_INDEX_BLOCK_SIZE = 4 * 1024LL; // index_buffer is 4K; + +class ObDirectLoadIndexBlockMetaIterator; +class ObDirectLoadSSTableScanner; + +struct ObDirectLoadSSTableMeta +{ +public: + ObDirectLoadSSTableMeta() + : rowkey_column_count_(0), + column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_item_count_(0), + index_block_count_(0), + row_count_(0) + { + } + void reset(); + TO_STRING_KV(K_(tablet_id), K_(rowkey_column_count), K_(column_count), K_(index_block_size), + K_(data_block_size), K(index_item_count_), K(index_block_count_), K(row_count_)); +public: + common::ObTabletID tablet_id_; + int64_t rowkey_column_count_; + int64_t column_count_; + int64_t index_block_size_; // 索引块大小 + int64_t data_block_size_; // 数据块大小 + int64_t index_item_count_; //索引项个数 + int64_t index_block_count_; //索引块个数 + int64_t row_count_; // row的个数 +}; + +class ObDirectLoadSSTableFragmentMeta +{ +public: + ObDirectLoadSSTableFragmentMeta(); + ~ObDirectLoadSSTableFragmentMeta(); + void reset(); + bool is_valid() const; + TO_STRING_KV(K_(index_item_count), K_(index_block_count), K_(row_count), K_(occupy_size)); +public: + int64_t index_item_count_; //索引项个数 + int64_t index_block_count_; //索引块个数 + int64_t row_count_; //行的个数 + int64_t occupy_size_; //文件的大小 +}; + +class ObDirectLoadSSTableFragment +{ +public: + ObDirectLoadSSTableFragment(); + ~ObDirectLoadSSTableFragment(); + void reset(); + bool is_valid() const; + int assign(const ObDirectLoadSSTableFragment &other); + TO_STRING_KV(K_(meta), K_(index_file_handle), K_(data_file_handle)); +public: + ObDirectLoadSSTableFragmentMeta meta_; + ObDirectLoadTmpFileHandle index_file_handle_; + ObDirectLoadTmpFileHandle data_file_handle_; +}; + +struct ObDirectLoadSSTableCreateParam +{ +public: + ObDirectLoadSSTableCreateParam() + : rowkey_column_count_(0), + column_count_(0), + index_block_size_(0), + data_block_size_(0), + index_item_count_(0), + index_block_count_(0), + row_count_(0) + { + } + bool is_valid() const + { + return tablet_id_.is_valid() && + rowkey_column_count_ > 0 && + column_count_ > 0 && + rowkey_column_count_ <= column_count_ && + index_block_size_ > 0 && index_block_size_ % DIO_ALIGN_SIZE == 0 && + data_block_size_ > 0 && data_block_size_ % DIO_ALIGN_SIZE == 0 && + index_item_count_ > 0 && + index_block_count_ > 0 && + row_count_ > 0 && + start_key_.is_valid() && + end_key_.is_valid() && + !fragments_.empty(); + } + TO_STRING_KV(K_(tablet_id), K_(rowkey_column_count), K_(column_count), K_(index_block_size), + K_(data_block_size), K_(index_item_count), K_(index_block_count), K_(row_count), + K_(start_key), K_(end_key), K_(fragments)); +public: + common::ObTabletID tablet_id_; + int64_t rowkey_column_count_; + int64_t column_count_; // 写到sstable的列数目 + int64_t index_block_size_; // 索引块大小 + int64_t data_block_size_; // 数据块大小 + int64_t index_item_count_; // 索引项个数 + int64_t index_block_count_; //索引块个数 + int64_t row_count_; // row的行数 + blocksstable::ObDatumRowkey start_key_; + blocksstable::ObDatumRowkey end_key_; + common::ObArray fragments_; +}; + +class ObDirectLoadSSTable : public ObIDirectLoadPartitionTable +{ +public: + ObDirectLoadSSTable(); + virtual ~ObDirectLoadSSTable(); + void reset(); + int init(ObDirectLoadSSTableCreateParam ¶m); + int scan_index_block_meta(ObIAllocator &allocator, + ObDirectLoadIndexBlockMetaIterator *&meta_iter); + // for sstable scan merge + int scan(const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObDatumRange &key_range, + const blocksstable::ObStorageDatumUtils *datum_utils, + common::ObIAllocator &allocator, + ObDirectLoadSSTableScanner *&scanner); + int64_t get_row_count() const override { return meta_.row_count_; } + const common::ObTabletID &get_tablet_id() const override { return meta_.tablet_id_; } + bool is_empty() const { return 0 == meta_.row_count_; } + bool is_valid() const override { return is_inited_; } + int copy(const ObDirectLoadSSTable &other); + const common::ObArray &get_fragment_array() const + { + return fragments_; + } + const ObDirectLoadSSTableMeta &get_meta() const { return meta_; } + const blocksstable::ObDatumRowkey &get_start_key() const { return start_key_; } + const blocksstable::ObDatumRowkey &get_end_key() const { return end_key_; } + TO_STRING_KV(K_(meta), K_(start_key), K_(end_key), K(fragments_)); +private: + common::ObArenaAllocator allocator_; + ObDirectLoadSSTableMeta meta_; + blocksstable::ObDatumRowkey start_key_; + blocksstable::ObDatumRowkey end_key_; + common::ObArray fragments_; + bool is_inited_; +}; + +class ObDirectLoadSSTableFragmentOperator +{ +public: + ObDirectLoadSSTableFragmentOperator() : sstable_(nullptr), is_inited_(false) {} + int init(ObDirectLoadSSTable *sstable); + int get_fragment(const int64_t idx, ObDirectLoadSSTableFragment &fragment); + int get_fragment_item_idx(int64_t idx, int64_t &locate_idx, int64_t &new_idx); + int get_fragment_block_idx(int64_t idx, int64_t &locate_idx, int64_t &new_idx); + int get_next_fragment(int64_t &curr_fragment_idx, ObDirectLoadSSTableFragment &fragment); +private: + ObDirectLoadSSTable *sstable_; + bool is_inited_; +}; + + +} // namespace storage +} // namespace oceanbase \ No newline at end of file diff --git a/src/storage/direct_load/ob_direct_load_sstable_builder.cpp b/src/storage/direct_load/ob_direct_load_sstable_builder.cpp new file mode 100644 index 0000000000..92d4510e8f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_builder.cpp @@ -0,0 +1,894 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_builder.h" +#include "observer/table_load/ob_table_load_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; + +/** + * ObDirectLoadIndexBlock + */ + +int64_t ObDirectLoadIndexBlock::get_item_num_per_block(int64_t block_size) +{ + ObDirectLoadIndexBlockHeader header; + ObDirectLoadIndexBlockItem item; + const int64_t header_size = header.get_serialize_size(); + const int64_t item_size = item.get_serialize_size(); + int64_t item_num_per_block = 0; + if (block_size > header_size) { + item_num_per_block = (block_size - header_size) / item_size; + } + return item_num_per_block; +} +/** + * ObDirectLoadSSTableBuilder + */ + +int ObDirectLoadSSTableBuilder::init(const ObDirectLoadSSTableBuildParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableBuilder init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + const uint64_t tenant_id = MTL_ID(); + param_ = param; + allocator_.set_tenant_id(tenant_id); + start_key_.set_min_rowkey(); + end_key_.set_min_rowkey(); + int64_t dir_id = -1; + if (OB_ISNULL(param_.file_mgr_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid file mgr", KR(ret), K(file_mgr_)); + } else if (OB_FAIL(param_.file_mgr_->alloc_dir(dir_id))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } else if (OB_FAIL(param_.file_mgr_->alloc_file(dir_id, data_file_handle_))) { + LOG_WARN("fail to alloc datafragment", KR(ret)); + } else if (OB_FAIL(param_.file_mgr_->alloc_file(dir_id, index_file_handle_))) { + LOG_WARN("fail to alloc index fragment", KR(ret)); + } else if (OB_FAIL(index_block_writer_.init(tenant_id, + param_.table_data_desc_.sstable_index_block_size_, + index_file_handle_))) { + LOG_WARN("fail to init index block writer", KR(ret), + K(param_.table_data_desc_.sstable_index_block_size_), K(index_file_handle_)); + } else if (OB_FAIL(data_block_writer_.init(tenant_id, + param_.table_data_desc_.sstable_data_block_size_, + data_file_handle_, &index_block_writer_))) { + LOG_WARN("fail to init data block writer", KR(ret), + K(param_.table_data_desc_.sstable_data_block_size_), K(data_file_handle_)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadSSTableBuilder::append_row(const ObTabletID &tablet_id, const ObDatumRow &datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load sstable builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!datum_row.is_valid() || + datum_row.get_column_count() != param_.table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(datum_row)); + } else { + ObDatumRowkey key(datum_row.storage_datums_, param_.table_data_desc_.rowkey_column_num_); + ObDirectLoadExternalRow external_row; + OB_TABLE_LOAD_STATISTICS_TIME_COST(simple_sstable_append_row_time_us); + if (OB_FAIL(check_rowkey_order(key))) { + LOG_WARN("fail to check rowkey order", KR(ret), K(datum_row)); + } else if (OB_FAIL(external_row.from_datums(datum_row.storage_datums_, datum_row.count_, + param_.table_data_desc_.rowkey_column_num_))) { + LOG_WARN("fail to from datum row", KR(ret)); + } else if (OB_FAIL(data_block_writer_.append_row(external_row))) { + LOG_WARN("fail to append row to data block writer", KR(ret), K(external_row)); + } else if (start_key_.is_min_rowkey()) { + if (OB_FAIL(key.deep_copy(start_key_, allocator_))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadSSTableBuilder::append_row(const ObDirectLoadExternalRow &external_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load sstable builder is closed", KR(ret)); + } else if (OB_UNLIKELY(!external_row.is_valid()) || + (external_row.rowkey_datum_array_.count_ != + param_.table_data_desc_.rowkey_column_num_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param_), K(external_row)); + } else { + ObDatumRowkey key(external_row.rowkey_datum_array_.datums_, + param_.table_data_desc_.rowkey_column_num_); + OB_TABLE_LOAD_STATISTICS_TIME_COST(simple_sstable_append_row_time_us); + if (OB_FAIL(check_rowkey_order(key))) { + LOG_WARN("fail to check rowkey order", KR(ret), K(external_row)); + } else if (OB_FAIL(data_block_writer_.append_row(external_row))) { + LOG_WARN("fail to append row to data block writer", KR(ret), K(external_row)); + } else if (start_key_.is_min_rowkey()) { + if (OB_FAIL(key.deep_copy(start_key_, allocator_))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadSSTableBuilder::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load sstable is closed", KR(ret)); + } else { + OB_TABLE_LOAD_STATISTICS_TIME_COST(simple_sstable_append_row_time_us); + if (OB_FAIL(data_block_writer_.close())) { + LOG_WARN("fail to close data block writer", KR(ret), K(data_block_writer_)); + } else if (OB_FAIL(index_block_writer_.close())) { + LOG_WARN("fail to close index block writer", KR(ret), K(index_block_writer_)); + } + } + if (OB_SUCC(ret)) { + is_closed_ = true; + } + return ret; +} + +int ObDirectLoadSSTableBuilder::get_tables(ObIArray &table_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableBuilder not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("direct load sstable not closed", KR(ret)); + } else { + const int64_t index_item_num_per_block = ObDirectLoadIndexBlock::get_item_num_per_block( + param_.table_data_desc_.sstable_index_block_size_); + ObDirectLoadSSTableCreateParam param; + param.tablet_id_ = param_.tablet_id_; + param.rowkey_column_count_ = param_.table_data_desc_.rowkey_column_num_; + param.column_count_ = param_.table_data_desc_.column_count_; + param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + param.index_item_count_ = index_block_writer_.get_total_index_size(); + param.row_count_ = data_block_writer_.get_total_row_count(); + param.index_block_count_ = + (param.index_item_count_ + index_item_num_per_block - 1) / index_item_num_per_block; + param.start_key_ = start_key_; + param.end_key_ = end_key_; + if (param.row_count_ > 0) { + ObDirectLoadSSTableFragment fragment; + fragment.meta_.row_count_ = data_block_writer_.get_total_row_count(); + fragment.meta_.index_item_count_ = index_block_writer_.get_total_index_size(); + fragment.meta_.occupy_size_ = data_block_writer_.get_file_size(); + fragment.meta_.index_block_count_ = param.index_block_count_; + if (OB_FAIL(fragment.data_file_handle_.assign(data_file_handle_))) { + LOG_WARN("fail to assign data file handle", KR(ret)); + } else if (OB_FAIL(fragment.index_file_handle_.assign(index_file_handle_))) { + LOG_WARN("fail to assign index file handle", KR(ret)); + } else if (OB_FAIL(param.fragments_.push_back(fragment))) { + LOG_WARN("fail to push back", KR(ret)); + } + } + if (OB_SUCC(ret)) { + ObDirectLoadSSTable *sstable = nullptr; + if (OB_ISNULL(sstable = OB_NEWx(ObDirectLoadSSTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadSSTable", KR(ret)); + } else if (OB_FAIL(sstable->init(param))) { + LOG_WARN("fail to init sstable", KR(ret)); + } else if (OB_FAIL(table_array.push_back(sstable))) { + LOG_WARN("fail to push back sstable", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != sstable) { + sstable->~ObDirectLoadSSTable(); + allocator.free(sstable); + sstable = nullptr; + } + } + } + } + return ret; +} + +int ObDirectLoadSSTableBuilder::check_rowkey_order(const ObDatumRowkey &rowkey) +{ + int ret = OB_SUCCESS; + int cmp_ret = 1; + if (OB_FAIL(rowkey.compare(end_key_, *param_.datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare", KR(ret)); + } else if (cmp_ret > 0) { + rowkey_allocator_.reuse(); + if (OB_FAIL(rowkey.deep_copy(end_key_, rowkey_allocator_))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } else if (cmp_ret == 0) { + ret = OB_ERR_PRIMARY_KEY_DUPLICATE; + LOG_INFO("rowkey == last rowkey", K(ret), K(cmp_ret), K(end_key_), K(rowkey)); + } else { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_INFO("rowkey < last rowkey", K(ret), K(cmp_ret), K(end_key_), K(rowkey)); + } + return ret; +} +/** + * ObDirectLoadDataBlockWriter2 + */ + +ObDirectLoadDataBlockWriter2::ObDirectLoadDataBlockWriter2() + : tenant_id_(OB_INVALID_ID), + header_length_(0), + buf_pos_(0), + buf_size_(0), + total_row_count_(0), + row_count_(0), + file_size_(0), + buf_(nullptr), + allocator_("TLD_DBWriter"), + is_inited_(false), + is_closed_(false) +{ +} + +ObDirectLoadDataBlockWriter2::~ObDirectLoadDataBlockWriter2() { reset(); } + +void ObDirectLoadDataBlockWriter2::reset() +{ + is_inited_ = false; + is_closed_ = false; + assign(0, 0, nullptr); + file_io_handle_.reset(); + buf_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadDataBlockWriter2::assign(const int64_t buf_pos, const int64_t buf_cap, char *buf) +{ + buf_pos_ = buf_pos; + buf_size_ = buf_cap; + buf_ = buf; +} + +int ObDirectLoadDataBlockWriter2::init(uint64_t tenant_id, int64_t buf_size, + const ObDirectLoadTmpFileHandle &file_handle, + ObDirectLoadIndexBlockWriter *index_block_writer) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDataBlockWriter2 init twice", KR(ret), KP(this)); + } else if (buf_size < DIRECT_LOAD_DEFAULT_SSTABLE_INDEX_BLOCK_SIZE || + buf_size % DIO_ALIGN_SIZE != 0 || OB_INVALID_ID == tenant_id) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(buf_size)); + } else if (OB_FAIL(file_io_handle_.open(file_handle))) { + LOG_WARN("fail to open file handle", KR(ret)); + } else { + allocator_.set_tenant_id(tenant_id); + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + header_length_ = header_.get_serialize_size(); + assign(header_length_, buf_size, buf_); + index_block_writer_ = index_block_writer; + tenant_id_ = tenant_id; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadDataBlockWriter2::write_item(const ObDirectLoadExternalRow &external_row) +{ + int ret = OB_SUCCESS; + int64_t offset = buf_pos_; + int64_t data_size = external_row.get_serialize_size(); + if (data_size + buf_pos_ > buf_size_) { + ret = OB_BUF_NOT_ENOUGH; + } else if (OB_FAIL(external_row.serialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to serialize datum_row", KR(ret), KP(buf_), K(buf_size_), K(buf_pos_)); + } + if (OB_SUCC(ret)) { + row_count_++; + header_.last_row_offset_ = offset; + } + return ret; +} + +int ObDirectLoadDataBlockWriter2::write_large_item(const ObDirectLoadExternalRow &external_row, + int64_t new_buf_size) +{ + int ret = OB_SUCCESS; + char *new_buf; + const int64_t align_buf_size = upper_align(new_buf_size, DIO_ALIGN_SIZE); + if (OB_ISNULL(new_buf = static_cast(ob_malloc(align_buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(align_buf_size)); + } else { + int64_t new_buf_pos = header_length_; + if (OB_FAIL(external_row.serialize(new_buf, align_buf_size, new_buf_pos))) { + LOG_WARN("fail to serialize datum_row", KR(ret), K(align_buf_size), K(new_buf_pos)); + } else { + header_.last_row_offset_ = header_length_; + buf_pos_ = new_buf_pos; + row_count_++; + if (OB_FAIL(flush_buffer(align_buf_size, new_buf))) { + LOG_WARN("fail to flush buffer", KR(ret)); + } + } + } + if (nullptr != new_buf) { + ob_free(new_buf); + } + return ret; +} + +int ObDirectLoadDataBlockWriter2::append_row(const ObDirectLoadExternalRow &external_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDataBlockWriter2 not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(write_item(external_row))) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to write item", KR(ret)); + } else { + if (buf_pos_ != header_length_ && (OB_FAIL(flush_buffer(buf_size_, buf_)))) { + LOG_WARN("fail to flush buffer", KR(ret)); + } else { + int64_t total_size = external_row.get_serialize_size() + header_length_; + if (total_size > buf_size_) { + if (OB_FAIL(write_large_item(external_row, total_size))) { + LOG_WARN("fail to write item", KR(ret), K(external_row), K(total_size)); + } + } else { + if (OB_FAIL(write_item(external_row))) { + LOG_WARN("fail to write item", KR(ret), K(external_row)); + } + } + } + } + } + } + if (OB_SUCC(ret)) { + total_row_count_++; + } + return ret; +} + +int ObDirectLoadDataBlockWriter2::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDataBlockWriter2 not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObDirectLoadDataBlockWriter2 is closed", KR(ret)); + } else if (buf_pos_ > header_length_ && OB_FAIL(flush_buffer(buf_size_, buf_))) { + LOG_WARN("fail to flush buffer", KR(ret)); + } else { + reset(); + } + if (OB_SUCC(ret)) { + is_closed_ = true; + } + return ret; +} + +int ObDirectLoadDataBlockWriter2::flush_buffer(int64_t buf_size, char *buf) +{ + int ret = OB_SUCCESS; + header_.size_ = buf_pos_; + header_.occupy_size_ = buf_size; + int64_t pos = 0; + if (OB_FAIL(header_.serialize(buf, buf_size, pos))) { + LOG_WARN("fail to serialize data block header", KR(ret), K(buf_size), KP(buf_), K(pos)); + } else { + if (OB_FAIL(file_io_handle_.aio_write(buf, buf_size))) { + LOG_WARN("fail to do aio write data file", KR(ret)); + } else { + ObDirectLoadIndexBlockItem item; + assign(header_length_, buf_size_, buf_); + file_size_ += buf_size; + item.end_offset_ = file_size_; + if (OB_FAIL(index_block_writer_->append_row(row_count_, item))) { + LOG_WARN("fail to append row index", KR(ret)); + } else { + row_count_ = 0; + } + } + } + return ret; +} + +/** + * ObDirectLoadIndexBlockWriter + */ + +ObDirectLoadIndexBlockWriter::ObDirectLoadIndexBlockWriter() + : tenant_id_(OB_INVALID_ID), + header_length_(0), + buf_pos_(0), + buf_size_(0), + item_size_(0), + row_count_(0), + total_index_size_(0), + offset_(0), + buf_(nullptr), + allocator_("TLD_IBWriter"), + is_inited_(false), + is_closed_(false) +{ +} + +ObDirectLoadIndexBlockWriter::~ObDirectLoadIndexBlockWriter() { reset(); } + +void ObDirectLoadIndexBlockWriter::reset() +{ + is_inited_ = false; + is_closed_ = false; + assign(0, 0, nullptr); + file_io_handle_.reset(); + buf_ = nullptr; + allocator_.reset(); +} + +void ObDirectLoadIndexBlockWriter::assign(const int64_t buf_pos, const int64_t buf_cap, char *buf) +{ + buf_pos_ = buf_pos; + buf_size_ = buf_cap; + buf_ = buf; +} + +int ObDirectLoadIndexBlockWriter::init(uint64_t tenant_id, int64_t buf_size, + const ObDirectLoadTmpFileHandle &file_handle) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadIndexBlockWriter init twice", KR(ret), KP(this)); + } else if (buf_size < DIRECT_LOAD_DEFAULT_SSTABLE_INDEX_BLOCK_SIZE || + buf_size % DIO_ALIGN_SIZE != 0 || OB_INVALID_ID == tenant_id) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(buf_size)); + } else if (OB_FAIL(file_io_handle_.open(file_handle))) { + LOG_WARN("fail to open file handle", KR(ret)); + } else { + allocator_.set_tenant_id(tenant_id); + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + header_length_ = header_.get_serialize_size(); + assign(header_length_, buf_size, buf_); + tenant_id_ = tenant_id; + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadIndexBlockWriter::append_row(int64_t row_count, + const ObDirectLoadIndexBlockItem &item) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadIndexBlockWriter not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(write_item(item))) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to write item", KR(ret), K(item)); + } else { + if (OB_FAIL(flush_buffer())) { + LOG_WARN("fail to flush buffer", KR(ret)); + } else if (OB_FAIL(write_item(item))) { + LOG_WARN("fail to write item", KR(ret), K(item)); + } + } + } + if (OB_SUCC(ret)) { + offset_ = item.end_offset_; + row_count_ += row_count; + item_size_++; + } + } + return ret; +} + +int ObDirectLoadIndexBlockWriter::write_item(const ObDirectLoadIndexBlockItem &item) +{ + int ret = OB_SUCCESS; + int64_t data_size = item.get_serialize_size(); + if (data_size + buf_pos_ > buf_size_) { + ret = OB_BUF_NOT_ENOUGH; + } else if (OB_FAIL(item.serialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to serialize datum_row", KR(ret)); + } + return ret; +} + +int ObDirectLoadIndexBlockWriter::flush_buffer() +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + header_.row_count_ = row_count_; + if (OB_FAIL(header_.serialize(buf_, buf_size_, pos))) { + LOG_WARN("fail to serialize data block header", KR(ret), K(buf_size_), K(pos), KP(buf_)); + } else { + if (OB_FAIL(file_io_handle_.aio_write(buf_, buf_size_))) { + LOG_WARN("fail to do aio write index file", KR(ret)); + } else { + header_.start_offset_ = offset_; + total_index_size_ += item_size_; + item_size_ = 0; + row_count_ = 0; + assign(header_length_, buf_size_, buf_); + } + } + return ret; +} + +int ObDirectLoadIndexBlockWriter::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadIndexBlockWriter not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(is_closed_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("ObDirectLoadIndexBlockWriter is closed", KR(ret)); + } else if (buf_pos_ > header_length_ && OB_FAIL(flush_buffer())) { + LOG_WARN("fail to flush buffer", KR(ret)); + } else { + reset(); + } + if (OB_SUCC(ret)) { + is_closed_ = true; + } + return ret; +} + +/** + * ObDirectLoadIndexBlockReader + */ + +ObDirectLoadIndexBlockReader::ObDirectLoadIndexBlockReader() + : tenant_id_(OB_INVALID_ID), + buf_(nullptr), + buf_size_(0), + header_length_(0), + item_size_(0), + index_item_num_per_block_(0), + io_timeout_ms_(0), + allocator_("TLD_IBReader"), + is_inited_(false) +{ +} + +int ObDirectLoadIndexBlockReader::init(uint64_t tenant_id, int64_t buf_size, + const ObDirectLoadTmpFileHandle &file_handle) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadIndexBlockReader init twice", KR(ret), KP(this)); + } else if (buf_size < 0 || buf_size % DIO_ALIGN_SIZE != 0 || OB_INVALID_ID == tenant_id) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(buf_size)); + } else if (OB_FAIL(file_io_handle_.open(file_handle))) { + LOG_WARN("fail to open file handle", KR(ret)); + } else { + allocator_.set_tenant_id(tenant_id); + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + ObDirectLoadIndexBlockItem item; + header_length_ = header_.get_serialize_size(); + item_size_ = item.get_serialize_size(); + if (item_size_ == 0) { + ret = OB_ERROR; + LOG_WARN("divide zero", K(ret), K(item_size_)); + } else { + index_item_num_per_block_ = ObDirectLoadIndexBlock::get_item_num_per_block(buf_size); + assign(buf_size, buf_); + tenant_id_ = tenant_id; + io_timeout_ms_ = std::max(GCONF._data_storage_io_timeout / 1000, DEFAULT_IO_WAIT_TIME_MS); + is_inited_ = true; + } + } + } + return ret; +} + +void ObDirectLoadIndexBlockReader::assign(const int64_t buf_size, char *buf) +{ + buf_size_ = buf_size; + buf_ = buf; +} + +int ObDirectLoadIndexBlockReader::change_fragment(const ObDirectLoadTmpFileHandle &file_handle) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(file_io_handle_.open(file_handle))) { + LOG_WARN("fail to change file handle", KR(ret)); + } + return ret; +} + +// 读对应索引项块 +int ObDirectLoadIndexBlockReader::read_buffer(int64_t idx) +{ + int ret = OB_SUCCESS; + uint64_t offset = 0; + offset = buf_size_ * idx; + if (OB_FAIL(file_io_handle_.aio_pread(buf_, buf_size_, offset))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do aio read from index file", KR(ret)); + } + } else { + if (OB_FAIL(file_io_handle_.wait(io_timeout_ms_))) { + LOG_WARN("fail to wait io finish", KR(ret), K(io_timeout_ms_)); + } + } + return ret; +} + +//读对应索引块下标的索引项 +int ObDirectLoadIndexBlockReader::get_index_info(int64_t idx, ObDirectLoadIndexInfo &info) +{ + int ret = OB_SUCCESS; + ObDirectLoadIndexBlockItem start_item; + ObDirectLoadIndexBlockItem end_item; + int64_t num_index = idx / index_item_num_per_block_; + int64_t offset = idx % index_item_num_per_block_; + int64_t buf_pos = 0; + if (OB_FAIL(read_buffer(num_index))) { + LOG_WARN("fail to read buffer", KR(ret)); + } else if (OB_FAIL(header_.deserialize(buf_, buf_size_, buf_pos))) { + LOG_WARN("fail to deserialize header", KR(ret)); + } else { + if (0 == offset) { + info.offset_ = header_.start_offset_; + } else { + buf_pos = header_length_ + (offset - 1) * item_size_; + if (OB_FAIL(start_item.deserialize(buf_, buf_size_, buf_pos))) { + LOG_WARN("fail to deserialize item", KR(ret), K(buf_size_), K(buf_pos)); + } else { + info.offset_ = start_item.end_offset_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(end_item.deserialize(buf_, buf_size_, buf_pos))) { + LOG_WARN("fail to deserialize item", KR(ret), K(buf_size_), K(buf_pos)); + } else { + info.size_ = end_item.end_offset_ - info.offset_; + } + } + } + return ret; +} + +/** + * ObDirectLoadDataBlockReader2 + */ + +ObDirectLoadDataBlockReader2::ObDirectLoadDataBlockReader2() + : buf_(nullptr), buf_pos_(0), buf_size_(0), is_inited_(false) +{ +} + +void ObDirectLoadDataBlockReader2::assign(const int64_t buf_pos, const int64_t buf_size, char *buf) +{ + buf_pos_ = buf_pos; + buf_size_ = buf_size; + buf_ = buf; +} + +void ObDirectLoadDataBlockReader2::reset() +{ + is_inited_ = false; + assign(0, 0, nullptr); + buf_ = nullptr; +} + +int ObDirectLoadDataBlockReader2::init(int64_t buf_size, char *buf, int64_t cols_count) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadDataBlockReader2 init twice", KR(ret), KP(this)); + } else if (buf_size <= 0 || buf_size % DIO_ALIGN_SIZE != 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(buf_size)); + } else { + assign(0, buf_size, buf); + if (OB_FAIL(header_.deserialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to deserialize header", KR(ret), K(buf_), K(buf_size_), K(buf_pos_)); + } else if (header_.occupy_size_ > buf_size_) { + ret = OB_BUF_NOT_ENOUGH; + LOG_WARN("buf is not enough", KR(ret), K(header_.occupy_size_), K(buf_size_)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadDataBlockReader2::get_next_item(const ObDirectLoadExternalRow *&item) +{ + int ret = OB_SUCCESS; + item = NULL; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadDataBlockReader2 not init", KR(ret), KP(this)); + } else if (buf_pos_ == header_.size_) { + ret = OB_ITER_END; + } else if (OB_FAIL(curr_row_.deserialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to deserialize buffer", KR(ret), K(buf_size_), K(buf_pos_)); + } else { + item = &curr_row_; + } + return ret; +} + +OB_DEF_SERIALIZE(ObDirectLoadDataBlockHeader) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, size_))) { + RPC_WARN("encode object fail", "name", MSTR(size_), K(buf_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, occupy_size_))) { + RPC_WARN("encode object fail", "name", MSTR(occupy_size_), K(buf_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, last_row_offset_))) { + RPC_WARN("encode object fail", "name", MSTR(last_row_offset_), K(buf_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObDirectLoadDataBlockHeader) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &size_))) { + RPC_WARN("decode object fail", "name", MSTR(size_), K(data_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &occupy_size_))) { + RPC_WARN("decode object fail", "name", MSTR(occupy_size_), K(data_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &last_row_offset_))) { + RPC_WARN("decode object fail", "name", MSTR(last_row_offset_), K(data_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObDirectLoadDataBlockHeader) +{ + int64_t len = 0; + len += NS_::encoded_length_i32(size_); + len += NS_::encoded_length_i32(occupy_size_); + len += NS_::encoded_length_i32(last_row_offset_); + return len; +} + +OB_DEF_SERIALIZE(ObDirectLoadIndexBlockHeader) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, start_offset_))) { + RPC_WARN("encode object fail", "name", MSTR(start_offset_), K(buf_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, row_count_))) { + RPC_WARN("encode object fail", "name", MSTR(row_count_), K(buf_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObDirectLoadIndexBlockHeader) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, reinterpret_cast(&start_offset_)))) { + RPC_WARN("decode object fail", "name", MSTR(start_offset_), K(data_len), K(pos), K(ret)); + } + } + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &row_count_))) { + RPC_WARN("decode object fail", "name", MSTR(row_count_), K(data_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObDirectLoadIndexBlockHeader) +{ + int64_t len = 0; + len += NS_::encoded_length_i64(start_offset_); + len += NS_::encoded_length_i64(row_count_); + return len; +} + +OB_DEF_SERIALIZE(ObDirectLoadIndexBlockItem) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret)) { + if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, end_offset_))) { + RPC_WARN("encode object fail", "name", MSTR(end_offset_), K(buf_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_DESERIALIZE(ObDirectLoadIndexBlockItem) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret) && pos < data_len) { + if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, reinterpret_cast(&end_offset_)))) { + RPC_WARN("decode object fail", "name", MSTR(end_offset_), K(data_len), K(pos), K(ret)); + } + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObDirectLoadIndexBlockItem) +{ + int64_t len = 0; + len += NS_::encoded_length_i64(end_offset_); + return len; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_builder.h b/src/storage/direct_load/ob_direct_load_sstable_builder.h new file mode 100644 index 0000000000..4251b05099 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_builder.h @@ -0,0 +1,239 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "ob_direct_load_tmp_file.h" +#include "storage/direct_load/ob_direct_load_external_row.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_sstable.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +struct ObDirectLoadDataBlockHeader +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadDataBlockHeader() : size_(0), occupy_size_(0), last_row_offset_(0) {} + TO_STRING_KV(K_(size), K_(occupy_size), K(last_row_offset_)); +public: + int32_t size_; // 有效数据大小 + int32_t occupy_size_; // 实际占用大小 + int32_t last_row_offset_; +}; + +struct ObDirectLoadIndexBlockHeader +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadIndexBlockHeader() : start_offset_(0), row_count_(0) {} + TO_STRING_KV(K(start_offset_), K(row_count_)); +public: + uint64_t start_offset_; + int64_t row_count_; //索引块的row_count +}; + +struct ObDirectLoadIndexBlockItem +{ + OB_UNIS_VERSION(1); +public: + ObDirectLoadIndexBlockItem() : end_offset_(0) {} + TO_STRING_KV(K(end_offset_)); +public: + uint64_t end_offset_; //索引项的offset +}; + +struct ObDirectLoadIndexInfo +{ +public: + ObDirectLoadIndexInfo() : offset_(0), size_(0) {} + uint64_t offset_; //索引块对应数据块的offset + int64_t size_; //数据块的大小 + TO_STRING_KV(K(offset_), K(size_)); +}; + +class ObDirectLoadIndexBlock +{ +public: + static int64_t get_item_num_per_block(int64_t block_size); +}; + +struct ObDirectLoadSSTableBuildParam +{ +public: + ObDirectLoadSSTableBuildParam() : datum_utils_(nullptr), file_mgr_(nullptr) {} + bool is_valid() const + { + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != file_mgr_ && + nullptr != datum_utils_; + } + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(file_mgr), KP_(datum_utils)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + ObDirectLoadTmpFileManager *file_mgr_; +}; + +class ObDirectLoadIndexBlockWriter +{ +public: + ObDirectLoadIndexBlockWriter(); + ~ObDirectLoadIndexBlockWriter(); + int init(uint64_t tenant_id, int64_t buf_size, const ObDirectLoadTmpFileHandle &file_handle); + int append_row(int64_t row_count, const ObDirectLoadIndexBlockItem &item); + void reset(); + int close(); + int64_t get_total_index_size() const { return total_index_size_; } + TO_STRING_KV(KP(buf_), K(buf_pos_), K(buf_size_), K(item_size_), K(total_index_size_), K(offset_), + K(tenant_id_)); +private: + int flush_buffer(); + int write_item(const ObDirectLoadIndexBlockItem &item); + void assign(const int64_t buf_pos, const int64_t buf_cap, char *buf); +private: + uint64_t tenant_id_; + int64_t header_length_; + int64_t buf_pos_; + int64_t buf_size_; + int64_t item_size_; //每个索引块对应的索引项个数 + int64_t row_count_; //索引块的总行数 + int64_t total_index_size_; //索引项个数 + uint64_t offset_; //维护索引项的offset + char *buf_; + common::ObArenaAllocator allocator_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + ObDirectLoadIndexBlockHeader header_; + bool is_inited_; + bool is_closed_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadIndexBlockWriter); +}; + +class ObDirectLoadDataBlockWriter2 +{ +public: + ObDirectLoadDataBlockWriter2(); + ~ObDirectLoadDataBlockWriter2(); + int init(uint64_t tenant_id, int64_t buf_size, const ObDirectLoadTmpFileHandle &file_handle, + ObDirectLoadIndexBlockWriter *index_block_writer); + int append_row(const ObDirectLoadExternalRow &external_row); + void reset(); + int close(); + ObDirectLoadDataBlockHeader *get_header() { return &header_; } + int64_t get_total_row_count() const { return total_row_count_; } + int64_t get_file_size() const { return file_size_; } + TO_STRING_KV(KP(buf_), K(buf_pos_), K(buf_size_), K(file_size_), K(file_io_handle_), + K(tenant_id_), K(total_row_count_), K(row_count_)); +private: + int write_item(const ObDirectLoadExternalRow &external_row); + int write_large_item(const ObDirectLoadExternalRow &datum_row, int64_t total_size); + void assign(const int64_t buf_pos, const int64_t buf_cap, char *buf); + int flush_buffer(int64_t buf_size, char *buf); +private: + uint64_t tenant_id_; + int64_t header_length_; + int64_t buf_pos_; + int64_t buf_size_; + int64_t total_row_count_; + int64_t row_count_; + uint64_t file_size_; + ObDirectLoadExternalRow last_row_; + char *buf_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + common::ObArenaAllocator allocator_; + ObDirectLoadDataBlockHeader header_; + ObDirectLoadIndexBlockWriter *index_block_writer_; + bool is_inited_; + bool is_closed_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockWriter2); +}; + +class ObDirectLoadSSTableBuilder : public ObIDirectLoadPartitionTableBuilder +{ +public: + ObDirectLoadSSTableBuilder() : allocator_("TLD_sstablebdr"), is_closed_(false), is_inited_(false) + { + } + virtual ~ObDirectLoadSSTableBuilder() = default; + int init(const ObDirectLoadSSTableBuildParam ¶m); + int append_row(const common::ObTabletID &tablet_id, + const blocksstable::ObDatumRow &datum_row) override; + int append_row(const ObDirectLoadExternalRow &external_row); + int close() override; + int64_t get_row_count() const override { return data_block_writer_.get_total_row_count(); } + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator) override; +private: + int check_rowkey_order(const blocksstable::ObDatumRowkey &rowkey); +private: + ObDirectLoadSSTableBuildParam param_; + ObDirectLoadDataBlockWriter2 data_block_writer_; + ObDirectLoadIndexBlockWriter index_block_writer_; + common::ObArenaAllocator allocator_; + common::ObArenaAllocator rowkey_allocator_; + blocksstable::ObDatumRowkey start_key_; + blocksstable::ObDatumRowkey end_key_; + ObDirectLoadTmpFileHandle data_file_handle_; + ObDirectLoadTmpFileHandle index_file_handle_; + ObDirectLoadTmpFileManager *file_mgr_; + bool is_closed_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadSSTableBuilder); +}; + +class ObDirectLoadIndexBlockReader +{ +public: + ObDirectLoadIndexBlockReader(); + virtual ~ObDirectLoadIndexBlockReader() = default; + int init(uint64_t tenant_id, int64_t buf_size, const ObDirectLoadTmpFileHandle &file_handle); + int change_fragment(const ObDirectLoadTmpFileHandle &file_handle); + int get_index_info(int64_t idx, ObDirectLoadIndexInfo &info); + ObDirectLoadIndexBlockHeader *get_header() { return &header_; } + TO_STRING_KV(KP(buf_), K(buf_size_), K(tenant_id_)); +private: + void assign(const int64_t buf_size, char *buf); + int read_buffer(int64_t idx); +private: + uint64_t tenant_id_; + char *buf_; + int64_t buf_size_; + int64_t header_length_; + int64_t item_size_; + int64_t index_item_num_per_block_; + int64_t io_timeout_ms_; + ObDirectLoadIndexBlockHeader header_; + common::ObArenaAllocator allocator_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadIndexBlockReader); +}; + +class ObDirectLoadDataBlockReader2 +{ +public: + ObDirectLoadDataBlockReader2(); + virtual ~ObDirectLoadDataBlockReader2() = default; + int init(int64_t buf_size, char *buf, int64_t cols_count); + void assign(const int64_t buf_pos, const int64_t buf_size, char *buf); + void change_fragment(const ObDirectLoadTmpFileHandle &file_handle); + void reset(); + int get_next_item(const ObDirectLoadExternalRow *&item); + ObDirectLoadDataBlockHeader *get_header() { return &header_; } + TO_STRING_KV(KP(buf_), K(buf_pos_), K(buf_size_)); +private: + char *buf_; + int64_t buf_pos_; + int64_t buf_size_; + ObDirectLoadDataBlockHeader header_; + ObDirectLoadExternalRow curr_row_; + bool is_inited_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadDataBlockReader2); +}; + +} // namespace storage +} // namespace oceanbase \ No newline at end of file diff --git a/src/storage/direct_load/ob_direct_load_sstable_compactor.cpp b/src/storage/direct_load/ob_direct_load_sstable_compactor.cpp new file mode 100644 index 0000000000..acab4b0f4a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_compactor.cpp @@ -0,0 +1,190 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_compactor.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadSSTableCompactParam + */ + +ObDirectLoadSSTableCompactParam::ObDirectLoadSSTableCompactParam() + : datum_utils_(nullptr) +{ +} + +ObDirectLoadSSTableCompactParam::~ObDirectLoadSSTableCompactParam() +{ +} + +bool ObDirectLoadSSTableCompactParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != datum_utils_; +} + +/** + * ObDirectLoadSSTableCompactor + */ + +ObDirectLoadSSTableCompactor::ObDirectLoadSSTableCompactor() + : index_item_count_(0), index_block_count_(0), row_count_(0), is_inited_(false) +{ +} + +ObDirectLoadSSTableCompactor::~ObDirectLoadSSTableCompactor() +{ +} + +int ObDirectLoadSSTableCompactor::init(const ObDirectLoadSSTableCompactParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableCompactor init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + param_ = param; + start_key_.set_min_rowkey(); + end_key_.set_min_rowkey(); + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadSSTableCompactor::add_table(ObIDirectLoadPartitionTable *table) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableCompactor not init", KR(ret), KP(this)); + } else { + int cmp_ret = 0; + ObDirectLoadSSTable *sstable = dynamic_cast(table); + if (OB_ISNULL(sstable)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(sstable)); + } else if (OB_FAIL(check_table_compactable(sstable))) { + LOG_WARN("fail to check table compactable", KR(ret), KPC(sstable)); + } else if (!sstable->is_empty()) { + const ObDirectLoadSSTableMeta &table_meta = sstable->get_meta(); + index_item_count_ += table_meta.index_item_count_; + index_block_count_ += table_meta.index_block_count_; + row_count_ += table_meta.row_count_; + for (int64_t i = 0; OB_SUCC(ret) && i < sstable->get_fragment_array().count(); ++i) { + if (OB_FAIL(fragments_.push_back(sstable->get_fragment_array().at(i)))) { + LOG_WARN("fail to push back table fragment", KR(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + end_key_allocator_.reuse(); + if (start_key_.is_min_rowkey() && + OB_FAIL(sstable->get_start_key().deep_copy(start_key_, start_key_allocator_))) { + LOG_WARN("fail to deep copy start key", KR(ret)); + } else if (OB_FAIL(sstable->get_end_key().deep_copy(end_key_, end_key_allocator_))) { + LOG_WARN("fail to deep copy end key", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadSSTableCompactor::check_table_compactable(ObDirectLoadSSTable *sstable) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(sstable)); + } else { + const ObDirectLoadSSTableMeta &table_meta = sstable->get_meta(); + if (OB_UNLIKELY( + table_meta.tablet_id_ != param_.tablet_id_ || + table_meta.rowkey_column_count_ != param_.table_data_desc_.rowkey_column_num_ || + table_meta.column_count_ != param_.table_data_desc_.column_count_ || + table_meta.index_block_size_ != param_.table_data_desc_.sstable_index_block_size_ || + table_meta.data_block_size_ != param_.table_data_desc_.sstable_data_block_size_)) { + ret = OB_ITEM_NOT_MATCH; + LOG_WARN("table meta not match", KR(ret), K(param_), K(table_meta)); + } else if (!sstable->is_empty()) { + int cmp_ret = 0; + if (OB_FAIL(end_key_.compare(sstable->get_start_key(), *param_.datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare rowkey", KR(ret)); + } else if (cmp_ret >= 0) { + ret = OB_ROWKEY_ORDER_ERROR; + LOG_WARN("sstable is not contiguous", KR(ret), K(end_key_), K(sstable->get_start_key())); + } + } + } + return ret; +} + +int ObDirectLoadSSTableCompactor::compact() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableCompactor not init", KR(ret), KP(this)); + } else { + // do nothing + } + return ret; +} + +int ObDirectLoadSSTableCompactor::get_table(ObIDirectLoadPartitionTable *&table, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableCompactor not init", KR(ret), KP(this)); + } else { + ObDirectLoadSSTable *sstable = nullptr; + ObDirectLoadSSTableCreateParam create_param; + create_param.tablet_id_ = param_.tablet_id_; + create_param.rowkey_column_count_ = param_.table_data_desc_.rowkey_column_num_; + create_param.column_count_ = param_.table_data_desc_.column_count_; + create_param.index_block_size_ = param_.table_data_desc_.sstable_index_block_size_; + create_param.data_block_size_ = param_.table_data_desc_.sstable_data_block_size_; + create_param.index_item_count_ = index_item_count_; + create_param.index_block_count_ = index_block_count_; + create_param.row_count_ = row_count_; + create_param.start_key_ = start_key_; + create_param.end_key_ = end_key_; + if (OB_FAIL(create_param.fragments_.assign(fragments_))) { + LOG_WARN("fail to assign fragments", KR(ret)); + } else if (OB_ISNULL(sstable = OB_NEWx(ObDirectLoadSSTable, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadSSTable", KR(ret)); + } else if (OB_FAIL(sstable->init(create_param))) { + LOG_WARN("fail to init sstable table", KR(ret)); + } else { + table = sstable; + } + if (OB_FAIL(ret)) { + if (nullptr != sstable) { + sstable->~ObDirectLoadSSTable(); + allocator.free(sstable); + sstable = nullptr; + } + } + } + return ret; +} + +void ObDirectLoadSSTableCompactor::stop() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_compactor.h b/src/storage/direct_load/ob_direct_load_sstable_compactor.h new file mode 100644 index 0000000000..d85600ba72 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_compactor.h @@ -0,0 +1,55 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_sstable.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadSSTableCompactParam +{ +public: + ObDirectLoadSSTableCompactParam(); + ~ObDirectLoadSSTableCompactParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(datum_utils)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; +}; + +class ObDirectLoadSSTableCompactor : public ObIDirectLoadTabletTableCompactor +{ +public: + ObDirectLoadSSTableCompactor(); + virtual ~ObDirectLoadSSTableCompactor(); + int init(const ObDirectLoadSSTableCompactParam ¶m); + int add_table(ObIDirectLoadPartitionTable *table) override; + int compact() override; + int get_table(ObIDirectLoadPartitionTable *&table, common::ObIAllocator &allocator) override; + void stop() override; +private: + int check_table_compactable(ObDirectLoadSSTable *sstable); +private: + ObDirectLoadSSTableCompactParam param_; + int64_t index_item_count_; + int64_t index_block_count_; + int64_t row_count_; + common::ObArray fragments_; + common::ObArenaAllocator start_key_allocator_; + common::ObArenaAllocator end_key_allocator_; + blocksstable::ObDatumRowkey start_key_; + blocksstable::ObDatumRowkey end_key_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_data_block.cpp b/src/storage/direct_load/ob_direct_load_sstable_data_block.cpp new file mode 100644 index 0000000000..8441925bb7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_data_block.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * ObDirectLoadSSTableDataBlock + */ + +ObDirectLoadSSTableDataBlock::Header::Header() + : last_row_pos_(0), reserved_(0) +{ +} + +ObDirectLoadSSTableDataBlock::Header::~Header() +{ +} + +void ObDirectLoadSSTableDataBlock::Header::reset() +{ + ObDirectLoadDataBlock::Header::reset(); + last_row_pos_ = 0; + reserved_ = 0; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadSSTableDataBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::serialize(buf, buf_len, pos))) { + LOG_WARN("fail to encode header", KR(ret), K(buf_len), K(pos)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, last_row_pos_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(last_row_pos_)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, reserved_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(reserved_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadSSTableDataBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::deserialize(buf, data_len, pos))) { + LOG_WARN("fail to decode header", KR(ret), K(data_len), K(pos)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &last_row_pos_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(last_row_pos_)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &reserved_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(reserved_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadSSTableDataBlock::Header) +{ + int64_t len = 0; + len += ObDirectLoadDataBlock::Header::get_serialize_size(); + len += NS_::encoded_length_i32(last_row_pos_); + len += NS_::encoded_length_i32(reserved_); + return len; +} + +/** + * ObDirectLoadSSTableDataBlock + */ + +int64_t ObDirectLoadSSTableDataBlock::get_header_size() +{ + static int64_t size = Header().get_serialize_size(); + return size; +} + +/** + * ObDirectLoadSSTableDataBlockDesc + */ + +ObDirectLoadSSTableDataBlockDesc::ObDirectLoadSSTableDataBlockDesc() + : fragment_idx_(0), + offset_(0), + size_(0), + block_count_(0), + is_left_border_(false), + is_right_border_(false) +{ +} + +ObDirectLoadSSTableDataBlockDesc::~ObDirectLoadSSTableDataBlockDesc() +{ +} + +void ObDirectLoadSSTableDataBlockDesc::reset() +{ + fragment_idx_ = 0; + offset_ = 0; + size_ = 0; + block_count_ = 0; + is_left_border_ = false; + is_right_border_ = false; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_data_block.h b/src/storage/direct_load/ob_direct_load_sstable_data_block.h new file mode 100644 index 0000000000..1b1a49ba11 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_data_block.h @@ -0,0 +1,52 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadSSTableDataBlock +{ +public: + static const int64_t DEFAULT_DATA_BLOCK_SIZE = 16 * 1024; // 16K + struct Header : public ObDirectLoadDataBlock::Header + { + OB_UNIS_VERSION(1); + public: + Header(); + ~Header(); + void reset(); + TO_STRING_KV(K_(last_row_pos)); + public: + int32_t last_row_pos_; + int32_t reserved_; + }; +public: + static int64_t get_header_size(); +}; + +struct ObDirectLoadSSTableDataBlockDesc +{ +public: + ObDirectLoadSSTableDataBlockDesc(); + ~ObDirectLoadSSTableDataBlockDesc(); + void reset(); + TO_STRING_KV(K_(fragment_idx), K_(offset), K_(size), K_(block_count), K_(is_left_border), + K_(is_right_border)); +public: + int64_t fragment_idx_; + int64_t offset_; + int64_t size_; + int64_t block_count_; + bool is_left_border_; + bool is_right_border_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_data_block_reader.h b/src/storage/direct_load/ob_direct_load_sstable_data_block_reader.h new file mode 100644 index 0000000000..94ff6e19b2 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_data_block_reader.h @@ -0,0 +1,47 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadSSTableDataBlockReader + : public ObDirectLoadDataBlockReader +{ +public: + ObDirectLoadSSTableDataBlockReader() = default; + virtual ~ObDirectLoadSSTableDataBlockReader() = default; + int get_next_row(const T *&row); + int get_last_row(const T *&row); +}; + +template +int ObDirectLoadSSTableDataBlockReader::get_next_row(const T *&row) +{ + return this->get_next_item(row); +} + +template +int ObDirectLoadSSTableDataBlockReader::get_last_row(const T *&row) +{ + int ret = common::OB_SUCCESS; + const ObDirectLoadSSTableDataBlock::Header &header = this->data_block_reader_.get_header(); + this->curr_item_.reuse(); + if (OB_FAIL(this->data_block_reader_.read_item(header.last_row_pos_, this->curr_item_))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + row = &this->curr_item_; + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_data_block_writer.h b/src/storage/direct_load/ob_direct_load_sstable_data_block_writer.h new file mode 100644 index 0000000000..16cd47830a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_data_block_writer.h @@ -0,0 +1,73 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_writer.h" +#include "storage/direct_load/ob_direct_load_sstable_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadSSTableDataBlockWriter + : public ObDirectLoadDataBlockWriter +{ +public: + ObDirectLoadSSTableDataBlockWriter(); + virtual ~ObDirectLoadSSTableDataBlockWriter(); + int append_row(const T &row); +private: + int pre_write_item() override; + int pre_flush_buffer() override; +private: + int32_t last_row_pos_; + int32_t cur_row_pos_; // for one row data block + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadSSTableDataBlockWriter); +}; + +template +ObDirectLoadSSTableDataBlockWriter::ObDirectLoadSSTableDataBlockWriter() + : last_row_pos_(-1), cur_row_pos_(-1) +{ +} + +template +ObDirectLoadSSTableDataBlockWriter::~ObDirectLoadSSTableDataBlockWriter() +{ +} + +template +int ObDirectLoadSSTableDataBlockWriter::append_row(const T &row) +{ + int ret = common::OB_SUCCESS; + if (OB_FAIL(this->write_item(row))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } else { + last_row_pos_ = cur_row_pos_; + } + return ret; +} + +template +int ObDirectLoadSSTableDataBlockWriter::pre_write_item() +{ + cur_row_pos_ = this->data_block_writer_.get_pos(); + return common::OB_SUCCESS; +} + +template +int ObDirectLoadSSTableDataBlockWriter::pre_flush_buffer() +{ + ObDirectLoadSSTableDataBlock::Header &header = this->data_block_writer_.get_header(); + header.last_row_pos_ = (last_row_pos_ != -1 ? last_row_pos_ : cur_row_pos_); + last_row_pos_ = -1; + cur_row_pos_ = -1; + return common::OB_SUCCESS; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block.cpp b/src/storage/direct_load/ob_direct_load_sstable_index_block.cpp new file mode 100644 index 0000000000..6545175438 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block.cpp @@ -0,0 +1,159 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_index_block.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +/** + * Header + */ + +ObDirectLoadSSTableIndexBlock::Header::Header() + : offset_(0), count_(0), last_entry_pos_(0) +{ +} + +ObDirectLoadSSTableIndexBlock::Header::~Header() +{ +} + +void ObDirectLoadSSTableIndexBlock::Header::reset() +{ + ObDirectLoadDataBlock::Header::reset(); + offset_ = 0; + count_ = 0; + last_entry_pos_ = 0; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::serialize(buf, buf_len, pos))) { + LOG_WARN("fail to encode header", KR(ret), K(buf_len), K(pos)); + } else if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, offset_))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(offset_)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, count_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(count_)); + } else if (OB_FAIL(NS_::encode_i32(buf, buf_len, pos, last_entry_pos_))) { + LOG_WARN("fail to encode i32", KR(ret), K(buf_len), K(pos), K(last_entry_pos_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Header) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObDirectLoadDataBlock::Header::deserialize(buf, data_len, pos))) { + LOG_WARN("fail to decode header", KR(ret), K(data_len), K(pos)); + } else if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &offset_))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(offset_)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &count_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(count_)); + } else if (OB_FAIL(NS_::decode_i32(buf, data_len, pos, &last_entry_pos_))) { + LOG_WARN("fail to decode i32", KR(ret), K(data_len), K(pos), K(last_entry_pos_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Header) +{ + int64_t len = 0; + len += ObDirectLoadDataBlock::Header::get_serialize_size(); + len += NS_::encoded_length_i64(offset_); + len += NS_::encoded_length_i32(count_); + len += NS_::encoded_length_i32(last_entry_pos_); + return len; +} + +/* + * Entry + */ + +ObDirectLoadSSTableIndexBlock::Entry::Entry() + : offset_(0) +{ +} + +ObDirectLoadSSTableIndexBlock::Entry::~Entry() +{ +} + +void ObDirectLoadSSTableIndexBlock::Entry::reset() +{ + offset_ = 0; +} + +void ObDirectLoadSSTableIndexBlock::Entry::reuse() +{ + offset_ = 0; +} + +OB_DEF_SERIALIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Entry) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::encode_i64(buf, buf_len, pos, offset_))) { + LOG_WARN("fail to encode i64", KR(ret), K(buf_len), K(pos), K(offset_)); + } + return ret; +} + +OB_DEF_DESERIALIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Entry) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(NS_::decode_i64(buf, data_len, pos, &offset_))) { + LOG_WARN("fail to decode i64", KR(ret), K(data_len), K(pos), K(offset_)); + } + return ret; +} + +OB_DEF_SERIALIZE_SIZE_SIMPLE(ObDirectLoadSSTableIndexBlock::Entry) +{ + int64_t len = 0; + len += NS_::encoded_length_i64(offset_); + return len; +} + +/** + * ObDirectLoadSSTableIndexBlock + */ + +int64_t ObDirectLoadSSTableIndexBlock::get_header_size() +{ + static int64_t size = Header().get_serialize_size(); + return size; +} + +int64_t ObDirectLoadSSTableIndexBlock::get_entry_size() +{ + static int64_t size = Entry().get_serialize_size(); + return size; +} + +int64_t ObDirectLoadSSTableIndexBlock::get_entries_per_block(int64_t block_size) +{ + return (block_size - get_header_size()) / get_entry_size(); +} + +/** + * ObDirectLoadSSTableIndexEntry + */ + +ObDirectLoadSSTableIndexEntry::ObDirectLoadSSTableIndexEntry() + : offset_(0), size_(0) +{ +} + +ObDirectLoadSSTableIndexEntry::~ObDirectLoadSSTableIndexEntry() +{ +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block.h b/src/storage/direct_load/ob_direct_load_sstable_index_block.h new file mode 100644 index 0000000000..425f2a07eb --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block.h @@ -0,0 +1,61 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadSSTableIndexBlock +{ +public: + static const int64_t DEFAULT_INDEX_BLOCK_SIZE = 4 * 1024; // 4K + struct Header : public ObDirectLoadDataBlock::Header + { + OB_UNIS_VERSION(1); + public: + Header(); + ~Header(); + void reset(); + TO_STRING_KV(K_(offset), K_(count), K_(last_entry_pos)); + public: + int64_t offset_; // start offset of index block data + int32_t count_; + int32_t last_entry_pos_; + }; + struct Entry + { + OB_UNIS_VERSION(1); + public: + Entry(); + ~Entry(); + void reuse(); + void reset(); + TO_STRING_KV(K_(offset)); + public: + int64_t offset_; + }; +public: + static int64_t get_header_size(); + static int64_t get_entry_size(); + static int64_t get_entries_per_block(int64_t block_size); +}; + +struct ObDirectLoadSSTableIndexEntry +{ +public: + ObDirectLoadSSTableIndexEntry(); + ~ObDirectLoadSSTableIndexEntry(); + TO_STRING_KV(K_(offset), K_(size)); +public: + int64_t offset_; + int64_t size_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block_iterator.h b/src/storage/direct_load/ob_direct_load_sstable_index_block_iterator.h new file mode 100644 index 0000000000..22c2049e0a --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block_iterator.h @@ -0,0 +1,171 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadSSTableIndexBlockIterator +{ + typedef ObDirectLoadSSTableIndexBlockIterator self_t; +public: + typedef typename std::random_access_iterator_tag iterator_category; + typedef int64_t difference_type; + typedef self_t value_type; + typedef self_t *value_ptr_t; + typedef self_t *pointer; + typedef self_t &reference; +public: + ObDirectLoadSSTableIndexBlockIterator() : sstable_(nullptr), fragment_idx_(0), index_block_idx_(0) + { + } + ObDirectLoadSSTableIndexBlockIterator(const self_t &other) { *this = other; } + ~ObDirectLoadSSTableIndexBlockIterator() {} + self_t &operator=(const self_t &other) + { + sstable_ = other.sstable_; + fragment_idx_ = other.fragment_idx_; + index_block_idx_ = other.index_block_idx_; + return *this; + } +public: + reference operator*() { return *this; } + value_ptr_t operator->() { return this; } + operator value_ptr_t() { return this; } + bool operator==(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return fragment_idx_ == other.fragment_idx_ && index_block_idx_ == other.index_block_idx_; + } + bool operator!=(const self_t &other) const { return !(*this == other); } + bool operator<(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return (fragment_idx_ != other.fragment_idx_ ? fragment_idx_ < other.fragment_idx_ + : index_block_idx_ < other.index_block_idx_); + } + bool operator>(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return (fragment_idx_ != other.fragment_idx_ ? fragment_idx_ > other.fragment_idx_ + : index_block_idx_ > other.index_block_idx_); + } + bool operator>=(const self_t &other) const { return !(*this < other); } + bool operator<=(const self_t &other) const { return !(*this > other); } + difference_type operator-(const self_t &rhs) const + { + abort_unless(sstable_ == rhs.sstable_); + difference_type value = 0; + if (fragment_idx_ == rhs.fragment_idx_) { + value = index_block_idx_ - rhs.index_block_idx_; + } else if (fragment_idx_ > rhs.fragment_idx_) { // lhs > rhs + int64_t fragment_idx = fragment_idx_ - 1; + value += index_block_idx_; + abort_unless(fragment_idx < sstable_->get_fragments().count()); + while (fragment_idx > rhs.fragment_idx_) { + abort_unless(fragment_idx >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value += fragment.index_block_count_; + --fragment_idx; + } + abort_unless(fragment_idx >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value += (fragment.index_block_count_ - rhs.index_block_idx_); + } else { // lhs < rhs + abort_unless(fragment_idx_ >= 0 && fragment_idx_ < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + value -= (fragment.index_block_count_ - index_block_idx_); + int64_t fragment_idx = fragment_idx_ + 1; + while (fragment_idx < rhs.fragment_idx_) { + abort_unless(fragment_idx < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value -= fragment.index_block_count_; + ++fragment_idx; + } + value -= rhs.index_block_idx_; + } + return value; + } + self_t &operator+=(difference_type step) + { + while (step > 0) { + abort_unless(fragment_idx_ < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + if (index_block_idx_ + step < fragment.index_block_count_) { + index_block_idx_ += step; + step = 0; + } else { + step -= (fragment.index_block_count_ - index_block_idx_); + ++fragment_idx_; + index_block_idx_ = 0; + } + } + return *this; + } + self_t operator+(difference_type step) + { + self_t value(*this); + return (value += step); + } + self_t &operator-=(difference_type step) + { + while (step > 0) { + if (index_block_idx_ == 0) { + // prev fragment + fragment_idx_ -= 1; + abort_unless(fragment_idx_ >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + index_block_idx_ = fragment.index_block_count_; + } else if (index_block_idx_ >= step) { + index_block_idx_ -= step; + step = 0; + } else { + step -= index_block_idx_; + index_block_idx_ = 0; + } + } + return *this; + } + self_t operator-(difference_type step) + { + self_t value(*this); + return (value -= step); + } + self_t &operator++() + { + *this += 1; + return *this; + } + self_t operator++(int) + { + self_t tmp = *this; + *this += 1; + return tmp; + } + self_t &operator--() + { + *this -= 1; + return *this; + } + self_t operator--(int) + { + self_t tmp = *this; + *this -= 1; + return tmp; + } + TO_STRING_KV(KP_(sstable), K_(fragment_idx), K_(index_block_idx)); +public: + SSTable *sstable_; + int64_t fragment_idx_; + int64_t index_block_idx_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.cpp b/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.cpp new file mode 100644 index 0000000000..f865faf64f --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_index_block_reader.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadSSTableIndexBlockReader::ObDirectLoadSSTableIndexBlockReader() + : last_offset_(0) +{ +} + +ObDirectLoadSSTableIndexBlockReader::~ObDirectLoadSSTableIndexBlockReader() +{ +} + +int ObDirectLoadSSTableIndexBlockReader::init(int64_t data_block_size, + ObCompressorType compressor_type) +{ + return ParentType::init(data_block_size, data_block_size, compressor_type); +} + +int ObDirectLoadSSTableIndexBlockReader::get_next_entry(const ObDirectLoadSSTableIndexEntry *&entry) +{ + int ret = OB_SUCCESS; + const ObDirectLoadSSTableIndexBlock::Entry *item = nullptr; + if (OB_FAIL(this->get_next_item(item))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + STORAGE_LOG(WARN, "fail to get next item", KR(ret)); + } + } else { + entry_.offset_ = last_offset_; + entry_.size_ = item->offset_ - last_offset_; + last_offset_ = item->offset_; + } + return ret; +} + +int ObDirectLoadSSTableIndexBlockReader::get_last_entry(const ObDirectLoadSSTableIndexEntry *&entry) +{ + int ret = OB_SUCCESS; + const ObDirectLoadSSTableIndexBlock::Header &header = this->data_block_reader_.get_header(); + if (header.count_ == 1) { + entry_.offset_ = header.offset_; + } else { + // get penultimate entry + ObDirectLoadSSTableIndexBlock::Entry item; + const int64_t pos = header.last_entry_pos_ - ObDirectLoadSSTableIndexBlock::get_entry_size(); + if (OB_FAIL(this->data_block_reader_.read_item(pos, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + entry_.offset_ = item.offset_; + } + } + if (OB_SUCC(ret)) { + // get last entry + ObDirectLoadSSTableIndexBlock::Entry item; + if (OB_FAIL(this->data_block_reader_.read_item(header.last_entry_pos_, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + entry_.size_ = item.offset_ - entry_.offset_; + entry = &entry_; + } + } + return ret; +} + +int ObDirectLoadSSTableIndexBlockReader::get_entry(int64_t idx, + const ObDirectLoadSSTableIndexEntry *&entry) +{ + int ret = OB_SUCCESS; + const ObDirectLoadSSTableIndexBlock::Header &header = this->data_block_reader_.get_header(); + if (OB_UNLIKELY(idx >= header.count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(header), K(idx)); + } else { + const int64_t pos = ObDirectLoadSSTableIndexBlock::get_header_size() + + ObDirectLoadSSTableIndexBlock::get_entry_size() * idx; + if (0 == idx) { + entry_.offset_ = header.offset_; + } else { + // get prev entry + ObDirectLoadSSTableIndexBlock::Entry item; + const int64_t prev_pos = pos - ObDirectLoadSSTableIndexBlock::get_entry_size(); + if (OB_FAIL(this->data_block_reader_.read_item(prev_pos, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + entry_.offset_ = item.offset_; + } + } + if (OB_SUCC(ret)) { + // get current entry + ObDirectLoadSSTableIndexBlock::Entry item; + if (OB_FAIL(this->data_block_reader_.read_item(pos, item))) { + STORAGE_LOG(WARN, "fail to read item", KR(ret)); + } else { + entry_.size_ = item.offset_ - entry_.offset_; + entry = &entry_; + } + } + } + return ret; +} + +int ObDirectLoadSSTableIndexBlockReader::prepare_read_block() +{ + const ObDirectLoadSSTableIndexBlock::Header &header = this->data_block_reader_.get_header(); + last_offset_ = header.offset_; + return OB_SUCCESS; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.h b/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.h new file mode 100644 index 0000000000..9f1cc7a1c7 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block_reader.h @@ -0,0 +1,42 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_reader.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadSSTableIndexBlockReader + : public ObDirectLoadDataBlockReader +{ + typedef ObDirectLoadDataBlockReader + ParentType; +public: + ObDirectLoadSSTableIndexBlockReader(); + virtual ~ObDirectLoadSSTableIndexBlockReader(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + int get_next_entry(const ObDirectLoadSSTableIndexEntry *&entry); + int get_last_entry(const ObDirectLoadSSTableIndexEntry *&entry); + int get_entry(int64_t idx, const ObDirectLoadSSTableIndexEntry *&entry); + const ObDirectLoadSSTableIndexBlock::Header &get_header() const + { + return this->data_block_reader_.get_header(); + } +protected: + int prepare_read_block() override; +private: + int64_t last_offset_; + ObDirectLoadSSTableIndexEntry entry_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadSSTableIndexBlockReader); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.cpp b/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.cpp new file mode 100644 index 0000000000..b064529978 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_index_block_writer.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadSSTableIndexBlockWriter::ObDirectLoadSSTableIndexBlockWriter() + : start_offset_(0), entry_count_(0), last_entry_pos_(-1), cur_entry_pos_(-1) +{ +} + +ObDirectLoadSSTableIndexBlockWriter::~ObDirectLoadSSTableIndexBlockWriter() +{ +} + +int ObDirectLoadSSTableIndexBlockWriter::init(int64_t data_block_size, + ObCompressorType compressor_type) +{ + return ObDirectLoadDataBlockWriter::init(data_block_size, compressor_type, nullptr, 0, nullptr); +} + +int ObDirectLoadSSTableIndexBlockWriter::append_entry(const ObDirectLoadSSTableIndexEntry &entry) +{ + int ret = OB_SUCCESS; + ObDirectLoadSSTableIndexBlock::Entry item; + item.offset_ = entry.offset_ + entry.size_; + if (OB_FAIL(this->write_item(item))) { + STORAGE_LOG(WARN, "fail to write item", KR(ret)); + } else { + if (0 == entry_count_) { + start_offset_ = entry.offset_; + } + ++entry_count_; + last_entry_pos_ = cur_entry_pos_; + } + return ret; +} + +int ObDirectLoadSSTableIndexBlockWriter::pre_write_item() +{ + cur_entry_pos_ = this->data_block_writer_.get_pos(); + return OB_SUCCESS; +} + +int ObDirectLoadSSTableIndexBlockWriter::pre_flush_buffer() +{ + ObDirectLoadSSTableIndexBlock::Header &header = this->data_block_writer_.get_header(); + header.offset_ = start_offset_; + header.count_ = entry_count_; + header.last_entry_pos_ = (last_entry_pos_ != -1 ? last_entry_pos_ : cur_entry_pos_); + start_offset_ = 0; + entry_count_ = 0; + last_entry_pos_ = -1; + cur_entry_pos_ = -1; + return OB_SUCCESS; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.h b/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.h new file mode 100644 index 0000000000..e7a3479b76 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_block_writer.h @@ -0,0 +1,36 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_data_block_writer.h" +#include "storage/direct_load/ob_direct_load_sstable_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadSSTableIndexBlockWriter + : public ObDirectLoadDataBlockWriter +{ +public: + ObDirectLoadSSTableIndexBlockWriter(); + virtual ~ObDirectLoadSSTableIndexBlockWriter(); + int init(int64_t data_block_size, common::ObCompressorType compressor_type); + int append_entry(const ObDirectLoadSSTableIndexEntry &entry); +private: + int pre_write_item() override; + int pre_flush_buffer() override; +private: + int64_t start_offset_; + int32_t entry_count_; + int32_t last_entry_pos_; + int32_t cur_entry_pos_; + DISALLOW_COPY_AND_ASSIGN(ObDirectLoadSSTableIndexBlockWriter); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_index_entry_iterator.h b/src/storage/direct_load/ob_direct_load_sstable_index_entry_iterator.h new file mode 100644 index 0000000000..5572bd1040 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_index_entry_iterator.h @@ -0,0 +1,171 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/direct_load/ob_direct_load_sstable_index_block.h" + +namespace oceanbase +{ +namespace storage +{ + +template +class ObDirectLoadSSTableIndexEntryIterator +{ + typedef ObDirectLoadSSTableIndexEntryIterator self_t; +public: + typedef typename std::random_access_iterator_tag iterator_category; + typedef int64_t difference_type; + typedef self_t value_type; + typedef self_t *value_ptr_t; + typedef self_t *pointer; + typedef self_t &reference; +public: + ObDirectLoadSSTableIndexEntryIterator() : sstable_(nullptr), fragment_idx_(0), index_entry_idx_(0) + { + } + ObDirectLoadSSTableIndexEntryIterator(const self_t &other) { *this = other; } + ~ObDirectLoadSSTableIndexEntryIterator() {} + self_t &operator=(const self_t &other) + { + sstable_ = other.sstable_; + fragment_idx_ = other.fragment_idx_; + index_entry_idx_ = other.index_entry_idx_; + return *this; + } +public: + reference operator*() { return *this; } + value_ptr_t operator->() { return this; } + operator value_ptr_t() { return this; } + bool operator==(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return fragment_idx_ == other.fragment_idx_ && index_entry_idx_ == other.index_entry_idx_; + } + bool operator!=(const self_t &other) const { return !(*this == other); } + bool operator<(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return (fragment_idx_ != other.fragment_idx_ ? fragment_idx_ < other.fragment_idx_ + : index_entry_idx_ < other.index_entry_idx_); + } + bool operator>=(const self_t &other) const { return !(*this < other); } + bool operator>(const self_t &other) const + { + abort_unless(sstable_ == other.sstable_); + return (fragment_idx_ != other.fragment_idx_ ? fragment_idx_ > other.fragment_idx_ + : index_entry_idx_ > other.index_entry_idx_); + } + bool operator<=(const self_t &other) const { return !(*this > other); } + difference_type operator-(const self_t &rhs) const + { + abort_unless(sstable_ == rhs.sstable_); + difference_type value = 0; + if (fragment_idx_ == rhs.fragment_idx_) { + value = index_entry_idx_ - rhs.index_entry_idx_; + } else if (fragment_idx_ > rhs.fragment_idx_) { // lhs > rhs + int64_t fragment_idx = fragment_idx_ - 1; + value += index_entry_idx_; + abort_unless(fragment_idx < sstable_->get_fragments().count()); + while (fragment_idx > rhs.fragment_idx_) { + abort_unless(fragment_idx >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value += fragment.data_block_count_; + --fragment_idx; + } + abort_unless(fragment_idx >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value += (fragment.data_block_count_ - rhs.index_entry_idx_); + } else { // lhs < rhs + abort_unless(fragment_idx_ >= 0 && fragment_idx_ < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + value -= (fragment.data_block_count_ - index_entry_idx_); + int64_t fragment_idx = fragment_idx_ + 1; + while (fragment_idx < rhs.fragment_idx_) { + abort_unless(fragment_idx < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx); + value -= fragment.data_block_count_; + ++fragment_idx; + } + value -= rhs.index_entry_idx_; + } + return value; + } + self_t &operator+=(difference_type step) + { + while (step > 0) { + abort_unless(fragment_idx_ < sstable_->get_fragments().count()); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + if (index_entry_idx_ + step < fragment.data_block_count_) { + index_entry_idx_ += step; + step = 0; + } else { + step -= (fragment.data_block_count_ - index_entry_idx_); + ++fragment_idx_; + index_entry_idx_ = 0; + } + } + return *this; + } + self_t operator+(difference_type step) const + { + self_t value(*this); + return (value += step); + } + self_t &operator-=(difference_type step) + { + while (step > 0) { + if (index_entry_idx_ == 0) { + // prev fragment + fragment_idx_ -= 1; + abort_unless(fragment_idx_ >= 0); + const typename SSTable::Fragment &fragment = sstable_->get_fragments().at(fragment_idx_); + index_entry_idx_ = fragment.data_block_count_; + } else if (index_entry_idx_ >= step) { + index_entry_idx_ -= step; + step = 0; + } else { + step -= index_entry_idx_; + index_entry_idx_ = 0; + } + } + return *this; + } + self_t operator-(difference_type step) const + { + self_t value(*this); + return (value -= step); + } + self_t &operator++() + { + *this += 1; + return *this; + } + self_t operator++(int) + { + self_t tmp = *this; + *this += 1; + return tmp; + } + self_t &operator--() + { + *this -= 1; + return *this; + } + self_t operator--(int) + { + self_t tmp = *this; + *this -= 1; + return tmp; + } + TO_STRING_KV(KP_(sstable), K_(fragment_idx), K_(index_entry_idx)); +public: + SSTable *sstable_; + int64_t fragment_idx_; + int64_t index_entry_idx_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scan_merge.cpp b/src/storage/direct_load/ob_direct_load_sstable_scan_merge.cpp new file mode 100644 index 0000000000..c7d5f73cd2 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scan_merge.cpp @@ -0,0 +1,299 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_scan_merge.h" +#include "observer/table_load/ob_table_load_error_row_handler.h" +#include "storage/blocksstable/ob_datum_range.h" +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; +using namespace sql; + +/** + * ObDirectLoadSSTableScanMergeParam + */ + +ObDirectLoadSSTableScanMergeParam::ObDirectLoadSSTableScanMergeParam() + : datum_utils_(nullptr), error_row_handler_(nullptr), result_info_(nullptr) +{ +} + +ObDirectLoadSSTableScanMergeParam::~ObDirectLoadSSTableScanMergeParam() +{ +} + +bool ObDirectLoadSSTableScanMergeParam::is_valid() const +{ + return tablet_id_.is_valid() && table_data_desc_.is_valid() && nullptr != datum_utils_ && + nullptr != error_row_handler_ && nullptr != result_info_; +} + +/** + * ObDirectLoadSSTableScanMerge + */ + +ObDirectLoadSSTableScanMerge::ObDirectLoadSSTableScanMerge() + : datum_utils_(nullptr), + error_row_handler_(nullptr), + range_(nullptr), + consumers_(nullptr), + consumer_cnt_(0), + simple_merge_(nullptr), + loser_tree_(nullptr), + rows_merger_(nullptr), + is_inited_(false) +{ +} + +ObDirectLoadSSTableScanMerge::~ObDirectLoadSSTableScanMerge() +{ + reset(); +} + +void ObDirectLoadSSTableScanMerge::reset() +{ + tablet_id_.reset(); + table_data_desc_.reset(); + datum_utils_ = nullptr; + error_row_handler_ = nullptr; + range_ = nullptr; + for (int64_t i = 0; i < scanners_.count(); ++i) { + scanners_[i]->~ObDirectLoadSSTableScanner(); + } + scanners_.reset(); + consumers_ = nullptr; + consumer_cnt_ = 0; + if (nullptr != simple_merge_) { + simple_merge_->~ScanSimpleMerger(); + simple_merge_ = nullptr; + } + if (nullptr != loser_tree_) { + loser_tree_->~ScanMergeLoserTree(); + loser_tree_ = nullptr; + } + loser_tree_ = nullptr; + allocator_.reset(); + is_inited_ = false; +} + +int ObDirectLoadSSTableScanMerge::init(const ObDirectLoadSSTableScanMergeParam ¶m, + const ObIArray &sstable_array, + const ObDatumRange &range) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableScanMerge init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() || sstable_array.count() > MAX_SSTABLE_COUNT + || !range.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(sstable_array), K(range)); + } else { + // construct scanners + for (int64_t i = 0; OB_SUCC(ret) && i < sstable_array.count(); ++i) { + ObDirectLoadSSTable *sstable = sstable_array.at(i); + ObDirectLoadSSTableScanner *scanner = nullptr; + if (sstable->is_empty()) { + } else if (OB_FAIL(sstable->scan(param.table_data_desc_, range, param.datum_utils_, + allocator_, scanner))) { + LOG_WARN("fail to scan sstable", KR(ret)); + } else if (OB_FAIL(scanners_.push_back(scanner))) { + LOG_WARN("fail to push back scanner", KR(ret)); + } + } + if (OB_SUCC(ret) && !scanners_.empty()) { + // init consumers + if (OB_ISNULL(consumers_ = static_cast( + allocator_.alloc(sizeof(int64_t) * scanners_.count())))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", KR(ret)); + } else { + for (int64_t i = 0; i < scanners_.count(); ++i) { + consumers_[i] = i; + } + consumer_cnt_ = scanners_.count(); + } + // init rows merger + if (OB_FAIL(ret)) { + } else if (OB_FAIL(compare_.init(param.datum_utils_))) { + LOG_WARN("fail to init compare", KR(ret)); + } else if (OB_FAIL(init_rows_merger(scanners_.count()))) { + LOG_WARN("fail to init rows merger", KR(ret)); + } else if (OB_FAIL(datum_row_.init(param.table_data_desc_.column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } + } + if (OB_SUCC(ret)) { + tablet_id_ = param.tablet_id_; + table_data_desc_ = param.table_data_desc_; + datum_utils_ = param.datum_utils_; + error_row_handler_ = param.error_row_handler_; + result_info_ = param.result_info_; + range_ = ⦥ + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadSSTableScanMerge::init_rows_merger(int64_t sstable_count) +{ + int ret = OB_SUCCESS; + if (sstable_count <= ObScanSimpleMerger::USE_SIMPLE_MERGER_MAX_TABLE_CNT) { + if (OB_ISNULL(simple_merge_ = OB_NEWx(ScanSimpleMerger, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanSimpleMerger", KR(ret)); + } else { + rows_merger_ = simple_merge_; + } + } else { + if (OB_ISNULL(loser_tree_ = OB_NEWx(ScanMergeLoserTree, (&allocator_), compare_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ScanMergeLoserTree", KR(ret)); + } else { + rows_merger_ = loser_tree_; + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(rows_merger_->init(sstable_count, allocator_))) { + LOG_WARN("fail to init rows merger", KR(ret), K(sstable_count)); + } else if (FALSE_IT(rows_merger_->reuse())) { + } else if (OB_FAIL(rows_merger_->open(sstable_count))) { + LOG_WARN("fail to open rows merger", KR(ret), K(sstable_count)); + } + } + return ret; +} + +int ObDirectLoadSSTableScanMerge::supply_consume() +{ + int ret = OB_SUCCESS; + LoserTreeItem item; + for (int64_t i = 0; OB_SUCC(ret) && i < consumer_cnt_; ++i) { + const int64_t iter_idx = consumers_[i]; + ObDirectLoadSSTableScanner *scanner = scanners_.at(iter_idx); + if (OB_FAIL(scanner->get_next_row(item.external_row_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from scanner", KR(ret)); + } else { + ret = OB_SUCCESS; + } + } else { + item.iter_idx_ = iter_idx; + if (OB_FAIL(rows_merger_->push(item))) { + LOG_WARN("fail to push to loser tree", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + // no worry, if no new items pushed, the rebuild will quickly exit + if (OB_FAIL(rows_merger_->rebuild())) { + LOG_WARN("fail to rebuild loser tree", KR(ret), K(consumer_cnt_)); + } else { + consumer_cnt_ = 0; + } + } + return ret; +} + +int ObDirectLoadSSTableScanMerge::inner_get_next_row(const ObDirectLoadExternalRow *&external_row) +{ + int ret = OB_SUCCESS; + if (rows_merger_->empty()) { + ret = OB_ITER_END; + } else { + const LoserTreeItem *top_item = nullptr; + external_row = nullptr; + while (OB_SUCC(ret) && !rows_merger_->empty() && nullptr == external_row) { + if (OB_FAIL(rows_merger_->top(top_item))) { + LOG_WARN("fail to get top item", KR(ret)); + } else if (OB_LIKELY(rows_merger_->is_unique_champion())) { + external_row = top_item->external_row_; + } else { + // record same rowkey row + if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_REPLACE) { + ATOMIC_AAF(&result_info_->rows_affected_, 2); + ATOMIC_INC(&result_info_->deleted_); + } else if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_IGNORE) { + ATOMIC_INC(&result_info_->skipped_); + } else if (error_row_handler_->get_action() == ObLoadDupActionType::LOAD_STOP_ON_DUP) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(top_item->external_row_->to_datums(datum_row_.storage_datums_, + datum_row_.count_))) { + LOG_WARN("fail to transfer external row to datums", KR(tmp_ret)); + } else if (OB_TMP_FAIL(error_row_handler_->append_error_row(datum_row_))) { + LOG_WARN("fail to append row to error row handler", KR(tmp_ret), K(datum_row_)); + } + } + } + if (OB_SUCC(ret)) { + consumers_[consumer_cnt_++] = top_item->iter_idx_; + if (OB_FAIL(rows_merger_->pop())) { + LOG_WARN("fail to pop item", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanMerge::get_next_row(const ObDirectLoadExternalRow *&external_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableScanMerge not init", KR(ret), KP(this)); + } else if (scanners_.empty()) { + ret = OB_ITER_END; + } else if (1 == scanners_.count()) { + // direct get next row from scanner + if (OB_FAIL(scanners_.at(0)->get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row from scanner", KR(ret)); + } + } + } else { + // get next row from loser tree + if (consumer_cnt_ > 0 && OB_FAIL(supply_consume())) { + LOG_WARN("fail to supply consume", KR(ret)); + } else if (OB_FAIL(inner_get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do inner get next row", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanMerge::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableScanMerge not init", KR(ret), KP(this)); + } else { + const ObDirectLoadExternalRow *external_row = nullptr; + if (OB_FAIL(get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next external row", KR(ret)); + } + } else if (OB_FAIL(external_row->to_datums(datum_row_.storage_datums_, datum_row_.count_))) { + LOG_WARN("fail to transfer datum row", KR(ret)); + } else { + datum_row = &datum_row_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scan_merge.h b/src/storage/direct_load/ob_direct_load_sstable_scan_merge.h new file mode 100644 index 0000000000..a3a879c280 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scan_merge.h @@ -0,0 +1,87 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/container/ob_loser_tree.h" +#include "lib/container/ob_se_array.h" +#include "storage/access/ob_simple_rows_merger.h" +#include "storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" +#include "storage/access/ob_store_row_iterator.h" +#include "storage/direct_load/ob_direct_load_sstable.h" +#include "share/table/ob_table_load_define.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObDatumRange; +class ObStorageDatumUtils; +} // namespace blocksstable +namespace observer +{ +class ObTableLoadErrorRowHandler; +} // namespace observer +namespace storage +{ +class ObDirectLoadExternalRow; +struct ObDirectLoadSSTableScanMergeParam +{ +public: + ObDirectLoadSSTableScanMergeParam(); + ~ObDirectLoadSSTableScanMergeParam(); + bool is_valid() const; + TO_STRING_KV(K_(tablet_id), K_(table_data_desc), KP_(datum_utils), KP_(error_row_handler), KP_(result_info)); +public: + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + table::ObTableLoadResultInfo *result_info_; +}; + +class ObDirectLoadSSTableScanMerge : public ObIStoreRowIterator +{ +public: + static const int64_t MAX_SSTABLE_COUNT = 1024; + typedef ObDirectLoadSSTableScanMergeLoserTreeItem LoserTreeItem; + typedef ObDirectLoadSSTableScanMergeLoserTreeCompare LoserTreeCompare; + typedef ObSimpleRowsMerger ScanSimpleMerger; + typedef common::ObLoserTree + ScanMergeLoserTree; +public: + ObDirectLoadSSTableScanMerge(); + ~ObDirectLoadSSTableScanMerge(); + void reset(); + int init(const ObDirectLoadSSTableScanMergeParam ¶m, + const common::ObIArray &sstable_array, + const blocksstable::ObDatumRange &range); + int get_next_row(const ObDirectLoadExternalRow *&external_row); + int get_next_row(const blocksstable::ObDatumRow *&datum_row) override; +private: + int init_rows_merger(int64_t sstable_count); + int supply_consume(); + int inner_get_next_row(const ObDirectLoadExternalRow *&external_row); +private: + common::ObArenaAllocator allocator_; + common::ObTabletID tablet_id_; + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + observer::ObTableLoadErrorRowHandler *error_row_handler_; + table::ObTableLoadResultInfo *result_info_; + const blocksstable::ObDatumRange *range_; + common::ObSEArray scanners_; + int64_t *consumers_; + int64_t consumer_cnt_; + LoserTreeCompare compare_; + ScanSimpleMerger *simple_merge_; + ScanMergeLoserTree *loser_tree_; + common::ObRowsMerger *rows_merger_; + blocksstable::ObDatumRow datum_row_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.cpp b/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.cpp new file mode 100644 index 0000000000..f72dfcbf05 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h" +#include "storage/direct_load/ob_direct_load_external_row.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadSSTableScanMergeLoserTreeCompare + */ + +ObDirectLoadSSTableScanMergeLoserTreeCompare::ObDirectLoadSSTableScanMergeLoserTreeCompare() + : datum_utils_(nullptr) +{ +} + +ObDirectLoadSSTableScanMergeLoserTreeCompare::~ObDirectLoadSSTableScanMergeLoserTreeCompare() +{ +} + +int ObDirectLoadSSTableScanMergeLoserTreeCompare::init( + const blocksstable::ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(datum_utils)); + } else { + datum_utils_ = datum_utils; + } + return ret; +} + +int ObDirectLoadSSTableScanMergeLoserTreeCompare::cmp( + const ObDirectLoadSSTableScanMergeLoserTreeItem &lhs, + const ObDirectLoadSSTableScanMergeLoserTreeItem &rhs, int64_t &cmp_ret) +{ + int ret = OB_SUCCESS; + int tmp_cmp_ret = 0; + if (OB_UNLIKELY(nullptr == datum_utils_)) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableScanMergeLoserTreeCompare not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == lhs.external_row_ || nullptr == rhs.external_row_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(lhs), K(rhs)); + } else if (OB_UNLIKELY(lhs.external_row_->rowkey_datum_array_.count_ != + rhs.external_row_->rowkey_datum_array_.count_ || + 0 == lhs.external_row_->rowkey_datum_array_.count_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected rowkey datum count", KR(ret), K(lhs), K(rhs)); + } else { + if (OB_FAIL(lhs_rowkey_.assign(lhs.external_row_->rowkey_datum_array_.datums_, + lhs.external_row_->rowkey_datum_array_.count_))) { + LOG_WARN("fail to assign rowkey", KR(ret), K(lhs)); + } else if (OB_FAIL(rhs_rowkey_.assign(rhs.external_row_->rowkey_datum_array_.datums_, + rhs.external_row_->rowkey_datum_array_.count_))) { + LOG_WARN("fail to assign rowkey", KR(ret), K(rhs)); + } else if (OB_FAIL(lhs_rowkey_.compare(rhs_rowkey_, *datum_utils_, tmp_cmp_ret))) { + LOG_WARN("fail to compare rowkey", K(ret), K(lhs_rowkey_), K(rhs_rowkey_), KPC(datum_utils_)); + } else { + cmp_ret = tmp_cmp_ret; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h b/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h new file mode 100644 index 0000000000..e15504c0d4 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scan_merge_loser_tree.h @@ -0,0 +1,56 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "storage/blocksstable/ob_datum_rowkey.h" +#include "storage/direct_load/ob_direct_load_external_row.h" + +namespace oceanbase +{ +namespace blocksstable +{ +class ObStorageDatumUtils; +} // namespace blocksstable +namespace storage +{ + +struct ObDirectLoadSSTableScanMergeLoserTreeItem +{ +public: + ObDirectLoadSSTableScanMergeLoserTreeItem() + : external_row_(nullptr), iter_idx_(0), equal_with_next_(false) + { + } + ~ObDirectLoadSSTableScanMergeLoserTreeItem() = default; + void reset() + { + external_row_ = nullptr; + iter_idx_ = 0; + equal_with_next_ = false; + } + TO_STRING_KV(KPC_(external_row), K_(iter_idx), K_(equal_with_next)); +public: + const ObDirectLoadExternalRow *external_row_; + int64_t iter_idx_; + bool equal_with_next_; // for simple row merger +}; + +class ObDirectLoadSSTableScanMergeLoserTreeCompare +{ +public: + ObDirectLoadSSTableScanMergeLoserTreeCompare(); + ~ObDirectLoadSSTableScanMergeLoserTreeCompare(); + int init(const blocksstable::ObStorageDatumUtils *datum_utils); + int cmp(const ObDirectLoadSSTableScanMergeLoserTreeItem &lhs, + const ObDirectLoadSSTableScanMergeLoserTreeItem &rhs, + int64_t &cmp_ret); +public: + const blocksstable::ObStorageDatumUtils *datum_utils_; + blocksstable::ObDatumRowkey lhs_rowkey_; + blocksstable::ObDatumRowkey rhs_rowkey_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scanner.cpp b/src/storage/direct_load/ob_direct_load_sstable_scanner.cpp new file mode 100644 index 0000000000..b5e385f442 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scanner.cpp @@ -0,0 +1,783 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" +#include "observer/table_load/ob_table_load_stat.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace observer; + +/** + * ObDirectLoadSSTableScanner + */ + +ObDirectLoadSSTableScanner::ObDirectLoadSSTableScanner() + : buf_pos_(0), + buf_size_(0), + sstable_data_block_size_(0), + rowkey_column_num_(0), + column_count_(0), + buf_(nullptr), + large_buf_(nullptr), + io_timeout_ms_(0), + curr_idx_(0), + start_idx_(0), + end_idx_(0), + start_fragment_idx_(0), + end_fragment_idx_(0), + curr_fragment_idx_(0), + locate_start_offset_(0), + locate_end_offset_(0), + found_start_(false), + found_end_(false), + offset_(0), + allocator_("TLD_SSTScanner"), + is_inited_(false) +{ +} + +ObDirectLoadSSTableScanner::~ObDirectLoadSSTableScanner() {} +void ObDirectLoadSSTableScanner::assign(const int64_t buf_cap, char *buf) +{ + buf_size_ = buf_cap; + buf_ = buf; +} + +int ObDirectLoadSSTableScanner::init(ObDirectLoadSSTable *sstable, + const ObDirectLoadTableDataDesc &table_data_desc, + const ObDatumRange &range, + const ObStorageDatumUtils *datum_utils) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadSSTableScanner init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(nullptr == sstable || !sstable->is_valid() || !range.is_valid() || + nullptr == datum_utils)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", K(ret), KPC(sstable), K(range), KP(datum_utils)); + } else { + sstable_data_block_size_ = table_data_desc.sstable_data_block_size_; + sstable_ = sstable; + query_range_ = ⦥ + datum_utils_ = datum_utils; + allocator_.set_tenant_id(MTL_ID()); + const int64_t buf_size = sstable_data_block_size_; + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + assign(buf_size, buf_); + rowkey_column_num_ = sstable->get_meta().rowkey_column_count_; + column_count_ = sstable->get_meta().column_count_; + io_timeout_ms_ = std::max(GCONF._data_storage_io_timeout / 1000, DEFAULT_IO_WAIT_TIME_MS); + } + if (OB_SUCC(ret)) { + if (!sstable_->is_empty()) { + if (OB_FAIL(inner_open())) { + LOG_WARN("fail to inner open", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(datum_row_.init(column_count_))) { + LOG_WARN("fail to init datum row", KR(ret)); + } else { + datum_row_.row_flag_.set_flag(ObDmlFlag::DF_INSERT); + datum_row_.mvcc_row_flag_.set_last_multi_version_row(true); + is_inited_ = true; + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::locate_lower_bound(const ObDatumRowkey &rowkey, int64_t &logic_id) +{ + int ret = OB_SUCCESS; + int64_t length = sstable_->get_meta().index_item_count_; + int64_t left = 0; + int64_t right = length - 1; + int64_t ans = length; + ObDatumRowkey start_key; + int cmp_ret = 0; + while (OB_SUCC(ret) && (left <= right)) { + int64_t mid = left + (right - left) / 2; + if (OB_FAIL(get_start_key(mid, start_key))) { + LOG_WARN("fail to get start key", KR(ret)); + } else if (OB_FAIL(start_key.compare(rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare", KR(ret)); + } + if (OB_SUCC(ret)) { + if (cmp_ret >= 0) { + ans = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + } + if (OB_SUCC(ret)) { + logic_id = ans; + } + return ret; +} + +int ObDirectLoadSSTableScanner::locate_upper_bound(const ObDatumRowkey &rowkey, int64_t &logic_id) +{ + int ret = OB_SUCCESS; + int64_t length = sstable_->get_meta().index_item_count_; + int64_t left = 0; + int64_t right = length - 1; + int64_t ans = length; + ObDatumRowkey start_key; + int cmp_ret = 0; + while (OB_SUCC(ret) && (left <= right)) { + int64_t mid = left + (right - left) / 2; + if (OB_FAIL(get_start_key(mid, start_key))) { + LOG_WARN("fail to get start key", KR(ret)); + } else if (OB_FAIL(start_key.compare(rowkey, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare", KR(ret)); + } + if (OB_SUCC(ret)) { + if (cmp_ret > 0) { + ans = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + } + if (OB_SUCC(ret)) { + logic_id = ans; + } + return ret; +} + +int ObDirectLoadSSTableScanner::get_start_key(int64_t idx, ObDatumRowkey &startkey) +{ + int ret = OB_SUCCESS; + ObDirectLoadIndexInfo info; + const ObDirectLoadExternalRow *item = nullptr; + int64_t locate_fragment_idx = 0; + int64_t new_idx = 0; + data_block_reader_.reset(); + ObDirectLoadSSTableFragment fragment; + if (OB_FAIL(fragment_operator_.get_fragment_item_idx(idx, locate_fragment_idx, new_idx))) { + LOG_WARN("fail to get fragment idx", KR(ret)); + } else if (OB_FAIL(fragment_operator_.get_fragment(locate_fragment_idx, fragment))) { + LOG_WARN("fail to get fragment ", KR(ret)); + } else if (OB_FAIL(index_block_reader_.change_fragment(fragment.index_file_handle_))) { + LOG_WARN("fail to change index file handle ", KR(ret)); + } else if (OB_FAIL(file_io_handle_.open(fragment.data_file_handle_))) { + LOG_WARN("Fail to open file handle", K(ret)); + } else if (OB_FAIL(index_block_reader_.get_index_info(new_idx, info))) { + LOG_WARN("fail to get index info", KR(ret)); + } else if (OB_FAIL(read_buffer(info.offset_, info.size_))) { + LOG_WARN("fail to read buffer", KR(ret)); + } else { + if (info.size_ > sstable_data_block_size_) { + if (OB_FAIL(data_block_reader_.init(info.size_, large_buf_, column_count_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } + } else { + if (OB_FAIL(data_block_reader_.init(info.size_, buf_, column_count_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(data_block_reader_.get_next_item(item))) { + LOG_WARN("fail to read item", KR(ret)); + } + } + } + if (OB_SUCC(ret)) { + ObDatumRowkey key(item->rowkey_datum_array_.datums_, rowkey_column_num_); + if (OB_FAIL(key.deep_copy(startkey, allocator_))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::inner_open() +{ + int ret = OB_SUCCESS; + int64_t data_buf_size = sstable_data_block_size_; + int64_t start_idx = 0; + int64_t end_idx = 0; + const uint64_t tenant_id = MTL_ID(); + int64_t index_size = sstable_->get_meta().index_block_size_; + data_block_reader_.reset(); + if (OB_FAIL(fragment_operator_.init(sstable_))) { + LOG_WARN("Fail to init fragment opeartor", K(ret)); + } else if (OB_FAIL(index_block_reader_.init( + tenant_id, index_size, sstable_->get_fragment_array().at(0).index_file_handle_))) { + LOG_WARN("Fail to init index_block_reader", K(ret)); + } else if (OB_FAIL(locate_lower_bound(query_range_->start_key_, start_idx))) { + LOG_WARN("fail to local lower bound", KR(ret)); + } else if (OB_FAIL(locate_upper_bound(query_range_->end_key_, end_idx))) { + LOG_WARN("fail to local upper bound", KR(ret)); + } else { + if (start_idx == 0) { + start_idx_ = 0; + curr_idx_ = 0; + } else { + start_idx_ = start_idx - 1; + curr_idx_ = start_idx - 1; + } + end_idx_ = end_idx - 1; + // 如果定位的下界为第一块, 属于特殊情况,则直接跳过数据块扫描 + if (end_idx_ < 0) { + end_idx_ = 0; + found_end_ = true; + } + data_block_reader_.reset(); + if (nullptr != large_buf_) { + ob_free(large_buf_); + large_buf_ = nullptr; + } + } + // locate start and end + if (OB_SUCC(ret)) { + int64_t start_fragment_idx = 0; + int64_t new_start_idx = 0; + int64_t end_fragment_idx = 0; + int64_t new_end_idx = 0; + ObDirectLoadSSTableFragment start_fragment; + ObDirectLoadSSTableFragment end_fragment; + if (OB_FAIL(fragment_operator_.get_fragment_item_idx(start_idx_, start_fragment_idx, + new_start_idx))) { + LOG_WARN("fail to get start fragment idx", KR(ret)); + } else if (OB_FAIL(fragment_operator_.get_fragment(start_fragment_idx, start_fragment))) { + LOG_WARN("fail to get start fragment ", KR(ret)); + } else if (OB_FAIL(fragment_operator_.get_fragment_item_idx(end_idx_, end_fragment_idx, + new_end_idx))) { + LOG_WARN("fail to get end fragment idx", KR(ret)); + } else if (OB_FAIL(fragment_operator_.get_fragment(end_fragment_idx, end_fragment))) { + LOG_WARN("fail to get end fragment ", KR(ret)); + } else { + ObDirectLoadIndexInfo start_info; + ObDirectLoadIndexInfo end_info; + if (OB_FAIL(index_block_reader_.change_fragment(start_fragment.index_file_handle_))) { + LOG_WARN("fail to change start fragment", KR(ret)); + } else if (OB_FAIL(index_block_reader_.get_index_info(new_start_idx, start_info))) { + LOG_WARN("fail to get index start info", KR(ret)); + } else if (OB_FAIL(index_block_reader_.change_fragment(end_fragment.index_file_handle_))) { + LOG_WARN("fail to change end fragment", KR(ret)); + } else if (OB_FAIL(index_block_reader_.get_index_info(new_end_idx, end_info))) { + LOG_WARN("fail to get index end info", KR(ret)); + } else if (OB_FAIL(file_io_handle_.open(start_fragment.data_file_handle_))) { + LOG_WARN("Fail to open file handle", K(ret)); + } else { + start_fragment_idx_ = start_fragment_idx; + end_fragment_idx_ = end_fragment_idx; + curr_fragment_idx_ = start_fragment_idx_; + locate_start_offset_ = start_info.offset_; + locate_end_offset_ = end_info.offset_ + end_info.size_; + offset_ = locate_start_offset_; + } + } + } + // read buffer + if (OB_SUCC(ret)) { + if (OB_FAIL(get_next_buffer())) { + LOG_WARN("fail to read buffer", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(data_buf_size, buf_, column_count_))) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else { + int64_t data_block_size = data_block_reader_.get_header()->occupy_size_; + if (OB_FAIL(get_large_buffer(data_block_size))) { + LOG_WARN("fail to get large buffer", KR(ret)); + } + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::locate_next_buffer() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + LOG_WARN("ObDirectLoadSSTableScanner is not init", KR(ret)); + } else { + if (OB_FAIL(change_buffer())) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to switch next buffer", KR(ret)); + } else { + if (nullptr != large_buf_) { + ob_free(large_buf_); + large_buf_ = nullptr; + } + if (OB_FAIL(get_next_buffer())) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to switch next buffer", KR(ret)); + } + } else if (OB_FAIL(data_block_reader_.init(buf_size_, buf_, column_count_))) { + if (OB_UNLIKELY(OB_BUF_NOT_ENOUGH != ret)) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else { + int64_t data_block_size = data_block_reader_.get_header()->occupy_size_; + if (OB_FAIL(get_large_buffer(data_block_size))) { + LOG_WARN("fail to get large buffer", KR(ret)); + } + } + } + } + } + if (OB_SUCC(ret)) { + curr_idx_++; + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::change_buffer() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + LOG_WARN("ObDirectLoadSSTableScanner is not init", KR(ret)); + } else { + int32_t data_block_size = 0; + data_block_size = data_block_reader_.get_header()->occupy_size_; + buf_pos_ += data_block_size; + int64_t buf_size = buf_size_ - buf_pos_; + abort_unless(large_buf_ == nullptr || buf_pos_ == buf_size_); + char *buf = buf_ + buf_pos_; + data_block_reader_.reset(); + if (buf_size == 0) { + ret = OB_BUF_NOT_ENOUGH; + } else { + if (OB_FAIL(data_block_reader_.init(buf_size, buf, column_count_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::read_buffer(uint64_t offset, uint64_t size) +{ + int ret = OB_SUCCESS; + int64_t read_size = size; + if (size <= sstable_data_block_size_) { + if (OB_FAIL(file_io_handle_.pread(buf_, read_size, offset, io_timeout_ms_))) { + LOG_WARN("fail to do pread from data file", KR(ret)); + } + } else { + int64_t read_size = size; + if (large_buf_ == nullptr) { + int64_t large_buf_size = OB_SERVER_BLOCK_MGR.get_macro_block_size(); + if (OB_ISNULL(large_buf_ = static_cast(ob_malloc(large_buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(large_buf_size)); + } + } + if (OB_FAIL(file_io_handle_.pread(large_buf_, read_size, offset, io_timeout_ms_))) { + LOG_WARN("fail to do pread from data file", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::get_large_buffer(int64_t buf_size) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(large_buf_ = static_cast(ob_malloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + int64_t read_size = buf_size; + data_block_reader_.reset(); + if (OB_FAIL(file_io_handle_.pread(large_buf_, read_size, offset_, io_timeout_ms_))) { + LOG_WARN("fail to do pread from data file", KR(ret)); + } else if (OB_FAIL(data_block_reader_.init(buf_size, large_buf_, column_count_))) { + LOG_WARN("fail to init data block reader", KR(ret)); + } else { + buf_pos_ = 0; + buf_size_ = buf_size; + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::get_next_buffer() +{ + int ret = OB_SUCCESS; + offset_ += buf_pos_; + buf_pos_ = 0; + int64_t curr_fragment_end_offset = 0; + if (curr_fragment_idx_ == end_fragment_idx_) { + curr_fragment_end_offset = locate_end_offset_; + if (curr_fragment_end_offset == offset_) { + ret = OB_ITER_END; + } + } else { + ObDirectLoadSSTableFragment fragment; + buf_size_ = sstable_data_block_size_; + curr_fragment_end_offset = + sstable_->get_fragment_array().at(curr_fragment_idx_).meta_.occupy_size_; + if (curr_fragment_end_offset == offset_) { + if (OB_FAIL(fragment_operator_.get_next_fragment(curr_fragment_idx_, fragment))) { + LOG_WARN("fail to get next fragment", KR(ret)); + } else if (OB_FAIL(file_io_handle_.open(fragment.data_file_handle_))) { + LOG_WARN("Fail to open file handle", K(ret)); + } else { + if (curr_fragment_idx_ == end_fragment_idx_) { + curr_fragment_end_offset = locate_end_offset_; + } else { + curr_fragment_end_offset = + sstable_->get_fragment_array().at(curr_fragment_idx_).meta_.occupy_size_; + } + offset_ = 0; + } + } + } + if (OB_SUCC(ret)) { + buf_size_ = sstable_data_block_size_; + int64_t size = MIN(buf_size_, curr_fragment_end_offset - offset_); + if (OB_FAIL(read_buffer(offset_, size))) { + LOG_WARN("fail to read buffer", KR(ret)); + } + buf_size_ = size; + } + return ret; +} + +int ObDirectLoadSSTableScanner::inner_get_next_row(const ObDirectLoadExternalRow *&external_row) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(data_block_reader_.get_next_item(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next item", KR(ret)); + } else { + if (OB_FAIL(locate_next_buffer())) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to locate next buffer", KR(ret)); + } + } else if (OB_FAIL(data_block_reader_.get_next_item(external_row))) { + LOG_WARN("fail to read item", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::compare(ObDatumRowkey cmp_key, + const ObDirectLoadExternalRow &external_row, int &cmp_ret) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(external_row.rowkey_datum_array_.count_ != rowkey_column_num_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected rowkey column num", KR(ret), K(external_row.rowkey_datum_array_.count_), + K(rowkey_column_num_)); + } else { + ObDatumRowkey key(external_row.rowkey_datum_array_.datums_, rowkey_column_num_); + if (OB_FAIL(key.compare(cmp_key, *datum_utils_, cmp_ret))) { + LOG_WARN("fail to compare key", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::get_next_row(const ObDirectLoadExternalRow *&external_row) +{ + int ret = OB_SUCCESS; + external_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableScanner not init", KR(ret), KP(this)); + } else { + int cmp_ret = 0; + external_row = nullptr; + if (curr_idx_ > end_idx_ || found_end_ || sstable_->is_empty()) { + ret = OB_ITER_END; + } + while (OB_SUCC(ret) && nullptr == external_row) { + if (OB_FAIL(inner_get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to inner get next row", KR(ret)); + } + } + if (OB_SUCC(ret) && !found_start_) { + if (OB_FAIL(compare(query_range_->start_key_, *external_row, cmp_ret))) { + LOG_WARN("fail to compare start key", KR(ret)); + } else if (cmp_ret < 0 || (!query_range_->border_flag_.inclusive_start() && cmp_ret == 0)) { + external_row = nullptr; + } else { + found_start_ = true; + } + } + if (OB_SUCC(ret) && nullptr != external_row && curr_idx_ == end_idx_) { + if (OB_FAIL(compare(query_range_->end_key_, *external_row, cmp_ret))) { + LOG_WARN("fail to compare start key", KR(ret)); + } else if (cmp_ret > 0 || (!query_range_->border_flag_.inclusive_end() && cmp_ret == 0)) { + external_row = nullptr; + found_end_ = true; + ret = OB_ITER_END; + } + } + } + } + return ret; +} + +int ObDirectLoadSSTableScanner::get_next_row(const ObDatumRow *&datum_row) +{ + int ret = OB_SUCCESS; + datum_row = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadSSTableScanner not init", KR(ret), KP(this)); + } else { + const ObDirectLoadExternalRow *external_row = nullptr; + if (OB_FAIL(get_next_row(external_row))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next row", KR(ret)); + } + } else if (OB_FAIL(external_row->to_datums(datum_row_.storage_datums_, datum_row_.count_))) { + LOG_WARN("fail to transfer datum row", KR(ret)); + } else { + datum_row = &datum_row_; + } + } + return ret; +} +/** + * ObDirectLoadIndexBlockMetaIterator + */ +ObDirectLoadIndexBlockMetaIterator::ObDirectLoadIndexBlockMetaIterator() + : buf_pos_(0), + buf_size_(0), + io_timeout_ms_(0), + buf_(nullptr), + curr_fragment_idx_(0), + curr_block_idx_(0), + rowkey_column_count_(0), + total_index_block_count_(0), + index_item_num_per_block_(0), + allocator_("TLD_IDBMeta"), + is_inited_(false) +{ +} + +ObDirectLoadIndexBlockMetaIterator::~ObDirectLoadIndexBlockMetaIterator() {} + +void ObDirectLoadIndexBlockMetaIterator::assign(const int64_t buf_pos, const int64_t buf_cap, + char *buf) +{ + buf_pos_ = buf_pos; + buf_size_ = buf_cap; + buf_ = buf; +} + +int ObDirectLoadIndexBlockMetaIterator::init(ObDirectLoadSSTable *sstable) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("The ObDirectLoadIndexBlockMetaIterator has been inited", K(ret)); + } else if (OB_ISNULL(sstable) || !sstable->is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("Invalid argument", K(ret), KPC(sstable)); + } else { + sstable_ = sstable; + const uint64_t tenant_id = MTL_ID(); + int64_t index_size = sstable_->get_meta().index_block_size_; + if (!sstable_->is_empty()) { + if (OB_FAIL(fragment_operator_.init(sstable_))) { + LOG_WARN("Failed to init fragment operator", K(ret)); + } else if (OB_FAIL(index_block_reader_.init( + tenant_id, index_size, + sstable_->get_fragment_array().at(0).index_file_handle_))) { + LOG_WARN("Fail to init index_block_reader", K(ret)); + } else if (OB_FAIL( + file_io_handle_.open(sstable_->get_fragment_array().at(0).data_file_handle_))) { + LOG_WARN("Fail to assign file handle", K(ret)); + } + } + if (OB_SUCC(ret)) { + int64_t buf_size = OB_SERVER_BLOCK_MGR.get_macro_block_size(); + allocator_.set_tenant_id(tenant_id); + if (OB_ISNULL(buf_ = static_cast(allocator_.alloc(buf_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", KR(ret), K(buf_size)); + } else { + rowkey_column_count_ = sstable_->get_meta().rowkey_column_count_; + index_item_num_per_block_ = ObDirectLoadIndexBlock::get_item_num_per_block( + sstable_->get_meta().index_block_size_); + total_index_block_count_ = sstable->get_meta().index_block_count_; + assign(0, buf_size, buf_); + io_timeout_ms_ = std::max(GCONF._data_storage_io_timeout / 1000, DEFAULT_IO_WAIT_TIME_MS); + is_inited_ = true; + } + } + } + return ret; +} + +int ObDirectLoadIndexBlockMetaIterator::get_end_key(ObDirectLoadExternalRow &row, + ObDirectLoadIndexBlockMeta &index_block_meta) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("meta iterator not inited", K(ret)); + } else { + int64_t count = sstable_->get_meta().rowkey_column_count_; + ObDatumRowkey key(row.rowkey_datum_array_.datums_, count); + if (OB_FAIL(key.deep_copy(index_block_meta.end_key_, allocator_))) { + LOG_WARN("fail to deep copy", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadIndexBlockMetaIterator::get_next(ObDirectLoadIndexBlockMeta &index_block_meta) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("meta iterator not inited", K(ret)); + } else { + if (curr_block_idx_ >= total_index_block_count_ || sstable_->is_empty()) { + ret = OB_ITER_END; + } + int64_t row_count = 0; + int64_t locate_fragment_idx = 0; + int64_t new_idx = 0; + ObDirectLoadSSTableFragment fragment; + if (OB_SUCC(ret) && curr_block_idx_ < total_index_block_count_) { + if (OB_FAIL(fragment_operator_.get_fragment_block_idx(curr_block_idx_, locate_fragment_idx, + new_idx))) { + LOG_WARN("fail to get start fragment idx", KR(ret)); + } else if (OB_FAIL(fragment_operator_.get_fragment(locate_fragment_idx, fragment))) { + LOG_WARN("fail to get start fragment ", KR(ret)); + } else { + curr_fragment_idx_ = locate_fragment_idx; + if (OB_FAIL(index_block_reader_.change_fragment(fragment.index_file_handle_))) { + LOG_WARN("fail to change start fragment", KR(ret)); + } else if (OB_FAIL(file_io_handle_.open(fragment.data_file_handle_))) { + LOG_WARN("Fail to open file handle", K(ret)); + } else if (OB_FAIL(get_row(new_idx, index_block_meta))) { + LOG_WARN("Fail to get secondary meta row from block", K(ret)); + } else if (OB_FAIL(get_end_key(row_, index_block_meta))) { + LOG_WARN("Fail to parse macro meta", K(ret)); + } else { + curr_block_idx_++; + } + } + } + } + return ret; +} + +int ObDirectLoadIndexBlockMetaIterator::get_row(int64_t idx, ObDirectLoadIndexBlockMeta &meta) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("meta iterator not inited", K(ret)); + } else { + int64_t count = 0; + int64_t index_item_idx = (idx + 1) * index_item_num_per_block_ - 1; + index_item_idx = + MIN(index_item_idx, + sstable_->get_fragment_array().at(curr_fragment_idx_).meta_.index_item_count_ - 1); + ObDirectLoadIndexInfo info; + ObDirectLoadDataBlockHeader header; + if (OB_FAIL(index_block_reader_.get_index_info(index_item_idx, info))) { + LOG_WARN("fail to get index info", KR(ret)); + } else if (OB_FAIL(read_buffer(info.offset_, info.size_))) { + LOG_WARN("fail to read buffer", KR(ret)); + } else if (OB_FAIL(header.deserialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to deserialize header", KR(ret), K(buf_size_), K(buf_pos_)); + } else { + meta.row_count_ = index_block_reader_.get_header()->row_count_; + meta.rowkey_column_count_ = rowkey_column_count_; + buf_pos_ = header.last_row_offset_; + if (OB_FAIL(row_.deserialize(buf_, buf_size_, buf_pos_))) { + LOG_WARN("fail to deserialize buffer", KR(ret), K(buf_size_), K(buf_pos_)); + } + } + } + return ret; +} + +int ObDirectLoadIndexBlockMetaIterator::read_buffer(uint64_t offset, uint64_t size) +{ + int ret = OB_SUCCESS; + int64_t read_size = size; + if (OB_FAIL(file_io_handle_.pread(buf_, read_size, offset, io_timeout_ms_))) { + LOG_WARN("fail to do pread from data file", KR(ret)); + } else { + buf_pos_ = 0; + buf_size_ = size; + } + return ret; +} + +/** + * ObDirectLoadIndexBlockEndKeyIterator + */ + +ObDirectLoadIndexBlockEndKeyIterator::~ObDirectLoadIndexBlockEndKeyIterator() +{ + if (nullptr != index_block_meta_iter_) { + index_block_meta_iter_->~ObDirectLoadIndexBlockMetaIterator(); + index_block_meta_iter_ = nullptr; + } +} + +int ObDirectLoadIndexBlockEndKeyIterator::init( + ObDirectLoadIndexBlockMetaIterator *index_block_meta_iter) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadIndexBlockEndKeyIterator init twice", KR(ret), KP(this)); + } else if (OB_ISNULL(index_block_meta_iter)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(index_block_meta_iter)); + } else { + index_block_meta_iter_ = index_block_meta_iter; + is_inited_ = true; + } + return ret; +} + +int ObDirectLoadIndexBlockEndKeyIterator::get_next_rowkey(const ObDatumRowkey *&rowkey) +{ + int ret = OB_SUCCESS; + rowkey = nullptr; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadIndexBlockEndKeyIterator not init", KR(ret), KP(this)); + } else { + ObDirectLoadIndexBlockMeta index_block_meta; + if (OB_FAIL(index_block_meta_iter_->get_next(index_block_meta))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to get next macro block meta", KR(ret)); + } + } else if (OB_FAIL(rowkey_.assign(index_block_meta.end_key_.datums_, + index_block_meta.rowkey_column_count_))) { + LOG_WARN("fail to get datum rowkey", KR(ret)); + } else { + rowkey = &rowkey_; + } + } + return ret; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_sstable_scanner.h b/src/storage/direct_load/ob_direct_load_sstable_scanner.h new file mode 100644 index 0000000000..b6fdf7bc64 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_sstable_scanner.h @@ -0,0 +1,136 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// yiren.ly + +#pragma once + +#include "ob_direct_load_tmp_file.h" +#include "storage/access/ob_store_row_iterator.h" +#include "storage/direct_load/ob_direct_load_external_row.h" +#include "storage/direct_load/ob_direct_load_rowkey_iterator.h" +#include "storage/direct_load/ob_direct_load_sstable_builder.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +struct ObDirectLoadIndexBlockMeta +{ +public: + ObDirectLoadIndexBlockMeta() : row_count_(0) {} + TO_STRING_KV(K_(row_count), K(rowkey_column_count_), K(end_key_)); +public: + int64_t row_count_; + int64_t rowkey_column_count_; + blocksstable::ObDatumRowkey end_key_; +}; + +class ObDirectLoadSSTableScanner +{ +public: + ObDirectLoadSSTableScanner(); + virtual ~ObDirectLoadSSTableScanner(); + int init(ObDirectLoadSSTable *sstable, const ObDirectLoadTableDataDesc &table_data_desc, + const blocksstable::ObDatumRange &range, + const blocksstable::ObStorageDatumUtils *datum_utils); + int get_next_row(const blocksstable::ObDatumRow *&datum_row); + int get_next_row(const ObDirectLoadExternalRow *&external_row); + TO_STRING_KV(KP(buf_), K(buf_pos_), K(buf_size_), K(curr_idx_), K(start_idx_), K(end_idx_), + K(offset_)); +private: + int get_start_key(int64_t idx, blocksstable::ObDatumRowkey &startkey); + int inner_open(); + int locate_next_buffer(); + int change_buffer(); + int compare(blocksstable::ObDatumRowkey cmp_key, const ObDirectLoadExternalRow &external_row, + int &cmp_ret); + int inner_get_next_row(const ObDirectLoadExternalRow *&external_row); + int read_buffer(uint64_t offset, uint64_t size); + int get_next_buffer(); + int get_large_buffer(int64_t buf_size); + void assign(const int64_t buf_cap, char *buf); + int locate_lower_bound(const blocksstable::ObDatumRowkey &rowkey, int64_t &logic_id); + int locate_upper_bound(const blocksstable::ObDatumRowkey &rowkey, int64_t &logic_id); +private: + int64_t buf_pos_; + int64_t buf_size_; + int64_t sstable_data_block_size_; + int64_t rowkey_column_num_; + int64_t column_count_; + char *buf_; + char *large_buf_; + int64_t io_timeout_ms_; + int64_t curr_idx_; + int64_t start_idx_; + int64_t end_idx_; + int64_t start_fragment_idx_; + int64_t end_fragment_idx_; + int64_t curr_fragment_idx_; + uint64_t locate_start_offset_; + uint64_t locate_end_offset_; + bool found_start_; + bool found_end_; + uint64_t offset_; + blocksstable::ObDatumRow datum_row_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + ObDirectLoadSSTable *sstable_; + const blocksstable::ObDatumRange *query_range_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + common::ObArenaAllocator allocator_; + ObDirectLoadDataBlockReader2 data_block_reader_; + ObDirectLoadIndexBlockReader index_block_reader_; + ObDirectLoadSSTableFragmentOperator fragment_operator_; + bool is_inited_; +}; + +class ObDirectLoadIndexBlockMetaIterator +{ +public: + ObDirectLoadIndexBlockMetaIterator(); + ~ObDirectLoadIndexBlockMetaIterator(); +public: + int init(ObDirectLoadSSTable *sstable); + int get_next(ObDirectLoadIndexBlockMeta &index_meta); +private: + int64_t get_total_block_count() const { return total_index_block_count_; } + void assign(const int64_t buf_pos, const int64_t buf_cap, char *buf); + int get_end_key(ObDirectLoadExternalRow &row, ObDirectLoadIndexBlockMeta &index_block_meta); + int get_row(int64_t idx, ObDirectLoadIndexBlockMeta &meta); + int read_buffer(uint64_t offset, uint64_t size); + TO_STRING_KV(KP(buf_), K(buf_pos_), K(buf_size_), K(curr_fragment_idx_), K(curr_block_idx_), + K(total_index_block_count_), K(index_item_num_per_block_)); +private: + int64_t buf_pos_; + int64_t buf_size_; + int64_t io_timeout_ms_; + char *buf_; + ObDirectLoadExternalRow row_; + int64_t curr_fragment_idx_; + int64_t curr_block_idx_; + int64_t rowkey_column_count_; + int64_t total_index_block_count_; + int64_t index_item_num_per_block_; + ObDirectLoadTmpFileIOHandle file_io_handle_; + ObDirectLoadSSTable *sstable_; + common::ObArenaAllocator allocator_; + ObDirectLoadIndexBlockReader index_block_reader_; + ObDirectLoadSSTableFragmentOperator fragment_operator_; + bool is_inited_; +}; + +class ObDirectLoadIndexBlockEndKeyIterator : public ObIDirectLoadDatumRowkeyIterator +{ +public: + ObDirectLoadIndexBlockEndKeyIterator() : index_block_meta_iter_(nullptr), is_inited_(false) {} + virtual ~ObDirectLoadIndexBlockEndKeyIterator(); + int init(ObDirectLoadIndexBlockMetaIterator *index_block_meta_iter); + int get_next_rowkey(const blocksstable::ObDatumRowkey *&rowkey) override; +private: + ObDirectLoadIndexBlockMetaIterator *index_block_meta_iter_; + blocksstable::ObDatumRowkey rowkey_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase \ No newline at end of file diff --git a/src/storage/direct_load/ob_direct_load_table_builder_allocator.h b/src/storage/direct_load/ob_direct_load_table_builder_allocator.h new file mode 100644 index 0000000000..6b84f7cc95 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_table_builder_allocator.h @@ -0,0 +1,98 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/list/ob_dlist.h" +#include "share/rc/ob_tenant_base.h" +#include "storage/direct_load/ob_direct_load_i_table.h" + +namespace oceanbase +{ +namespace storage +{ + +class ObDirectLoadTableBuilderAllocator +{ +public: + ObDirectLoadTableBuilderAllocator(); + ~ObDirectLoadTableBuilderAllocator(); + template + T *alloc(Args &&... args); + void free(ObIDirectLoadPartitionTableBuilder *table_builder); + void assert_in_own_thread(); + +private: + struct Item : public common::ObDLinkBase + { + char buf_[]; + }; + +private: + int64_t tid_; + ObDList using_list_; +}; + +ObDirectLoadTableBuilderAllocator::ObDirectLoadTableBuilderAllocator() +{ + tid_ = get_tid_cache(); +} + +ObDirectLoadTableBuilderAllocator::~ObDirectLoadTableBuilderAllocator() +{ + assert_in_own_thread(); + Item *item = nullptr; + DLIST_REMOVE_ALL_NORET(item, using_list_) + { + ObIDirectLoadPartitionTableBuilder *table_builder = + (ObIDirectLoadPartitionTableBuilder *)item->buf_; + table_builder->~ObIDirectLoadPartitionTableBuilder(); + ob_free(item); + } + OB_ASSERT(using_list_.is_empty()); +} + +template +T *ObDirectLoadTableBuilderAllocator::alloc(Args &&... args) +{ + assert_in_own_thread(); + T *t = nullptr; + void *buf = nullptr; + ObMemAttr attr; + attr.label_ = "TLD_TB_Alloc"; + attr.tenant_id_ = MTL_ID(); + if (OB_NOT_NULL(buf = ob_malloc(sizeof(Item) + sizeof(T), attr))) { + Item *item = new (buf) Item; + t = new (item->buf_) T(args...); + using_list_.add_last(item); + } + return t; +} + +void ObDirectLoadTableBuilderAllocator::free(ObIDirectLoadPartitionTableBuilder *table_builder) +{ + assert_in_own_thread(); + if (OB_NOT_NULL(table_builder)) { + table_builder->~ObIDirectLoadPartitionTableBuilder(); + Item *item = (Item *)table_builder - 1; + using_list_.remove(item); + item->~Item(); + ob_free(item); + } +} + +void ObDirectLoadTableBuilderAllocator::assert_in_own_thread() +{ + const int64_t tid = get_tid_cache(); + OB_ASSERT(tid == tid_); +} + +OB_INLINE ObDirectLoadTableBuilderAllocator *get_table_builder_allocator() +{ + RLOCAL_INLINE(ObDirectLoadTableBuilderAllocator, allcator); + return &allcator; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_table_data_desc.cpp b/src/storage/direct_load/ob_direct_load_table_data_desc.cpp new file mode 100644 index 0000000000..939df1cd12 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_table_data_desc.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; + +ObDirectLoadTableDataDesc::ObDirectLoadTableDataDesc() + : rowkey_column_num_(0), + column_count_(0), + external_data_block_size_(0), + sstable_index_block_size_(0), + sstable_data_block_size_(0), + extra_buf_size_(0), + compressor_type_(ObCompressorType::INVALID_COMPRESSOR), + is_heap_table_(false), + mem_chunk_size_(0), + max_mem_chunk_count_(0), + merge_count_per_round_(0), + heap_table_mem_chunk_size_(0) +{ +} + +ObDirectLoadTableDataDesc::~ObDirectLoadTableDataDesc() +{ +} + +void ObDirectLoadTableDataDesc::reset() +{ + rowkey_column_num_ = 0; + column_count_ = 0; + external_data_block_size_ = 0; + sstable_index_block_size_ = 0; + sstable_data_block_size_ = 0; + extra_buf_size_ = 0; + compressor_type_ = ObCompressorType::INVALID_COMPRESSOR; + is_heap_table_ = false; + mem_chunk_size_ = 0; + max_mem_chunk_count_ = 0; + merge_count_per_round_ = 0; + heap_table_mem_chunk_size_ = 0; +} + +bool ObDirectLoadTableDataDesc::is_valid() const +{ + return (is_heap_table_ || rowkey_column_num_ > 0) && + rowkey_column_num_ <= column_count_ && column_count_ > 0 && + external_data_block_size_ > 0 && external_data_block_size_ % DIO_ALIGN_SIZE == 0 && + sstable_index_block_size_ > 0 && sstable_index_block_size_ % DIO_ALIGN_SIZE == 0 && + sstable_data_block_size_ > 0 && sstable_data_block_size_ % DIO_ALIGN_SIZE == 0 && + extra_buf_size_ > 0 && extra_buf_size_ % DIO_ALIGN_SIZE == 0 && + compressor_type_ > ObCompressorType::INVALID_COMPRESSOR && mem_chunk_size_ > 0 && + max_mem_chunk_count_ > 0 && merge_count_per_round_ > 0 && heap_table_mem_chunk_size_ > 0; +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_table_data_desc.h b/src/storage/direct_load/ob_direct_load_table_data_desc.h new file mode 100644 index 0000000000..35089f25c6 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_table_data_desc.h @@ -0,0 +1,46 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "lib/compress/ob_compressor.h" +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace storage +{ + +struct ObDirectLoadTableDataDesc +{ + static const int64_t DEFAULT_EXTRA_BUF_SIZE = (2LL << 20); // 2M +public: + ObDirectLoadTableDataDesc(); + ~ObDirectLoadTableDataDesc(); + void reset(); + bool is_valid() const; + TO_STRING_KV(K_(rowkey_column_num), K_(column_count), K_(external_data_block_size), + K_(sstable_index_block_size), K_(sstable_data_block_size), K_(extra_buf_size), + K_(compressor_type), K_(is_heap_table), K_(mem_chunk_size), K_(max_mem_chunk_count), + K_(merge_count_per_round), K_(heap_table_mem_chunk_size)); +public: + int64_t rowkey_column_num_; + int64_t column_count_; + int64_t external_data_block_size_; + int64_t sstable_index_block_size_; + int64_t sstable_data_block_size_; + int64_t extra_buf_size_; + common::ObCompressorType compressor_type_; + bool is_heap_table_; + // sort param + int64_t mem_chunk_size_; + int64_t max_mem_chunk_count_; + int64_t merge_count_per_round_; + + //heap sort param + int64_t heap_table_mem_chunk_size_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_table_store.cpp b/src/storage/direct_load/ob_direct_load_table_store.cpp new file mode 100644 index 0000000000..6668ddc570 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_table_store.cpp @@ -0,0 +1,361 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_table_store.h" +#include "observer/table_load/ob_table_load_stat.h" +#include "storage/direct_load/ob_direct_load_external_multi_partition_table.h" +#include "storage/direct_load/ob_direct_load_fast_heap_table_builder.h" +#include "storage/direct_load/ob_direct_load_sstable_builder.h" +#include "storage/direct_load/ob_direct_load_table_builder_allocator.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; +using namespace share; +using namespace table; + +/** + * ObDirectLoadTableStoreParam + */ + +ObDirectLoadTableStoreParam::ObDirectLoadTableStoreParam() + : datum_utils_(nullptr), + file_mgr_(nullptr), + is_multiple_mode_(false), + is_fast_heap_table_(false), + insert_table_ctx_(nullptr), + fast_heap_table_ctx_(nullptr), + extra_buf_(nullptr), + extra_buf_size_(0), + result_info_(nullptr) +{ +} + +ObDirectLoadTableStoreParam::~ObDirectLoadTableStoreParam() +{ +} + +bool ObDirectLoadTableStoreParam::is_valid() const +{ + return table_data_desc_.is_valid() && nullptr != datum_utils_ && nullptr != file_mgr_ && + (!is_fast_heap_table_ || + (nullptr != insert_table_ctx_ && nullptr != fast_heap_table_ctx_)) && + nullptr != result_info_; +} + +/** + * ObDirectLoadTableStoreBucket + */ + +ObDirectLoadTableStoreBucket::ObDirectLoadTableStoreBucket() + : param_(nullptr), table_builder_allocator_(nullptr), table_builder_(nullptr), is_inited_(false) +{ +} + +ObDirectLoadTableStoreBucket::~ObDirectLoadTableStoreBucket() +{ +} + +int ObDirectLoadTableStoreBucket::init(const ObDirectLoadTableStoreParam ¶m, + const ObTabletID &tablet_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadTableStore init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid() || !tablet_id.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param), K(tablet_id)); + } else { + table_builder_allocator_ = get_table_builder_allocator(); + if (param.is_multiple_mode_) { + // new external multi partition table + ObDirectLoadExternalMultiPartitionTableBuildParam external_mp_table_build_param; + external_mp_table_build_param.table_data_desc_ = param.table_data_desc_; + external_mp_table_build_param.datum_utils_ = param.datum_utils_; + external_mp_table_build_param.file_mgr_ = param.file_mgr_; + external_mp_table_build_param.extra_buf_ = param.extra_buf_; + external_mp_table_build_param.extra_buf_size_ = param.extra_buf_size_; + ObDirectLoadExternalMultiPartitionTableBuilder *external_mp_table_builder = nullptr; + if (OB_ISNULL( + external_mp_table_builder = + table_builder_allocator_->alloc())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc ObDirectLoadExternalMultiPartitionTableBuilder", KR(ret)); + } else if (OB_FAIL(external_mp_table_builder->init(external_mp_table_build_param))) { + LOG_WARN("fail to init external multi partition table builder", KR(ret)); + } + table_builder_ = external_mp_table_builder; + } else if (param.is_fast_heap_table_) { + abort_unless(param.table_data_desc_.is_heap_table_); + // new fast heap table + ObDirectLoadFastHeapTableBuildParam fast_heap_table_build_param; + fast_heap_table_build_param.tablet_id_ = tablet_id; + fast_heap_table_build_param.table_data_desc_ = param.table_data_desc_; + fast_heap_table_build_param.col_descs_ = param.col_descs_; + fast_heap_table_build_param.insert_table_ctx_ = param.insert_table_ctx_; + fast_heap_table_build_param.fast_heap_table_ctx_ = param.fast_heap_table_ctx_; + fast_heap_table_build_param.result_info_ = param.result_info_; + fast_heap_table_build_param.online_opt_stat_gather_ = param.online_opt_stat_gather_; + ObDirectLoadFastHeapTableBuilder *fast_heap_table_builder = nullptr; + if (OB_ISNULL(fast_heap_table_builder = + table_builder_allocator_->alloc())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc ObDirectLoadFastHeapTableBuilder", KR(ret)); + } else if (OB_FAIL(fast_heap_table_builder->init(fast_heap_table_build_param))) { + LOG_WARN("fail to init sstable builder", KR(ret)); + } + table_builder_ = fast_heap_table_builder; + } else { + abort_unless(!param.table_data_desc_.is_heap_table_); + // new sstable + ObDirectLoadSSTableBuildParam sstable_build_param; + sstable_build_param.tablet_id_ = tablet_id; + sstable_build_param.table_data_desc_ = param.table_data_desc_; + sstable_build_param.datum_utils_ = param.datum_utils_; + sstable_build_param.file_mgr_ = param.file_mgr_; + ObDirectLoadSSTableBuilder *sstable_builder = nullptr; + if (OB_ISNULL(sstable_builder = + table_builder_allocator_->alloc())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc ObDirectLoadSSTableBuilder", KR(ret)); + } else if (OB_FAIL(sstable_builder->init(sstable_build_param))) { + LOG_WARN("fail to init sstable builder", KR(ret)); + } + table_builder_ = sstable_builder; + } + if (OB_SUCC(ret)) { + param_ = ¶m; + is_inited_ = true; + } else { + clean_up(); + } + } + return ret; +} + +int ObDirectLoadTableStoreBucket::append_row(const ObTabletID &tablet_id, + const ObDatumRow &datum_row) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_store_bucket_append_row); + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || !datum_row.is_valid() || + datum_row.get_column_count() != param_->table_data_desc_.column_count_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), K(datum_row), KPC(param_)); + } else { + if (OB_FAIL(table_builder_->append_row(tablet_id, datum_row))) { + LOG_WARN("fail to append row", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadTableStoreBucket::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(table_builder_->close())) { + LOG_WARN("fail to close table builder", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadTableStoreBucket::get_tables(ObIArray &table_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else { + if (OB_FAIL(table_builder_->get_tables(table_array, allocator))) { + LOG_WARN("fail to get tables", KR(ret)); + } + } + return ret; +} + +void ObDirectLoadTableStoreBucket::clean_up() +{ + if (nullptr != table_builder_) { + table_builder_allocator_->free(table_builder_); + table_builder_allocator_ = nullptr; + table_builder_ = nullptr; + } +} + +/** + * ObDirectLoadTableStore + */ + +ObDirectLoadTableStore::~ObDirectLoadTableStore() +{ + for (int64_t i = 0; i < bucket_ptr_array_.count(); i++) { + if (bucket_ptr_array_.at(i) != nullptr) { + bucket_ptr_array_.at(i)->~ObDirectLoadTableStoreBucket(); + } + } +} + +int ObDirectLoadTableStore::init(const ObDirectLoadTableStoreParam ¶m) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadTableStore init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!param.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(param)); + } else { + const uint64_t tenant_id = MTL_ID(); + param_ = param; + allocator_.set_tenant_id(tenant_id); + if (OB_FAIL(tablet_index_.create(64, "TLD_TS_PartMap", "TLD_TS_PartMap", tenant_id))) { + LOG_WARN("fail to create hashmap", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadTableStore::new_bucket(ObDirectLoadTableStoreBucket *&bucket) +{ + int ret = OB_SUCCESS; + bucket = nullptr; + if (OB_ISNULL(bucket = OB_NEWx(ObDirectLoadTableStoreBucket, (&allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to new ObDirectLoadTableStoreBucket", K(ret)); + } else if (OB_FAIL(bucket_ptr_array_.push_back(bucket))) { + LOG_WARN("fail to push back bucket", KR(ret)); + } + return ret; +} + +int ObDirectLoadTableStore::get_bucket(const ObTabletID &tablet_id, + ObDirectLoadTableStoreBucket *&bucket) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_store_get_bucket); + int ret = OB_SUCCESS; + bucket = nullptr; + if (!param_.is_multiple_mode_) { + if (OB_FAIL(tablet_index_.get_refactored(tablet_id, bucket))) { + if (OB_UNLIKELY(OB_HASH_NOT_EXIST != ret)) { + LOG_WARN("fail to get refactored", KR(ret), K(tablet_id)); + } else { + ret = OB_SUCCESS; + if (OB_FAIL(new_bucket(bucket))) { + LOG_WARN("fail to new bucket", KR(ret)); + } else if (OB_FAIL(bucket->init(param_, tablet_id))) { + LOG_WARN("fail to init bucket", KR(ret)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tablet_index_.set_refactored(tablet_id, bucket))) { + LOG_WARN("fail to set refactored", KR(ret), K(tablet_id)); + } + } + } + } + } else { + if (bucket_ptr_array_.count() >= 1) { + bucket = bucket_ptr_array_.at(0); + } else { + if (OB_FAIL(new_bucket(bucket))) { + LOG_WARN("fail to new bucket", KR(ret)); + } else if (OB_FAIL(bucket->init(param_, tablet_id))) { + LOG_WARN("fail to init bucket", KR(ret)); + } + } + } + return ret; +} + +int ObDirectLoadTableStore::append_row(const ObTabletID &tablet_id, const ObDatumRow &datum_row) +{ + OB_TABLE_LOAD_STATISTICS_TIME_COST(table_store_append_row); + OB_TABLE_LOAD_STATISTICS_COUNTER(table_store_row_count); + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(!tablet_id.is_valid() || !datum_row.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tablet_id), K(datum_row)); + } else { + ObDirectLoadTableStoreBucket *bucket = nullptr; + if (OB_FAIL(get_bucket(tablet_id, bucket))) { + LOG_WARN("fail to get bucket", KR(ret), K(tablet_id)); + } else if (OB_FAIL(bucket->append_row(tablet_id, datum_row))) { + LOG_WARN("fail to append row to bucket", KR(ret), K(tablet_id), K(datum_row)); + } + } + return ret; +} + +int ObDirectLoadTableStore::close() +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else { + for (int64_t i = 0; OB_SUCC(ret) && i < bucket_ptr_array_.count(); ++i) { + if (OB_FAIL(bucket_ptr_array_.at(i)->close())) { + LOG_WARN("fail to close bucket", KR(ret), K(i)); + } + } + } + return ret; +} + +int ObDirectLoadTableStore::get_tables(ObIArray &table_array, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTableStore not init", KR(ret), KP(this)); + } else { + table_array.reset(); + ObSEArray bucket_table_array; + for (int64_t i = 0; OB_SUCC(ret) && i < bucket_ptr_array_.count(); ++i) { + bucket_table_array.reset(); + if (OB_FAIL(bucket_ptr_array_.at(i)->get_tables(bucket_table_array, allocator))) { + LOG_WARN("fail to get tables from bucket", KR(ret), K(i)); + } else if (OB_UNLIKELY(bucket_table_array.empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected empty bucket table array", KR(ret)); + } + for (int64_t j = 0; OB_SUCC(ret) && j < bucket_table_array.count(); ++j) { + if (OB_FAIL(table_array.push_back(bucket_table_array.at(j)))) { + LOG_WARN("fail to push back table", KR(ret)); + } + } + } + } + return ret; +} + +void ObDirectLoadTableStore::clean_up() +{ + for (int64_t i = 0; i < bucket_ptr_array_.count(); ++i) { + bucket_ptr_array_.at(i)->clean_up(); + } +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_table_store.h b/src/storage/direct_load/ob_direct_load_table_store.h new file mode 100644 index 0000000000..93e173b657 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_table_store.h @@ -0,0 +1,90 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "share/table/ob_table_load_array.h" +#include "share/table/ob_table_load_define.h" +#include "storage/blocksstable/ob_datum_row.h" +#include "storage/direct_load/ob_direct_load_i_table.h" +#include "storage/direct_load/ob_direct_load_table_data_desc.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTableDataDesc; +class ObDirectLoadTmpFileManager; +class ObDirectLoadTableBuilderAllocator; +class ObDirectLoadInsertTableContext; +class ObDirectLoadFastHeapTableContext; + +struct ObDirectLoadTableStoreParam +{ +public: + ObDirectLoadTableStoreParam(); + ~ObDirectLoadTableStoreParam(); + bool is_valid() const; + TO_STRING_KV(K_(table_data_desc), KP_(datum_utils), KP_(col_descs), KP_(file_mgr), K_(is_multiple_mode), + K_(is_fast_heap_table), KP_(insert_table_ctx), KP_(fast_heap_table_ctx), + KP_(extra_buf), K_(extra_buf_size), KP_(result_info)); +public: + ObDirectLoadTableDataDesc table_data_desc_; + const blocksstable::ObStorageDatumUtils *datum_utils_; + const common::ObIArray *col_descs_; + ObDirectLoadTmpFileManager *file_mgr_; + bool is_multiple_mode_; + bool is_fast_heap_table_; + bool online_opt_stat_gather_; + ObDirectLoadInsertTableContext *insert_table_ctx_; + ObDirectLoadFastHeapTableContext *fast_heap_table_ctx_; + char *extra_buf_; + int64_t extra_buf_size_; + table::ObTableLoadResultInfo *result_info_; +}; + +class ObDirectLoadTableStoreBucket +{ +public: + ObDirectLoadTableStoreBucket(); + ~ObDirectLoadTableStoreBucket(); + int init(const ObDirectLoadTableStoreParam ¶m, const common::ObTabletID &tablet_id); + int append_row(const common::ObTabletID &tablet_id, const blocksstable::ObDatumRow &datum_row); + int close(); + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator); + void clean_up(); + TO_STRING_KV(KP(param_)); +private: + const ObDirectLoadTableStoreParam *param_; + ObDirectLoadTableBuilderAllocator *table_builder_allocator_; + ObIDirectLoadPartitionTableBuilder *table_builder_; + bool is_inited_; +}; + +class ObDirectLoadTableStore +{ +public: + const static constexpr int64_t MAX_BUCKET_CNT = 1024; + ObDirectLoadTableStore() : allocator_("TLD_TSBucket"), is_inited_(false) {} + ~ObDirectLoadTableStore(); + int init(const ObDirectLoadTableStoreParam ¶m); + int append_row(const common::ObTabletID &tablet_id, const blocksstable::ObDatumRow &datum_row); + int close(); + void clean_up(); + int get_tables(common::ObIArray &table_array, + common::ObIAllocator &allocator); +private: + int new_bucket(ObDirectLoadTableStoreBucket *&bucket); + int get_bucket(const common::ObTabletID &tablet_id, ObDirectLoadTableStoreBucket *&bucket); +private: + ObDirectLoadTableStoreParam param_; + common::ObArenaAllocator allocator_; + common::ObArray bucket_ptr_array_; + common::hash::ObHashMap tablet_index_; + bool is_inited_; +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_tmp_file.cpp b/src/storage/direct_load/ob_direct_load_tmp_file.cpp new file mode 100644 index 0000000000..67325c6345 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_tmp_file.cpp @@ -0,0 +1,473 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#define USING_LOG_PREFIX STORAGE + +#include "storage/direct_load/ob_direct_load_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ +using namespace common; +using namespace blocksstable; + +/** + * ObDirectLoadTmpFileHandle + */ + +ObDirectLoadTmpFileHandle::ObDirectLoadTmpFileHandle() + : tmp_file_(nullptr) +{ +} + +ObDirectLoadTmpFileHandle::~ObDirectLoadTmpFileHandle() +{ + reset(); +} + +void ObDirectLoadTmpFileHandle::reset() +{ + if (is_valid()) { + int64_t ref_count = tmp_file_->dec_ref_count(); + if (ref_count == 0) { + tmp_file_->get_file_mgr()->put_file(tmp_file_); + } + tmp_file_ = nullptr; + } +} + +int ObDirectLoadTmpFileHandle::assign(const ObDirectLoadTmpFileHandle &other) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(set_file(other.tmp_file_))) { + LOG_WARN("fail to set file", KR(ret)); + } + return ret; +} + +int ObDirectLoadTmpFileHandle::set_file(ObDirectLoadTmpFile *tmp_file) +{ + int ret = OB_SUCCESS; + reset(); + if (OB_UNLIKELY(nullptr == tmp_file || !tmp_file->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(tmp_file)); + } else { + tmp_file->inc_ref_count(); + tmp_file_ = tmp_file; + } + return ret; +} + +/** + * ObDirectLoadTmpFilesHandle + */ + +ObDirectLoadTmpFilesHandle::ObDirectLoadTmpFilesHandle() +{ +} + +ObDirectLoadTmpFilesHandle::~ObDirectLoadTmpFilesHandle() +{ + reset(); +} + +void ObDirectLoadTmpFilesHandle::reset() +{ + for (int64_t i = 0; i < tmp_file_list_.count(); ++i) { + ObDirectLoadTmpFile *tmp_file = tmp_file_list_.at(i); + int64_t ref_count = tmp_file->dec_ref_count(); + if (ref_count == 0) { + tmp_file->get_file_mgr()->put_file(tmp_file); + } + } + tmp_file_list_.reset(); +} + +int ObDirectLoadTmpFilesHandle::assign(const ObDirectLoadTmpFilesHandle &other) +{ + int ret = OB_SUCCESS; + reset(); + if (OB_FAIL(tmp_file_list_.assign(other.tmp_file_list_))) { + LOG_WARN("fail to assign tmp file list", KR(ret)); + } else { + for (int64_t i = 0; i < tmp_file_list_.count(); ++i) { + tmp_file_list_.at(i)->inc_ref_count(); + } + } + return ret; +} + +int ObDirectLoadTmpFilesHandle::add_file(ObDirectLoadTmpFile *tmp_file) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(nullptr == tmp_file || !tmp_file->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(tmp_file)); + } else { + if (OB_FAIL(tmp_file_list_.push_back(tmp_file))) { + LOG_WARN("fail to push back", KR(ret)); + } else { + tmp_file->inc_ref_count(); + } + } + return ret; +} + +int ObDirectLoadTmpFilesHandle::add(const ObDirectLoadTmpFileHandle &tmp_file_handle) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!tmp_file_handle.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tmp_file_handle)); + } else { + ObDirectLoadTmpFile *tmp_file = tmp_file_handle.get_file(); + if (OB_FAIL(add_file(tmp_file))) { + LOG_WARN("fail to add file", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadTmpFilesHandle::add(const ObDirectLoadTmpFilesHandle &tmp_files_handle) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < tmp_files_handle.count(); ++i) { + ObDirectLoadTmpFile *tmp_file = tmp_files_handle.tmp_file_list_.at(i); + if (OB_FAIL(add_file(tmp_file))) { + LOG_WARN("fail to add file", KR(ret)); + } + } + return ret; +} + +int ObDirectLoadTmpFilesHandle::get_file(int64_t idx, + ObDirectLoadTmpFileHandle &tmp_file_handle) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(idx >= tmp_file_list_.count())) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("idx overflow", KR(ret), K(idx), K(tmp_file_list_.count())); + } else if (OB_FAIL(tmp_file_handle.set_file(tmp_file_list_.at(idx)))) { + LOG_WARN("fail to set file", KR(ret)); + } + return ret; +} + +/** + * ObDirectLoadTmpFileIOHandle + */ + +ObDirectLoadTmpFileIOHandle::ObDirectLoadTmpFileIOHandle() +{ +} + +ObDirectLoadTmpFileIOHandle::~ObDirectLoadTmpFileIOHandle() +{ + reset(); +} + +void ObDirectLoadTmpFileIOHandle::reset() +{ + file_handle_.reset(); + io_info_.reset(); + file_io_handle_.reset(); +} + +int ObDirectLoadTmpFileIOHandle::open(const ObDirectLoadTmpFileHandle &file_handle) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!file_handle.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(file_handle)); + } else { + reset(); + if (OB_FAIL(file_handle_.assign(file_handle))) { + LOG_WARN("fail to assign file handle", KR(ret)); + } else { + io_info_.tenant_id_ = MTL_ID(); + io_info_.dir_id_ = file_handle_.get_file()->get_file_id().dir_id_; + io_info_.fd_ = file_handle_.get_file()->get_file_id().fd_; + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::aio_read(char *buf, int64_t size) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_DATA_READ); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.aio_read(io_info_, file_io_handle_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do aio read from tmp file", KR(ret), K_(io_info)); + } + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::aio_pread(char *buf, int64_t size, int64_t offset) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0 || offset < 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size), K(offset)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_DATA_READ); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.aio_pread(io_info_, offset, file_io_handle_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do aio pread from tmp file", KR(ret), K_(io_info), K(offset)); + } + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::read(char *buf, int64_t &size, int64_t timeout_ms) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_DATA_READ); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.read(io_info_, timeout_ms, file_io_handle_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do read from tmp file", KR(ret), K_(io_info)); + } else { + size = file_io_handle_.get_data_size(); + } + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::pread(char *buf, int64_t &size, int64_t offset, int64_t timeout_ms) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_DATA_READ); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.pread(io_info_, offset, timeout_ms, file_io_handle_))) { + if (OB_UNLIKELY(OB_ITER_END != ret)) { + LOG_WARN("fail to do pread from tmp file", KR(ret), K_(io_info), K(offset)); + } else { + size = file_io_handle_.get_data_size(); + } + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::aio_write(char *buf, int64_t size) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_INDEX_BUILD_WRITE); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.aio_write(io_info_, file_io_handle_))) { + LOG_WARN("fail to do aio write to tmp file", KR(ret), K_(io_info)); + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::write(char *buf, int64_t size, int64_t timeout_ms) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!is_valid())) { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("tmp file not set", KR(ret)); + } else if (OB_UNLIKELY(nullptr == buf || size <= 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KP(buf), K(size)); + } else { + io_info_.size_ = size; + io_info_.buf_ = buf; + io_info_.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info_.io_desc_.set_wait_event(ObWaitEventIds::DB_FILE_INDEX_BUILD_WRITE); + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.write(io_info_, timeout_ms))) { + LOG_WARN("fail to do write to tmp file", KR(ret), K_(io_info)); + } + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::wait(int64_t timeout_ms) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(file_io_handle_.wait(timeout_ms))) { + LOG_WARN("fail to wait io finish", KR(ret)); + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::seek(const ObDirectLoadTmpFileHandle &file_handle, int64_t offset, + int whence) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!file_handle.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(file_handle)); + } else if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.seek(file_handle.get_file()->get_file_id().fd_, + offset, whence))) { + LOG_WARN("fail to seek tmp file", KR(ret), K(file_handle), K(offset), K(whence)); + } + return ret; +} + +int ObDirectLoadTmpFileIOHandle::sync(const ObDirectLoadTmpFileHandle &file_handle, + int64_t timeout_ms) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(!file_handle.is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(file_handle)); + } else if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.sync(file_handle.get_file()->get_file_id().fd_, + timeout_ms))) { + LOG_WARN("fail to sync tmp file", KR(ret), K(file_handle)); + } + return ret; +} + +/** + * ObDirectLoadTmpFileManager + */ + +ObDirectLoadTmpFileManager::ObDirectLoadTmpFileManager() + : is_inited_(false) +{ +} + +ObDirectLoadTmpFileManager::~ObDirectLoadTmpFileManager() +{ +} + +int ObDirectLoadTmpFileManager::init(uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (IS_INIT) { + ret = OB_INIT_TWICE; + LOG_WARN("ObDirectLoadTmpFileManager init twice", KR(ret), KP(this)); + } else if (OB_UNLIKELY(OB_INVALID_ID == tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(tenant_id)); + } else { + if (OB_FAIL(file_allocator_.init("TLD_FilePool", tenant_id))) { + LOG_WARN("fail to init allocator", KR(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObDirectLoadTmpFileManager::alloc_dir(int64_t &dir_id) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTmpFileManager not init", KR(ret), KP(this)); + } else if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.alloc_dir(dir_id))) { + LOG_WARN("fail to alloc dir", KR(ret)); + } + return ret; +} + +int ObDirectLoadTmpFileManager::alloc_file(int64_t dir_id, + ObDirectLoadTmpFileHandle &tmp_file_handle) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTmpFileManager not init", KR(ret), KP(this)); + } else if (OB_UNLIKELY(dir_id < 0)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), K(dir_id)); + } else { + ObDirectLoadTmpFile *tmp_file = nullptr; + ObDirectLoadTmpFileId file_id; + file_id.dir_id_ = dir_id; + if (OB_FAIL(FILE_MANAGER_INSTANCE_V2.open(file_id.fd_, file_id.dir_id_))) { + LOG_WARN("fail to open file", KR(ret)); + } else if (OB_ISNULL(tmp_file = file_allocator_.alloc(this, file_id))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc tmp file", KR(ret)); + } else if (OB_FAIL(tmp_file_handle.set_file(tmp_file))) { + LOG_WARN("fail to set file", KR(ret)); + } + if (OB_FAIL(ret)) { + if (nullptr != tmp_file) { + file_allocator_.free(tmp_file); + tmp_file = nullptr; + } + if (file_id.is_valid()) { + FILE_MANAGER_INSTANCE_V2.remove(file_id.fd_); + } + } + } + return ret; +} + +void ObDirectLoadTmpFileManager::put_file(ObDirectLoadTmpFile *tmp_file) +{ + int ret = OB_SUCCESS; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("ObDirectLoadTmpFileManager not init", KR(ret), KP(this)); + } else if (OB_ISNULL(tmp_file) || OB_UNLIKELY(!tmp_file->is_valid())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", KR(ret), KPC(tmp_file)); + } else { + const int64_t ref_count = tmp_file->get_ref_count(); + if (0 == ref_count) { + FILE_MANAGER_INSTANCE_V2.remove(tmp_file->get_file_id().fd_); + file_allocator_.free(tmp_file); + } else { + LOG_ERROR("tmp file ref count must be zero", K(ref_count)); + } + } +} + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/direct_load/ob_direct_load_tmp_file.h b/src/storage/direct_load/ob_direct_load_tmp_file.h new file mode 100644 index 0000000000..76017cf118 --- /dev/null +++ b/src/storage/direct_load/ob_direct_load_tmp_file.h @@ -0,0 +1,131 @@ +// Copyright (c) 2022-present Oceanbase Inc. All Rights Reserved. +// Author: +// suzhi.yt + +#pragma once + +#include "observer/table_load/ob_table_load_object_allocator.h" +#include "storage/blocksstable/ob_tmp_file.h" + +namespace oceanbase +{ +namespace storage +{ +class ObDirectLoadTmpFileManager; + +struct ObDirectLoadTmpFileId +{ + ObDirectLoadTmpFileId() : dir_id_(-1), fd_(-1) {} + bool is_valid() const { return -1 != dir_id_ && -1 != fd_; } + void reset() + { + dir_id_ = -1; + fd_ = -1; + } + TO_STRING_KV(K_(dir_id), K_(fd)); +public: + int64_t dir_id_; + int64_t fd_; +}; + +class ObDirectLoadTmpFile +{ +public: + ObDirectLoadTmpFile(ObDirectLoadTmpFileManager *file_mgr, const ObDirectLoadTmpFileId &file_id) + : file_mgr_(file_mgr), file_id_(file_id), ref_count_(0) + { + } + bool is_valid() const { return nullptr != file_mgr_ && file_id_.is_valid(); } + int64_t get_ref_count() const { return ATOMIC_LOAD(&ref_count_); } + int64_t inc_ref_count() { return ATOMIC_AAF(&ref_count_, 1); } + int64_t dec_ref_count() { return ATOMIC_AAF(&ref_count_, -1); } + ObDirectLoadTmpFileManager *get_file_mgr() const { return file_mgr_; } + const ObDirectLoadTmpFileId &get_file_id() const { return file_id_; } + TO_STRING_KV(KP_(file_mgr), K_(file_id), K_(ref_count)); +private: + ObDirectLoadTmpFileManager *const file_mgr_; + const ObDirectLoadTmpFileId file_id_; + int64_t ref_count_ CACHE_ALIGNED; + DISABLE_COPY_ASSIGN(ObDirectLoadTmpFile); +}; + +class ObDirectLoadTmpFileHandle final +{ +public: + ObDirectLoadTmpFileHandle(); + ~ObDirectLoadTmpFileHandle(); + void reset(); + bool is_valid() const { return nullptr != tmp_file_ && tmp_file_->is_valid(); } + int assign(const ObDirectLoadTmpFileHandle &other); + int set_file(ObDirectLoadTmpFile *tmp_file); + ObDirectLoadTmpFile *get_file() const { return tmp_file_; } + TO_STRING_KV(KPC_(tmp_file)); +private: + ObDirectLoadTmpFile *tmp_file_; + DISABLE_COPY_ASSIGN(ObDirectLoadTmpFileHandle); +}; + +class ObDirectLoadTmpFilesHandle final +{ +public: + ObDirectLoadTmpFilesHandle(); + ~ObDirectLoadTmpFilesHandle(); + void reset(); + int assign(const ObDirectLoadTmpFilesHandle &other); + int add(const ObDirectLoadTmpFileHandle &tmp_file_handle); + int add(const ObDirectLoadTmpFilesHandle &tmp_files_handle); + int count() const { return tmp_file_list_.count(); } + bool empty() const { return tmp_file_list_.empty(); } + int get_file(int64_t idx, ObDirectLoadTmpFileHandle &tmp_file_handle) const; + TO_STRING_KV(K_(tmp_file_list)); +private: + int add_file(ObDirectLoadTmpFile *tmp_file); +private: + common::ObArray tmp_file_list_; + DISABLE_COPY_ASSIGN(ObDirectLoadTmpFilesHandle); +}; + +class ObDirectLoadTmpFileIOHandle final +{ +public: + ObDirectLoadTmpFileIOHandle(); + ~ObDirectLoadTmpFileIOHandle(); + void reset(); + bool is_valid() const { return file_handle_.is_valid(); } + int open(const ObDirectLoadTmpFileHandle &file_handle); + int aio_read(char *buf, int64_t size); + int aio_pread(char *buf, int64_t size, int64_t offset); + int read(char *buf, int64_t &size, int64_t timeout_ms); + int pread(char *buf, int64_t &size, int64_t offset, int64_t timeout_ms); + int aio_write(char *buf, int64_t size); + int write(char *buf, int64_t size, int64_t timeout_ms); + int wait(int64_t timeout_ms); + // for aio read to get real read size when ret = OB_ITER_END + OB_INLINE int64_t get_data_size() { return file_io_handle_.get_data_size(); } + static int seek(const ObDirectLoadTmpFileHandle &file_handle, int64_t offset, int whence); + static int sync(const ObDirectLoadTmpFileHandle &file_handle, int64_t timeout_ms); + TO_STRING_KV(K_(file_handle)); +private: + ObDirectLoadTmpFileHandle file_handle_; + blocksstable::ObTmpFileIOInfo io_info_; + blocksstable::ObTmpFileIOHandle file_io_handle_; + DISABLE_COPY_ASSIGN(ObDirectLoadTmpFileIOHandle); +}; + +class ObDirectLoadTmpFileManager +{ +public: + ObDirectLoadTmpFileManager(); + ~ObDirectLoadTmpFileManager(); + int init(uint64_t tenant_id); + int alloc_dir(int64_t &dir_id); + int alloc_file(int64_t dir_id, ObDirectLoadTmpFileHandle &tmp_file_handle); + void put_file(ObDirectLoadTmpFile *tmp_file); +private: + observer::ObTableLoadObjectAllocator file_allocator_; + bool is_inited_; + DISABLE_COPY_ASSIGN(ObDirectLoadTmpFileManager); +}; + +} // namespace storage +} // namespace oceanbase diff --git a/src/storage/ls/ob_ls_tablet_service.cpp b/src/storage/ls/ob_ls_tablet_service.cpp index 2ecf7195b1..d473cd8ba0 100644 --- a/src/storage/ls/ob_ls_tablet_service.cpp +++ b/src/storage/ls/ob_ls_tablet_service.cpp @@ -27,6 +27,7 @@ #include "share/ob_rpc_struct.h" #include "share/rc/ob_tenant_base.h" #include "share/schema/ob_table_param.h" +#include "share/schema/ob_table_dml_param.h" #include "share/schema/ob_tenant_schema_service.h" #include "share/ob_ddl_common.h" #include "storage/blocksstable/ob_index_block_builder.h" @@ -64,10 +65,15 @@ #include "storage/slog/ob_storage_log_replayer.h" #include "storage/slog/ob_storage_log_struct.h" #include "storage/slog/ob_storage_logger.h" +#include "observer/table_load/ob_table_load_table_ctx.h" +#include "observer/table_load/ob_table_load_coordinator.h" +#include "observer/table_load/ob_table_load_service.h" +#include "observer/table_load/ob_table_load_store.h" using namespace oceanbase::share; using namespace oceanbase::common; using namespace oceanbase::blocksstable; +using namespace oceanbase::observer; namespace oceanbase { @@ -2339,6 +2345,21 @@ int ObLSTabletService::insert_rows( } else if (OB_FAIL(get_tablet_with_timeout( ctx.tablet_id_, tablet_handle, dml_param.timeout_))) { LOG_WARN("failed to check and get tablet", K(ret), K(ctx.tablet_id_)); + } else if (dml_param.is_direct_insert()) { // direct-insert mode + const ObTableSchemaParam::Columns &columns = dml_param.table_param_->get_data_table().get_columns(); + bool is_heap_table = columns.at(0)->is_hidden(); + if (OB_FAIL(direct_insert_rows(dml_param.table_param_->get_data_table().get_table_id(), + dml_param.direct_insert_task_id_, + ctx.tablet_id_, + is_heap_table, + row_iter, + afct_num))) { + LOG_WARN("failed to insert rows direct", KR(ret), + K(dml_param.table_param_->get_data_table().get_table_id()), + K(dml_param.direct_insert_task_id_), + K(ctx.tablet_id_), + K(is_heap_table)); + } } else { ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); ObDMLRunningCtx run_ctx(ctx, @@ -2399,17 +2420,80 @@ int ObLSTabletService::insert_rows( work_allocator.free(ptr); } lob_allocator.reset(); - if (OB_SUCC(ret)) { - LOG_DEBUG("succeeded to insert rows", K(ret)); - affected_rows = afct_num; - EVENT_ADD(STORAGE_INSERT_ROW_COUNT, afct_num); - } + } + if (OB_SUCC(ret)) { + LOG_DEBUG("succeeded to insert rows", K(ret)); + affected_rows = afct_num; + EVENT_ADD(STORAGE_INSERT_ROW_COUNT, afct_num); } NG_TRACE(S_insert_rows_end); return ret; } +int ObLSTabletService::direct_insert_rows( + const uint64_t table_id, + const int64_t task_id, + const ObTabletID &tablet_id, + const bool is_heap_table, + ObNewRowIterator *row_iter, + int64_t &affected_rows) +{ + int ret = OB_SUCCESS; + ObTableLoadTableCtx *table_ctx = nullptr; + ObTableLoadKey key(MTL_ID(), table_id); + if (OB_FAIL(ObTableLoadService::get_ctx(key, table_ctx))) { + LOG_WARN("fail to get table ctx", KR(ret), K(key)); + } else { + int64_t row_count = 0; + ObNewRow *rows = nullptr; + table::ObTableLoadTransId trans_id; + trans_id.segment_id_ = task_id; + trans_id.trans_gid_ = 1; + ObTableLoadStore store(table_ctx); + if (OB_FAIL(store.init())) { + LOG_WARN("fail to init store", KR(ret)); + } + + while (OB_SUCC(ret) && OB_SUCC(get_next_rows(row_iter, rows, row_count))) { + if (row_count <= 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("row_count should be greater than 0", K(ret)); + } else { + common::ObArray row_array; + for (int64_t i = 0; OB_SUCC(ret) && (i < row_count); ++i) { + ObNewRow new_row; + if (is_heap_table) { + new_row.assign(rows[i].cells_ + 1, rows[i].count_ - 1); + } else { + new_row.assign(rows[i].cells_, rows[i].count_); + } + if (OB_FAIL(row_array.push_back(new_row))) { + LOG_WARN("failed to push back row to row_array", KR(ret), K(i), K(new_row)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(store.px_write(trans_id, tablet_id, row_array))) { + LOG_WARN("failed to write to store", KR(ret), K(trans_id), + K(table_id), K(tablet_id), K(row_array)); + } else { + affected_rows += row_count; + } + } + } + } + + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } + } + if (OB_NOT_NULL(table_ctx)) { + ObTableLoadService::put_ctx(table_ctx); + table_ctx = nullptr; + } + return ret; +} + int ObLSTabletService::insert_row( ObStoreCtx &ctx, const ObDMLBaseParam &dml_param, diff --git a/src/storage/ls/ob_ls_tablet_service.h b/src/storage/ls/ob_ls_tablet_service.h index e0a6261cb8..a255153a37 100644 --- a/src/storage/ls/ob_ls_tablet_service.h +++ b/src/storage/ls/ob_ls_tablet_service.h @@ -793,6 +793,14 @@ private: const ObStoreRow &tbl_row); int set_allow_to_read_(ObLS *ls); +private: + int direct_insert_rows(const uint64_t table_id, + const int64_t task_id, + const common::ObTabletID &tablet_id, + const bool is_heap_table, + common::ObNewRowIterator *row_iter, + int64_t &affected_rows); + private: friend class ObLSTabletIterator; diff --git a/src/storage/memtable/ob_memtable.h b/src/storage/memtable/ob_memtable.h index 794e025df3..cde32f2c71 100644 --- a/src/storage/memtable/ob_memtable.h +++ b/src/storage/memtable/ob_memtable.h @@ -389,7 +389,7 @@ public: { return key_.scn_range_.start_scn_; } - bool is_empty() + bool is_empty() const override { return get_end_scn() == get_start_scn() && share::ObScnRange::MIN_SCN == get_max_end_scn(); diff --git a/src/storage/memtable/ob_memtable_interface.h b/src/storage/memtable/ob_memtable_interface.h index 1f30f383fc..88ff588696 100644 --- a/src/storage/memtable/ob_memtable_interface.h +++ b/src/storage/memtable/ob_memtable_interface.h @@ -261,7 +261,7 @@ public: int ret = OB_NOT_SUPPORTED; return ret; } - virtual bool is_empty() + virtual bool is_empty() const override { return false; } diff --git a/src/storage/ob_i_table.h b/src/storage/ob_i_table.h index e034356f05..99733127df 100644 --- a/src/storage/ob_i_table.h +++ b/src/storage/ob_i_table.h @@ -232,6 +232,7 @@ public: virtual OB_INLINE int64_t get_timestamp() const { return 0; } virtual bool is_ddl_sstable() const { return is_ddl_sstable(key_.table_type_); } virtual bool is_remote_logical_minor_sstable() const { return is_remote_logical_minor_sstable(key_.table_type_); } + virtual bool is_empty() const = 0; DECLARE_VIRTUAL_TO_STRING; static bool is_sstable(const TableType table_type) diff --git a/src/storage/tx_storage/ob_access_service.cpp b/src/storage/tx_storage/ob_access_service.cpp index 22128b767f..8d43d561f8 100644 --- a/src/storage/tx_storage/ob_access_service.cpp +++ b/src/storage/tx_storage/ob_access_service.cpp @@ -552,7 +552,8 @@ int ObAccessService::check_write_allowed_( is_try_lock, lock_expired_ts))) { LOG_WARN("get lock param failed", K(ret), K(lock_id)); - } else if (OB_FAIL(ls->lock(ctx_guard.get_store_ctx(), lock_param))) { + } else if (!dml_param.is_direct_insert() + && OB_FAIL(ls->lock(ctx_guard.get_store_ctx(), lock_param))) { LOG_WARN("lock tablet failed", K(ret), K(lock_param)); } else if (dml_param.spec_seq_no_ != -1) { ctx_guard.get_store_ctx().mvcc_acc_ctx_.tx_scn_ = dml_param.spec_seq_no_; diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 4e5c77e1f9..75b1030c02 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -269,6 +269,7 @@ _minor_compaction_interval _mvcc_gc_using_min_txn_snapshot _ob_ddl_timeout _ob_elr_fast_freeze_threshold +_ob_enable_direct_load _ob_enable_fast_freeze _ob_enable_fast_parser _ob_enable_prepared_statement diff --git a/tools/upgrade/upgrade_checker.py b/tools/upgrade/upgrade_checker.py index aa2eb67709..755c41d424 100755 --- a/tools/upgrade/upgrade_checker.py +++ b/tools/upgrade/upgrade_checker.py @@ -438,6 +438,13 @@ def check_tenant_primary_zone(query_cur): def modify_server_permanent_offline_time(cur): set_parameter(cur, 'server_permanent_offline_time', '72h') +# 9. 检查是否有DDL任务在执行 +def check_ddl_task_execute(query_cur): + (desc, results) = query_cur.exec_query("""select count(1) from __all_virtual_ddl_task_status""") + if 0 != results[0][0]: + fail_list.append("There are DDL task in progress") + logging.info('check ddl task execut status success') + # last check of do_check, make sure no function execute after check_fail_list def check_fail_list(): if len(fail_list) != 0 : @@ -465,6 +472,7 @@ def do_check(my_host, my_port, my_user, my_passwd, upgrade_params): check_tenant_status(query_cur) check_restore_job_exist(query_cur) check_tenant_primary_zone(query_cur) + check_ddl_task_execute(query_cur) # all check func should execute before check_fail_list check_fail_list() #modify_server_permanent_offline_time(cur) diff --git a/tools/upgrade/upgrade_post.py b/tools/upgrade/upgrade_post.py index aa1b6a9928..696592078a 100755 --- a/tools/upgrade/upgrade_post.py +++ b/tools/upgrade/upgrade_post.py @@ -1916,6 +1916,13 @@ #def modify_server_permanent_offline_time(cur): # set_parameter(cur, 'server_permanent_offline_time', '72h') # +## 9. 检查是否有DDL任务在执行 +#def check_ddl_task_execute(query_cur): +# (desc, results) = query_cur.exec_query("""select count(1) from __all_virtual_ddl_task_status""") +# if 0 != results[0][0]: +# fail_list.append("There are DDL task in progress") +# logging.info('check ddl task execut status success') +# ## last check of do_check, make sure no function execute after check_fail_list #def check_fail_list(): # if len(fail_list) != 0 : @@ -1943,6 +1950,7 @@ # check_tenant_status(query_cur) # check_restore_job_exist(query_cur) # check_tenant_primary_zone(query_cur) +# check_ddl_task_execute(query_cur) # # all check func should execute before check_fail_list # check_fail_list() # #modify_server_permanent_offline_time(cur) diff --git a/tools/upgrade/upgrade_pre.py b/tools/upgrade/upgrade_pre.py index fffbd5ee1a..aa9bbe874a 100755 --- a/tools/upgrade/upgrade_pre.py +++ b/tools/upgrade/upgrade_pre.py @@ -1916,6 +1916,13 @@ #def modify_server_permanent_offline_time(cur): # set_parameter(cur, 'server_permanent_offline_time', '72h') # +## 9. 检查是否有DDL任务在执行 +#def check_ddl_task_execute(query_cur): +# (desc, results) = query_cur.exec_query("""select count(1) from __all_virtual_ddl_task_status""") +# if 0 != results[0][0]: +# fail_list.append("There are DDL task in progress") +# logging.info('check ddl task execut status success') +# ## last check of do_check, make sure no function execute after check_fail_list #def check_fail_list(): # if len(fail_list) != 0 : @@ -1943,6 +1950,7 @@ # check_tenant_status(query_cur) # check_restore_job_exist(query_cur) # check_tenant_primary_zone(query_cur) +# check_ddl_task_execute(query_cur) # # all check func should execute before check_fail_list # check_fail_list() # #modify_server_permanent_offline_time(cur) diff --git a/unittest/storage/CMakeLists.txt b/unittest/storage/CMakeLists.txt index 9e3a6f24ee..6f6f103114 100644 --- a/unittest/storage/CMakeLists.txt +++ b/unittest/storage/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(mockcontainer) add_subdirectory(transaction) add_subdirectory(tx) add_subdirectory(blocksstable) +add_subdirectory(direct_load) add_subdirectory(utl_file) add_subdirectory(tx_table) diff --git a/unittest/storage/backup/test_backup_index_merger.cpp b/unittest/storage/backup/test_backup_index_merger.cpp index a8524f61ae..d8c77bf414 100644 --- a/unittest/storage/backup/test_backup_index_merger.cpp +++ b/unittest/storage/backup/test_backup_index_merger.cpp @@ -284,7 +284,7 @@ protected: }; TestBackupIndexMerger::TestBackupIndexMerger() - : TestDataFilePrepare(&getter, "TestBackupIndexMerger"), + : TestDataFilePrepare(&getter, "TestBackupIndexMerger", OB_DEFAULT_MACRO_BLOCK_SIZE, 800), tenant_base_(500), job_desc_(), backup_dest_(), diff --git a/unittest/storage/backup/test_backup_iterator.cpp b/unittest/storage/backup/test_backup_iterator.cpp index 7d1be120f4..50723eae4c 100644 --- a/unittest/storage/backup/test_backup_iterator.cpp +++ b/unittest/storage/backup/test_backup_iterator.cpp @@ -73,7 +73,7 @@ protected: TestBackupIndexIterator::TestBackupIndexIterator() - : TestDataFilePrepare(&getter, "TestBackupIndexIterator"), + : TestDataFilePrepare(&getter, "TestBackupIndexIterator", OB_DEFAULT_MACRO_BLOCK_SIZE, 500), tenant_base_(500), job_desc_(), backup_dest_(), @@ -344,4 +344,4 @@ int main(int argc, char **argv) OB_LOGGER.set_log_level("INFO"); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/unittest/storage/blocksstable/test_tmp_file.cpp b/unittest/storage/blocksstable/test_tmp_file.cpp index 8c12ef5e6e..946ea618f8 100644 --- a/unittest/storage/blocksstable/test_tmp_file.cpp +++ b/unittest/storage/blocksstable/test_tmp_file.cpp @@ -14,6 +14,8 @@ #define protected public #define private public #include "storage/blocksstable/ob_tmp_file.h" +#include "storage/blocksstable/ob_tmp_file_store.h" +#include "storage/blocksstable/ob_tmp_file_cache.h" #include "ob_row_generate.h" #include "ob_data_file_prepare.h" #include "share/ob_simple_mem_limit_getter.h" @@ -80,6 +82,7 @@ class TestTmpFileStress : public share::ObThreadPool { public: TestTmpFileStress(); + TestTmpFileStress(ObTenantBase *tenant_ctx); virtual ~TestTmpFileStress(); int init(const int fd, const bool is_write, const int64_t thread_cnt, ObTableSchema *table_schema, const bool is_plain_data, const bool is_big_file); @@ -103,6 +106,7 @@ private: bool is_big_file_; ObTableSchema *table_schema_; bool is_plain_; + ObTenantBase *tenant_ctx_; }; TestTmpFileStress::TestTmpFileStress() @@ -111,6 +115,13 @@ TestTmpFileStress::TestTmpFileStress() { } +TestTmpFileStress::TestTmpFileStress(ObTenantBase *tenant_ctx) + : thread_cnt_(0), size_(OB_SERVER_BLOCK_MGR.get_macro_block_size()), fd_(0), + is_write_(false), is_big_file_(false), table_schema_(NULL), is_plain_(false), + tenant_ctx_(tenant_ctx) +{ +} + TestTmpFileStress::~TestTmpFileStress() { } @@ -340,8 +351,7 @@ void TestTmpFileStress::read_plain_data(const char *read_buf, const int64_t macr void TestTmpFileStress::run1() { - ObTenantBase tenant_ctx(1); - ObTenantEnv::set_tenant(&tenant_ctx); + ObTenantEnv::set_tenant(tenant_ctx_); if (is_plain_) { char *buf = NULL; write_plain_data(buf, size_); @@ -359,6 +369,7 @@ class TestMultiTmpFileStress : public share::ObThreadPool { public: TestMultiTmpFileStress(); + TestMultiTmpFileStress(ObTenantBase *tenant_ctx); virtual ~TestMultiTmpFileStress(); int init(const int64_t file_cnt, const int64_t dir_id, const int64_t thread_cnt, ObTableSchema *table_schema, const bool is_plain_data, const bool is_big_file); @@ -373,6 +384,7 @@ private: ObTableSchema *table_schema_; bool is_big_file_; bool is_plain_data_; + ObTenantBase *tenant_ctx_; }; TestMultiTmpFileStress::TestMultiTmpFileStress() @@ -384,6 +396,16 @@ TestMultiTmpFileStress::TestMultiTmpFileStress() is_plain_data_(false) { } +TestMultiTmpFileStress::TestMultiTmpFileStress(ObTenantBase *tenant_ctx) + : file_cnt_(0), + dir_id_(-1), + thread_cnt_perf_file_(0), + table_schema_(NULL), + is_big_file_(false), + is_plain_data_(false), + tenant_ctx_(tenant_ctx) +{ +} TestMultiTmpFileStress::~TestMultiTmpFileStress() { @@ -417,7 +439,7 @@ void TestMultiTmpFileStress::run_plain_case() { int ret = OB_SUCCESS; int64_t fd = 0; - TestTmpFileStress test; + TestTmpFileStress test(tenant_ctx_); ret = ObTmpFileManager::get_instance().open(fd, dir_id_); ASSERT_EQ(OB_SUCCESS, ret); ret = test.init(fd, true, thread_cnt_perf_file_, table_schema_, is_plain_data_, is_big_file_); @@ -433,8 +455,8 @@ void TestMultiTmpFileStress::run_normal_case() int ret = OB_SUCCESS; int64_t fd = 0; const int64_t timeout_ms = 50000; - TestTmpFileStress test_write; - TestTmpFileStress test_read; + TestTmpFileStress test_write(tenant_ctx_); + TestTmpFileStress test_read(tenant_ctx_); ret = ObTmpFileManager::get_instance().open(fd, dir_id_); ASSERT_EQ(OB_SUCCESS, ret); STORAGE_LOG(INFO, "open file success", K(fd)); @@ -454,6 +476,7 @@ void TestMultiTmpFileStress::run_normal_case() void TestMultiTmpFileStress::run1() { + ObTenantEnv::set_tenant(tenant_ctx_); if (is_plain_data_) { run_plain_case(); } else { @@ -557,6 +580,7 @@ void TestTmpFile::TearDown() table_schema_.reset(); ObTmpFileManager::get_instance().destroy(); ObKVGlobalCache::get_instance().destroy(); + ObTmpFileStore::get_instance().destroy(); TestDataFilePrepare::TearDown(); } @@ -645,7 +669,7 @@ TEST_F(TestTmpFile, test_multi_small_file_single_thread_read_write) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = false; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -674,7 +698,7 @@ TEST_F(TestTmpFile, test_multi_small_file_multi_thread_read_write ) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = false; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -782,7 +806,7 @@ TEST_F(TestTmpFile, test_single_file_single_thread_read_write) const int64_t file_cnt = 1; const bool is_plain_data = false; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -895,8 +919,8 @@ TEST_F(TestTmpFile, test_100_small_files) int64_t fd = 0; int count = 100; const int64_t timeout_ms = 50000; - TestTmpFileStress test_write; - TestTmpFileStress test_read; + TestTmpFileStress test_write(MTL_CTX()); + TestTmpFileStress test_read(MTL_CTX()); ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); while (count--) { @@ -937,7 +961,7 @@ TEST_F(TestTmpFile, test_single_file_multi_thread_read_write) const int64_t file_cnt = 1; const bool is_plain_data = false; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -967,7 +991,7 @@ TEST_F(TestTmpFile, test_multi_file_single_thread_read_write) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -997,7 +1021,7 @@ TEST_F(TestTmpFile, test_multi_file_multi_thread_read_write) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -1027,7 +1051,7 @@ TEST_F(TestTmpFile, test_write_not_macro_size) const int64_t file_cnt = 1; const bool is_plain_data = true; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -1383,7 +1407,7 @@ TEST_F(TestTmpFile, test_single_dir_multi_file) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = false; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -1413,7 +1437,7 @@ TEST_F(TestTmpFile, test_drop_tenant_file) const int64_t file_cnt = 4; const bool is_plain_data = false; const bool is_big_file = true; - TestMultiTmpFileStress test; + TestMultiTmpFileStress test(MTL_CTX()); int64_t dir = -1; ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); @@ -1434,8 +1458,8 @@ TEST_F(TestTmpFile, test_drop_tenant_file) int64_t fd = 0; int count = 100; const int64_t timeout_ms = 50000; - TestTmpFileStress test_write; - TestTmpFileStress test_read; + TestTmpFileStress test_write(MTL_CTX()); + TestTmpFileStress test_read(MTL_CTX()); ret = ObTmpFileManager::get_instance().alloc_dir(dir); ASSERT_EQ(OB_SUCCESS, ret); while (count--) { @@ -1623,15 +1647,15 @@ TEST_F(TestTmpFile, test_page_buddy) ret = page_buddy_1.init(allocator); ASSERT_EQ(OB_SUCCESS, ret); - int32_t page_nums = 64; - int32_t alloced_page_nums = 64; - int32_t start_page_id = -1; + uint8_t page_nums = 64; + uint8_t alloced_page_nums = 64; + uint8_t start_page_id = 255; ASSERT_EQ(true, page_buddy_1.is_empty()); ret = page_buddy_1.alloc(page_nums, start_page_id, alloced_page_nums); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(false, page_buddy_1.is_empty()); - int32_t start_page_id_2 = -1; + uint8_t start_page_id_2 = 255; ret = page_buddy_1.alloc(page_nums, start_page_id_2, alloced_page_nums); ASSERT_EQ(OB_SUCCESS, ret); ASSERT_EQ(false, page_buddy_1.is_empty()); @@ -1691,6 +1715,204 @@ TEST_F(TestTmpFile, test_page_buddy) ASSERT_EQ(false, page_buddy_4.is_empty()); } +TEST_F(TestTmpFile, test_tmp_file_sync) +{ + int ret = OB_SUCCESS; + int64_t dir = -1; + int64_t fd = -1; + ObTmpFileIOInfo io_info; + ObTmpFileIOHandle handle; + ret = ObTmpFileManager::get_instance().alloc_dir(dir); + ASSERT_EQ(OB_SUCCESS, ret); + ret = ObTmpFileManager::get_instance().open(fd, dir); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t write_size = 16*1024; + char *write_buf = (char *)malloc(write_size); + for (int64_t i = 0; i < write_size; ++i) { + write_buf[i] = static_cast(i % 256); + } + io_info.fd_ = fd; + io_info.tenant_id_ = 1; + io_info.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info.io_desc_.set_wait_event(2); + io_info.buf_ = write_buf; + io_info.size_ = write_size; + const int64_t timeout_ms = 5000; + int64_t write_time = ObTimeUtility::current_time(); + ret = ObTmpFileManager::get_instance().write(io_info, timeout_ms); + write_time = ObTimeUtility::current_time() - write_time; + ASSERT_EQ(OB_SUCCESS, ret); + free(write_buf); + + STORAGE_LOG(INFO, "test_tmp_file_sync"); + STORAGE_LOG(INFO, "io time", K(write_time)); + ObTmpTenantFileStoreHandle store_handle; + OB_TMP_FILE_STORE.get_store(1, store_handle); + ASSERT_EQ(1, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + ObTmpFileManager::get_instance().sync(fd, 5000); + ASSERT_EQ(0, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + + store_handle.get_tenant_store()->print_block_usage(); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(500); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(500); + + ObTmpFileManager::get_instance().remove(fd); +} + +TEST_F(TestTmpFile, test_tmp_file_sync_same_block) +{ + int ret = OB_SUCCESS; + int64_t dir = -1; + int64_t fd1, fd2 = -1; + const int64_t timeout_ms = 5000; + ObTmpFileIOHandle handle; + ObTmpFileIOInfo io_info; + io_info.tenant_id_ = 1; + io_info.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info.io_desc_.set_wait_event(2); + int64_t write_size = 16 *1024; + char *write_buf = (char *)malloc(write_size); + for (int64_t i = 0; i < write_size; ++i) { + write_buf[i] = static_cast(i % 256); + } + io_info.buf_ = write_buf; + io_info.size_ = write_size; + + ret = ObTmpFileManager::get_instance().alloc_dir(dir); + ASSERT_EQ(OB_SUCCESS, ret); + + ret = ObTmpFileManager::get_instance().open(fd1, dir); + ASSERT_EQ(OB_SUCCESS, ret); + io_info.fd_ = fd1; + int64_t write_time = ObTimeUtility::current_time(); + ret = ObTmpFileManager::get_instance().write(io_info, timeout_ms); + write_time = ObTimeUtility::current_time() - write_time; + ASSERT_EQ(OB_SUCCESS, ret); + + ret = ObTmpFileManager::get_instance().open(fd2, dir); + ASSERT_EQ(OB_SUCCESS, ret); + io_info.fd_ = fd2; + write_time = ObTimeUtility::current_time(); + ret = ObTmpFileManager::get_instance().write(io_info, timeout_ms); + write_time = ObTimeUtility::current_time() - write_time; + ASSERT_EQ(OB_SUCCESS, ret); + + free(write_buf); + + STORAGE_LOG(INFO, "test_tmp_file_sync_same_block"); + STORAGE_LOG(INFO, "io time", K(write_time)); + ObTmpTenantFileStoreHandle store_handle; + OB_TMP_FILE_STORE.get_store(1, store_handle); + ASSERT_EQ(1, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + ObTmpFileManager::get_instance().sync(fd1, 5000); + ASSERT_EQ(1, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + ObTmpFileManager::get_instance().sync(fd2, 5000); + ASSERT_EQ(0, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + + store_handle.get_tenant_store()->print_block_usage(); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(500); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(500); + + ObTmpFileManager::get_instance().remove(fd1); + ObTmpFileManager::get_instance().remove(fd2); +} + +TEST_F(TestTmpFile, test_tmp_file_wash) +{ + int ret = OB_SUCCESS; + const int64_t timeout_ms = 5000; + int count = 64; + int64_t dir = -1; + int64_t fd = -1; + ObTmpFileIOHandle handle; + ObTmpFileIOInfo io_info; + io_info.tenant_id_ = 1; + io_info.io_desc_.set_group_id(THIS_WORKER.get_group_id()); + io_info.io_desc_.set_wait_event(2); + int64_t write_size = 1024 *1024; + char *write_buf = (char *)malloc(write_size); + for (int64_t i = 0; i < write_size; ++i) { + write_buf[i] = static_cast(i % 256); + } + io_info.buf_ = write_buf; + io_info.size_ = write_size; + + for(int64_t i=0; itmp_mem_block_manager_.t_mblk_map_.begin(); + iter != store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.end(); ++iter){ + int64_t alloc_time = iter->second->get_alloc_time(); + if (alloc_time < oldest_time){ + oldest_id = iter->first; + oldest_time = alloc_time; + } + if (alloc_time > newest_time){ + newest_id = iter->first; + newest_time = alloc_time; + } + if(iter->second->get_free_page_nums()==0){ + used_up_id = iter->first; + } + } + ObTmpMacroBlock* wash_block; + ret = store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.get_refactored(newest_id, wash_block); + ASSERT_EQ(OB_SUCCESS, ret); + wash_block->alloc_time_ = wash_block->alloc_time_ - 60 * 1000000L; + + ObArray free_blocks; + ASSERT_EQ(64, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + store_handle.get_tenant_store()->tmp_mem_block_manager_.wash(3,free_blocks); + ret = store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.get_refactored(oldest_id, wash_block); + ASSERT_NE(OB_SUCCESS, ret); + ret = store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.get_refactored(newest_id, wash_block); + ASSERT_NE(OB_SUCCESS, ret); + ret = store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.get_refactored(used_up_id, wash_block); + ASSERT_NE(OB_SUCCESS, ret); + ASSERT_EQ(61, store_handle.get_tenant_store()->tmp_mem_block_manager_.t_mblk_map_.size()); + + + store_handle.get_tenant_store()->print_block_usage(); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(1); + ObMallocAllocator::get_instance()->print_tenant_memory_usage(500); + ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(500); + + count = 64; + while (count--) { + ret = ObTmpFileManager::get_instance().remove(count); + ASSERT_EQ(OB_SUCCESS, ret); + } +} + + } // end namespace unittest } // end namespace oceanbase diff --git a/unittest/storage/direct_load/CMakeLists.txt b/unittest/storage/direct_load/CMakeLists.txt new file mode 100644 index 0000000000..c6d87a70b1 --- /dev/null +++ b/unittest/storage/direct_load/CMakeLists.txt @@ -0,0 +1,2 @@ +storage_unittest(test_direct_load_index_block_writer) +storage_unittest(test_direct_load_data_block_writer) diff --git a/unittest/storage/direct_load/test_direct_load_data_block_writer.cpp b/unittest/storage/direct_load/test_direct_load_data_block_writer.cpp new file mode 100644 index 0000000000..faea05c6bb --- /dev/null +++ b/unittest/storage/direct_load/test_direct_load_data_block_writer.cpp @@ -0,0 +1,1529 @@ +// Copyright 2014-2014 Alibaba Inc. All Rights Reserved. +// Author: +// yiren.ly +// +// This file defines test_direct_load_data_block_writer.cpp +#include +#define private public +#define protected public +#include +#include +#include "../unittest/storage/blocksstable/ob_data_file_prepare.h" +#include "../unittest/storage/blocksstable/ob_row_generate.h" +#include "observer/table_load/ob_table_load_partition_location.h" +#include "share/ob_simple_mem_limit_getter.h" +#include "storage/blocksstable/ob_tmp_file.h" +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" +#include "storage/direct_load/ob_direct_load_sstable_compactor.h" +#include "storage/ob_i_store.h" + +namespace oceanbase +{ +using namespace common; +using namespace blocksstable; +using namespace storage; +using namespace share::schema; +using namespace share; + +static ObSimpleMemLimitGetter getter; + +namespace unittest +{ +class TestDataBlockWriter : public TestDataFilePrepare +{ +public: + static const int64_t rowkey_column_count = 2; + // Every ObObjType from ObTinyIntType to ObHexStringType inclusive. + // Skip ObNullType and ObExtendType because for external usage, a column type + // can't be NULL or NOP. + static const int64_t column_num = ObHexStringType + 1; + static const int64_t macro_block_size = 2L * 8 * 1024L; + static const int64_t SNAPSHOT_VERSION = 2; + +public: + TestDataBlockWriter() : TestDataFilePrepare(&getter, "TestDataBlockWriter", 8 * 1024 * 1024, 2048){}; + virtual void SetUp(); + virtual void TearDown(); + static void SetUpTestCase() {} + static void TearDownTestCase() {} + + void check_row(const ObDatumRow *next_row, const ObDatumRow *curr_row); + void test_alloc(char *&ptr, const int64_t size); + +private: + void prepare_schema(); + +protected: + ObTableSchema table_schema_; + ObDirectLoadTableDataDesc table_data_desc_; + ObRowGenerate row_generate_; + ObDirectLoadTmpFileManager *file_mgr_; +}; + +void TestDataBlockWriter::test_alloc(char *&ptr, const int64_t size) +{ + ptr = reinterpret_cast(allocator_.alloc(size)); + ASSERT_TRUE(nullptr != ptr); +} + +void TestDataBlockWriter::check_row(const ObDatumRow *next_row, const ObDatumRow *curr_row) +{ + int cmp_ret = 0; + ObDatumRowkey next_key(next_row->storage_datums_, rowkey_column_count); + ObDatumRowkey curr_key(curr_row->storage_datums_, rowkey_column_count); + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + ASSERT_EQ(OB_SUCCESS, next_key.compare(curr_key, datum_utils, cmp_ret)); + ASSERT_TRUE(cmp_ret == 0); +} + +void TestDataBlockWriter::prepare_schema() +{ + ObColumnSchemaV2 column; + int64_t table_id = 3001; + // init table schema + table_schema_.reset(); + ASSERT_EQ(OB_SUCCESS, table_schema_.set_table_name("test_macro_file")); + table_schema_.set_tenant_id(1); + table_schema_.set_tablegroup_id(1); + table_schema_.set_database_id(1); + table_schema_.set_table_id(table_id); + table_schema_.set_tablet_id(1); + table_schema_.set_rowkey_column_num(rowkey_column_count); + table_schema_.set_max_used_column_id(column_num); + + // init column + char name[OB_MAX_FILE_NAME_LENGTH]; + memset(name, 0, sizeof(name)); + for (int64_t i = 0; i < column_num; ++i) { + ObObjType obj_type = static_cast(i + 1); + if (i == column_num - 1) { + obj_type = ObTextType; + } + column.reset(); + column.set_table_id(table_id); + column.set_column_id(i + OB_APP_MIN_COLUMN_ID); + sprintf(name, "test%020ld", i); + ASSERT_EQ(OB_SUCCESS, column.set_column_name(name)); + column.set_data_type(obj_type); + if (obj_type == common::ObIntType) { + column.set_rowkey_position(1); + } else if (obj_type == common::ObNumberType) { + column.set_rowkey_position(2); + } else { + column.set_rowkey_position(0); + } + column.set_collation_type(ObCollationType::CS_TYPE_UTF8MB4_GENERAL_CI); + ASSERT_EQ(OB_SUCCESS, table_schema_.add_column(column)); + } + ObTmpFileManager::get_instance().destroy(); +} + +void TestDataBlockWriter::SetUp() +{ + int ret = OB_SUCCESS; + // init file + const int64_t bucket_num = 1024; + const int64_t max_cache_size = 1024 * 1024 * 1024; + const int64_t block_size = common::OB_MALLOC_BIG_BLOCK_SIZE; + TestDataFilePrepare::SetUp(); + prepare_schema(); + table_data_desc_.rowkey_column_num_ = table_schema_.get_rowkey_column_num(); + table_data_desc_.column_count_ = column_num; + table_data_desc_.external_data_block_size_ = (2LL << 20); + table_data_desc_.sstable_index_block_size_ = DIRECT_LOAD_DEFAULT_SSTABLE_INDEX_BLOCK_SIZE; + table_data_desc_.sstable_data_block_size_ = DIRECT_LOAD_DEFAULT_SSTABLE_DATA_BLOCK_SIZE; + table_data_desc_.extra_buf_size_ = (2LL << 20); + table_data_desc_.compressor_type_ = ObCompressorType::NONE_COMPRESSOR; + table_data_desc_.is_heap_table_ = false; + table_data_desc_.mem_chunk_size_ = (64LL << 20); + table_data_desc_.max_mem_chunk_count_ = 128; + table_data_desc_.merge_count_per_round_ = 64; + table_data_desc_.heap_table_mem_chunk_size_ = (64LL << 20); + file_mgr_ = OB_NEWx(ObDirectLoadTmpFileManager, (&allocator_)); + ASSERT_TRUE(nullptr != file_mgr_); + ret = file_mgr_->init(table_schema_.get_tenant_id()); + ASSERT_EQ(OB_SUCCESS, ret); + // init ObRowGenerate + ASSERT_EQ(OB_SUCCESS, row_generate_.init(table_schema_)); + + ret = getter.add_tenant(1, 8L * 1024L * 1024L, 2L * 1024L * 1024L * 1024L); + ASSERT_EQ(OB_SUCCESS, ret); + ret = ObKVGlobalCache::get_instance().init(&getter, bucket_num, max_cache_size, block_size); + if (OB_INIT_TWICE == ret) { + ret = OB_SUCCESS; + } else { + ASSERT_EQ(OB_SUCCESS, ret); + } + // set observer memory limit + CHUNK_MGR.set_limit(8L * 1024L * 1024L * 1024L); + ret = ObTmpFileManager::get_instance().init(); + ASSERT_EQ(OB_SUCCESS, ret); + + static ObTenantBase tenant_ctx(1); + ObTenantEnv::set_tenant(&tenant_ctx); + ObTenantIOManager *io_service = nullptr; + EXPECT_EQ(OB_SUCCESS, ObTenantIOManager::mtl_init(io_service)); +} + +void TestDataBlockWriter::TearDown() +{ + file_mgr_->~ObDirectLoadTmpFileManager(); + ObTmpFileManager::get_instance().destroy(); + ObKVGlobalCache::get_instance().destroy(); + TestDataFilePrepare::TearDown(); +} + +TEST_F(TestDataBlockWriter, test_empty_write_and_scan) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 100000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObDirectLoadTmpFileManager *file_mgr = new ObDirectLoadTmpFileManager(); + ret = file_mgr->init(table_schema_.get_tenant_id()); + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + + datum_range.set_whole_range(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + + // left closed ,right closed + datum_range.set_left_closed(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + int64_t index_item_count = sstable->get_meta().index_item_count_; + ObDirectLoadIndexBlockMetaIterator* meta_iter; + ObDirectLoadIndexBlockMeta meta; + ret = sstable->scan_index_block_meta(allocator_, meta_iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, meta_iter->get_next(meta)); + //delete file_mgr; //释放会导致core,因为sstable等都没释放,干脆就都不释放了 +} + +TEST_F(TestDataBlockWriter, test_write_and_scan) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 100000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObDirectLoadTmpFileManager *file_mgr = new ObDirectLoadTmpFileManager(); + ret = file_mgr->init(table_schema_.get_tenant_id()); + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array.push_back(row); + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + // max = 6085; + // min = 6083; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + + // left closed ,right closed + datum_range.set_left_closed(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t new_min = min + 1; + for (int64_t i = new_min; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left closed ,right open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = min; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = new_min; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + int64_t index_item_count = sstable->get_meta().index_item_count_; + ObDirectLoadIndexBlockMetaIterator* meta_iter; + ObDirectLoadIndexBlockMeta meta; + ret = sstable->scan_index_block_meta(allocator_, meta_iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t number= meta_iter->get_total_block_count(); + for (int64_t i = 0; i < number; ++i) { + ASSERT_EQ(OB_SUCCESS, meta_iter->get_next(meta)); + } + ASSERT_EQ(OB_ITER_END, meta_iter->get_next(meta)); + + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } + //delete file_mgr; //同上 +} + +TEST_F(TestDataBlockWriter, test_write_and_scan_range) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 10000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array.push_back(row); + if (i < 5000) { + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + max = 6085; + min = 6000; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left closed ,right open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_scan_less_range) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 10000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array.push_back(row); + if (i >= 5000) { + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + max = 4999; + min = 3000; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + // left closed ,right closed + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left open ,rigth closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left open ,rigth open + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left closed ,rigth open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} +TEST_F(TestDataBlockWriter, test_scan_range) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 10000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array.push_back(row); + if (i < 5000) { + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + max = 6085; + min = 3000; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + // left closed ,right closed + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= 4999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left open ,rigth closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = (min + 1); i <= 4999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + ASSERT_NO_FATAL_FAILURE(check_row(datum_row, array.at(i))); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left open ,rigth open + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = (min + 1); i <= 4999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + // left closed ,rigth open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = min; i <= 4999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + ASSERT_TRUE(datum_row == nullptr); + + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_write_and_scan_large_low) +{ + int ret = OB_SUCCESS; + const int64_t index_block_size = DIO_ALIGN_SIZE; + const int64_t data_block_size = 4 * DIO_ALIGN_SIZE; + const int64_t test_row_num = 100000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + if (i % 100 == 0) { + int32_t value1_size = 20 * 1024; + char *ptr1 = nullptr; + test_alloc(ptr1, value1_size); + ASSERT_TRUE(nullptr != ptr1); + row->storage_datums_[24].set_string(ObString(value1_size, ptr1)); + } + array.push_back(row); + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + // max = 6085; + // min = 6083; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + // left closed ,rigth closed + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right open + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = (min + 1); i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right open + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = (min + 1); i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left closed ,right open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = min; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + +int64_t index_item_count = sstable->get_meta().index_item_count_; + ObDirectLoadIndexBlockMetaIterator* meta_iter; + ObDirectLoadIndexBlockMeta meta; + ret = sstable->scan_index_block_meta(allocator_, meta_iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t number= meta_iter->get_total_block_count(); + for (int64_t i = 0; i < number; ++i) { + ASSERT_EQ(OB_SUCCESS, meta_iter->get_next(meta)); + } + ASSERT_EQ(OB_ITER_END, meta_iter->get_next(meta)); + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_write_and_scan_range_large_low) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 10000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + if (i % 100 == 0) { + int32_t value1_size = 20 * 1024; + char *ptr1 = nullptr; + test_alloc(ptr1, value1_size); + ASSERT_TRUE(nullptr != ptr1); + row->storage_datums_[24].set_string(ObString(value1_size, ptr1)); + } + array.push_back(row); + if (i < 5000) { + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + max = 6085; + min = 6000; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_scan_range_large_low) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 10000; + ObArray array; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder; + ret = sstable_builder.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + if (i % 100 == 0) { + int32_t value1_size = 20 * 1024; + char *ptr1 = nullptr; + test_alloc(ptr1, value1_size); + ASSERT_TRUE(nullptr != ptr1); + row->storage_datums_[24].set_string(ObString(value1_size, ptr1)); + } + array.push_back(row); + if (i < 5000) { + ret = sstable_builder.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + } + ret = sstable_builder.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array; + ret = sstable_builder.get_tables(table_array, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable = nullptr; + sstable = dynamic_cast(table_array.at(0)); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + max = 6085; + min = 3000; + ObDatumRowkey start_key(array.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + datum_range.set_left_closed(); + datum_range.set_right_closed(); + + ObTableReadInfo read_info; + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= 4999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + for (int64_t i = 0; i < array.count(); ++i) { + ObDatumRow *row = array.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_write_and_compact) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 100000; + ObArray array1; + ObArray array2; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder1; + ObDirectLoadSSTableBuilder sstable_builder2; + ret = sstable_builder1.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array1.push_back(row); + ret = sstable_builder1.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + array2.push_back(row); + ret = sstable_builder2.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + + ret = sstable_builder1.close(); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array1; + ObArray table_array2; + ret = sstable_builder1.get_tables(table_array1, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.get_tables(table_array2, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable1 = nullptr; + sstable1 = dynamic_cast(table_array1.at(0)); + ASSERT_TRUE(nullptr != sstable1); + + ObDirectLoadSSTable *sstable2 = nullptr; + sstable2 = dynamic_cast(table_array2.at(0)); + ASSERT_TRUE(nullptr != sstable2); + + ObIDirectLoadPartitionTable *new_sstable = nullptr; + ObDirectLoadSSTableCompactor compactor; + ObDirectLoadSSTableCompactParam compact_param; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + compact_param.tablet_id_ = table_schema_.get_tablet_id(); + compact_param.table_data_desc_ = table_data_desc_; + ObTableReadInfo read_info; + + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + compact_param.datum_utils_ = &(read_info.datum_utils_); + + ret = compactor.init(compact_param); + ASSERT_EQ(OB_SUCCESS, ret); + ret = compactor.add_table(sstable1); + ASSERT_EQ(OB_SUCCESS, ret); + ret = compactor.add_table(sstable2); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_SUCCESS, compactor.compact()); + ASSERT_EQ(OB_SUCCESS, compactor.get_table(new_sstable, allocator_)); + ObDirectLoadSSTable *sstable = dynamic_cast(new_sstable); + ASSERT_TRUE(nullptr != sstable); + ObDirectLoadSSTableScanner *iter = nullptr; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + ObDatumRowkey start_key(array1.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array2.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + + // left closed ,right closed + datum_range.set_left_closed(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t new_min = min + 1; + for (int64_t i = new_min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left closed ,right open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = new_min; i <=99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + int64_t index_item_count = sstable->get_meta().index_item_count_; + ObDirectLoadIndexBlockMetaIterator* meta_iter; + ObDirectLoadIndexBlockMeta meta; + ret = sstable->scan_index_block_meta(allocator_, meta_iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t number = meta_iter->get_total_block_count(); + for (int64_t i = 0; i < number; ++i) { + ASSERT_EQ(OB_SUCCESS, meta_iter->get_next(meta)); + } + ASSERT_EQ(OB_ITER_END, meta_iter->get_next(meta)); + + for (int64_t i = 0; i < array1.count(); ++i) { + ObDatumRow *row = array1.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } + for (int64_t i = 0; i < array2.count(); ++i) { + ObDatumRow *row = array2.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +TEST_F(TestDataBlockWriter, test_write_and_compact_large_row) +{ + int ret = OB_SUCCESS; + const int64_t test_row_num = 100000; + ObArray array1; + ObArray array2; + ObDirectLoadSSTableBuildParam param; + ObArray col_descs; + ObStorageDatumUtils datum_utils; + ASSERT_EQ(OB_SUCCESS, table_schema_.get_column_ids(col_descs)); + ret = datum_utils.init(col_descs, rowkey_column_count, lib::is_oracle_mode(), allocator_); + param.tablet_id_ = table_schema_.get_tablet_id(); + param.table_data_desc_ = table_data_desc_; + param.datum_utils_ = &datum_utils; + param.file_mgr_ = file_mgr_; + ObDirectLoadSSTableBuilder sstable_builder1; + ObDirectLoadSSTableBuilder sstable_builder2; + ret = sstable_builder1.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.init(param); + ASSERT_EQ(OB_SUCCESS, ret); + + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + if (i % 100 == 0) { + int32_t value1_size = 20 * 1024; + char *ptr1 = nullptr; + test_alloc(ptr1, value1_size); + ASSERT_TRUE(nullptr != ptr1); + row->storage_datums_[24].set_string(ObString(value1_size, ptr1)); + } + array1.push_back(row); + ret = sstable_builder1.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + for (int64_t i = 0; i < test_row_num; ++i) { + ObDatumRow *row = OB_NEWx(ObDatumRow, (&allocator_)); + ASSERT_EQ(OB_SUCCESS, row->init(allocator_, column_num)); + ASSERT_EQ(OB_SUCCESS, row_generate_.get_next_row(*row)); + if (i % 100 == 0) { + int32_t value1_size = 20 * 1024; + char *ptr1 = nullptr; + test_alloc(ptr1, value1_size); + ASSERT_TRUE(nullptr != ptr1); + row->storage_datums_[24].set_string(ObString(value1_size, ptr1)); + } + array2.push_back(row); + ret = sstable_builder2.append_row(table_schema_.get_tablet_id(), *row); + ASSERT_EQ(OB_SUCCESS, ret); + } + + ret = sstable_builder1.close(); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.close(); + ASSERT_EQ(OB_SUCCESS, ret); + + ObArray table_array1; + ObArray table_array2; + ret = sstable_builder1.get_tables(table_array1, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ret = sstable_builder2.get_tables(table_array2, allocator_); + ASSERT_EQ(OB_SUCCESS, ret); + ObDirectLoadSSTable *sstable1 = nullptr; + sstable1 = dynamic_cast(table_array1.at(0)); + ASSERT_TRUE(nullptr != sstable1); + + ObDirectLoadSSTable *sstable2 = nullptr; + sstable2 = dynamic_cast(table_array2.at(0)); + ASSERT_TRUE(nullptr != sstable2); + + ObIDirectLoadPartitionTable *new_sstable = nullptr; + ObDirectLoadSSTableCompactor compactor; + ObDirectLoadSSTableCompactParam compact_param; + ObTableAccessParam access_param; + ObTableAccessContext access_ctx; + compact_param.tablet_id_ = table_schema_.get_tablet_id(); + compact_param.table_data_desc_ = table_data_desc_; + ObTableReadInfo read_info; + + // init access_param + ret = read_info.init(allocator_, table_schema_.get_column_count(), + table_schema_.get_rowkey_column_num(), lib::is_oracle_mode(), col_descs); + ASSERT_EQ(OB_SUCCESS, ret); + ret = access_param.init_merge_param(table_schema_.get_table_id(), param.tablet_id_, read_info); + ASSERT_EQ(OB_SUCCESS, ret); + + compact_param.datum_utils_ = &(read_info.datum_utils_); + ret = compactor.init(compact_param); + ASSERT_EQ(OB_SUCCESS, ret); + ret = compactor.add_table(sstable1); + ASSERT_EQ(OB_SUCCESS, ret); + ret = compactor.add_table(sstable2); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_EQ(OB_SUCCESS, compactor.compact()); + ASSERT_EQ(OB_SUCCESS, compactor.get_table(new_sstable, allocator_)); + ObDirectLoadSSTable *sstable = dynamic_cast(new_sstable); + ASSERT_TRUE(nullptr != sstable); + + ObDirectLoadSSTableScanner *iter = nullptr; + ObDatumRange datum_range; + int64_t start_count = rand() % test_row_num; + int64_t end_count = rand() % test_row_num; + int64_t max = std::max(start_count, end_count); + int64_t min = std::min(start_count, end_count); + ObDatumRowkey start_key(array1.at(min)->storage_datums_, rowkey_column_count); + ObDatumRowkey end_key(array2.at(max)->storage_datums_, rowkey_column_count); + + datum_range.set_start_key(start_key); + datum_range.set_end_key(end_key); + + // init access_ctx + const int64_t snapshot_version = ObTimeUtil::current_time_ns(); + ObQueryFlag query_flag(ObQueryFlag::Forward, false /*daily_merge*/, true /*optimize*/, + true /*whole_macro_scan*/, false /*full_row*/, false /*index_back*/, + false /*query_stat*/ + ); + ObVersionRange trans_version_range; + query_flag.multi_version_minor_merge_ = false; + trans_version_range.multi_version_start_ = 0; + trans_version_range.base_version_ = 0; + trans_version_range.snapshot_version_ = snapshot_version; + ObStoreCtx store_ctx; + access_ctx.store_ctx_ = &store_ctx; + access_ctx.stmt_allocator_ = &allocator_; + access_ctx.allocator_ = &allocator_; + access_ctx.is_inited_ = true; + + // left closed ,right closed + datum_range.set_left_closed(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + const ObDatumRow *datum_row = nullptr; + for (int64_t i = min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_closed(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t new_min = min + 1; + for (int64_t i = new_min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i <= max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left closed ,right open + datum_range.set_left_closed(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = min; i <= 99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + + // left open ,right closed + datum_range.set_left_open(); + datum_range.set_right_open(); + ret = sstable->scan(param.table_data_desc_, datum_range, param.datum_utils_, allocator_, iter); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = new_min; i <=99999; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array1.at(i)); + } + for (int64_t i = 0; i < max; ++i) { + ASSERT_EQ(OB_SUCCESS, iter->get_next_row(datum_row)); + check_row(datum_row, array2.at(i)); + } + ASSERT_EQ(OB_ITER_END, iter->get_next_row(datum_row)); + int64_t index_item_count = sstable->get_meta().index_item_count_; + ObDirectLoadIndexBlockMetaIterator* meta_iter; + ObDirectLoadIndexBlockMeta meta; + ret = sstable->scan_index_block_meta(allocator_, meta_iter); + ASSERT_EQ(OB_SUCCESS, ret); + int64_t number = meta_iter->get_total_block_count(); + for (int64_t i = 0; i < number; ++i) { + ASSERT_EQ(OB_SUCCESS, meta_iter->get_next(meta)); + } + ASSERT_EQ(OB_ITER_END, meta_iter->get_next(meta)); + + for (int64_t i = 0; i < array1.count(); ++i) { + ObDatumRow *row = array1.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } + for (int64_t i = 0; i < array2.count(); ++i) { + ObDatumRow *row = array2.at(i); + row->~ObDatumRow(); + allocator_.free(row); + } +} + +} // end namespace unittest +} // end namespace oceanbase + +int main(int argc, char **argv) +{ + system("rm -rf test_direct_load_data_block_writer.log"); + OB_LOGGER.set_file_name("test_direct_load_data_block_writer.log", true, true); + oceanbase::common::ObLogger::get_logger().set_log_level("INFO"); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/unittest/storage/direct_load/test_direct_load_index_block_writer.cpp b/unittest/storage/direct_load/test_direct_load_index_block_writer.cpp new file mode 100644 index 0000000000..693f088af0 --- /dev/null +++ b/unittest/storage/direct_load/test_direct_load_index_block_writer.cpp @@ -0,0 +1,196 @@ +// Copyright 2014-2014 Alibaba Inc. All Rights Reserved. +// Author: +// yiren.ly +// +// This file defines test_direct_load_data_block_writer.cpp +#include +#define private public +#define protected public +#include +#include +#include "../unittest/storage/blocksstable/ob_data_file_prepare.h" +#include "../unittest/storage/blocksstable/ob_row_generate.h" +#include "observer/table_load/ob_table_load_partition_location.h" +#include "share/ob_simple_mem_limit_getter.h" +#include "storage/blocksstable/ob_tmp_file.h" +#include "storage/direct_load/ob_direct_load_tmp_file.h" +#include "storage/direct_load/ob_direct_load_sstable_scanner.h" +#include "storage/ob_i_store.h" +namespace oceanbase +{ +using namespace common; +using namespace blocksstable; +using namespace storage; +using namespace share::schema; + +static ObSimpleMemLimitGetter getter; + +namespace unittest +{ +class TestIndexBlockWriter : public TestDataFilePrepare +{ +public: + static const int64_t rowkey_column_count = 2; + // Every ObObjType from ObTinyIntType to ObHexStringType inclusive. + // Skip ObNullType and ObExtendType because for external usage, a column type + // can't be NULL or NOP. + static const int64_t column_num = ObHexStringType; + static const int64_t macro_block_size = 2L * 8 * 1024L; + static const int64_t SNAPSHOT_VERSION = 2; + +public: + TestIndexBlockWriter() : TestDataFilePrepare(&getter, "TestIndexBlockWriter", 2 * 1024 * 1024, 2048){}; + virtual void SetUp(); + virtual void TearDown(); + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void test_alloc(char *&ptr, const int64_t size); + +private: + void prepare_schema(); + +protected: + ObTableSchema table_schema_; + ObRowGenerate row_generate_; + ObDirectLoadTmpFileManager *file_mgr_; + ObArenaAllocator allocator_; +}; + +void TestIndexBlockWriter::test_alloc(char *&ptr, const int64_t size) +{ + ptr = reinterpret_cast(allocator_.alloc(size)); + ASSERT_TRUE(nullptr != ptr); +} + +void TestIndexBlockWriter::prepare_schema() +{ + ObColumnSchemaV2 column; + int64_t table_id = 3001; + int64_t micro_block_size = 16 * 1024; + // init table schema + table_schema_.reset(); + ASSERT_EQ(OB_SUCCESS, table_schema_.set_table_name("test_macro_file")); + table_schema_.set_tenant_id(1); + table_schema_.set_tablegroup_id(1); + table_schema_.set_database_id(1); + table_schema_.set_table_id(table_id); + table_schema_.set_rowkey_column_num(rowkey_column_count); + table_schema_.set_max_used_column_id(column_num); + table_schema_.set_block_size(micro_block_size); + table_schema_.set_compress_func_name("none"); + // init column + char name[OB_MAX_FILE_NAME_LENGTH]; + memset(name, 0, sizeof(name)); + for (int64_t i = 0; i < column_num; ++i) { + ObObjType obj_type = static_cast(i + 1); + column.reset(); + column.set_table_id(table_id); + column.set_column_id(i + OB_APP_MIN_COLUMN_ID); + sprintf(name, "test%020ld", i); + ASSERT_EQ(OB_SUCCESS, column.set_column_name(name)); + column.set_data_type(obj_type); + if (obj_type == common::ObIntType) { + column.set_rowkey_position(1); + } else if (obj_type == common::ObNumberType) { + column.set_rowkey_position(2); + } else { + column.set_rowkey_position(0); + } + column.set_collation_type(ObCollationType::CS_TYPE_UTF8MB4_GENERAL_CI); + ASSERT_EQ(OB_SUCCESS, table_schema_.add_column(column)); + } + ObTmpFileManager::get_instance().destroy(); +} + +void TestIndexBlockWriter::SetUp() +{ + int ret = OB_SUCCESS; + // init file + const int64_t bucket_num = 1024; + const int64_t max_cache_size = 1024 * 1024 * 1024; + const int64_t block_size = common::OB_MALLOC_BIG_BLOCK_SIZE; + TestDataFilePrepare::SetUp(); + prepare_schema(); + file_mgr_ = OB_NEWx(ObDirectLoadTmpFileManager, (&allocator_)); + ret = file_mgr_->init(table_schema_.get_tenant_id()); + ASSERT_EQ(OB_SUCCESS, ret); + // init ObRowGenerate + ASSERT_EQ(OB_SUCCESS, row_generate_.init(table_schema_)); + + ret = getter.add_tenant(1, 8L * 1024L * 1024L, 2L * 1024L * 1024L * 1024L); + ASSERT_EQ(OB_SUCCESS, ret); + ret = ObKVGlobalCache::get_instance().init(&getter, bucket_num, max_cache_size, block_size); + if (OB_INIT_TWICE == ret) { + ret = OB_SUCCESS; + } else { + ASSERT_EQ(OB_SUCCESS, ret); + } + // set observer memory limit + CHUNK_MGR.set_limit(8L * 1024L * 1024L * 1024L); + ret = ObTmpFileManager::get_instance().init(); + ASSERT_EQ(OB_SUCCESS, ret); + static ObTenantBase tenant_ctx(1); + ObTenantEnv::set_tenant(&tenant_ctx); + ObTenantIOManager *io_service = nullptr; + EXPECT_EQ(OB_SUCCESS, ObTenantIOManager::mtl_init(io_service)); +} + +void TestIndexBlockWriter::TearDown() +{ + file_mgr_->~ObDirectLoadTmpFileManager(); + table_schema_.reset(); + ObTmpFileManager::get_instance().destroy(); + ObKVGlobalCache::get_instance().destroy(); + TestDataFilePrepare::TearDown(); +} + +TEST_F(TestIndexBlockWriter, test_write_and_read) +{ + int ret = OB_SUCCESS; + ObArray array; + int64_t sum = 0; + ObDirectLoadIndexBlockWriter index_block_writer; + ObDirectLoadIndexBlockReader index_block_reader; + uint64_t tenant_id = table_schema_.get_tenant_id(); + ObDirectLoadTmpFileHandle file_handle; + + const int64_t index_block_size = DIO_ALIGN_SIZE; + int64_t dir_id = -1; + ret = file_mgr_->alloc_dir(dir_id); + ASSERT_EQ(OB_SUCCESS, ret); + ret= file_mgr_->alloc_file(dir_id, file_handle); + ASSERT_EQ(OB_SUCCESS, ret); + // init index block writer + ret = index_block_writer.init(tenant_id, DIO_ALIGN_SIZE, file_handle); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < 1000; ++i) { + ObDirectLoadIndexBlockItem item; + sum += rand() % 1024; + item.end_offset_ = sum; + array.push_back(item.end_offset_); + ret = index_block_writer.append_row(100, item); + ASSERT_EQ(OB_SUCCESS, ret); + } + ret = index_block_writer.close(); + ASSERT_EQ(OB_SUCCESS, ret); + ret = index_block_reader.init(1, DIO_ALIGN_SIZE, file_handle); + ASSERT_EQ(OB_SUCCESS, ret); + for (int64_t i = 0; i < 1000; ++i) { + ObDirectLoadIndexInfo info; + ret = index_block_reader.get_index_info(i, info); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(array.at(i) == (info.offset_ + info.size_)); + } +} + +} // end namespace unittest +} // end namespace oceanbase + +int main(int argc, char **argv) +{ + system("rm -rf test_direct_load_index_block_writer.log"); + OB_LOGGER.set_file_name("test_direct_load_index_block_writer.log", true, true); + oceanbase::common::ObLogger::get_logger().set_log_level("INFO"); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}