From a4c97d03f7bdb6cee2e6f3263654c2f0cd2b0c5b Mon Sep 17 00:00:00 2001 From: nroskill Date: Fri, 24 Feb 2023 14:26:20 +0000 Subject: [PATCH] [FEAT MERGE]vos merge into master Co-authored-by: ZenoWang Co-authored-by: zhjc1124 Co-authored-by: JiahuaChen --- deps/oblib/src/common/ob_local_store.h | 43 - deps/oblib/src/lib/CMakeLists.txt | 2 +- deps/oblib/src/lib/alloc/alloc_func.cpp | 7 + deps/oblib/src/lib/alloc/alloc_func.h | 4 + deps/oblib/src/lib/alloc/alloc_struct.h | 4 +- deps/oblib/src/lib/alloc/block_set.h | 2 + deps/oblib/src/lib/alloc/malloc_hook.cpp | 31 +- deps/oblib/src/lib/alloc/malloc_hook.h | 6 + deps/oblib/src/lib/alloc/memory_dump.cpp | 63 +- deps/oblib/src/lib/alloc/memory_dump.h | 4 + deps/oblib/src/lib/alloc/ob_futex_v2.cpp | 5 +- .../src/lib/alloc/ob_malloc_allocator.cpp | 41 +- .../ob_malloc_sample_struct.cpp} | 21 +- .../src/lib/alloc/ob_malloc_sample_struct.h | 182 +++ .../src/lib/alloc/ob_tenant_ctx_allocator.cpp | 185 ++- .../src/lib/alloc/ob_tenant_ctx_allocator.h | 13 + deps/oblib/src/lib/alloc/object_set.cpp | 2 + deps/oblib/src/lib/alloc/object_set.h | 2 + .../src/lib/allocator/ob_allocator_v2.cpp | 54 +- .../src/lib/allocator/ob_mem_leak_checker.h | 2 +- deps/oblib/src/lib/allocator/ob_mod_define.h | 2 + .../src/lib/allocator/ob_page_manager.cpp | 5 +- deps/oblib/src/lib/allocator/ob_tc_malloc.cpp | 8 +- deps/oblib/src/lib/lock/ob_futex.cpp | 7 +- deps/oblib/src/lib/lock/ob_futex.h | 21 +- deps/oblib/src/lib/lock/ob_latch.cpp | 72 +- deps/oblib/src/lib/lock/ob_latch.h | 84 +- deps/oblib/src/lib/lock/ob_spin_rwlock.h | 1 + deps/oblib/src/lib/lock/ob_tc_rwlock.h | 16 + deps/oblib/src/lib/ob_define.h | 23 +- deps/oblib/src/lib/ob_lib_config.cpp | 24 +- deps/oblib/src/lib/ob_lib_config.h | 56 +- .../lib/objectpool/ob_concurrency_objpool.cpp | 55 +- .../lib/objectpool/ob_concurrency_objpool.h | 75 +- deps/oblib/src/lib/objectpool/ob_pool.ipp | 3 + .../src/lib/oblog/ob_base_log_writer.cpp | 13 +- deps/oblib/src/lib/oblog/ob_base_log_writer.h | 2 +- deps/oblib/src/lib/oblog/ob_log.h | 59 +- deps/oblib/src/lib/queue/ob_priority_queue.h | 20 +- deps/oblib/src/lib/resource/achunk_mgr.cpp | 6 +- deps/oblib/src/lib/resource/achunk_mgr.h | 3 + .../src/lib/resource/ob_resource_mgr.cpp | 6 + deps/oblib/src/lib/stat/ob_di_cache.cpp | 4 +- deps/oblib/src/lib/stat/ob_di_tls.h | 202 +-- deps/oblib/src/lib/stat/ob_diagnose_info.cpp | 4 +- deps/oblib/src/lib/stat/ob_session_stat.cpp | 6 +- deps/oblib/src/lib/stat/ob_session_stat.h | 4 +- .../src/lib/statistic_event/ob_stat_event.h | 8 +- deps/oblib/src/lib/task/ob_timer.cpp | 1 + .../src/lib/thread/ob_async_task_queue.cpp | 1 + .../src/lib/thread/ob_reentrant_thread.h | 6 +- deps/oblib/src/lib/thread/ob_thread_name.h | 2 + .../lib/thread/protected_stack_allocator.h | 2 +- deps/oblib/src/lib/thread/thread.cpp | 3 +- deps/oblib/src/lib/thread/thread.h | 18 +- .../src/lib/thread/thread_mgr_interface.h | 1 + deps/oblib/src/lib/thread/threads.cpp | 5 - deps/oblib/src/lib/thread/threads.h | 16 +- .../src/lib/thread_local/ob_tsi_factory.h | 452 +------ deps/oblib/src/lib/utility/ob_macro_utils.h | 279 ++-- .../src/lib/utility/ob_unify_serialize.h | 518 +++----- deps/oblib/src/lib/utility/utility.h | 1 + deps/oblib/src/lib/worker.cpp | 9 +- deps/oblib/src/lib/worker.h | 214 +--- deps/oblib/src/rpc/CMakeLists.txt | 1 - deps/oblib/src/rpc/frame/ob_net_easy.cpp | 20 +- deps/oblib/src/rpc/frame/ob_req_deliver.h | 1 + .../src/rpc/frame/ob_req_queue_thread.cpp | 2 +- deps/oblib/src/rpc/frame/ob_req_transport.h | 3 +- .../src/rpc/obmysql/ob_mysql_request_utils.h | 1 + deps/oblib/src/rpc/obmysql/ob_sql_nio.cpp | 154 ++- deps/oblib/src/rpc/obmysql/ob_sql_nio.h | 21 +- .../src/rpc/obmysql/ob_sql_nio_server.cpp | 11 +- .../oblib/src/rpc/obmysql/ob_sql_nio_server.h | 9 +- .../src/rpc/obmysql/ob_sql_sock_handler.h | 4 +- .../src/rpc/obmysql/ob_sql_sock_session.cpp | 34 +- .../src/rpc/obmysql/ob_sql_sock_session.h | 4 +- deps/oblib/src/rpc/obrpc/ob_listener.cpp | 36 + deps/oblib/src/rpc/obrpc/ob_listener.h | 1 + deps/oblib/src/rpc/obrpc/ob_net_client.cpp | 4 + deps/oblib/src/rpc/obrpc/ob_nio_interface.h | 72 -- deps/oblib/src/rpc/obrpc/ob_poc_nio.cpp | 114 -- deps/oblib/src/rpc/obrpc/ob_poc_nio.h | 36 - deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.cpp | 179 ++- deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.h | 178 ++- .../rpc/obrpc/ob_poc_rpc_request_operator.cpp | 2 + .../oblib/src/rpc/obrpc/ob_poc_rpc_server.cpp | 177 ++- deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.h | 40 +- deps/oblib/src/rpc/obrpc/ob_rpc_endec.cpp | 2 +- deps/oblib/src/rpc/obrpc/ob_rpc_endec.h | 50 +- deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.cpp | 44 +- deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.h | 9 +- deps/oblib/src/rpc/obrpc/ob_rpc_opts.h | 2 - .../src/rpc/obrpc/ob_rpc_processor_base.cpp | 2 +- .../src/rpc/obrpc/ob_rpc_processor_base.h | 4 +- deps/oblib/src/rpc/obrpc/ob_rpc_proxy.cpp | 113 +- deps/oblib/src/rpc/obrpc/ob_rpc_proxy.h | 20 +- deps/oblib/src/rpc/obrpc/ob_rpc_proxy.ipp | 281 ++-- .../oblib/src/rpc/obrpc/ob_rpc_proxy_macros.h | 337 ++--- deps/oblib/src/rpc/pnio/README.md | 18 + deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.c | 110 ++ deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.h | 11 + deps/oblib/src/rpc/pnio/alloc/chunk_cache.c | 42 + deps/oblib/src/rpc/pnio/alloc/chunk_cache.h | 10 + deps/oblib/src/rpc/pnio/alloc/fifo_alloc.c | 76 ++ deps/oblib/src/rpc/pnio/alloc/fifo_alloc.h | 8 + deps/oblib/src/rpc/pnio/alloc/mod_alloc.c | 77 ++ deps/oblib/src/rpc/pnio/alloc/mod_alloc.h | 10 + deps/oblib/src/rpc/pnio/alloc/mod_define.h | 13 + deps/oblib/src/rpc/pnio/alloc/ref_alloc.c | 16 + deps/oblib/src/rpc/pnio/alloc/ref_alloc.h | 2 + deps/oblib/src/rpc/pnio/config.h | 23 + deps/oblib/src/rpc/pnio/cpp/ready_flag.h | 17 + deps/oblib/src/rpc/pnio/cpp/rpc_interface.h | 228 ++++ deps/oblib/src/rpc/pnio/cpp/rpc_mem_pool.h | 10 + deps/oblib/src/rpc/pnio/cpp/simple_mem_pool.h | 43 + deps/oblib/src/rpc/pnio/cpp/sync_resp_cb.h | 30 + deps/oblib/src/rpc/pnio/ds/counter.h | 26 + deps/oblib/src/rpc/pnio/ds/dlink.c | 6 + deps/oblib/src/rpc/pnio/ds/dlink.h | 36 + deps/oblib/src/rpc/pnio/ds/fixed_queue.c | 11 + deps/oblib/src/rpc/pnio/ds/fixed_queue.h | 44 + deps/oblib/src/rpc/pnio/ds/fixed_stack.c | 7 + deps/oblib/src/rpc/pnio/ds/fixed_stack.h | 53 + deps/oblib/src/rpc/pnio/ds/hash.c | 42 + deps/oblib/src/rpc/pnio/ds/hash.h | 1 + deps/oblib/src/rpc/pnio/ds/hash_map.c | 51 + deps/oblib/src/rpc/pnio/ds/hash_map.h | 10 + deps/oblib/src/rpc/pnio/ds/id_map.c | 32 + deps/oblib/src/rpc/pnio/ds/id_map.h | 18 + deps/oblib/src/rpc/pnio/ds/ihash_map.c | 37 + deps/oblib/src/rpc/pnio/ds/ihash_map.h | 3 + deps/oblib/src/rpc/pnio/ds/link-queue.h | 49 + deps/oblib/src/rpc/pnio/ds/link.c | 5 + deps/oblib/src/rpc/pnio/ds/link.h | 31 + deps/oblib/src/rpc/pnio/ds/queue.c | 10 + deps/oblib/src/rpc/pnio/ds/queue.h | 31 + deps/oblib/src/rpc/pnio/ds/sc_queue.c | 21 + deps/oblib/src/rpc/pnio/ds/sc_queue.h | 42 + deps/oblib/src/rpc/pnio/ds/str_type.c | 2 + deps/oblib/src/rpc/pnio/ds/str_type.h | 10 + deps/oblib/src/rpc/pnio/gen-ns.py | 23 + deps/oblib/src/rpc/pnio/interface/group.c | 477 +++++++ deps/oblib/src/rpc/pnio/interface/group.h | 53 + deps/oblib/src/rpc/pnio/io/eloop.c | 107 ++ deps/oblib/src/rpc/pnio/io/eloop.h | 11 + deps/oblib/src/rpc/pnio/io/evfd.c | 23 + deps/oblib/src/rpc/pnio/io/evfd.h | 8 + deps/oblib/src/rpc/pnio/io/ibuffer.c | 100 ++ deps/oblib/src/rpc/pnio/io/ibuffer.h | 15 + deps/oblib/src/rpc/pnio/io/io_func.c | 127 ++ deps/oblib/src/rpc/pnio/io/io_func.h | 18 + deps/oblib/src/rpc/pnio/io/iov.c | 3 + deps/oblib/src/rpc/pnio/io/iov.h | 14 + deps/oblib/src/rpc/pnio/io/msg.c | 1 + deps/oblib/src/rpc/pnio/io/msg.h | 11 + deps/oblib/src/rpc/pnio/io/sock.c | 14 + deps/oblib/src/rpc/pnio/io/sock.h | 34 + deps/oblib/src/rpc/pnio/io/sock_io.c | 50 + deps/oblib/src/rpc/pnio/io/sock_io.h | 4 + deps/oblib/src/rpc/pnio/io/time_wheel.c | 87 ++ deps/oblib/src/rpc/pnio/io/time_wheel.h | 13 + deps/oblib/src/rpc/pnio/io/timerfd.c | 19 + deps/oblib/src/rpc/pnio/io/timerfd.h | 7 + deps/oblib/src/rpc/pnio/io/write_queue.c | 79 ++ deps/oblib/src/rpc/pnio/io/write_queue.h | 12 + deps/oblib/src/rpc/pnio/nio/addr.c | 69 + deps/oblib/src/rpc/pnio/nio/addr.h | 17 + deps/oblib/src/rpc/pnio/nio/decode.t.h | 17 + deps/oblib/src/rpc/pnio/nio/easy_head.c | 4 + deps/oblib/src/rpc/pnio/nio/easy_head.h | 50 + deps/oblib/src/rpc/pnio/nio/handle_io.t.h | 60 + deps/oblib/src/rpc/pnio/nio/inet.c | 119 ++ deps/oblib/src/rpc/pnio/nio/inet.h | 14 + deps/oblib/src/rpc/pnio/nio/listener.c | 138 ++ deps/oblib/src/rpc/pnio/nio/listener.h | 11 + deps/oblib/src/rpc/pnio/nio/listenfd.c | 72 ++ deps/oblib/src/rpc/pnio/nio/listenfd.h | 9 + deps/oblib/src/rpc/pnio/nio/msg_decode.c | 2 + deps/oblib/src/rpc/pnio/nio/msg_decode.h | 11 + deps/oblib/src/rpc/pnio/nio/nio-tpl-ns.h | 41 + deps/oblib/src/rpc/pnio/nio/packet_client.c | 44 + deps/oblib/src/rpc/pnio/nio/packet_client.h | 60 + deps/oblib/src/rpc/pnio/nio/packet_server.c | 52 + deps/oblib/src/rpc/pnio/nio/packet_server.h | 45 + deps/oblib/src/rpc/pnio/nio/pktc_post.h | 112 ++ deps/oblib/src/rpc/pnio/nio/pktc_resp.h | 54 + deps/oblib/src/rpc/pnio/nio/pktc_sk_factory.h | 71 ++ deps/oblib/src/rpc/pnio/nio/pktc_wait.c | 2 + deps/oblib/src/rpc/pnio/nio/pktc_wait.h | 23 + deps/oblib/src/rpc/pnio/nio/pkts_post.h | 43 + deps/oblib/src/rpc/pnio/nio/pkts_sk_factory.h | 45 + deps/oblib/src/rpc/pnio/nio/timeout.h | 9 + deps/oblib/src/rpc/pnio/nio/write_queue.t.h | 36 + deps/oblib/src/rpc/pnio/pkt-nio.c | 47 + deps/oblib/src/rpc/pnio/pkt-nio.h | 53 + deps/oblib/src/rpc/pnio/r0/atomic.h | 19 + deps/oblib/src/rpc/pnio/r0/debug.c | 25 + deps/oblib/src/rpc/pnio/r0/debug.h | 73 ++ deps/oblib/src/rpc/pnio/r0/define.c | 1 + deps/oblib/src/rpc/pnio/r0/define.h | 38 + deps/oblib/src/rpc/pnio/r0/format.c | 52 + deps/oblib/src/rpc/pnio/r0/format.h | 13 + deps/oblib/src/rpc/pnio/r0/futex.c | 22 + deps/oblib/src/rpc/pnio/r0/futex.h | 2 + deps/oblib/src/rpc/pnio/r0/get_us.c | 13 + deps/oblib/src/rpc/pnio/r0/get_us.h | 2 + deps/oblib/src/rpc/pnio/r0/log.c | 42 + deps/oblib/src/rpc/pnio/r0/log.h | 22 + deps/oblib/src/rpc/pnio/test/test-basic.c | 168 +++ deps/oblib/src/rpc/pnio/test/test-cfifo.c | 28 + deps/oblib/src/rpc/pnio/test/test-group.c | 133 ++ deps/oblib/src/rpc/pnio/test/test-nio.cpp | 82 ++ .../allocator/test_allocator_performance.cpp | 73 -- .../unittest/lib/charset/test_charset.cpp | 1 + .../unittest/lib/hash/test_cuckoo_hashmap.cpp | 1 + .../lib/queue/test_priority_queue.cpp | 2 +- .../unittest/lib/stat/test_diagnose_info.cpp | 10 +- .../unittest/lib/thread/test_thread_pool.cpp | 5 - .../lib/utility/test_ob_unify_serialize.cpp | 12 +- src/diagnose/lua/ob_lua_api.cpp | 598 ++++++++- src/diagnose/lua/test.lua | 500 +++++--- src/logservice/cdcservice/ob_cdc_service.cpp | 1 + .../libobcdc/src/ob_concurrent_seq_queue.cpp | 4 +- src/observer/CMakeLists.txt | 3 +- src/observer/layer_perf/ob_layer_perf.cpp | 4 +- src/observer/ob_server.cpp | 1 - src/observer/ob_server_reload_config.cpp | 7 +- src/observer/ob_srv_deliver.cpp | 171 ++- src/observer/ob_srv_deliver.h | 40 +- src/observer/ob_srv_network_frame.cpp | 28 +- src/observer/ob_srv_network_frame.h | 23 + src/observer/ob_tenant_duty_task.cpp | 22 + src/observer/ob_tenant_duty_task.h | 1 + src/observer/omt/ob_multi_tenant.cpp | 212 ++- src/observer/omt/ob_multi_tenant.h | 2 - src/observer/omt/ob_tenant.cpp | 1133 ++++++----------- src/observer/omt/ob_tenant.h | 301 ++--- src/observer/omt/ob_tenant_hook.cpp | 182 +++ src/observer/omt/ob_th_worker.cpp | 159 +-- src/observer/omt/ob_th_worker.h | 164 +-- src/observer/omt/ob_worker_pool.cpp | 174 --- src/observer/omt/ob_worker_pool.h | 77 -- .../ob_all_virtual_dump_tenant_info.cpp | 16 +- .../ob_all_virtual_malloc_sample_info.cpp | 149 +++ .../ob_all_virtual_malloc_sample_info.h | 59 + .../ob_virtual_table_iterator_factory.cpp | 9 + src/rootserver/ddl_task/ob_ddl_scheduler.cpp | 2 +- src/rootserver/ob_root_service.cpp | 2 - src/rootserver/ob_rs_reentrant_thread.cpp | 4 +- src/rootserver/ob_thread_idling.cpp | 3 + src/share/config/ob_config_manager.cpp | 2 +- src/share/config/ob_server_config.cpp | 7 +- .../ob_lcl_batch_sender_thread.cpp | 1 + .../ob_inner_table_schema.12351_12400.cpp | 189 +++ src/share/inner_table/ob_inner_table_schema.h | 11 +- .../ob_inner_table_schema_constants.h | 2 + .../inner_table/ob_inner_table_schema_def.py | 24 +- .../location_cache/ob_tablet_ls_service.cpp | 2 +- src/share/ob_common_rpc_proxy.h | 19 - src/share/ob_ddl_task_executor.cpp | 2 +- src/share/ob_debug_sync.cpp | 2 +- src/share/ob_occam_thread_pool.h | 1 + src/share/parameter/ob_parameter_seed.ipp | 35 +- src/share/rc/ob_tenant_base.h | 7 +- src/share/resource_manager/ob_cgroup_ctrl.cpp | 142 ++- src/share/resource_manager/ob_cgroup_ctrl.h | 5 +- src/share/resource_manager/ob_group_list.h | 3 + src/share/restore/ob_log_restore_source.h | 4 +- src/share/scheduler/ob_dag_scheduler.h | 1 + .../ob_maintain_dependency_info_task.cpp | 1 + src/sql/resolver/ob_resolver_define.h | 3 +- .../blocksstable/ob_micro_block_cache.cpp | 8 +- .../blocksstable/ob_sstable_meta_info.cpp | 1 + src/storage/slog/ob_storage_log_writer.cpp | 2 +- src/storage/tablet/ob_tablet_memtable_mgr.cpp | 2 +- src/storage/tx/ob_trans_ctx_lock.h | 16 - src/storage/tx/ob_tx_api.cpp | 7 +- src/storage/tx/ob_tx_free_route_msg.h | 4 +- src/storage/tx/ob_tx_serialization.h | 22 +- .../all_virtual_sys_parameter_stat.result | 9 + .../r/mysql/inner_table_overall.result | 1 + unittest/observer/CMakeLists.txt | 1 - unittest/observer/omt/test_worker_pool.cpp | 64 - 284 files changed, 9655 insertions(+), 4755 deletions(-) delete mode 100644 deps/oblib/src/common/ob_local_store.h rename deps/oblib/src/lib/{thread_local/ob_tsi_factory.cpp => alloc/ob_malloc_sample_struct.cpp} (57%) create mode 100644 deps/oblib/src/lib/alloc/ob_malloc_sample_struct.h delete mode 100644 deps/oblib/src/rpc/obrpc/ob_nio_interface.h delete mode 100644 deps/oblib/src/rpc/obrpc/ob_poc_nio.cpp delete mode 100644 deps/oblib/src/rpc/obrpc/ob_poc_nio.h create mode 100644 deps/oblib/src/rpc/pnio/README.md create mode 100644 deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.c create mode 100644 deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.h create mode 100644 deps/oblib/src/rpc/pnio/alloc/chunk_cache.c create mode 100644 deps/oblib/src/rpc/pnio/alloc/chunk_cache.h create mode 100644 deps/oblib/src/rpc/pnio/alloc/fifo_alloc.c create mode 100644 deps/oblib/src/rpc/pnio/alloc/fifo_alloc.h create mode 100644 deps/oblib/src/rpc/pnio/alloc/mod_alloc.c create mode 100644 deps/oblib/src/rpc/pnio/alloc/mod_alloc.h create mode 100644 deps/oblib/src/rpc/pnio/alloc/mod_define.h create mode 100644 deps/oblib/src/rpc/pnio/alloc/ref_alloc.c create mode 100644 deps/oblib/src/rpc/pnio/alloc/ref_alloc.h create mode 100644 deps/oblib/src/rpc/pnio/config.h create mode 100644 deps/oblib/src/rpc/pnio/cpp/ready_flag.h create mode 100644 deps/oblib/src/rpc/pnio/cpp/rpc_interface.h create mode 100644 deps/oblib/src/rpc/pnio/cpp/rpc_mem_pool.h create mode 100644 deps/oblib/src/rpc/pnio/cpp/simple_mem_pool.h create mode 100644 deps/oblib/src/rpc/pnio/cpp/sync_resp_cb.h create mode 100644 deps/oblib/src/rpc/pnio/ds/counter.h create mode 100644 deps/oblib/src/rpc/pnio/ds/dlink.c create mode 100644 deps/oblib/src/rpc/pnio/ds/dlink.h create mode 100644 deps/oblib/src/rpc/pnio/ds/fixed_queue.c create mode 100644 deps/oblib/src/rpc/pnio/ds/fixed_queue.h create mode 100644 deps/oblib/src/rpc/pnio/ds/fixed_stack.c create mode 100644 deps/oblib/src/rpc/pnio/ds/fixed_stack.h create mode 100644 deps/oblib/src/rpc/pnio/ds/hash.c create mode 100644 deps/oblib/src/rpc/pnio/ds/hash.h create mode 100644 deps/oblib/src/rpc/pnio/ds/hash_map.c create mode 100644 deps/oblib/src/rpc/pnio/ds/hash_map.h create mode 100644 deps/oblib/src/rpc/pnio/ds/id_map.c create mode 100644 deps/oblib/src/rpc/pnio/ds/id_map.h create mode 100644 deps/oblib/src/rpc/pnio/ds/ihash_map.c create mode 100644 deps/oblib/src/rpc/pnio/ds/ihash_map.h create mode 100644 deps/oblib/src/rpc/pnio/ds/link-queue.h create mode 100644 deps/oblib/src/rpc/pnio/ds/link.c create mode 100644 deps/oblib/src/rpc/pnio/ds/link.h create mode 100644 deps/oblib/src/rpc/pnio/ds/queue.c create mode 100644 deps/oblib/src/rpc/pnio/ds/queue.h create mode 100644 deps/oblib/src/rpc/pnio/ds/sc_queue.c create mode 100644 deps/oblib/src/rpc/pnio/ds/sc_queue.h create mode 100644 deps/oblib/src/rpc/pnio/ds/str_type.c create mode 100644 deps/oblib/src/rpc/pnio/ds/str_type.h create mode 100755 deps/oblib/src/rpc/pnio/gen-ns.py create mode 100644 deps/oblib/src/rpc/pnio/interface/group.c create mode 100644 deps/oblib/src/rpc/pnio/interface/group.h create mode 100644 deps/oblib/src/rpc/pnio/io/eloop.c create mode 100644 deps/oblib/src/rpc/pnio/io/eloop.h create mode 100644 deps/oblib/src/rpc/pnio/io/evfd.c create mode 100644 deps/oblib/src/rpc/pnio/io/evfd.h create mode 100644 deps/oblib/src/rpc/pnio/io/ibuffer.c create mode 100644 deps/oblib/src/rpc/pnio/io/ibuffer.h create mode 100644 deps/oblib/src/rpc/pnio/io/io_func.c create mode 100644 deps/oblib/src/rpc/pnio/io/io_func.h create mode 100644 deps/oblib/src/rpc/pnio/io/iov.c create mode 100644 deps/oblib/src/rpc/pnio/io/iov.h create mode 100644 deps/oblib/src/rpc/pnio/io/msg.c create mode 100644 deps/oblib/src/rpc/pnio/io/msg.h create mode 100644 deps/oblib/src/rpc/pnio/io/sock.c create mode 100644 deps/oblib/src/rpc/pnio/io/sock.h create mode 100644 deps/oblib/src/rpc/pnio/io/sock_io.c create mode 100644 deps/oblib/src/rpc/pnio/io/sock_io.h create mode 100644 deps/oblib/src/rpc/pnio/io/time_wheel.c create mode 100644 deps/oblib/src/rpc/pnio/io/time_wheel.h create mode 100644 deps/oblib/src/rpc/pnio/io/timerfd.c create mode 100644 deps/oblib/src/rpc/pnio/io/timerfd.h create mode 100644 deps/oblib/src/rpc/pnio/io/write_queue.c create mode 100644 deps/oblib/src/rpc/pnio/io/write_queue.h create mode 100644 deps/oblib/src/rpc/pnio/nio/addr.c create mode 100644 deps/oblib/src/rpc/pnio/nio/addr.h create mode 100644 deps/oblib/src/rpc/pnio/nio/decode.t.h create mode 100644 deps/oblib/src/rpc/pnio/nio/easy_head.c create mode 100644 deps/oblib/src/rpc/pnio/nio/easy_head.h create mode 100644 deps/oblib/src/rpc/pnio/nio/handle_io.t.h create mode 100644 deps/oblib/src/rpc/pnio/nio/inet.c create mode 100644 deps/oblib/src/rpc/pnio/nio/inet.h create mode 100644 deps/oblib/src/rpc/pnio/nio/listener.c create mode 100644 deps/oblib/src/rpc/pnio/nio/listener.h create mode 100644 deps/oblib/src/rpc/pnio/nio/listenfd.c create mode 100644 deps/oblib/src/rpc/pnio/nio/listenfd.h create mode 100644 deps/oblib/src/rpc/pnio/nio/msg_decode.c create mode 100644 deps/oblib/src/rpc/pnio/nio/msg_decode.h create mode 100644 deps/oblib/src/rpc/pnio/nio/nio-tpl-ns.h create mode 100644 deps/oblib/src/rpc/pnio/nio/packet_client.c create mode 100644 deps/oblib/src/rpc/pnio/nio/packet_client.h create mode 100644 deps/oblib/src/rpc/pnio/nio/packet_server.c create mode 100644 deps/oblib/src/rpc/pnio/nio/packet_server.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pktc_post.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pktc_resp.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pktc_sk_factory.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pktc_wait.c create mode 100644 deps/oblib/src/rpc/pnio/nio/pktc_wait.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pkts_post.h create mode 100644 deps/oblib/src/rpc/pnio/nio/pkts_sk_factory.h create mode 100644 deps/oblib/src/rpc/pnio/nio/timeout.h create mode 100644 deps/oblib/src/rpc/pnio/nio/write_queue.t.h create mode 100644 deps/oblib/src/rpc/pnio/pkt-nio.c create mode 100644 deps/oblib/src/rpc/pnio/pkt-nio.h create mode 100644 deps/oblib/src/rpc/pnio/r0/atomic.h create mode 100644 deps/oblib/src/rpc/pnio/r0/debug.c create mode 100644 deps/oblib/src/rpc/pnio/r0/debug.h create mode 100644 deps/oblib/src/rpc/pnio/r0/define.c create mode 100644 deps/oblib/src/rpc/pnio/r0/define.h create mode 100644 deps/oblib/src/rpc/pnio/r0/format.c create mode 100644 deps/oblib/src/rpc/pnio/r0/format.h create mode 100644 deps/oblib/src/rpc/pnio/r0/futex.c create mode 100644 deps/oblib/src/rpc/pnio/r0/futex.h create mode 100644 deps/oblib/src/rpc/pnio/r0/get_us.c create mode 100644 deps/oblib/src/rpc/pnio/r0/get_us.h create mode 100644 deps/oblib/src/rpc/pnio/r0/log.c create mode 100644 deps/oblib/src/rpc/pnio/r0/log.h create mode 100644 deps/oblib/src/rpc/pnio/test/test-basic.c create mode 100644 deps/oblib/src/rpc/pnio/test/test-cfifo.c create mode 100644 deps/oblib/src/rpc/pnio/test/test-group.c create mode 100644 deps/oblib/src/rpc/pnio/test/test-nio.cpp create mode 100644 src/observer/omt/ob_tenant_hook.cpp delete mode 100644 src/observer/omt/ob_worker_pool.cpp delete mode 100644 src/observer/omt/ob_worker_pool.h create mode 100644 src/observer/virtual_table/ob_all_virtual_malloc_sample_info.cpp create mode 100644 src/observer/virtual_table/ob_all_virtual_malloc_sample_info.h delete mode 100644 unittest/observer/omt/test_worker_pool.cpp diff --git a/deps/oblib/src/common/ob_local_store.h b/deps/oblib/src/common/ob_local_store.h deleted file mode 100644 index 1e279dfa8..000000000 --- a/deps/oblib/src/common/ob_local_store.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 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_COMMON_LOCAL_STORE_ -#define OCEANBASE_COMMON_LOCAL_STORE_ - -#include "lib/oblog/ob_log_level.h" - -#include - -namespace oceanbase -{ -namespace common -{ -struct ObLocalStore -{ - ObLocalStore() - : stack_addr_(nullptr), stack_size_(0) - {} - ObThreadLogLevel log_level_; - void *stack_addr_; - size_t stack_size_; -}; - -inline ObLocalStore *get_local_store() -{ - // use thread local for raw thread. - RLOCAL_INLINE(ObLocalStore, default_local_store); - return &default_local_store; -} - -} -} -#endif diff --git a/deps/oblib/src/lib/CMakeLists.txt b/deps/oblib/src/lib/CMakeLists.txt index 042faf250..724cc7807 100644 --- a/deps/oblib/src/lib/CMakeLists.txt +++ b/deps/oblib/src/lib/CMakeLists.txt @@ -134,7 +134,6 @@ ob_set_subtarget(oblib_lib common_mixed string/ob_string_buffer.cpp task/ob_timer.cpp task/ob_timer_monitor.cpp - thread_local/ob_tsi_factory.cpp thread_local/ob_tsi_utils.cpp thread_local/thread_buffer.cpp time/Time.cpp @@ -248,6 +247,7 @@ ob_set_subtarget(ob_malloc_object_list common_alloc alloc/memory_dump.cpp alloc/ob_malloc_allocator.cpp alloc/ob_malloc_callback.cpp + alloc/ob_malloc_sample_struct.cpp alloc/ob_tenant_ctx_allocator.cpp alloc/object_mgr.cpp alloc/object_set.cpp diff --git a/deps/oblib/src/lib/alloc/alloc_func.cpp b/deps/oblib/src/lib/alloc/alloc_func.cpp index e004bbe78..b6eea8329 100644 --- a/deps/oblib/src/lib/alloc/alloc_func.cpp +++ b/deps/oblib/src/lib/alloc/alloc_func.cpp @@ -171,5 +171,12 @@ int set_meta_obj_limit(uint64_t tenant_id, int64_t meta_obj_pct_lmt) return set_ctx_limit(tenant_id, common::ObCtxIds::META_OBJ_CTX_ID, ctx_limit); } +int set_rpc_limit(uint64_t tenant_id, int64_t rpc_pct_lmt) +{ + const int64_t tenant_limit = get_tenant_memory_limit(tenant_id); + const int64_t rpc_lmt = (tenant_limit / 100) * rpc_pct_lmt; + return set_ctx_limit(tenant_id, common::ObCtxIds::RPC_CTX_ID, rpc_lmt); +} + } // end of namespace lib } // end of namespace oceanbase diff --git a/deps/oblib/src/lib/alloc/alloc_func.h b/deps/oblib/src/lib/alloc/alloc_func.h index 8184f26b0..85274c861 100644 --- a/deps/oblib/src/lib/alloc/alloc_func.h +++ b/deps/oblib/src/lib/alloc/alloc_func.h @@ -53,6 +53,10 @@ int set_wa_limit(uint64_t tenand_id, int64_t wa_pctg); // set meta object memory limit for specified tenant. // - meta_obj_pct_lmt: percentage limitation of tenant memory can be used for meta object. int set_meta_obj_limit(uint64_t tenant_id, int64_t meta_obj_pct_lmt); + +// set rpc memory limit for specified tenant. +// - rpc_pct_lmt: percentage limitation of tenant rpc memory. +int set_rpc_limit(uint64_t tenant_id, int64_t rpc_pct_lmt); } // end of namespace lib } // end of namespace oceanbase diff --git a/deps/oblib/src/lib/alloc/alloc_struct.h b/deps/oblib/src/lib/alloc/alloc_struct.h index 8a6c102e1..52b8e3be9 100644 --- a/deps/oblib/src/lib/alloc/alloc_struct.h +++ b/deps/oblib/src/lib/alloc/alloc_struct.h @@ -237,6 +237,7 @@ struct AObject { struct { struct { uint8_t on_leak_check_ : 1; + uint8_t on_malloc_sample_ : 1; }; }; }; @@ -475,7 +476,8 @@ char *ABlock::data() const AObject::AObject() : MAGIC_CODE_(FREE_AOBJECT_MAGIC_CODE), nobjs_(0), nobjs_prev_(0), obj_offset_(0), - alloc_bytes_(0), tenant_id_(0) + alloc_bytes_(0), tenant_id_(0), + on_leak_check_(false), on_malloc_sample_(false) { } diff --git a/deps/oblib/src/lib/alloc/block_set.h b/deps/oblib/src/lib/alloc/block_set.h index ff1936182..82c22a3cf 100644 --- a/deps/oblib/src/lib/alloc/block_set.h +++ b/deps/oblib/src/lib/alloc/block_set.h @@ -106,11 +106,13 @@ private: void BlockSet::lock() { + ObDisableDiagnoseGuard diagnose_disable_guard; locker_->lock(); } void BlockSet::unlock() { + ObDisableDiagnoseGuard diagnose_disable_guard; locker_->unlock(); } diff --git a/deps/oblib/src/lib/alloc/malloc_hook.cpp b/deps/oblib/src/lib/alloc/malloc_hook.cpp index 78d0050a0..4b10682ba 100644 --- a/deps/oblib/src/lib/alloc/malloc_hook.cpp +++ b/deps/oblib/src/lib/alloc/malloc_hook.cpp @@ -60,22 +60,21 @@ void *ob_malloc_retry(size_t size) return ptr; } -static __thread bool in_hook = false; void *ob_malloc_hook(size_t size, const void *) { void *ptr = nullptr; size_t real_size = size + Header::SIZE; void *tmp_ptr = nullptr; bool from_mmap = false; - if (OB_UNLIKELY(in_hook)) { + if (OB_UNLIKELY(in_hook())) { if (MAP_FAILED == (tmp_ptr = ::mmap(nullptr, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) { tmp_ptr = nullptr; } from_mmap = true; } else { - bool in_hook_bak = in_hook; - in_hook = true; - DEFER(in_hook = in_hook_bak); + bool in_hook_bak = in_hook(); + in_hook()= true; + DEFER(in_hook()= in_hook_bak); tmp_ptr = ob_malloc_retry(real_size); } if (OB_LIKELY(tmp_ptr != nullptr)) { @@ -96,9 +95,9 @@ void ob_free_hook(void *ptr, const void *) if (OB_UNLIKELY(header->from_mmap_)) { ::munmap(orig_ptr, header->data_size_ + Header::SIZE + header->offset_); } else { - bool in_hook_bak = in_hook; - in_hook = true; - DEFER(in_hook = in_hook_bak); + bool in_hook_bak = in_hook(); + in_hook()= true; + DEFER(in_hook()= in_hook_bak); ob_free(orig_ptr); } } @@ -110,15 +109,15 @@ void *ob_realloc_hook(void *ptr, size_t size, const void *caller) size_t real_size = size + Header::SIZE; void *tmp_ptr = nullptr; bool from_mmap = false; - if (OB_UNLIKELY(in_hook)) { + if (OB_UNLIKELY(in_hook())) { if (MAP_FAILED == (tmp_ptr = ::mmap(nullptr, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) { tmp_ptr = nullptr; } from_mmap = true; } else { - bool in_hook_bak = in_hook; - in_hook = true; - DEFER(in_hook = in_hook_bak); + bool in_hook_bak = in_hook(); + in_hook()= true; + DEFER(in_hook()= in_hook_bak); tmp_ptr = ob_malloc_retry(real_size); } if (OB_LIKELY(tmp_ptr != nullptr)) { @@ -149,15 +148,15 @@ void *ob_memalign_hook(size_t alignment, size_t size, const void *) size_t real_size = 2 * MAX(alignment, Header::SIZE) + size; void *tmp_ptr = nullptr; bool from_mmap = false; - if (OB_UNLIKELY(in_hook)) { + if (OB_UNLIKELY(in_hook())) { if (MAP_FAILED == (tmp_ptr = ::mmap(nullptr, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) { tmp_ptr = nullptr; } from_mmap = true; } else { - bool in_hook_bak = in_hook; - in_hook = true; - DEFER(in_hook = in_hook_bak); + bool in_hook_bak = in_hook(); + in_hook()= true; + DEFER(in_hook()= in_hook_bak); tmp_ptr = ob_malloc_retry(real_size); } if (OB_LIKELY(tmp_ptr != nullptr)) { diff --git a/deps/oblib/src/lib/alloc/malloc_hook.h b/deps/oblib/src/lib/alloc/malloc_hook.h index be33fdc33..288ed2292 100644 --- a/deps/oblib/src/lib/alloc/malloc_hook.h +++ b/deps/oblib/src/lib/alloc/malloc_hook.h @@ -15,4 +15,10 @@ extern void init_malloc_hook(); +inline bool& in_hook() +{ + thread_local bool in_hook = false; + return in_hook; +} + #endif /* MALLOC_HOOK_H */ diff --git a/deps/oblib/src/lib/alloc/memory_dump.cpp b/deps/oblib/src/lib/alloc/memory_dump.cpp index 1ffcc8b05..0ae567089 100644 --- a/deps/oblib/src/lib/alloc/memory_dump.cpp +++ b/deps/oblib/src/lib/alloc/memory_dump.cpp @@ -128,6 +128,13 @@ int ObMemoryDump::init() w_stat_ = new (r_stat_ + 1) Stat(); dump_context_ = context; is_inited_ = true; + if (OB_FAIL(r_stat_->malloc_sample_map_.create(1000, "MallocInfoMap", + "MallocInfoMap"))) { + LOG_WARN("create memory info map for reading failed", K(ret)); + } else if (OB_FAIL(w_stat_->malloc_sample_map_.create(1000, "MallocInfoMap", + "MallocInfoMap"))) { + LOG_WARN("create memory info map for writing failed", K(ret)); + } } if (OB_SUCC(ret)) { if (OB_FAIL(TG_SET_RUNNABLE_AND_START(TGDefIDs::MEMORY_DUMP, *this))) { @@ -179,6 +186,17 @@ int ObMemoryDump::push(void *task) return ret; } +int ObMemoryDump::load_malloc_sample_map(ObMallocSampleMap &malloc_sample_map) +{ + int ret = OB_SUCCESS; + ObLatchRGuard guard(iter_lock_, ObLatchIds::MEM_DUMP_ITER_LOCK); + auto &map = r_stat_->malloc_sample_map_; + for (auto it = map.begin(); OB_SUCC(ret) && it != map.end(); ++it) { + ret = malloc_sample_map.set_refactored(it->first, it->second); + } + return ret; +} + void ObMemoryDump::run1() { SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range @@ -365,11 +383,12 @@ int label_stat(AChunk *chunk, ABlock *block, AObject *object, ObString str(len, label); LabelItem *litem = nullptr; LabelInfoItem *linfoitem = lmap.get(str); + int64_t bt_size = object->on_malloc_sample_ ? AOBJECT_BACKTRACE_SIZE : 0; if (NULL != linfoitem) { // exist litem = linfoitem->litem_; litem->hold_ += hold; - litem->used_ += object->alloc_bytes_; + litem->used_ += (object->alloc_bytes_ - bt_size); litem->count_++; if (chunk != linfoitem->chunk_) { litem->chunk_cnt_ += 1; @@ -389,7 +408,7 @@ int label_stat(AChunk *chunk, ABlock *block, AObject *object, litem->str_[len] = '\0'; litem->str_len_ = len; litem->hold_ = hold; - litem->used_ = object->alloc_bytes_; + litem->used_ = (object->alloc_bytes_ - bt_size); litem->count_ = 1; litem->block_cnt_ = 1; litem->chunk_cnt_ = 1; @@ -400,6 +419,35 @@ int label_stat(AChunk *chunk, ABlock *block, AObject *object, return ret; } +int malloc_sample_stat(uint64_t tenant_id, uint64_t ctx_id, + AObject *object, ObMallocSampleMap &malloc_sample_map) +{ + int ret = OB_SUCCESS; + if (object->in_use_ && object->on_malloc_sample_) { + int64_t offset = object->alloc_bytes_ - AOBJECT_BACKTRACE_SIZE; + ObMallocSampleKey key; + key.tenant_id_ = tenant_id; + key.ctx_id_ = ctx_id; + void **backtrace = reinterpret_cast(&object->data_[offset]); + int32_t bt_size = 0; + while (bt_size < AOBJECT_BACKTRACE_COUNT && nullptr != backtrace[bt_size]) { + key.bt_[bt_size] = backtrace[bt_size]; + ++bt_size; + } + key.bt_size_ = bt_size; + STRNCPY(key.label_, object->label_, sizeof(key.label_)); + key.label_[sizeof(key.label_) - 1] = '\0'; + ObMallocSampleValue *item = malloc_sample_map.get(key); + if (NULL != item) { + item->alloc_count_ += 1; + item->alloc_bytes_ += offset; + } else { + ret = malloc_sample_map.set_refactored(key, ObMallocSampleValue(1, offset)); + } + } + return ret; +} + void ObMemoryDump::handle(void *task) { int ret = OB_SUCCESS; @@ -415,6 +463,7 @@ void ObMemoryDump::handle(void *task) get_tenant_ids(tenant_ids_, MAX_TENANT_CNT, tenant_cnt); std::sort(tenant_ids_, tenant_ids_ + tenant_cnt); w_stat_->tcr_cnt_ = 0; + w_stat_->malloc_sample_map_.clear(); int64_t item_used = 0; int64_t log_pos = 0; IGNORE_RETURN databuff_printf(log_buf_, LOG_BUF_LEN, log_pos, @@ -456,8 +505,9 @@ void ObMemoryDump::handle(void *task) UNUSEDx(chunk, block); return OB_SUCCESS; }, - [tenant_id, &lmap, w_stat, &item_used] + [tenant_id, ctx_id, &lmap, w_stat, &item_used] (AChunk *chunk, ABlock *block, AObject *object) { + int ret = OB_SUCCESS; if (object->in_use_) { bool expect = AOBJECT_TAIL_MAGIC_CODE == reinterpret_cast(object->data_[object->alloc_bytes_]); @@ -470,9 +520,14 @@ void ObMemoryDump::handle(void *task) K(length), K(label)); } } - return label_stat(chunk, block, object, lmap, + ret = label_stat(chunk, block, object, lmap, w_stat->up2date_items_, ARRAYSIZEOF(w_stat->up2date_items_), item_used); + if (OB_SUCC(ret)) { + ret = malloc_sample_stat(tenant_id, ctx_id, + object, w_stat->malloc_sample_map_); + } + return ret; }); if (OB_FAIL(ret)) { LOG_WARN("parse_chunk_meta failed", K(ret), KP(chunk)); diff --git a/deps/oblib/src/lib/alloc/memory_dump.h b/deps/oblib/src/lib/alloc/memory_dump.h index 0f621f910..af31de06d 100644 --- a/deps/oblib/src/lib/alloc/memory_dump.h +++ b/deps/oblib/src/lib/alloc/memory_dump.h @@ -13,6 +13,7 @@ #ifndef OCEANBASE_DUMP_MEMORY_H_ #define OCEANBASE_DUMP_MEMORY_H_ +#include "lib/alloc/ob_malloc_sample_struct.h" #include "lib/queue/ob_lighty_queue.h" #include "lib/hash/ob_hashmap.h" #include "lib/rc/context.h" @@ -26,6 +27,7 @@ namespace oceanbase namespace observer { class ObAllVirtualMemoryInfo; +class ObMallocSampleInfo; } namespace lib { @@ -142,6 +144,7 @@ struct TenantCtxRange struct Stat { LabelItem up2date_items_[MAX_LABEL_ITEM_CNT]; TenantCtxRange tcrs_[MAX_TENANT_CNT * ObCtxIds::MAX_CTX_ID]; + lib::ObMallocSampleMap malloc_sample_map_; int tcr_cnt_ = 0; }; @@ -182,6 +185,7 @@ public: lib::ObMutexGuard guard(task_mutex_); avaliable_task_set_ |= (1 << pos); } + int load_malloc_sample_map(lib::ObMallocSampleMap& malloc_sample_map); private: void run1() override; void handle(void *task); diff --git a/deps/oblib/src/lib/alloc/ob_futex_v2.cpp b/deps/oblib/src/lib/alloc/ob_futex_v2.cpp index 5186e43cf..a91c03537 100644 --- a/deps/oblib/src/lib/alloc/ob_futex_v2.cpp +++ b/deps/oblib/src/lib/alloc/ob_futex_v2.cpp @@ -16,16 +16,15 @@ #include #include "lib/ob_abort.h" -#define futex(...) syscall(SYS_futex,__VA_ARGS__) inline int futex_v2_wake(volatile int *p, int val) { - return static_cast(futex((int *)p, FUTEX_WAKE_PRIVATE, val, NULL, NULL, 0)); + return static_cast(futex((uint *)p, FUTEX_WAKE_PRIVATE, val, NULL)); } inline int futex_v2_wait(volatile int *p, int val, const timespec *timeout) { int ret = 0; - if (0 != futex((int *)p, FUTEX_WAIT_PRIVATE, val, timeout, NULL, 0)) { + if (0 != futex((uint *)p, FUTEX_WAIT_PRIVATE, val, timeout)) { ret = errno; } return ret; diff --git a/deps/oblib/src/lib/alloc/ob_malloc_allocator.cpp b/deps/oblib/src/lib/alloc/ob_malloc_allocator.cpp index 831c5a69f..4953a70c8 100644 --- a/deps/oblib/src/lib/alloc/ob_malloc_allocator.cpp +++ b/deps/oblib/src/lib/alloc/ob_malloc_allocator.cpp @@ -97,6 +97,7 @@ void *ObMallocAllocator::alloc(const int64_t size, const oceanbase::lib::ObMemAt return ::malloc(size); #else SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range + ObDisableDiagnoseGuard disable_diagnose_guard; int ret = OB_E(EventTable::EN_4) OB_SUCCESS; void *ptr = NULL; ObTenantCtxAllocatorGuard allocator = NULL; @@ -129,13 +130,6 @@ void *ObMallocAllocator::alloc(const int64_t size, const oceanbase::lib::ObMemAt ptr = allocator->alloc(size, inner_attr); } - if (OB_NOT_NULL(ptr)) { - AObject *obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); - abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE - || obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE); - get_mem_leak_checker().on_alloc(*obj, inner_attr); - } - return ptr; #endif } @@ -148,6 +142,7 @@ void *ObMallocAllocator::realloc( return ::realloc(const_cast(ptr), size); #else SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range + ObDisableDiagnoseGuard disable_diagnose_guard; // Won't create tenant allocator!! void *nptr = NULL; int ret = OB_E(EventTable::EN_4) OB_SUCCESS; @@ -172,11 +167,6 @@ void *ObMallocAllocator::realloc( // do nothing } else if (OB_ISNULL(nptr = allocator->realloc(ptr, size, inner_attr))) { // do nothing - } else { - AObject *obj = reinterpret_cast((char*)nptr - AOBJECT_HEADER_SIZE); - abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE - || obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE); - get_mem_leak_checker().on_alloc(*obj, inner_attr); } return nptr;; #endif @@ -189,24 +179,7 @@ void ObMallocAllocator::free(void *ptr) #else SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range // directly free object instead of using tenant allocator. - if (NULL != ptr) { - AObject *obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); - abort_unless(NULL != obj); - abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE - || obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE); - abort_unless(obj->in_use_); - SANITY_POISON(obj->data_, obj->alloc_bytes_); - - get_mem_leak_checker().on_free(*obj); - ABlock *block = obj->block(); - abort_unless(block); - abort_unless(block->is_valid()); - abort_unless(block->in_use_); - abort_unless(block->obj_set_ != NULL); - - ObjectSet *set = block->obj_set_; - set->free_object(obj); - } + ObTenantCtxAllocator::common_free(ptr); #endif // PERF_MODE } @@ -223,6 +196,7 @@ ObTenantCtxAllocatorGuard ObMallocAllocator::get_tenant_ctx_allocator_without_tl } } const int64_t slot = tenant_id % PRESERVED_TENANT_COUNT; + ObDisableDiagnoseGuard disable_diagnose_guard; BucketRLockGuard guard(const_cast(locks_[slot]), GETTID() % BucketLock::BUCKET_COUNT); if (OB_LIKELY(tenant_id < PRESERVED_TENANT_COUNT)) { @@ -342,6 +316,7 @@ int ObMallocAllocator::add_tenant_allocator(ObTenantCtxAllocator *allocator) uint64_t tenant_id = allocator->get_tenant_id(); const int64_t slot = tenant_id % PRESERVED_TENANT_COUNT; // critical area is extremely small, just wait without trylock + ObDisableDiagnoseGuard disable_diagnose_guard; BucketWLockGuard guard(locks_[slot]); ObTenantCtxAllocator **cur = &allocators_[slot]; while ((NULL != *cur) && (*cur)->get_tenant_id() < tenant_id) { @@ -361,6 +336,7 @@ ObTenantCtxAllocator *ObMallocAllocator::take_off_tenant_allocator(uint64_t tena { ObTenantCtxAllocator *ta = NULL; const int64_t slot = tenant_id % PRESERVED_TENANT_COUNT; + ObDisableDiagnoseGuard disable_diagnose_guard; BucketWLockGuard guard(locks_[slot]); ObTenantCtxAllocator **cur = &allocators_[slot]; while (*cur && (*cur)->get_tenant_id() < tenant_id) { @@ -566,6 +542,7 @@ int ObMallocAllocator::set_tenant_ctx_idle(const uint64_t tenant_id, int ObMallocAllocator::get_chunks(AChunk **chunks, int cap, int &cnt) { int ret = OB_SUCCESS; + ObDisableDiagnoseGuard disable_diagnose_guard; for (int64_t slot = 0; OB_SUCC(ret) && slot < PRESERVED_TENANT_COUNT; ++slot) { ObTenantCtxAllocatorGuard tas[16]; // TODO: should be dynamic array, but enough so far int tas_cnt = 0; @@ -624,6 +601,7 @@ ObTenantCtxAllocatorGuard ObMallocAllocator::get_tenant_ctx_allocator_unrecycled uint64_t tenant_id, uint64_t ctx_id) const { ObTenantCtxAllocatorGuard ta; + ObDisableDiagnoseGuard disable_diagnose_guard; ObLatchRGuard guard(const_cast(unrecycled_lock_), ObLatchIds::OB_ALLOCATOR_LOCK); ObTenantCtxAllocator * const *cur = &unrecycled_allocators_; while (*cur) { @@ -643,6 +621,7 @@ void ObMallocAllocator::add_tenant_allocator_unrecycled(ObTenantCtxAllocator *al modify_tenant_memory_access_permission(allocator, false); } #endif + ObDisableDiagnoseGuard disable_diagnose_guard; ObLatchWGuard guard(unrecycled_lock_, ObLatchIds::OB_ALLOCATOR_LOCK); allocator->get_next() = unrecycled_allocators_; unrecycled_allocators_ = allocator; @@ -652,6 +631,7 @@ ObTenantCtxAllocator *ObMallocAllocator::take_off_tenant_allocator_unrecycled(ui { ObTenantCtxAllocator *ta = NULL; { + ObDisableDiagnoseGuard disable_diagnose_guard; ObLatchWGuard guard(unrecycled_lock_, ObLatchIds::OB_ALLOCATOR_LOCK); ObTenantCtxAllocator **cur = &unrecycled_allocators_; while (*cur) { @@ -760,6 +740,7 @@ int ObMallocAllocator::recycle_tenant_allocator(uint64_t tenant_id) void ObMallocAllocator::get_unrecycled_tenant_ids(uint64_t *ids, int cap, int &cnt) const { cnt = 0; + ObDisableDiagnoseGuard disable_diagnose_guard; ObLatchRGuard guard(const_cast(unrecycled_lock_), ObLatchIds::OB_ALLOCATOR_LOCK); ObTenantCtxAllocator * const *cur = &unrecycled_allocators_; while (*cur && cnt < cap) { diff --git a/deps/oblib/src/lib/thread_local/ob_tsi_factory.cpp b/deps/oblib/src/lib/alloc/ob_malloc_sample_struct.cpp similarity index 57% rename from deps/oblib/src/lib/thread_local/ob_tsi_factory.cpp rename to deps/oblib/src/lib/alloc/ob_malloc_sample_struct.cpp index 46b179468..1b642b422 100644 --- a/deps/oblib/src/lib/thread_local/ob_tsi_factory.cpp +++ b/deps/oblib/src/lib/alloc/ob_malloc_sample_struct.cpp @@ -10,16 +10,19 @@ * See the Mulan PubL v2 for more details. */ -#include "lib/thread_local/ob_tsi_factory.h" +#include "lib/alloc/ob_malloc_sample_struct.h" namespace oceanbase { -namespace common +namespace lib { -TSIFactory &get_tsi_fatcory() -{ - static TSIFactory instance; - return instance; -} -} // namespace common -} // namespace oceanbase +#if defined(__x86_64__) +int32_t ObMallocSampleLimiter::min_malloc_sample_interval = 16; +int32_t ObMallocSampleLimiter::max_malloc_sample_interval = 256; +#else +int32_t ObMallocSampleLimiter::min_malloc_sample_interval = 10000; +int32_t ObMallocSampleLimiter::max_malloc_sample_interval = 10000; +#endif + +} // end of namespace lib +} // end of namespace oceanbase diff --git a/deps/oblib/src/lib/alloc/ob_malloc_sample_struct.h b/deps/oblib/src/lib/alloc/ob_malloc_sample_struct.h new file mode 100644 index 000000000..32a2fbd41 --- /dev/null +++ b/deps/oblib/src/lib/alloc/ob_malloc_sample_struct.h @@ -0,0 +1,182 @@ +/** + * 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_MALLOC_SAMPLE_STRUCT_H_ +#define OCEANBASE_MALLOC_SAMPLE_STRUCT_H_ + +#include "lib/alloc/alloc_struct.h" +#include "lib/hash/ob_hashmap.h" + +namespace oceanbase +{ +namespace lib +{ +static const int32_t AOBJECT_BACKTRACE_COUNT = 16; +static const int32_t AOBJECT_BACKTRACE_SIZE = sizeof(void*) * AOBJECT_BACKTRACE_COUNT; +static const int32_t MAX_MALLOC_SAMPLER_NUM = (1<<15) - 1; + +class ObMallocSampleLimiter +{ +public: + ObMallocSampleLimiter(); + bool try_acquire(int64_t alloc_bytes); + static bool malloc_sample_allowed(const int64_t size, const ObMemAttr &attr); + static void set_interval(int32_t max_ratio, int32_t min_ratio); +private: + static int32_t min_malloc_sample_interval; + static int32_t max_malloc_sample_interval; + static const int32_t INTERVAL_UPPER_LIMIT = 10000; + static const int32_t MUST_SAMPLE_SIZE = 16<<20; + static const int32_t CUMULATIVE_SAMPLE_SIZE = 4<<20; + int64_t count_; + int64_t hold_; +}; + +static ObMallocSampleLimiter rate_limiters[MAX_MALLOC_SAMPLER_NUM + 1]; + +struct ObMallocSampleKey +{ + ObMallocSampleKey() + {} + int64_t hash() const; + bool operator==(const ObMallocSampleKey &other) const; + int64_t tenant_id_; + int64_t ctx_id_; + int32_t bt_size_; + char label_[lib::AOBJECT_LABEL_SIZE + 1]; + void *bt_[AOBJECT_BACKTRACE_COUNT]; +}; + +struct ObMallocSampleValue +{ + ObMallocSampleValue() + {} + ObMallocSampleValue(int64_t alloc_count, int64_t alloc_bytes) + : alloc_count_(alloc_count), alloc_bytes_(alloc_bytes) + {} + int64_t alloc_count_; + int64_t alloc_bytes_; +}; + +typedef hash::ObHashMap ObMallocSampleMap; + + +inline uint64_t ob_malloc_sample_hash(const char* data) +{ + return (uint64_t)data * 0xdeece66d + 0xb; +} + +inline ObMallocSampleLimiter::ObMallocSampleLimiter() + : count_(0), hold_(0) +{} + +inline bool ObMallocSampleLimiter::try_acquire(int64_t alloc_bytes) +{ + bool ret = false; + // Condition sample: controlled by sampler interval and Cumulative hold. + hold_ += alloc_bytes; + count_ += 1; + if (min_malloc_sample_interval <= count_) { + if (hold_ >= CUMULATIVE_SAMPLE_SIZE || max_malloc_sample_interval <= count_) { + count_ = 0; + hold_ = 0; + ret = true; + } + } + return ret; +} + +#ifndef PERF_MODE +inline bool ObMallocSampleLimiter::malloc_sample_allowed(const int64_t size, const ObMemAttr &attr) +{ + bool ret = false; + if (OB_UNLIKELY(INTERVAL_UPPER_LIMIT == min_malloc_sample_interval)) { + // Zero sample mode. + } else if (OB_UNLIKELY(MUST_SAMPLE_SIZE <= size)) { + // Full sample when size is bigger than 16M. + ret = true; + } else { + uint64_t hash_val = ob_malloc_sample_hash(attr.label_.str_); + if (rate_limiters[hash_val & MAX_MALLOC_SAMPLER_NUM].try_acquire(size)) { + ret = true; + } + } + return ret; +} +#else +inline bool ObMallocSampleLimiter::malloc_sample_allowed(const int64_t size, const ObMemAttr &attr) +{ + return false; +} +#endif + +inline void ObMallocSampleLimiter::set_interval(int32_t max_interval, int32_t min_interval) +{ + if (min_interval < 1 || max_interval > INTERVAL_UPPER_LIMIT + || max_interval < min_interval) { + _OB_LOG_RET(WARN, common::OB_INVALID_ARGUMENT, "set the min or max malloc times between two samples unexpected," + "max_interval=%d, min_interval=%d", max_interval, min_interval); + } else { + min_malloc_sample_interval = min_interval; + max_malloc_sample_interval = max_interval; + _OB_LOG_RET(INFO, common::OB_SUCCESS, "set the min or max malloc times between two samples succeed," + "max_interval=%d, min_interval=%d", max_interval, min_interval); + } +} + +inline int64_t ObMallocSampleKey::hash() const +{ + int64_t hash_val = 0; + hash_val = murmurhash(&tenant_id_, sizeof(tenant_id_), hash_val); + hash_val = murmurhash(&ctx_id_, sizeof(ctx_id_), hash_val); + hash_val = murmurhash(label_, sizeof(label_), hash_val); + hash_val = murmurhash(bt_, bt_size_ * sizeof(void*), hash_val); + return hash_val; +} + +inline bool ObMallocSampleKey::operator==(const ObMallocSampleKey &other) const +{ + bool ret = true; + if (tenant_id_ != other.tenant_id_ || ctx_id_ != other.ctx_id_ + || 0 != STRNCMP(label_, other.label_, sizeof(label_))) { + ret = false; + } + if (ret) { + if (other.bt_size_ != bt_size_) { + ret = false; + } else { + for (int i = 0; i < bt_size_; ++i) { + if ((int64_t)bt_[i] != (int64_t)other.bt_[i]) { + ret = false; + break; + } + } + } + } + return ret; +} + +#define ob_malloc_sample_backtrace(obj, size) \ + { \ + if (OB_UNLIKELY(obj->on_malloc_sample_)) { \ + int bt_len = backtrace(reinterpret_cast(&obj->data_[size]), AOBJECT_BACKTRACE_COUNT); \ + if (AOBJECT_BACKTRACE_COUNT > bt_len) { \ + reinterpret_cast(obj->data_[size + bt_len * sizeof(void*)]) = nullptr; \ + } \ + } \ + } + +} // end of namespace lib +} // end of namespace oceanbase + +#endif diff --git a/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.cpp b/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.cpp index 03fadec1b..7a3fc41b9 100644 --- a/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.cpp +++ b/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.cpp @@ -13,6 +13,8 @@ #define USING_LOG_PREFIX LIB #include "lib/alloc/ob_tenant_ctx_allocator.h" +#include "lib/alloc/ob_malloc_sample_struct.h" +#include "lib/allocator/ob_mem_leak_checker.h" #include "lib/allocator/ob_tc_malloc.h" #include "lib/utility/ob_print_utils.h" #include "lib/alloc/memory_dump.h" @@ -25,33 +27,10 @@ using namespace oceanbase::lib; using namespace oceanbase::common; void *ObTenantCtxAllocator::alloc(const int64_t size, const ObMemAttr &attr) { - SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range abort_unless(attr.tenant_id_ == tenant_id_); abort_unless(attr.ctx_id_ == ctx_id_); BACKTRACE_RET(WARN, OB_INVALID_ARGUMENT, !attr.label_.is_valid(), "[OB_MOD_DO_NOT_USE_ME ALLOC]size:%ld", size); - void *ptr = NULL; - AObject *obj = obj_mgr_.alloc_object(size, attr); - if(OB_ISNULL(obj) && g_alloc_failed_ctx().need_wash()) { - int64_t total_size = sync_wash(); - obj = obj_mgr_.alloc_object(size, attr); - } - if (NULL != obj) { - ptr = obj->data_; - SANITY_POISON(obj, AOBJECT_HEADER_SIZE); - SANITY_UNPOISON(obj->data_, obj->alloc_bytes_); - SANITY_POISON((void*)upper_align((int64_t)obj->data_ + obj->alloc_bytes_, 8), sizeof(AOBJECT_TAIL_MAGIC_CODE)); - } - if (NULL == ptr && REACH_TIME_INTERVAL(1 * 1000 * 1000)) { - const char *msg = alloc_failed_msg(); - LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg)); - _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, " - "ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld", - tenant_id_, ctx_id_, - common::get_global_ctx_info().get_ctx_name(ctx_id_), - get_hold(), get_limit(), get_tenant_hold(), get_tenant_limit()); - // 49 is the user defined signal to dump memory - raise(49); - } + void *ptr = common_alloc(size, attr, *this, obj_mgr_); return ptr; } @@ -64,54 +43,14 @@ int64_t ObTenantCtxAllocator::get_obj_hold(void *ptr) void* ObTenantCtxAllocator::realloc(const void *ptr, const int64_t size, const ObMemAttr &attr) { - SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range - void *nptr = NULL; - AObject *obj = NULL; - BACKTRACE_RET(WARN, OB_INVALID_ARGUMENT, !attr.label_.is_valid(), "[OB_MOD_DO_NOT_USE_ME REALLOC]size:%ld", size); - if (NULL != ptr) { - obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); - abort_unless(obj->is_valid()); - abort_unless(obj->in_use_); - abort_unless(obj->block()->is_valid()); - abort_unless(obj->block()->in_use_); - SANITY_POISON(obj->data_, obj->alloc_bytes_); - } - obj = obj_mgr_.realloc_object(obj, size, attr); - if(OB_ISNULL(obj) && g_alloc_failed_ctx().need_wash()) { - int64_t total_size = sync_wash(); - obj = obj_mgr_.realloc_object(obj, size, attr); - } - if (obj != NULL) { - nptr = obj->data_; - SANITY_POISON(obj, AOBJECT_HEADER_SIZE); - SANITY_UNPOISON(obj->data_, obj->alloc_bytes_); - SANITY_POISON((void*)upper_align((int64_t)obj->data_ + obj->alloc_bytes_, 8), sizeof(AOBJECT_TAIL_MAGIC_CODE)); - } else if (REACH_TIME_INTERVAL(1 * 1000 * 1000)) { - const char *msg = alloc_failed_msg(); - LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg)); - _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, " - "ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld", - tenant_id_, ctx_id_, - common::get_global_ctx_info().get_ctx_name(ctx_id_), - get_hold(), get_limit(), get_tenant_hold(), get_tenant_limit()); - // 49 is the user defined signal to dump memory - raise(49); - } + BACKTRACE_RET(WARN, OB_INVALID_ARGUMENT, !attr.label_.is_valid(), "[OB_MOD_DO_NOT_USE_ME REALLOC]size:%ld", size); + void *nptr = common_realloc(ptr, size, attr, *this, obj_mgr_); return nptr; } void ObTenantCtxAllocator::free(void *ptr) { - SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range - if (NULL != ptr) { - AObject *obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); - abort_unless(NULL != obj); - abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE - || obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE); - abort_unless(obj->in_use_); - SANITY_POISON(obj->data_, obj->alloc_bytes_); - obj_mgr_.free_object(obj); - } + common_free(ptr); } int ObTenantCtxAllocator::iter_label(VisitFunc func) const { @@ -234,6 +173,7 @@ void ObTenantCtxAllocator::print_usage() const AChunk *ObTenantCtxAllocator::pop_chunk() { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(chunk_freelist_mutex_); AChunk *chunk = head_chunk_.next_; AChunk *next_chunk = nullptr == chunk ? nullptr : chunk->next_; @@ -246,6 +186,7 @@ AChunk *ObTenantCtxAllocator::pop_chunk() void ObTenantCtxAllocator::push_chunk(AChunk *chunk) { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(chunk_freelist_mutex_); chunk->next_ = head_chunk_.next_; head_chunk_.next_ = chunk; @@ -277,6 +218,7 @@ AChunk *ObTenantCtxAllocator::alloc_chunk(const int64_t size, const ObMemAttr &a chunk = ObPageManagerCenter::get_instance().alloc_from_thread_local_cache(tenant_id_, ctx_id_); } } else { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(using_list_mutex_); chunk->prev2_ = &using_list_head_; chunk->next2_ = using_list_head_.next2_; @@ -290,6 +232,7 @@ AChunk *ObTenantCtxAllocator::alloc_chunk(const int64_t size, const ObMemAttr &a void ObTenantCtxAllocator::free_chunk(AChunk *chunk, const ObMemAttr &attr) { if (chunk != nullptr) { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(using_list_mutex_); chunk->prev2_->next2_ = chunk->next2_; chunk->next2_->prev2_ = chunk->prev2_; @@ -388,6 +331,7 @@ int ObTenantCtxAllocator::set_idle(const int64_t set_size, const bool reserve/*= void ObTenantCtxAllocator::get_chunks(AChunk **chunks, int cap, int &cnt) { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(using_list_mutex_); AChunk *cur = using_list_head_.next2_; while (cur != &using_list_head_ && cnt < cap) { @@ -449,3 +393,110 @@ void ObTenantCtxAllocator::update_wash_stat(int64_t related_chunks, int64_t bloc (void)ATOMIC_FAA(&washed_blocks_, blocks); (void)ATOMIC_FAA(&washed_size_, size); } + +template +void* ObTenantCtxAllocator::common_alloc(const int64_t size, const ObMemAttr &attr, + ObTenantCtxAllocator& ta, T &allocator) +{ + SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range + void *ret = nullptr; + bool sample_allowed = ObMallocSampleLimiter::malloc_sample_allowed(size, attr); + const int64_t alloc_size = sample_allowed ? (size + AOBJECT_BACKTRACE_SIZE) : size; + AObject *obj = allocator.alloc_object(alloc_size, attr); + if (OB_ISNULL(obj) && g_alloc_failed_ctx().need_wash()) { + int64_t total_size = ta.sync_wash(); + obj = allocator.alloc_object(alloc_size, attr); + } + if (NULL != obj) { + obj->on_malloc_sample_ = sample_allowed; + ob_malloc_sample_backtrace(obj, size); + ret = obj->data_; + get_mem_leak_checker().on_alloc(*obj, attr); + SANITY_POISON(obj, AOBJECT_HEADER_SIZE); + SANITY_UNPOISON(obj->data_, size); + SANITY_POISON((void*)upper_align((int64_t)obj->data_ + size, 8), + alloc_size - size + sizeof(AOBJECT_TAIL_MAGIC_CODE)); + } + if (OB_UNLIKELY(nullptr == obj) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) { + const char *msg = alloc_failed_msg(); + LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg)); + _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, " + "ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld", + attr.tenant_id_, attr.ctx_id_, + get_global_ctx_info().get_ctx_name(attr.ctx_id_), + ta.get_hold(), ta.get_limit(), ta.get_tenant_hold(), ta.get_tenant_limit()); + // 49 is the user defined signal to dump memory + raise(49); + } + return ret; +} + +template +void* ObTenantCtxAllocator::common_realloc(const void *ptr, const int64_t size, + const ObMemAttr &attr, ObTenantCtxAllocator& ta, + T &allocator) +{ + SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range + void *nptr = NULL; + AObject *obj = NULL; + if (NULL != ptr) { + obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); + abort_unless(obj->is_valid()); + abort_unless(obj->in_use_); + abort_unless(obj->block()->is_valid()); + abort_unless(obj->block()->in_use_); + SANITY_POISON(obj->data_, obj->alloc_bytes_); + get_mem_leak_checker().on_free(*obj); + } + bool sample_allowed = ObMallocSampleLimiter::malloc_sample_allowed(size, attr); + const int64_t alloc_size = sample_allowed ? (size + AOBJECT_BACKTRACE_SIZE) : size; + obj = allocator.realloc_object(obj, alloc_size, attr); + if(OB_ISNULL(obj) && g_alloc_failed_ctx().need_wash()) { + int64_t total_size = ta.sync_wash(); + obj = allocator.realloc_object(obj, alloc_size, attr); + } + if (obj != NULL) { + obj->on_malloc_sample_ = sample_allowed; + ob_malloc_sample_backtrace(obj, size); + nptr = obj->data_; + get_mem_leak_checker().on_alloc(*obj, attr); + SANITY_POISON(obj, AOBJECT_HEADER_SIZE); + SANITY_UNPOISON(obj->data_, size); + SANITY_POISON((void*)upper_align((int64_t)obj->data_ + size, 8), + alloc_size - size + sizeof(AOBJECT_TAIL_MAGIC_CODE)); + } else if (REACH_TIME_INTERVAL(1 * 1000 * 1000)) { + const char *msg = alloc_failed_msg(); + LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg)); + _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, " + "ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld", + attr.tenant_id_, attr.ctx_id_, + get_global_ctx_info().get_ctx_name(attr.ctx_id_), + ta.get_hold(), ta.get_limit(), ta.get_tenant_hold(), ta.get_tenant_limit()); + // 49 is the user defined signal to dump memory + raise(49); + } + return nptr; +} + +void ObTenantCtxAllocator::common_free(void *ptr) +{ + SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range + if (NULL != ptr) { + AObject *obj = reinterpret_cast((char*)ptr - AOBJECT_HEADER_SIZE); + abort_unless(NULL != obj); + abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE + || obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE); + abort_unless(obj->in_use_); + SANITY_POISON(obj->data_, obj->alloc_bytes_); + + get_mem_leak_checker().on_free(*obj); + ABlock *block = obj->block(); + abort_unless(block); + abort_unless(block->is_valid()); + abort_unless(block->in_use_); + abort_unless(block->obj_set_ != NULL); + + ObjectSet *os = block->obj_set_; + os->free_object(obj); + } +} diff --git a/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.h b/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.h index 3b2f18fef..d872d31b8 100644 --- a/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.h +++ b/deps/oblib/src/lib/alloc/ob_tenant_ctx_allocator.h @@ -184,6 +184,19 @@ private: } return ret; } + +public: + template + static void* common_alloc(const int64_t size, const ObMemAttr &attr, + ObTenantCtxAllocator& ta, T &allocator); + + template + static void* common_realloc(const void *ptr, const int64_t size, + const ObMemAttr &attr, ObTenantCtxAllocator& ta, + T &allocator); + + static void common_free(void *ptr); + private: ObTenantResourceMgrHandle resource_handle_; int64_t ref_cnt_; diff --git a/deps/oblib/src/lib/alloc/object_set.cpp b/deps/oblib/src/lib/alloc/object_set.cpp index f002f9a6d..8887910b2 100644 --- a/deps/oblib/src/lib/alloc/object_set.cpp +++ b/deps/oblib/src/lib/alloc/object_set.cpp @@ -377,6 +377,7 @@ void ObjectSet::free_object(AObject *obj) } #endif const int64_t ctx_id = blk_mgr_->ctx_id_; + ObDisableDiagnoseGuard diagnose_disable_guard; if (ctx_id == common::ObCtxIds::LIBEASY) { if (locker_->trylock()) { do_free_object(obj); @@ -417,6 +418,7 @@ void ObjectSet::do_free_object(AObject *obj) used_bytes_ -= hold; obj->in_use_ = false; + obj->on_malloc_sample_ = false; if (!obj->is_large_) { free_normal_object(obj); } else { diff --git a/deps/oblib/src/lib/alloc/object_set.h b/deps/oblib/src/lib/alloc/object_set.h index 94289644f..9becffd0f 100644 --- a/deps/oblib/src/lib/alloc/object_set.h +++ b/deps/oblib/src/lib/alloc/object_set.h @@ -126,11 +126,13 @@ private: inline void ObjectSet::lock() { + ObDisableDiagnoseGuard diagnose_disable_guard; locker_->lock(); } inline void ObjectSet::unlock() { + ObDisableDiagnoseGuard diagnose_disable_guard; locker_->unlock(); } diff --git a/deps/oblib/src/lib/allocator/ob_allocator_v2.cpp b/deps/oblib/src/lib/allocator/ob_allocator_v2.cpp index ffeb6477d..f50f368c8 100644 --- a/deps/oblib/src/lib/allocator/ob_allocator_v2.cpp +++ b/deps/oblib/src/lib/allocator/ob_allocator_v2.cpp @@ -30,37 +30,13 @@ void *ObAllocator::alloc(const int64_t size, const ObMemAttr &attr) ret = init(); } if (OB_SUCC(ret)) { - BACKTRACE(WARN, !attr.label_.is_valid(), "[OB_MOD_DO_NOT_USE_ME ALLOC]size:%ld", size); + BACKTRACE_RET(WARN, OB_INVALID_ARGUMENT, !attr.label_.is_valid(), "[OB_MOD_DO_NOT_USE_ME ALLOC]size:%ld", size); ObMemAttr inner_attr = attr_; if (attr.label_.is_valid()) { inner_attr.label_ = attr.label_; } - AObject *obj = os_.alloc_object(size, inner_attr); - if (OB_ISNULL(obj) && g_alloc_failed_ctx().need_wash()) { - auto ta = lib::ObMallocAllocator::get_instance()->get_tenant_ctx_allocator(attr_.tenant_id_, - attr_.ctx_id_); - int64_t total_size = ta->sync_wash(); - obj = os_.alloc_object(size, inner_attr); - } - if (NULL != obj) { - ptr = obj->data_; - get_mem_leak_checker().on_alloc(*obj, inner_attr); - SANITY_POISON(obj, AOBJECT_HEADER_SIZE); - SANITY_UNPOISON(obj->data_, obj->alloc_bytes_); - SANITY_POISON((void*)upper_align((int64_t)obj->data_ + obj->alloc_bytes_, 8), sizeof(AOBJECT_TAIL_MAGIC_CODE)); - } - if (OB_UNLIKELY(nullptr == obj) && REACH_TIME_INTERVAL(1 * 1000 * 1000)) { - auto ta = lib::ObMallocAllocator::get_instance()->get_tenant_ctx_allocator(attr_.tenant_id_, - attr_.ctx_id_); - _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "[OOPS] alloc failed reason: %s", alloc_failed_msg()); - _OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, " - "ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld", - inner_attr.tenant_id_, inner_attr.ctx_id_, - common::get_global_ctx_info().get_ctx_name(inner_attr.ctx_id_), - ta->get_hold(), ta->get_limit(), ta->get_tenant_hold(), ta->get_tenant_limit()); - // 49 is the user defined signal to dump memory - raise(49); - } + auto ta = lib::ObMallocAllocator::get_instance()->get_tenant_ctx_allocator(attr_.tenant_id_, attr_.ctx_id_); + ptr = ObTenantCtxAllocator::common_alloc(size, inner_attr, *(ta.ref_allocator()), os_); } return ptr; } @@ -68,28 +44,8 @@ void *ObAllocator::alloc(const int64_t size, const ObMemAttr &attr) void ObAllocator::free(void *ptr) { SANITY_DISABLE_CHECK_RANGE(); // prevent sanity_check_range - int ret = OB_SUCCESS; - if (OB_UNLIKELY(!is_inited_)) { - ret = init(); - } - if (OB_SUCC(ret)) { - if (OB_LIKELY(nullptr != ptr)) { - AObject *obj = reinterpret_cast((char*)ptr - lib::AOBJECT_HEADER_SIZE); - abort_unless(NULL != obj); - abort_unless(obj->MAGIC_CODE_ == lib::AOBJECT_MAGIC_CODE - || obj->MAGIC_CODE_ == lib::BIG_AOBJECT_MAGIC_CODE); - abort_unless(obj->in_use_); - SANITY_POISON(obj->data_, obj->alloc_bytes_); - - get_mem_leak_checker().on_free(*obj); - lib::ABlock *block = obj->block(); - abort_unless(block); - abort_unless(block->is_valid()); - ObjectSet *os = block->obj_set_; - abort_unless(os == &os_); - os->free_object(obj); - } - } + // directly free object instead of using tenant allocator. + ObTenantCtxAllocator::common_free(ptr); } void *ObParallelAllocator::alloc(const int64_t size, const ObMemAttr &attr) diff --git a/deps/oblib/src/lib/allocator/ob_mem_leak_checker.h b/deps/oblib/src/lib/allocator/ob_mem_leak_checker.h index 76a24e6c9..35380d2d2 100644 --- a/deps/oblib/src/lib/allocator/ob_mem_leak_checker.h +++ b/deps/oblib/src/lib/allocator/ob_mem_leak_checker.h @@ -160,7 +160,6 @@ public: void on_alloc(lib::AObject &obj, const ObMemAttr &attr) { - obj.on_leak_check_ = false; if (is_label_check() && label_match(obj) && (tenant_id_ == UINT64_MAX || tenant_id_ == attr.tenant_id_) && @@ -187,6 +186,7 @@ public: if (is_label_check() && obj.on_leak_check_ && label_match(obj)) { + obj.on_leak_check_ = false; PtrKey ptr_key; ptr_key.ptr_ = obj.data_; int ret = OB_SUCCESS; diff --git a/deps/oblib/src/lib/allocator/ob_mod_define.h b/deps/oblib/src/lib/allocator/ob_mod_define.h index 4aa450d29..0066ba1fd 100644 --- a/deps/oblib/src/lib/allocator/ob_mod_define.h +++ b/deps/oblib/src/lib/allocator/ob_mod_define.h @@ -43,6 +43,8 @@ CTX_ITEM_DEF(META_OBJ_CTX_ID) CTX_ITEM_DEF(TX_CALLBACK_CTX_ID) CTX_ITEM_DEF(LOB_CTX_ID) CTX_ITEM_DEF(PS_CACHE_CTX_ID) +CTX_ITEM_DEF(RPC_CTX_ID) +CTX_ITEM_DEF(PKT_NIO) CTX_ITEM_DEF(TX_DATA_TABLE) CTX_ITEM_DEF(MAX_CTX_ID) #endif diff --git a/deps/oblib/src/lib/allocator/ob_page_manager.cpp b/deps/oblib/src/lib/allocator/ob_page_manager.cpp index f5e6f3753..1dc304b22 100644 --- a/deps/oblib/src/lib/allocator/ob_page_manager.cpp +++ b/deps/oblib/src/lib/allocator/ob_page_manager.cpp @@ -32,6 +32,7 @@ ObPageManagerCenter &ObPageManagerCenter::get_instance() int ObPageManagerCenter::register_pm(ObPageManager &pm) { int ret = OB_SUCCESS; + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(mutex_); rb_tree_.insert(&pm); pm.has_register_ = true; @@ -42,6 +43,7 @@ int ObPageManagerCenter::register_pm(ObPageManager &pm) void ObPageManagerCenter::unregister_pm(ObPageManager &pm) { + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(mutex_); pm.has_register_ = false; rb_tree_.remove(&pm); @@ -57,7 +59,7 @@ int ObPageManagerCenter::print_tenant_stat(int64_t tenant_id, char *buf, int64_t len, int64_t &pos) { int ret = OB_SUCCESS; - + ObDisableDiagnoseGuard disable_diagnose_guard; lib::ObMutexGuard guard(mutex_); int64_t sum_used = 0; int64_t sum_hold = 0; @@ -74,6 +76,7 @@ AChunk *ObPageManagerCenter::alloc_from_thread_local_cache(int64_t tenant_id, in int tmpret = OB_SUCCESS; AChunk *ret = nullptr; const int RETRY_LIMIT = 10; + ObDisableDiagnoseGuard disable_diagnose_guard; for (int retry = 0; retry < RETRY_LIMIT && OB_EAGAIN == (tmpret = mutex_.trylock()); ++retry) { sched_yield(); } diff --git a/deps/oblib/src/lib/allocator/ob_tc_malloc.cpp b/deps/oblib/src/lib/allocator/ob_tc_malloc.cpp index 88b2e2dbf..2d5aae2fc 100644 --- a/deps/oblib/src/lib/allocator/ob_tc_malloc.cpp +++ b/deps/oblib/src/lib/allocator/ob_tc_malloc.cpp @@ -18,11 +18,13 @@ #include "lib/allocator/ob_allocator.h" #include "lib/allocator/ob_mod_define.h" #include "lib/list/ob_free_list.h" +#include "lib/utility/ob_tracepoint.h" #include "lib/utility/utility.h" #include "lib/hash_func/ob_hash_func.h" #include "lib/allocator/ob_mem_leak_checker.h" #include "lib/alloc/ob_malloc_allocator.h" #include "lib/worker.h" +#include "lib/alloc/malloc_hook.h" using namespace oceanbase::lib; using namespace oceanbase::common; @@ -131,7 +133,12 @@ const ObCtxInfo &get_global_ctx_info() void __attribute__((constructor(MALLOC_INIT_PRIORITY))) init_global_memory_pool() { + auto& t = EventTable::instance(); + auto& c = get_mem_leak_checker(); + auto& a = AChunkMgr::instance(); + in_hook()= true; global_default_allocator = ObMallocAllocator::get_instance(); + in_hook()= false; #ifndef OB_USE_ASAN abort_unless(OB_SUCCESS == install_ob_signal_handler()); #endif @@ -151,6 +158,5 @@ int64_t get_virtual_memory_used(int64_t *resident_size) return page_cnt * ps; } - } // end namespace common } // end namespace oceanbase diff --git a/deps/oblib/src/lib/lock/ob_futex.cpp b/deps/oblib/src/lib/lock/ob_futex.cpp index c5a9f2c30..db6404308 100644 --- a/deps/oblib/src/lib/lock/ob_futex.cpp +++ b/deps/oblib/src/lib/lock/ob_futex.cpp @@ -22,7 +22,12 @@ static struct timespec make_timespec(int64_t us) return ts; } - +extern "C" { +int __attribute__((weak)) futex_hook(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec* timeout) +{ + return syscall(SYS_futex, uaddr, futex_op, val, timeout); +} +} using namespace oceanbase::lib; using namespace oceanbase::common; diff --git a/deps/oblib/src/lib/lock/ob_futex.h b/deps/oblib/src/lib/lock/ob_futex.h index 8acec08b4..555fb52a5 100644 --- a/deps/oblib/src/lib/lock/ob_futex.h +++ b/deps/oblib/src/lib/lock/ob_futex.h @@ -18,25 +18,22 @@ #include "lib/list/ob_dlist.h" #include #include "lib/ob_abort.h" -#define futex(...) syscall(SYS_futex,__VA_ARGS__) + +extern "C" { +extern int futex_hook(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec* timeout); +} + +#define futex(...) futex_hook(__VA_ARGS__) + inline int futex_wake(volatile int *p, int val) { - return static_cast(futex((int *)p, FUTEX_WAKE_PRIVATE, val, NULL, NULL, 0)); + return futex((uint32_t *)p, FUTEX_WAKE_PRIVATE, val, NULL); } inline int futex_wait(volatile int *p, int val, const timespec *timeout) { int ret = 0; - if (0 != futex((int *)p, FUTEX_WAIT_PRIVATE, val, timeout, NULL, 0)) { - ret = errno; - } - return ret; -} - -inline int futex_wait_until(volatile int *p, int val, const timespec *timeout, int wait_mask) -{ - int ret = 0; - if (0 != futex((int *)p, FUTEX_WAIT_BITSET_PRIVATE, val, timeout, NULL, wait_mask)) { + if (0 != futex((uint32_t *)p, FUTEX_WAIT_PRIVATE, val, timeout)) { ret = errno; } return ret; diff --git a/deps/oblib/src/lib/lock/ob_latch.cpp b/deps/oblib/src/lib/lock/ob_latch.cpp index 60cbdd7a1..b8c162653 100644 --- a/deps/oblib/src/lib/lock/ob_latch.cpp +++ b/deps/oblib/src/lib/lock/ob_latch.cpp @@ -22,11 +22,33 @@ namespace oceanbase namespace common { bool USE_CO_LATCH = false; +thread_local uint32_t* ObLatch::current_lock = nullptr; +thread_local uint32_t* ObLatch::current_wait = nullptr; + +class ObLatchWaitEventGuard : public ObWaitEventGuard +{ +public: + explicit ObLatchWaitEventGuard( + const int64_t event_no, + const uint64_t timeout_ms = 0, + const int64_t p1 = 0, + uint32_t* p2_addr = 0, + const int64_t p3 = 0, + const bool is_atomic = false + ) : ObWaitEventGuard(event_no, timeout_ms, p1, OB_ISNULL(p2_addr) ? 0 : *p2_addr, p3, is_atomic) + { + ObLatch::current_wait = p2_addr; + } + ~ObLatchWaitEventGuard() { ObLatch::current_wait = nullptr; } +}; /** * -------------------------------------------------------ObLatchMutex--------------------------------------------------------------- */ ObLatchMutex::ObLatchMutex() - : lock_(), record_stat_(true) + : lock_() + #ifndef PERF_MODE + ,record_stat_(true) + #endif { } @@ -51,8 +73,12 @@ int ObLatchMutex::try_lock( } else { if (!ATOMIC_BCAS(&lock_.val(), 0, (WRITE_MASK | uid))) { ret = OB_EAGAIN; + } else { + ObLatch::current_lock = (uint32_t*)&lock_.val(); + } + if (need_record_stat()) { + TRY_LOCK_RECORD_STAT(latch_id, 1, ret); } - TRY_LOCK_RECORD_STAT(latch_id, 1, ret, record_stat_); } HOLD_LOCK_INC(); return ret; @@ -93,11 +119,11 @@ int ObLatchMutex::lock( //wait waited = true; // latch mutex wait is an atomic wait event - ObWaitEventGuard wait_guard( + ObLatchWaitEventGuard wait_guard( OB_LATCHES[latch_id].wait_event_idx_, abs_timeout_us / 1000, reinterpret_cast(this), - lock_.val(), + (uint32_t*)&lock_.val(), 0, true /*is_atomic*/); if (OB_FAIL(wait(abs_timeout_us, uid))) { @@ -109,7 +135,9 @@ int ObLatchMutex::lock( } } } - LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt, record_stat_); + if (need_record_stat()) { + LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt); + } } HOLD_LOCK_INC(); return ret; @@ -157,7 +185,7 @@ int ObLatchMutex::unlock() { int ret = OB_SUCCESS; uint32_t lock = ATOMIC_SET(&lock_.val(), 0); - + ObLatch::current_lock = nullptr; if (OB_UNLIKELY(0 == lock)) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "invalid lock,", K(lock), K(ret)); @@ -237,11 +265,11 @@ int ObLatchWaitQueue::wait( } { - ObWaitEventGuard wait_guard( + ObLatchWaitEventGuard wait_guard( ObWaitEventIds::LATCH_WAIT_QUEUE_LOCK_WAIT, abs_timeout_us / 1000, reinterpret_cast(this), - latch.lock_, + (uint32_t*)&latch.lock_, 0, true /*is_atomic*/); ts.tv_sec = timeout / 1000000; @@ -545,6 +573,9 @@ void ObLockDiagnose::print() ObLatch::ObLatch() : lock_(0) + #ifndef PERF_MODE + , record_stat_(true) + #endif { } @@ -582,6 +613,7 @@ int ObLatch::try_rdlock(const uint32_t latch_id) ++i; if (ATOMIC_BCAS(&lock_, lock, lock + 1)) { ret = OB_SUCCESS; + ObLatch::current_lock = (uint32_t*)&lock_; break; } } @@ -590,8 +622,9 @@ int ObLatch::try_rdlock(const uint32_t latch_id) } PAUSE(); } while (true); - - TRY_LOCK_RECORD_STAT(latch_id, i, ret, true); + if (need_record_stat()) { + TRY_LOCK_RECORD_STAT(latch_id, i, ret); + } } HOLD_LOCK_INC(); return ret; @@ -609,9 +642,12 @@ int ObLatch::try_wrlock(const uint32_t latch_id, const uint32_t *puid) } else { if (!ATOMIC_BCAS(&lock_, 0, (WRITE_MASK | uid))) { ret = OB_EAGAIN; + } else { + ObLatch::current_lock = (uint32_t*)&lock_; + } + if (need_record_stat()) { + TRY_LOCK_RECORD_STAT(latch_id, 1, ret); } - - TRY_LOCK_RECORD_STAT(latch_id, 1, ret, true); } HOLD_LOCK_INC(); return ret; @@ -678,6 +714,7 @@ int ObLatch::wr2rdlock(const uint32_t *puid) lock = lock_; PAUSE(); } + ObLatch::current_lock = (uint32_t*)&lock_; bool only_rd_wait = true; if (OB_FAIL(ObLatchWaitQueue::get_instance().wake_up(*this, only_rd_wait))) { COMMON_LOG(ERROR, "Fail to wake up latch wait queue, ", K(this), K(ret)); @@ -699,9 +736,11 @@ int ObLatch::unlock(const uint32_t *puid) COMMON_LOG(ERROR, "The latch is not write locked by the uid, ", K(uid), K(wid), KCSTRING(lbt()), K(ret)); } else { lock = ATOMIC_ANDF(&lock_, WAIT_MASK); + ObLatch::current_lock = nullptr; } } else if ((lock & (~WAIT_MASK)) > 0) { lock = ATOMIC_AAF(&lock_, -1); + ObLatch::current_lock = nullptr; } else { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "invalid lock,", K(lock), K(ret)); @@ -769,11 +808,11 @@ OB_INLINE int ObLatch::low_lock( } else { //wait waited = true; - ObWaitEventGuard wait_guard( + ObLatchWaitEventGuard wait_guard( OB_LATCHES[latch_id].wait_event_idx_, abs_timeout_us / 1000, reinterpret_cast(this), - lock, + (uint32_t*)&lock_, 0); ObWaitProc proc(*this, wait_mode); if (OB_FAIL(ObLatchWaitQueue::get_instance().wait( @@ -791,8 +830,9 @@ OB_INLINE int ObLatch::low_lock( } } } - - LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt, true); + if (need_record_stat()) { + LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt); + } } return ret; } diff --git a/deps/oblib/src/lib/lock/ob_latch.h b/deps/oblib/src/lib/lock/ob_latch.h index 8b771b53c..ecf3f9c74 100644 --- a/deps/oblib/src/lib/lock/ob_latch.h +++ b/deps/oblib/src/lib/lock/ob_latch.h @@ -37,10 +37,10 @@ extern bool USE_CO_LATCH; do { \ } while(0) -#if !PERF_MODE -#define TRY_LOCK_RECORD_STAT(latch_id, spin_cnt, ret, enable) \ +#ifndef PERF_MODE +#define TRY_LOCK_RECORD_STAT(latch_id, spin_cnt, ret) \ do { \ - if (enable) { \ + if (lib::is_diagnose_info_enabled()) { \ ObDiagnoseTenantInfo *di = ObDiagnoseTenantInfo::get_local_diagnose_info(); \ if (NULL != di) { \ ObLatchStat &latch_stat = di->get_latch_stats().items_[latch_id]; \ @@ -54,35 +54,35 @@ extern bool USE_CO_LATCH; } \ } while(0) #else -#define TRY_LOCK_RECORD_STAT(latch_id, spin_cnt, ret, enable) +#define TRY_LOCK_RECORD_STAT(latch_id, spin_cnt, ret) #endif -#if !PERF_MODE -#define LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt, enable) \ - do { \ - if (enable) { \ - ObDiagnoseTenantInfo *di = ObDiagnoseTenantInfo::get_local_diagnose_info(); \ - if (NULL != di) { \ - ObLatchStat &latch_stat = di->get_latch_stats().items_[latch_id]; \ - ++latch_stat.gets_; \ - latch_stat.spin_gets_ += spin_cnt; \ - latch_stat.sleeps_ += yield_cnt; \ - if (OB_UNLIKELY(waited)) { \ - ++latch_stat.misses_; \ - ObDiagnoseSessionInfo *dsi = ObDiagnoseSessionInfo::get_local_diagnose_info(); \ - if (NULL != dsi) { \ - latch_stat.wait_time_ += dsi->get_curr_wait().wait_time_; \ - if (dsi->get_curr_wait().wait_time_ > 1000 * 1000) { \ - COMMON_LOG_RET(WARN, OB_ERR_TOO_MUCH_TIME, "The Latch wait too much time, ", \ - K(dsi->get_curr_wait()), KCSTRING(lbt())); \ - } \ - } \ - } \ - } \ - } \ +#ifndef PERF_MODE +#define LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt) \ + do { \ + if (lib::is_diagnose_info_enabled()) { \ + ObDiagnoseTenantInfo *di = ObDiagnoseTenantInfo::get_local_diagnose_info(); \ + if (NULL != di) { \ + ObLatchStat &latch_stat = di->get_latch_stats().items_[latch_id]; \ + ++latch_stat.gets_; \ + latch_stat.spin_gets_ += spin_cnt; \ + latch_stat.sleeps_ += yield_cnt; \ + if (OB_UNLIKELY(waited)) { \ + ++latch_stat.misses_; \ + ObDiagnoseSessionInfo *dsi = ObDiagnoseSessionInfo::get_local_diagnose_info(); \ + if (NULL != dsi) { \ + latch_stat.wait_time_ += dsi->get_curr_wait().wait_time_; \ + if (dsi->get_curr_wait().wait_time_ > 1000 * 1000) { \ + COMMON_LOG_RET(WARN, OB_ERR_TOO_MUCH_TIME, "The Latch wait too much time, ", \ + K(dsi->get_curr_wait()), KCSTRING(lbt())); \ + } \ + } \ + } \ + } \ + } \ } while(0) #else -#define LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt, enable) +#define LOCK_RECORD_STAT(latch_id, waited, spin_cnt, yield_cnt) #endif struct ObLatchWaitMode @@ -111,7 +111,13 @@ public: inline bool is_locked(); inline uint32_t get_wid(); int64_t to_string(char* buf, const int64_t buf_len); +#ifndef PERF_MODE void enable_record_stat(bool enable) { record_stat_ = enable; } + bool need_record_stat() const { return record_stat_; } +#else + void enable_record_stat(bool enable) { UNUSED(enable); } + bool need_record_stat() const { return false; } +#endif private: OB_INLINE uint64_t low_try_lock(const int64_t max_spin_cnt, const uint32_t lock_value); @@ -122,7 +128,9 @@ private: static const uint32_t WAIT_MASK = 1<<31; lib::ObFutex lock_; //volatile int32_t lock_; +#ifndef PERF_MODE bool record_stat_; +#endif }; class ObLatch; @@ -206,8 +214,11 @@ private: DISALLOW_COPY_AND_ASSIGN(ObLatchWaitQueue); }; +class TCRWLock; + class ObLatch { + friend class TCRWLock; public: ObLatch(); ~ObLatch(); @@ -228,7 +239,16 @@ public: inline bool is_wrlocked_by(const uint32_t *puid = NULL) const; inline uint32_t get_wid() const; int64_t to_string(char* buf, const int64_t buf_len) const; - +#ifndef PERF_MODE + void enable_record_stat(bool enable) { record_stat_ = enable; } + bool need_record_stat() const { return record_stat_; } +#else + void enable_record_stat(bool enable) { UNUSED(enable); } + bool need_record_stat() const { return false; } +#endif + uint32_t val() const { return lock_; } + static thread_local uint32_t* current_lock; + static thread_local uint32_t* current_wait; private: template OB_INLINE int low_lock( @@ -260,6 +280,9 @@ private: static const uint32_t WAIT_MASK = 1<<31; static const uint32_t MAX_READ_LOCK_CNT = 1<<24; volatile uint32_t lock_; +#ifndef PERF_MODE + bool record_stat_; +#endif }; struct ObLDLockType @@ -459,6 +482,7 @@ OB_INLINE uint64_t ObLatchMutex::low_try_lock(const int64_t max_spin_cnt, const for (; spin_cnt < max_spin_cnt; ++spin_cnt) { if (0 == lock_.val()) { if (ATOMIC_BCAS(&lock_.val(), 0, lock_value)) { + ObLatch::current_lock = (uint32_t*)(&lock_.val()); break; } } @@ -520,6 +544,7 @@ inline int ObLatch::LowTryRDLock::operator()(volatile uint32_t *latch, conflict = false; if (ATOMIC_BCAS(latch, lock, lock + 1)) { ret = OB_SUCCESS; + ObLatch::current_lock = (uint32_t*)latch; } } else { conflict = true; @@ -542,6 +567,7 @@ inline int ObLatch::LowTryWRLock::operator()(volatile uint32_t *latch, conflict = false; if (ATOMIC_BCAS(latch, lock, (lock | (WRITE_MASK | uid)))) { ret = OB_SUCCESS; + ObLatch::current_lock = (uint32_t*)latch; } } else { conflict = true; diff --git a/deps/oblib/src/lib/lock/ob_spin_rwlock.h b/deps/oblib/src/lib/lock/ob_spin_rwlock.h index a129b049c..34962a22f 100644 --- a/deps/oblib/src/lib/lock/ob_spin_rwlock.h +++ b/deps/oblib/src/lib/lock/ob_spin_rwlock.h @@ -50,6 +50,7 @@ public: inline int unlock() { return latch_.unlock(); } inline void rdunlock() { unlock(); } inline void wrunlock() { unlock(); } + inline void enable_record_stat(bool enable) { latch_.enable_record_stat(enable); } private: ObLatch latch_; uint32_t latch_id_; diff --git a/deps/oblib/src/lib/lock/ob_tc_rwlock.h b/deps/oblib/src/lib/lock/ob_tc_rwlock.h index 2a7b527fe..33e3c4155 100644 --- a/deps/oblib/src/lib/lock/ob_tc_rwlock.h +++ b/deps/oblib/src/lib/lock/ob_tc_rwlock.h @@ -148,6 +148,10 @@ public: ret = latch_.unlock(); } } + if (OB_SUCC(ret)) { + // record in try_rdlock will be overwrited by latch_.rdlock, so record again. + ObLatch::current_lock = (uint32_t*)&(latch_.lock_); + } return ret; } inline bool try_rdlock() @@ -157,6 +161,7 @@ public: get_tcref().inc_ref(&read_ref_); if (OB_LIKELY(0 == ATOMIC_LOAD(&write_id_))) { locked = true; + ObLatch::current_lock = (uint32_t*)&(latch_.lock_); } else { get_tcref().dec_ref(&read_ref_); lcond_.signal(); @@ -168,6 +173,7 @@ public: { int ret = OB_SUCCESS; get_tcref().dec_ref(&read_ref_); + ObLatch::current_lock = nullptr; lcond_.signal(); return ret; } @@ -179,6 +185,9 @@ public: ATOMIC_STORE(&write_id_, itid); get_tcref().sync(&read_ref_); int64_t ttl = 0; + // although we know that waiting myself is meanless, + // but it is helpful for us to understand the lock logic. + ObLatch::current_wait = (uint32_t*)&(latch_.lock_); while(0 != ATOMIC_LOAD(&read_ref_) && (ttl = abs_timeout_us - ObTimeUtility::current_time()) >= 0) { lcond_.wait(std::min(ttl, (int64_t)10 * 1000)); @@ -190,6 +199,7 @@ public: } else { ATOMIC_STORE(&write_id_, itid | WRITE_MASK); } + ObLatch::current_wait = nullptr; } return ret; } @@ -250,6 +260,7 @@ public: get_tcref().inc_ref(&read_ref_, slot_id); if (OB_LIKELY(0 == ATOMIC_LOAD(&write_id_))) { locked = true; + ObLatch::current_lock = (uint32_t*)&(latch_.lock_); } else { get_tcref().dec_ref(&read_ref_, slot_id); lcond_.signal(); @@ -265,12 +276,17 @@ public: ret = latch_.unlock(); } } + if (OB_SUCC(ret)) { + // record in try_rdlock will be overwrited by latch_.rdlock, so record again. + ObLatch::current_lock = (uint32_t*)&(latch_.lock_); + } return ret; } inline int rdunlock(int64_t slot_id) { int ret = OB_SUCCESS; get_tcref().dec_ref(&read_ref_, slot_id); + ObLatch::current_lock = nullptr; lcond_.signal(); return ret; } diff --git a/deps/oblib/src/lib/ob_define.h b/deps/oblib/src/lib/ob_define.h index ef44e75bb..37c845b35 100644 --- a/deps/oblib/src/lib/ob_define.h +++ b/deps/oblib/src/lib/ob_define.h @@ -2166,7 +2166,6 @@ enum ObTraceGranularity #define DIO_ALIGN_SIZE 4096 #define DIO_READ_ALIGN_SIZE 4096 #define DIO_ALLOCATOR_CACHE_BLOCK_SIZE (OB_DEFAULT_MACRO_BLOCK_SIZE + DIO_READ_ALIGN_SIZE) -#define CORO_INIT_PRIORITY 120 #define MALLOC_INIT_PRIORITY 128 #define NORMAL_INIT_PRIORITY (MALLOC_INIT_PRIORITY + 1) @@ -2343,22 +2342,22 @@ OB_INLINE int64_t ob_gettid() return tid; } -OB_INLINE uint64_t &ob_get_tenant_id() +OB_INLINE uint64_t& ob_get_tenant_id() { - RLOCAL_INLINE(uint64_t, tenant_id); + thread_local uint64_t tenant_id = 0;; return tenant_id; } -OB_INLINE char *ob_get_tname() +OB_INLINE char* ob_get_tname() { - struct TNameBuf { - TNameBuf() { - snprintf(v_, oceanbase::OB_THREAD_NAME_BUF_LEN, "%s", ""); - } - char v_[oceanbase::OB_THREAD_NAME_BUF_LEN]; - }; - RLOCAL_INLINE(TNameBuf, tname); - return tname.v_; + thread_local char tname[oceanbase::OB_THREAD_NAME_BUF_LEN] = {0}; + return tname; +} + +OB_INLINE const char*& ob_get_origin_thread_name() +{ + thread_local const char* tname = nullptr; + return tname; } // There are many clusters in arbitration server, we need a field identify the different clusters. diff --git a/deps/oblib/src/lib/ob_lib_config.cpp b/deps/oblib/src/lib/ob_lib_config.cpp index 6537103e0..22adea0c4 100644 --- a/deps/oblib/src/lib/ob_lib_config.cpp +++ b/deps/oblib/src/lib/ob_lib_config.cpp @@ -16,27 +16,9 @@ namespace oceanbase namespace lib { -ObLibConfig::ObLibConfig() - : enable_diagnose_info_(true), - enable_trace_log_(true) -{ -} - -ObLibConfig &ObLibConfig::get_instance() -{ - static ObLibConfig instance_; - return instance_; -} - -void ObLibConfig::reload_diagnose_info_config(const bool enable_diagnose_info) -{ - ATOMIC_SET(&enable_diagnose_info_, enable_diagnose_info); -} - -void ObLibConfig::reload_trace_log_config(const bool enable_trace_log) -{ - ATOMIC_SET(&enable_trace_log_, enable_trace_log); -} +volatile bool ObLibConfig::enable_diagnose_info_ = true; +volatile bool ObLibConfig::enable_trace_log_ = true; +thread_local bool ObDisableDiagnoseGuard::in_disable_diagnose_guard_ = false; } //lib } //oceanbase diff --git a/deps/oblib/src/lib/ob_lib_config.h b/deps/oblib/src/lib/ob_lib_config.h index 54dd0c87a..bae81400b 100644 --- a/deps/oblib/src/lib/ob_lib_config.h +++ b/deps/oblib/src/lib/ob_lib_config.h @@ -13,56 +13,66 @@ #ifndef OB_LIB_CONFIG_H_ #define OB_LIB_CONFIG_H_ -#include "lib/ob_define.h" -#include "lib/utility/ob_print_utils.h" +#include "lib/atomic/ob_atomic.h" + namespace oceanbase { namespace lib { +bool is_diagnose_info_enabled(); +void reload_diagnose_info_config(const bool); +bool is_trace_log_enabled(); +void reload_trace_log_config(const bool); class ObLibConfig { + friend bool is_diagnose_info_enabled(); + friend void reload_diagnose_info_config(const bool); + friend bool is_trace_log_enabled(); + friend void reload_trace_log_config(const bool); +private: + static volatile bool enable_diagnose_info_ CACHE_ALIGNED; + static volatile bool enable_trace_log_ CACHE_ALIGNED; +}; + +class ObPerfModeGuard +{ + friend bool is_diagnose_info_enabled(); + friend bool is_trace_log_enabled(); public: - static ObLibConfig &get_instance(); - void reload_diagnose_info_config(const bool enable_diagnose_info); - void reload_trace_log_config(const bool enable_trace_log); - bool is_diagnose_info_enabled() const + explicit ObPerfModeGuard() : old_value_(in_disable_diagnose_guard_) { - return enable_diagnose_info_; + in_disable_diagnose_guard_ = true; } - bool is_trace_log_enabled() const + ~ObPerfModeGuard() { - return enable_trace_log_; + in_disable_diagnose_guard_ = old_value_; } private: - ObLibConfig(); - virtual ~ObLibConfig() = default; - volatile bool enable_diagnose_info_ CACHE_ALIGNED; - volatile bool enable_trace_log_ CACHE_ALIGNED; + static thread_local bool in_disable_diagnose_guard_; + bool old_value_; }; +using ObDisableDiagnoseGuard = ObPerfModeGuard; + inline bool is_diagnose_info_enabled() { - return ObLibConfig::get_instance().is_diagnose_info_enabled(); + return ObLibConfig::enable_diagnose_info_ && !ObPerfModeGuard::in_disable_diagnose_guard_; } -inline int reload_diagnose_info_config(const bool enable_diagnose_info) +inline void reload_diagnose_info_config(const bool enable_diagnose_info) { - int ret = common::OB_SUCCESS; - ObLibConfig::get_instance().reload_diagnose_info_config(enable_diagnose_info); - return ret; + ATOMIC_STORE(&ObLibConfig::enable_diagnose_info_, enable_diagnose_info); } inline bool is_trace_log_enabled() { - return ObLibConfig::get_instance().is_trace_log_enabled(); + return ObLibConfig::enable_trace_log_ && !ObPerfModeGuard::in_disable_diagnose_guard_; } -inline int reload_trace_log_config(const bool enable_trace_log) +inline void reload_trace_log_config(const bool enable_trace_log) { - int ret = common::OB_SUCCESS; - ObLibConfig::get_instance().reload_trace_log_config(enable_trace_log); - return ret; + ATOMIC_STORE(&ObLibConfig::enable_trace_log_, enable_trace_log); } } //lib diff --git a/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.cpp b/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.cpp index f50192e08..3b89f6f47 100644 --- a/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.cpp +++ b/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.cpp @@ -369,7 +369,7 @@ int ObObjFreeList::init(const char *name, const int64_t obj_size, alignment_ = alignment; obj_count_base_ = (OP_GLOBAL == cache_type) ? 0 : obj_count; type_size_base_ = obj_size; - only_global_ = (OP_RECLAIM != cache_type); + only_global_ = (OP_GLOBAL == cache_type); name_ = name; // Make sure we align *all* the objects in the allocation, @@ -631,22 +631,6 @@ void *ObObjFreeList::reclaim_alloc(ObThreadCache *thread_cache) return ret; } -void *ObObjFreeList::tc_alloc(ObThreadCache *thread_cache) -{ - void *ret = NULL; - if (OB_LIKELY(NULL != thread_cache)){ - if (NULL != (ret = thread_cache->inner_free_list_.pop())) { - thread_cache->nr_free_--; - thread_cache->nr_malloc_++; - } else if (only_global_) { - if (NULL != (ret = global_alloc())) { - thread_cache->nr_malloc_++; - } - } - } - return ret; -} - void *ObObjFreeList::alloc() { void *ret = NULL; @@ -661,7 +645,9 @@ void *ObObjFreeList::alloc() } if (only_global_) { - ret = tc_alloc(thread_cache); + if (OB_NOT_NULL(ret = global_alloc())) { + thread_cache->nr_malloc_++; + } } else { ret = reclaim_alloc(thread_cache); } @@ -691,36 +677,6 @@ void ObObjFreeList::reclaim_free(ObThreadCache *cur_thread_cache, void *item) rcu_read_unlock(cur_thread_cache); } -void ObObjFreeList::tc_free(ObThreadCache *cur_thread_cache, void *item) -{ - if (obj_count_base_ > 0) { - // free all thread cache obj upto global free list if it's overflow - if (OB_UNLIKELY(cur_thread_cache->nr_free_ >= obj_count_base_)) { - void *next = NULL; - obj_free_list_.push(item); - // keep half of obj_count_base_ - int64_t low_watermark = obj_count_base_ / 2; - while (cur_thread_cache->nr_free_ > low_watermark - && NULL != (next = cur_thread_cache->inner_free_list_.pop())) { - obj_free_list_.push(next); - cur_thread_cache->nr_free_--; - } - } else { - cur_thread_cache->inner_free_list_.push(reinterpret_cast(item)); - cur_thread_cache->nr_free_++; - } - } else { - global_free(item); - } - - /** - * For global allocate mode, maybe thread A allocates memory and thread B frees it. - * So when thread B frees, B's thread cache maybe NULL. The thread_cache->nr_malloc_ - * isn't the actual malloc number of this thread, maybe it's negative. - */ - cur_thread_cache->nr_malloc_--; -} - void ObObjFreeList::free(void *item) { ObThreadCache *thread_cache = NULL; @@ -734,7 +690,8 @@ void ObObjFreeList::free(void *item) if (OB_LIKELY(NULL != thread_cache)) { if (only_global_) { - tc_free(thread_cache, item); + global_free(item); + thread_cache->nr_malloc_--; } else { reclaim_free(thread_cache, item); } diff --git a/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.h b/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.h index 8ca0375f3..80997e360 100644 --- a/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.h +++ b/deps/oblib/src/lib/objectpool/ob_concurrency_objpool.h @@ -43,7 +43,6 @@ extern void thread_shutdown_cleanup(void *); enum ObMemCacheType { OP_GLOBAL, - OP_TC, OP_RECLAIM }; @@ -177,8 +176,6 @@ private: void global_free(void *item); void *reclaim_alloc(ObThreadCache *thread_cache); void reclaim_free(ObThreadCache *cur_thread_cache, void *item); - void *tc_alloc(ObThreadCache *thread_cache); - void tc_free(ObThreadCache *cur_thread_cache, void *item); ObThreadCache *init_thread_cache(); void privatize_thread_cache(ObThreadCache *cur_thread_cache, ObThreadCache *src_thread_cache); @@ -796,16 +793,14 @@ inline void call_destructor(T *ptr) { // 3. because object pool uses singleton, please only use one of global, // tc or reclaim interfaces for each object type in the whole procject. // Note: -// op_alloc,op_tc_alloc and op_reclaim_alloc call the default constructor if it exist, +// op_alloc and op_reclaim_alloc call the default constructor if it exist, // else it just reinterpret_cast ptr. // -// op_alloc_args,op_tc_alloc_args and op_reclaim_args call the constructor with args. +// op_alloc_args and op_reclaim_args call the constructor with args. // It uses placement new to construct instance, if args is null and there isn't public // default constructor, compiler isn't happy. // // op_alloc_args uses global object freelist, save memory but performance is poor. -// op_tc_alloc_args uses thread local object free list, perfromance is better but -// waste some memory. // op_reclaim_alloc_args uses thread local object free list and with memory reclaim, // performace is good and object waste less memory. @@ -887,61 +882,7 @@ inline void call_destructor(T *ptr) { } \ }) -// thread cache pool allocator interface -#define op_tc_alloc_args(type, args...) \ - ({ \ - type *ret = NULL; \ - common::ObClassAllocator *instance = \ - common::ObClassAllocator::get(common::OPNum::LOCAL_NUM, common::OP_TC, \ - common::OPNum::LABEL); \ - if (OB_LIKELY(NULL != instance)) { \ - void *tmp = instance->alloc_void(); \ - if (OB_LIKELY(NULL != tmp)) { \ - ret = new (tmp) type(args); \ - } \ - } \ - ret; \ - }) - -#define op_tc_alloc(type) \ - ({ \ - type *ret = NULL; \ - common::ObClassAllocator *instance = \ - common::ObClassAllocator::get(common::OPNum::LOCAL_NUM, common::OP_TC, \ - common::OPNum::LABEL); \ - if (OB_LIKELY(NULL != instance)) { \ - ret = instance->alloc(); \ - } \ - ret; \ - }) - -#define op_tc_free(ptr) \ - ({ \ - common::ObClassAllocator<__typeof__(*ptr)> *instance = \ - common::ObClassAllocator<__typeof__(*ptr)>::get(common::OPNum<__typeof__(*ptr)>::LOCAL_NUM, common::OP_TC, \ - common::OPNum<__typeof__(*ptr)>::LABEL); \ - if (OB_LIKELY(NULL != instance)) { \ - instance->free(ptr); \ - } \ - }) - -// thread cache pool and reclaim allocator interface -#define op_reclaim_alloc_args(type, args...) \ - ({ \ - type *ret = NULL; \ - common::ObClassAllocator *instance = \ - common::ObClassAllocator::get(common::OPNum::LOCAL_NUM, common::OP_RECLAIM, \ - common::OPNum::LABEL); \ - if (OB_LIKELY(NULL != instance)) { \ - void *tmp = instance->alloc_void(); \ - if (OB_LIKELY(NULL != tmp)) { \ - ret = new (tmp) type(args); \ - } \ - } \ - ret; \ - }) - -#define op_reclaim_alloc(type) \ +#define op_reclaim_alloc_old(type) \ ({ \ OLD_STATIC_ASSERT((std::is_default_constructible::value), "type is not default constructible"); \ type *ret = NULL; \ @@ -954,7 +895,7 @@ inline void call_destructor(T *ptr) { ret; \ }) -#define op_reclaim_free(ptr) \ +#define op_reclaim_free_old(ptr) \ ({ \ common::ObClassAllocator<__typeof__(*ptr)> *instance = \ common::ObClassAllocator<__typeof__(*ptr)>::get(common::OPNum<__typeof__(*ptr)>::LOCAL_NUM, \ @@ -965,6 +906,14 @@ inline void call_destructor(T *ptr) { } \ }) +#ifndef PERF_MODE +#define op_reclaim_alloc(type) op_alloc(type) +#define op_reclaim_free(ptr) op_free(ptr) +#else +#define op_reclaim_alloc(type) op_reclaim_alloc_old(type) +#define op_reclaim_free(ptr) op_reclaim_free_old(ptr) +#endif + } // end of namespace common } // end of namespace oceanbase diff --git a/deps/oblib/src/lib/objectpool/ob_pool.ipp b/deps/oblib/src/lib/objectpool/ob_pool.ipp index 37265a228..f152628e2 100644 --- a/deps/oblib/src/lib/objectpool/ob_pool.ipp +++ b/deps/oblib/src/lib/objectpool/ob_pool.ipp @@ -50,6 +50,9 @@ void ObPool::reset() { BlockHeader *curr = blocklist_; BlockHeader *next = NULL; + //if (in_use_count_ != 0) { + // LIB_LOG(ERROR, "there was memory leak", K(in_use_count_), K(free_count_), K(total_count_)); + //} while (NULL != curr) { next = curr->next_; block_allocator_.free(curr); diff --git a/deps/oblib/src/lib/oblog/ob_base_log_writer.cpp b/deps/oblib/src/lib/oblog/ob_base_log_writer.cpp index 0c09bc8a2..0925c0849 100644 --- a/deps/oblib/src/lib/oblog/ob_base_log_writer.cpp +++ b/deps/oblib/src/lib/oblog/ob_base_log_writer.cpp @@ -26,6 +26,7 @@ #include "lib/oblog/ob_log_print_kv.h" #include "lib/worker.h" #include "lib/thread/ob_thread_name.h" +#include "lib/thread/thread.h" using namespace oceanbase::lib; @@ -79,14 +80,7 @@ int ObBaseLogWriter::init( log_cfg_ = log_cfg; max_buffer_item_cnt_ = log_cfg.max_buffer_item_cnt_; memset((void*) log_items_, 0, sizeof(ObIBaseLogItem*) * max_buffer_item_cnt_); - if (STRLEN(thread_name) > MAX_THREAD_NAME_LEN) { - ret = OB_SIZE_OVERFLOW; - LOG_STDERR("Size of thread_name exceeds the limit, thread_name_size=%lu.\n", sizeof(thread_name)); - } else if (tenant_id == 0) { - MEMCPY(thread_name_, thread_name, STRLEN(thread_name)); - } else { - snprintf(thread_name_, PR_SET_NAME, "T%lu_%s", tenant_id, thread_name); - } + thread_name_ = thread_name; if (OB_SUCC(ret)) { is_inited_ = true; LOG_STDOUT("successfully init ObBaseLogWriter\n"); @@ -254,7 +248,7 @@ void *ObBaseLogWriter::flush_log_thread(void *arg) } else { pthread_cleanup_push(cleanup_log_thread, arg); ObBaseLogWriter *log_writer = reinterpret_cast (arg); - prctl(PR_SET_NAME, log_writer->thread_name_, 0, 0, 0); + lib::set_thread_name(log_writer->thread_name_); log_writer->flush_log(); pthread_cleanup_pop(1); } @@ -264,6 +258,7 @@ void *ObBaseLogWriter::flush_log_thread(void *arg) void ObBaseLogWriter::flush_log() { while (!has_stopped_) { + IGNORE_RETURN lib::Thread::update_loop_ts(ObTimeUtility::fast_current_time()); pthread_mutex_lock(&thread_mutex_); // 每个线程执行16次再重新抢占, 对cpu cache hit有利 for (int64_t i = 0; i < 16; i++) { diff --git a/deps/oblib/src/lib/oblog/ob_base_log_writer.h b/deps/oblib/src/lib/oblog/ob_base_log_writer.h index 1ca6f48b7..a402d0185 100644 --- a/deps/oblib/src/lib/oblog/ob_base_log_writer.h +++ b/deps/oblib/src/lib/oblog/ob_base_log_writer.h @@ -116,7 +116,7 @@ protected: SimpleCond* log_write_cond_; SimpleCond* log_flush_cond_; - char thread_name_[PR_SET_NAME]; + const char* thread_name_; }; } diff --git a/deps/oblib/src/lib/oblog/ob_log.h b/deps/oblib/src/lib/oblog/ob_log.h index 4a05d3e49..527adc4d9 100644 --- a/deps/oblib/src/lib/oblog/ob_log.h +++ b/deps/oblib/src/lib/oblog/ob_log.h @@ -41,7 +41,6 @@ #include "lib/oblog/ob_async_log_struct.h" #include "lib/utility/ob_defer.h" #include "lib/oblog/ob_syslog_rate_limiter.h" -#include "common/ob_local_store.h" #define OB_LOG_MAX_PAR_MOD_SIZE 32 #define OB_LOG_MAX_SUB_MOD_SIZE 32 @@ -161,8 +160,9 @@ public: static inline const ObLogIdLevelMap *get(); static inline int8_t get_level(); - //@brief Get the thread-only ObThreadLogLevel. - static inline ObThreadLogLevel *get_thread_log_level(); +private: + static inline const ObLogIdLevelMap*& get_id_level_map_(); + static inline int8_t& get_level_(); }; class ObThreadFlags @@ -834,64 +834,47 @@ inline int8_t ObLogIdLevelMap::get_level(uint64_t par_mod_id, uint64_t sub_mod_i inline void ObThreadLogLevelUtils::init() { - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - trace_log_level->id_level_map_ = NULL; - } + get_id_level_map_() = NULL; } inline void ObThreadLogLevelUtils::init(const ObLogIdLevelMap *id_level_map) { - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - trace_log_level->id_level_map_ = id_level_map; - trace_log_level->level_ = (id_level_map == NULL - ? (int8_t)OB_LOG_LEVEL_NONE : id_level_map->non_mod_level_); - } + get_id_level_map_() = id_level_map; + get_level_() = (id_level_map == NULL + ? (int8_t)OB_LOG_LEVEL_NONE : id_level_map->non_mod_level_); } inline void ObThreadLogLevelUtils::init(const int8_t level) { - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - trace_log_level->level_ = level; - } + get_level_() = level; } inline void ObThreadLogLevelUtils::clear() { - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - trace_log_level->id_level_map_ = NULL; - trace_log_level->level_ = OB_LOG_LEVEL_NONE; - } + get_id_level_map_() = NULL; + get_level_() = OB_LOG_LEVEL_NONE; } inline const ObLogIdLevelMap *ObThreadLogLevelUtils::get() { - const ObLogIdLevelMap *ret = NULL; - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - ret = trace_log_level->id_level_map_; - } - return ret; + return get_id_level_map_(); } inline int8_t ObThreadLogLevelUtils::get_level() { - int8_t level = OB_LOG_LEVEL_NONE; - ObThreadLogLevel *trace_log_level = get_thread_log_level(); - if (NULL != trace_log_level) { - level = trace_log_level->level_; - } - return level; + return get_level_();; } -inline ObThreadLogLevel *ObThreadLogLevelUtils::get_thread_log_level() +inline const ObLogIdLevelMap*& ObThreadLogLevelUtils::get_id_level_map_() { - ObThreadLogLevel *ret = nullptr; - ret = &(common::get_local_store()->log_level_); - return ret; + thread_local const ObLogIdLevelMap* id_level_map = nullptr; + return id_level_map; +} + +inline int8_t& ObThreadLogLevelUtils::get_level_() +{ + thread_local int8_t level = OB_LOG_LEVEL_NONE; + return level; } inline void ObLogger::check_log_end(ObPLogItem &log_item, int64_t pos) diff --git a/deps/oblib/src/lib/queue/ob_priority_queue.h b/deps/oblib/src/lib/queue/ob_priority_queue.h index c9891e6ad..20190e0ca 100644 --- a/deps/oblib/src/lib/queue/ob_priority_queue.h +++ b/deps/oblib/src/lib/queue/ob_priority_queue.h @@ -101,11 +101,11 @@ private: DISALLOW_COPY_AND_ASSIGN(ObPriorityQueue); }; -template +template class ObPriorityQueue2 { public: - enum { PRIO_CNT = HIGH_HIGH_PRIOS + HIGH_PRIOS + LOW_PRIOS }; + enum { PRIO_CNT = HIGH_PRIOS + NORMAL_PRIOS + LOW_PRIOS }; ObPriorityQueue2() : queue_(), size_(0), limit_(INT64_MAX) {} ~ObPriorityQueue2() {} @@ -137,9 +137,9 @@ public: } else if (OB_FAIL(queue_[priority].push(data))) { // do nothing } else { - if (priority < HIGH_HIGH_PRIOS) { + if (priority < HIGH_PRIOS) { cond_.signal(1, 0); - } else if (priority < HIGH_PRIOS + HIGH_HIGH_PRIOS) { + } else if (priority < NORMAL_PRIOS + HIGH_PRIOS) { cond_.signal(1, 1); } else { cond_.signal(1, 2); @@ -157,14 +157,14 @@ public: return do_pop(data, PRIO_CNT, timeout_us); } - int pop_high(ObLink*& data, int64_t timeout_us) + int pop_normal(ObLink*& data, int64_t timeout_us) { - return do_pop(data, HIGH_HIGH_PRIOS + HIGH_PRIOS, timeout_us); + return do_pop(data, HIGH_PRIOS + NORMAL_PRIOS, timeout_us); } - int pop_high_high(ObLink*& data, int64_t timeout_us) + int pop_high(ObLink*& data, int64_t timeout_us) { - return do_pop(data, HIGH_HIGH_PRIOS, timeout_us); + return do_pop(data, HIGH_PRIOS, timeout_us); } private: @@ -175,9 +175,9 @@ private: ret = OB_INVALID_ARGUMENT; COMMON_LOG(ERROR, "timeout is invalid", K(ret), K(timeout_us)); } else { - if (plimit <= HIGH_HIGH_PRIOS) { + if (plimit <= HIGH_PRIOS) { cond_.prepare(0); - } else if (plimit <= HIGH_PRIOS + HIGH_HIGH_PRIOS) { + } else if (plimit <= NORMAL_PRIOS + HIGH_PRIOS) { cond_.prepare(1); } else { cond_.prepare(2); diff --git a/deps/oblib/src/lib/resource/achunk_mgr.cpp b/deps/oblib/src/lib/resource/achunk_mgr.cpp index d88c5f86e..ab6397a9c 100644 --- a/deps/oblib/src/lib/resource/achunk_mgr.cpp +++ b/deps/oblib/src/lib/resource/achunk_mgr.cpp @@ -23,7 +23,6 @@ #include "lib/alloc/alloc_struct.h" #include "lib/alloc/alloc_failed_reason.h" #include "lib/alloc/memory_sanity.h" -#include "lib/stat/ob_diagnose_info.h" using namespace oceanbase::lib; @@ -68,8 +67,6 @@ void *AChunkMgr::direct_alloc(const uint64_t size, const bool can_use_huge_page, { common::ObTimeGuard time_guard(__func__, 1000 * 1000); int orig_errno = errno; - EVENT_INC(MMAP_COUNT); - EVENT_ADD(MMAP_SIZE, size); void *ptr = nullptr; ptr = low_alloc(size, can_use_huge_page, huge_page_used, alloc_shadow); @@ -114,8 +111,7 @@ void *AChunkMgr::direct_alloc(const uint64_t size, const bool can_use_huge_page, void AChunkMgr::direct_free(const void *ptr, const uint64_t size) { common::ObTimeGuard time_guard(__func__, 1000 * 1000); - EVENT_INC(MUNMAP_COUNT); - EVENT_ADD(MUNMAP_SIZE, size); + ATOMIC_FAA(&unmaps_, 1); if (size > INTACT_ACHUNK_SIZE) { ATOMIC_FAA(&large_unmaps_, 1); diff --git a/deps/oblib/src/lib/resource/achunk_mgr.h b/deps/oblib/src/lib/resource/achunk_mgr.h index a2c560d37..0adb9a967 100644 --- a/deps/oblib/src/lib/resource/achunk_mgr.h +++ b/deps/oblib/src/lib/resource/achunk_mgr.h @@ -22,6 +22,7 @@ #include "lib/atomic/ob_atomic.h" #include "lib/ob_define.h" #include "lib/lock/ob_mutex.h" +#include "lib/ob_lib_config.h" namespace oceanbase { @@ -70,6 +71,7 @@ public: { bool bret = false; if (count() < max_chunk_cache_cnt_) { + ObDisableDiagnoseGuard disable_diagnose_guard; if (with_mutex_) { mutex_.lock(); } @@ -97,6 +99,7 @@ public: { AChunk *chunk = NULL; if (!OB_ISNULL(header_)) { + ObDisableDiagnoseGuard disable_diagnose_guard; if (with_mutex_) { mutex_.lock(); } diff --git a/deps/oblib/src/lib/resource/ob_resource_mgr.cpp b/deps/oblib/src/lib/resource/ob_resource_mgr.cpp index 5fc35eec8..b7e0497e5 100644 --- a/deps/oblib/src/lib/resource/ob_resource_mgr.cpp +++ b/deps/oblib/src/lib/resource/ob_resource_mgr.cpp @@ -16,6 +16,7 @@ #include #include +#include "lib/alloc/memory_sanity.h" #include "lib/oblog/ob_log.h" #include "lib/stat/ob_diagnose_info.h" #include "lib/utility/utility.h" @@ -427,6 +428,7 @@ ObResourceMgr::ObResourceMgr() : inited_(false), cache_washer_(NULL), locks_(), tenant_resource_mgrs_() { for (int64_t i = 0; i < MAX_TENANT_COUNT; ++i) { + locks_[i].enable_record_stat(false); locks_[i].set_latch_id(common::ObLatchIds::TENANT_RES_MGR_LIST_LOCK); } } @@ -461,6 +463,7 @@ ObResourceMgr &ObResourceMgr::get_instance() static ObResourceMgr resource_mgr; if (!resource_mgr.inited_) { // use first lock to avoid concurrent init of resource mgr + ObDisableDiagnoseGuard disable_diagnose_guard; SpinWLockGuard guard(resource_mgr.locks_[0]); if (!resource_mgr.inited_) { int ret = OB_SUCCESS; @@ -481,6 +484,7 @@ int ObResourceMgr::set_cache_washer(ObICacheWasher &cache_washer) } else { cache_washer_ = &cache_washer; for (int64_t pos = 0; pos < MAX_TENANT_COUNT; ++pos) { + ObDisableDiagnoseGuard disable_diagnose_guard; SpinWLockGuard guard(locks_[pos]); ObTenantResourceMgr *tenant_resource_mgr = tenant_resource_mgrs_[pos]; while (NULL != tenant_resource_mgr) { @@ -505,6 +509,7 @@ int ObResourceMgr::get_tenant_resource_mgr(const uint64_t tenant_id, LOG_WARN("invalid argument", K(ret), K(tenant_id)); } else { const int64_t pos = tenant_id % MAX_TENANT_COUNT; + ObDisableDiagnoseGuard disable_diagnose_guard; ObTenantResourceMgr *tenant_resource_mgr = NULL; { SpinRLockGuard guard(locks_[pos]); @@ -555,6 +560,7 @@ void ObResourceMgr::dec_ref(ObTenantResourceMgr *tenant_resource_mgr) int64_t ref_cnt = 0; if (0 == (ref_cnt = ATOMIC_SAF(&tenant_resource_mgr->ref_cnt_, 1))) { const int64_t pos = tenant_resource_mgr->tenant_id_ % MAX_TENANT_COUNT; + ObDisableDiagnoseGuard disable_diagnose_guard; SpinWLockGuard guard(locks_[pos]); if (0 == ATOMIC_LOAD(&tenant_resource_mgr->ref_cnt_)) { int ret = OB_SUCCESS; diff --git a/deps/oblib/src/lib/stat/ob_di_cache.cpp b/deps/oblib/src/lib/stat/ob_di_cache.cpp index 4a23e7789..f9ed3a376 100644 --- a/deps/oblib/src/lib/stat/ob_di_cache.cpp +++ b/deps/oblib/src/lib/stat/ob_di_cache.cpp @@ -76,7 +76,7 @@ ObDISessionCache &ObDISessionCache::get_instance() int ObDISessionCache::get_node(uint64_t session_id, ObDISessionCollect *&session_collect) { int ret = OB_SUCCESS; - ObRandom *random = ObDITls::get_instance(); + ObRandom *random = GET_TSI(ObRandom); ObSessionBucket &bucket = di_map_[session_id % OB_MAX_SERVER_SESSION_CNT]; while (1) { bucket.lock_.rdlock(); @@ -227,7 +227,7 @@ int ObDIThreadTenantCache::get_node(uint64_t tenant_id, ObDITenantCollect *&tena int ret = OB_SUCCESS; if (OB_ISNULL(tenant_collect = tenant_cache_.get_node(tenant_id, tenant_collect))) { if (nullptr == extend_tenant_cache_) { - extend_tenant_cache_ = ObDITls>::get_instance(); + extend_tenant_cache_ = GET_TSI(ObDIBaseTenantCache); } if (nullptr != extend_tenant_cache_) { tenant_collect = extend_tenant_cache_->get_node(tenant_id, tenant_collect); diff --git a/deps/oblib/src/lib/stat/ob_di_tls.h b/deps/oblib/src/lib/stat/ob_di_tls.h index d831fe787..358642a04 100644 --- a/deps/oblib/src/lib/stat/ob_di_tls.h +++ b/deps/oblib/src/lib/stat/ob_di_tls.h @@ -14,102 +14,154 @@ #define OB_DI_TLS_H_ #include "lib/ob_define.h" +#include "lib/allocator/ob_malloc.h" + +#include namespace oceanbase { namespace common { - -template +template class ObDITls { + // avoid reconstruct during construction. + static constexpr uint64_t PLACE_HOLDER = 0x1; + static constexpr uint64_t MAX_TNAME_LENGTH = 128; public: - static ObDITls &get_di_tls(); - void destroy(); - T *new_instance(); - static T *get_instance(); + static T* get_instance(); + OB_INLINE bool is_valid() { return OB_NOT_NULL(instance_) && PLACE_HOLDER != (uint64_t)instance_; } private: - ObDITls() : key_(INT32_MAX) - { - if (0 != pthread_key_create(&key_, destroy_thread_data_)) { - } - } - ~ObDITls() { destroy(); } - static void destroy_thread_data_(void *ptr); + ObDITls() : instance_(nullptr) {} + ~ObDITls(); + static const char* get_label(); private: - pthread_key_t key_; - static TLOCAL(T *, instance_); - static TLOCAL(bool, disable_); + T* instance_; }; -// NOTE: thread local diagnose information -// TODO: check if multi-query execute within one thread. -template -TLOCAL(T *, ObDITls::instance_); -template -TLOCAL(bool, ObDITls::disable_); -template -void ObDITls::destroy_thread_data_(void *ptr) -{ - if (NULL != ptr) { - T *tls = (T *)ptr; - instance_ = NULL; - disable_ = true; - delete tls; - } -} - -template -ObDITls &ObDITls::get_di_tls() -{ - static ObDITls di_tls; - return di_tls; -} - -template -void ObDITls::destroy() -{ - if (INT32_MAX != key_) { - void *ptr = pthread_getspecific(key_); - destroy_thread_data_(ptr); - if (0 != pthread_key_delete(key_)) { +template +const char* ObDITls::get_label() { + const char* cxxname = typeid(T).name(); + const char* ret = "DITls"; + static char buf[MAX_TNAME_LENGTH]; + if (nullptr == cxxname || strlen(cxxname) > MAX_TNAME_LENGTH - 5) { + // do nothing, avoid realloc in __cxa_demangle + } else { + int status = 0; + int length = MAX_TNAME_LENGTH - 3; + ret = abi::__cxa_demangle(cxxname, buf + 3, (size_t*)&length, &status); + if (0 != status) { + ret = "DITls"; } else { - key_ = INT32_MAX; + // remove namespace + length = MAX_TNAME_LENGTH - 1; + while (length >= 3 && buf[length] != ':') { + --length; + } + length -= 2; + buf[length] = '['; + buf[length + 1] = 'T'; + buf[length + 2] = ']'; + ret = buf + length; } } + return ret; } -template -T *ObDITls::new_instance() +template +ObDITls::~ObDITls() { - T *instance = NULL; - if (INT32_MAX != key_) { - T *tls = (T *)pthread_getspecific(key_); - if (NULL == tls) { - tls = new (std::nothrow) T(); - if (NULL != tls && 0 != pthread_setspecific(key_, tls)) { - delete tls; - tls = NULL; + if (is_valid()) { + ob_delete(instance_); + instance_ = nullptr; + } +} + +template +T* ObDITls::get_instance() +{ + static thread_local ObDITls di_tls; + if (!di_tls.is_valid()) { + static const char* label = get_label(); + di_tls.instance_ = (T*)PLACE_HOLDER; + // add tenant + di_tls.instance_ = OB_NEW(T, label); + } + return di_tls.instance_; +} + +template +class ObDITls +{ + // avoid reconstruct during construction. + static constexpr uint64_t PLACE_HOLDER = 0x1; + static constexpr uint64_t MAX_TNAME_LENGTH = 128; +public: + static T* get_instance(); + OB_INLINE bool is_valid() { return OB_NOT_NULL(instance_) && PLACE_HOLDER != (uint64_t)instance_; } +private: + ObDITls() : instance_(nullptr) {} + ~ObDITls(); + static const char* get_label(); +private: + T* instance_; +}; + +template +const char* ObDITls::get_label() { + const char* cxxname = typeid(T).name(); + const char* ret = "DITls"; + static char buf[MAX_TNAME_LENGTH]; + if (nullptr == cxxname || strlen(cxxname) > MAX_TNAME_LENGTH - 5) { + // do nothing, avoid realloc in __cxa_demangle + } else { + int status = 0; + int length = MAX_TNAME_LENGTH - 3; + ret = abi::__cxa_demangle(cxxname, buf + 3, (size_t*)&length, &status); + if (0 != status) { + ret = "DITls"; + } else { + // remove namespace + length = MAX_TNAME_LENGTH - 1; + while (length >= 3 && buf[length] != ':') { + --length; + } + length -= 2; + buf[length] = '['; + buf[length + 1] = 'T'; + buf[length + 2] = ']'; + ret = buf + length; + } + } + return ret; +} + +template +ObDITls::~ObDITls() +{ + if (is_valid()) { + for (auto i = 0; i < N; ++i) { + instance_[i].~T(); + } + ob_free(instance_); + } +} + +template +T* ObDITls::get_instance() +{ + static thread_local ObDITls di_tls; + if (!di_tls.is_valid()) { + static const char* label = get_label(); + di_tls.instance_ = (T*)PLACE_HOLDER; + // add tenant + if (OB_NOT_NULL(di_tls.instance_ = (T*)ob_malloc(sizeof(T) * N, label))) { + for (auto i = 0; i < N; ++i) { + new (di_tls.instance_ + i) T; } } - if (NULL != tls) { - instance = tls; - } } - return instance; -} - -template -T *ObDITls::get_instance() -{ - if (OB_UNLIKELY(NULL == instance_)) { - if (OB_LIKELY(!disable_)) { - disable_ = true; - instance_ = get_di_tls().new_instance(); - disable_ = false; - } - } - return instance_; + return di_tls.instance_; } } diff --git a/deps/oblib/src/lib/stat/ob_diagnose_info.cpp b/deps/oblib/src/lib/stat/ob_diagnose_info.cpp index 6ae23577f..05dd9fc17 100644 --- a/deps/oblib/src/lib/stat/ob_diagnose_info.cpp +++ b/deps/oblib/src/lib/stat/ob_diagnose_info.cpp @@ -555,7 +555,7 @@ ObDiagnoseSessionInfo *ObDiagnoseSessionInfo::get_local_diagnose_info() if (lib::is_diagnose_info_enabled()) { ObDISessionCollect *collect = NULL; ObSessionDIBuffer *buffer = NULL; - buffer = ObDITls::get_instance(); + buffer = GET_TSI(ObSessionDIBuffer); if (NULL != buffer) { collect = buffer->get_curr_session(); if (NULL != collect) { @@ -656,7 +656,7 @@ ObDiagnoseTenantInfo *ObDiagnoseTenantInfo::get_local_diagnose_info() if (lib::is_diagnose_info_enabled()) { ObDITenantCollect *collect = NULL; ObSessionDIBuffer *buffer = NULL; - buffer = ObDITls::get_instance(); + buffer = GET_TSI(ObSessionDIBuffer); if (NULL != buffer) { if (NULL == (collect = buffer->get_curr_tenant())) { if (OB_FAIL(buffer->switch_tenant(OB_SYS_TENANT_ID))) { diff --git a/deps/oblib/src/lib/stat/ob_session_stat.cpp b/deps/oblib/src/lib/stat/ob_session_stat.cpp index 26730ba86..b9deb7061 100644 --- a/deps/oblib/src/lib/stat/ob_session_stat.cpp +++ b/deps/oblib/src/lib/stat/ob_session_stat.cpp @@ -40,7 +40,7 @@ ObSessionStatEstGuard::ObSessionStatEstGuard(const uint64_t tenant_id, const uin prev_session_id_(0) { if (oceanbase::lib::is_diagnose_info_enabled()) { - buffer_ = ObDITls::get_instance(); + buffer_ = GET_TSI(ObSessionDIBuffer); if (NULL != buffer_) { prev_tenant_id_ = buffer_->get_tenant_id(); if (NULL != (buffer_->get_curr_session())) { @@ -67,9 +67,5 @@ ObSessionStatEstGuard::~ObSessionStatEstGuard() } } -void __attribute__((constructor(101))) init_SessionDIBuffer() -{ - oceanbase::common::ObDITls::get_instance(); -} } /* namespace common */ } /* namespace oceanbase */ diff --git a/deps/oblib/src/lib/stat/ob_session_stat.h b/deps/oblib/src/lib/stat/ob_session_stat.h index b826dd2a2..bf133b994 100644 --- a/deps/oblib/src/lib/stat/ob_session_stat.h +++ b/deps/oblib/src/lib/stat/ob_session_stat.h @@ -14,7 +14,7 @@ #define OB_SESSION_STAT_H_ #include "lib/stat/ob_di_cache.h" -#include "lib/stat/ob_di_tls.h" +#include "lib/thread_local/ob_tsi_factory.h" namespace oceanbase { @@ -77,7 +77,7 @@ public: : prev_tenant_id_(OB_SYS_TENANT_ID) { if (oceanbase::lib::is_diagnose_info_enabled()) { - buffer_ = ObDITls::get_instance(); + buffer_ = GET_TSI(ObSessionDIBuffer); if (NULL != buffer_) { prev_tenant_id_ = buffer_->get_tenant_id(); if (0 < tenant_id) { diff --git a/deps/oblib/src/lib/statistic_event/ob_stat_event.h b/deps/oblib/src/lib/statistic_event/ob_stat_event.h index e00ae7ed4..125e9b81f 100644 --- a/deps/oblib/src/lib/statistic_event/ob_stat_event.h +++ b/deps/oblib/src/lib/statistic_event/ob_stat_event.h @@ -197,10 +197,10 @@ STAT_EVENT_ADD_DEF(LOCATION_CACHE_NONBLOCK_MISS, "location nonblock get miss", O STAT_EVENT_ADD_DEF(LOCATION_CACHE_RPC_CHECK, "location cache rpc renew count", ObStatClassIds::CACHE, "location cache rpc renew count", 50021, true, true) STAT_EVENT_ADD_DEF(LOCATION_CACHE_RENEW, "location cache renew", ObStatClassIds::CACHE, "location cache renew", 50022, true, true) STAT_EVENT_ADD_DEF(LOCATION_CACHE_RENEW_IGNORED, "location cache renew ignored", ObStatClassIds::CACHE, "location cache renew ignored", 50023, true, true) -STAT_EVENT_ADD_DEF(MMAP_COUNT, "mmap count", ObStatClassIds::CACHE, "mmap count", 50024, true, true) -STAT_EVENT_ADD_DEF(MUNMAP_COUNT, "munmap count", ObStatClassIds::CACHE, "munmap count", 50025, true, true) -STAT_EVENT_ADD_DEF(MMAP_SIZE, "mmap size", ObStatClassIds::CACHE, "mmap size", 50026, true, true) -STAT_EVENT_ADD_DEF(MUNMAP_SIZE, "munmap size", ObStatClassIds::CACHE, "munmap size", 50027, true, true) +//STAT_EVENT_ADD_DEF(MMAP_COUNT, "mmap count", ObStatClassIds::CACHE, "mmap count", 50024, true, true) +//STAT_EVENT_ADD_DEF(MUNMAP_COUNT, "munmap count", ObStatClassIds::CACHE, "munmap count", 50025, true, true) +//STAT_EVENT_ADD_DEF(MMAP_SIZE, "mmap size", ObStatClassIds::CACHE, "mmap size", 50026, true, true) +//STAT_EVENT_ADD_DEF(MUNMAP_SIZE, "munmap size", ObStatClassIds::CACHE, "munmap size", 50027, true, true) STAT_EVENT_ADD_DEF(KVCACHE_SYNC_WASH_TIME, "kvcache sync wash time", ObStatClassIds::CACHE, "kvcache sync wash time", 50028, true, true) STAT_EVENT_ADD_DEF(KVCACHE_SYNC_WASH_COUNT, "kvcache sync wash count", ObStatClassIds::CACHE, "kvcache sync wash count", 50029, true, true) STAT_EVENT_ADD_DEF(LOCATION_CACHE_RPC_RENEW_FAIL, "location cache rpc renew fail count", ObStatClassIds::CACHE, "location cache rpc renew fail count", 50030, true, true) diff --git a/deps/oblib/src/lib/task/ob_timer.cpp b/deps/oblib/src/lib/task/ob_timer.cpp index 2c8041a4a..31c93c8fb 100644 --- a/deps/oblib/src/lib/task/ob_timer.cpp +++ b/deps/oblib/src/lib/task/ob_timer.cpp @@ -294,6 +294,7 @@ void ObTimer::run1() set_thread_name("ObTimer"); } while (true) { + IGNORE_RETURN lib::Thread::update_loop_ts(); { ObMonitor::Lock guard(monitor_); static const int64_t STATISTICS_INTERVAL_US = 600L * 1000 * 1000; // 10m diff --git a/deps/oblib/src/lib/thread/ob_async_task_queue.cpp b/deps/oblib/src/lib/thread/ob_async_task_queue.cpp index 3f3632447..d7ee4ee16 100644 --- a/deps/oblib/src/lib/thread/ob_async_task_queue.cpp +++ b/deps/oblib/src/lib/thread/ob_async_task_queue.cpp @@ -112,6 +112,7 @@ void ObAsyncTaskQueue::run2() } else { ObAddr zero_addr; while (!stop_) { + IGNORE_RETURN lib::Thread::update_loop_ts(ObTimeUtility::fast_current_time()); if (REACH_TIME_INTERVAL(600 * 1000 * 1000)) { //每隔一段时间,打印队列的大小 LOG_INFO("[ASYNC TASK QUEUE]", "queue_size", queue_.size()); diff --git a/deps/oblib/src/lib/thread/ob_reentrant_thread.h b/deps/oblib/src/lib/thread/ob_reentrant_thread.h index 69006ae2e..3d239ee31 100644 --- a/deps/oblib/src/lib/thread/ob_reentrant_thread.h +++ b/deps/oblib/src/lib/thread/ob_reentrant_thread.h @@ -40,7 +40,11 @@ public: void logical_stop(); void logical_wait(); void wait() override; // wait running task stoped - bool has_set_stop() const override { return ATOMIC_LOAD(&stop_); }; + bool has_set_stop() const override + { + IGNORE_RETURN lib::Thread::update_loop_ts(); + return ATOMIC_LOAD(&stop_); + } // destroy thread int destroy(); diff --git a/deps/oblib/src/lib/thread/ob_thread_name.h b/deps/oblib/src/lib/thread/ob_thread_name.h index 318d2fd1c..eaf360168 100644 --- a/deps/oblib/src/lib/thread/ob_thread_name.h +++ b/deps/oblib/src/lib/thread/ob_thread_name.h @@ -32,6 +32,7 @@ inline void set_thread_name(const char* type, uint64_t idx) { char *name = ob_get_tname(); uint64_t tenant_id = ob_get_tenant_id(); + ob_get_origin_thread_name() = type; if (tenant_id == 0) { snprintf(name, OB_THREAD_NAME_BUF_LEN, "%s%ld", type, idx); } else { @@ -44,6 +45,7 @@ inline void set_thread_name(const char* type) { char *name = ob_get_tname(); uint64_t tenant_id = ob_get_tenant_id(); + ob_get_origin_thread_name() = type; if (tenant_id == 0) { snprintf(name, OB_THREAD_NAME_BUF_LEN, "%s", type); } else { diff --git a/deps/oblib/src/lib/thread/protected_stack_allocator.h b/deps/oblib/src/lib/thread/protected_stack_allocator.h index 12c6180e1..c0c334cb5 100644 --- a/deps/oblib/src/lib/thread/protected_stack_allocator.h +++ b/deps/oblib/src/lib/thread/protected_stack_allocator.h @@ -43,8 +43,8 @@ public: void dealloc(void *ptr); static ssize_t adjust_size(const ssize_t size); static ObStackHeader *stack_header(void *ptr); -private: static ssize_t page_size(); +private: void *__alloc(const uint64_t tenant_id, const ssize_t size); }; diff --git a/deps/oblib/src/lib/thread/thread.cpp b/deps/oblib/src/lib/thread/thread.cpp index 7a6d3b287..d710c3b86 100644 --- a/deps/oblib/src/lib/thread/thread.cpp +++ b/deps/oblib/src/lib/thread/thread.cpp @@ -30,7 +30,8 @@ using namespace oceanbase; using namespace oceanbase::common; using namespace oceanbase::lib; -TLOCAL(Thread *, Thread::current_thread_) = nullptr; +thread_local int64_t Thread::loop_ts_ = 0; +thread_local Thread* Thread::current_thread_ = nullptr; int64_t Thread::total_thread_count_ = 0; Thread &Thread::current() diff --git a/deps/oblib/src/lib/thread/thread.h b/deps/oblib/src/lib/thread/thread.h index 5c8010118..389cdc633 100644 --- a/deps/oblib/src/lib/thread/thread.h +++ b/deps/oblib/src/lib/thread/thread.h @@ -14,6 +14,7 @@ #define CORO_THREAD_H #include +#include "lib/time/ob_time_utility.h" #include "lib/utility/ob_macro_utils.h" namespace oceanbase { @@ -48,10 +49,24 @@ public: bool has_set_stop() const; + OB_INLINE static int64_t update_loop_ts(int64_t t) + { + int64_t ret = loop_ts_; + loop_ts_ = t; + return ret; + } + + OB_INLINE static int64_t update_loop_ts() + { + return update_loop_ts(common::ObTimeUtility::fast_current_time()); + } +public: + static thread_local int64_t loop_ts_; + private: static void* __th_start(void *th); void destroy_stack(); - static TLOCAL(Thread *, current_thread_); + static thread_local Thread* current_thread_; private: static int64_t total_thread_count_; @@ -80,6 +95,7 @@ OB_INLINE pid_t Thread::get_tid() const OB_INLINE bool Thread::has_set_stop() const { + IGNORE_RETURN update_loop_ts(); return stop_; } diff --git a/deps/oblib/src/lib/thread/thread_mgr_interface.h b/deps/oblib/src/lib/thread/thread_mgr_interface.h index cf6faf521..fde93a060 100644 --- a/deps/oblib/src/lib/thread/thread_mgr_interface.h +++ b/deps/oblib/src/lib/thread/thread_mgr_interface.h @@ -26,6 +26,7 @@ public: virtual void run1() = 0; bool has_set_stop() const { + IGNORE_RETURN lib::Thread::update_loop_ts(); return ATOMIC_LOAD(&stop_); } void set_stop(bool stop) diff --git a/deps/oblib/src/lib/thread/threads.cpp b/deps/oblib/src/lib/thread/threads.cpp index 36c406ec7..489a5d2df 100644 --- a/deps/oblib/src/lib/thread/threads.cpp +++ b/deps/oblib/src/lib/thread/threads.cpp @@ -278,8 +278,3 @@ void Threads::destroy() threads_ = nullptr; } } - -void Threads::set_thread_max_tasks(uint64_t cnt) -{ - thread_max_tasks_ = cnt; -} diff --git a/deps/oblib/src/lib/thread/threads.h b/deps/oblib/src/lib/thread/threads.h index 7a49b7648..4f14d9db0 100644 --- a/deps/oblib/src/lib/thread/threads.h +++ b/deps/oblib/src/lib/thread/threads.h @@ -58,7 +58,6 @@ public: threads_(nullptr), stack_size_(global_thread_stack_size), stop_(true), - thread_max_tasks_(INT64_MAX), run_wrapper_(nullptr), cgroup_(INVALID_CGROUP) {} @@ -103,8 +102,6 @@ public: return threads_[0]->get_tid(); } public: - void set_thread_max_tasks(uint64_t cnt); - template int submit(const Functor &func) { @@ -113,9 +110,17 @@ public: return ret; } ThreadCGroup get_cgroup() { return cgroup_; } + virtual bool has_set_stop() const + { + IGNORE_RETURN lib::Thread::update_loop_ts(); + return ATOMIC_LOAD(&stop_); + } + bool &has_set_stop() + { + IGNORE_RETURN lib::Thread::update_loop_ts(); + return stop_; + } protected: - virtual bool has_set_stop() const { return ATOMIC_LOAD(&stop_); } - bool &has_set_stop() { return stop_; } int64_t get_thread_count() const { return n_threads_; } uint64_t get_thread_idx() const { return thread_idx_; } void set_thread_idx(int64_t idx) { thread_idx_ = idx; } @@ -140,7 +145,6 @@ private: bool stop_; // protect for thread count changing. common::SpinRWLock lock_; - int64_t thread_max_tasks_; // tenant ctx IRunWrapper *run_wrapper_; // thread cgroups diff --git a/deps/oblib/src/lib/thread_local/ob_tsi_factory.h b/deps/oblib/src/lib/thread_local/ob_tsi_factory.h index e655823c8..adf3c5df5 100644 --- a/deps/oblib/src/lib/thread_local/ob_tsi_factory.h +++ b/deps/oblib/src/lib/thread_local/ob_tsi_factory.h @@ -12,457 +12,17 @@ #ifndef OCEANBASE_COMMON_OB_TSI_FACTORY_ #define OCEANBASE_COMMON_OB_TSI_FACTORY_ -#include -#include -#include -#include -#include -#include -#include "lib/ob_define.h" -#include "lib/allocator/page_arena.h" -#include "lib/allocator/ob_malloc.h" -#include "lib/allocator/ob_mod_define.h" + +#include "lib/stat/ob_di_tls.h" namespace oceanbase { namespace common { -enum TSICommonType -{ - TSI_COMMON_OBJPOOL_1 = 1001, - TSI_COMMON_SCAN_PARAM_1, - TSI_COMMON_SCANNER_1, - TSI_COMMON_MUTATOR_1, - TSI_COMMON_THE_META_1, - TSI_COMMON_GET_PARAM_1, - TSI_COMMON_MULTI_WAKEUP_1, - TSI_COMMON_PACKET_TRACE_ID_1, - TSI_COMMON_SEQ_ID_1, - TSI_COMMON_OBSERVER_1, - TSI_COMMON_TO_CSTRING_BUFFER_OBJ_1, - TSI_COMMON_TO_CSTRING_BUFFER_OBJ_2, - TSI_COMMON_TO_CSTRING_BUFFER_OBJ_3, - TSI_COMMON_DEBUG_SYNC_ARRAY, -}; - -enum TSISSTableType -{ - TSI_SSTABLE_FILE_BUFFER_1 = 2001, - TSI_SSTABLE_THREAD_AIO_BUFFER_MGR_ARRAY_1, - TSI_SSTABLE_MODULE_ARENA_1, - TSI_SSTABLE_COMPRESS_BUFFER_MODULE_ARENA_1, - TSI_SSTABLE_COLUMN_CHECKSUM_MODULE_ARENA_1 -}; - -enum TSIBlockSSTableType -{ - TSI_BLOCKSSTABLE_FILE_BUFFER_1 = 11001, - TSI_BLOCKSSTABLE_FILE_BUFFER_2 = 11002, - TSI_BLOCKSSTABLE_ROW_CHECKSUM_GENERATOR_1, - TSI_BLOCKSSTABLE_BLOCK_INDEX_MGR, - TSI_BLOCKSSTABLE_BLOCK_INDEX_TRANSFORMER, - TSI_BLOCKSSTABLE_TABLET_ARRAY_1, - TSI_BLOCKSSTABLE_GET_READER_ARRAY_1, - TSI_BLOCKSSTABLE_SCAN_READER_ARRAY_1, - TSI_BLOCKSSTABLE_CHUNK_LOG_WRITER_1, - TSI_BLOCKSSTABLE_MACRO_BLOCK_META_LOG_1, - TSI_BLOCKSSTABLE_SSTABLE_SCHEMA_1, - TSI_BLOCKSSTABLE_FETCH_DATA_1, - TSI_BLOCKSSTABLE_SEND_DATA_1, -}; - -enum TSIChunkserverType -{ - TSI_CS_SCANNER_1 = 3001, - TSI_CS_NEW_SCANNER_1, - TSI_CS_NEW_SCANNER_2, - TSI_CS_GET_PARAM_1, - TSI_CS_SCAN_PARAM_1, - TSI_CS_SQL_SCAN_PARAM_1, - TSI_CS_SQL_GET_PARAM_1, - TSI_CS_TABLET_REPORT_INFO_LIST_1, - TSI_CS_TABLET_REPORT_INFO_LIST_2, - TSI_CS_SSTABLE_GETTER_1, - TSI_CS_GET_THREAD_CONTEXT_1, - TSI_CS_SSTABLE_SCANNER_1, - TSI_CS_SCHEMA_DECODER_ASSIS_1, - TSI_CS_THEEAD_META_WRITER_1, - TSI_CS_COMPACTSSTABLE_ITERATOR_1, - TSI_CS_COMPACTSSTABLE_GET_SCANEER_1, - TSI_CS_COLUMNFILTER_1, - TSI_CS_QUERY_SERVICE_1, - TSI_CS_TABLET_SERVICE_1, - TSI_CS_STATIC_DATA_SERVICE_1, - TSI_CS_MULTI_TABLET_MERGER_1, - TSI_CS_TABLE_IMPORT_INFO_1, - TSI_CS_FETCH_DATA_1, - TSI_CS_FETCH_DATA_2, - TSI_CS_SSTABLE_SCAN_PARAM_1, - TSI_CS_MEDIATING_ALLOCATOR_1, - TSI_CS_TABLE_LOCAL_INDEX_BUILDER_1, - TSI_CS_TABLE_LOCAL_INDEX_SAMPLER_1, - TSI_CS_TABLE_GLOBAL_INDEX_BUILDER_1, - TSI_CS_MIGRATE_SCAN_1, - TSI_CS_MIGRATE_SCAN_2, - TSI_CS_TABLET_DATA_CORRECTION_REPORT_INFO_LIST, -}; - -enum TSIUpdateserverType -{ - TSI_UPS_SCANNER_1 = 4001, - TSI_UPS_NEW_SCANNER_1, - TSI_UPS_NEW_SCANNER_2, - TSI_UPS_GET_PARAM_1, - TSI_UPS_SCAN_PARAM_1, - TSI_UPS_INC_SCAN_1, - TSI_UPS_INC_GET_1, - TSI_UPS_MUTATOR_1, - TSI_UPS_SCANNER_ARRAY_1, - TSI_UPS_UPS_MUTATOR_1, - TSI_UPS_TABLE_UTILS_SET_1, - TSI_UPS_COLUMN_FILTER_1, - TSI_UPS_COLUMN_MAP_1, - TSI_UPS_TABLE_LIST_1, - TSI_UPS_ROW_COMPACTION_1, - TSI_UPS_ROW_COMPACTION_2, - TSI_UPS_CLIENT_WRAPPER_TSI_1, - TSI_UPS_FIXED_SIZE_BUFFER_1, - TSI_UPS_FIXED_SIZE_BUFFER_2, - TSI_UPS_SCAN_PARAM_2, - TSI_UPS_SQL_SCAN_PARAM_1, - TSI_UPS_ARENA_ALLOC_1, - TSI_UPS_SCAN_MERGE_1, - TSI_UPS_GET_MERGE_1, - TSI_UPS_SQL_MULTI_SCAN_MERGE_1, - TSI_UPS_SCHEMA_MGR_1, - TSI_UPS_SINGLE_GET_PARAM_1, - TSI_UPS_EMPTY_SCAN_1, - TSI_UPS_EMPTY_GET_1, - TSI_UPS_TABLE_DUMP_1, -}; - -enum TSIMergeserverType -{ - TSI_MS_SCANNER_1 = 5001, - TSI_MS_ORG_GET_PARAM_1, - TSI_MS_DECODED_GET_PARAM_1, - TSI_MS_GET_PARAM_WITH_NAME_1, - TSI_MS_ORG_SCAN_PARAM_1, - TSI_MS_DECODED_SCAN_PARAM_1, - TSI_MS_SCHEMA_DECODER_ASSIS_1, - TSI_MS_GET_EVENT_1, - TSI_MS_SCAN_EVENT_1, - TSI_MS_MS_SCAN_PARAM_1, - TSI_MS_ORG_MUTATOR_1, - TSI_MS_DECODED_MUTATOR_1, - TSI_MS_UPS_SCANNER_1, - TSI_MS_NEW_SCANNER_1, - TSI_MS_NEW_SCANNER_2, - TSI_MS_SQL_SCAN_PARAM_1, - TSI_MS_SERVER_COUNTER_ID, - TSI_MS_MGET_STRING_BUF_1, - TSI_MS_SCAN_STRING_BUF_1, -}; - -enum TSIOlapDrive -{ - TSI_OLAP_SCAN_EXTRA_INFO_1 = 6001, - TSI_OLAP_THREAD_ROW_KEY_1, - TSI_OLAP_GET_PARAM_1, - TSI_OLAP_SCAN_PARAM_1, - TSI_OLAP_SCANNER_1, - TSI_OLAP_MUTATOR_1, -}; - -enum TSISqlType -{ - TSI_SQL_GET_PARAM_1 = 7001, - TSI_SQL_GET_PARAM_2 = 7002, - TSI_SQL_EXPR_STACK_1 = 7003, - TSI_SQL_EXPR_EXTRA_PARAMS_1 = 7005, - TSI_SQL_TP_ARENA_1 = 7006, - TSI_SQL_ROW_1 = 7007, - TSI_SQL_PLAN_EXECUTOR_1 = 7008, - TSI_SQL_EXPLAIN_FORMATOR_1 = 7009, - TSI_SQL_CALC_BUF_1 = 7010, -}; - -enum TSIMySQLType -{ - TSI_MYSQL_CLIENT_WAIT_1 = 8001, - TSI_MYSQL_RESULT_SET_1, - TSI_MYSQL_PREPARE_RESULT_1, - TSI_MYSQL_SESSION_KEY_1, -}; - -enum TSIRootserverType -{ - TSI_RS_SCANNER_1 = 9001, - TSI_RS_GET_PARAM_1, - TSI_RS_MS_PROVIDER_1, - TSI_RS_NEW_SCANNER_1, - TSI_RS_SQL_SCAN_PARAM_1, - TSI_RS_NEW_SCANNER_2, - TSI_RS_SCHEMA_MGR_1, -}; - -enum TSIProxyserverType -{ - TSI_YUNTI_PROXY_READER_1 = 10001, - TSI_YUNTI_PROXY_READER_2, -}; - -enum TSILiboblogType -{ - TSI_LIBOBLOG_PARTITION = 11001, - TSI_LIBOBLOG_DML_STMT, - TSI_LIBOBLOG_MYSQL_ADAPTOR, - TSI_LIBOBLOG_META_MANAGER, - TSI_LIBOBLOG_ROW_VALUE, - TSI_LIBOBLOG_SERVER_SELECTOR, - TSI_LIBOBLOG_MYSQL_QUERY_RESULT, -}; - -enum TSICLogType -{ - TSI_CLOG_READER_TSIINFO = 12001, - TSI_CLOG_WRITE_AIOPARAM, -}; - -enum TSIMemtableType -{ -}; - -enum TSITransType -{ -}; - -#define GET_TSI0(type) ::oceanbase::common::TSIFactory::get_instance() -#define GET_TSI_MULT0(type, tag) ::oceanbase::common::TSIFactory::get_instance() -#define GET_TSI(type) ::oceanbase::common::TSIFactory::get_instance() -#define GET_TSI_MULT(type, tag) ::oceanbase::common::TSIFactory::get_instance() - -template -class Wrapper -{ -public: - Wrapper() : instance_(NULL) {} - ~Wrapper() - { - if (NULL != instance_) { - delete instance_; - instance_ = NULL; - } - } -public: - T *&get_instance() { return instance_; } -private: - T *instance_; -}; - -#define GET_TSI_ARGS(type, num, args...) \ - ({ \ - type *__type_ret__ = NULL; \ - Wrapper *__type_wrapper__ = GET_TSI_MULT(Wrapper, num); \ - if (NULL != __type_wrapper__) \ - { \ - __type_ret__ = __type_wrapper__->get_instance(); \ - if (NULL == __type_ret__) \ - { \ - __type_wrapper__->get_instance() = new(std::nothrow) type(args); \ - __type_ret__ = __type_wrapper__->get_instance(); \ - } \ - } \ - __type_ret__; \ - }) -// GET_TSI(Wrapper) ? (GET_TSI(Wrapper)->get_instance() ? (GET_TSI(Wrapper)->get_instance()) : -// (GET_TSI(Wrapper)->get_instance() = new(std::nothrow) type(args))) : NULL - -class TSINodeBase -{ -public: - TSINodeBase() : next(NULL) {} - virtual ~TSINodeBase() { next = NULL; } - TSINodeBase *next; -}; - -template -class TSINode : public TSINodeBase -{ -public: - explicit TSINode(T *instance) : instance_(instance) {} - virtual ~TSINode() - { - // FIXME: support print log at this point. - // - // Currently syslog need COVAR information e.g. TRACE ID, - // log_limiter. But when thread exits rouine's context has been - // destroyed. - if (NULL != instance_) { - // _LIB_LOG(INFO, "delete instance [%s] %p", typeid(T).name(), instance_); - instance_->~T(); - instance_ = NULL; - } - } -private: - T *instance_; -}; - -template -class TSINode : public TSINodeBase -{ -public: - explicit TSINode(T (*instance)[N]) : instance_(*instance) {} - virtual ~TSINode() - { - if (nullptr != instance_) { - for (int i = 0; i < N; i++) { - instance_[i].~T(); - } - instance_ = nullptr; - } - } - -private: - T *instance_; -}; - - - -class ThreadSpecInfo -{ -public: - ThreadSpecInfo() : list_(NULL), - alloc_(ObModIds::OB_TSI_FACTORY) - {} - ~ThreadSpecInfo() - { - TSINodeBase *iter = list_; - while (NULL != iter) { - TSINodeBase *tmp = iter; - iter = iter->next; - tmp->~TSINodeBase(); - } - list_ = NULL; - } -public: - template - T *get_instance() - { - T *instance = NULL; - TSINode *node = NULL; - void *instance_buffer = nullptr; - void *node_buffer = nullptr; - while (nullptr == instance) { - if (nullptr == instance_buffer) { - instance_buffer = alloc_.alloc(sizeof(T)); - } - if (nullptr != instance_buffer && nullptr == node_buffer) { - node_buffer = alloc_.alloc(sizeof(TSINode)); - } - if (nullptr == instance_buffer || nullptr == node_buffer) { - if (REACH_TIME_INTERVAL(10 * 1000L * 1000L)) { - LIB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "new instance fail", "type", typeid(T).name()); - } - ::usleep(100L * 1000L); - } else { - instance = reinterpret_cast(new (instance_buffer) T()); - node = new(node_buffer) TSINode(instance); - _LIB_LOG(INFO, "new instance succ [%s] %p size=%ld, tsi=%p", - typeid(T).name(), instance, sizeof(T), this); - if (NULL == list_) { - list_ = node; - list_->next = NULL; - } else { - node->next = list_; - list_ = node; - } - } - } - return instance; - }; -private: - TSINodeBase *list_; - common::ObArenaAllocator alloc_; -}; - -class TSIFactory; -extern TSIFactory &get_tsi_fatcory(); - -class TSIFactory -{ - static const pthread_key_t INVALID_THREAD_KEY = INT32_MAX; -public: - TSIFactory() : key_(INVALID_THREAD_KEY) - { - if (0 != pthread_key_create(&key_, destroy_thread_data_)) { - _LIB_LOG_RET(WARN, OB_ERROR, "pthread_key_create fail errno=%u", errno); - } - } - ~TSIFactory() - { - if (INVALID_THREAD_KEY != key_) { - void *ptr = pthread_getspecific(key_); - destroy_thread_data_(ptr); - if (0 != pthread_key_delete(key_)) { - _LIB_LOG_RET(WARN, OB_ERROR, "pthread_key_delete fail errno=%u", errno); - } else { - key_ = INVALID_THREAD_KEY; - } - } - } -public: - template - T *new_instance() - { - T *instance = NULL; - if (INVALID_THREAD_KEY != key_) { - ThreadSpecInfo *tsi = (ThreadSpecInfo *)pthread_getspecific(key_); - if (NULL == tsi) { - tsi = new (std::nothrow) ThreadSpecInfo(); - // As some log call to_cstring and to_cstring->GET_TSI_MULT->get_instance->new_instance, - // so this place do not print log. - //if (NULL != tsi) { - //_LIB_LOG(INFO, "new tsi succ %p key=%d", tsi, key_); - //} - if (NULL != tsi - && 0 != pthread_setspecific(key_, tsi)) { - _LIB_LOG_RET(WARN, OB_ERROR, "pthread_setspecific fail errno=%u key=%d", errno, key_); - delete tsi; - tsi = NULL; - } - } - if (NULL != tsi) { - instance = tsi->get_instance(); - } - } - return instance; - } - template - OB_INLINE static T *get_instance() - { - // Note: Accelerating TSI object access. - #ifdef TSI_STATIC_SUM - static char TSI_PLACEHOLDER[sizeof(T)] __attribute__((section("tsi_placeholder"), used)); - #endif - RLOCAL_INLINE(T *, instance); - if (OB_UNLIKELY(NULL == instance)) { - instance = get_tsi_fatcory().new_instance(); - } - return instance; - } -private: - static void destroy_thread_data_(void *ptr) - { - if (NULL != ptr) { - ThreadSpecInfo *tsi = (ThreadSpecInfo *)ptr; - delete tsi; - } - } -private: - pthread_key_t key_; -}; - +#define GET_TSI0(type) (::oceanbase::common::ObDITls::get_instance()) +#define GET_TSI_MULT0(type, tag) (::oceanbase::common::ObDITls::get_instance()) +#define GET_TSI(type) (::oceanbase::common::ObDITls::get_instance()) +#define GET_TSI_MULT(type, tag) (::oceanbase::common::ObDITls::get_instance()) } // namespace common } // namespace oceanbase diff --git a/deps/oblib/src/lib/utility/ob_macro_utils.h b/deps/oblib/src/lib/utility/ob_macro_utils.h index 1b3d8a513..7fa8600be 100644 --- a/deps/oblib/src/lib/utility/ob_macro_utils.h +++ b/deps/oblib/src/lib/utility/ob_macro_utils.h @@ -25,21 +25,8 @@ _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, \ _100, ...) _100 -#define _SELECT100_(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ - _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ - _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ - _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \ - _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, \ - _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, \ - _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, \ - _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, \ - _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, \ - _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, \ - _100, ...) _100 - // These two macros do same work that select the 100th argument from // argument list. -#define _SELECT100(...) _SELECT100_(__VA_ARGS__) #define SELECT100(...) SELECT100_(__VA_ARGS__) // Expand to the number of arguments @@ -76,129 +63,117 @@ #define _CONCAT_(x, y) x ## y #define _CONCAT(x, y) _CONCAT_(x, y) -// make that many duplicates of X, X should be surrounded by parentheses. +#define APPLY_VARGS(f, x) f(x) +#define APPLY0(f, ...) __VA_ARGS__ +#define APPLY1(f, ...) APPLY_VARGS(f, APPLY0(f, ##__VA_ARGS__)) +#define APPLY2(f, ...) APPLY_VARGS(f, APPLY1(f, ##__VA_ARGS__)) +#define APPLY3(f, ...) APPLY_VARGS(f, APPLY2(f, ##__VA_ARGS__)) +#define APPLY4(f, ...) APPLY_VARGS(f, APPLY3(f, ##__VA_ARGS__)) +#define APPLY5(f, ...) APPLY_VARGS(f, APPLY4(f, ##__VA_ARGS__)) +#define APPLY6(f, ...) APPLY_VARGS(f, APPLY5(f, ##__VA_ARGS__)) +#define APPLY7(f, ...) APPLY_VARGS(f, APPLY6(f, ##__VA_ARGS__)) +#define APPLY8(f, ...) APPLY_VARGS(f, APPLY7(f, ##__VA_ARGS__)) +#define APPLY9(f, ...) APPLY_VARGS(f, APPLY8(f, ##__VA_ARGS__)) +#define APPLY10(f, ...) APPLY_VARGS(f, APPLY9(f, ##__VA_ARGS__)) +#define APPLY11(f, ...) APPLY_VARGS(f, APPLY10(f, ##__VA_ARGS__)) +#define APPLY12(f, ...) APPLY_VARGS(f, APPLY11(f, ##__VA_ARGS__)) +#define APPLY13(f, ...) APPLY_VARGS(f, APPLY12(f, ##__VA_ARGS__)) +#define APPLY14(f, ...) APPLY_VARGS(f, APPLY13(f, ##__VA_ARGS__)) +#define APPLY15(f, ...) APPLY_VARGS(f, APPLY14(f, ##__VA_ARGS__)) +#define APPLY16(f, ...) APPLY_VARGS(f, APPLY15(f, ##__VA_ARGS__)) +#define APPLY17(f, ...) APPLY_VARGS(f, APPLY16(f, ##__VA_ARGS__)) +#define APPLY18(f, ...) APPLY_VARGS(f, APPLY17(f, ##__VA_ARGS__)) +#define APPLY19(f, ...) APPLY_VARGS(f, APPLY18(f, ##__VA_ARGS__)) +#define APPLY20(f, ...) APPLY_VARGS(f, APPLY19(f, ##__VA_ARGS__)) +#define APPLY21(f, ...) APPLY_VARGS(f, APPLY20(f, ##__VA_ARGS__)) +#define APPLY22(f, ...) APPLY_VARGS(f, APPLY21(f, ##__VA_ARGS__)) +#define APPLY23(f, ...) APPLY_VARGS(f, APPLY22(f, ##__VA_ARGS__)) +#define APPLY24(f, ...) APPLY_VARGS(f, APPLY23(f, ##__VA_ARGS__)) +#define APPLY25(f, ...) APPLY_VARGS(f, APPLY24(f, ##__VA_ARGS__)) +#define APPLY26(f, ...) APPLY_VARGS(f, APPLY25(f, ##__VA_ARGS__)) +#define APPLY27(f, ...) APPLY_VARGS(f, APPLY26(f, ##__VA_ARGS__)) +#define APPLY28(f, ...) APPLY_VARGS(f, APPLY27(f, ##__VA_ARGS__)) +#define APPLY29(f, ...) APPLY_VARGS(f, APPLY28(f, ##__VA_ARGS__)) +#define APPLY30(f, ...) APPLY_VARGS(f, APPLY29(f, ##__VA_ARGS__)) +#define APPLY31(f, ...) APPLY_VARGS(f, APPLY30(f, ##__VA_ARGS__)) +#define APPLY32(f, ...) APPLY_VARGS(f, APPLY31(f, ##__VA_ARGS__)) +#define APPLY33(f, ...) APPLY_VARGS(f, APPLY32(f, ##__VA_ARGS__)) +#define APPLY34(f, ...) APPLY_VARGS(f, APPLY33(f, ##__VA_ARGS__)) +#define APPLY35(f, ...) APPLY_VARGS(f, APPLY34(f, ##__VA_ARGS__)) +#define APPLY36(f, ...) APPLY_VARGS(f, APPLY35(f, ##__VA_ARGS__)) +#define APPLY37(f, ...) APPLY_VARGS(f, APPLY36(f, ##__VA_ARGS__)) +#define APPLY38(f, ...) APPLY_VARGS(f, APPLY37(f, ##__VA_ARGS__)) +#define APPLY39(f, ...) APPLY_VARGS(f, APPLY38(f, ##__VA_ARGS__)) +#define APPLY40(f, ...) APPLY_VARGS(f, APPLY39(f, ##__VA_ARGS__)) +#define APPLY41(f, ...) APPLY_VARGS(f, APPLY40(f, ##__VA_ARGS__)) +#define APPLY42(f, ...) APPLY_VARGS(f, APPLY41(f, ##__VA_ARGS__)) +#define APPLY43(f, ...) APPLY_VARGS(f, APPLY42(f, ##__VA_ARGS__)) +#define APPLY44(f, ...) APPLY_VARGS(f, APPLY43(f, ##__VA_ARGS__)) +#define APPLY45(f, ...) APPLY_VARGS(f, APPLY44(f, ##__VA_ARGS__)) +#define APPLY46(f, ...) APPLY_VARGS(f, APPLY45(f, ##__VA_ARGS__)) +#define APPLY47(f, ...) APPLY_VARGS(f, APPLY46(f, ##__VA_ARGS__)) +#define APPLY48(f, ...) APPLY_VARGS(f, APPLY47(f, ##__VA_ARGS__)) +#define APPLY49(f, ...) APPLY_VARGS(f, APPLY48(f, ##__VA_ARGS__)) +#define APPLY50(f, ...) APPLY_VARGS(f, APPLY49(f, ##__VA_ARGS__)) +#define APPLY51(f, ...) APPLY_VARGS(f, APPLY50(f, ##__VA_ARGS__)) +#define APPLY52(f, ...) APPLY_VARGS(f, APPLY51(f, ##__VA_ARGS__)) +#define APPLY53(f, ...) APPLY_VARGS(f, APPLY52(f, ##__VA_ARGS__)) +#define APPLY54(f, ...) APPLY_VARGS(f, APPLY53(f, ##__VA_ARGS__)) +#define APPLY55(f, ...) APPLY_VARGS(f, APPLY54(f, ##__VA_ARGS__)) +#define APPLY56(f, ...) APPLY_VARGS(f, APPLY55(f, ##__VA_ARGS__)) +#define APPLY57(f, ...) APPLY_VARGS(f, APPLY56(f, ##__VA_ARGS__)) +#define APPLY58(f, ...) APPLY_VARGS(f, APPLY57(f, ##__VA_ARGS__)) +#define APPLY59(f, ...) APPLY_VARGS(f, APPLY58(f, ##__VA_ARGS__)) +#define APPLY60(f, ...) APPLY_VARGS(f, APPLY59(f, ##__VA_ARGS__)) +#define APPLY61(f, ...) APPLY_VARGS(f, APPLY60(f, ##__VA_ARGS__)) +#define APPLY62(f, ...) APPLY_VARGS(f, APPLY61(f, ##__VA_ARGS__)) +#define APPLY63(f, ...) APPLY_VARGS(f, APPLY62(f, ##__VA_ARGS__)) +#define APPLY64(f, ...) APPLY_VARGS(f, APPLY63(f, ##__VA_ARGS__)) +#define APPLY65(f, ...) APPLY_VARGS(f, APPLY64(f, ##__VA_ARGS__)) +#define APPLY66(f, ...) APPLY_VARGS(f, APPLY65(f, ##__VA_ARGS__)) +#define APPLY67(f, ...) APPLY_VARGS(f, APPLY66(f, ##__VA_ARGS__)) +#define APPLY68(f, ...) APPLY_VARGS(f, APPLY67(f, ##__VA_ARGS__)) +#define APPLY69(f, ...) APPLY_VARGS(f, APPLY68(f, ##__VA_ARGS__)) +#define APPLY70(f, ...) APPLY_VARGS(f, APPLY69(f, ##__VA_ARGS__)) +#define APPLY71(f, ...) APPLY_VARGS(f, APPLY70(f, ##__VA_ARGS__)) +#define APPLY72(f, ...) APPLY_VARGS(f, APPLY71(f, ##__VA_ARGS__)) +#define APPLY73(f, ...) APPLY_VARGS(f, APPLY72(f, ##__VA_ARGS__)) +#define APPLY74(f, ...) APPLY_VARGS(f, APPLY73(f, ##__VA_ARGS__)) +#define APPLY75(f, ...) APPLY_VARGS(f, APPLY74(f, ##__VA_ARGS__)) +#define APPLY76(f, ...) APPLY_VARGS(f, APPLY75(f, ##__VA_ARGS__)) +#define APPLY77(f, ...) APPLY_VARGS(f, APPLY76(f, ##__VA_ARGS__)) +#define APPLY78(f, ...) APPLY_VARGS(f, APPLY77(f, ##__VA_ARGS__)) +#define APPLY79(f, ...) APPLY_VARGS(f, APPLY78(f, ##__VA_ARGS__)) +#define APPLY80(f, ...) APPLY_VARGS(f, APPLY79(f, ##__VA_ARGS__)) +#define APPLY81(f, ...) APPLY_VARGS(f, APPLY80(f, ##__VA_ARGS__)) +#define APPLY82(f, ...) APPLY_VARGS(f, APPLY81(f, ##__VA_ARGS__)) +#define APPLY83(f, ...) APPLY_VARGS(f, APPLY82(f, ##__VA_ARGS__)) +#define APPLY84(f, ...) APPLY_VARGS(f, APPLY83(f, ##__VA_ARGS__)) +#define APPLY85(f, ...) APPLY_VARGS(f, APPLY84(f, ##__VA_ARGS__)) +#define APPLY86(f, ...) APPLY_VARGS(f, APPLY85(f, ##__VA_ARGS__)) +#define APPLY87(f, ...) APPLY_VARGS(f, APPLY86(f, ##__VA_ARGS__)) +#define APPLY88(f, ...) APPLY_VARGS(f, APPLY87(f, ##__VA_ARGS__)) +#define APPLY89(f, ...) APPLY_VARGS(f, APPLY88(f, ##__VA_ARGS__)) +#define APPLY90(f, ...) APPLY_VARGS(f, APPLY89(f, ##__VA_ARGS__)) +#define APPLY91(f, ...) APPLY_VARGS(f, APPLY90(f, ##__VA_ARGS__)) +#define APPLY92(f, ...) APPLY_VARGS(f, APPLY91(f, ##__VA_ARGS__)) +#define APPLY93(f, ...) APPLY_VARGS(f, APPLY92(f, ##__VA_ARGS__)) +#define APPLY94(f, ...) APPLY_VARGS(f, APPLY93(f, ##__VA_ARGS__)) +#define APPLY95(f, ...) APPLY_VARGS(f, APPLY94(f, ##__VA_ARGS__)) +#define APPLY96(f, ...) APPLY_VARGS(f, APPLY95(f, ##__VA_ARGS__)) +#define APPLY97(f, ...) APPLY_VARGS(f, APPLY96(f, ##__VA_ARGS__)) +#define APPLY98(f, ...) APPLY_VARGS(f, APPLY97(f, ##__VA_ARGS__)) +#define APPLY99(f, ...) APPLY_VARGS(f, APPLY98(f, ##__VA_ARGS__)) +#define APPLY100(f, ...) APPLY_VARGS(f, APPLY99(f, ##__VA_ARGS__)) +#define APPLY(n, f, ...) APPLY ## n (f, ##__VA_ARGS__) + +// select nth argument // -// DUP1((=)) => = -// DUP2((,)) => ,, -// DUP5((a++;)) => a++;a++;a++;a++;a++; -// -#define DUP1(X) SELF X -#define DUP2(X) SELF X DUP1(X) -#define DUP3(X) SELF X DUP2(X) -#define DUP4(X) SELF X DUP3(X) -#define DUP5(X) SELF X DUP4(X) -#define DUP6(X) SELF X DUP5(X) -#define DUP7(X) SELF X DUP6(X) -#define DUP8(X) SELF X DUP7(X) -#define DUP9(X) SELF X DUP8(X) -#define DUP10(X) SELF X DUP9(X) -#define DUP11(X) SELF X DUP10(X) -#define DUP12(X) SELF X DUP11(X) -#define DUP13(X) SELF X DUP12(X) -#define DUP14(X) SELF X DUP13(X) -#define DUP15(X) SELF X DUP14(X) -#define DUP16(X) SELF X DUP15(X) -#define DUP17(X) SELF X DUP16(X) -#define DUP18(X) SELF X DUP17(X) -#define DUP19(X) SELF X DUP18(X) -#define DUP20(X) SELF X DUP19(X) -#define DUP21(X) SELF X DUP20(X) -#define DUP22(X) SELF X DUP21(X) -#define DUP23(X) SELF X DUP22(X) -#define DUP24(X) SELF X DUP23(X) -#define DUP25(X) SELF X DUP24(X) -#define DUP26(X) SELF X DUP25(X) -#define DUP27(X) SELF X DUP26(X) -#define DUP28(X) SELF X DUP27(X) -#define DUP29(X) SELF X DUP28(X) -#define DUP30(X) SELF X DUP29(X) -#define DUP31(X) SELF X DUP30(X) -#define DUP32(X) SELF X DUP31(X) -#define DUP33(X) SELF X DUP32(X) -#define DUP34(X) SELF X DUP33(X) -#define DUP35(X) SELF X DUP34(X) -#define DUP36(X) SELF X DUP35(X) -#define DUP37(X) SELF X DUP36(X) -#define DUP38(X) SELF X DUP37(X) -#define DUP39(X) SELF X DUP38(X) -#define DUP40(X) SELF X DUP39(X) -#define DUP41(X) SELF X DUP40(X) -#define DUP42(X) SELF X DUP41(X) -#define DUP43(X) SELF X DUP42(X) -#define DUP44(X) SELF X DUP43(X) -#define DUP45(X) SELF X DUP44(X) -#define DUP46(X) SELF X DUP45(X) -#define DUP47(X) SELF X DUP46(X) -#define DUP48(X) SELF X DUP47(X) -#define DUP49(X) SELF X DUP48(X) -#define DUP50(X) SELF X DUP49(X) -#define DUP51(X) SELF X DUP50(X) -#define DUP52(X) SELF X DUP51(X) -#define DUP53(X) SELF X DUP52(X) -#define DUP54(X) SELF X DUP53(X) -#define DUP55(X) SELF X DUP54(X) -#define DUP56(X) SELF X DUP55(X) -#define DUP57(X) SELF X DUP56(X) -#define DUP58(X) SELF X DUP57(X) -#define DUP59(X) SELF X DUP58(X) -#define DUP60(X) SELF X DUP59(X) -#define DUP61(X) SELF X DUP60(X) -#define DUP62(X) SELF X DUP61(X) -#define DUP63(X) SELF X DUP62(X) -#define DUP64(X) SELF X DUP63(X) -#define DUP65(X) SELF X DUP64(X) -#define DUP66(X) SELF X DUP65(X) -#define DUP67(X) SELF X DUP66(X) -#define DUP68(X) SELF X DUP67(X) -#define DUP69(X) SELF X DUP68(X) -#define DUP70(X) SELF X DUP69(X) -#define DUP71(X) SELF X DUP70(X) -#define DUP72(X) SELF X DUP71(X) -#define DUP73(X) SELF X DUP72(X) -#define DUP74(X) SELF X DUP73(X) -#define DUP75(X) SELF X DUP74(X) -#define DUP76(X) SELF X DUP75(X) -#define DUP77(X) SELF X DUP76(X) -#define DUP78(X) SELF X DUP77(X) -#define DUP79(X) SELF X DUP78(X) -#define DUP80(X) SELF X DUP79(X) -#define DUP81(X) SELF X DUP80(X) -#define DUP82(X) SELF X DUP81(X) -#define DUP83(X) SELF X DUP82(X) -#define DUP84(X) SELF X DUP83(X) -#define DUP85(X) SELF X DUP84(X) -#define DUP86(X) SELF X DUP85(X) -#define DUP87(X) SELF X DUP86(X) -#define DUP88(X) SELF X DUP87(X) -#define DUP89(X) SELF X DUP88(X) -#define DUP90(X) SELF X DUP89(X) -#define DUP91(X) SELF X DUP90(X) -#define DUP92(X) SELF X DUP91(X) -#define DUP93(X) SELF X DUP92(X) -#define DUP94(X) SELF X DUP93(X) -#define DUP95(X) SELF X DUP94(X) -#define DUP96(X) SELF X DUP95(X) -#define DUP97(X) SELF X DUP96(X) -#define DUP98(X) SELF X DUP97(X) -#define DUP99(X) SELF X DUP98(X) - -#define DUP_(n, X) DUP ## n (X) -#define DUP(n, X) DUP_(n, X) - - -// expand to the number of 100 minus n -#define COMP100(n) \ - _SELECT100(DUP(n, (,)), \ - 1, 2, 3, 4, 5, 6, 7, 8, 9, \ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \ - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \ - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \ - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, \ - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, \ - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, \ - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \ - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, \ - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99) +// SELECT(2, arg1, arg2, arg3) => arg2 +#define EXPAND(...) __VA_ARGS__ +#define FIRST(x,...) x +#define REMOVE_FIRST(x,...) __VA_ARGS__ +#define SELECT(n, ...) APPLY_VARGS(FIRST, APPLY(n, REMOVE_FIRST, ,##__VA_ARGS__)) #define LST_DO_0(...) #define LST_DO_1(M, s, P, ...) P(M, 1, ##__VA_ARGS__) @@ -307,11 +282,6 @@ #define LST_DO(M, s, ...) LST_DO_(ARGS_NUM(__VA_ARGS__), M, s, PROC_ONE, ##__VA_ARGS__) #define LST_DO2(M, s, ...) LST_DO_(ARGS_NUM(__VA_ARGS__), M, s, PROC_ONE2, ##__VA_ARGS__) -// select nth argument -// -// SELECT(2, arg1, arg2, arg3) => arg2 -#define SELECT(n, ...) SELECT100(DUP(COMP100(n), (,)), __VA_ARGS__) - #define PROC_ONE(M, ...) M(SELECT(__VA_ARGS__)) #define PROC_ONE2(M, IDX, ...) M(SELECT(IDX, __VA_ARGS__), IDX) @@ -351,20 +321,10 @@ // IF_PARENT(XXX, MACRO_PAREN, MACRO_NO_PAREN) ==> MACRO_NO_PAREN(XXX) // IF_PARENT((XXX), MACRO_PAREN, MACRO_NO_PAREN) ==> MACRO_PAREN(XXX) // -#define OBMPAR IGNORE( -#define PAR(x) _SELF( -#define OBM_SELF(x) x - -#define PAREN(x, M) CONCAT(OBM, PAR x) M x) - -#define OBMNPNPAR SELF(IGNORE( -#define OBMNP_SELF(x) SELF -#define NPAR(x) _IGNORE( -#define OBMNP_IGNORE(...) IGNORE( - -#define NO_PAREN(x, M) CONCAT(OBMNP, NPAR x)) M (x)) - -#define IF_PAREN(x, MP, MNP) PAREN(x, MP) NO_PAREN(x, MNP) +#define COMMA_(...) , +#define APPLY_(f, ...) f(__VA_ARGS__) +#define IF_IS_PAREN(x, yes_branch, no_branch) APPLY_(SELECT3, COMMA_ x, yes_branch, no_branch) +#define IF_PAREN(x, yes_branch, no_branch) EXPAND(IF_IS_PAREN(x, yes_branch, no_branch) IF_IS_PAREN(x, x, (x))) #ifndef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -381,17 +341,6 @@ #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) #define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ -#define EMPTY() -#define INNER_DEFER(id) id EMPTY() -#define OBSTRUCT(...) __VA_ARGS__ INNER_DEFER(EMPTY)() -#define EXPAND(...) __VA_ARGS__ - -#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) -#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) -#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__))) -#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__))) -#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__))) -#define EVAL5(...) __VA_ARGS__ //////////////////////////////////////////////////////////////// /** diff --git a/deps/oblib/src/lib/utility/ob_unify_serialize.h b/deps/oblib/src/lib/utility/ob_unify_serialize.h index a685ac206..8f17fd7ec 100644 --- a/deps/oblib/src/lib/utility/ob_unify_serialize.h +++ b/deps/oblib/src/lib/utility/ob_unify_serialize.h @@ -15,59 +15,11 @@ #include "lib/utility/serialization.h" -#define UNIS_DEF_HAS_MEMBER(m) \ - template \ - struct __unis_has_member : std::false_type{}; \ - \ - template \ - struct __unis_has_member< \ - _T, \ - decltype((void)_T::m, void()) \ - > : std::true_type {}; - -#define UNIS_HAS_COMPAT(CLS) __unis_has_member{} - namespace oceanbase { namespace lib { -inline uint64_t &get_unis_global_compat_version() -{ - static uint64_t global_version; - return global_version; -} - -inline uint64_t &get_unis_compat_version() -{ - RLOCAL_INLINE(uint64_t, compat_version); - return compat_version; -} - -class UnisCompatVersionGuard { -public: - UnisCompatVersionGuard(uint64_t version) - : version_(get_unis_compat_version()) - { - get_unis_compat_version() = version; - } - ~UnisCompatVersionGuard() - { - get_unis_compat_version() = version_; - } -private: - uint64_t version_; -}; -} -} - -#define UNIS_VERSION_GUARD(v) ::oceanbase::lib::UnisCompatVersionGuard __unis_guard(v) #define SERIAL_PARAMS char *buf, const int64_t buf_len, int64_t &pos #define DESERIAL_PARAMS const char *buf, const int64_t data_len, int64_t &pos -#define SERIALIZE_SIGNATURE(func) int func(SERIAL_PARAMS) const -#define DESERIALIZE_SIGNATURE(func) int func(DESERIAL_PARAMS) -#define GET_SERIALIZE_SIZE_SIGNATURE(func) int64_t func(void) const -#define SERIALIZE_DISPATCH_NAME serialize_dispatch_ -#define DESERIALIZE_DISPATCH_NAME deserialize_dispatch_ -#define GET_SERIALIZE_SIZE_DISPATCH_NAME get_serialize_size_dispatch_ #define UNF_UNUSED_SER ({(void)buf; (void)buf_len; (void)pos;}) #define UNF_UNUSED_DES ({(void)buf; (void)data_len; (void)pos;}) @@ -76,12 +28,20 @@ private: #define RPC_WARN(...) OB_LOG(WARN, __VA_ARGS__) #endif +#define OB_DEF_SERIALIZE_SIMPLE(CLS) \ + int CLS::serialize(SERIAL_PARAMS) const + +#define OB_DEF_DESERIALIZE_SIMPLE(CLS) \ + int CLS::deserialize(DESERIAL_PARAMS) + +#define OB_DEF_SERIALIZE_SIZE_SIMPLE(CLS) \ + int64_t CLS::get_serialize_size(void) const + /// // define essential macros used for encode/decode single object //---------------------------------------------------------------------- #define NS_ ::oceanbase::common::serialization #define OK_ ::oceanbase::common::OB_SUCCESS -#define LIB_NS_ ::oceanbase::lib #define OB_UNIS_ENCODE(obj) \ if (OB_SUCC(ret)) { \ @@ -111,57 +71,55 @@ private: len += NS_::encoded_length(obj) //----------------------------------------------------------------------- -/// utility macros to deal with C native array -#define OB_UNIS_ENCODE_ARRAY(objs, objs_count) \ - OB_UNIS_ENCODE((objs_count)); \ - for (int64_t i = 0; OB_SUCC(ret) && i < (objs_count); ++i) { \ - OB_UNIS_ENCODE(objs[i]); \ +// serialize_ no header +#define OB_SERIALIZE_NOHEADER(CLS, PARENT, SUFFIX, PRED, ...) \ + int CLS::serialize##SUFFIX(SERIAL_PARAMS) const { \ + int ret = PARENT::serialize(buf, buf_len, pos); \ + if (OB_SUCC(ret) && (PRED)) { \ + LST_DO_CODE(OB_UNIS_ENCODE, ##__VA_ARGS__); \ + } \ + return ret; \ } -#define OB_UNIS_ADD_LEN_ARRAY(objs, objs_count) \ - OB_UNIS_ADD_LEN((objs_count)); \ - for (int64_t i = 0; i < (objs_count); ++i) { \ - OB_UNIS_ADD_LEN(objs[i]); \ +#define OB_DESERIALIZE_NOHEADER(CLS, PARENT, SUFFIX, ...) \ + int CLS::deserialize##SUFFIX(DESERIAL_PARAMS) { \ + int ret = PARENT::deserialize(buf, data_len, pos); \ + if (OB_SUCC(ret)) { \ + LST_DO_CODE(OB_UNIS_DECODE, ##__VA_ARGS__); \ + } \ + return ret; \ +} + +#define OB_SERIALIZE_SIZE_NOHEADER(CLS, PARENT, SUFFIX, PRED, ...) \ + int64_t CLS::get_serialize_size##SUFFIX(void) const { \ + int64_t len = PARENT::get_serialize_size(); \ + if (PRED) { \ + LST_DO_CODE(OB_UNIS_ADD_LEN, ##__VA_ARGS__); \ + } \ + return len; \ } -#define OB_UNIS_DECODE_ARRAY(objs, objs_count) \ - for (int64_t i = 0; OB_SUCC(ret) && i < (objs_count); ++i) { \ - OB_UNIS_DECODE(objs[i]); \ +#define OB_SERIALIZE_MEMBER_INHERIT(CLS, PARENT, ...) \ + OB_SERIALIZE_NOHEADER(CLS, PARENT, , true, ##__VA_ARGS__); \ + OB_DESERIALIZE_NOHEADER(CLS, PARENT, ,##__VA_ARGS__); \ + OB_SERIALIZE_SIZE_NOHEADER(CLS, PARENT, , true, ##__VA_ARGS__); + +struct EmptyUnisStruct +{ + static int serialize(SERIAL_PARAMS) { + UNF_UNUSED_SER; + return 0; } - -/// -// define macros deal with parent class -//----------------------------------------------------------------------- -#define UNF_CONCAT_(a, b) a##b -#define UNF_CONCAT(a, b) UNF_CONCAT_(a, b) -#define UNF_IGNORE(...) -#define UNF_uSELF(...) __VA_ARGS__ -#define UNF_SAFE_DO(M) \ - do { \ - if (OB_SUCC(ret)) { \ - if (OB_FAIL((M))) { \ - RPC_WARN("fail to execute: " #M, K(ret)); \ - } \ - } \ - } while (0) - -#define UNF_MYCLS_ UNF_uSELF( -#define MYCLS_(D, B) uSELF( D -#define UNF_MYCLS(x) UNF_CONCAT(UNF_, MYCLS_ x) ) - -#define UNF_SBASE_ UNF_IGNORE( -#define SBASE_(D, B) \ - uSELF( UNF_SAFE_DO(B::serialize(buf, buf_len, pos)) -#define BASE_SER(x) UNF_CONCAT(UNF_, SBASE_ x) ) - -#define UNF_DBASE_ UNF_IGNORE( -#define DBASE_(D, B) \ - uSELF( UNF_SAFE_DO(B::deserialize(buf, data_len, pos)) -#define BASE_DESER(x) UNF_CONCAT(UNF_, DBASE_ x) ) - -#define UNF_LBASE_ UNF_IGNORE( -#define LBASE_(D, B) uSELF( len += B::get_serialize_size() -#define BASE_ADD_LEN(x) UNF_CONCAT(UNF_, LBASE_ x) ) + static int deserialize(DESERIAL_PARAMS) { + UNF_UNUSED_DES; + return 0; + } + static int64_t get_serialize_size() { + return 0; + } +}; +#define EmptyParent ::oceanbase::lib::EmptyUnisStruct +#define OB_SERIALIZE_MEMBER_SIMPLE(CLS, ...) OB_SERIALIZE_MEMBER_INHERIT(CLS, EmptyParent, ##__VA_ARGS__) /// // define serialize/desrialize wrapper which helps hide "version" and @@ -181,104 +139,27 @@ private: } \ } -#define CALL_SERIALIZE_(SUFFIX, ...) \ - if (OB_SUCC(ret)) { \ - if (OB_FAIL(serialize_##SUFFIX(buf, buf_len, pos, ##__VA_ARGS__))) { \ - RPC_WARN("serialize fail", K(ret)); \ - } \ - } - -#define CALL_DESERIALIZE_(SLEN, SUFFIX, ...) \ - if (OB_SUCC(ret)) { \ - int64_t pos_orig = pos; \ - pos = 0; \ - if (OB_FAIL(deserialize_##SUFFIX( \ - buf + pos_orig, SLEN, pos, ##__VA_ARGS__))) { \ - RPC_WARN("deserialize_ fail", \ - "slen", SLEN, K(pos), K(ret)); \ - } \ - pos = pos_orig + SLEN; \ - } \ - -#define CALL_GET_SERIALIZE_SIZE_(SUFFIX, ...) \ - get_serialize_size_##SUFFIX(__VA_ARGS__) - -#define SERIALIZE_HEADER(version) \ - if (OB_SUCC(ret)) { \ - OB_UNIS_ENCODE(version); \ - } - -// dispatch compatible function depend on current -// get_unis_compat_version(). -#define OB_UNIS_DEFINE_DISPATCH() \ - int SERIALIZE_DISPATCH_NAME(SERIAL_PARAMS, std::false_type) const \ - { \ - int ret = OK_; \ - CALL_SERIALIZE_(); \ - return ret; \ - } \ - int DESERIALIZE_DISPATCH_NAME(DESERIAL_PARAMS, std::false_type) \ - { \ - int ret = OK_; \ - CALL_DESERIALIZE_(data_len,); \ - return ret; \ - } \ - int64_t GET_SERIALIZE_SIZE_DISPATCH_NAME(std::false_type) const \ - { \ - return CALL_GET_SERIALIZE_SIZE_(); \ - } - -#define OB_UNIS_DEFINE_COMPAT_DISPATCH() \ - int SERIALIZE_DISPATCH_NAME(SERIAL_PARAMS, std::true_type) const \ - { \ - int ret = OK_; \ - if (OB_LIKELY(LIB_NS_::get_unis_compat_version() == 0 || \ - LIB_NS_::get_unis_compat_version() > compat_ver_)) { \ - CALL_SERIALIZE_(); \ - } else { \ - CALL_SERIALIZE_(compat_); \ - } \ - return ret; \ - } \ - int DESERIALIZE_DISPATCH_NAME(DESERIAL_PARAMS, std::true_type) \ - { \ - int ret = OK_; \ - if (OB_LIKELY(LIB_NS_::get_unis_compat_version() == 0 || \ - LIB_NS_::get_unis_compat_version() > compat_ver_)) { \ - CALL_DESERIALIZE_(data_len,); \ - } else { \ - CALL_DESERIALIZE_(data_len, compat_); \ - } \ - return ret; \ - } \ - int64_t GET_SERIALIZE_SIZE_DISPATCH_NAME(std::true_type) const \ - { \ - if (OB_LIKELY(LIB_NS_::get_unis_compat_version() == 0 || \ - LIB_NS_::get_unis_compat_version() > compat_ver_)) { \ - return CALL_GET_SERIALIZE_SIZE_(); \ - } else { \ - return CALL_GET_SERIALIZE_SIZE_(compat_); \ - } \ - } - #ifdef NDEBUG #define CHECK_SERIALIZE_SIZE(CLS, real_size) #else #define CHECK_SERIALIZE_SIZE(CLS, real_size) \ - int64_t expect_size = \ - CALL_GET_SERIALIZE_SIZE_(dispatch_, UNIS_HAS_COMPAT(CLS)); \ + int64_t expect_size = get_serialize_size(); \ assert(expect_size >= real_size); #endif -#define OB_UNIS_SERIALIZE(CLS) \ +#define OB_UNIS_SERIALIZE(CLS) \ int CLS::serialize(SERIAL_PARAMS) const \ { \ int ret = OK_; \ - SERIALIZE_HEADER(UNIS_VERSION); \ + OB_UNIS_ENCODE(UNIS_VERSION); \ if (OB_SUCC(ret)) { \ int64_t size_nbytes = NS_::OB_SERIALIZE_SIZE_NEED_BYTES; \ int64_t pos_bak = (pos += size_nbytes); \ - CALL_SERIALIZE_(dispatch_, UNIS_HAS_COMPAT(CLS)); \ + if (OB_SUCC(ret)) { \ + if (OB_FAIL(serialize_(buf, buf_len, pos))) { \ + RPC_WARN("serialize fail", K(ret)); \ + } \ + } \ int64_t serial_size = pos - pos_bak; \ int64_t tmp_pos = 0; \ CHECK_SERIALIZE_SIZE(CLS, serial_size); \ @@ -290,34 +171,32 @@ private: return ret; \ } -#define DESERIALIZE_HEADER(CLS, version, len) \ - if (OB_SUCC(ret)) { \ - OB_UNIS_DECODEx(version); \ - OB_UNIS_DECODEx(len); \ - CHECK_VERSION_LENGTH(CLS, version, len); \ - } - #define OB_UNIS_DESERIALIZE(CLS) \ - int CLS::deserialize(DESERIAL_PARAMS) \ - { \ + int CLS::deserialize(DESERIAL_PARAMS) { \ int ret = OK_; \ int64_t version = 0; \ int64_t len = 0; \ - DESERIALIZE_HEADER(CLS, version, len); \ - CALL_DESERIALIZE_(len, dispatch_, UNIS_HAS_COMPAT(CLS)); \ + if (OB_SUCC(ret)) { \ + OB_UNIS_DECODEx(version); \ + OB_UNIS_DECODEx(len); \ + CHECK_VERSION_LENGTH(CLS, version, len); \ + } \ + if (OB_SUCC(ret)) { \ + int64_t pos_orig = pos; \ + pos = 0; \ + if (OB_FAIL(deserialize_(buf + pos_orig, len, pos))) { \ + RPC_WARN("deserialize_ fail", "slen", len, K(pos), K(ret)); \ + } \ + pos = pos_orig + len; \ + } \ return ret; \ } -#define SERIALIZE_SIZE_HEADER(version) \ - OB_UNIS_ADD_LEN(version); \ - len += NS_::OB_SERIALIZE_SIZE_NEED_BYTES; - #define OB_UNIS_SERIALIZE_SIZE(CLS) \ - int64_t CLS::get_serialize_size(void) const \ - { \ - int64_t len = CALL_GET_SERIALIZE_SIZE_( \ - dispatch_, UNIS_HAS_COMPAT(CLS)); \ - SERIALIZE_SIZE_HEADER(UNIS_VERSION); \ + int64_t CLS::get_serialize_size(void) const { \ + int64_t len = get_serialize_size_(); \ + OB_UNIS_ADD_LEN(UNIS_VERSION); \ + len += NS_::OB_SERIALIZE_SIZE_NEED_BYTES; \ return len; \ } @@ -335,16 +214,6 @@ private: int deserialize_(DESERIAL_PARAMS); \ VIR int64_t get_serialize_size() const PURE; \ int64_t get_serialize_size_() const; \ - UNIS_DEF_HAS_MEMBER(compat_ver_); \ - OB_UNIS_DEFINE_DISPATCH() - -#define OB_DECLARE_UNIS_COMPAT() \ - int serialize_compat_(SERIAL_PARAMS) const; \ - int deserialize_compat_(DESERIAL_PARAMS); \ - int64_t get_serialize_size_compat_() const; \ - OB_UNIS_DEFINE_COMPAT_DISPATCH() - -//----------------------------------------------------------------------- /// // public entries, define interfaces of manual serialization @@ -362,192 +231,91 @@ const static int64_t UNIS_VERSION = VER #define OB_UNIS_VERSION_PV() \ public: OB_DECLARE_UNIS(virtual,=0); private: -#define OB_DEF_SERIALIZE(CLS, TEMP...) \ - TEMP OB_UNIS_SERIALIZE(CLS); \ +#define OB_DEF_SERIALIZE(CLS, TEMP...) \ + TEMP OB_UNIS_SERIALIZE(CLS); \ TEMP int CLS::serialize_(SERIAL_PARAMS) const -#define OB_DEF_DESERIALIZE(CLS, TEMP...) \ - TEMP OB_UNIS_DESERIALIZE(CLS); \ +#define OB_DEF_DESERIALIZE(CLS, TEMP...) \ + TEMP OB_UNIS_DESERIALIZE(CLS); \ TEMP int CLS::deserialize_(DESERIAL_PARAMS) -#define OB_DEF_SERIALIZE_SIZE(CLS, TEMP...) \ - TEMP OB_UNIS_SERIALIZE_SIZE(CLS); \ +#define OB_DEF_SERIALIZE_SIZE(CLS, TEMP...) \ + TEMP OB_UNIS_SERIALIZE_SIZE(CLS); \ TEMP int64_t CLS::get_serialize_size_(void) const -/// {{{ helper functions -#define OB_DEF_SERIALIZE_COMPAT_(CLS, TEMP...) \ - TEMP int CLS::serialize_compat_(SERIAL_PARAMS) const -#define OB_DEF_DESERIALIZE_COMPAT_(CLS, TEMP...) \ - TEMP int CLS::deserialize_compat_(DESERIAL_PARAMS) -#define OB_DEF_SERIALIZE_SIZE_COMPAT_(CLS, TEMP...) \ - TEMP int64_t CLS::get_serialize_size_compat_(void) const -/// }}} +#define OB_SERIALIZE_MEMBER_TEMP_INHERIT(TEMP, CLS, PARENT, ...) \ + TEMP OB_UNIS_SERIALIZE(CLS); \ + TEMP OB_UNIS_DESERIALIZE(CLS); \ + TEMP OB_UNIS_SERIALIZE_SIZE(CLS); \ + TEMP OB_SERIALIZE_NOHEADER(CLS, PARENT, _, true, ##__VA_ARGS__); \ + TEMP OB_DESERIALIZE_NOHEADER(CLS, PARENT, _,##__VA_ARGS__); \ + TEMP OB_SERIALIZE_SIZE_NOHEADER(CLS, PARENT, _, true, ##__VA_ARGS__); -#define OB_DEF_SERIALIZE_COMPAT(VER, CLS, TEMP...) \ - OB_DEF_SERIALIZE_COMPAT_(CLS, ##TEMP) -#define OB_DEF_DESERIALIZE_COMPAT(VER, CLS, TEMP...) \ - OB_DEF_DESERIALIZE_COMPAT_(CLS, ##TEMP) -#define OB_DEF_SERIALIZE_SIZE_COMPAT(VER, CLS, TEMP...) \ - OB_DEF_SERIALIZE_SIZE_COMPAT_(CLS, ##TEMP) +#define CAR(a, b) a +#define CDR(a, b) b +#define MY_CLS(CLS) IF_IS_PAREN(CLS, CAR CLS, CLS) +#define BASE_CLS(CLS) IF_IS_PAREN(CLS, CDR CLS, EmptyParent) +#define OB_SERIALIZE_MEMBER_TEMP(TEMP, CLS, ...) OB_SERIALIZE_MEMBER_TEMP_INHERIT(TEMP, MY_CLS(CLS), BASE_CLS(CLS), ##__VA_ARGS__) +#define OB_SERIALIZE_MEMBER(CLS, ...) OB_SERIALIZE_MEMBER_TEMP(, CLS, ##__VA_ARGS__) - -//----------------------------------------------------------------------- - -/// -// public entries, define interfaces of list encode/decode members -//----------------------------------------------------------------------- -#define OB_SERIALIZE_MEMBER_COMPAT_TEMP_IF(COMPAT, TEMP, CLS, PRED, ...) \ - OB_DEF_SERIALIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ - { \ - int ret = OK_; \ - UNF_UNUSED_SER; \ - BASE_SER(CLS); \ - if (PRED) { \ - LST_DO_CODE(OB_UNIS_ENCODE, ##__VA_ARGS__); \ - } \ - return ret; \ - } \ - OB_DEF_DESERIALIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ - { \ - int ret = OK_; \ - UNF_UNUSED_DES; \ - BASE_DESER(CLS); \ - LST_DO_CODE(OB_UNIS_DECODE, ##__VA_ARGS__); \ - return ret; \ - } \ - OB_DEF_SERIALIZE_SIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ - { \ - int64_t len = 0; \ - BASE_ADD_LEN(CLS); \ - if (PRED) { \ - LST_DO_CODE(OB_UNIS_ADD_LEN, ##__VA_ARGS__); \ - } \ - return len; \ +/// utility macros to deal with C native array +#define OB_UNIS_ENCODE_ARRAY(objs, objs_count) \ + OB_UNIS_ENCODE((objs_count)); \ + for (int64_t i = 0; OB_SUCC(ret) && i < (objs_count); ++i) { \ + OB_UNIS_ENCODE(objs[i]); \ } -#define OB_SERIALIZE_MEMBER_TEMP_IF(TEMP, CLS, PRED, ...) \ - OB_SERIALIZE_MEMBER_COMPAT_TEMP_IF(, TEMP, CLS, PRED, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_TEMP_IF_COMPAT(VER, TEMP, CLS, PRED, ...) \ - OB_SERIALIZE_MEMBER_COMPAT_TEMP_IF(_COMPAT_, TEMP, CLS, PRED, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_TEMP(TEMP, CLS, ...) \ - OB_SERIALIZE_MEMBER_TEMP_IF(TEMP, CLS, true, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_TEMP_COMPAT(VER, TEMP, CLS, ...) \ - OB_SERIALIZE_MEMBER_TEMP_IF_COMPAT(VER, TEMP, CLS, true, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_IF(CLS, PRED, ...) \ - OB_SERIALIZE_MEMBER_TEMP_IF(, CLS, PRED, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_IF_COMPAT(VER, CLS, PRED, ...) \ - OB_SERIALIZE_MEMBER_TEMP_IF_COMPAT(VER, , CLS, PRED, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER(CLS, ...) \ - OB_SERIALIZE_MEMBER_TEMP(, CLS, ##__VA_ARGS__) - -#define OB_SERIALIZE_MEMBER_COMPAT(VER, CLS, ...) \ - OB_SERIALIZE_MEMBER_TEMP_COMPAT(VER, , CLS, ##__VA_ARGS__) - -#define OB_UNIS_DEF_SERIALIZE(CLS, ...) \ - OB_DEF_SERIALIZE(UNF_MYCLS(CLS),) \ - { \ - int ret = OK_; \ - UNF_UNUSED_SER; \ - BASE_SER(CLS); \ - LST_DO_CODE(OB_UNIS_ENCODE, ##__VA_ARGS__); \ - return ret; \ +#define OB_UNIS_ADD_LEN_ARRAY(objs, objs_count) \ + OB_UNIS_ADD_LEN((objs_count)); \ + for (int64_t i = 0; i < (objs_count); ++i) { \ + OB_UNIS_ADD_LEN(objs[i]); \ } -#define OB_UNIS_DEF_DESERIALIZE(CLS, ...) \ - OB_DEF_DESERIALIZE(UNF_MYCLS(CLS),) \ - { \ - int ret = OK_; \ - UNF_UNUSED_DES; \ - BASE_DESER(CLS); \ - LST_DO_CODE(OB_UNIS_DECODE, ##__VA_ARGS__); \ - return ret; \ +#define OB_UNIS_DECODE_ARRAY(objs, objs_count) \ + for (int64_t i = 0; OB_SUCC(ret) && i < (objs_count); ++i) { \ + OB_UNIS_DECODE(objs[i]); \ } -#define OB_UNIS_DEF_SERIALIZE_SIZE(CLS, ...) \ - OB_DEF_SERIALIZE_SIZE(UNF_MYCLS(CLS),) \ - { \ - int64_t len = 0; \ - BASE_ADD_LEN(CLS); \ - LST_DO_CODE(OB_UNIS_ADD_LEN, ##__VA_ARGS__); \ - return len; \ +#define OB_UNIS_DEF_SERIALIZE(CLS, ...) \ + OB_UNIS_SERIALIZE(MY_CLS(CLS)); \ + OB_SERIALIZE_NOHEADER(MY_CLS(CLS), BASE_CLS(CLS), _, true, ##__VA_ARGS__); + +#define OB_UNIS_DEF_SERIALIZE_SIZE(CLS, ...) \ + OB_UNIS_SERIALIZE_SIZE(MY_CLS(CLS)); \ + OB_SERIALIZE_SIZE_NOHEADER(MY_CLS(CLS), BASE_CLS(CLS), _, true, ##__VA_ARGS__); + +#define BASE_ADD_LEN(Base) len += BASE_CLS(Base)::get_serialize_size() +#define BASE_SER(Base) if (OB_SUCC(ret) && OB_FAIL(BASE_CLS(Base)::serialize(buf, buf_len, pos))) { \ + RPC_WARN("serialize base failed", K(ret)); \ } - -//----------------------------------------------------------------------- -// Compatibility not guaranteed, **DONT** use this any more. - -#define OB_DEF_SERIALIZE_SIMPLE(CLS) \ - int CLS::serialize(SERIAL_PARAMS) const - -#define OB_DEF_DESERIALIZE_SIMPLE(CLS) \ - int CLS::deserialize(DESERIAL_PARAMS) - -#define OB_DEF_SERIALIZE_SIZE_SIMPLE(CLS) \ - int64_t CLS::get_serialize_size(void) const - -#define OB_SERIALIZE_MEMBER_SIMPLE(CLS, ...) \ - OB_DEF_SERIALIZE_SIMPLE(CLS) \ - { \ - int ret = OK_; \ - LST_DO_CODE(OB_UNIS_ENCODE, ##__VA_ARGS__); \ - return ret; \ - } \ - OB_DEF_DESERIALIZE_SIMPLE(CLS) \ - { \ - int ret = OK_; \ - LST_DO_CODE(OB_UNIS_DECODE, ##__VA_ARGS__); \ - return ret; \ - } \ - OB_DEF_SERIALIZE_SIZE_SIMPLE(CLS) \ - { \ - int64_t len = 0; \ - LST_DO_CODE(OB_UNIS_ADD_LEN, ##__VA_ARGS__); \ - return len; \ +#define BASE_DESER(Base) if (OB_SUCC(ret) && OB_FAIL(BASE_CLS(Base)::deserialize(buf, data_len, pos))) { \ + RPC_WARN("deserialize base failed", K(ret)); \ } - -#define OB_SERIALIZE_MEMBER_INHERIT(CLS, PARENT, ...) \ - OB_DEF_SERIALIZE_SIMPLE(CLS) \ - { \ - int ret = PARENT::serialize(buf, buf_len, pos); \ - if (OB_SUCC(ret)) { \ - LST_DO_CODE(OB_UNIS_ENCODE, ##__VA_ARGS__); \ - } \ - return ret; \ - } \ - OB_DEF_DESERIALIZE_SIMPLE(CLS) \ - { \ - int ret = PARENT::deserialize(buf, data_len, pos); \ - if (OB_SUCC(ret)) { \ - LST_DO_CODE(OB_UNIS_DECODE, ##__VA_ARGS__); \ - } \ - return ret; \ - } \ - OB_DEF_SERIALIZE_SIZE_SIMPLE(CLS) \ - { \ - int64_t len = PARENT::get_serialize_size(); \ - LST_DO_CODE(OB_UNIS_ADD_LEN, ##__VA_ARGS__); \ - return len; \ - } - -#define UNIS_VER(major, minor, patch) \ - (((uint64_t)major << 32L) + ((uint64_t)minor << 16L) + (uint64_t)patch) -#define OB_UNIS_COMPAT(V) \ - private: \ - const static uint64_t compat_ver_ = UNIS_##V; \ - OB_DECLARE_UNIS_COMPAT() - +#define SERIALIZE_SIZE_HEADER(version) \ + OB_UNIS_ADD_LEN(version); \ + len += NS_::OB_SERIALIZE_SIZE_NEED_BYTES; // Define dummy node to replace obsolete member. -namespace oceanbase { namespace lib { template -struct UNFDummy { + struct UNFDummy { OB_UNIS_VERSION(N); }; OB_SERIALIZE_MEMBER_TEMP(template, UNFDummy); + +#define OB_SERIALIZE_MEMBER_IF(CLS, PRED, ...) \ + OB_UNIS_SERIALIZE(CLS); \ + OB_UNIS_DESERIALIZE(CLS); \ + OB_UNIS_SERIALIZE_SIZE(CLS); \ + OB_SERIALIZE_NOHEADER(CLS, EmptyParent, _, PRED, ##__VA_ARGS__); \ + OB_DESERIALIZE_NOHEADER(CLS, EmptyParent, _,##__VA_ARGS__); \ + OB_SERIALIZE_SIZE_NOHEADER(CLS, EmptyParent, _, PRED, ##__VA_ARGS__); + +inline uint64_t &get_unis_compat_version() +{ + static uint64_t x; + return x; +} + +#define UNIS_VERSION_GUARD(x) }} // namespace oceanbase::lib #endif /* _OCEABASE_LIB_UTILITY_OB_UNIFY_SERIALIZE_H_ */ diff --git a/deps/oblib/src/lib/utility/utility.h b/deps/oblib/src/lib/utility/utility.h index 9fef3d575..1c088485c 100644 --- a/deps/oblib/src/lib/utility/utility.h +++ b/deps/oblib/src/lib/utility/utility.h @@ -18,6 +18,7 @@ #include "easy_define.h" #include "io/easy_io_struct.h" #include "lib/allocator/ob_allocator.h" +#include "lib/lock/ob_spin_lock.h" #include "lib/stat/ob_diagnose_info.h" #include "lib/utility/ob_print_utils.h" #include "lib/utility/ob_utility.h" diff --git a/deps/oblib/src/lib/worker.cpp b/deps/oblib/src/lib/worker.cpp index 57effc7bf..0c2399671 100644 --- a/deps/oblib/src/lib/worker.cpp +++ b/deps/oblib/src/lib/worker.cpp @@ -44,23 +44,20 @@ __thread Worker *Worker::self_; Worker::Worker() : allocator_(nullptr), + st_current_priority_(0), + session_(nullptr), cur_request_(nullptr), + is_blocking_(false), worker_level_(INT32_MAX), curr_request_level_(0), group_id_(0), rpc_stat_srv_(nullptr), - st_current_priority_(0), - session_(nullptr), timeout_ts_(INT64_MAX), ntp_offset_(0), rpc_tenant_id_(0), - tidx_(-1), - large_token_expired_(0), disable_wait_(false) { worker_node_.get_data() = this; - lq_worker_node_.get_data() = this; - lq_waiting_worker_node_.get_data() = this; if (OB_ISNULL(self_)) { self_ = this; } else { diff --git a/deps/oblib/src/lib/worker.h b/deps/oblib/src/lib/worker.h index e148d8f41..0c94ee008 100644 --- a/deps/oblib/src/lib/worker.h +++ b/deps/oblib/src/lib/worker.h @@ -15,9 +15,7 @@ #include #include "lib/ob_define.h" -#include "lib/allocator/page_arena.h" #include "lib/rc/context.h" -#include "lib/allocator/ob_fifo_allocator.h" #include "lib/runtime.h" namespace oceanbase @@ -26,9 +24,7 @@ namespace rpc { class ObRequest; } namespace sql { class ObSQLSessionInfo; } namespace lib { -using common::ObArenaAllocator; using common::ObIAllocator; -using common::ObFIFOAllocator; class Worker { @@ -41,6 +37,16 @@ public: virtual Status check_wait(); virtual int check_status() { check_wait(); return common::OB_SUCCESS; } + virtual int check_large_query_quota() { return common::OB_SUCCESS; } + // check if retry disabled for the query + virtual bool can_retry() const { return false; } + // Set retry flag so that scheduler will reprocess this request then + virtual void set_need_retry() {} + // It's used to check whether query need retry. Whenever worker has + // observed this query need retry, it should stop processing this + // query immediately. + virtual bool need_retry() const { return false; } + virtual void resume() {} // This function is called before worker waiting for some resources // and starting to give cpu out so that Multi-Tenancy would be aware @@ -61,123 +67,78 @@ public: // 2. false the worker hasn't right to go ahead bool sched_run(int64_t waittime=0); - ObIAllocator &get_sql_arena_allocator() ; + OB_INLINE ObIAllocator& get_sql_arena_allocator() { return CURRENT_CONTEXT->get_arena_allocator(); } ObIAllocator &get_allocator() ; - void set_req_flag(const rpc::ObRequest *cur_request); - bool has_req_flag(); - const rpc::ObRequest *get_cur_request(); + void set_req_flag(const rpc::ObRequest *cur_request) { cur_request_ = cur_request; } + bool has_req_flag() { return OB_NOT_NULL(cur_request_); } + const rpc::ObRequest *get_cur_request() { return cur_request_; } - void set_worker_level(const int32_t level) { worker_level_ = level; } - int32_t get_worker_level() const { return worker_level_; } + OB_INLINE void set_is_blocking(bool v) { is_blocking_ = v; } + OB_INLINE bool is_blocking() { return is_blocking_; } - void set_curr_request_level(const int32_t level) { curr_request_level_ = level; } - int32_t get_curr_request_level() const { return curr_request_level_; } + OB_INLINE void set_worker_level(const int32_t level) { worker_level_ = level; } + OB_INLINE int32_t get_worker_level() const { return worker_level_; } - void set_group_id(int32_t group_id) { group_id_ = group_id; } - int32_t get_group_id() const { return group_id_; } + OB_INLINE void set_curr_request_level(const int32_t level) { curr_request_level_ = level; } + OB_INLINE int32_t get_curr_request_level() const { return curr_request_level_; } - void set_rpc_stat_srv(void *rpc_stat_srv) { rpc_stat_srv_ = rpc_stat_srv; } - void *get_rpc_stat_srv() const { return rpc_stat_srv_; } + OB_INLINE void set_group_id(int32_t group_id) { group_id_ = group_id; } + OB_INLINE int32_t get_group_id() const { return group_id_; } - virtual int check_large_query_quota() - { - return common::OB_SUCCESS; - } + OB_INLINE void set_rpc_stat_srv(void *rpc_stat_srv) { rpc_stat_srv_ = rpc_stat_srv; } + OB_INLINE void *get_rpc_stat_srv() const { return rpc_stat_srv_; } - static void set_compatibility_mode(CompatMode mode); - static CompatMode get_compatibility_mode(); - - bool is_timeout_ts_valid() - { return INT64_MAX != timeout_ts_;} - void set_timeout_ts(int64_t timeout_ts) { timeout_ts_ = timeout_ts; } - int64_t get_timeout_ts() const { return timeout_ts_; } - void set_ntp_offset(int64_t offset) { ntp_offset_ = offset; } - int64_t get_ntp_offset() const { return ntp_offset_; } + OB_INLINE bool is_timeout_ts_valid() { return INT64_MAX != timeout_ts_;} + OB_INLINE void set_timeout_ts(int64_t timeout_ts) { timeout_ts_ = timeout_ts; } + OB_INLINE int64_t get_timeout_ts() const { return timeout_ts_; } + OB_INLINE void set_ntp_offset(int64_t offset) { ntp_offset_ = offset; } + OB_INLINE int64_t get_ntp_offset() const { return ntp_offset_; } int64_t get_timeout_remain() const; bool is_timeout() const; - void set_rpc_tenant(uint64_t tenant_id) { rpc_tenant_id_ = tenant_id; } - void reset_rpc_tenant() { rpc_tenant_id_ = 0; } - uint64_t get_rpc_tenant() const { return rpc_tenant_id_; } - - ObIAllocator &ssstore_allocator(); - ObFIFOAllocator &ssstore_fifo_allocator(); - - void set_tidx(int64_t tidx); - void unset_tidx(); - int64_t get_tidx() const; - - // It's called when current query can't been retry, maybe some - // shared states have been published such as part of result has been - // sent to client, operation is doing or even has done and can't - // restart easily. It doesn't mean this query won't retry, but - // indicates following retry flag setting is forbade, - virtual void disable_retry(); - // check if retry disabled for the query - virtual bool can_retry() const; - // Set retry flag so that scheduler will reprocess this request then - virtual void set_need_retry(); - // It's used to check whether query need retry. Whenever worker has - // observed this query need retry, it should stop processing this - // query immediately. - virtual bool need_retry() const; - - // Set large token expired timestamp. - // - // Worker prefer process large queries than normal queries until - // token expires, that is the timestamp is larger than now. - void set_large_token_expired(int64_t timestamp); - - // Get large token expired timestamp. - int64_t get_large_token_expired() const; + OB_INLINE void set_rpc_tenant(uint64_t tenant_id) { rpc_tenant_id_ = tenant_id; } + OB_INLINE void reset_rpc_tenant() { rpc_tenant_id_ = 0; } + OB_INLINE uint64_t get_rpc_tenant() const { return rpc_tenant_id_; } // check wait is disabled if f is true - void set_disable_wait_flag(bool f); - bool get_disable_wait_flag() const; - - common::ObDLinkNode worker_node_; - common::ObDLinkNode lq_worker_node_; - common::ObDLinkNode lq_waiting_worker_node_; - common::ObLink wpool_link_; - - virtual void resume() {} + void set_disable_wait_flag(bool f) { disable_wait_ = f; } + bool get_disable_wait_flag() const { return disable_wait_; } void set_sql_throttle_current_priority(int64_t st_current_priority) { st_current_priority_ = st_current_priority; } void reset_sql_throttle_current_priority() { set_sql_throttle_current_priority(100); } - void set_session(sql::ObSQLSessionInfo* session) - { - session_ = session; - } + OB_INLINE void set_session(sql::ObSQLSessionInfo* session) { session_ = session; } + +public: + static void set_compatibility_mode(CompatMode mode); + static CompatMode get_compatibility_mode(); + static Worker& self(); public: static __thread Worker *self_; public: - // static variables - static Worker& self(); - + common::ObDLinkNode worker_node_; protected: // 线程运行时内存从此分配器分配 // 初始tenant_id=500, 在处理request时,tenant_id被更新成request的租户id // 可单独指定ctx_id, 此ctx_id保持不变 ObIAllocator *allocator_; + int64_t st_current_priority_; + sql::ObSQLSessionInfo *session_; private: const rpc::ObRequest *cur_request_; + // whether worker is in blocking + bool is_blocking_; int32_t worker_level_; int32_t curr_request_level_; int32_t group_id_; void *rpc_stat_srv_; -protected: - int64_t st_current_priority_; - sql::ObSQLSessionInfo *session_; - -private: int64_t timeout_ts_; //ingnore net time, equal to (receive_ts - send_ts). @@ -185,12 +146,6 @@ private: uint64_t rpc_tenant_id_; - // worker index in its tenant - int64_t tidx_; - - // timestamp when large token expires. - int64_t large_token_expired_; - // Used to prevent the thread holding the lock from being suspended by check_wait bool disable_wait_; @@ -208,79 +163,6 @@ inline Worker &Worker::self() return *self_; } -inline void Worker::set_tidx(int64_t tidx) -{ - tidx_ = tidx; -} - -inline void Worker::unset_tidx() -{ - tidx_ = -1; -} - -inline int64_t Worker::get_tidx() const -{ - return tidx_; -} - -inline void Worker::disable_retry() -{ -} - -inline bool Worker::can_retry() const -{ - return false; -} - -inline void Worker::set_need_retry() -{ -} - -inline bool Worker::need_retry() const -{ - return false; -} - -inline void Worker::set_large_token_expired(int64_t timestamp) -{ - large_token_expired_ = timestamp; -} - -inline int64_t Worker::get_large_token_expired() const -{ - return large_token_expired_; -} - -inline void Worker::set_disable_wait_flag(bool f) -{ - disable_wait_ = f; -} - -inline bool Worker::get_disable_wait_flag() const -{ - return disable_wait_; -} - -inline void Worker::set_req_flag(const rpc::ObRequest *cur_request) -{ - cur_request_ = cur_request; -} - -inline bool Worker::has_req_flag() -{ - return (NULL != cur_request_); -} - -inline const rpc::ObRequest *Worker::get_cur_request() -{ - return cur_request_; -} - -inline ObIAllocator &Worker::get_sql_arena_allocator() -{ - return CURRENT_CONTEXT->get_arena_allocator(); -} - inline ObIAllocator &Worker::get_allocator() { // 预期只在处理请求过程中调用 @@ -365,16 +247,16 @@ inline bool is_mysql_mode() return get_compat_mode() == Worker::CompatMode::MYSQL; } -inline void Worker::set_compatibility_mode(Worker::CompatMode mode) +OB_INLINE void Worker::set_compatibility_mode(Worker::CompatMode mode) { set_compat_mode(mode); } -inline Worker::CompatMode Worker::get_compatibility_mode() + +OB_INLINE Worker::CompatMode Worker::get_compatibility_mode() { return get_compat_mode(); } - } // end of namespace lib } // end of namespace oceanbase diff --git a/deps/oblib/src/rpc/CMakeLists.txt b/deps/oblib/src/rpc/CMakeLists.txt index feab56d71..73cd95856 100644 --- a/deps/oblib/src/rpc/CMakeLists.txt +++ b/deps/oblib/src/rpc/CMakeLists.txt @@ -62,7 +62,6 @@ ob_set_subtarget(oblib_rpc obrpc obrpc/ob_net_keepalive.cpp obrpc/ob_listener.cpp obrpc/ob_net_client.cpp - obrpc/ob_poc_nio.cpp obrpc/ob_poc_rpc_proxy.cpp obrpc/ob_poc_rpc_request_operator.cpp obrpc/ob_poc_rpc_server.cpp diff --git a/deps/oblib/src/rpc/frame/ob_net_easy.cpp b/deps/oblib/src/rpc/frame/ob_net_easy.cpp index 7c680a024..74efa5363 100644 --- a/deps/oblib/src/rpc/frame/ob_net_easy.cpp +++ b/deps/oblib/src/rpc/frame/ob_net_easy.cpp @@ -14,6 +14,7 @@ #include "io/easy_io.h" #include "rpc/frame/ob_net_easy.h" +#include "rpc/obrpc/ob_poc_rpc_server.h" #include "lib/ob_define.h" #include "lib/utility/utility.h" @@ -796,15 +797,20 @@ int ObNetEasy::start() LOG_ERROR("eio is NULL, not inited", K(is_inited_), KP_(rpc_eio), KP_(mysql_eio), KP_(batch_rpc_eio), K(ret)); } + // TODO: rpc_port_ might not in use + global_ob_listener = &rpc_listener_; if (OB_SUCC(ret) && rpc_port_ > 0) { - if (OB_FAIL(rpc_listener_.listen_create(rpc_port_))) { - LOG_ERROR("create listen failed", K(ret)); - } else if (OB_FAIL(rpc_listener_.start())) { - LOG_ERROR("oblistener start failed!", K(rpc_port_), K(ret)); - } else if (OB_FAIL(ObNetKeepAlive::get_instance().start())) { - LOG_ERROR("oblistener start failed!", K(rpc_port_), K(ret)); + if (!global_poc_server.has_start()) { + if (OB_FAIL(rpc_listener_.listen_create(rpc_port_))) { + LOG_ERROR("create listen failed", K(ret)); + } else if (OB_FAIL(rpc_listener_.start())) { + LOG_ERROR("oblistener start failed!", K(rpc_port_), K(ret)); + } + } + if (OB_SUCC(ret) && OB_FAIL(ObNetKeepAlive::get_instance().start())) { + LOG_ERROR("ObNetKeepAlive start failed!", K(rpc_port_), K(ret)); } else { - LOG_INFO("oblistener start!", K(rpc_port_)); + LOG_INFO("ObNetKeepAlive start!", K(rpc_port_)); } } diff --git a/deps/oblib/src/rpc/frame/ob_req_deliver.h b/deps/oblib/src/rpc/frame/ob_req_deliver.h index cc1266ca0..135ea168a 100644 --- a/deps/oblib/src/rpc/frame/ob_req_deliver.h +++ b/deps/oblib/src/rpc/frame/ob_req_deliver.h @@ -45,6 +45,7 @@ class ObReqQDeliver { public: explicit ObReqQDeliver(ObiReqQHandler &qhandler); + ObiReqQHandler &get_qhandler() { return qhandler_; } protected: ObiReqQHandler &qhandler_; diff --git a/deps/oblib/src/rpc/frame/ob_req_queue_thread.cpp b/deps/oblib/src/rpc/frame/ob_req_queue_thread.cpp index a9995996c..522abb6a4 100644 --- a/deps/oblib/src/rpc/frame/ob_req_queue_thread.cpp +++ b/deps/oblib/src/rpc/frame/ob_req_queue_thread.cpp @@ -148,7 +148,7 @@ void ObReqQueue::loop() ret = OB_INVALID_ARGUMENT; LOG_ERROR("invalid argument", K(qhandler_)); } else if (OB_FAIL(qhandler_->onThreadCreated(nullptr))) { - LOG_ERROR("do thread craeted fail, thread will exit", K(ret)); + LOG_ERROR("do thread created fail, thread will exit", K(ret)); } else { // The main loop threads process tasks. while (!Thread::current().has_set_stop()) { diff --git a/deps/oblib/src/rpc/frame/ob_req_transport.h b/deps/oblib/src/rpc/frame/ob_req_transport.h index 1a292a3b0..ba57a1821 100644 --- a/deps/oblib/src/rpc/frame/ob_req_transport.h +++ b/deps/oblib/src/rpc/frame/ob_req_transport.h @@ -93,7 +93,7 @@ public: { public: AsyncCB(int pcode) - : dst_(), timeout_(0), tenant_id_(0), + : low_level_cb_(NULL), dst_(), timeout_(0), tenant_id_(0), err_(0), pcode_(pcode), send_ts_(0), payload_(0) {} virtual ~AsyncCB() {} @@ -124,6 +124,7 @@ public: void set_payload(const int64_t payload) { payload_ = payload; } int64_t get_payload() { return payload_; } + void* low_level_cb_; private: static const int64_t REQUEST_ITEM_COST_RT = 100 * 1000; // 100ms protected: diff --git a/deps/oblib/src/rpc/obmysql/ob_mysql_request_utils.h b/deps/oblib/src/rpc/obmysql/ob_mysql_request_utils.h index 0eb3781ae..75664155b 100644 --- a/deps/oblib/src/rpc/obmysql/ob_mysql_request_utils.h +++ b/deps/oblib/src/rpc/obmysql/ob_mysql_request_utils.h @@ -16,6 +16,7 @@ #include "lib/ob_define.h" #include "lib/utility/ob_print_utils.h" #include "lib/allocator/ob_mod_define.h" +#include "lib/allocator/page_arena.h" #include "rpc/obmysql/ob_mysql_packet.h" namespace oceanbase diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_nio.cpp b/deps/oblib/src/rpc/obmysql/ob_sql_nio.cpp index 04bec0b86..32a0c8ff7 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_nio.cpp +++ b/deps/oblib/src/rpc/obmysql/ob_sql_nio.cpp @@ -92,10 +92,9 @@ struct ReadyFlag int32_t pending_ CACHE_ALIGNED; }; -#define futex(...) syscall(SYS_futex,__VA_ARGS__) static int futex_wake(volatile int *p, int val) { - return static_cast(futex((int *)p, FUTEX_WAKE_PRIVATE, val, NULL, NULL, 0)); + return futex((uint *)p, FUTEX_WAKE_PRIVATE, val, NULL); } struct SingleWaitCond @@ -330,7 +329,7 @@ private: class ObSqlSock: public ObLink { public: - ObSqlSock(ObSqlNioImpl& nio, int fd): nio_impl_(nio), fd_(fd), err_(0), read_buffer_(fd), + ObSqlSock(ObSqlNioImpl *nio, int fd): nio_impl_(nio), fd_(fd), err_(0), read_buffer_(fd), need_epoll_trigger_write_(false), may_handling_(true), handler_close_flag_(false), need_shutdown_(false), last_decode_time_(0), last_write_time_(0), sql_session_info_(NULL) { memset(sess_, 0, sizeof(sess_)); @@ -339,7 +338,8 @@ public: int64_t get_remain_sz() const { return read_buffer_.get_remain_sz(); } TO_STRING_KV(KP(this), K_(fd), K_(err), K(last_decode_time_), K(last_write_time_), K(read_buffer_.get_consume_sz()), K(get_pending_flag()), KPC(get_trace_id())); - ObSqlNioImpl& get_nio_impl() { return nio_impl_; } + ObSqlNioImpl *get_nio_impl() { return nio_impl_; } + void set_nio_impl(ObSqlNioImpl *impl) { nio_impl_ = impl; } bool set_error(int err) { return 0 == ATOMIC_TAS(&err_, err); } bool has_error() const { return ATOMIC_LOAD(&err_) != 0; } @@ -439,7 +439,7 @@ public: ObDLink all_list_link_; ObLink write_task_link_; private: - ObSqlNioImpl& nio_impl_; + ObSqlNioImpl *nio_impl_; int fd_; int err_; ReadBuffer read_buffer_; @@ -457,6 +457,11 @@ public: char sess_[3000] __attribute__((aligned(16))); }; +static ObSqlSock *sess2sock(void *sess) +{ + return CONTAINER_OF(sess, ObSqlSock, sess_); +} + int ObSqlSock::set_ssl_enabled() { int ret = OB_SUCCESS; @@ -584,8 +589,41 @@ public: ObSqlNioImpl(ObISqlSockHandler& handler): handler_(handler), epfd_(-1), lfd_(-1), tcp_keepalive_enabled_(0), tcp_keepidle_(0), tcp_keepintvl_(0), tcp_keepcnt_(0) {} - ~ObSqlNioImpl() {} + ~ObSqlNioImpl() { + destroy(); + } + void destroy() { + ObDLink *head = all_list_.head(); + ObLink *cur = head->next_; + while (cur != head) { + ObSqlSock *s = CONTAINER_OF(cur, ObSqlSock, all_list_link_); + cur = cur->next_; + free_sql_sock(s); + } + } int init(int port) { + int ret = OB_SUCCESS; + if (port == -1) { + ret = init_io(); + } else { + ret = init_listen(port); + } + return ret; + } + int init_io() { + int ret = OB_SUCCESS; + uint32_t epflag = EPOLLIN; + if ((epfd_ = epoll_create1(EPOLL_CLOEXEC)) < 0) { + ret = OB_IO_ERROR; + LOG_WARN("epoll_create fail", K(ret), K(errno)); + } else if (OB_FAIL(evfd_.create(epfd_))) { + LOG_WARN("evfd create fail", K(ret)); + } else { + LOG_INFO("sql_nio init io succ"); + } + return ret; + } + int init_listen(int port) { int ret = OB_SUCCESS; uint32_t epflag = EPOLLIN; if ((epfd_ = epoll_create1(EPOLL_CLOEXEC)) < 0) { @@ -600,7 +638,7 @@ public: } else if (OB_FAIL(evfd_.create(epfd_))) { LOG_WARN("evfd create fail", K(ret)); } else { - LOG_INFO("sql_nio listen succ", K(port)); + LOG_INFO("sql_nio init listen succ", K(port)); } return ret; } @@ -618,6 +656,25 @@ public: update_tcp_keepalive_parameters(); print_session_info(); } + int regist_sess(void *sess) { + int err = 0; + ObSqlSock *sock = sess2sock(sess); + int fd = sock->get_fd(); + uint32_t epflag = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLET | EPOLLRDHUP; + ObSqlNioImpl *nio_impl = sock->get_nio_impl(); + sock->remove_fd_from_epoll(nio_impl->get_epfd()); + nio_impl->remove_session_info(sock); + record_session_info(sock); + sock->set_nio_impl(this); + if (0 != (err = epoll_regist(epfd_, fd, epflag, sock))) { + LOG_WARN_RET(OB_ERR_SYS, "epoll_regist fail", K(fd), K(err)); + } + if (0 != err && NULL != sock) { + ObSqlSockSession *sess = (ObSqlSockSession *)sock->sess_; + sess->destroy_sock(); + } + return err; + } void push_close_req(ObSqlSock* s) { if (s->set_error(EIO)) { LOG_WARN_RET(OB_ERR_SYS, "close sql sock by user req", K(*s)); @@ -724,7 +781,6 @@ private: } else { if (true == s->sql_session_info_is_null()) { pending_destroy_list_.del(&s->dlink_); - remove_session_info(s); s->do_close(); free_sql_sock(s); } @@ -832,13 +888,14 @@ private: ObSqlSock* alloc_sql_sock(int fd) { ObSqlSock* s = NULL; if (NULL != (s = (ObSqlSock*)direct_alloc(sizeof(*s)))) { - new(s)ObSqlSock(*this, fd); + new (s) ObSqlSock(this, fd); record_session_info(s); } return s; } void free_sql_sock(ObSqlSock* s) { if (NULL != s) { + remove_session_info(s); s->~ObSqlSock(); direct_free(s); } @@ -893,6 +950,7 @@ private: static void* direct_alloc(int64_t sz) { return common::ob_malloc(sz, common::ObModIds::OB_COMMON_NETWORK); } static void direct_free(void* p) { common::ob_free(p); } + int get_epfd(){return epfd_;} private: ObISqlSockHandler& handler_; int epfd_; @@ -908,21 +966,28 @@ private: uint32_t tcp_keepcnt_; }; -int ObSqlNio::start(int port, ObISqlSockHandler* handler, int n_thread) +int ObSqlNio::start(int port, ObISqlSockHandler *handler, int n_thread, + const uint64_t tenant_id) { int ret = OB_SUCCESS; - if (NULL == (impl_ = (typeof(impl_))ob_malloc(sizeof(ObSqlNioImpl) * n_thread, "SqlNio"))) { + port_ = port; + handler_ = handler; + tenant_id_ = tenant_id; + if (n_thread > MAX_THREAD_CNT) { + ret = OB_INVALID_ARGUMENT; + } else if (NULL == (impl_ = (typeof(impl_))ob_malloc( + sizeof(ObSqlNioImpl) * MAX_THREAD_CNT, "SqlNio"))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc sql nio fail", K(ret)); } else { - for(int i = 0; OB_SUCCESS == ret && i < n_thread; i++) { - new(impl_ + i)ObSqlNioImpl(*handler); + for (int i = 0; OB_SUCCESS == ret && i < n_thread; i++) { + new (impl_ + i) ObSqlNioImpl(*handler); if (OB_FAIL(impl_[i].init(port))) { LOG_WARN("impl init fail", K(ret)); } } if (OB_SUCC(ret)) { - set_thread_count(n_thread); + lib::Threads::set_thread_count(n_thread); lib::Threads::start(); } } @@ -941,14 +1006,23 @@ void ObSqlNio::wait() void ObSqlNio::destroy() { + for (int i = 0; i < get_thread_count(); i++) { + impl_[i].destroy(); + } } +int __attribute__((weak)) sql_nio_add_cgroup(const uint64_t tenant_id) +{ + return 0; +} void ObSqlNio::run(int64_t idx) { - int ret = OB_SUCCESS; if (NULL != impl_) { lib::set_thread_name("sql_nio", idx); - while(!has_set_stop()) { + // if (tenant_id_ != common::OB_INVALID_ID) { + // obmysql::sql_nio_add_cgroup(tenant_id_); + // } + while(!has_set_stop() && !(OB_NOT_NULL(&lib::Thread::current()) ? lib::Thread::current().has_set_stop() : false)) { impl_[idx].do_work(); } if (has_set_stop()) { @@ -957,21 +1031,16 @@ void ObSqlNio::run(int64_t idx) } } -static ObSqlSock* sess2sock(void* sess) -{ - return CONTAINER_OF(sess, ObSqlSock, sess_); -} - void ObSqlNio::destroy_sock(void* sess) { ObSqlSock* sock = sess2sock(sess); - sock->get_nio_impl().push_close_req(sock); + sock->get_nio_impl()->push_close_req(sock); } void ObSqlNio::revert_sock(void* sess) { ObSqlSock* sock = sess2sock(sess); - sock->get_nio_impl().revert_sock(sock); + sock->get_nio_impl()->revert_sock(sock); } void ObSqlNio::set_shutdown(void* sess) @@ -1027,7 +1096,7 @@ void ObSqlNio::async_write_data(void* sess, const char* buf, int64_t sz) { ObSqlSock* sock = sess2sock(sess); sock->init_write_task(buf, sz); - sock->get_nio_impl().push_write_req(sock); + sock->get_nio_impl()->push_write_req(sock); } int ObSqlNio::set_ssl_enabled(void* sess) @@ -1042,6 +1111,43 @@ SSL* ObSqlNio::get_ssl_st(void* sess) return sock->get_ssl_st(); } +int ObSqlNio::set_thread_count(const int n_thread) +{ + int ret = OB_SUCCESS; + int cur_thread = get_thread_count(); + if (n_thread > MAX_THREAD_CNT) { + ret = OB_INVALID_ARGUMENT; + } else if (n_thread == cur_thread) { + // do nothing + } else { + if (n_thread > cur_thread) { + for (int i = cur_thread; OB_SUCCESS == ret && i < n_thread; i++) { + new (impl_ + i) ObSqlNioImpl(*handler_); + if (OB_FAIL(impl_[i].init(port_))) { + LOG_WARN("impl init fail"); + } + } + if (OB_SUCC(ret)) { + lib::Threads::set_thread_count(n_thread); + } + } else { + LOG_WARN("decrease thread count not allowed", K(cur_thread), + K(n_thread)); + } + } + return ret; +} + +int ObSqlNio::regist_sess(void *sess) +{ + int err = 0; + ((ObSqlSockSession *)sess)->nio_ = this; + if (0 != (err = impl_[get_dispatch_idx()].regist_sess(sess))) { + LOG_ERROR_RET(OB_ERR_SYS, "regist sess fd fail", K(err)); + } + return err; +} + void ObSqlNio::update_tcp_keepalive_params(int keepalive_enabled, uint32_t tcp_keepidle, uint32_t tcp_keepintvl, uint32_t tcp_keepcnt) { int thread_count = get_thread_count(); diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_nio.h b/deps/oblib/src/rpc/obmysql/ob_sql_nio.h index 0995439de..eaa4d65f9 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_nio.h +++ b/deps/oblib/src/rpc/obmysql/ob_sql_nio.h @@ -17,6 +17,8 @@ #include "lib/thread/threads.h" #include "lib/ssl/ob_ssl_config.h" +#define MAX_THREAD_CNT 64 + namespace oceanbase { namespace obmysql @@ -26,9 +28,12 @@ class ObISqlSockHandler; class ObSqlNio: public lib::Threads { public: - ObSqlNio(): impl_(NULL) {} + ObSqlNio() + : impl_(NULL), port_(0), handler_(NULL), dispatch_idx_(0), + tenant_id_(common::OB_INVALID_ID) {} virtual ~ObSqlNio() {} - int start(int port, ObISqlSockHandler* handler, int n_thread); + int start(int port, ObISqlSockHandler *handler, int n_thread, + const uint64_t tenant_id); bool has_error(void* sess); void destroy_sock(void* sess); void revert_sock(void* sess); @@ -46,13 +51,23 @@ public: void shutdown(void* sess); int set_ssl_enabled(void* sess); SSL* get_ssl_st(void* sess); + int get_thread_count() { return lib::Threads::get_thread_count(); } + int set_thread_count(const int n_thread); + int regist_sess(void *sess); + uint64_t get_dispatch_idx() { + return ATOMIC_FAA(&dispatch_idx_, 1) % get_thread_count(); + } void update_tcp_keepalive_params(int keepalive_enabled, uint32_t tcp_keepidle, uint32_t tcp_keepintvl, uint32_t tcp_keepcnt); private: void run(int64_t idx); private: ObSqlNioImpl* impl_; + int port_; + ObISqlSockHandler* handler_; + uint64_t dispatch_idx_; + uint64_t tenant_id_; }; - +extern int sql_nio_add_cgroup(const uint64_t tenant_id); }; // end namespace obmysql }; // end namespace oceanbase diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.cpp b/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.cpp index f12bec69a..9779061f1 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.cpp +++ b/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.cpp @@ -24,12 +24,21 @@ int ObSqlNioServer::start(int port, rpc::frame::ObReqDeliver* deliver, int n_thr int ret = OB_SUCCESS; if (OB_FAIL(io_handler_.init(deliver))) { LOG_WARN("handler init fail", K(ret)); - } else if (OB_FAIL(nio_.start(port, &io_handler_, n_thread))) { + } else if (OB_FAIL(nio_.start(port, &io_handler_, n_thread, tenant_id_))) { LOG_WARN("sql nio start fail", K(ret)); } return ret; } +int ObSqlNioServer::set_thread_count(const int thread_num) +{ + int ret = OB_SUCCESS; + if(thread_num != get_nio()->get_thread_count()){ + ret = nio_.set_thread_count(thread_num); + } + return ret; +} + void ObSqlNioServer::stop() { nio_.stop(); diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.h b/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.h index 679d893f3..7e692c7f5 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.h +++ b/deps/oblib/src/rpc/obmysql/ob_sql_nio_server.h @@ -23,13 +23,19 @@ namespace obmysql class ObSqlNioServer { public: - ObSqlNioServer(ObISMConnectionCallback& conn_cb, ObMySQLHandler& mysql_handler): thread_processor_(mysql_handler), io_handler_(conn_cb, thread_processor_, nio_) {} + ObSqlNioServer(ObISMConnectionCallback &conn_cb, + ObMySQLHandler &mysql_handler, + const uint64_t tenant_id = common::OB_INVALID_ID) + : thread_processor_(mysql_handler), + io_handler_(conn_cb, thread_processor_, nio_), tenant_id_(tenant_id) {} virtual ~ObSqlNioServer() {} + ObSqlNio *get_nio() { return &nio_; } int start(int port, rpc::frame::ObReqDeliver* deliver, int n_thread); void revert_sock(void* sess); int peek_data(void* sess, int64_t limit, const char*& buf, int64_t& sz); int consume_data(void* sess, int64_t sz); int write_data(void* sess, const char* buf, int64_t sz); + int set_thread_count(const int thread_num); void stop(); void wait(); void destroy(); @@ -38,6 +44,7 @@ private: ObSqlSockProcessor thread_processor_; // for tenant worker ObSqlSockHandler io_handler_; // for io thread ObSqlNio nio_; + uint64_t tenant_id_; }; extern ObSqlNioServer* global_sql_nio_server; }; // end namespace obmysql diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_sock_handler.h b/deps/oblib/src/rpc/obmysql/ob_sql_sock_handler.h index 639b6c39d..5254ea4a5 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_sock_handler.h +++ b/deps/oblib/src/rpc/obmysql/ob_sql_sock_handler.h @@ -29,7 +29,7 @@ class ObSqlSockHandler: public ObISqlSockHandler { public: ObSqlSockHandler(ObISMConnectionCallback& conn_cb, ObSqlSockProcessor& sock_processor, ObSqlNio& nio): - conn_cb_(conn_cb), sock_processor_(sock_processor), deliver_(nullptr), nio_(nio) {} + conn_cb_(conn_cb), sock_processor_(sock_processor), deliver_(nullptr), nio_(&nio) {} virtual ~ObSqlSockHandler() {} int init(rpc::frame::ObReqDeliver* deliver); virtual int on_readable(void* sess) override; @@ -40,7 +40,7 @@ private: ObISMConnectionCallback& conn_cb_; ObSqlSockProcessor& sock_processor_; rpc::frame::ObReqDeliver* deliver_; - ObSqlNio& nio_; + ObSqlNio* nio_; }; }; // end namespace obmysql diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.cpp b/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.cpp index 0ff4a9acf..33df3cc3f 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.cpp +++ b/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.cpp @@ -22,7 +22,7 @@ using namespace observer; namespace obmysql { -ObSqlSockSession::ObSqlSockSession(ObISMConnectionCallback& conn_cb, ObSqlNio& nio): +ObSqlSockSession::ObSqlSockSession(ObISMConnectionCallback& conn_cb, ObSqlNio* nio): nio_(nio), sm_conn_cb_(conn_cb), sql_req_(ObRequest::OB_MYSQL, 1), @@ -48,7 +48,7 @@ void ObSqlSockSession::destroy() void ObSqlSockSession::destroy_sock() { - return nio_.destroy_sock((void*)this); + return nio_->destroy_sock((void*)this); } int ObSqlSockSession::on_disconnect() @@ -58,18 +58,18 @@ int ObSqlSockSession::on_disconnect() void ObSqlSockSession::set_shutdown() { - return nio_.set_shutdown((void *)this); + return nio_->set_shutdown((void *)this); } void ObSqlSockSession::shutdown() { - return nio_.shutdown((void *)this); + return nio_->shutdown((void *)this); } void ObSqlSockSession::revert_sock() { if (last_pkt_sz_ > 0) { - nio_.consume_data((void*)this, last_pkt_sz_); + nio_->consume_data((void*)this, last_pkt_sz_); last_pkt_sz_ = 0; } sql_req_.reset_trace_id(); @@ -78,10 +78,10 @@ void ObSqlSockSession::revert_sock() int64_t sz = pending_write_sz_; pending_write_buf_ = NULL; pending_write_sz_ = 0; - nio_.async_write_data((void*)this, data, sz); + nio_->async_write_data((void*)this, data, sz); } else { pool_.reuse(); - nio_.revert_sock((void*)this); + nio_->revert_sock((void*)this); } } @@ -90,12 +90,12 @@ void ObSqlSockSession::on_flushed() /* TODO should not go here*/ //abort(); pool_.reuse(); - nio_.revert_sock((void*)this); + nio_->revert_sock((void*)this); } bool ObSqlSockSession::has_error() { - return nio_.has_error((void*)this); + return nio_->has_error((void*)this); } int ObSqlSockSession::peek_data(int64_t limit, const char*& buf, int64_t& sz) @@ -104,7 +104,7 @@ int ObSqlSockSession::peek_data(int64_t limit, const char*& buf, int64_t& sz) if (has_error()) { ret = OB_IO_ERROR; LOG_WARN("sock has error", K(ret)); - } else if (OB_FAIL(nio_.peek_data((void*)this, limit, buf, sz))) { + } else if (OB_FAIL(nio_->peek_data((void*)this, limit, buf, sz))) { destroy_sock(); } return ret; @@ -112,7 +112,7 @@ int ObSqlSockSession::peek_data(int64_t limit, const char*& buf, int64_t& sz) void ObSqlSockSession::clear_sql_session_info() { - nio_.reset_sql_session_info(this); + nio_->reset_sql_session_info(this); } int ObSqlSockSession::consume_data(int64_t sz) @@ -121,7 +121,7 @@ int ObSqlSockSession::consume_data(int64_t sz) if (has_error()) { ret = OB_IO_ERROR; LOG_WARN("sock has error", K(ret)); - } else if (OB_FAIL(nio_.consume_data((void*)this, sz))) { + } else if (OB_FAIL(nio_->consume_data((void*)this, sz))) { destroy_sock(); } return ret; @@ -129,7 +129,7 @@ int ObSqlSockSession::consume_data(int64_t sz) void ObSqlSockSession::set_last_decode_succ_and_deliver_time(int64_t time) { - nio_.set_last_decode_succ_time((void*)this, time); + nio_->set_last_decode_succ_time((void*)this, time); } int ObSqlSockSession::write_data(const char* buf, int64_t sz) { @@ -137,7 +137,7 @@ int ObSqlSockSession::write_data(const char* buf, int64_t sz) if (has_error()) { ret = OB_IO_ERROR; LOG_WARN("sock has error", K(ret)); - } else if (OB_FAIL(nio_.write_data((void*)this, buf, sz))) { + } else if (OB_FAIL(nio_->write_data((void*)this, buf, sz))) { destroy_sock(); } return ret; @@ -158,17 +158,17 @@ int ObSqlSockSession::async_write_data(const char* buf, int64_t sz) void ObSqlSockSession::set_sql_session_info(void* sess) { - nio_.set_sql_session_info((void *)this, sess); + nio_->set_sql_session_info((void *)this, sess); } int ObSqlSockSession::set_ssl_enabled() { - return nio_.set_ssl_enabled((void *)this); + return nio_->set_ssl_enabled((void *)this); } SSL* ObSqlSockSession::get_ssl_st() { - return nio_.get_ssl_st((void *)this); + return nio_->get_ssl_st((void *)this); } }; // end namespace obmysql diff --git a/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.h b/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.h index 075bd1c00..e1b1d2a13 100644 --- a/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.h +++ b/deps/oblib/src/rpc/obmysql/ob_sql_sock_session.h @@ -39,7 +39,7 @@ private: class ObSqlSockSession { public: - ObSqlSockSession(ObISMConnectionCallback& conn_cb, ObSqlNio& nio); + ObSqlSockSession(ObISMConnectionCallback& conn_cb, ObSqlNio* nio); ~ObSqlSockSession(); void* alloc(int64_t sz) { return pool_.alloc(sz); } int init(); @@ -61,7 +61,7 @@ public: void set_sql_session_info(void* sess); int set_ssl_enabled(); SSL* get_ssl_st(); - ObSqlNio& nio_; + ObSqlNio* nio_; ObISMConnectionCallback& sm_conn_cb_; rpc::ObRequest sql_req_; ObSqlSessionMemPool pool_; diff --git a/deps/oblib/src/rpc/obrpc/ob_listener.cpp b/deps/oblib/src/rpc/obrpc/ob_listener.cpp index 8d70416c9..0bae7c2d1 100644 --- a/deps/oblib/src/rpc/obrpc/ob_listener.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_listener.cpp @@ -365,6 +365,42 @@ void ObListener::do_work() return; } +int ObListener::do_one_event(int accept_fd) { + int err = 0; + int tmp_ret = OB_SUCCESS; + uint64_t client_magic = 0; + uint8_t index = 0; + io_threads_pipefd_pool_t *pipefd_pool = NULL; + + if (OB_TMP_FAIL(read_client_magic(accept_fd, client_magic, index))) { + index = compatible_balance_assign(pipefd_pool); + trace_connection_info(accept_fd); + if (OB_TMP_FAIL(connection_redispatch(accept_fd, pipefd_pool, index))) { + close(accept_fd); + } + pipefd_pool = NULL; + } else { + for (int i = 0; i < MAX_PROTOCOL_TYPE_SIZE; i++) { + if (io_wrpipefd_map_[i].used && io_wrpipefd_map_[i].magic == client_magic) { + pipefd_pool = &(io_wrpipefd_map_[i].ioth_wrpipefd_pool); + } + } + + trace_connection_info(accept_fd); + + if (OB_ISNULL(pipefd_pool)) { /* high_prio_rpc_eio exist or not is decided by configuration */ + index = compatible_balance_assign(pipefd_pool); + } else { + RPC_LOG(INFO, "dispatch to", K(client_magic), K(index)); + } + if(OB_TMP_FAIL(connection_redispatch(accept_fd, pipefd_pool, index))) { + close(accept_fd); + } + pipefd_pool = NULL; + } + return err; +} + uint8_t ObListener::compatible_balance_assign(io_threads_pipefd_pool_t * &pipefd_pool) { static uint8_t ioth_index_inc = 0; diff --git a/deps/oblib/src/rpc/obrpc/ob_listener.h b/deps/oblib/src/rpc/obrpc/ob_listener.h index ea29bfcd9..cf96d66f8 100644 --- a/deps/oblib/src/rpc/obrpc/ob_listener.h +++ b/deps/oblib/src/rpc/obrpc/ob_listener.h @@ -66,6 +66,7 @@ public: int regist(uint64_t magic, int count, int *pipefd_array); uint8_t compatible_balance_assign(io_threads_pipefd_pool_t *& pipefd_pool); void set_port(int port) {port_ = port;} + int do_one_event(int accept_fd); void destroy(); private: diff --git a/deps/oblib/src/rpc/obrpc/ob_net_client.cpp b/deps/oblib/src/rpc/obrpc/ob_net_client.cpp index d70093f68..0974ad7ca 100644 --- a/deps/oblib/src/rpc/obrpc/ob_net_client.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_net_client.cpp @@ -16,6 +16,9 @@ #include "lib/ob_define.h" #include "lib/net/ob_addr.h" #include "rpc/obrpc/ob_rpc_proxy.h" +extern "C" { +#include "rpc/pnio/interface/group.h" +}; using namespace oceanbase::common; @@ -50,6 +53,7 @@ int ObNetClient::init_(const ObNetOptions opts) } else if (OB_FAIL(net_.start())) { LOG_ERROR("Start client network fail", K(ret)); } else { + pn_provision(-1, 1, 1); inited_ = true; } diff --git a/deps/oblib/src/rpc/obrpc/ob_nio_interface.h b/deps/oblib/src/rpc/obrpc/ob_nio_interface.h deleted file mode 100644 index 6ed7f2d44..000000000 --- a/deps/oblib/src/rpc/obrpc/ob_nio_interface.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * 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_OBRPC_OB_NIO_INTERFACE_H_ -#define OCEANBASE_OBRPC_OB_NIO_INTERFACE_H_ -#include -#include -#include "lib/net/ob_addr.h" - -namespace oceanbase -{ -namespace obrpc -{ - -class IReqHandler -{ -public: - IReqHandler() {} - virtual ~IReqHandler() {} - virtual int handle_req(int64_t resp_id, char* buf, int64_t sz) = 0; -}; - -class IRespHandler -{ -public: - IRespHandler() {} - virtual ~IRespHandler() {} - virtual void* alloc(int64_t sz) = 0; - virtual int handle_resp(int io_err, char* buf, int64_t sz) = 0; -}; - -class ObINio -{ -public: - ObINio(): accept_queue_fd_(-1), req_handler_(NULL) {} - virtual ~ObINio() {} - void init(IReqHandler* req_handler, int accept_queue_fd) { - req_handler_ = req_handler; - accept_queue_fd_ = accept_queue_fd; - } - int start() { - return pthread_create(&thread_, NULL, thread_func, this); - } - virtual int post(const common::ObAddr& addr, const char* req, int64_t req_size, IRespHandler* resp_handler) = 0; - virtual int resp(int64_t resp_id, char* buf, int64_t sz) = 0; -private: - static void* thread_func(void* arg) { - ((ObINio*)arg)->do_work(0); - return NULL; - } - virtual int do_work(int tid) = 0; -private: - pthread_t thread_; -protected: - int accept_queue_fd_; - IReqHandler* req_handler_; -}; - -}; // end namespace obrpc -}; // end namespace oceanbase - -#endif /* OCEANBASE_OBRPC_OB_NIO_INTERFACE_H_ */ - diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_nio.cpp b/deps/oblib/src/rpc/obrpc/ob_poc_nio.cpp deleted file mode 100644 index 948d1bcf8..000000000 --- a/deps/oblib/src/rpc/obrpc/ob_poc_nio.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * 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. - */ - -#include "rpc/obrpc/ob_poc_nio.h" -#include "lib/oblog/ob_log.h" -#include -#include - -using namespace oceanbase::common; -using namespace oceanbase::obrpc; - -static struct sockaddr_in* obaddr2sockaddr(struct sockaddr_in *sin, const ObAddr& addr) -{ - if (NULL != sin) { - sin->sin_port = (uint16_t)htons((uint16_t)(addr.get_port() + 123)); - sin->sin_addr.s_addr = htonl(addr.get_ipv4()); - sin->sin_family = AF_INET; - } - return sin; -} - -int ObPocNio::post(const common::ObAddr& addr, const char* req, int64_t req_size, IRespHandler* resp_handler) -{ - int ret = 0; - int64_t io_limit = 1<<21; - RLOCAL(char*, resp_buf); - struct sockaddr_in sin; - int fd = -1; - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - ret = errno; - RPC_LOG(WARN, "create socket fail", K(errno)); - } else if (connect(fd, (sockaddr*)obaddr2sockaddr(&sin, addr), sizeof(sin)) < 0) { - ret = errno; - RPC_LOG(WARN, "connect fail", K(addr), K(errno)); - } else if (write(fd, req, req_size) != req_size) { - ret = errno; - RPC_LOG(WARN, "write fail", K(req_size), K(errno)); - } else if (NULL == resp_buf && NULL == (resp_buf = (char*)malloc(io_limit))) { - ret = ENOMEM; - RPC_LOG(WARN, "alloc resp buffer fail", K(io_limit), K(errno)); - } else { - shutdown(fd, SHUT_WR); - RPC_LOG(INFO, "post succ, shutdown write side, blocking read response"); - int64_t sz = read(fd, resp_buf, io_limit); - if (sz < 0) { - RPC_LOG(WARN, "read resp fail", K(errno)); - sz = 0; - } - RPC_LOG(INFO, "receive resp finish", K(sz)); - resp_handler->handle_resp(ret, resp_buf, sz); - RPC_LOG(INFO, "resp callback finish"); - } - if (fd >= 0) { - close(fd); - } - return ret; -} - -int ObPocNio::resp(int64_t resp_id, char* buf, int64_t sz) -{ - int fd = (int)resp_id; - if (sz > 0 && fd >= 0) { - if (write(fd, buf, sz) < 0) { - RPC_LOG_RET(WARN, common::OB_ERR_SYS, "write resp fail", K(errno)); - } else { - RPC_LOG_RET(WARN, common::OB_SUCCESS, "write resp OK"); - } - } else { - RPC_LOG_RET(WARN, common::OB_INVALID_ARGUMENT, "resp invalid argument", KP(buf), K(sz), K(fd)); - } - if (fd >= 0) { - close(fd); - } - return 0; -} - -int ObPocNio::do_work(int tid) -{ - UNUSED(tid); - int64_t io_limit = 1<<22; - char* io_buf = (char*)malloc(io_limit); - while(1){ - int fd = -1; - if (read(accept_queue_fd_, &fd, sizeof(fd)) != sizeof(fd)) { - RPC_LOG_RET(ERROR, common::OB_ERR_SYS, "read accept queue fail"); - continue; - } else { - RPC_LOG(INFO, "read accept queue succ", K(fd)); - } - int64_t sz = read(fd, io_buf, io_limit); - if (sz < 0 || sz >= io_limit) { - RPC_LOG_RET(WARN, common::OB_ERR_SYS, "read socket error", K(errno), K(fd)); - close(fd); - } else { - int ret = OB_SUCCESS; - RPC_LOG(INFO, "read a complete request", K(fd)); - if (OB_FAIL(req_handler_->handle_req(fd, io_buf, sz))) { - RPC_LOG(WARN, "read socket error", K(ret)); - close(fd); - } else { - RPC_LOG(INFO, "handle_req success", K(fd)); - } - } - } -} diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_nio.h b/deps/oblib/src/rpc/obrpc/ob_poc_nio.h deleted file mode 100644 index 8f40c4a83..000000000 --- a/deps/oblib/src/rpc/obrpc/ob_poc_nio.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * 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_OBRPC_OB_POC_NIO_H_ -#define OCEANBASE_OBRPC_OB_POC_NIO_H_ -#include "rpc/obrpc/ob_nio_interface.h" - -namespace oceanbase -{ -namespace obrpc -{ -class ObPocNio: public ObINio -{ -public: - ObPocNio() {} - virtual ~ObPocNio() {} - int post(const common::ObAddr& addr, const char* req, int64_t req_size, IRespHandler* resp_handler) override; - int resp(int64_t resp_id, char* buf, int64_t sz) override; -private: - int do_work(int tid); -}; - -extern ObPocNio global_poc_nio_; -}; // end namespace obrpc -}; // end namespace oceanbase - -#endif /* OCEANBASE_OBRPC_OB_POC_NIO_H_ */ diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.cpp b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.cpp index e30482dd4..cd8e1245d 100644 --- a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.cpp @@ -13,22 +13,53 @@ #include "rpc/obrpc/ob_poc_rpc_proxy.h" #include "rpc/obrpc/ob_poc_rpc_server.h" #include "rpc/obrpc/ob_rpc_proxy.h" +#include "rpc/obrpc/ob_net_keepalive.h" +extern "C" { +#include "rpc/pnio/r0/futex.h" +} using namespace oceanbase::common; namespace oceanbase { namespace obrpc { - -int ObSyncRespCallback::handle_resp(int io_err, char* buf, int64_t sz) +const int easy_head_size = 16; +int ObSyncRespCallback::handle_resp(int io_err, const char* buf, int64_t sz) { - int ret = OB_SUCCESS; - if (0 == io_err) { - resp_ = buf; + if (PNIO_OK != io_err) { + if (PNIO_TIMEOUT == io_err || PNIO_DISCONNECT == io_err) { + send_ret_ = OB_TIMEOUT; + } else { + send_ret_ = OB_RPC_SEND_ERROR; + RPC_LOG_RET(WARN, send_ret_, "pnio error", KP(buf), K(sz), K(io_err)); + } + } else if (NULL == buf || sz <= easy_head_size) { + send_ret_ = OB_ERR_UNEXPECTED; + RPC_LOG_RET(WARN, send_ret_, "response is null", KP(buf), K(sz), K(io_err)); + } else { + buf = buf + easy_head_size; + sz = sz - easy_head_size; // skip easy header sz_ = sz; + resp_ = reinterpret_cast(alloc(sz_)); + if (resp_ == NULL) { + send_ret_ = OB_ALLOCATE_MEMORY_FAILED; + RPC_LOG_RET(WARN, send_ret_, "alloc response buffer fail"); + } else { + memcpy(resp_, buf, sz_); + } } + int ret = send_ret_; + ATOMIC_STORE(&cond_, 1); + rk_futex_wake(&cond_, 1); return ret; } +int ObSyncRespCallback::wait() +{ + while(ATOMIC_LOAD(&cond_) == 0) { + rk_futex_wait(&cond_, 0, NULL); + } + return send_ret_; +} class ObPocSPAlloc: public rpc::frame::SPAlloc { @@ -42,7 +73,7 @@ private: ObRpcMemPool& pool_; }; -ObAsyncRespCallback* ObAsyncRespCallback::create(ObRpcMemPool& pool, UAsyncCB& ucb) +ObAsyncRespCallback* ObAsyncRespCallback::create(ObRpcMemPool& pool, UAsyncCB* ucb) { int ret = OB_SUCCESS; ObPocSPAlloc sp_alloc(pool); @@ -50,46 +81,142 @@ ObAsyncRespCallback* ObAsyncRespCallback::create(ObRpcMemPool& pool, UAsyncCB& u ObAsyncRespCallback* pcb = NULL; if (NULL == (pcb = (ObAsyncRespCallback*)pool.alloc(sizeof(ObAsyncRespCallback)))) { RPC_LOG(WARN, "alloc resp callback fail", K(ret)); - } else if (NULL == (cb = ucb.clone(sp_alloc))) { - RPC_LOG(WARN, "ucb.clone fail", K(ret)); } else { - new(pcb)ObAsyncRespCallback(pool, *cb); + if (NULL != ucb) { + if (NULL == (cb = ucb->clone(sp_alloc))) { + RPC_LOG(WARN, "ucb.clone fail", K(ret)); + } else { + cb->low_level_cb_ = pcb; + } + } + new(pcb)ObAsyncRespCallback(pool, cb); } return pcb; } -int ObAsyncRespCallback::handle_resp(int io_err, char* buf, int64_t sz) +int ObAsyncRespCallback::handle_resp(int io_err, const char* buf, int64_t sz) { int ret = OB_SUCCESS; ObRpcPacket* ret_pkt = NULL; - if (0 != io_err) { - ucb_.set_error(io_err); - ucb_.on_error(io_err); + if (buf != NULL && sz > easy_head_size) { + sz = sz - easy_head_size; + buf = buf + easy_head_size; + } else { + sz = 0; + buf = NULL; + } + if (ucb_ == NULL) { + // do nothing + } else if (0 != io_err) { + ucb_->set_error(io_err); + if (OB_SUCCESS != ucb_->on_error(io_err)) { + ucb_->on_timeout(); + } } else if (NULL == buf) { - ucb_.on_timeout(); + ucb_->on_timeout(); } else if (OB_FAIL(rpc_decode_ob_packet(pool_, buf, sz, ret_pkt))) { - ucb_.on_invalid(); + ucb_->on_invalid(); RPC_LOG(WARN, "rpc_decode_ob_packet fail", K(ret)); - } else if (OB_FAIL(ucb_.decode(ret_pkt))) { - ucb_.on_invalid(); + } else if (OB_FAIL(ucb_->decode(ret_pkt))) { + ucb_->on_invalid(); RPC_LOG(WARN, "ucb.decode fail", K(ret)); } else { int tmp_ret = OB_SUCCESS; - if (OB_SUCCESS != (tmp_ret = ucb_.process())) { + if (OB_SUCCESS != (tmp_ret = ucb_->process())) { RPC_LOG(WARN, "ucb.process fail", K(tmp_ret)); } } + pool_.destroy(); + return ret; +} + +void init_ucb(ObRpcProxy& proxy, UAsyncCB* ucb, const common::ObAddr& dest, int64_t send_ts, int64_t payload_sz) +{ + ucb->set_dst(dest); + ucb->set_tenant_id(proxy.get_tenant()); + ucb->set_timeout(proxy.timeout()); + ucb->set_send_ts(send_ts); + ucb->set_payload(payload_sz); +} +static easy_addr_t to_ez_addr(const ObAddr &addr) +{ + easy_addr_t ez; + memset(&ez, 0, sizeof (ez)); + if (addr.is_valid()) { + ez.port = (htons)(static_cast(addr.get_port())); + ez.cidx = 0; + if (addr.using_ipv4()) { + ez.family = AF_INET; + ez.u.addr = htonl(addr.get_ipv4()); + } else if (addr.using_unix()) { + ez.family = AF_UNIX; + snprintf(ez.u.unix_path, UNIX_PATH_MAX, "%s", addr.get_unix_path()); + } else { + ez.family = AF_INET6; + (void) addr.get_ipv6(&ez.u.addr6, sizeof(ez.u.addr6)); + } + } + return ez; +} + +int64_t ObPocClientStub::get_proxy_timeout(ObRpcProxy& proxy) { + return proxy.timeout(); +} +void ObPocClientStub::set_rcode(ObRpcProxy& proxy, const ObRpcResultCode& rcode) { + proxy.set_result_code(rcode); +} +void ObPocClientStub::set_handle(ObRpcProxy& proxy, Handle* handle, const ObRpcPacketCode& pcode, const ObRpcOpts& opts, bool is_stream_next, int64_t session_id) { + proxy.set_handle_attr(handle, pcode, opts, is_stream_next, session_id); +} +int ObPocClientStub::translate_io_error(int io_err) { + int ret = OB_SUCCESS; + if (PNIO_OK == io_err) { + } else if (ENOMEM == io_err || -ENOMEM == io_err) { + ret = OB_ALLOCATE_MEMORY_FAILED; + } else if (EINVAL == io_err || -EINVAL == io_err) { + ret = OB_INVALID_ARGUMENT; + } else { + ret = OB_ERR_UNEXPECTED; + } + return ret; +} + +int ObPocClientStub::log_user_error_and_warn(const ObRpcResultCode &rcode) const +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(OB_SUCCESS != rcode.rcode_)) { + FORWARD_USER_ERROR(rcode.rcode_, rcode.msg_); + } + for (int i = 0; OB_SUCC(ret) && i < rcode.warnings_.count(); ++i) { + const common::ObWarningBuffer::WarningItem warning_item = rcode.warnings_.at(i); + if (ObLogger::USER_WARN == warning_item.log_level_) { + FORWARD_USER_WARN(warning_item.code_, warning_item.msg_); + } else if (ObLogger::USER_NOTE == warning_item.log_level_) { + FORWARD_USER_NOTE(warning_item.code_, warning_item.msg_); + } else { + ret = common::OB_ERR_UNEXPECTED; + RPC_LOG(WARN, "unknown log type", K(ret)); + } + } return ret; } -void init_ucb(ObRpcProxy& proxy, UAsyncCB& ucb, const common::ObAddr& dest, int64_t send_ts, int64_t payload_sz) -{ - ucb.set_dst(dest); - ucb.set_tenant_id(proxy.get_tenant()); - ucb.set_timeout(proxy.timeout()); - ucb.set_send_ts(send_ts); - ucb.set_payload(payload_sz); +int ObPocClientStub::check_blacklist(const common::ObAddr& addr) { + int ret = OB_SUCCESS; + if(!addr.is_valid()) { + ret = common::OB_INVALID_ARGUMENT; + RPC_LOG(WARN, "invalid addr", K(ret), K(addr)); + } else { + easy_addr_t ez_addr = to_ez_addr(addr); + if (ObNetKeepAlive::get_instance().in_black(ez_addr)) { + ret = OB_RPC_POST_ERROR; + if (REACH_TIME_INTERVAL(1000000)) { + RPC_LOG(WARN, "address in blacklist", K(ret), K(addr)); + } + } + } + return ret; } -ObPocClientStub global_poc_client(global_poc_server.get_nio()); +ObPocClientStub global_poc_client; }; // end namespace obrpc }; // end namespace oceanbase diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.h b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.h index a7042c30d..e60587c0e 100644 --- a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.h +++ b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_proxy.h @@ -12,57 +12,79 @@ #ifndef OCEANBASE_OBRPC_OB_POC_RPC_PROXY_H_ #define OCEANBASE_OBRPC_OB_POC_RPC_PROXY_H_ -#include "rpc/obrpc/ob_nio_interface.h" #include "rpc/obrpc/ob_rpc_endec.h" #include "rpc/frame/ob_req_transport.h" #include "rpc/ob_request.h" +#include "rpc/obrpc/ob_poc_rpc_server.h" +extern "C" { +#include "rpc/pnio/interface/group.h" +} namespace oceanbase { namespace obrpc { -class ObSyncRespCallback: public IRespHandler +class ObSyncRespCallback { public: - ObSyncRespCallback(ObRpcMemPool& pool): pool_(pool), resp_(NULL), sz_(0) {} - virtual ~ObSyncRespCallback() {} + ObSyncRespCallback(ObRpcMemPool& pool): pkt_nio_cb_(NULL), pool_(pool), resp_(NULL), sz_(0), cond_(0), send_ret_(common::OB_SUCCESS){} + ~ObSyncRespCallback() {} void* alloc(int64_t sz) { return pool_.alloc(sz); } - int handle_resp(int io_err, char* buf, int64_t sz); - char* get_resp(int64_t& sz) { + int handle_resp(int io_err, const char* buf, int64_t sz); + int wait(); + const char* get_resp(int64_t& sz) { sz = sz_; return resp_; } + static int client_cb(void* arg, int io_err, const char* b, int64_t sz) { + int ret = ((ObSyncRespCallback*)arg)->handle_resp(io_err, b, sz); + return ret; + } private: + void* pkt_nio_cb_; ObRpcMemPool& pool_; char* resp_; int64_t sz_; + int cond_; + int send_ret_; }; typedef rpc::frame::ObReqTransport::AsyncCB UAsyncCB; -class ObAsyncRespCallback: public IRespHandler +class Handle; +class ObAsyncRespCallback { public: - ObAsyncRespCallback(ObRpcMemPool& pool, UAsyncCB& ucb): pool_(pool), ucb_(ucb) {} + ObAsyncRespCallback(ObRpcMemPool& pool, UAsyncCB* ucb): pkt_nio_cb_(NULL), pool_(pool), ucb_(ucb) {} ~ObAsyncRespCallback() {} - static ObAsyncRespCallback* create(ObRpcMemPool& pool, UAsyncCB& ucb); - UAsyncCB& get_ucb() { return ucb_; } - void* alloc(int64_t sz) { return pool_.alloc(sz); } - int handle_resp(int io_err, char* buf, int64_t sz); + static ObAsyncRespCallback* create(ObRpcMemPool& pool, UAsyncCB* ucb); + UAsyncCB* get_ucb() { return ucb_; } + int handle_resp(int io_err, const char* buf, int64_t sz); + static int client_cb(void* arg, int io_error, const char* b, int64_t sz) { + int ret = common::OB_SUCCESS; + if (arg != NULL) { + ret = ((ObAsyncRespCallback*)arg)->handle_resp(io_error, b, sz); + } else { + RPC_LOG(WARN, "async rpc callback is null, it is unexpected", KP(b), K(sz)); + } + return ret; + } + private: + void* pkt_nio_cb_; ObRpcMemPool& pool_; - UAsyncCB& ucb_; + UAsyncCB* ucb_; }; -void init_ucb(ObRpcProxy& proxy, UAsyncCB& ucb, const common::ObAddr& addr, int64_t send_ts, int64_t payload_sz); +void init_ucb(ObRpcProxy& proxy, UAsyncCB* ucb, const common::ObAddr& addr, int64_t send_ts, int64_t payload_sz); template - void set_ucb_args(UCB& ucb, const Input& args) + void set_ucb_args(UCB* ucb, const Input& args) { - ucb.set_args(args); + ucb->set_args(args); } template - void set_ucb_args(UAsyncCB& ucb, const NoneType& none) + void set_ucb_args(UAsyncCB* ucb, const NoneType& none) { UNUSED(ucb); UNUSED(none); @@ -71,55 +93,119 @@ template class ObPocClientStub { public: - ObPocClientStub(ObINio& nio): nio_(nio) {} + ObPocClientStub() {} ~ObPocClientStub() {} + static int64_t get_proxy_timeout(ObRpcProxy& proxy); + static void set_rcode(ObRpcProxy& proxy, const ObRpcResultCode& rcode); + static int check_blacklist(const common::ObAddr& addr); + static void set_handle(ObRpcProxy& proxy, Handle* handle, const ObRpcPacketCode& pcode, const ObRpcOpts& opts, bool is_stream_next, int64_t session_id); + static uint8_t balance_assign_tidx() + { + static uint8_t s_rpc_tidx CACHE_ALIGNED; + return ATOMIC_FAA(&s_rpc_tidx, 1); + } + static int translate_io_error(int io_err); template - int send(ObRpcProxy& proxy, const common::ObAddr& addr, ObRpcPacketCode pcode, const Input& args, Output& out, const ObRpcOpts& opts) { + int send(ObRpcProxy& proxy, const common::ObAddr& addr, ObRpcPacketCode pcode, const Input& args, Output& out, Handle* handle, const ObRpcOpts& opts) { + int sys_err = 0; int ret = common::OB_SUCCESS; - ObRpcMemPool pool; + const int64_t start_ts = common::ObTimeUtility::current_time(); + int64_t src_tenant_id = ob_get_tenant_id(); + auto &set = obrpc::ObRpcPacketSet::instance(); + const char* pcode_label = set.name_of_idx(set.idx_of_pcode(pcode)); + ObRpcMemPool pool(src_tenant_id, pcode_label); ObSyncRespCallback cb(pool); char* req = NULL; int64_t req_sz = 0; - char* resp = NULL; + const char* resp = NULL; int64_t resp_sz = 0; - int resp_ret = common::OB_SUCCESS; - if (OB_FAIL(rpc_encode_req(proxy, pool, pcode, args, opts, req, req_sz))) { + ObRpcPacket resp_pkt; + ObRpcResultCode rcode; + sockaddr_in sock_addr; + uint8_t thread_id = balance_assign_tidx(); + if (OB_FAIL(rpc_encode_req(proxy, pool, pcode, args, opts, req, req_sz, false))) { RPC_LOG(WARN, "rpc encode req fail", K(ret)); - } else if (OB_FAIL(nio_.post(addr, req, req_sz, &cb))) { - RPC_LOG(WARN, "nio post fail", K(ret)); + } else if(OB_FAIL(check_blacklist(addr))) { + RPC_LOG(WARN, "check_blacklist failed", K(ret)); + } else if (0 != (sys_err = pn_send( + (1ULL<<32) + thread_id, + obaddr2sockaddr(&sock_addr, addr), + req, + req_sz, + static_cast(set.idx_of_pcode(pcode)), + start_ts + get_proxy_timeout(proxy), + ObSyncRespCallback::client_cb, + &cb))) { + ret = translate_io_error(sys_err); + RPC_LOG(WARN, "pn_send fail", K(sys_err), K(ret)); + } else if (OB_FAIL(cb.wait())) { + RPC_LOG(WARN, "sync rpc execute fail", K(ret), K(addr)); } else if (NULL == (resp = cb.get_resp(resp_sz))) { ret = common::OB_ERR_UNEXPECTED; - RPC_LOG(WARN, "get NULL response buffer", K(ret)); - } else if (OB_FAIL(rpc_decode_resp(resp, resp_sz, out))) { - RPC_LOG(WARN, "rpc decode response fail", K(ret)); - } else { - if (common::OB_SUCCESS != resp_ret) { - ret = resp_ret; - RPC_LOG(WARN, "rpc execute fail", K(ret)); + RPC_LOG(WARN, "sync rpc execute success but resp is null", K(ret), K(addr)); + } else if (OB_FAIL(rpc_decode_resp(resp, resp_sz, out, resp_pkt, rcode))) { + RPC_LOG(WARN, "rpc decode response fail", KP(resp), K(resp_sz), K(ret)); + } + if (rcode.rcode_ != OB_DESERIALIZE_ERROR) { + int wb_ret = OB_SUCCESS; + if (common::OB_SUCCESS != (wb_ret = log_user_error_and_warn(rcode))) { + RPC_OBRPC_LOG(WARN, "fail to log user error and warn", K(ret), K(wb_ret), K((rcode))); + } + set_rcode(proxy, rcode); + if (OB_SUCC(ret) && handle) { + set_handle(proxy, handle, pcode, opts, resp_pkt.is_stream_next(), resp_pkt.get_session_id()); } } return ret; } template - int post(ObRpcProxy& proxy, const common::ObAddr& addr, ObRpcPacketCode pcode, const Input& args, UCB& ucb, const ObRpcOpts& opts) { + int post(ObRpcProxy& proxy, const common::ObAddr& addr, ObRpcPacketCode pcode, const Input& args, UCB* ucb, const ObRpcOpts& opts) { + int sys_err = 0; int ret = common::OB_SUCCESS; const int64_t start_ts = common::ObTimeUtility::current_time(); ObRpcMemPool* pool = NULL; - if (NULL == (pool = ObRpcMemPool::create(sizeof(ObAsyncRespCallback) + sizeof(UCB)))) { + uint8_t thread_id = balance_assign_tidx(); + int64_t src_tenant_id = ob_get_tenant_id(); +#ifndef PERF_MODE + const int init_alloc_sz = 0; +#else + const int init_alloc_sz = 400<<10; +#endif + auto &set = obrpc::ObRpcPacketSet::instance(); + const char* pcode_label = set.name_of_idx(set.idx_of_pcode(pcode)); + if (NULL == (pool = ObRpcMemPool::create(src_tenant_id, pcode_label, init_alloc_sz))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; } else { ObAsyncRespCallback* cb = NULL; char* req = NULL; int64_t req_sz = 0; - if (OB_FAIL(rpc_encode_req(proxy, *pool, pcode, args, opts, req, req_sz))) { + if (OB_FAIL(rpc_encode_req(proxy, *pool, pcode, args, opts, req, req_sz, NULL == ucb))) { RPC_LOG(WARN, "rpc encode req fail", K(ret)); + } else if(OB_FAIL(check_blacklist(addr))) { + RPC_LOG(WARN, "check_blacklist failed", K(addr)); } else if (NULL == (cb = ObAsyncRespCallback::create(*pool, ucb))) { ret = common::OB_ALLOCATE_MEMORY_FAILED; } else { - init_ucb(proxy, cb->get_ucb(), addr, start_ts, req_sz); - set_ucb_args(ucb, args); - if (OB_FAIL(nio_.post(addr, req, req_sz, cb))) { - RPC_LOG(WARN, "nio post fail", K(ret)); + auto newcb = reinterpret_cast(cb->get_ucb()); + if (newcb) { + set_ucb_args(newcb, args); + init_ucb(proxy, cb->get_ucb(), addr, start_ts, req_sz); + } + } + if (OB_SUCC(ret)) { + sockaddr_in sock_addr; + if (0 != (sys_err = pn_send( + (1ULL<<32) + thread_id, + obaddr2sockaddr(&sock_addr, addr), + req, + req_sz, + static_cast(set.idx_of_pcode(pcode)), + start_ts + get_proxy_timeout(proxy), + ObAsyncRespCallback::client_cb, + cb) + )) { + ret = translate_io_error(sys_err); + RPC_LOG(WARN, "pn_send fail", K(sys_err), K(ret)); } } } @@ -129,12 +215,20 @@ public: return ret; } -private: - ObINio& nio_; + static struct sockaddr_in* obaddr2sockaddr(struct sockaddr_in *sin, const ObAddr& addr) + { + if (NULL != sin) { + sin->sin_port = (uint16_t)htons((uint16_t)(addr.get_port())); + sin->sin_addr.s_addr = htonl(addr.get_ipv4()); + sin->sin_family = AF_INET; + } + return sin; + } + int log_user_error_and_warn(const ObRpcResultCode &rcode) const; }; extern ObPocClientStub global_poc_client; -#define POC_RPC_INTERCEPT(func, args...) if (transport_impl_ == rpc::ObRequest::TRANSPORT_PROTO_POC) return global_poc_client.func(*this, args); +#define POC_RPC_INTERCEPT(func, args...) if (transport_impl_ == rpc::ObRequest::TRANSPORT_PROTO_POC && global_poc_server.client_use_pkt_nio()) return global_poc_client.func(*this, args); }; // end namespace obrpc }; // end namespace oceanbase diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_request_operator.cpp b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_request_operator.cpp index 35ee70b96..0a32a3deb 100644 --- a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_request_operator.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_request_operator.cpp @@ -31,6 +31,8 @@ void* ObPocRpcRequestOperator::alloc_response_buffer(ObRequest* req, int64_t siz void ObPocRpcRequestOperator::response_result(ObRequest* req, obrpc::ObRpcPacket* pkt) { get_poc_handle_context(req)->resp(pkt); + get_poc_handle_context(req)->destroy(); + } ObAddr ObPocRpcRequestOperator::get_peer(const ObRequest* req) diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.cpp b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.cpp index 53918ecc5..6aa46b1e5 100644 --- a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.cpp @@ -11,13 +11,27 @@ */ #include "rpc/obrpc/ob_poc_rpc_server.h" +#include "lib/oblog/ob_log_module.h" +#include "rpc/obrpc/ob_net_keepalive.h" + +#define rk_log_macro(level, ret, format, ...) _OB_LOG_RET(level, ret, "PNIO " format, ##__VA_ARGS__) +#include "lib/lock/ob_futex.h" +extern "C" { +#include "rpc/pnio/interface/group.h" +}; #include "rpc/obrpc/ob_rpc_endec.h" +#define cfgi(k, v) atoi(getenv(k)?:v) namespace oceanbase { namespace obrpc { +extern const int easy_head_size; ObPocRpcServer global_poc_server; +ObListener* global_ob_listener; +bool __attribute__((weak)) enable_pkt_nio() { + return false; +} }; // end namespace obrpc }; // end namespace oceanbase @@ -25,52 +39,167 @@ using namespace oceanbase::common; using namespace oceanbase::obrpc; using namespace oceanbase::rpc; -ObRequest* ObPocServerHandleContext::create(ObINio& nio, int64_t resp_id, char* buf, int64_t sz) +frame::ObReqDeliver* global_deliver; +int ObPocServerHandleContext::create(int64_t resp_id, const char* buf, int64_t sz, ObRequest*& req) { int ret = OB_SUCCESS; - ObRequest* req = NULL; ObPocServerHandleContext* ctx = NULL; - ObRpcMemPool* pool = ObRpcMemPool::create(sizeof(ObPocServerHandleContext) + sizeof(ObRequest)); - if (NULL != pool) { - ctx = new(pool + 1)ObPocServerHandleContext(nio, *pool, resp_id); - req = new(ctx + 1)ObRequest(ObRequest::OB_RPC, 1); - ObRpcPacket* pkt = NULL; - if (OB_FAIL(rpc_decode_ob_packet(*pool, buf, sz, pkt))) { - RPC_LOG(ERROR, "decode packet fail", K(ret)); + ObRpcPacket tmp_pkt; +#ifndef PERF_MODE + const int64_t alloc_payload_sz = sz; +#else + const int64_t alloc_payload_sz = 0; +#endif + if (OB_FAIL(tmp_pkt.decode(buf, sz))) { + RPC_LOG(ERROR, "decode packet fail", K(ret)); + } else { + obrpc::ObRpcPacketCode pcode = tmp_pkt.get_pcode(); + auto &set = obrpc::ObRpcPacketSet::instance(); + const char* pcode_label = set.name_of_idx(set.idx_of_pcode(pcode)); + const int64_t pool_size = sizeof(ObPocServerHandleContext) + sizeof(ObRequest) + sizeof(ObRpcPacket) + alloc_payload_sz; + ObRpcMemPool* pool = ObRpcMemPool::create(tmp_pkt.get_tenant_id(), pcode_label, pool_size); + void *temp = NULL; + if (OB_ISNULL(pool)) { + ret = common::OB_ALLOCATE_MEMORY_FAILED; + RPC_LOG(WARN, "create memory pool failed", K(ret)); + } else if (OB_ISNULL(temp = pool->alloc(sizeof(ObPocServerHandleContext) + sizeof(ObRequest)))){ + ret = common::OB_ALLOCATE_MEMORY_FAILED; + RPC_LOG(WARN, "pool allocate memory failed", K(ret)); } else { - req->set_server_handle_context(ctx); - req->set_packet(pkt); + ctx = new(temp)ObPocServerHandleContext(*pool, resp_id); + req = new(ctx + 1)ObRequest(ObRequest::OB_RPC, ObRequest::TRANSPORT_PROTO_POC); + ObRpcPacket* pkt = (ObRpcPacket*)pool->alloc(sizeof(ObRpcPacket) + alloc_payload_sz); + if (NULL == pkt) { + RPC_LOG(WARN, "pool allocate rpc packet memory failed", K(ret)); + ret = common::OB_ALLOCATE_MEMORY_FAILED; + } else { + MEMCPY(reinterpret_cast(pkt), reinterpret_cast(&tmp_pkt), sizeof(ObRpcPacket)); + const char* packet_data = NULL; + if (alloc_payload_sz > 0) { + packet_data = reinterpret_cast(pkt + 1); + MEMCPY(const_cast(packet_data), tmp_pkt.get_cdata(), tmp_pkt.get_clen()); + } else { + packet_data = tmp_pkt.get_cdata(); + } + int64_t receive_ts = ObTimeUtility::current_time(); + pkt->set_receive_ts(receive_ts); + pkt->set_content(packet_data, tmp_pkt.get_clen()); + req->set_server_handle_context(ctx); + req->set_packet(pkt); + req->set_receive_timestamp(pkt->get_receive_ts()); + req->set_request_arrival_time(pkt->get_receive_ts()); + req->set_arrival_push_diff(common::ObTimeUtility::current_time()); + + const int64_t fly_ts = receive_ts - pkt->get_timestamp(); + if (fly_ts > oceanbase::common::OB_MAX_PACKET_FLY_TS && TC_REACH_TIME_INTERVAL(100 * 1000)) { + RPC_LOG(WARN, "PNIO packet wait too much time between proxy and server_cb", "pcode", pkt->get_pcode(), + "fly_ts", fly_ts, "send_timestamp", pkt->get_timestamp()); + } + } } } - return req; + return ret; } void ObPocServerHandleContext::resp(ObRpcPacket* pkt) { int ret = OB_SUCCESS; + int sys_err = 0; char* buf = NULL; int64_t sz = 0; - if (OB_FAIL(rpc_encode_ob_packet(pool_, pkt, buf, sz))) { + if (NULL == pkt) { + RPC_LOG(WARN, "resp pkt is null", K(pkt)); + } else if (OB_FAIL(rpc_encode_ob_packet(pool_, pkt, buf, sz))) { RPC_LOG(WARN, "rpc_encode_ob_packet fail", K(pkt)); buf = NULL; sz = 0; } - nio_.resp(resp_id_, buf, sz); + if ((sys_err = pn_resp(resp_id_, buf, sz)) != 0) { + RPC_LOG(WARN, "pn_resp fail", K(resp_id_), K(sys_err)); + } } -int ObPocRpcServer::start(int port, frame::ObReqDeliver* deliver) +int serve_cb(int grp, const char* b, int64_t sz, uint64_t resp_id) { int ret = OB_SUCCESS; - uint64_t POC_RPC_MAGIC = 0; - server_req_handler_.init(deliver, &nio_); - int accept_queue_fd = listener_.regist(POC_RPC_MAGIC, 0, NULL); - nio_.init(&server_req_handler_, accept_queue_fd); - if (OB_FAIL( nio_.start())) { - RPC_LOG(ERROR, "poc nio start fail", K(ret)); - } else if (OB_FAIL(listener_.start())) { - RPC_LOG(ERROR, "listen fail", K(ret), K(port)); + int tmp_ret = OB_SUCCESS; + if (NULL == b || sz <= easy_head_size) { + tmp_ret = OB_INVALID_DATA; + RPC_LOG(WARN, "rpc request is invalid", K(tmp_ret), K(b), K(sz)); } else { - RPC_LOG(INFO, "poc rpc server listen succ"); + b = b + easy_head_size; + sz = sz - easy_head_size; + ObRequest* req = NULL; + if (OB_TMP_FAIL(ObPocServerHandleContext::create(resp_id, b, sz, req))) { + RPC_LOG(WARN, "created req is null", K(tmp_ret), K(sz), K(resp_id)); + } else { + global_deliver->deliver(*req); + } + } + if (OB_SUCCESS != tmp_ret) { + int sys_err = 0; + if ((sys_err = pn_resp(resp_id, NULL, 0)) != 0) { + RPC_LOG(WARN, "pn_resp fail", K(resp_id), K(sys_err)); + } } return ret; } + +int ObPocRpcServer::start(int port, int net_thread_count, frame::ObReqDeliver* deliver) +{ + int ret = OB_SUCCESS; + // init pkt-nio framework + int lfd = -1; + int grp = 1; + if ((lfd = pn_listen(port, serve_cb)) == -1) { + ret = OB_IO_ERROR; + RPC_LOG(ERROR, "pn_listen failed", K(ret)); + } else { + global_deliver = deliver; + int count = pn_provision(lfd, grp, net_thread_count); + if (count != net_thread_count) { + RPC_LOG(WARN, "pn_provision error", K(count), K(net_thread_count)); + } + has_start_ = true; + } + return ret; +} +int ObPocRpcServer::update_tcp_keepalive_params(int64_t user_timeout) { + int ret = OB_SUCCESS; + if (pn_set_keepalive_timeout(user_timeout) != user_timeout) { + ret = OB_INVALID_ARGUMENT; + RPC_LOG(WARN, "invalid user_timeout", K(ret), K(user_timeout)); + } + return ret; +} + +bool ObPocRpcServer::client_use_pkt_nio() { + return has_start() && enable_pkt_nio(); +} + +extern "C" { +void* pkt_nio_malloc(int64_t sz, const char* label) { + ObMemAttr attr(OB_SERVER_TENANT_ID, label, ObCtxIds::PKT_NIO); + return oceanbase::common::ob_malloc(sz, attr); +} +void pkt_nio_free(void *ptr) { + oceanbase::common::ob_free(ptr); +} +bool server_in_black(struct sockaddr* sa) { + easy_addr_t ez_addr; + easy_inet_atoe(sa, &ez_addr); + return ObNetKeepAlive::get_instance().in_black(ez_addr); +} +int dispatch_to_ob_listener(int accept_fd) { + int ret = -1; + if (oceanbase::obrpc::global_ob_listener) { + ret = oceanbase::obrpc::global_ob_listener->do_one_event(accept_fd); + } + return ret; +} +#define PKT_NIO_MALLOC(sz, label) pkt_nio_malloc(sz, label) +#define PKT_NIO_FREE(ptr) pkt_nio_free(ptr) +#define SERVER_IN_BLACK(sa) server_in_black(sa) +#define DISPATCH_EXTERNAL(accept_fd) dispatch_to_ob_listener(accept_fd) +#include "rpc/pnio/pkt-nio.c" +}; diff --git a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.h b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.h index 87b75fe6b..bf78c7f4f 100644 --- a/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.h +++ b/deps/oblib/src/rpc/obrpc/ob_poc_rpc_server.h @@ -12,7 +12,6 @@ #ifndef OCEANBASE_OBRPC_OB_POC_RPC_SERVER_H_ #define OCEANBASE_OBRPC_OB_POC_RPC_SERVER_H_ -#include "rpc/obrpc/ob_poc_nio.h" #include "rpc/obrpc/ob_rpc_mem_pool.h" #include "rpc/ob_request.h" #include "rpc/frame/ob_req_deliver.h" @@ -26,56 +25,39 @@ namespace obrpc class ObPocServerHandleContext { public: - ObPocServerHandleContext(ObINio& nio, ObRpcMemPool& pool, uint64_t resp_id): - nio_(nio), pool_(pool), resp_id_(resp_id) + ObPocServerHandleContext( ObRpcMemPool& pool, uint64_t resp_id): + pool_(pool), resp_id_(resp_id) {} ~ObPocServerHandleContext() { destroy(); } - static rpc::ObRequest* create(ObINio& nio, int64_t resp_id, char* buf, int64_t sz); + static int create(int64_t resp_id, const char* buf, int64_t sz, rpc::ObRequest*& req); void destroy() { pool_.destroy(); } void resp(ObRpcPacket* pkt); void* alloc(int64_t sz) { return pool_.alloc(sz); } private: - ObINio& nio_; ObRpcMemPool& pool_; - int64_t resp_id_; + uint64_t resp_id_; }; -class ObPocServerReqHandler: public IReqHandler -{ -public: - ObPocServerReqHandler(): deliver_(NULL), nio_(NULL) {} - ~ObPocServerReqHandler() {} - void init(rpc::frame::ObReqDeliver* deliver, ObINio* nio) { - deliver_ = deliver; - nio_ = nio; - } - int handle_req(int64_t resp_id, char* buf, int64_t sz) { - rpc::ObRequest* req = ObPocServerHandleContext::create(*nio_, resp_id, buf, sz); - return deliver_->deliver(*req); - } -private: - rpc::frame::ObReqDeliver* deliver_; - ObINio* nio_; -}; class ObPocRpcServer { public: - ObPocRpcServer() {} + ObPocRpcServer() : has_start_(false){} ~ObPocRpcServer() {} - int start(int port, rpc::frame::ObReqDeliver* deliver); + int start(int port, int net_thread_count, rpc::frame::ObReqDeliver* deliver); void stop() {} - ObPocNio& get_nio() { return nio_; } + bool has_start() {return has_start_;} + int update_tcp_keepalive_params(int64_t user_timeout); + bool client_use_pkt_nio(); private: - ObPocNio nio_; - ObListener listener_; - ObPocServerReqHandler server_req_handler_; + bool has_start_; }; extern ObPocRpcServer global_poc_server; +extern ObListener* global_ob_listener; }; // end namespace obrpc }; // end namespace oceanbase diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_endec.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_endec.cpp index e794c4d0b..733b4812f 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_endec.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_endec.cpp @@ -71,7 +71,7 @@ int init_packet(ObRpcProxy& proxy, ObRpcPacket& pkt, ObRpcPacketCode pcode, cons return proxy.init_pkt(&pkt, pcode, opts, unneed_response); } -int rpc_decode_ob_packet(ObRpcMemPool& pool, char* buf, int64_t sz, ObRpcPacket*& ret_pkt) +int rpc_decode_ob_packet(ObRpcMemPool& pool, const char* buf, int64_t sz, ObRpcPacket*& ret_pkt) { int ret = common::OB_SUCCESS; ObRpcPacket* pkt = (ObRpcPacket*)pool.alloc(sizeof(ObRpcPacket)); diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_endec.h b/deps/oblib/src/rpc/obrpc/ob_rpc_endec.h index e414a937c..74fac4d85 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_endec.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_endec.h @@ -28,13 +28,30 @@ int init_packet(ObRpcProxy& proxy, ObRpcPacket& pkt, ObRpcPacketCode pcode, cons const bool unneed_response); template - int rpc_encode_req(ObRpcProxy& proxy, ObRpcMemPool& pool, ObRpcPacketCode pcode, const T& args, const ObRpcOpts& opts, char*& req, int64_t& req_sz) + int rpc_encode_req( + ObRpcProxy& proxy, + ObRpcMemPool& pool, + ObRpcPacketCode pcode, + const T& args, + const ObRpcOpts& opts, + char*& req, + int64_t& req_sz, + bool unneed_resp, + bool is_next = false, + bool is_last = false, + int64_t session_id = 0 + ) { int ret = common::OB_SUCCESS; ObRpcPacket pkt; const int64_t header_sz = pkt.get_header_size(); const int64_t payload_sz = calc_extra_payload_size() + common::serialization::encoded_length(args); - char* header_buf = (char*)pool.alloc(header_sz + payload_sz); +#ifdef PERF_MODE + const int64_t reserve_bytes_for_pnio = 200; +#else + const int64_t reserve_bytes_for_pnio = 0; +#endif + char* header_buf = (char*)pool.alloc(reserve_bytes_for_pnio + header_sz + payload_sz) + reserve_bytes_for_pnio; char* payload_buf = header_buf + header_sz; int64_t pos = 0; UNIS_VERSION_GUARD(opts.unis_version_); @@ -53,9 +70,20 @@ template } else { int64_t header_pos = 0; pkt.set_content(payload_buf, payload_sz); - if (OB_FAIL(init_packet(proxy, pkt, pcode, opts, false))) { + if (OB_FAIL(init_packet(proxy, pkt, pcode, opts, unneed_resp))) { RPC_OBRPC_LOG(WARN, "init packet fail", K(ret)); - } else if (OB_FAIL(pkt.encode_header(header_buf, header_sz, header_pos))) { + } else { + if (is_next) { + pkt.set_stream_next(); + } + if (is_last) { + pkt.set_stream_last(); + } + if (session_id) { + pkt.set_session_id(session_id); + } + } + if (OB_FAIL(pkt.encode_header(header_buf, header_sz, header_pos))) { RPC_OBRPC_LOG(WARN, "encode header fail", K(ret)); } else { req = header_buf; @@ -66,23 +94,23 @@ template } template - int rpc_decode_resp(char* resp_buf, int64_t resp_sz, T& result) +int rpc_decode_resp(const char* resp_buf, int64_t resp_sz, T& result, ObRpcPacket &pkt, ObRpcResultCode &rcode) { int ret = common::OB_SUCCESS; - ObRpcPacket pkt; int64_t pos = 0; if (OB_FAIL(pkt.decode(resp_buf, resp_sz))) { RPC_OBRPC_LOG(WARN, "decode packet fail", K(ret)); } else { - ObRpcResultCode rcode; UNIS_VERSION_GUARD(pkt.get_unis_version()); - if (OB_FAIL(rcode.deserialize(resp_buf, resp_sz, pos))) { + const char* payload = pkt.get_cdata(); + int64_t limit = pkt.get_clen(); + if (OB_FAIL(rcode.deserialize(payload, limit, pos))) { + rcode.rcode_ = common::OB_DESERIALIZE_ERROR; RPC_OBRPC_LOG(WARN, "deserialize result code fail", K(ret)); } else { if (rcode.rcode_ != common::OB_SUCCESS) { ret = rcode.rcode_; - RPC_OBRPC_LOG(WARN, "execute rpc fail", K(ret)); - } else if (OB_FAIL(common::serialization::decode(resp_buf, resp_sz, pos, result))) { + } else if (OB_FAIL(common::serialization::decode(payload, limit, pos, result))) { RPC_OBRPC_LOG(WARN, "deserialize result fail", K(ret)); } else { ret = rcode.rcode_; @@ -92,7 +120,7 @@ template return ret; } -int rpc_decode_ob_packet(ObRpcMemPool& pool, char* buf, int64_t sz, ObRpcPacket*& ret_pkt); +int rpc_decode_ob_packet(ObRpcMemPool& pool, const char* buf, int64_t sz, ObRpcPacket*& ret_pkt); int rpc_encode_ob_packet(ObRpcMemPool& pool, ObRpcPacket* pkt, char*& buf, int64_t& sz); }; // end namespace obrpc diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.cpp index ced63cf97..3ed98ba6c 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.cpp @@ -37,25 +37,49 @@ struct ObRpcMemPool::Page int64_t cur_; char base_[]; }; -static void* rpc_mem_pool_direct_alloc(int64_t sz) { return common::ob_malloc(sz, common::ObModIds::OB_COMMON_NETWORK); } +static void* rpc_mem_pool_direct_alloc(int64_t tenant_id, const char* label, int64_t sz) { + if (OB_INVALID_TENANT_ID == tenant_id) { + tenant_id = OB_SERVER_TENANT_ID; + } + ObMemAttr attr(tenant_id, label, common::ObCtxIds::RPC_CTX_ID); + auto* ret = common::ob_malloc(sz, attr); + if (OB_ISNULL(ret) + && OB_ISNULL(lib::ObMallocAllocator::get_instance()->get_tenant_ctx_allocator(tenant_id, common::ObCtxIds::RPC_CTX_ID))) { + attr.tenant_id_ = OB_SERVER_TENANT_ID; + ret = common::ob_malloc(sz, attr); + } + return ret; +} static void rpc_mem_pool_direct_free(void* p) { common::ob_free(p); } -static ObRpcMemPool::Page* rpc_mem_pool_create_page(int64_t sz) { +static ObRpcMemPool::Page* rpc_mem_pool_create_page(int64_t tenant_id, const char* label, int64_t sz) { int64_t alloc_sz = std::max(sizeof(ObRpcMemPool::Page) + sz, (uint64_t)ObRpcMemPool::RPC_POOL_PAGE_SIZE); - ObRpcMemPool::Page* page = (typeof(page))rpc_mem_pool_direct_alloc(alloc_sz); + ObRpcMemPool::Page* page = (typeof(page))rpc_mem_pool_direct_alloc(tenant_id, label, alloc_sz); if (OB_ISNULL(page)) { - LOG_ERROR_RET(common::OB_ALLOCATE_MEMORY_FAILED, "rpc memory pool alloc memory failed", K(sz), K(alloc_sz)); + LOG_WARN_RET(common::OB_ALLOCATE_MEMORY_FAILED, "rpc memory pool alloc memory failed", K(sz), K(alloc_sz)); } else { new(page)ObRpcMemPool::Page(alloc_sz); } return page; } +static void rpc_mem_pool_destroy_page(ObRpcMemPool::Page* page) { + if (OB_NOT_NULL(page)) { + page->ObRpcMemPool::Page::~Page(); + common::ob_free(page); + } +} -ObRpcMemPool* ObRpcMemPool::create(int64_t req_sz) +ObRpcMemPool* ObRpcMemPool::create(int64_t tenant_id, const char* label, int64_t req_sz) { - Page* page = rpc_mem_pool_create_page(req_sz + sizeof(ObRpcMemPool)); - ObRpcMemPool* pool = (typeof(pool))page->alloc(sizeof(ObRpcMemPool)); - new(pool)ObRpcMemPool(); // can not be null - pool->add_page(page); + Page* page = nullptr; + ObRpcMemPool* pool = nullptr; + if (OB_NOT_NULL(page = rpc_mem_pool_create_page(tenant_id, label, req_sz + sizeof(ObRpcMemPool)))) { + if (OB_NOT_NULL(pool = (typeof(pool))page->alloc(sizeof(ObRpcMemPool)))) { + new(pool)ObRpcMemPool(tenant_id, label); // can not be null + pool->add_page(page); + } else { + rpc_mem_pool_destroy_page(page); + } + } return pool; } @@ -64,7 +88,7 @@ void* ObRpcMemPool::alloc(int64_t sz) void* ret = NULL; Page* page = NULL; if (NULL != last_ && NULL != (ret = last_->alloc(sz))) { - } else if (NULL == (page = rpc_mem_pool_create_page(sz))) { + } else if (NULL == (page = rpc_mem_pool_create_page(tenant_id_, mem_label_, sz))) { } else { ret = page->alloc(sz); add_page(page); diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.h b/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.h index 54b8e4d17..e75d4d18f 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_mem_pool.h @@ -21,11 +21,12 @@ namespace obrpc class ObRpcMemPool { public: - enum { RPC_POOL_PAGE_SIZE = 1<<16 }; + enum { RPC_POOL_PAGE_SIZE = (1<<14) - 128}; struct Page; - ObRpcMemPool(): last_(NULL) {} + explicit ObRpcMemPool(): last_(NULL), tenant_id_(OB_INVALID_TENANT_ID), mem_label_("RpcDefault") {} + explicit ObRpcMemPool(int64_t tenant_id, const char* label): last_(NULL), tenant_id_(tenant_id), mem_label_(label) {} ~ObRpcMemPool() { destroy(); } - static ObRpcMemPool* create(int64_t sz); + static ObRpcMemPool* create(int64_t tenant_id, const char* label, int64_t req_sz); void* alloc(int64_t sz); void reuse(); void destroy(); @@ -33,6 +34,8 @@ private: void add_page(Page* page); private: Page* last_; + int64_t tenant_id_; + const char* mem_label_; }; }; // end namespace obrpc diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_opts.h b/deps/oblib/src/rpc/obrpc/ob_rpc_opts.h index fe3421da8..c1482d8bc 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_opts.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_opts.h @@ -26,7 +26,6 @@ struct ObRpcOpts ObRpcPriority pr_; // priority of this RPC packet mutable bool is_stream_; // is this RPC packet a stream packet? mutable bool is_stream_last_; // is this RPC packet the last packet in stream? - uint64_t unis_version_; common::ObAddr local_addr_; common::ObString ssl_invited_nodes_; @@ -38,7 +37,6 @@ struct ObRpcOpts local_addr_(), ssl_invited_nodes_() { - unis_version_ = lib::get_unis_global_compat_version(); } }; diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp index d8e755b87..44a2b906f 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp @@ -318,7 +318,7 @@ int ObRpcProcessorBase::do_response(const Response &rsp) if (rsp.bad_routing_) { packet->set_bad_routing(); } - packet->set_unis_version(unis_version_); + packet->set_unis_version(0); packet->calc_checksum(); opacket_size = packet->get_clen() + packet->get_header_size() + common::OB_NET_HEADER_LENGTH; EVENT_INC(RPC_PACKET_OUT); diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h index 4f47c4e4c..c58bddc2a 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h @@ -36,8 +36,7 @@ public: : rpc_pkt_(NULL), sh_(NULL), sc_(NULL), is_stream_(false), is_stream_end_(false), bad_routing_(false), preserve_recv_data_(false), preserved_buf_(NULL), uncompressed_buf_(NULL), using_buffer_(NULL), send_timestamp_(0), pkt_size_(0), tenant_id_(0), - result_compress_type_(common::INVALID_COMPRESSOR), - unis_version_(lib::get_unis_global_compat_version()) + result_compress_type_(common::INVALID_COMPRESSOR) {} virtual ~ObRpcProcessorBase(); @@ -172,7 +171,6 @@ protected: int64_t tenant_id_; // compress the result if not INVALID_COMPRESSOR common::ObCompressorType result_compress_type_; - const uint64_t unis_version_; private: DISALLOW_COPY_AND_ASSIGN(ObRpcProcessorBase); }; // end of class ObRpcProcessorBase diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.cpp index 2a055dcb9..263aed013 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.cpp @@ -68,101 +68,14 @@ int ObRpcProxy::init(const ObReqTransport *transport, src_cluster_id_ = src_cluster_id; dst_ = dst; init_ = true; - } - - return ret; -} - -int ObRpcProxy::rpc_call(ObRpcPacketCode pcode, Handle *handle, const ObRpcOpts &opts) -{ - POC_RPC_INTERCEPT(send, dst_, pcode, None, None, opts); - int ret = OB_E(EventTable::EN_6) OB_SUCCESS; - const int64_t start_ts = ObTimeUtility::current_time(); - rpc::RpcStatPiece piece; - - if (OB_FAIL(ret)) { - } else if (!active_) { - ret = OB_INACTIVE_RPC_PROXY; - LOG_WARN("Rpc proxy is inactive", K(ret)); - } - int64_t pos = 0; - const int64_t payload = calc_payload_size(0); - ObReqTransport::Request req; - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(transport_)) { - ret = OB_NOT_INIT; - LOG_WARN("Rpc proxy transport is not inited", K(ret)); - } else if (OB_UNLIKELY(payload > OB_MAX_RPC_PACKET_LENGTH)) { - ret = OB_RPC_PACKET_TOO_LONG; - LOG_WARN("obrpc packet payload execced its limit", - K(ret), K(payload), "limit", OB_MAX_RPC_PACKET_LENGTH); - } else if (OB_FAIL(create_request(pcode, *transport_, - req, dst_, payload, timeout_, opts.local_addr_, - do_ratelimit_, is_bg_flow_, opts.ssl_invited_nodes_, NULL))) { - LOG_WARN("create request fail", K(ret)); - } else if (OB_ISNULL(req.pkt()) || OB_ISNULL(req.buf())) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_ERROR("request packet or req buf is NULL", K(ret), - "packet", req.pkt(), "buf", req.buf()); - } else if (OB_FAIL(fill_extra_payload(req, payload, pos))) { - LOG_WARN("fill extra payload fail", K(ret), K(pos), K(payload)); - } else if (OB_FAIL(init_pkt(req.pkt(), pcode, opts, false))) { - LOG_WARN("Init packet error", K(ret)); - } else { - rpc::RpcStatPiece piece; - piece.size_ = payload; - piece.time_ = ObTimeUtility::current_time() - req.pkt()->get_timestamp(); - RPC_STAT(pcode, tenant_id_, piece); - - ObReqTransport::Result r; - if (OB_FAIL(send_request(req, r))) { - LOG_WARN("send rpc request fail", K(pcode), K(ret)); - } else if (OB_ISNULL(r.pkt()) || OB_ISNULL(r.pkt()->get_cdata())) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("packet or packet cdata is NULL", K(ret), "pkt", r.pkt()); + int enable_poc_rpc = atoi(getenv("enable_poc_rpc")?:"1"); + if (enable_poc_rpc > 0) { + transport_impl_ = 1; } else { - const char *buf = r.pkt()->get_cdata(); - int64_t len = r.pkt()->get_clen(); - pos = 0; - UNIS_VERSION_GUARD(r.pkt()->get_unis_version()); - - if (OB_FAIL(rcode_.deserialize(buf, len, pos))) { - LOG_WARN("deserialize result code fail", K(ret)); - } else { - int wb_ret = OB_SUCCESS; - if (OB_UNLIKELY(OB_SUCCESS != rcode_.rcode_)) { - ret = rcode_.rcode_; - LOG_WARN("execute rpc fail", K(ret)); - } else if (OB_SUCC(ret) && NULL != handle) { - handle->has_more_ = r.pkt()->is_stream_next(); - handle->dst_ = dst_; - handle->sessid_ = r.pkt()->get_session_id(); - handle->opts_ = opts; - handle->transport_ = transport_; - handle->proxy_ = *this; - handle->pcode_ = pcode; - handle->do_ratelimit_ = do_ratelimit_; - handle->is_bg_flow_ = is_bg_flow_; - } else { - //do nothing - } - if (OB_SUCCESS != (wb_ret = log_user_error_and_warn(rcode_))) { - LOG_WARN("fail to log user error and warn", K(ret), K(wb_ret), K((rcode_))); - } - } + transport_impl_ = 0; } } - piece.size_ = payload; - piece.time_ = ObTimeUtility::current_time() - start_ts; - if (OB_FAIL(ret)) { - piece.failed_ = true; - if (OB_TIMEOUT == ret) { - piece.is_timeout_ = true; - } - } - RPC_STAT(pcode, tenant_id_, piece); - return ret; } @@ -171,7 +84,7 @@ int ObRpcProxy::rpc_post( ObReqTransport::AsyncCB *cb, const ObRpcOpts &opts) { - POC_RPC_INTERCEPT(post, dst_, pcode, None, *cb, opts); + POC_RPC_INTERCEPT(post, dst_, pcode, None, cb, opts); int ret = OB_SUCCESS; if (!active_) { @@ -259,7 +172,7 @@ int ObRpcProxy::init_pkt( pkt->set_dst_cluster_id(dst_cluster_id_); // For request, src_cluster_id must be the cluster_id of this cluster, directly hard-coded pkt->set_src_cluster_id(src_cluster_id_); - pkt->set_unis_version(opts.unis_version_); + pkt->set_unis_version(0); pkt->set_group_id((0 != get_group_id()) ? get_group_id() : this_worker().get_group_id()); if (need_increment_request_level(pcode)) { if (this_worker().get_worker_level() == INT32_MAX) { // The inner sql request is not sent from the tenant thread, so the worker level is still the initial value, given @@ -408,3 +321,17 @@ int ObRpcProxy::create_request( PCodeGuard pcode_guard(pcode); return transport.create_request(req, addr, size, timeout, local_addr, do_ratelimit, is_bg_flow, ob_ssl_invited_nodes, cb); } + +void ObRpcProxy::set_handle_attr(Handle* handle, const ObRpcPacketCode& pcode, const ObRpcOpts& opts, bool is_stream_next, int64_t session_id) { + if (handle) { + handle->pcode_ = pcode; + handle->opts_ = opts; + handle->has_more_ = is_stream_next; + handle->sessid_ = session_id; + handle->dst_ = dst_; + handle->proxy_ = *this; + handle->do_ratelimit_ = do_ratelimit_; + handle->is_bg_flow_ = is_bg_flow_; + handle->transport_ = NULL; + } +} diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.h b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.h index 501ddcce8..99b65d813 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.h @@ -113,7 +113,7 @@ public: public: ObRpcProxy() - : transport_(NULL), dst_(), transport_impl_(0), timeout_(MAX_RPC_TIMEOUT), + : transport_(NULL), dst_(), transport_impl_(1), timeout_(MAX_RPC_TIMEOUT), tenant_id_(common::OB_SYS_TENANT_ID), group_id_(0), priv_tenant_id_(common::OB_INVALID_TENANT_ID), max_process_handler_time_(0), compressor_type_(common::INVALID_COMPRESSOR), @@ -145,6 +145,13 @@ public: void set_compressor_type(const common::ObCompressorType &compressor_type) { compressor_type_ = compressor_type; } void set_dst_cluster(int64_t dst_cluster_id) { dst_cluster_id_ = dst_cluster_id; } void set_transport_impl(int transport_impl) { transport_impl_ = transport_impl; } + void set_result_code(const ObRpcResultCode retcode) { + rcode_.rcode_ = retcode.rcode_; + snprintf(rcode_.msg_, common::OB_MAX_ERROR_MSG_LEN, "%s", retcode.msg_); + rcode_.warnings_.reset(); + rcode_.warnings_ = retcode.warnings_; + } + void set_handle_attr(Handle* handle, const ObRpcPacketCode& pcode, const ObRpcOpts& opts, bool is_stream_next, int64_t session_id); bool need_increment_request_level(int pcode) const { return ((pcode > OB_SQL_PCODE_START && pcode < OB_SQL_PCODE_END) @@ -221,17 +228,6 @@ protected: Out &result, Handle *handle, const ObRpcOpts &opts); - template - int rpc_call(ObRpcPacketCode pcode, - const Input &args, - Handle *handle, - const ObRpcOpts &opts); - template - int rpc_call(ObRpcPacketCode pcode, - Output &result, - Handle *handle, - const ObRpcOpts &opts); - int rpc_call(ObRpcPacketCode pcode, Handle *handle, const ObRpcOpts &opts); template int rpc_post(const typename pcodeStruct::Request &args, diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.ipp b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.ipp index 7cf61ac34..3400de265 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.ipp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy.ipp @@ -49,8 +49,49 @@ int SSHandle::get_more(typename pcodeStruct::Response &result) ObReqTransport::Result r; if (OB_ISNULL(transport_)) { - ret = OB_NOT_INIT; - RPC_OBRPC_LOG(WARN, "transport_ is NULL", K(ret)); + RPC_OBRPC_LOG(INFO, "transport_ is NULL, use poc_rpc", K(sess_id), K(has_more_)); + const int64_t start_ts = common::ObTimeUtility::current_time(); + int64_t src_tenant_id = ob_get_tenant_id(); + auto &set = obrpc::ObRpcPacketSet::instance(); + const char* pcode_label = set.name_of_idx(set.idx_of_pcode(pcode_)); + ObRpcMemPool pool(src_tenant_id, pcode_label); + ObSyncRespCallback cb(pool); + char* pnio_req = NULL; + int64_t pnio_req_sz = 0, resp_sz = 0; + const char* resp = NULL; + ObRpcPacket resp_pkt; + sockaddr_in sock_addr; + static unsigned int thread_id = 0; + thread_id ++; + if (OB_FAIL(rpc_encode_req(proxy_, pool, pcode_, NULL, opts_, pnio_req, pnio_req_sz, false, true, false, sessid_))) { + RPC_LOG(WARN, "rpc encode req fail", K(ret)); + } else if(!dst_.is_valid()) { + ret = common::OB_INVALID_ARGUMENT; + RPC_LOG(WARN, "invalid addr", K(ret)); + } else if (OB_FAIL(pn_send( + (1ULL<<32) + thread_id, + ObPocClientStub::obaddr2sockaddr(&sock_addr, dst_), + pnio_req, + pnio_req_sz, + static_cast(set.idx_of_pcode(pcode_)), + start_ts + proxy_.timeout(), + ObSyncRespCallback::client_cb, + &cb))) { + RPC_LOG(WARN, "pnio post fail", K(ret)); + } else if (OB_FAIL(cb.wait())) { + RPC_LOG(WARN, "stream rpc execute fail", K(ret), K(dst_)); + } else if (NULL == (resp = cb.get_resp(resp_sz))) { + ret = common::OB_ERR_UNEXPECTED; + RPC_LOG(WARN, "stream rpc execute success but resp is null", K(ret), K(dst_)); + } else if (OB_FAIL(rpc_decode_resp(resp, resp_sz, result, resp_pkt, rcode_))) { + RPC_LOG(WARN, "rpc decode response fail", KP(resp), K(resp_sz), K(ret)); + } else if (rcode_.rcode_ != OB_SUCCESS) { + ret = rcode_.rcode_; + RPC_OBRPC_LOG(WARN, "execute rpc fail", K(ret)); + } else { + has_more_ = resp_pkt.is_stream_next(); + } + } else if (OB_FAIL(ObRpcProxy::create_request(pcode_, *transport_, req, dst_, PAYLOAD_SIZE, proxy_.timeout(), opts_.local_addr_, do_ratelimit_, is_bg_flow_, opts_.ssl_invited_nodes_, NULL))) { @@ -139,8 +180,53 @@ int SSHandle::abort() ObReqTransport::Result r; if (OB_ISNULL(transport_)) { - ret = OB_ERR_UNEXPECTED; - RPC_OBRPC_LOG(ERROR, "transport_ should not be NULL", K(ret)); + RPC_OBRPC_LOG(INFO, "transport_ is NULL, use poc_rpc", K(sess_id), K(has_more_)); + const int64_t start_ts = common::ObTimeUtility::current_time(); + int64_t src_tenant_id = ob_get_tenant_id(); + auto &set = obrpc::ObRpcPacketSet::instance(); + const char* pcode_label = set.name_of_idx(set.idx_of_pcode(pcode_)); + ObRpcMemPool pool(src_tenant_id, pcode_label); + ObSyncRespCallback cb(pool); + char* pnio_req = NULL; + int64_t pnio_req_sz = 0, resp_sz = 0; + const char* resp = NULL; + ObRpcPacket resp_pkt; + sockaddr_in sock_addr; + static unsigned int thread_id = 0; + thread_id ++; + if (OB_FAIL(rpc_encode_req(proxy_, pool, pcode_, NULL, opts_, pnio_req, pnio_req_sz, false, false, true, sessid_))) { + RPC_LOG(WARN, "rpc encode req fail", K(ret)); + } else if(!dst_.is_valid()) { + ret = common::OB_INVALID_ARGUMENT; + RPC_LOG(WARN, "invalid addr", K(ret)); + } else if (OB_FAIL(pn_send( + (1ULL<<32) + thread_id, + ObPocClientStub::obaddr2sockaddr(&sock_addr, dst_), + pnio_req, + pnio_req_sz, + static_cast(set.idx_of_pcode(pcode_)), + start_ts + proxy_.timeout(), + ObSyncRespCallback::client_cb, + &cb))) { + RPC_LOG(WARN, "pnio post fail", K(ret)); + } else if (OB_FAIL(cb.wait())) { + RPC_LOG(WARN, "stream rpc execute fail", K(ret), K(dst_)); + } else if (NULL == (resp = cb.get_resp(resp_sz))) { + ret = common::OB_ERR_UNEXPECTED; + RPC_LOG(WARN, "stream rpc execute success but resp is null", K(ret), K(dst_)); + } else { + typename pcodeStruct::Response result; + if (OB_FAIL(rpc_decode_resp(resp, resp_sz, result, resp_pkt, rcode_))) { + RPC_LOG(WARN, "rpc decode response fail", KP(resp), K(resp_sz), K(ret)); + } else if (rcode_.rcode_ != OB_SUCCESS) { + ret = rcode_.rcode_; + RPC_OBRPC_LOG(WARN, "execute rpc fail", K(ret)); + } else { + //do nothing + } + has_more_ = false; + } + } else if (OB_FAIL(ObRpcProxy::create_request(pcode_, *transport_, req, dst_, PAYLOAD_SIZE, proxy_.timeout(), opts_.local_addr_, do_ratelimit_, is_bg_flow_, opts_.ssl_invited_nodes_, NULL))) { @@ -274,7 +360,7 @@ template int ObRpcProxy::rpc_call(ObRpcPacketCode pcode, const Input &args, Out &result, Handle *handle, const ObRpcOpts &opts) { - POC_RPC_INTERCEPT(send, dst_, pcode, args, result, opts); + POC_RPC_INTERCEPT(send, dst_, pcode, args, result, handle, opts); using namespace oceanbase::common; using namespace rpc::frame; int ret = OB_SUCCESS; @@ -408,194 +494,11 @@ int ObRpcProxy::rpc_call(ObRpcPacketCode pcode, const Input &args, return ret; } -template -int ObRpcProxy::rpc_call(ObRpcPacketCode pcode, const Input &args, - Handle *handle, const ObRpcOpts &opts) -{ - POC_RPC_INTERCEPT(send, dst_, pcode, args, None, opts); - using namespace oceanbase::common; - using namespace rpc::frame; - int ret = OB_SUCCESS; - UNIS_VERSION_GUARD(opts.unis_version_); - - const int64_t start_ts = ObTimeUtility::current_time(); - rpc::RpcStatPiece piece; - - if (!init_) { - ret = OB_NOT_INIT; - } else if (!active_) { - ret = OB_INACTIVE_RPC_PROXY; - } - - int64_t pos = 0; - const int64_t payload = calc_payload_size(common::serialization::encoded_length(args)); - ObReqTransport::Request req; - - if (OB_FAIL(ret)) { - } else if (payload > OB_MAX_RPC_PACKET_LENGTH) { - ret = OB_RPC_PACKET_TOO_LONG; - RPC_OBRPC_LOG(WARN, "obrpc packet payload execced its limit", - K(ret), K(payload), "limit", OB_MAX_RPC_PACKET_LENGTH); - } else if (OB_FAIL(ObRpcProxy::create_request(pcode, *transport_, - req, dst_, payload, timeout_, opts.local_addr_, do_ratelimit_, - is_bg_flow_, opts.ssl_invited_nodes_, NULL))) { - RPC_OBRPC_LOG(WARN, "create request fail", K(ret)); - } else if (NULL == req.pkt()) { - ret = OB_ALLOCATE_MEMORY_FAILED; - RPC_OBRPC_LOG(WARN, "request packet is NULL", K(ret)); - } else if (OB_FAIL(common::serialization::encode(req.buf(), payload, pos, args))) { - RPC_OBRPC_LOG(WARN, "serialize argument fail", K(ret)); - } else if (OB_FAIL(fill_extra_payload(req, payload, pos))) { - RPC_OBRPC_LOG(WARN, "fill extra payload fail", K(ret), K(pos), K(payload)); - } else if (OB_FAIL(init_pkt(req.pkt(), pcode, opts, false))) { - RPC_OBRPC_LOG(WARN, "Init packet error", K(ret)); - } else { - ObReqTransport::Result r; - if (OB_FAIL(send_request(req, r))) { - RPC_OBRPC_LOG(WARN, "send rpc request fail", K(pcode), K(ret)); - } else { - const char *buf = r.pkt()->get_cdata(); - int64_t len = r.pkt()->get_clen(); - int64_t pos = 0; - UNIS_VERSION_GUARD(r.pkt()->get_unis_version()); - - if (OB_FAIL(rcode_.deserialize(buf, len, pos))) { - RPC_OBRPC_LOG(WARN, "deserialize result code fail", K(ret)); - } else { - int wb_ret = OB_SUCCESS; - ret = rcode_.rcode_; - if (common::OB_SUCCESS == ret && NULL != handle) { - handle->has_more_ = r.pkt()->is_stream_next(); - handle->dst_ = dst_; - handle->sessid_ = r.pkt()->get_session_id(); - handle->opts_ = opts; - handle->transport_ = transport_; - handle->proxy_ = *this; - handle->do_ratelimit_ = do_ratelimit_; - handle->is_bg_flow_ = is_bg_flow_; - } - if (common::OB_SUCCESS != (wb_ret = log_user_error_and_warn(rcode_))) { - RPC_OBRPC_LOG(WARN, "fail to log user error and warn", K(ret), K(wb_ret), K((rcode_))); - } - } - } - } - - piece.size_ = payload; - piece.time_ = ObTimeUtility::current_time() - start_ts; - if (OB_FAIL(ret)) { - piece.failed_ = true; - if (OB_TIMEOUT == ret) { - piece.is_timeout_ = true; - } - } - RPC_STAT(pcode, tenant_id_, piece); - - return ret; -} - -template -int ObRpcProxy::rpc_call(ObRpcPacketCode pcode, Output &result, - Handle *handle, const ObRpcOpts &opts) -{ - POC_RPC_INTERCEPT(send, dst_, pcode, None, result, opts); - using namespace oceanbase::common; - using namespace rpc::frame; - static const int64_t PAYLOAD_SIZE = 0; - int ret = OB_SUCCESS; - UNIS_VERSION_GUARD(opts.unis_version_); - - const int64_t start_ts = ObTimeUtility::current_time(); - rpc::RpcStatPiece piece; - - if (!init_) { - ret = OB_NOT_INIT; - } else if (!active_) { - ret = OB_INACTIVE_RPC_PROXY; - } else { - //do nothing - } - - int64_t pos = 0; - const int64_t payload = calc_payload_size(PAYLOAD_SIZE); - - ObReqTransport::Request req; - if (OB_FAIL(ret)) { - } else if (OB_FAIL(ObRpcProxy::create_request(pcode, *transport_, - req, dst_, payload, timeout_, opts.local_addr_, do_ratelimit_, - is_bg_flow_, opts.ssl_invited_nodes_, NULL))) { - RPC_OBRPC_LOG(WARN, "create request fail", K(ret)); - } else if (NULL == req.pkt()) { - ret = OB_ALLOCATE_MEMORY_FAILED; - RPC_OBRPC_LOG(WARN, "request packet is NULL", K(ret)); - } else if (OB_FAIL(fill_extra_payload(req, payload, pos))) { - RPC_OBRPC_LOG(WARN, "fill extra payload fail", K(ret), K(pos), K(payload)); - } else if (OB_FAIL(init_pkt(req.pkt(), pcode, opts, false))) { - RPC_OBRPC_LOG(WARN, "Init packet error", K(ret)); - } else { - int64_t timestamp = req.pkt()->get_timestamp(); - ObReqTransport::Result r; - if (OB_FAIL(send_request(req, r))) { - RPC_OBRPC_LOG(WARN, "send rpc request fail", K(pcode), K(ret)); - } else { - rpc::RpcStatPiece piece; - piece.size_ = 0; - piece.time_ = ObTimeUtility::current_time() - timestamp; - RPC_STAT(pcode, tenant_id_, piece); - const char *buf = r.pkt()->get_cdata(); - int64_t len = r.pkt()->get_clen(); - int64_t pos = 0; - UNIS_VERSION_GUARD(r.pkt()->get_unis_version()); - - if (OB_FAIL(rcode_.deserialize(buf, len, pos))) { - RPC_OBRPC_LOG(WARN, "deserialize result code fail", K(ret)); - } else { - int wb_ret = OB_SUCCESS; - if (rcode_.rcode_ != OB_SUCCESS) { - ret = rcode_.rcode_; - RPC_OBRPC_LOG(WARN, "execute rpc fail", K(ret), K_(dst)); - } else if (OB_FAIL(common::serialization::decode(buf, len, pos, result))) { - RPC_OBRPC_LOG(WARN, "deserialize result fail", K(ret)); - } else { - ret = rcode_.rcode_; - } - - if (OB_SUCC(ret) && NULL != handle) { - handle->has_more_ = r.pkt()->is_stream_next(); - handle->dst_ = dst_; - handle->sessid_ = r.pkt()->get_session_id(); - handle->opts_ = opts; - handle->transport_ = transport_; - handle->proxy_ = *this; - handle->pcode_ = pcode; - handle->do_ratelimit_ = do_ratelimit_; - handle->is_bg_flow_ = is_bg_flow_; - } - if (common::OB_SUCCESS != (wb_ret = log_user_error_and_warn(rcode_))) { - RPC_OBRPC_LOG(WARN, "fail to log user error and warn", K(ret), K(wb_ret), K((rcode_))); - } - } - } - } - - piece.size_ = PAYLOAD_SIZE; - piece.time_ = ObTimeUtility::current_time() - start_ts; - if (OB_FAIL(ret)) { - piece.failed_ = true; - if (OB_TIMEOUT == ret) { - piece.is_timeout_ = true; - } - } - RPC_STAT(pcode, tenant_id_, piece); - - return ret; -} - template int ObRpcProxy::rpc_post(const typename pcodeStruct::Request &args, AsyncCB *cb, const ObRpcOpts &opts) { - POC_RPC_INTERCEPT(post, dst_, pcodeStruct::PCODE, args, *cb, opts); + POC_RPC_INTERCEPT(post, dst_, pcodeStruct::PCODE, args, cb, opts); using namespace oceanbase::common; using namespace rpc::frame; int ret = OB_SUCCESS; diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy_macros.h b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy_macros.h index 738c1d9ba..aa92cdb29 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_proxy_macros.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_proxy_macros.h @@ -16,71 +16,6 @@ #include "lib/utility/ob_macro_utils.h" #include "lib/oblog/ob_log_module.h" -#define SELECT4(a, b, c, d, ...) d -#define SELECT5(a, b, c, d, e, ...) e - -// AOR_, aka argument or result, accepts one argument which is a -// typename. If the argument is surrounded by parenthesis, then the -// type is represented as input argument type and result into "const -// Type & args", otherwise the argument will be treated as result type -// and produces "Type & result". Here's the explanation of expanding -// step by step: -// -// AOR_((Type)) -// => CONCAT(IS_, NOT_CONST_P_ (Type)) & AOR_P_((Type)) -// => CONCAT(IS_, CONST_P_ Type) & CONCAT(IS_, RESULT_P_ (Type)) ) -// => IS_CONST_P_ Type & CONCAT(IS_, ARGS_P_) ) -// => const Type & IS_ARGS_P_ ) -// => const Type & args IGNORE_( ) -// => const Type & args -// -// AOR_(Type) -// => CONCAT(IS_, NOT_CONST_P_ Type) & AOR_P_(Type) -// => IS_NOT_CONST_P_ Type & CONCAT(IS_, RESULT_P_ Type) ) -// => Type & IS_RESULT_P_ Type ) -// => Type & result IGNORE_( Type ) -// => Type & result -// -#define RPM_ARGS(T) const T &args -#define RPM_RESULT(T) T &result -#define AOR_(T) IF_PAREN(T, RPM_ARGS, RPM_RESULT) - -// AOR_P_ is the core macro used by macro AOR_, return "args" if it's -// surrounded by parenthesis, "result" or not. -// -// AOR_P_((Type)) => args -// AOR_P_(Type) => result -// -#define RPM_ARGS_P(T) args -#define RPM_RESULT_P(T) result -#define AOR_P_(T) IF_PAREN(T, RPM_ARGS_P, RPM_RESULT_P) - -// SWITCH_IN_OUT_(Type) => (Type) -// SWITCH_IN_OUT_((Type)) => Type -#define RPM2INPUT(T) (T) -#define RPM2OUPUT(T) T -#define SWITCH_IN_OUT_(T) IF_PAREN(T, RPM2OUTPUT, RPM2INPUT) - -// INPUT_TYPE_((Type)) => Type -// INPUT_TYPE_(Type) => NoneT -// OUTPUT_TYPE_((Type)) => NoneT -// OUTPUT_TYPE_(Type) => Type -#define RPM_SELF_TYPE(T) T -#define RPM_NONE_TYPE(T) NoneT -#define INPUT_TYPE_(T) IF_PAREN(T, RPM_SELF_TYPE, RPM_NONE_TYPE) -#define OUTPUT_TYPE_(T) IF_PAREN(T, RPM_NONE_TYPE, RPM_SELF_TYPE) - -// AP_AOR_(Type) => , -// AP_AOR_((Type)) => const Type &args, -#define AP_IGNORE(T) -#define AP_INPUT(T) const T &args, -#define AP_AOR_(T) IF_PAREN(T, AP_INPUT, AP_IGNORE) - -// AP_AOR_P_(Type) => , -// AP_AOR_P_((Type)) => const Type &args, -#define AP_INPUT_P(T) args, -#define AP_AOR_P_(T) IF_PAREN(T, AP_INPUT_P, AP_IGNORE) - #define OROP_ const ObRpcOpts &opts = ObRpcOpts() #define ORSSH_(pcode) SSHandle &handle #define ORACB_(pcode) AsyncCB *cb @@ -110,68 +45,67 @@ typedef OUTPUT_TYPE_(Output) Response; \ }; -#define OB_DEFINE_RPC_S2(name, pcode, prio, Input, Output) \ - OB_RPC_STRUCT(pcode, Input, Output) \ - virtual int name(AOR_(Input), AOR_(Output), OROP_) \ +#define OB_DEFINE_RPC_STRUCT(pcode, Input, Output) \ + template \ + struct ObRpc { \ + static constexpr auto PCODE = pcode; \ + typedef Input Request; \ + typedef Output Response; \ + }; + +#define RPC_CALL_DISPATCH(name, ...) \ + if (mock_proxy_) { \ + mock_proxy_->set_server(dst_); \ + return mock_proxy_->name(__VA_ARGS__); \ + } else { \ + return name ##_(args, result, opts); \ + } + +#define OB_DEFINE_RPC_SYNC(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_STRUCT(pcode, Input, Output) \ + int name ## _(const Input& args, Output& result, OROP_) \ { \ const static ObRpcPriority PR = prio; \ int ret = common::OB_SUCCESS; \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(args, result, opts); \ - } else { \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, args, result, NULL, newopts); \ - } \ + ObRpcOpts newopts = opts; \ + if (newopts.pr_ == ORPR_UNDEF) { \ + newopts.pr_ = PR; \ + } \ + newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ + newopts.local_addr_ = GCTX.self_addr(); \ + ret = rpc_call(pcode, args, result, NULL, newopts); \ return ret; \ - } \ + } -#define OB_DEFINE_RPC_S1(name, pcode, prio, InOut) \ - OB_RPC_STRUCT(pcode, InOut, InOut) \ - virtual int name(AOR_(InOut), OROP_) \ - { \ - const static ObRpcPriority PR = prio; \ - int ret = common::OB_SUCCESS; \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(AOR_P_(InOut), opts); \ - } else { \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, AOR_P_(InOut), NULL, newopts); \ - } \ - return ret; \ - } \ +#define OB_DEFINE_RPC_S2_(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_SYNC(name, pcode, prio, Input, Output); \ + virtual int name(const Input& args, Output& result, OROP_) { \ + RPC_CALL_DISPATCH(name, args, result, opts); \ + } +#define OB_DEFINE_RPC_S2(name, pcode, prio, Input, Output) OB_DEFINE_RPC_S2_(name, pcode, prio, EXPAND Input, Output) -#define OB_DEFINE_RPC_S0(name, pcode, prio) \ - OB_RPC_STRUCT(pcode, (NoneT), NoneT) \ - virtual int name(OROP_) \ - { \ - const static ObRpcPriority PR = prio; \ - int ret = common::OB_SUCCESS; \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(opts); \ - } else { \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, NULL, newopts); \ - } \ - return ret; \ - } \ +#define OB_DEFINE_RPC_S1_INPUT_(name, pcode, prio, Input) \ + OB_DEFINE_RPC_SYNC(name, pcode, prio, Input, NoneT); \ + virtual int name(const Input& args, OROP_) { \ + NoneT result; \ + RPC_CALL_DISPATCH(name, args, opts); \ + } +#define OB_DEFINE_RPC_S1_INPUT(name, pcode, prio, Input) OB_DEFINE_RPC_S1_INPUT_(name, pcode, prio, EXPAND Input) +#define OB_DEFINE_RPC_S1_OUTPUT(name, pcode, prio, Output) \ + OB_DEFINE_RPC_SYNC(name, pcode, prio, NoneT, Output); \ + virtual int name(Output& result, OROP_) { \ + const NoneT args; \ + RPC_CALL_DISPATCH(name, result, opts); \ + } +#define OB_DEFINE_RPC_S1(name, pcode, prio, InOut) IF_IS_PAREN(InOut, OB_DEFINE_RPC_S1_INPUT, OB_DEFINE_RPC_S1_OUTPUT)(name, pcode, prio, InOut) + +#define OB_DEFINE_RPC_S0(name, pcode, prio) \ + OB_DEFINE_RPC_SYNC(name, pcode, prio, NoneT, NoneT); \ + virtual int name(OROP_) { \ + const NoneT args; \ + NoneT result; \ + RPC_CALL_DISPATCH(name, opts); \ + } #define OB_DEFINE_RPC_S(prio, name, pcode, ...) \ SELECT4(, \ @@ -182,58 +116,46 @@ #define RPC_S(args...) _CONCAT(OB_DEFINE_RPC, _S IGNORE_(args)) -// define synchronized stream interface -#define OB_DEFINE_RPC_SS2(name, pcode, prio, Input, Output) \ - OB_RPC_STRUCT(pcode, Input, Output) \ - virtual int name(AOR_(Input), AOR_(Output), ORSSH_(pcode), OROP_) \ - { \ +#define OB_DEFINE_RPC_STREAM(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_STRUCT(pcode, Input, Output); \ + int name ##_(const Input& args, Output& result, ORSSH_(pcode), OROP_) { \ int ret = common::OB_SUCCESS; \ const static ObRpcPriority PR = prio; \ ObRpcOpts newopts = opts; \ if (newopts.pr_ == ORPR_UNDEF) { \ newopts.pr_ = PR; \ } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, args, result, &handle, newopts); \ + newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ + newopts.local_addr_ = GCTX.self_addr(); \ + ret = rpc_call(pcode, args, result, &handle, newopts); \ return ret; \ - } \ - -#define OB_DEFINE_RPC_SS1(name, pcode, prio, InOut) \ - OB_RPC_STRUCT(pcode, InOut, InOut) \ - virtual int name(AOR_(InOut), ORSSH_(pcode), OROP_) \ - { \ - int ret = common::OB_SUCCESS; \ - const static ObRpcPriority PR = prio; \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, AOR_P_(InOut), &handle, newopts); \ - return ret; \ - } \ + } +// define synchronized stream interface +#define OB_DEFINE_RPC_SS2_(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_STREAM(name, pcode, prio, Input, Output); \ + virtual int name(const Input& args, Output& result, ORSSH_(pcode), OROP_) { \ + return name ##_(args, result, handle, opts); \ + } +#define OB_DEFINE_RPC_SS2(name, pcode, prio, Input, Output) OB_DEFINE_RPC_SS2_(name, pcode, prio, EXPAND Input, Output) +#define OB_DEFINE_RPC_SS1_INPUT_(name, pcode, prio, Input) \ + OB_DEFINE_RPC_STREAM(name, pcode, prio, Input, NoneT); \ + virtual int name(const Input& args, ORSSH_(pcode), OROP_) { \ + NoneT result; \ + return name ##_(args, result, handle, opts); \ + } +#define OB_DEFINE_RPC_SS1_INPUT(name, pcode, prio, Input) OB_DEFINE_RPC_SS1_INPUT_(name, pcode, prio, EXPAND Input) +#define OB_DEFINE_RPC_SS1_OUTPUT(name, pcode, prio, Output) \ + OB_DEFINE_RPC_STREAM(name, pcode, prio, NoneT, Output); \ + virtual int name(Output& result, ORSSH_(pcode), OROP_) { \ + NoneT args; \ + return name ##_(args, result, handle, opts); \ + } +#define OB_DEFINE_RPC_SS1(name, pcode, prio, InOut) IF_IS_PAREN(InOut, OB_DEFINE_RPC_SS1_INPUT, OB_DEFINE_RPC_SS1_OUTPUT)(name, pcode, prio, InOut) // Theoretically, stream rpc without argument or result is // impossible. We add this SS0 interface just complete our rpc // framework. -#define OB_DEFINE_RPC_SS0(name, pcode, prio) \ - OB_RPC_STRUCT(pcode, (NoneT), NoneT) \ - virtual int name(ORSSH_(pcode), OROP_) \ - { \ - int ret = common::OB_SUCCESS; \ - const static ObRpcPriority PR = prio; \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_call(pcode, &handle, newopts); \ - return ret; \ - } \ - +#define OB_DEFINE_RPC_SS0(name, pcode, prio) #define OB_DEFINE_RPC_SS(prio, name, pcode, ...) \ SELECT4(, \ ## __VA_ARGS__, \ @@ -244,9 +166,17 @@ #define RPC_SS(args...) _CONCAT(OB_DEFINE_RPC, _SS IGNORE_(args)) // define asynchronous interface -#define OB_DEFINE_RPC_AP2(name, pcode, prio, Input, Output) \ - OB_RPC_STRUCT(pcode, Input, Output) \ - virtual int name(AOR_(Input), ORACB_(pcode), OROP_) \ +#define OB_RPC_ASYNC_DISPATCH(name, ...) \ + if (mock_proxy_) { \ + mock_proxy_->set_server(dst_); \ + return mock_proxy_->name(__VA_ARGS__); \ + } else { \ + return name##_(args, cb, opts); \ + } + +#define OB_DEFINE_RPC_ASYNC(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_STRUCT(pcode, Input, Output); \ + int name##_(const Input& args, ORACB_(pcode), OROP_) \ { \ const static ObRpcPriority PR = prio; \ int ret = common::OB_SUCCESS; \ @@ -254,60 +184,39 @@ if (newopts.pr_ == ORPR_UNDEF) { \ newopts.pr_ = PR; \ } \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(args, cb, newopts); \ - } else { \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_post>(args, cb, newopts); \ - } \ + newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ + newopts.local_addr_ = GCTX.self_addr(); \ + ret = rpc_post>(args, cb, newopts); \ return ret; \ } -#define OB_DEFINE_RPC_AP1(name, pcode, prio, InOut) \ - OB_RPC_STRUCT(pcode, InOut, InOut) \ - virtual int name(AP_AOR_(InOut) ORACB_(pcode), OROP_) \ - { \ - const static ObRpcPriority PR = prio; \ - int ret = common::OB_SUCCESS; \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(AP_AOR_P_(InOut) cb, newopts); \ - } else { \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_post>(AP_AOR_P_(InOut) cb, newopts); \ - } \ - return ret; \ +#define OB_DEFINE_RPC_AP2_(name, pcode, prio, Input, Output) \ + OB_DEFINE_RPC_ASYNC(name, pcode, prio, Input, Output); \ + virtual int name(const Input& args, ORACB_(pcode), OROP_) { \ + OB_RPC_ASYNC_DISPATCH(name, args, cb, opts); \ + } +#define OB_DEFINE_RPC_AP2(name, pcode, prio, Input, Output) OB_DEFINE_RPC_AP2_(name, pcode, prio, EXPAND Input, Output) + +#define OB_DEFINE_RPC_AP1_INPUT_(name, pcode, prio, Input) \ + OB_DEFINE_RPC_ASYNC(name, pcode, prio, Input, NoneT); \ + virtual int name(const Input& args, ORACB_(pcode), OROP_) { \ + OB_RPC_ASYNC_DISPATCH(name, args, cb, opts); \ + } +#define OB_DEFINE_RPC_AP1_OUTPUT(name, pcode, prio, Output) \ + OB_DEFINE_RPC_ASYNC(name, pcode, prio, NoneT, Output); \ + virtual int name(ORACB_(pcode), OROP_) { \ + OB_RPC_ASYNC_DISPATCH(name, cb, opts); \ + } +#define OB_DEFINE_RPC_AP1_INPUT(name, pcode, prio, InOut) OB_DEFINE_RPC_AP1_INPUT_(name, pcode, prio, EXPAND InOut) +#define OB_DEFINE_RPC_AP1(name, pcode, prio, InOut) IF_IS_PAREN(InOut, OB_DEFINE_RPC_AP1_INPUT, OB_DEFINE_RPC_AP1_OUTPUT)(name, pcode, prio, InOut) + +#define OB_DEFINE_RPC_AP0(name, pcode, prio) \ + OB_DEFINE_RPC_ASYNC(name, pcode, prio, NoneT, NoneT); \ + virtual int name(ORACB_(pcode), OROP_) { \ + OB_RPC_ASYNC_DISPATCH(name, cb, opts); \ } -#define OB_DEFINE_RPC_AP0(name, pcode, prio) \ - OB_RPC_STRUCT(pcode, (NoneT), NoneT) \ - virtual int name(ORACB_(pcode), OROP_) \ - { \ - const static ObRpcPriority PR = prio; \ - int ret = common::OB_SUCCESS; \ - ObRpcOpts newopts = opts; \ - if (newopts.pr_ == ORPR_UNDEF) { \ - newopts.pr_ = PR; \ - } \ - if (mock_proxy_) { \ - mock_proxy_->set_server(dst_); \ - ret = mock_proxy_->name(cb, newopts); \ - } else { \ - newopts.ssl_invited_nodes_ = GCONF._ob_ssl_invited_nodes.get_value_string(); \ - newopts.local_addr_ = GCTX.self_addr(); \ - ret = rpc_post(pcode, cb, newopts); \ - } \ - return ret; \ - } - - +#define SELECT4(a, b, c, d, ...) d #define OB_DEFINE_RPC_AP(prio, name, pcode, ...) \ SELECT4(, \ ## __VA_ARGS__, \ diff --git a/deps/oblib/src/rpc/pnio/README.md b/deps/oblib/src/rpc/pnio/README.md new file mode 100644 index 000000000..ce4fd4143 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/README.md @@ -0,0 +1,18 @@ +# pkt-nio + +## API +see interface/group.h + +## test +``` +make test/test-group +test/test-group +``` + +## example +``` +#define rk_log_macro(level, format, ...) _OB_LOG(level, "PNIO " format, ##__VA_ARGS__) +#include "interface/group.h" +... +#include "interface/pkt-nio.c" +``` diff --git a/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.c b/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.c new file mode 100644 index 000000000..6f14f4340 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.c @@ -0,0 +1,110 @@ +typedef struct cfifo_page_t +{ + // 每次alloc ref不加1,每次free,ref减1. retire page的时候ref加K + int ref_ RK_CACHE_ALIGNED; + uint64_t stock_ RK_CACHE_ALIGNED; + char data_[0]; +} cfifo_page_t; + +static void cfifo_page_born(cfifo_page_t* pg, int sz) +{ + pg->ref_ = 0; + pg->stock_ = (1ULL<<63) + sz - sizeof(*pg); +} + +static int32_t cfifo_calc_pgsz(int sz) +{ + return sz + sizeof(cfifo_page_t); +} + +static cfifo_page_t* cfifo_page_create(cfifo_alloc_t* alloc, int pgsz, int* ret_pgsz) +{ + cfifo_page_t* pg = NULL; + if ((pg = (cfifo_page_t*)chunk_cache_alloc(alloc->chunk_alloc, pgsz, ret_pgsz))) { + cfifo_page_born(pg, *ret_pgsz); + } + return pg; +} + +static void cfifo_page_release(cfifo_page_t* pg) +{ + if (0 == AAF(&pg->ref_, -1)) { + chunk_cache_free(pg); + } +} + +static void* cfifo_alloc_from_page(cfifo_page_t* pg, int32_t offset) +{ + void* ret = NULL; + ret = pg->data_ + (int32_t)offset; + *(typeof(&pg))ret = pg; + ret = (void*)((typeof(&pg))ret + 1); + return ret; +} + +static bool cfifo_page_after_sliced(cfifo_page_t* pg, int32_t sz) +{ + bool ret = 0; + int64_t compound_sz = sz + (1ULL<<32); + uint64_t pos = AAF(&pg->stock_, -compound_sz); + if ((ret = ((int32_t)pos <= 0))) { + if (0 == AAF(&pg->ref_, (1<<31) ^ -(int32_t)(pos>>32))) { + chunk_cache_free(pg); + } + } + return ret; +} + +void cfifo_alloc_init(cfifo_alloc_t* alloc, chunk_cache_t* chunk_alloc) +{ + alloc->chunk_alloc = chunk_alloc; + alloc->cur = NULL; + alloc->remain = 0; +} + +void* cfifo_alloc(cfifo_alloc_t* alloc, int sz) +{ + void* ret = NULL; + int64_t req_sz = upalign8(sz) + sizeof(void*); + while(NULL == ret) { + int32_t remain = LOAD(&alloc->remain); + if (unlikely(remain <= 0)) { + if (LOAD(&alloc->cur)) { + continue; + } + int32_t pgsz = cfifo_calc_pgsz(req_sz); + int32_t ret_pgsz = 0; + cfifo_page_t* pg = cfifo_page_create(alloc, pgsz, &ret_pgsz); + if (NULL != pg) { + if (BCAS(&alloc->cur, NULL, pg)) { + STORE(&alloc->remain, ret_pgsz - sizeof(*pg)); + } else { + chunk_cache_free(pg); + } + } else { + break; + } + } else if (unlikely(remain < req_sz)) { + if (BCAS(&alloc->remain, remain, 0)) { + cfifo_page_t* pg = LOAD(&alloc->cur); + if (cfifo_page_after_sliced(pg, remain)) { + STORE(&alloc->cur, NULL); + } + cfifo_page_release(pg); + } + } else if (BCAS(&alloc->remain, remain, remain - req_sz)) { + cfifo_page_t* pg = LOAD(&alloc->cur); + if (cfifo_page_after_sliced(pg, req_sz)) { + STORE(&alloc->cur, NULL); + } + ret = cfifo_alloc_from_page(pg, remain - req_sz); + } + } + return ret; +} + +void cfifo_free(void* p) +{ + cfifo_page_t* pg = *((typeof(&pg))p - 1); + cfifo_page_release(pg); +} diff --git a/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.h b/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.h new file mode 100644 index 000000000..e25fbde60 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/cfifo_alloc.h @@ -0,0 +1,11 @@ +struct cfifo_page_t; +typedef struct cfifo_alloc_t +{ + chunk_cache_t* chunk_alloc; + struct cfifo_page_t* cur RK_CACHE_ALIGNED; + int32_t remain RK_CACHE_ALIGNED; +} cfifo_alloc_t; + +extern void cfifo_alloc_init(cfifo_alloc_t* alloc, chunk_cache_t* chunk_alloc); +extern void* cfifo_alloc(cfifo_alloc_t* alloc, int sz); +extern void cfifo_free(void* p); diff --git a/deps/oblib/src/rpc/pnio/alloc/chunk_cache.c b/deps/oblib/src/rpc/pnio/alloc/chunk_cache.c new file mode 100644 index 000000000..06f69c1d2 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/chunk_cache.c @@ -0,0 +1,42 @@ + +void chunk_cache_init(chunk_cache_t* cache, int chunk_bytes, int mod) +{ + fixed_stack_init(&cache->free_list); + cache->mod = mod; + cache->chunk_bytes = chunk_bytes; +} + +void* chunk_cache_alloc(chunk_cache_t* cache, int64_t sz, int* ret_sz) +{ + void* ret = NULL; + void* p = NULL; + if (unlikely(sz > cache->chunk_bytes)) { + p = mod_alloc(sz + sizeof(chunk_cache_t*), cache->mod); + if (p) { + *(chunk_cache_t**)p = NULL; + *ret_sz = sz; + } + } else if (NULL != (p = fixed_stack_pop(&cache->free_list))) { + *ret_sz = cache->chunk_bytes; + } else if (NULL != (p = mod_alloc(cache->chunk_bytes + sizeof(chunk_cache_t*), cache->mod))) { + if (p) { + *(chunk_cache_t**)p = cache; + *ret_sz = cache->chunk_bytes; + } + } else { + //fail; + } + if (p) { + ret = (void*)((chunk_cache_t**)p + 1); + } + return ret; +} + +void chunk_cache_free(void* p) +{ + void** pcache = ((void**)p) - 1; + chunk_cache_t* cache = (typeof(cache))*pcache; + if (NULL == cache || 0 != fixed_stack_push(&cache->free_list, pcache)) { + mod_free(pcache); + } +} diff --git a/deps/oblib/src/rpc/pnio/alloc/chunk_cache.h b/deps/oblib/src/rpc/pnio/alloc/chunk_cache.h new file mode 100644 index 000000000..3f2170c45 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/chunk_cache.h @@ -0,0 +1,10 @@ +typedef struct chunk_cache_t +{ + int mod; + int chunk_bytes; + fixed_stack_t free_list; +} chunk_cache_t; + +extern void chunk_cache_init(chunk_cache_t* cache, int chunk_bytes, int mod); +extern void* chunk_cache_alloc(chunk_cache_t* cache, int64_t sz, int* chunk_size); +extern void chunk_cache_free(void* p); diff --git a/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.c b/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.c new file mode 100644 index 000000000..4867886d8 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.c @@ -0,0 +1,76 @@ +typedef struct fifo_page_t +{ + int ref_; + int pos_; + char data_[0]; +} fifo_page_t; + +static void fifo_page_born(fifo_page_t* pg, int sz) +{ + pg->ref_ = 1; + pg->pos_ = sz - sizeof(*pg); +} + +static fifo_page_t* fifo_page_create(fifo_alloc_t* alloc, int sz) +{ + fifo_page_t* pg = NULL; + int pg_sz = sz + sizeof(*pg) + sizeof(&pg); + int chunk_size = 0; + if ((pg = (fifo_page_t*)chunk_cache_alloc(alloc->chunk_alloc, pg_sz, &chunk_size))) { + fifo_page_born(pg, chunk_size); + } + return pg; +} + +static void fifo_page_release(fifo_page_t* pg) +{ + if (0 == --pg->ref_) { + chunk_cache_free(pg); + } +} + +static void* fifo_alloc_from_page(fifo_page_t* pg, int sz) +{ + void* ret = NULL; + sz += sizeof(&pg); + if ((pg->pos_ -= sz) >= 0) { + ret = pg->data_ + pg->pos_; + *(typeof(&pg))ret = pg; + ret = (void*)((typeof(&pg))ret + 1); + pg->ref_++; + } + return ret; +} + +void fifo_alloc_init(fifo_alloc_t* alloc, chunk_cache_t* chunk_alloc) +{ + alloc->chunk_alloc = chunk_alloc; + alloc->cur = NULL; +} + +void* fifo_alloc(fifo_alloc_t* alloc, int sz1) +{ + void* ret = NULL; + fifo_page_t* pg = (fifo_page_t*)alloc->cur; + int sz = (int)upalign8(sz1); + if (pg) { + ret = fifo_alloc_from_page(pg, sz); + } + if (!ret) { + fifo_page_t* npg = fifo_page_create(alloc, sz); + if (npg) { + if (pg) { + fifo_page_release(pg); + } + alloc->cur = npg; + ret = fifo_alloc_from_page(npg, sz); + } + } + return ret; +} + +void fifo_free(void* p) +{ + fifo_page_t* pg = *((typeof(&pg))p - 1); + fifo_page_release(pg); +} diff --git a/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.h b/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.h new file mode 100644 index 000000000..d0fb197bb --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/fifo_alloc.h @@ -0,0 +1,8 @@ +typedef struct fifo_alloc_t +{ + chunk_cache_t* chunk_alloc; + void* cur; +} fifo_alloc_t; +extern void fifo_alloc_init(fifo_alloc_t* alloc, chunk_cache_t* chunk_alloc); +extern void* fifo_alloc(fifo_alloc_t* alloc, int sz); +extern void fifo_free(void* p); diff --git a/deps/oblib/src/rpc/pnio/alloc/mod_alloc.c b/deps/oblib/src/rpc/pnio/alloc/mod_alloc.c new file mode 100644 index 000000000..280c1778f --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/mod_alloc.c @@ -0,0 +1,77 @@ +#ifndef PKT_NIO_MALLOC +#define PKT_NIO_MALLOC(size, label) malloc(size); +#define PKT_NIO_FREE(p) free(p); +#endif + +typedef struct alloc_head_t { + link_t link; + int mod; + int64_t sz; +} alloc_head_t; + +static int64_t mod_stat[MOD_MAX_COUNT + 1]; +static const char* mod_name[MOD_MAX_COUNT + 1] = { +#define MOD_DEF(name) #name, //keep +#include "mod_define.h" +#undef MOD_DEF +}; + +static void mod_update(int mod, int64_t sz) { + FAA(&mod_stat[mod], sz); +} + +void mod_report(format_t* f) { + for(int i = 0; i < MOD_MAX_COUNT; i++) { + if (mod_stat[i] != 0) { + format_append(f, "%s:%'8ld ", mod_name[i], mod_stat[i]); + } + } +} + +static link_queue_t global_free_blocks; +static __attribute__((constructor)) void init_global_free_blocks() +{ + link_queue_init(&global_free_blocks); +} + +void* mod_alloc(int64_t sz, int mod) { +#ifndef ALLOC_ERRSIM_FREQ +#define ALLOC_ERRSIM_FREQ 20 +#endif +#ifdef PNIO_ERRSIM + int rand_value = rand(); + if (rand_value % ALLOC_ERRSIM_FREQ == 0) { + rk_warn("mod_alloc return null. rand_value = %d\n", rand_value); + errno = ENOMEM; + return NULL; + } +#endif + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_malloc_count, eloop_malloc_time)); + const char* label = mod_name[mod]; + alloc_head_t* h = (typeof(h))PKT_NIO_MALLOC(sizeof(*h) + sz, label); + if (h) { + h->mod = mod; + h->sz = sz; + mod_update(mod, sz); + h = h + 1; + } + return (void*)h; +} + +void mod_free(void* p) { + if (p) { + alloc_head_t* h = (typeof(h))p - 1; + mod_update(h->mod, -h->sz); + PKT_NIO_FREE(h); + } +} + +void* salloc(int64_t sz) +{ + return mod_alloc(sz, MOD_DEFAULT); +} + +void sfree(void* p) +{ + mod_free(p); +} diff --git a/deps/oblib/src/rpc/pnio/alloc/mod_alloc.h b/deps/oblib/src/rpc/pnio/alloc/mod_alloc.h new file mode 100644 index 000000000..f173e2cdd --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/mod_alloc.h @@ -0,0 +1,10 @@ +extern void mod_report(format_t* f); +extern void* mod_alloc(int64_t sz, int mod); +extern void mod_free(void* p); +extern void* salloc(int64_t sz); +extern void sfree(void* p); +enum { +#define MOD_DEF(name) MOD_ ## name, //keep +#include "mod_define.h" +#undef MOD_DEF +}; diff --git a/deps/oblib/src/rpc/pnio/alloc/mod_define.h b/deps/oblib/src/rpc/pnio/alloc/mod_define.h new file mode 100644 index 000000000..9cba1c44b --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/mod_define.h @@ -0,0 +1,13 @@ +//keep +MOD_DEF(DEFAULT) + MOD_DEF(SERVER_CTX_CHUNK) + MOD_DEF(SERVER_RESP_CHUNK) + MOD_DEF(CLIENT_REQ_CHUNK) + MOD_DEF(CLIENT_CB_CHUNK) + MOD_DEF(PKTC_CB) + MOD_DEF(PKTC_REQ) + MOD_DEF(PKTS_RESP) + MOD_DEF(PKTS_RESP_CTX) + MOD_DEF(PKTS_INBUF) + MOD_DEF(PKTC_INBUF) + MOD_DEF(MAX_COUNT) diff --git a/deps/oblib/src/rpc/pnio/alloc/ref_alloc.c b/deps/oblib/src/rpc/pnio/alloc/ref_alloc.c new file mode 100644 index 000000000..a88b80e11 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/ref_alloc.c @@ -0,0 +1,16 @@ +void* ref_alloc(int64_t sz, int mod) { + int64_t* ref = (int64_t*)mod_alloc(sz + sizeof(int64_t), mod); + if (ref) { + *ref = 0; + return ref + 1; + } + return NULL; +} + +void ref_free(void* p) { + if (NULL == p) return; + int64_t* ref = (int64_t*)p - 1; + if (0 == AAF(ref, -1)) { + mod_free(ref); + } +} diff --git a/deps/oblib/src/rpc/pnio/alloc/ref_alloc.h b/deps/oblib/src/rpc/pnio/alloc/ref_alloc.h new file mode 100644 index 000000000..c75519470 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/alloc/ref_alloc.h @@ -0,0 +1,2 @@ +extern void* ref_alloc(int64_t sz, int mod); +extern void ref_free(void* p); diff --git a/deps/oblib/src/rpc/pnio/config.h b/deps/oblib/src/rpc/pnio/config.h new file mode 100644 index 000000000..c23f38f99 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/config.h @@ -0,0 +1,23 @@ +#define PNIO_ENABLE_CRC 0 +#define PNIO_ENABLE_DELAY_WARN 1 + +#if PNIO_ENABLE_CRC +#define PNIO_CRC(...) __VA_ARGS__ +#else +#define PNIO_CRC(...) +#endif + +#if PNIO_ENABLE_DELAY_WARN +#define PNIO_DELAY_WARN(...) __VA_ARGS__ +#else +#define PNIO_DELAY_WARN(...) +#endif + + +#define FLUSH_DELAY_WARN_US 500000 +#define HANDLE_DELAY_WARN_US 500000 +#define ELOOP_WARN_US 500000 +#define EPOLL_HANDLE_TIME_LIMIT 0 +#define MAX_REQ_QUEUE_COUNT 4096 +#define MAX_WRITE_QUEUE_COUNT 4096 +#define MAX_CATEG_COUNT 1024 diff --git a/deps/oblib/src/rpc/pnio/cpp/ready_flag.h b/deps/oblib/src/rpc/pnio/cpp/ready_flag.h new file mode 100644 index 000000000..bd1f39138 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/cpp/ready_flag.h @@ -0,0 +1,17 @@ +class RespReadyFlag +{ +public: + RespReadyFlag(): ready_(0) {} + ~RespReadyFlag() {} + void set_ready() { + STORE(&ready_, 1); + rk_futex_wake(&ready_, UINT32_MAX); + } + void wait_ready() { + while(!LOAD(&ready_)) { + rk_futex_wait(&ready_, 0, NULL); + } + } +private: + int32_t ready_; +}; diff --git a/deps/oblib/src/rpc/pnio/cpp/rpc_interface.h b/deps/oblib/src/rpc/pnio/cpp/rpc_interface.h new file mode 100644 index 000000000..c19ec50ec --- /dev/null +++ b/deps/oblib/src/rpc/pnio/cpp/rpc_interface.h @@ -0,0 +1,228 @@ +#pragma once +extern "C" { +#include "../pkt-nio.h" +}; +#include "rpc_mem_pool.h" +#include "simple_mem_pool.h" + +class NioImpl; +class ReqHandleCtx +{ +public: + ReqHandleCtx(IMemPool& pool): pool_(pool) {} + ~ReqHandleCtx() {} + IMemPool& get_pool() { return pool_; } + int resp(const char* req, int64_t req_size); + void* alloc(int64_t sz) { return pool_.alloc(sz); } + void destroy() { pool_.destroy(); } + void set(NioImpl* nio, void* req_ref, uint64_t sock_id, uint64_t pkt_id) { + nio_ = nio; + req_ref_ = req_ref; + sock_id_ = sock_id; + pkt_id_ = pkt_id; + } + uint64_t get_sock_id() { return sock_id_; } + uint64_t get_pkt_id() { return pkt_id_; } + void release_req() { + if (NULL != req_ref_) { + ref_free(req_ref_); + req_ref_ = NULL; + } + } +private: + IMemPool& pool_; + NioImpl* nio_; + void* req_ref_; + uint64_t sock_id_; + uint64_t pkt_id_; +}; + +class IReqHandler +{ +public: + IReqHandler() {} + virtual ~IReqHandler() {} + virtual IMemPool* create_pool() { return RpcMemPool::create(0); } + virtual int handle_req(ReqHandleCtx* ctx, const char* buf, int64_t sz) = 0; +}; + +class IRespHandler +{ +public: + IRespHandler(IMemPool* pool): pool_(pool), ref_(0), packet_id_(0) {} + virtual ~IRespHandler() {} + virtual int handle_resp(int io_err, const char* buf, int64_t sz) = 0; + IMemPool* get_pool() { return pool_; } + void* alloc(int64_t sz) { return pool_->alloc(sz); } + void free_resp() { do_xref(-1); } + void free_req() { do_xref(1); } + uint64_t get_packet_id() const { return packet_id_; } + void set_packet_id(uint64_t packet_id) { packet_id_ = packet_id; } +private: + void destroy() { + // can not detect null pool_ ptr + pool_->destroy(); + } + int xref(int x) { return AAF(&ref_, x); } + void do_xref(int x) { + if (0 == xref(x)) { + destroy(); + } + } +private: + IMemPool* pool_; + int ref_; + uint64_t packet_id_; +}; + +class NioImpl +{ +public: + NioImpl(): idx_(0), next_pkt_id_(0), req_handler_(NULL) {} + ~NioImpl() {} + struct ClientReq { + IRespHandler* handler_; + pktc_cb_t cb_; + pktc_req_t req_; + easy_head_t head_; + }; + struct ServerResp { + ReqHandleCtx* ctx_; + pkts_req_t req_; + easy_head_t head_; + }; + int init(int idx, IReqHandler* req_handler, int port) { + int err = 0; + pkts_cfg_t svr_cfg; + svr_cfg.handle_func = pkts_handle_func; + addr_init(&svr_cfg.addr, "0.0.0.0", port); + if (0 != (err = eloop_init(&ep_))) { + } else if (port > 0 && 0 != (err = pkts_init(&pkts_, &ep_, &svr_cfg))) { + } else if (0 != (err = pktc_init(&pktc_, &ep_, 0))) { + } else { + idx_ = idx; + req_handler_ = req_handler; + } + return err; + } + int post(const addr_t& addr, const char* req, int64_t req_size, IRespHandler* resp_handler, int64_t timeout_us) { + ClientReq* post_struct = (typeof(post_struct))resp_handler->alloc(sizeof(*post_struct) + req_size); + post_struct->handler_ = resp_handler; + pktc_req_t* r = &post_struct->req_; + pktc_cb_t* cb = &post_struct->cb_; + cb->id = gen_packet_id(); + cb->expire_us = rk_get_corse_us() + timeout_us; + cb->resp_cb = pktc_resp_cb_func; + r->flush_cb = pktc_flush_cb_func; + r->resp_cb = cb; + r->dest = addr; + eh_copy_msg(&r->msg, cb->id, req, req_size); + resp_handler->set_packet_id(cb->id); + return pktc_post(&pktc_, r); + } + int resp(ReqHandleCtx* ctx, const char* req, int64_t req_size) { + ServerResp* resp_struct = (typeof(resp_struct))ctx->alloc(sizeof(*resp_struct) + req_size); + resp_struct->ctx_ = ctx; + pkts_req_t* r = &resp_struct->req_; + r->flush_cb = pkts_flush_cb_func; + r->sock_id = ctx->get_sock_id(); + eh_copy_msg(&r->msg, ctx->get_pkt_id(), req, req_size); + return pkts_resp(&pkts_, r); + } + void do_work() { + eloop_run(&ep_); + } +private: + uint32_t gen_packet_id() { + static uint32_t g_next_pkt_id = 0; + return AAF(&g_next_pkt_id, 1); + } + static int pkts_handle_func(pkts_t* pkts, void* req_handle, const char* b, int64_t s, uint64_t sock_id) { + NioImpl* impl = structof(pkts, NioImpl, pkts_); + IReqHandler* req_handler = impl->req_handler_; + uint64_t pkt_id = eh_packet_id(b); + IMemPool* pool = req_handler->create_pool(); + ReqHandleCtx* ctx = (typeof(ctx))pool->alloc(sizeof(*ctx)); + new(ctx)ReqHandleCtx(*pool); + ctx->set(impl, req_handle, sock_id, pkt_id); + return req_handler->handle_req(ctx, b + sizeof(easy_head_t), s - sizeof(easy_head_t)); + } + static void pkts_flush_cb_func(pkts_req_t* req) { + ServerResp* resp_struct = structof(req, ServerResp, req_); + ReqHandleCtx* ctx = resp_struct->ctx_; + ctx->destroy(); + } + static void pktc_flush_cb_func(pktc_req_t* req) { + ClientReq* ps = structof(req, ClientReq, req_); + IRespHandler* resp_cb = ps->handler_; + resp_cb->free_req(); + } + static void pktc_resp_cb_func(pktc_cb_t* cb, const char* resp, int64_t sz) { + ClientReq* ps = structof(cb, ClientReq, cb_); + IRespHandler* resp_cb = ps->handler_; + if (NULL != resp) { + resp += sizeof(easy_head_t); + sz -= sizeof(easy_head_t); + } + resp_cb->handle_resp(0, resp, sz); + } +private: + eloop_t ep_; + uint64_t idx_; + uint32_t next_pkt_id_; + IReqHandler* req_handler_; + pkts_t pkts_; + pktc_t pktc_; +}; + +inline int ReqHandleCtx::resp(const char* req, int64_t req_size) +{ + release_req(); // after nio_->resp(), ctx self is invalid. + int err = nio_->resp(this, req, req_size); + return err; +} + +#include +class Nio +{ +public: + enum { N_THREAD = 32}; + Nio(): n_thread_(0), thread_idx_(0), io_idx_round_robin_(0) {} + ~Nio() {} + int start(IReqHandler* req_handler, int port, int n_thread) { + int err = 0; + for(int i = 0; 0 == err && i < n_thread; i++) { + if (0 != (err = impl_[i].init(i, req_handler, port))) { + rk_error("nio init fail: %d", err); + } else { + if (0 != (err = pthread_create(pd_ + i, NULL, thread_work, this))) { + rk_error("pthread create fail: %d", err); + } + } + } + if (0 == err) { + n_thread_ = n_thread; + } + return err; + } + int post(const addr_t& addr, const char* req, int64_t req_size, IRespHandler* resp_handler, int64_t timeout_us) { + int64_t idx = (FAA(&io_idx_round_robin_, 1) % n_thread_); + return impl_[idx].post(addr, req, req_size, resp_handler, timeout_us); + } +private: + void do_thread_work() { + int64_t idx = FAA(&thread_idx_, 1); + impl_[idx].do_work(); + } + static void* thread_work(void* arg) { + Nio* nio = (typeof(nio))arg; + nio->do_thread_work(); + return NULL; + } +private: + int64_t n_thread_; + int64_t thread_idx_; + int64_t io_idx_round_robin_; + pthread_t pd_[N_THREAD]; + NioImpl impl_[N_THREAD]; +}; diff --git a/deps/oblib/src/rpc/pnio/cpp/rpc_mem_pool.h b/deps/oblib/src/rpc/pnio/cpp/rpc_mem_pool.h new file mode 100644 index 000000000..8f0c8e206 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/cpp/rpc_mem_pool.h @@ -0,0 +1,10 @@ +#pragma once +#include +class IMemPool +{ +public: + IMemPool() {} + virtual ~IMemPool() {} + virtual void* alloc(int64_t sz) = 0; + virtual void destroy() = 0; +}; diff --git a/deps/oblib/src/rpc/pnio/cpp/simple_mem_pool.h b/deps/oblib/src/rpc/pnio/cpp/simple_mem_pool.h new file mode 100644 index 000000000..db8068865 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/cpp/simple_mem_pool.h @@ -0,0 +1,43 @@ +class RpcMemPool: public IMemPool +{ +public: + struct Link { Link* next_; }; + RpcMemPool(): tail_(NULL) {} + virtual ~RpcMemPool() { destroy(); } + static RpcMemPool* create(int64_t sz) { + RpcMemPool* pool = NULL; + Link* link = (Link*)direct_alloc(sizeof(Link) + sizeof(RpcMemPool) + sz); + if (NULL != link) { + pool = (RpcMemPool*)(link + 1); + new(pool)RpcMemPool(); + pool->add_link(link); + } + return pool; + } + void* alloc(int64_t sz) { + void* ret = NULL; + Link* link = (Link*)direct_alloc(sizeof(Link) + sz); + if (NULL != link) { + add_link(link); + ret = (void*)(link + 1); + } + return ret; + } + void destroy() { + Link* cur = tail_; + while(NULL != cur) { + Link* next = cur->next_; + direct_free(cur); + cur = next; + } + } +private: + static void* direct_alloc(int64_t sz) { return ::malloc(sz); } + static void direct_free(void* p) { ::free(p); } + void add_link(Link* link) { + link->next_ = tail_; + tail_ = link; + } +private: + Link* tail_; +}; diff --git a/deps/oblib/src/rpc/pnio/cpp/sync_resp_cb.h b/deps/oblib/src/rpc/pnio/cpp/sync_resp_cb.h new file mode 100644 index 000000000..ed615972a --- /dev/null +++ b/deps/oblib/src/rpc/pnio/cpp/sync_resp_cb.h @@ -0,0 +1,30 @@ +#pragma once +#include "ready_flag.h" +class SyncRespCallback: public IRespHandler +{ +public: + SyncRespCallback(IMemPool* pool): IRespHandler(pool), buf_(NULL), sz_(0) {} + virtual ~SyncRespCallback() {} + static SyncRespCallback* create() { + IMemPool* pool = RpcMemPool::create(0); + SyncRespCallback* cb = (typeof(cb))pool->alloc(sizeof(*cb)); + return new(cb)SyncRespCallback(pool); + } + int handle_resp(int io_err, const char* buf, int64_t sz) { + if (NULL != buf && NULL != (buf_ = (char*)alloc(sz))) { + memcpy(buf_, buf, sz); + sz_ = sz; + } + ready_.set_ready(); + return 0; + } + const char* wait(int64_t& sz) { + ready_.wait_ready(); + sz = sz_; + return buf_; + } +private: + RespReadyFlag ready_; + char* buf_; + int64_t sz_; +}; diff --git a/deps/oblib/src/rpc/pnio/ds/counter.h b/deps/oblib/src/rpc/pnio/ds/counter.h new file mode 100644 index 000000000..8103b389b --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/counter.h @@ -0,0 +1,26 @@ +struct thread_node_t +{ + link_t link; + pthread_t pd; +}; + +static link_t* global_thread_list = NULL; +static void thread_counter_reg() +{ + static __thread struct thread_node_t thread_node; + thread_node.pd = pthread_self(); + thread_node.link.next = NULL; + link_t* head = TAS(&global_thread_list, &thread_node.link); + thread_node.link.next = head; +} + +static int64_t thread_counter_sum(int64_t* addr) +{ + int64_t s = 0; + uint64_t offset = (uint64_t)addr - (uint64_t)pthread_self(); + for(link_t* p = global_thread_list; p; p = p->next) { + struct thread_node_t* node = structof(p, struct thread_node_t, link); + s += *(int64_t*)((uint64_t)node->pd + offset); + } + return s; +} diff --git a/deps/oblib/src/rpc/pnio/ds/dlink.c b/deps/oblib/src/rpc/pnio/ds/dlink.c new file mode 100644 index 000000000..95eb1154c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/dlink.c @@ -0,0 +1,6 @@ +extern inline bool dlink_is_empty(dlink_t* n); +extern inline void dlink_init(dlink_t* n); +extern inline void __dlink_insert(dlink_t* prev, dlink_t* next, dlink_t* n); +extern inline void __dlink_delete(dlink_t* prev, dlink_t* next); +extern inline void dlink_insert(dlink_t* head, dlink_t* n); +extern inline void dlink_delete(dlink_t* n);; diff --git a/deps/oblib/src/rpc/pnio/ds/dlink.h b/deps/oblib/src/rpc/pnio/ds/dlink.h new file mode 100644 index 000000000..578e4618c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/dlink.h @@ -0,0 +1,36 @@ +typedef struct dlink_t { + struct dlink_t* prev; + struct dlink_t* next; +} dlink_t; + +inline bool dlink_is_empty(dlink_t* n) { return n->next == n; } + +inline void dlink_init(dlink_t* n) { + n->prev = n; + n->next = n; +} + +inline void __dlink_insert(dlink_t* prev, dlink_t* next, dlink_t* n) { + n->prev = prev; + n->next = next; + prev->next = n; + next->prev = n; +} + +inline void __dlink_delete(dlink_t* prev, dlink_t* next) { + prev->next = next; + next->prev = prev; +} + +inline void dlink_insert(dlink_t* head, dlink_t* n) { + __dlink_insert(head, head->next, n); +} + +inline void dlink_delete(dlink_t* n) { + if (n->next) { + __dlink_delete(n->prev, n->next); + n->next = NULL; + } +} + +#define dlink_for(head, p) for(dlink_t* p = (head)->next, *_np = p->next; p != (head); p = _np, _np = p->next) diff --git a/deps/oblib/src/rpc/pnio/ds/fixed_queue.c b/deps/oblib/src/rpc/pnio/ds/fixed_queue.c new file mode 100644 index 000000000..c4deb0795 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/fixed_queue.c @@ -0,0 +1,11 @@ +void fixed_queue_init(fixed_queue_t* q, void* buf, int64_t bytes) +{ + q->push = 0; + q->pop = 0; + q->data = (void**)buf; + q->capacity = bytes/sizeof(void*); + memset(buf, 0, bytes); +} + +extern int fixed_queue_push(fixed_queue_t* q, void* p); +extern void* fixed_queue_pop(fixed_queue_t* q); diff --git a/deps/oblib/src/rpc/pnio/ds/fixed_queue.h b/deps/oblib/src/rpc/pnio/ds/fixed_queue.h new file mode 100644 index 000000000..fce2c2dc4 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/fixed_queue.h @@ -0,0 +1,44 @@ +typedef struct fixed_queue_t { + void** data; + int64_t capacity; + int64_t push RK_CACHE_ALIGNED; + int64_t pop RK_CACHE_ALIGNED; +} fixed_queue_t; + +void fixed_queue_init(fixed_queue_t* q, void* buf, int64_t bytes); +inline int fixed_queue_push(fixed_queue_t* q, void* p) { + int err = -EAGAIN; + uint64_t push_limit = LOAD(&q->pop) + q->capacity; + uint64_t old_push = 0; + uint64_t push = LOAD(&q->push); + while((old_push = push) < push_limit + && old_push != (push = VCAS(&q->push, old_push, old_push + 1))) { + SPIN_PAUSE(); + } + if (push < push_limit) { + void** pdata = q->data + (push % q->capacity); + while(!BCAS(pdata, NULL, p)) { + SPIN_PAUSE(); + } + err = 0; + } + return err; +} + +inline void* fixed_queue_pop(fixed_queue_t* q) { + void* p = NULL; + uint64_t pop_limit = LOAD(&q->push); + uint64_t old_pop = 0; + uint64_t pop = LOAD(&q->pop); + while((old_pop = pop) < pop_limit + && old_pop != (pop = VCAS(&q->pop, old_pop, old_pop + 1))) { + SPIN_PAUSE(); + } + if (pop < pop_limit) { + void** pdata = q->data + (pop % q->capacity); + while(NULL == LOAD(pdata) || NULL == (p = TAS(pdata, NULL))) { + SPIN_PAUSE(); + } + } + return p; +} diff --git a/deps/oblib/src/rpc/pnio/ds/fixed_stack.c b/deps/oblib/src/rpc/pnio/ds/fixed_stack.c new file mode 100644 index 000000000..02168b971 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/fixed_stack.c @@ -0,0 +1,7 @@ +void fixed_stack_init(fixed_stack_t* stk) +{ + stk->top_ = 0; + memset(stk->array_, 0, sizeof(stk->array_)); +} +extern int fixed_stack_push(fixed_stack_t* stk, void* p); +extern void* fixed_stack_pop(fixed_stack_t* stk); diff --git a/deps/oblib/src/rpc/pnio/ds/fixed_stack.h b/deps/oblib/src/rpc/pnio/ds/fixed_stack.h new file mode 100644 index 000000000..f900ace92 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/fixed_stack.h @@ -0,0 +1,53 @@ +typedef struct fixed_stack_t +{ + int top_; + void* array_[4]; +} fixed_stack_t; + +extern void fixed_stack_init(fixed_stack_t* stk); + +int inc_bounded(int* addr, int limit) +{ + int nv = LOAD(addr); + int ov = 0; + while((ov = nv) < limit && ov != (nv = VCAS(addr, ov, ov + 1))) { + SPIN_PAUSE(); + } + return ov; +} + +int dec_bounded(int* addr, int limit) +{ + int nv = LOAD(addr); + int ov = 0; + while((ov = nv) > limit && ov != (nv = VCAS(addr, ov, ov - 1))) { + SPIN_PAUSE(); + } + return ov; +} + +inline int fixed_stack_push(fixed_stack_t* stk, void* p) +{ + int limit = arrlen(stk->array_); + int top = inc_bounded(&stk->top_, limit); + if (top < limit) { + void** pdata = stk->array_ + top; + while(!BCAS(pdata, NULL, p)) { + SPIN_PAUSE(); + } + } + return top < limit? 0: -EAGAIN; +} + +inline void* fixed_stack_pop(fixed_stack_t* stk) +{ + void* p = NULL; + int top = dec_bounded(&stk->top_, 0); + if (top > 0) { + void** pdata = stk->array_ + top - 1; + while(NULL == LOAD(pdata) || NULL == (p = TAS(pdata, NULL))) { + SPIN_PAUSE(); + } + } + return p; +} diff --git a/deps/oblib/src/rpc/pnio/ds/hash.c b/deps/oblib/src/rpc/pnio/ds/hash.c new file mode 100644 index 000000000..eb57299a4 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/hash.c @@ -0,0 +1,42 @@ +#define __fhmix(h) ({ \ + (h) ^= (h) >> 23; \ + (h) *= 0x2127599bf4325c37ULL; \ + (h) ^= (h) >> 47; }) + +uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) +{ + const uint64_t m = 0x880355f21e6d1965ULL; + const uint64_t *pos = (const uint64_t *)buf; + const uint64_t *end = pos + (len / 8); + const unsigned char *pos2; + uint64_t h = seed ^ (len * m); + uint64_t v; + + while (pos != end) { + v = *pos++; + h ^= __fhmix(v); + h *= m; + } + + pos2 = (const unsigned char*)pos; + v = 0; + + switch (len & 7) { + case 7: v ^= (uint64_t)pos2[6] << 48; + // fall through + case 6: v ^= (uint64_t)pos2[5] << 40; + // fall through + case 5: v ^= (uint64_t)pos2[4] << 32; + // fall through + case 4: v ^= (uint64_t)pos2[3] << 24; + // fall through + case 3: v ^= (uint64_t)pos2[2] << 16; + // fall through + case 2: v ^= (uint64_t)pos2[1] << 8; + // fall through + case 1: v ^= (uint64_t)pos2[0]; + h ^= __fhmix(v); + h *= m; + } + return __fhmix(h); +} diff --git a/deps/oblib/src/rpc/pnio/ds/hash.h b/deps/oblib/src/rpc/pnio/ds/hash.h new file mode 100644 index 000000000..2f0687876 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/hash.h @@ -0,0 +1 @@ +extern uint64_t fasthash64(const void *buf, size_t len, uint64_t seed); diff --git a/deps/oblib/src/rpc/pnio/ds/hash_map.c b/deps/oblib/src/rpc/pnio/ds/hash_map.c new file mode 100644 index 000000000..fca16cf9c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/hash_map.c @@ -0,0 +1,51 @@ +hash_t* hash_create(int64_t capacity) { + int64_t alloc_size = sizeof(hash_t) + capacity * sizeof(link_t); + hash_t* p = (hash_t*)malloc(alloc_size); + hash_init(p, capacity); + return p; +} + +void hash_init(hash_t* h, int64_t capacity) { + h->capacity = capacity; + memset(&h->table, 0, sizeof(link_t) * capacity); +} + +static uint64_t __hash_calc(link_t* k) { return str_hash((str_t*)(k + 1)); } +static link_t* __hash_locate(hash_t* map, link_t* k) { return &map->table[__hash_calc(k) % map->capacity]; } +static int __hash_cmp(link_t* s1, link_t* s2) { return str_cmp((str_t*)(s1 + 1), (str_t*)(s2 + 1)); } +static link_t* __hash_list_search(link_t* start, link_t* k, link_t** prev) { + link_t* p = start; + int cmp = -1; + while(p->next != NULL && (cmp = __hash_cmp(k, p->next)) > 0) { + p = p->next; + } + if (NULL != prev) { + *prev = p; + } + return 0 == cmp? p->next: NULL; +} + +link_t* pnio_hash_insert(hash_t* map, link_t* k) { + link_t* prev = NULL; + if(!__hash_list_search(__hash_locate(map, k), k, &prev)) { + link_insert(prev, k); + } else { + k = NULL; + } + return k; +} + +link_t* hash_del(hash_t* map, str_t* k) { + link_t* ret = NULL; + link_t* klink = (link_t*)k - 1; + link_t* prev = NULL; + if((ret = __hash_list_search(__hash_locate(map, klink), klink, &prev))) { + link_delete(prev); + } + return ret; +} + +link_t* hash_get(hash_t* map, str_t* k) { + link_t* klink = (link_t*)k - 1; + return __hash_list_search(__hash_locate(map, klink), klink, NULL); +} diff --git a/deps/oblib/src/rpc/pnio/ds/hash_map.h b/deps/oblib/src/rpc/pnio/ds/hash_map.h new file mode 100644 index 000000000..ad62ab4b7 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/hash_map.h @@ -0,0 +1,10 @@ +typedef struct hash_t { + int64_t capacity; + link_t table[0]; +} hash_t; + +extern hash_t* hash_create(int64_t capacity); +extern void hash_init(hash_t* h, int64_t capacity); +extern link_t* hash_insert(hash_t* map, link_t* k); +extern link_t* hash_del(hash_t* map, str_t* k); +extern link_t* hash_get(hash_t* map, str_t* k); diff --git a/deps/oblib/src/rpc/pnio/ds/id_map.c b/deps/oblib/src/rpc/pnio/ds/id_map.c new file mode 100644 index 000000000..472264803 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/id_map.c @@ -0,0 +1,32 @@ +static idm_item_t* idm_locate(idm_t* idm, uint64_t id) { return idm->table + (id % idm->capacity); } +static void idm_item_recycle(idm_item_t* item, uint64_t capacity) { + item->data = NULL; + item->id += capacity; +} + +extern void* idm_get(idm_t* idm, uint64_t id); +void idm_init(idm_t* idm, int64_t capacity) { + idm->capacity = capacity; + memset(idm->table, 0, sizeof(idm_item_t) * capacity); + for(int64_t i = 0; i < capacity; i++) { + idm_item_t* pi = idm_locate(idm, i); + pi->id = i; + link_insert(&idm->free_list, &pi->link); + } +} + +uint64_t idm_set(idm_t* idm, void* data) { + link_t* link = link_pop(&idm->free_list); + if (link) { + idm_item_t* item = structof(link, idm_item_t, link); + item->data = data; + return item->id; + } + return UINT64_MAX; +} + +void idm_del(idm_t* idm, uint64_t id) { + idm_item_t* item = idm_locate(idm, id); + idm_item_recycle(item, idm->capacity); + link_insert(&idm->free_list, &item->link); +} diff --git a/deps/oblib/src/rpc/pnio/ds/id_map.h b/deps/oblib/src/rpc/pnio/ds/id_map.h new file mode 100644 index 000000000..666e24b69 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/id_map.h @@ -0,0 +1,18 @@ +typedef struct idm_item_t { + link_t link; + uint64_t id; + void* data; +} idm_item_t; +typedef struct idm_t { + uint64_t capacity; + link_t free_list; + idm_item_t table[0]; +} idm_t; + +extern void idm_init(idm_t* idm, int64_t capacity); +inline void* idm_get(idm_t* idm, uint64_t id) { + idm_item_t* pi = idm->table + (id % idm->capacity); + return id == pi->id? pi->data: NULL; +} +extern uint64_t idm_set(idm_t* idm, void* data); +extern void idm_del(idm_t* idm, uint64_t id); diff --git a/deps/oblib/src/rpc/pnio/ds/ihash_map.c b/deps/oblib/src/rpc/pnio/ds/ihash_map.c new file mode 100644 index 000000000..ceebcdf7e --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/ihash_map.c @@ -0,0 +1,37 @@ +static uint64_t __ihash_calc(uint64_t k) { return fasthash64(&k, sizeof(k), 0); } +static link_t* __ihash_locate(hash_t* map, uint64_t k) { return &map->table[__ihash_calc(k) % map->capacity]; } +static uint64_t __ihash_key(link_t* l) { return *(uint64_t*)(l + 1); } +static link_t* __ihash_list_search(link_t* start, uint64_t k, link_t** prev) { + link_t* p = start; + while(p->next != NULL && __ihash_key(p->next) != k) { + p = p->next; + } + if (NULL != prev) { + *prev = p; + } + return p->next; +} + +link_t* ihash_insert(hash_t* map, link_t* klink) { + link_t* prev = NULL; + uint64_t k = __ihash_key(klink); + if(!__ihash_list_search(__ihash_locate(map, k), k, &prev)) { + link_insert(prev, klink); + } else { + klink = NULL; + } + return klink; +} + +link_t* ihash_del(hash_t* map, uint64_t k) { + link_t* ret = NULL; + link_t* prev = NULL; + if((ret = __ihash_list_search(__ihash_locate(map, k), k, &prev))) { + link_delete(prev); + } + return ret; +} + +link_t* ihash_get(hash_t* map, uint64_t k) { + return __ihash_list_search(__ihash_locate(map, k), k, NULL); +} diff --git a/deps/oblib/src/rpc/pnio/ds/ihash_map.h b/deps/oblib/src/rpc/pnio/ds/ihash_map.h new file mode 100644 index 000000000..e9bc839a7 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/ihash_map.h @@ -0,0 +1,3 @@ +extern link_t* ihash_insert(hash_t* map, link_t* k); +extern link_t* ihash_del(hash_t* map, uint64_t k); +extern link_t* ihash_get(hash_t* map, uint64_t k); diff --git a/deps/oblib/src/rpc/pnio/ds/link-queue.h b/deps/oblib/src/rpc/pnio/ds/link-queue.h new file mode 100644 index 000000000..c5d409ed9 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/link-queue.h @@ -0,0 +1,49 @@ +typedef struct link_queue_t +{ + link_t *head_ RK_CACHE_ALIGNED; + link_t *tail_ RK_CACHE_ALIGNED; + link_t dummy_ RK_CACHE_ALIGNED; +} link_queue_t; + +static void link_queue_init(link_queue_t* q) +{ + q->head_ = &q->dummy_; + q->tail_ = &q->dummy_; +} + +static link_t* link_queue_do_pop(link_queue_t* q) +{ + link_t* ret = NULL; + link_t* head = NULL; + while(NULL == (head = TAS(&q->head_, NULL))) { + SPIN_PAUSE(); + } + if (head == LOAD(&q->tail_)) { + STORE(&q->head_, head); + } else { + link_t* next = NULL; + while(NULL == (next = LOAD(&head->next))) { + SPIN_PAUSE(); + } + STORE(&q->head_, next); + ret = head; + } + return ret; +} + +static void link_queue_push(link_queue_t *q, link_t* p) +{ + link_t *tail = NULL; + p->next = NULL; + tail = TAS(&q->tail_, p); + STORE(&tail->next, p); +} + +static link_t* link_queue_pop(link_queue_t *q) +{ + link_t* ret = NULL; + while(NULL != (ret = link_queue_do_pop(q)) && ret == &q->dummy_) { + link_queue_push(q, &q->dummy_); + } + return ret; +} diff --git a/deps/oblib/src/rpc/pnio/ds/link.c b/deps/oblib/src/rpc/pnio/ds/link.c new file mode 100644 index 000000000..38a44927f --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/link.c @@ -0,0 +1,5 @@ +extern inline void link_init(link_t* n); +extern inline bool link_is_empty(link_t* n); +extern inline link_t* link_insert(link_t* prev, link_t* t); +extern inline link_t* link_delete(link_t* prev); +extern link_t* link_pop(link_t* h); diff --git a/deps/oblib/src/rpc/pnio/ds/link.h b/deps/oblib/src/rpc/pnio/ds/link.h new file mode 100644 index 000000000..50246af55 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/link.h @@ -0,0 +1,31 @@ +typedef struct link_t { + struct link_t* next; +} link_t; + +inline void link_init(link_t* n) { + n->next = n; +} + +inline bool link_is_empty(link_t* n) { + return n->next == n; +} + +inline link_t* link_insert(link_t* prev, link_t* t) { + t->next = prev->next; + return prev->next = t; +} + +inline link_t* link_delete(link_t* prev) { + link_t* next = prev->next; + prev->next = next->next; + return next; +} + +inline link_t* link_pop(link_t* h) { + link_t* ret = h->next; + if (ret) { + h->next = ret->next; + } + return ret; +} +#define link_for_each(h, n) for(link_t *lpi = h, *n = NULL; lpi && (n = lpi->next, 1); lpi = n) diff --git a/deps/oblib/src/rpc/pnio/ds/queue.c b/deps/oblib/src/rpc/pnio/ds/queue.c new file mode 100644 index 000000000..4506f9829 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/queue.c @@ -0,0 +1,10 @@ +void queue_init(queue_t* q) { + q->head.next = NULL; + q->tail = &q->head; +} + +extern void queue_push(queue_t* q, link_t* n); +extern link_t* queue_pop(queue_t* q); +extern link_t* queue_top(queue_t* q); +extern bool queue_empty(queue_t* q); +extern void queue_set(queue_t* q, link_t* n); diff --git a/deps/oblib/src/rpc/pnio/ds/queue.h b/deps/oblib/src/rpc/pnio/ds/queue.h new file mode 100644 index 000000000..d3d4fa1a8 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/queue.h @@ -0,0 +1,31 @@ +typedef struct queue_t { + link_t head; + link_t* tail; +} queue_t; + +extern void queue_init(queue_t* q); +inline void queue_push(queue_t* q, link_t* n) { + q->tail = link_insert(q->tail, n); +} + +inline link_t* queue_top(queue_t* q) { + return q->head.next; +} + +inline bool queue_empty(queue_t* q) { return NULL == queue_top(q); } +inline void queue_set(queue_t* q, link_t* n) { + if (!(q->head.next = n)) { + q->tail = &q->head; + } +} + +inline link_t* queue_pop(queue_t* q) { + link_t* n = queue_top(q); + if (n) { + q->head.next = n->next; + if (q->tail == n) { + q->tail = &q->head; + } + } + return n; +} diff --git a/deps/oblib/src/rpc/pnio/ds/sc_queue.c b/deps/oblib/src/rpc/pnio/ds/sc_queue.c new file mode 100644 index 000000000..277e32814 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/sc_queue.c @@ -0,0 +1,21 @@ +void sc_queue_init(sc_queue_t* q) { + q->head.next = NULL; + q->tail = &q->head; + q->cnt = 0; + q->sz = 0; +} + +extern str_t* sfl(link_t* l); +int64_t sc_queue_inc(sc_queue_t* q, link_t* n, int64_t* ret_cnt, int64_t* ret_sz) { + *ret_cnt = AAF(&q->cnt, 1); + *ret_sz = AAF(&q->sz, sfl(n)->s); + return *ret_cnt; +} +void sc_queue_dec(sc_queue_t* q, link_t* n) { + FAA(&q->cnt, -1); + FAA(&q->sz, -sfl(n)->s); +} + +extern link_t* sc_queue_top(sc_queue_t* q); +extern bool sc_queue_push(sc_queue_t* q, link_t* n); +extern link_t* sc_queue_pop(sc_queue_t* q); diff --git a/deps/oblib/src/rpc/pnio/ds/sc_queue.h b/deps/oblib/src/rpc/pnio/ds/sc_queue.h new file mode 100644 index 000000000..2049bcf09 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/sc_queue.h @@ -0,0 +1,42 @@ +typedef struct sc_queue_t { + link_t head RK_CACHE_ALIGNED; + link_t* tail RK_CACHE_ALIGNED; + int64_t cnt RK_CACHE_ALIGNED; + int64_t sz RK_CACHE_ALIGNED; +} sc_queue_t; + +extern void sc_queue_init(sc_queue_t* q); +inline link_t* sc_queue_top(sc_queue_t* q) { + return LOAD(&q->head.next); +} + +int64_t sc_queue_inc(sc_queue_t* q, link_t* n, int64_t* ret_cnt, int64_t* ret_sz); +void sc_queue_dec(sc_queue_t* q, link_t* n); +inline bool sc_queue_push(sc_queue_t* q, link_t* n) { + n->next = NULL; + link_t* ot = TAS(&q->tail, n); + STORE(&ot->next, n); + return ot == &q->head; +} + +inline link_t* sc_queue_pop(sc_queue_t* q) { + link_t* ret = sc_queue_top(q); + if (NULL != ret) { + sc_queue_dec(q, ret); + link_t* next = LOAD(&ret->next); + if (NULL != next) { + STORE(&q->head.next, next); + } else { + if (BCAS(&q->tail, ret, &q->head)) { + // 此处无论成功失败与否都符合预期。如果成功,代表没有push竞争,更新顺利,失败代表有push竞争,无需更新 + BCAS(&q->head.next, ret, NULL); + } else { + while(NULL == (next = LOAD(&ret->next))) { + SPIN_PAUSE(); + } + STORE(&q->head.next, next); + } + } + } + return ret; +} diff --git a/deps/oblib/src/rpc/pnio/ds/str_type.c b/deps/oblib/src/rpc/pnio/ds/str_type.c new file mode 100644 index 000000000..3208f361b --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/str_type.c @@ -0,0 +1,2 @@ +extern inline int64_t str_hash(str_t* s); +extern inline int str_cmp(str_t* s1, str_t* s2); diff --git a/deps/oblib/src/rpc/pnio/ds/str_type.h b/deps/oblib/src/rpc/pnio/ds/str_type.h new file mode 100644 index 000000000..43eceea2f --- /dev/null +++ b/deps/oblib/src/rpc/pnio/ds/str_type.h @@ -0,0 +1,10 @@ +typedef struct str_t { + int64_t s; + char b[0]; +} str_t; +inline int64_t str_hash(str_t* s) { return fasthash64(s->b, s->s, 0); } +inline int str_cmp(str_t* s1, str_t* s2) { + int cmp = memcmp(s1->b, s2->b, rk_min(s1->s, s2->s)); + if (!cmp) return cmp; + return s1->s - s2->s; +} diff --git a/deps/oblib/src/rpc/pnio/gen-ns.py b/deps/oblib/src/rpc/pnio/gen-ns.py new file mode 100755 index 000000000..192a75464 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/gen-ns.py @@ -0,0 +1,23 @@ +#!/bin/env python2 +''' +cat a.h b.h | ./gen-ns.py > ns.h +''' +import re +import sys + +def help(): print __doc__ +not sys.stdin.isatty() or help() or sys.exit() + +symlist = set(re.findall('my_([_a-zA-Z0-9]+)', sys.stdin.read())) +def_list = ['#define my_%s tns(_%s)'%(s, s) for s in symlist] +undef_list = ['#undef my_%s'%(s) for s in symlist] +print ''' +#ifndef __ns__ +#define __ns__ +%s +#else +#undef __ns__ +#undef tns +%s +#endif +''' %('\n'.join(def_list), '\n'.join(undef_list)) diff --git a/deps/oblib/src/rpc/pnio/interface/group.c b/deps/oblib/src/rpc/pnio/interface/group.c new file mode 100644 index 000000000..00db7ad64 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/interface/group.c @@ -0,0 +1,477 @@ +#include +#define MAX_PN_LISTEN 256 +#define MAX_PN_GRP (1<<17) +#define MAX_PN_PER_GRP 64 +#ifdef PERF_MODE +#define CHUNK_SIZE ((1<<21) - (17<<10)) +#else +#define CHUNK_SIZE (1<<14) - 128 +#endif + +typedef struct pn_listen_t +{ + listen_t l; + serve_cb_t serve_cb; + pthread_t pd; +} pn_listen_t; + +struct pn_t; +typedef struct pn_grp_t +{ + int count; + struct pn_t* pn_array[MAX_PN_PER_GRP]; +} pn_grp_t; + +typedef struct pn_t +{ + pthread_t pd; + int accept_qfd; + eloop_t ep; + int gid; + int tid; + serve_cb_t serve_cb; + fifo_alloc_t server_ctx_alloc; + cfifo_alloc_t server_resp_alloc; + cfifo_alloc_t client_req_alloc; + cfifo_alloc_t client_cb_alloc; + chunk_cache_t server_ctx_chunk_alloc; + chunk_cache_t server_resp_chunk_alloc; + chunk_cache_t client_req_chunk_alloc; + chunk_cache_t client_cb_chunk_alloc; + pkts_t pkts; + pktc_t pktc; +} pn_t; + +static int next_pn_listen_idx; +static pn_listen_t pn_listen_array[MAX_PN_LISTEN]; +static pn_grp_t* pn_grp_array[MAX_PN_GRP]; +int64_t pnio_keepalive_timeout; +PN_API int64_t pn_set_keepalive_timeout(int64_t user_timeout) { + if (user_timeout >= 0) { + pnio_keepalive_timeout = user_timeout; + } + return pnio_keepalive_timeout; +} +static pn_listen_t* locate_listen(int idx) +{ + return pn_listen_array + idx; +} + +static void* listen_thread_func(void* arg) +{ + thread_counter_reg(); + prctl(PR_SET_NAME, "pnlisten"); + pn_listen_t* l = (typeof(l))arg; + eloop_run(&l->l.ep); + return NULL; +} + +static void* pn_thread_func(void* arg) +{ + thread_counter_reg(); + prctl(PR_SET_NAME, "pnio"); + pn_t* pn = (typeof(pn))arg; + eloop_run(&pn->ep); + return NULL; +} + +static int pnl_dispatch_accept(int fd, const void* b, int sz); +PN_API int pn_listen(int port, serve_cb_t cb) +{ + int idx = FAA(&next_pn_listen_idx, 1); + pn_listen_t* pnl = locate_listen(idx); + addr_t addr; + addr_init(&addr, "0.0.0.0", port); + if (listen_init(&pnl->l, addr, pnl_dispatch_accept) < 0) { + idx = -1; + } else { + pnl->serve_cb = cb; + pthread_create(&pnl->pd, NULL, listen_thread_func, pnl); + } + return idx; +} + +static pn_grp_t* create_grp() +{ + pn_grp_t* grp = (typeof(grp))salloc(sizeof(*grp)); + if (grp) { + memset(grp, 0, sizeof(*grp)); + } + return grp; +} + +static pn_grp_t* locate_grp(int gid) +{ + return pn_grp_array[gid]; +} + +static pn_grp_t* ensure_grp(int gid) +{ + pn_grp_t** pgrp = pn_grp_array + gid; + if (unlikely(NULL == *pgrp)) { + *pgrp = create_grp(); + } + return *pgrp; +} + +static int dispatch_fd_to(int fd, uint32_t gid, uint32_t tid) +{ + int err = 0; + pn_grp_t* grp = locate_grp(gid); + if (NULL == grp || grp->count == 0) { + err = -ENOENT; + } else { + pn_t* pn = grp->pn_array[tid % grp->count]; + int wbytes = 0; + while((wbytes = write(pn->accept_qfd, (const char*)&fd, sizeof(fd))) < 0 + && EINTR == errno); + if (wbytes != sizeof(fd)) { + err = -EIO; + } + } + return err; +} + +static int pnl_dispatch_accept(int fd, const void* b, int sz) +{ + int err = 0; + uint64_t dispatch_id = 0; + if ((uint64_t)sz < sizeof(dispatch_id)) { + // abort(); + err = dispatch_fd_to(fd, 1, 0); + } else { + dispatch_id = *(uint64_t*)b; + uint32_t gid = dispatch_id >> 32; + uint32_t tid = dispatch_id & ((1ULL<<32) - 1); + err = dispatch_fd_to(fd, gid, tid); + } + return err; +} + +static int pn_pkts_handle_func(pkts_t* pkts, void* req_handle, const char* b, int64_t s, uint64_t chid); + +static pn_t* pn_alloc() +{ + pn_t* pn = (typeof(pn))salloc(sizeof(*pn)); + if (pn) { + memset(pn, 0, sizeof(*pn)); + } + return pn; +} + +static void pn_destroy(pn_t* pn) +{ + if (pn->accept_qfd >= 0) { + close(pn->accept_qfd); + pn->accept_qfd = -1; + } + sfree(pn); +} + +static uint64_t calc_dispatch_id(uint32_t gid, uint32_t tid) +{ + return ((uint64_t)gid)<<32 | tid; +} + +static int pn_init_pkts(int listen_id, pn_t* pn) +{ + int err = 0; + int pfd[2] = {-1, -1}; + pkts_cfg_t cfg = {.handle_func = pn_pkts_handle_func }; + if (listen_id < 0) { + } else if (0 != pipe2(pfd, O_NONBLOCK|O_CLOEXEC)) { + err = errno; + } else { + pn->accept_qfd = pfd[1]; + cfg.accept_qfd = pfd[0]; + if (0 != (err = pkts_init(&pn->pkts, &pn->ep, &cfg))) { + } else { + pn_listen_t* pnl = locate_listen(listen_id); + pn->serve_cb = pnl->serve_cb; + } + } + return err; +} + +static pn_t* pn_create(int listen_id, int gid, int tid) +{ + int err = 0; + pn_t* pn = NULL; + if (NULL == (pn = pn_alloc())) { + } else if (0 != (err = eloop_init(&pn->ep))) { + } else if (0 != (err = pktc_init(&pn->pktc, &pn->ep, calc_dispatch_id(gid, tid)))) { + } else if (0 != (err = pn_init_pkts(listen_id, pn))) { + } else { + pn->gid = gid; + pn->tid = tid; + chunk_cache_init(&pn->server_ctx_chunk_alloc, CHUNK_SIZE, MOD_SERVER_CTX_CHUNK); + chunk_cache_init(&pn->server_resp_chunk_alloc, CHUNK_SIZE, MOD_SERVER_RESP_CHUNK); + chunk_cache_init(&pn->client_req_chunk_alloc, CHUNK_SIZE, MOD_CLIENT_REQ_CHUNK); + chunk_cache_init(&pn->client_cb_chunk_alloc, CHUNK_SIZE, MOD_CLIENT_CB_CHUNK); + + fifo_alloc_init(&pn->server_ctx_alloc, &pn->server_ctx_chunk_alloc); + cfifo_alloc_init(&pn->server_resp_alloc, &pn->server_resp_chunk_alloc); + cfifo_alloc_init(&pn->client_req_alloc, &pn->client_req_chunk_alloc); + cfifo_alloc_init(&pn->client_cb_alloc, &pn->client_cb_chunk_alloc); + } + if (0 != err && NULL != pn) { + pn_destroy(pn); + } + return pn; +} + + +PN_API int pn_provision(int listen_id, int gid, int thread_count) +{ + int err = 0; + int count = 0; + pn_grp_t* pn_grp = ensure_grp(gid); + ef(pn_grp == NULL); + count = pn_grp->count; + while(0 == err && count < thread_count) { + pn_t* pn = pn_create(listen_id, gid, count); + if (NULL == pn) { + err = ENOMEM; + } else if (0 != (err = pthread_create(&pn->pd, NULL, pn_thread_func, pn))) { + pn_destroy(pn); + } else { + pn_grp->pn_array[count++] = pn; + } + } + pn_grp->count = count; + while(pn_grp->count > thread_count) { + pn_destroy(pn_grp->pn_array[--pn_grp->count]); + } + return pn_grp->count; + el(); + return -1; +} + +typedef struct pn_pktc_cb_t +{ + pktc_cb_t cb; + client_cb_t client_cb; + void* arg; +} pn_pktc_cb_t; + +typedef struct pn_client_req_t +{ + pktc_req_t req; + easy_head_t head; +} pn_client_req_t; + +typedef struct pn_client_slice_t +{ + int64_t ref_; + pn_pktc_cb_t cb_; + pn_client_req_t req_; +} pn_client_slice_t; + +#ifdef PERF_MODE +static void pn_pktc_flush_cb(pktc_req_t* r) +{ + pn_client_req_t* pn_req = structof(r, pn_client_req_t, req); + pn_client_slice_t* slice = structof(pn_req, pn_client_slice_t, req_); + if (0 == --slice->ref_) { + pn_pktc_cb_t* pn_cb = &slice->cb_; + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_client_cb_count, eloop_client_cb_time)); + pn_cb->client_cb(pn_cb->arg, (&pn_cb->cb)->errcode, NULL, 0); + } +} + +static void pn_pktc_resp_cb(pktc_cb_t* cb, const char* resp, int64_t sz) +{ + pn_pktc_cb_t* pn_cb = structof(cb, pn_pktc_cb_t, cb); + pn_client_slice_t* slice = structof(pn_cb, pn_client_slice_t, cb_); + if (0 == ++slice->ref_) { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_client_cb_count, eloop_client_cb_time)); + pn_cb->client_cb(pn_cb->arg, cb->errcode, resp, sz); + } +} +#else +static void pn_pktc_flush_cb(pktc_req_t* r) +{ + pn_client_req_t* pn_req = structof(r, pn_client_req_t, req); + write_queue_t* wq = &r->sk->wq; + wq->categ_count_bucket[r->categ_id % arrlen(wq->categ_count_bucket)] --; + cfifo_free(pn_req); +} + +static void pn_pktc_resp_cb(pktc_cb_t* cb, const char* resp, int64_t sz) +{ + pn_pktc_cb_t* pn_cb = structof(cb, pn_pktc_cb_t, cb); + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_client_cb_count, eloop_client_cb_time)); + pn_cb->client_cb(pn_cb->arg, cb->errcode, resp, sz); + cfifo_free(pn_cb); +} +#endif + +static pktc_req_t* pn_create_pktc_req(pn_t* pn, uint64_t pkt_id, addr_t dest, const char* req, int64_t req_sz, int16_t categ_id, int64_t expire_us, client_cb_t client_cb, void* arg) +{ +#ifdef PERF_MODE + pn_client_slice_t* slice = ((typeof(slice))req) - 1; + if (unlikely(NULL == slice)) { + return NULL; + } + pn_client_req_t* pn_req = &slice->req_; + struct pn_pktc_cb_t* pn_cb = &slice->cb_; + slice->ref_ = 0; +#else + pn_client_req_t* pn_req = (typeof(pn_req))cfifo_alloc(&pn->client_req_alloc, sizeof(*pn_req) + req_sz); + if (unlikely(NULL == pn_req)) { + return NULL; + } + struct pn_pktc_cb_t* pn_cb = (typeof(pn_cb))cfifo_alloc(&pn->client_cb_alloc, sizeof(*pn_cb)); + if (unlikely(NULL == pn_cb)) { + cfifo_free(pn_req); + return NULL; + } +#endif + pktc_cb_t* cb = &pn_cb->cb; + pktc_req_t* r = &pn_req->req; + pn_cb->client_cb = client_cb; + pn_cb->arg = arg; + cb->id = pkt_id; + cb->expire_us = expire_us; + cb->resp_cb = pn_pktc_resp_cb; + cb->errcode = PNIO_OK; + r->flush_cb = pn_pktc_flush_cb; + r->resp_cb = cb; + r->dest = dest; + r->categ_id = categ_id; + eh_copy_msg(&r->msg, cb->id, req, req_sz); + return r; +} + +static uint64_t global_next_pkt_id; +static uint64_t gen_pkt_id() +{ + static __thread uint64_t next_pkt_id = 0; + if (0 == (next_pkt_id & 0xff)) { + next_pkt_id = FAA(&global_next_pkt_id, 256); + } + return next_pkt_id++; +} + +static pn_t* get_pn_for_send(pn_grp_t* pgrp, int tid) +{ + return pgrp->pn_array[tid % pgrp->count]; +} + +PN_API int pn_send(uint64_t gtid, struct sockaddr_in* addr, const char* buf, int64_t sz, int16_t categ_id, int64_t expire_us, client_cb_t cb, void* arg) +{ + int err = 0; + pn_grp_t* pgrp = locate_grp(gtid>>32); + pn_t* pn = get_pn_for_send(pgrp, gtid & 0xffffffff); + addr_t dest = {.ip=addr->sin_addr.s_addr, .port=htons(addr->sin_port), .tid=0}; + if (addr->sin_addr.s_addr == 0 || htons(addr->sin_port) == 0) { + err = -EINVAL; + rk_error("invalid sin_addr: %x:%d", addr->sin_addr.s_addr, addr->sin_port); + } + pktc_req_t* r = pn_create_pktc_req(pn, gen_pkt_id(), dest, buf, sz, categ_id, expire_us, cb, arg); + if (NULL == r) { + err = ENOMEM; + } else { + if (NULL != arg) { + *((void**)arg) = r; + } + err = pktc_post(&pn->pktc, r); + } + return err; +} + +typedef struct pn_resp_ctx_t +{ + pn_t* pn; + void* req_handle; + uint64_t sock_id; + uint64_t pkt_id; +#ifdef PERF_MODE + char reserve[1<<10]; +#else + char reserve[sizeof(pkts_req_t)]; +#endif +} pn_resp_ctx_t; + +static pn_resp_ctx_t* create_resp_ctx(pn_t* pn, void* req_handle, uint64_t sock_id, uint64_t pkt_id) +{ + int64_t gid = pn->tid; + unused(gid); + pn_resp_ctx_t* ctx = (typeof(ctx))fifo_alloc(&pn->server_ctx_alloc, sizeof(*ctx)); + if (ctx) { + ctx->pn = pn; + ctx->req_handle = req_handle; + ctx->sock_id = sock_id; + ctx->pkt_id = pkt_id; + } + return ctx; +} + +static int pn_pkts_handle_func(pkts_t* pkts, void* req_handle, const char* b, int64_t s, uint64_t chid) +{ + int err = 0; + uint64_t pkt_id = eh_packet_id(b); + pn_t* pn = structof(pkts, pn_t, pkts); + pn_resp_ctx_t* ctx = create_resp_ctx(pn, req_handle, chid, pkt_id); + if (NULL == ctx) { + rk_info("create_resp_ctx failed, errno = %d", errno); + } else { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_server_process_count, eloop_server_process_time)); + err = pn->serve_cb(pn->gid, b, s, (uint64_t)ctx); + } + return err; +} + +typedef struct pn_resp_t +{ + pn_resp_ctx_t* ctx; + pkts_req_t req; + easy_head_t head; +} pn_resp_t; + +static void pn_pkts_flush_cb_func(pkts_req_t* req) +{ + pn_resp_t* resp = structof(req, pn_resp_t, req); + if ((uint64_t)resp->ctx->reserve == (uint64_t)resp) { + fifo_free(resp->ctx); + } else { + fifo_free(resp->ctx); + cfifo_free(resp); + } +} + +static void pn_pkts_flush_cb_error_func(pkts_req_t* req) +{ + pn_resp_ctx_t* ctx = (typeof(ctx))structof(req, pn_resp_ctx_t, reserve); + fifo_free(ctx); +} + +PN_API int pn_resp(uint64_t req_id, const char* buf, int64_t sz) +{ + pn_resp_ctx_t* ctx = (typeof(ctx))req_id; +#ifdef PERF_MODE + ref_free(ctx->req_handle); +#endif + pn_resp_t* resp = NULL; + if (sizeof(pn_resp_t) + sz <= sizeof(ctx->reserve)) { + resp = (typeof(resp))(ctx->reserve); + } else { + resp = (typeof(resp))cfifo_alloc(&ctx->pn->server_resp_alloc, sizeof(*resp) + sz); + } + pkts_req_t* r = NULL; + if (NULL != resp) { + r = &resp->req; + resp->ctx = ctx; + r->errcode = 0; + r->flush_cb = pn_pkts_flush_cb_func; + r->sock_id = ctx->sock_id; + eh_copy_msg(&r->msg, ctx->pkt_id, buf, sz); + } else { + r = (typeof(r))(ctx->reserve); + r->errcode = ENOMEM; + r->flush_cb = pn_pkts_flush_cb_error_func; + r->sock_id = ctx->sock_id; + } + pkts_t* pkts = &ctx->pn->pkts; + return pkts_resp(pkts, r); +} diff --git a/deps/oblib/src/rpc/pnio/interface/group.h b/deps/oblib/src/rpc/pnio/interface/group.h new file mode 100644 index 000000000..23162c242 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/interface/group.h @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#ifndef PN_API +#define PN_API +#endif + +#ifndef PN_PKTC_ALLOC +#define pn_alloc_pktc_cb(arg, sz) malloc(sz) +#define pn_free_pktc_cb(cb) free(cb) +#define pn_alloc_pktc_req(arg, sz) malloc(sz) +#define pn_free_pktc_req(r) free(r) +#endif + +#ifndef PN_PKTS_ALLOC +#define pn_alloc_pkts_ctx(gid, sz) mod_alloc(sz, MOD_PKTS_RESP_CTX) +#define pn_free_pkts_ctx(ctx) mod_free(ctx) +#define pn_alloc_pkts_resp(ctx, sz) mod_alloc(sz, MOD_PKTS_RESP) +#define pn_free_pkts_resp(r) mod_free(r) +#endif + +typedef int (*serve_cb_t)(int grp, const char* b, int64_t sz, uint64_t req_id); +typedef int (*client_cb_t)(void* arg, int io_err, const char* b, int64_t sz); +PN_API int64_t pn_set_keepalive_timeout(int64_t user_timeout); +PN_API int pn_listen(int port, serve_cb_t cb); +// if listen_id == -1, act as client only +// make sure grp != 0 +PN_API int pn_provision(int listen_id, int grp, int thread_count); +// gid_tid = (gid<<8) | tid +PN_API int pn_send(uint64_t gid_tid, struct sockaddr_in* addr, const char* buf, int64_t sz, int16_t categ_id, int64_t expire_us, client_cb_t cb, void* arg); +PN_API int pn_resp(uint64_t req_id, const char* buf, int64_t sz); + +extern int64_t pnio_keepalive_timeout; + +#define PNIO_OK 0 +#define PNIO_DISCONNECT (-46) +#define PNIO_TIMEOUT (-47) +#define PNIO_CONNECT_FAIL (-49) + +/* +// 启动listen线程和epool线程池, epoll线程池有10个线程 +int listen_id = pn_listen(8042, cb); +pn_provision(listen_id, GRP_ID, 10); + +// client 发包 +pn_send((GRP_ID<<8) + tid, addr, req, sz, get_us() + 1000000, resp_cb, arg); + +// server处理 + int serve_cb(int grp, const char* b, int64_t sz, uint64_t req_id) { + //handle xxx + pn_resp(req_id, resp, sz); + } + */ diff --git a/deps/oblib/src/rpc/pnio/io/eloop.c b/deps/oblib/src/rpc/pnio/io/eloop.c new file mode 100644 index 000000000..52bf3b2f0 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/eloop.c @@ -0,0 +1,107 @@ +struct epoll_event *__make_epoll_event(struct epoll_event *event, uint32_t event_flag, void* val) { + event->events = event_flag; + event->data.ptr = val; + return event; +} + +int eloop_init(eloop_t* ep) { + ep->fd = epoll_create1(EPOLL_CLOEXEC); + dlink_init(&ep->ready_link); + return (ep->fd < 0)? errno: 0; +} + +int eloop_unregist(eloop_t* ep, sock_t* s) +{ + int err = 0; + if (0 != epoll_ctl(ep->fd, EPOLL_CTL_DEL, s->fd, NULL)) { + err = -EIO; + } else { + dlink_delete(&s->ready_link); + } + return err; +} + +int eloop_regist(eloop_t* ep, sock_t* s, uint32_t eflag) { + int err = 0; + struct epoll_event event; + uint32_t flag = eflag | EPOLLERR | EPOLLET; + s->mask = 0; + s->ready_link.next = NULL; + if (0 != epoll_ctl(ep->fd, EPOLL_CTL_ADD, s->fd, __make_epoll_event(&event, flag, s))) { + err = -EIO; + } else { + rk_info("sock regist: %p fd=%d", s, s->fd); + } + return err; +} + +void eloop_fire(eloop_t* ep, sock_t* s) { + if (!s->ready_link.next) { + dlink_insert(&ep->ready_link, &s->ready_link); + } else { + sks(s, PENDING); + } +} + +static void eloop_refire(eloop_t* ep, int64_t timeout) { + const int maxevents = 512; + struct epoll_event events[maxevents]; + int cnt = epoll_wait(ep->fd, events, maxevents, timeout); + for(int i = 0; i < cnt; i++) { + sock_t* s = (sock_t*)events[i].data.ptr; + s->mask |= events[i].events; + rk_debug("eloop fire: %p mask=%x", s, s->mask); + eloop_fire(ep, s); + } +} + +static void sock_destroy(sock_t* s) { + dlink_delete(&s->ready_link); + if (s->fd >= 0) { + close(s->fd); + } + if (s->fty) { + s->fty->destroy(s->fty, s); + } +} + +static void eloop_handle_sock_event(sock_t* s) { + int err = 0; + if (skt(s, ERR) || skt(s, HUP)) { + rk_info("sock destroy: sock=%p, connection=%s, err=%d", s, T2S(sock_fd, s->fd), err); + sock_destroy(s); + } else if (0 == (err = s->handle_event(s))) { + // yield + } else if (EAGAIN == err) { + if (skt(s, PENDING)) { + skc(s, PENDING); + } else { + rk_debug("sock sleep: %p", s); + dlink_delete(&s->ready_link); + } + } else { + rk_info("sock destroy: sock=%p, connection=%s, err=%d", s, T2S(sock_fd, s->fd), err); + sock_destroy(s); + } +} + +int eloop_thread_run(eloop_t** udata) { + return eloop_run(*udata); +} + +int eloop_run(eloop_t* ep) { + while(true) { + int64_t epoll_timeout = 1000; + if (ep->ready_link.next != &ep->ready_link) { + epoll_timeout = 0; // make sure all events handled when progarm is blocked in epoll_ctl + } + eloop_refire(ep, epoll_timeout); + PNIO_DELAY_WARN(reset_eloop_time_stat()); + PNIO_DELAY_WARN(int64_t start_us = rk_get_corse_us()); + dlink_for(&ep->ready_link, p) { + eloop_handle_sock_event(structof(p, sock_t, ready_link)); + } + PNIO_DELAY_WARN(eloop_delay_warn(start_us, ELOOP_WARN_US)); + } + return 0; +} diff --git a/deps/oblib/src/rpc/pnio/io/eloop.h b/deps/oblib/src/rpc/pnio/io/eloop.h new file mode 100644 index 000000000..45ccc961f --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/eloop.h @@ -0,0 +1,11 @@ +typedef struct eloop_t { + int fd; + dlink_t ready_link; +} eloop_t; + +extern int eloop_init(eloop_t* ep); +extern int eloop_thread_run(eloop_t** ep); +extern int eloop_run(eloop_t* ep); +extern int eloop_unregist(eloop_t* ep, sock_t* s); +extern int eloop_regist(eloop_t* ep, sock_t* s, uint32_t eflag); +extern void eloop_fire(eloop_t* ep, sock_t* s); diff --git a/deps/oblib/src/rpc/pnio/io/evfd.c b/deps/oblib/src/rpc/pnio/io/evfd.c new file mode 100644 index 000000000..8db4b4cb6 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/evfd.c @@ -0,0 +1,23 @@ +void evfd_signal(int fd) { + int64_t c = 1; + write(fd, &c, sizeof(c)); +} + +int evfd_drain(int fd) { + int64_t c = 0; + return (read(fd, (char*)&c, sizeof(c)) < 0 && EAGAIN != errno)? errno: 0; +} + +int evfd_init(eloop_t* ep, evfd_t* s, handle_event_t handle) { + int err = 0; + sk_init((sock_t*)s, NULL, (void*)handle, eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC)); + if (s->fd < 0) { + err = EIO; + } else { + err = eloop_regist(ep, (sock_t*)s, EPOLLIN); + } + if (0 != err && s->fd >= 0) { + close(s->fd); + } + return err; +} diff --git a/deps/oblib/src/rpc/pnio/io/evfd.h b/deps/oblib/src/rpc/pnio/io/evfd.h new file mode 100644 index 000000000..acddcc370 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/evfd.h @@ -0,0 +1,8 @@ +#include +typedef struct evfd_t { + SOCK_COMMON; +} evfd_t; + +extern void evfd_signal(int fd); +extern int evfd_drain(int fd); +extern int evfd_init(eloop_t* ep, evfd_t* s, handle_event_t handle); diff --git a/deps/oblib/src/rpc/pnio/io/ibuffer.c b/deps/oblib/src/rpc/pnio/io/ibuffer.c new file mode 100644 index 000000000..6ef8afba8 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/ibuffer.c @@ -0,0 +1,100 @@ +static int64_t MIN_IBUFFER_SIZE = (1<<21) - (1<<15); + +static void* ib_alloc(int64_t sz, int mod) { + return ref_alloc(sz, mod); +} + +void* ib_ref(ibuffer_t* ib) { + ib->cur_ref_++; + return ib->b; +} + +static void ib_retire(ibuffer_t* ib) { + int64_t* ref = (int64_t*)ib->b - 1; + if (0 == AAF(ref, ib->cur_ref_)) { + mod_free(ref); + } +} + +static void ib_reset(ibuffer_t* ib) { + ib->cur_ref_ = 0; + ib->limit = ib->b = ib->s = ib->e = NULL; +} + +void ib_init(ibuffer_t* ib, int mod) { + ib_reset(ib); + ib->mod = mod; +} + +static void ib_set(ibuffer_t* ib, char* b, int64_t limit, int64_t sz) { + ib->cur_ref_ = 0; + ib->b = b; + ib->s = b; + ib->e = b + sz; + ib->limit = b + limit; +} + +static int ib_create(ibuffer_t* ib, int64_t sz) { + char* nb = (char*)ib_alloc(sz, ib->mod); + if (nb) { + ib_set(ib, nb, sz, 0); + return 0; + } + return ENOMEM; +} + +static int ib_replace(ibuffer_t* ib, int64_t sz) { + int64_t remain = ib->e - ib->s; + char* nb = (char*)ib_alloc(sz, ib->mod); + if (nb) { + memcpy(nb, ib->s, remain); + ib_retire(ib); + ib_set(ib, nb, sz, remain); + return 0; + } + return ENOMEM; +} + +static int ib_prepare_buffer(ibuffer_t* ib, int64_t sz) { + int err = 0; + if (NULL == ib->b) { + err = ib_create(ib, rk_max(sz, MIN_IBUFFER_SIZE)); + } else if (sz > ib->limit - ib->s) { + err = ib_replace(ib, sz); + } + return err; +} + +static char* ib_read(ibuffer_t* ib, int64_t sz) { + if (ib->e >= ib->s + sz) { + return ib->s; + } + return NULL; +} + +void ib_consumed(ibuffer_t* ib, int64_t sz) { + ib->s += sz; + if (ib->limit <= ib->s) { + ib_retire(ib); + ib_reset(ib); + } +} + +void ib_destroy(ibuffer_t* ib) { + if (ib->b) { + ib_retire(ib); + } +} + +int sk_read_with_ib(void** ret, sock_t* s, ibuffer_t* ib, int64_t sz) { + int err = 0; + int64_t rbytes = 0; + ef(*ret = ib_read(ib, sz)); + ef(err = ib_prepare_buffer(ib, sz)); + ef(err = sk_read(s, ib->e, ib->limit - ib->e, &rbytes)); + ib->e += rbytes; + *ret = ib_read(ib, sz); + ef(err); + el(); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/io/ibuffer.h b/deps/oblib/src/rpc/pnio/io/ibuffer.h new file mode 100644 index 000000000..92543455a --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/ibuffer.h @@ -0,0 +1,15 @@ +typedef struct ibuffer_t { + int mod; + int64_t cur_ref_; + char* limit; + char* b; + char* s; + char* e; +} ibuffer_t; + +extern void ib_init(ibuffer_t* ib, int mod); +extern void ib_consumed(ibuffer_t* ib, int64_t sz); +extern int sk_read_with_ib(void** ret, sock_t* s, ibuffer_t* ib, int64_t sz); +extern void* ib_ref(ibuffer_t* ib); +extern void ib_ref_free(void* p); +extern void ib_destroy(ibuffer_t* ib); diff --git a/deps/oblib/src/rpc/pnio/io/io_func.c b/deps/oblib/src/rpc/pnio/io/io_func.c new file mode 100644 index 000000000..a1922f690 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/io_func.c @@ -0,0 +1,127 @@ +int make_fd_nonblocking(int fd) +{ + int err = 0; + int flags = 0; + if ((flags = fcntl(fd, F_GETFL, 0)) < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + err = -errno; + } + return err; +} + +bool is_pipe(int fd) { + struct stat st; + return 0 == fstat(fd, &st) && S_ISFIFO(st.st_mode); +} + +ssize_t uintr_pread(int fd, char* buf, int64_t size, int64_t offset) { + ssize_t cnt = 0; + while(cnt < size) { + ssize_t rbytes = pread(fd, buf + cnt, size - cnt, offset + cnt); + if (rbytes > 0) { + cnt += rbytes; + } else if (rbytes < 0) { + if (errno != EINTR) { + cnt = -1; + break; + } + } else { + break; + } + } + return cnt; +} + +ssize_t uintr_pwrite(int fd, const char* buf, int64_t size, int64_t offset) { + ssize_t cnt = 0; + while(cnt < size) { + ssize_t wbytes = pwrite(fd, buf + cnt, size - cnt, offset + cnt); + if (wbytes > 0) { + cnt += wbytes; + } else if (wbytes < 0) { + if (errno != EINTR) { + cnt = -1; + break; + } + } else { + break; + } + } + return cnt; +} + +ssize_t fsize(const char* path) { + ssize_t size = 0; + struct stat _stat; + if (NULL != path && 0 == stat(path, &_stat)) { + size = _stat.st_size; + } + return size; +} + +char* fmap(const char* path, int oflag, int64_t size) { + char* buf = NULL; + int fd = 0; + bool writable = O_RDONLY != oflag; + if (NULL != path && (fd = open(path, oflag, S_IRWXU|S_IRGRP)) >= 0) { + if (size < 0) { + size = fsize(path); + } else { + if (writable && 0 != ftruncate(fd, size)) { + size = -1; + } + } + if (size > 0) { + if (MAP_FAILED == (buf = (char*)mmap(NULL, size, PROT_READ|(writable? PROT_WRITE: 0), MAP_SHARED, fd, 0))) { + buf = NULL; + } + } + } + return buf; +} + +#ifndef RW_ERRSIM_FREQ +#define RW_ERRSIM_FREQ 100 +#endif +ssize_t uintr_read(int fd, char* buf, size_t size) { + ssize_t bytes = 0; +#ifdef PNIO_ERRSIM + int rand_value = rand(); + if (rand_value % RW_ERRSIM_FREQ == 0) { + rk_warn("uintr_read return 0. rand_value = %d\n", rand_value); + errno = EIO; + return bytes; + } +#endif + while((bytes = read(fd, buf, size)) < 0 && EINTR == errno) + ; + return bytes; +} + +ssize_t uintr_readv(int fd, struct iovec* iov, int cnt) { + ssize_t bytes = 0; + while((bytes = readv(fd, iov, cnt)) < 0 && EINTR == errno) + ; + return bytes; +} + +ssize_t uintr_write(int fd, const char* buf, size_t size) { + ssize_t bytes = 0; + while((bytes = write(fd, buf, size)) < 0 && EINTR == errno) + ; + return bytes; +} + +ssize_t uintr_writev(int fd, struct iovec* iov, int cnt) { + ssize_t bytes = 0; +#ifdef PNIO_ERRSIM + int rand_value = rand(); + if (rand_value % RW_ERRSIM_FREQ == 0) { + rk_warn("uintr_writev return 0. rand_value = %d\n", rand_value); + errno = EIO; + return bytes; + } +#endif + while((bytes = writev(fd, iov, cnt)) < 0 && EINTR == errno) + ; + return bytes; +} diff --git a/deps/oblib/src/rpc/pnio/io/io_func.h b/deps/oblib/src/rpc/pnio/io/io_func.h new file mode 100644 index 000000000..d79916599 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/io_func.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#include + +extern int make_fd_nonblocking(int fd); + +extern bool is_pipe(int fd); +extern int64_t fsize(const char* path); +extern char* fmap(const char* path, int oflag, int64_t size); +extern ssize_t uintr_pread(int fd, char* buf, int64_t size, int64_t offset); +extern ssize_t uintr_pwrite(int fd, const char* buf, int64_t size, int64_t offset); +extern ssize_t uintr_read(int fd, char* buf, size_t size); +extern ssize_t uintr_readv(int fd, struct iovec* iov, int cnt); +extern ssize_t uintr_write(int fd, const char* buf, size_t size); +extern ssize_t uintr_writev(int fd, struct iovec* iov, int cnt); diff --git a/deps/oblib/src/rpc/pnio/io/iov.c b/deps/oblib/src/rpc/pnio/io/iov.c new file mode 100644 index 000000000..19043b15a --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/iov.c @@ -0,0 +1,3 @@ +extern void iov_set(struct iovec* iov, char* b, int64_t s); +extern void iov_set_from_str(struct iovec* iov, str_t* s); +extern void iov_consume_one(struct iovec* iov, int64_t bytes); diff --git a/deps/oblib/src/rpc/pnio/io/iov.h b/deps/oblib/src/rpc/pnio/io/iov.h new file mode 100644 index 000000000..076e25794 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/iov.h @@ -0,0 +1,14 @@ +#include +inline void iov_set(struct iovec* iov, char* b, int64_t s) { + iov->iov_base = b; + iov->iov_len = s; +} + +inline void iov_set_from_str(struct iovec* iov, str_t* s) { + iov_set(iov, s->b, s->s); +} + +inline void iov_consume_one(struct iovec* iov, int64_t bytes) { + iov->iov_base = (void*)((uint64_t)iov->iov_base + bytes); + iov->iov_len -= bytes; +} diff --git a/deps/oblib/src/rpc/pnio/io/msg.c b/deps/oblib/src/rpc/pnio/io/msg.c new file mode 100644 index 000000000..abff7f478 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/msg.c @@ -0,0 +1 @@ +extern msg_t* msg_init(msg_t* m, const char* b, int64_t s); diff --git a/deps/oblib/src/rpc/pnio/io/msg.h b/deps/oblib/src/rpc/pnio/io/msg.h new file mode 100644 index 000000000..039a05648 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/msg.h @@ -0,0 +1,11 @@ +enum { MSG_LIMIT = 64 * 1024}; +typedef struct msg_t +{ + int64_t s; + char b[]; +} msg_t; +inline msg_t* msg_init(msg_t* m, const char* b, int64_t s) { + m->s = s + sizeof(msg_t); + memcpy(m->b, b, s); + return m; +} diff --git a/deps/oblib/src/rpc/pnio/io/sock.c b/deps/oblib/src/rpc/pnio/io/sock.c new file mode 100644 index 000000000..39ce8ce76 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/sock.c @@ -0,0 +1,14 @@ +extern inline void skset(sock_t* s, uint32_t m); +extern inline void skclear(sock_t* s, uint32_t m); +extern inline bool sktest(sock_t* s, uint32_t m); + +void sf_init(sf_t* sf, void* create, void* destroy) { + sf->create = (typeof(sf->create))create; + sf->destroy = (typeof(sf->destroy))destroy; +} + +void sk_init(sock_t* s, sf_t* sf, void* handle_event, int fd) { + s->fty = sf; + s->handle_event = (typeof(s->handle_event))handle_event; + s->fd = fd; +} diff --git a/deps/oblib/src/rpc/pnio/io/sock.h b/deps/oblib/src/rpc/pnio/io/sock.h new file mode 100644 index 000000000..7ef6b60a8 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/sock.h @@ -0,0 +1,34 @@ +#include +struct sock_t; +#define SOCK_FACTORY_COMMON \ + struct sock_t* (*create)(struct sf_t*); \ + void (*destroy)(struct sf_t*, struct sock_t*); + +typedef struct sf_t { + SOCK_FACTORY_COMMON; +} sf_t; + +typedef int (*handle_event_t)(struct sock_t*); +#define SOCK_COMMON \ + struct sf_t* fty; \ + handle_event_t handle_event; \ + dlink_t ready_link; \ + int fd; \ + uint32_t mask; \ + uint8_t conn_ok:1 + +typedef struct sock_t { + SOCK_COMMON; +} sock_t; + + +#define EPOLLPENDING EPOLLONESHOT +inline void skset(sock_t* s, uint32_t m) { s->mask |= m; } +inline void skclear(sock_t* s, uint32_t m){ s->mask &= ~m; } +inline bool sktest(sock_t* s, uint32_t m) { return s->mask & m; } +#define sks(s, flag) skset((sock_t*)s, EPOLL ## flag) +#define skt(s, flag) sktest((sock_t*)s, EPOLL ## flag) +#define skc(s, flag) skclear((sock_t*)s, EPOLL ## flag) + +extern void sf_init(sf_t* sf, void* create, void* destroy); +extern void sk_init(sock_t* s, sf_t* sf, void* handle_event, int fd); diff --git a/deps/oblib/src/rpc/pnio/io/sock_io.c b/deps/oblib/src/rpc/pnio/io/sock_io.c new file mode 100644 index 000000000..8c54b7362 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/sock_io.c @@ -0,0 +1,50 @@ +static int sk_translate_io_error(sock_t* s, int64_t bytes, uint32_t epbit) { + if (bytes > 0) { + return 0; + } else if (bytes < 0) { + if (EWOULDBLOCK == errno || EAGAIN == errno) { + skclear(s, epbit); + return EAGAIN; + } else { + return errno; + } + } else { + return ENODATA; + } +} + +static int sk_after_io(sock_t* s, const char* buf, int64_t bytes, uint32_t epbit) { + int ret = sk_translate_io_error(s, bytes, epbit); + //sk_check_io(&s->debug_check, buf, bytes, epbit); + return ret; +} +static int sk_after_iov(sock_t* s, struct iovec* iov, int cnt, int64_t bytes, uint32_t epbit) { + int ret = sk_translate_io_error(s, bytes, epbit); + //sk_check_iov(&s->debug_check, iov, cnt, bytes, epbit); + return ret; +} + +static int sk_after_read(sock_t* s, const char* buf, int64_t bytes) { return sk_after_io(s, buf, bytes, EPOLLIN); } +static int sk_after_write(sock_t* s, const char* buf, int64_t bytes) { return sk_after_io(s, buf, bytes, EPOLLOUT); } +static int sk_after_readv(sock_t* s, struct iovec* iov, int cnt, int64_t bytes) { return sk_after_iov(s, iov, cnt, bytes, EPOLLIN); } +static int sk_after_writev(sock_t* s, struct iovec* iov, int cnt, int64_t bytes) { return sk_after_iov(s, iov, cnt, bytes, EPOLLOUT); } + +int sk_read(sock_t* s, char* buf, size_t size, ssize_t* rbytes) { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_read_count, eloop_read_time)); + return sk_after_read(s, buf, (*rbytes = uintr_read(s->fd, buf, size))); +} + +int sk_readv(sock_t* s, struct iovec* iov, int cnt, ssize_t* rbytes) { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_read_count, eloop_read_time)); + return sk_after_readv(s, iov, cnt, (*rbytes = uintr_readv(s->fd, iov, cnt))); +} + +int sk_write(sock_t* s, const char* buf, size_t size, ssize_t* wbytes) { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_write_count, eloop_write_time)); + return sk_after_write(s, buf, (*wbytes = uintr_write(s->fd, buf, size))); +} + +int sk_writev(sock_t* s, struct iovec* iov, int cnt, ssize_t* wbytes) { + PNIO_DELAY_WARN(STAT_TIME_GUARD(eloop_write_count, eloop_write_time)); + return sk_after_writev(s, iov, cnt, (*wbytes = uintr_writev(s->fd, iov, cnt))); +} diff --git a/deps/oblib/src/rpc/pnio/io/sock_io.h b/deps/oblib/src/rpc/pnio/io/sock_io.h new file mode 100644 index 000000000..1dc305619 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/sock_io.h @@ -0,0 +1,4 @@ +extern int sk_read(sock_t* s, char* buf, size_t size, ssize_t* rbytes); +extern int sk_readv(sock_t* s, struct iovec* iov, int cnt, ssize_t* rbytes); +extern int sk_write(sock_t* s, const char* buf, size_t size, ssize_t* wbytes); +extern int sk_writev(sock_t* s, struct iovec* iov, int cnt, ssize_t* wbytes); diff --git a/deps/oblib/src/rpc/pnio/io/time_wheel.c b/deps/oblib/src/rpc/pnio/io/time_wheel.c new file mode 100644 index 000000000..98acea9a6 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/time_wheel.c @@ -0,0 +1,87 @@ + +static int64_t tw_align_time(int64_t us) { return us & ~(TIME_WHEEL_SLOT_INTERVAL - 1); } +static dlink_t* tw_get_slot(time_wheel_t* tw, int64_t us) { return tw->slot + (us/TIME_WHEEL_SLOT_INTERVAL) % TIME_WHEEL_SLOT_NUM; } +void tw_init(time_wheel_t* tw, timer_cb_t* cb) { + for(int i = 0; i < TIME_WHEEL_SLOT_NUM; i++) { + dlink_init(tw->slot + i); + } + tw->cb = cb; + tw->finished_us = tw_align_time(rk_get_corse_us()); +} + +static int64_t tw_get_expire_us(dlink_t* l) { return *(int64_t*)(l + 1); } +static void tw_fire(time_wheel_t* tw, dlink_t* l) { tw->cb(tw, l); } + +static int tw_check_node(time_wheel_t* tw, dlink_t* l) { + if (tw_get_expire_us(l) < tw->finished_us) { + dlink_delete(l); + tw_fire(tw, l); + return ETIMEDOUT; + } + return 0; +} + +int tw_regist(time_wheel_t* tw, dlink_t* l) { + dlink_insert(tw_get_slot(tw, tw_get_expire_us(l)), l); + return tw_check_node(tw, l); +} + +static void tw_sweep_slot(time_wheel_t* tw) { + dlink_t* slot = tw_get_slot(tw, tw->finished_us - TIME_WHEEL_SLOT_INTERVAL); + dlink_for(slot, p) { + tw_check_node(tw, p); + } +} + +void tw_check(time_wheel_t* tw) { + int64_t cur_us = rk_get_corse_us(); + while(tw->finished_us < cur_us) { + tw->finished_us += TIME_WHEEL_SLOT_INTERVAL; + tw_sweep_slot(tw);} +} + +extern int64_t pnio_keepalive_timeout; +bool pn_server_in_black(struct sockaddr* sa) {return 0;} +#ifndef SERVER_IN_BLACK +#define SERVER_IN_BLACK(sa) pn_server_in_black(sa) +#endif +void keepalive_check(pktc_t* io) { + static __thread int time_count = 0; + time_count ++; + if (time_count < (int)(1000000/TIME_WHEEL_SLOT_INTERVAL)) { + } else { + time_count = 0; + // walks through pktc_t skmap, refresh tcp keepalive params and check server keepalive + dlink_for(&io->sk_list, p) { + pktc_sk_t *sk = structof(p, pktc_sk_t, list_link); + struct sockaddr_in sin; + if (SERVER_IN_BLACK((struct sockaddr*)make_sockaddr(&sin, sk->dest))) { + // mark the socket as waiting for destroy + rk_info("socket dest server in blacklist, it will be destroyed, sock=(ptr=%p,dest=%d:%d)", sk, sk->dest.ip, sk->dest.port); + sk->mask |= EPOLLERR; + eloop_fire(io->ep, (sock_t*)sk); + } else if(sk->user_keepalive_timeout != pnio_keepalive_timeout) { + rk_info("user_keepalive_timeout has been reset, sock=(ptr=%p,dest=%d:%d), old=%ld, new=%ld", + sk, sk->dest.ip, sk->dest.port, sk->user_keepalive_timeout, pnio_keepalive_timeout); + update_socket_keepalive_params(sk->fd, pnio_keepalive_timeout); + sk->user_keepalive_timeout = pnio_keepalive_timeout; + } + } + } +} + +static int timerfd_handle_tw(timerfd_t* s) { + time_wheel_t* tw = (time_wheel_t*)(s + 1); + tw_check(tw); + evfd_drain(s->fd); + keepalive_check(structof(s, pktc_t, cb_timerfd)); + return EAGAIN; +} + +int timerfd_init_tw(eloop_t* ep, timerfd_t* s) { + int err = 0; + ef(err = timerfd_init(ep, s, (handle_event_t)timerfd_handle_tw)); + ef(err = timerfd_set_interval(s, TIME_WHEEL_SLOT_INTERVAL)); + el(); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/io/time_wheel.h b/deps/oblib/src/rpc/pnio/io/time_wheel.h new file mode 100644 index 000000000..3bfc95aac --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/time_wheel.h @@ -0,0 +1,13 @@ +#define TIME_WHEEL_SLOT_NUM (1<<16) +#define TIME_WHEEL_SLOT_INTERVAL 1024 +typedef struct time_wheel_t time_wheel_t; +typedef void (timer_cb_t)(time_wheel_t* tw, dlink_t* l); +typedef struct time_wheel_t { + timer_cb_t* cb; + int64_t finished_us; + dlink_t slot[TIME_WHEEL_SLOT_NUM]; +} time_wheel_t; +extern void tw_init(time_wheel_t* tw, timer_cb_t* cb); +extern int tw_regist(time_wheel_t* tw, dlink_t* l); +extern void tw_check(time_wheel_t* tw); +extern int timerfd_init_tw(eloop_t* ep, timerfd_t* s); diff --git a/deps/oblib/src/rpc/pnio/io/timerfd.c b/deps/oblib/src/rpc/pnio/io/timerfd.c new file mode 100644 index 000000000..4b81c29cd --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/timerfd.c @@ -0,0 +1,19 @@ +int timerfd_set_interval(timerfd_t* s, int64_t interval) { + rk_info("set interval: %ld", interval); + struct itimerspec it = {{interval/1000000, 1000 * (interval % 1000000)}, {0, 1}}; + return timerfd_settime(s->fd, 0, &it, NULL)? errno: 0; +} + +int timerfd_init(eloop_t* ep, timerfd_t* s, handle_event_t handle) { + int err = 0; + sk_init((sock_t*)s, NULL, (void*)handle, timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)); + if (s->fd < 0) { + err = EIO; + } else { + err = eloop_regist(ep, (sock_t*)s, EPOLLIN); + } + if (0 != err && s->fd >= 0) { + close(s->fd); + } + return err; +} diff --git a/deps/oblib/src/rpc/pnio/io/timerfd.h b/deps/oblib/src/rpc/pnio/io/timerfd.h new file mode 100644 index 000000000..df921f821 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/timerfd.h @@ -0,0 +1,7 @@ +#include +typedef struct timerfd_t { + SOCK_COMMON; +} timerfd_t; + +extern int timerfd_set_interval(timerfd_t* s, int64_t interval); +extern int timerfd_init(eloop_t* ep, timerfd_t* s, handle_event_t handle); diff --git a/deps/oblib/src/rpc/pnio/io/write_queue.c b/deps/oblib/src/rpc/pnio/io/write_queue.c new file mode 100644 index 000000000..ddb4d3a10 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/write_queue.c @@ -0,0 +1,79 @@ +str_t* sfl(link_t* l) { return (str_t*)(l+1); } +static int iov_from_blist(struct iovec* iov, int64_t limit, link_t* h) { + int cnt = 0; + for(; cnt < limit && h; h = h->next, cnt++) { + iov_set_from_str(iov + cnt, sfl(h)); + } + return cnt; +} + +static int sk_flush_blist(sock_t* s, link_t* h, int64_t last_pos, int64_t* wbytes) { + int err = 0; + struct iovec iov[64]; + int cnt = iov_from_blist(iov, arrlen(iov), h); + if (cnt > 0) { + iov_consume_one(iov, last_pos); + err = sk_writev(s, iov, cnt, wbytes); + } + return err; +} + +void wq_inc(write_queue_t* wq, link_t* l) { + int64_t bytes = sfl(l)->s; + wq->cnt ++; + wq->sz += bytes; +} + +void wq_dec(write_queue_t* wq, int64_t bytes) { + wq->cnt --; + wq->sz -= bytes; +} + +static link_t* wq_consume(write_queue_t* wq, int64_t bytes) { + int64_t s = 0; + link_t* top = queue_top(&wq->queue); + link_t* h = top; + if((s = sfl(h)->s - wq->pos) <= bytes) { + bytes -= s; + wq_dec(wq, sfl(h)->s); + h = h->next; + while(bytes > 0 && (s = sfl(h)->s) <= bytes) { + bytes -= s; + h = h->next; + wq_dec(wq, s); + } + wq->pos = bytes; + } else { + wq->pos += bytes; + } + queue_set(&wq->queue, h); + return top; +} + +void wq_init(write_queue_t* wq) { + queue_init(&wq->queue); + wq->pos = 0; + wq->cnt = 0; + wq->sz = 0; + memset(wq->categ_count_bucket, 0, sizeof(wq->categ_count_bucket)); +} + +inline void wq_push(write_queue_t* wq, link_t* l) { + str_t* msg = sfl(l); + wq_inc(wq, l); + queue_push(&wq->queue, l); +} + +int wq_flush(sock_t* s, write_queue_t* wq, link_t** old_head) { + int err = 0; + link_t* h = queue_top(&wq->queue); + if (NULL == h) { + return err; + } + int64_t wbytes = 0; + err = sk_flush_blist((sock_t*)s, h, wq->pos, &wbytes); + if (0 == err) { + *old_head = wq_consume(wq, wbytes); + } + return err; +} diff --git a/deps/oblib/src/rpc/pnio/io/write_queue.h b/deps/oblib/src/rpc/pnio/io/write_queue.h new file mode 100644 index 000000000..7fee2b3dd --- /dev/null +++ b/deps/oblib/src/rpc/pnio/io/write_queue.h @@ -0,0 +1,12 @@ +#define BUCKET_SIZE 1024 +typedef struct write_queue_t { + queue_t queue; + int64_t pos; + int64_t cnt; + int64_t sz; + int16_t categ_count_bucket[BUCKET_SIZE]; +} write_queue_t; + +extern void wq_init(write_queue_t* wq); +extern void wq_push(write_queue_t* wq, link_t* l); +extern int wq_flush(sock_t* s, write_queue_t* wq, link_t** old_head); diff --git a/deps/oblib/src/rpc/pnio/nio/addr.c b/deps/oblib/src/rpc/pnio/nio/addr.c new file mode 100644 index 000000000..b3ebb3193 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/addr.c @@ -0,0 +1,69 @@ + +const char* addr_str(format_t* f, addr_t addr) { + char buf[18]; + return format_sf(f, "%s:%hu", + inet_ntop(AF_INET, (struct in_addr*)(&addr.ip), buf, sizeof(buf)), addr.port); +} + +addr_t addr_build(const char* ip, int port) { + addr_t addr; + return *addr_init(&addr, ip, port); +} + +addr_t* addr_init(addr_t* addr, const char* ip, int port) { + *addr = (addr_t){inet_addr(ip), (uint16_t)port, 0}; + return addr; +} + +addr_t* addr_set(addr_t* addr, uint32_t ip, uint16_t port, uint16_t id) { + addr->ip = ip; + addr->port = port; + addr->tid = id; + return addr; +} + +void addr_reset(addr_t* addr) +{ + addr_set(addr, 0, 0, 0); +} + +addr_t get_remote_addr(int fd) { + addr_t addr; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + if (0 == getpeername(fd, (struct sockaddr*)&sa, &sa_len)) { + int ip = sa.sin_addr.s_addr; + int port = (int)ntohs(sa.sin_port); + addr_set(&addr, ip, (uint16_t)port, 0); + } else { + addr_reset(&addr); + } + return addr; +} + +addr_t get_local_addr(int fd) { + addr_t addr; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + if (0 == getsockname(fd, (struct sockaddr*)&sa, &sa_len)) { + int ip = sa.sin_addr.s_addr; + int port = (int)ntohs(sa.sin_port); + addr_set(&addr, ip, (uint16_t)port, 0); + } else { + addr_reset(&addr); + } + return addr; +} + +static struct sockaddr_in* rk_make_unix_sockaddr(struct sockaddr_in *sin, in_addr_t ip, int port) { + if (NULL != sin) { + sin->sin_port = (uint16_t)htons((uint16_t)port); + sin->sin_addr.s_addr = ip; + sin->sin_family = AF_INET; + } + return sin; +} + +struct sockaddr_in* make_sockaddr(struct sockaddr_in* sin, addr_t addr) { + return rk_make_unix_sockaddr(sin, addr.ip, addr.port); +} diff --git a/deps/oblib/src/rpc/pnio/nio/addr.h b/deps/oblib/src/rpc/pnio/nio/addr.h new file mode 100644 index 000000000..77a515c26 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/addr.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +typedef struct addr_t { + uint32_t ip; + uint16_t port; + uint16_t tid; +} addr_t; +extern const char* addr_str(format_t* f, addr_t addr); +extern addr_t addr_build(const char* ip, int port); +extern addr_t* addr_init(addr_t* addr, const char* ip, int port); +extern addr_t* addr_set(addr_t* addr, uint32_t ip, uint16_t port, uint16_t tid); + +extern struct sockaddr_in* make_sockaddr(struct sockaddr_in *sin, addr_t addr); +extern addr_t get_remote_addr(int fd); +extern addr_t get_local_addr(int fd); diff --git a/deps/oblib/src/rpc/pnio/nio/decode.t.h b/deps/oblib/src/rpc/pnio/nio/decode.t.h new file mode 100644 index 000000000..4bac044ee --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/decode.t.h @@ -0,0 +1,17 @@ +static int my_sk_do_decode(my_sk_t* s, my_msg_t* msg) { + int err = 0; + void* b = NULL; + int64_t sz = sizeof(easy_head_t); + int64_t req_sz = sz; + while(0 == (err = my_sk_read(&b, s, sz)) + && NULL != b && (req_sz = my_decode((char*)b, sz)) > 0 && req_sz > sz) { + sz = req_sz; + } + if (req_sz <= 0) { + err = EINVAL; + } + if (0 == err) { + *msg = (my_msg_t) { .sz = req_sz, .payload = (char*)b }; + } + return err; +} diff --git a/deps/oblib/src/rpc/pnio/nio/easy_head.c b/deps/oblib/src/rpc/pnio/nio/easy_head.c new file mode 100644 index 000000000..241a89936 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/easy_head.c @@ -0,0 +1,4 @@ +extern void eh_set(easy_head_t* h, uint32_t len, uint32_t pkt_id); +extern uint64_t eh_packet_id(const char* b); +extern int64_t eh_decode(char* b, int64_t s); +extern void eh_copy_msg(str_t* m, uint32_t pkt_id, const char* b, int64_t s); diff --git a/deps/oblib/src/rpc/pnio/nio/easy_head.h b/deps/oblib/src/rpc/pnio/nio/easy_head.h new file mode 100644 index 000000000..e495b68ee --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/easy_head.h @@ -0,0 +1,50 @@ +typedef struct easy_head_t +{ + uint32_t magic_; + uint32_t len_; + uint32_t pkt_id_; + uint32_t reserved_; +} easy_head_t; + +#define rk_bswap32 __builtin_bswap32 +#if PNIO_ENABLE_CRC +static uint32_t calc_crc(const void* b, size_t len) +{ + return fasthash64(b, len, 0); +} +#endif + +inline void eh_set(easy_head_t* h, uint32_t len, uint32_t pkt_id) +{ + h->magic_ = 0xcedbdb01; + h->len_ = rk_bswap32(len); + h->pkt_id_ = rk_bswap32(pkt_id); + h->reserved_ = 0; +} + +inline uint64_t eh_packet_id(const char* b) +{ + return rk_bswap32(((easy_head_t*)b)->pkt_id_); +} + +static int64_t eh_decode(char* b, int64_t s) +{ + int64_t bytes = sizeof(easy_head_t); + if (s >= bytes) { + easy_head_t* h = (typeof(h))b; + bytes += rk_bswap32(h->len_); + PNIO_CRC(assert(s < bytes || h->reserved_ == calc_crc(b + sizeof(easy_head_t), bytes - sizeof(easy_head_t)))); + } + return bytes; +} + +static void eh_copy_msg(str_t* m, uint32_t pkt_id, const char* b, int64_t s) +{ + easy_head_t* h = (typeof(h))m->b; + m->s = s + sizeof(*h); + eh_set(h, s, pkt_id); + if ((uint64_t)(h+1) != (uint64_t)b) { + memcpy((void*)(h + 1), b, s); + } + PNIO_CRC(h->reserved_ = calc_crc(b, s)); +} diff --git a/deps/oblib/src/rpc/pnio/nio/handle_io.t.h b/deps/oblib/src/rpc/pnio/nio/handle_io.t.h new file mode 100644 index 000000000..3ebc33412 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/handle_io.t.h @@ -0,0 +1,60 @@ +/* errors +1. 0: yield, file is writable, and there is remain data to send. +2. EAGAIN: wait wakeup, 3 cases: + 1. file is not writable, wait epoll to wakeup + 2. no remain data to send, wait poster to wakeup + 3. wait for memory or bandwidth... +3. Exception: should destroy sock. +*/ +//int xxx_sk_do_flush(xxx_sk_t* s, int64_t* remain); + +/* errors +1. 0: decode success +2. EAGAIN: wait wakeup, 2 cases: + 1. file is not readable to complete a msg. + 2. wait for memory or bandwidth... +3. Exception: should destroy sock. + */ +//int xxx_sk_do_decode(xxx_sk_t* s, xxx_msg_t** msg); +/* errors +1. 0: handle success +2. EAGAIN: wait wakeup, wait for memory or bandwidth. +3. Exception: should destroy sock. + */ +//int xxx_handle_msg(xxx_sk_t* s, xxx_msg_t* msg); + +static int my_sk_flush(my_sk_t* s, int64_t time_limit) { + int err = 0; + int64_t remain = INT64_MAX; + while(0 == err && remain > 0 && !is_epoll_handle_timeout(time_limit)) { + if (0 != (err = my_sk_do_flush(s, &remain))) { + if (EAGAIN != err) { + rk_info("do_flush fail: %d", err); + } + } + } + return remain <= 0 && 0 == err? EAGAIN: err; +} + +static int my_sk_consume(my_sk_t* s, int64_t time_limit) { + int err = 0; + my_msg_t msg; + while(0 == err && !is_epoll_handle_timeout(time_limit)) { + if (0 != (err = my_sk_do_decode(s, &msg))) { + if (EAGAIN != err) { + rk_info("do_decode fail: %d", err); + } + } else if (NULL == msg.payload) { + // not read a complete package yet + } else if (0 != (err = my_sk_handle_msg(s, &msg))) { + rk_info("handle msg fail: %d", err); + } + } + return err; +} + +static int my_sk_handle_event_ready(my_sk_t* s) { + int consume_ret = my_sk_consume(s, get_epoll_handle_time_limit()); + int flush_ret = my_sk_flush(s, get_epoll_handle_time_limit()); + return EAGAIN == consume_ret? flush_ret: consume_ret; +} diff --git a/deps/oblib/src/rpc/pnio/nio/inet.c b/deps/oblib/src/rpc/pnio/nio/inet.c new file mode 100644 index 000000000..e3b9ddda9 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/inet.c @@ -0,0 +1,119 @@ +#define PNIO_TCP_SYNCNT 3 +int check_connect_result(int fd) { + int err = 0; + int sys_err = 0; + socklen_t errlen = sizeof(sys_err); + if (0 != getsockopt(fd, SOL_SOCKET, SO_ERROR, &sys_err, &errlen)) { + err = -EIO; + } else if (EINPROGRESS == sys_err) { + err = -EAGAIN; + } else if (0 != sys_err) { + err = -EIO; + rk_error("connect error: err=%d %s", sys_err, T2S(sock_fd, fd)); + } + return err; +} + +int async_connect(addr_t dest) { + int fd = -1; + struct sockaddr_in sin; + ef((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0); + ef(make_fd_nonblocking(fd)); + set_tcpopt(fd, TCP_SYNCNT, PNIO_TCP_SYNCNT); + ef(connect(fd, (struct sockaddr*)make_sockaddr(&sin, dest), sizeof(sin)) < 0 && EINPROGRESS != errno); + set_tcp_nodelay(fd); + return fd; + el(); + if (fd >= 0) { + close(fd); + } + return -1; +} + +int listen_create(addr_t src) { + int fd = 0; + struct sockaddr_in sin; + ef((fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0)) < 0); + ef(set_tcp_reuse_addr(fd)); + ef(set_tcp_reuse_port(fd)); + ef(bind(fd, (const struct sockaddr*)make_sockaddr(&sin, src), sizeof(sin))); + ef(listen(fd, 1024)); + return fd; + el(); + if (fd >= 0) { + close(fd); + } + return -1; +} + +int tcp_accept(int fd) { + return accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); +} + +int set_tcp_reuse_addr(int fd) { + int flag = 1; + return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); +} + +int set_tcp_reuse_port(int fd) { + int flag = 1; + return setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)); +} + +int set_tcp_linger_on(int fd) { + struct linger so_linger; + so_linger.l_onoff = 1; + so_linger.l_linger = 0; + return setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger); +} + +int set_tcp_nodelay(int fd) { + int flag = 1; + return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); +} + +int set_tcpopt(int fd, int option, int value) +{ + int ret = setsockopt(fd, IPPROTO_TCP, option, (const void *) &value, sizeof(value)); + if (ret < 0) { + rk_warn("IPPROTO_TCP fd: %d, errno: %d, option: %d, value: %d", fd, errno, option, value); + } + return ret; +} +void update_socket_keepalive_params(int fd, int64_t user_timeout) +{ + int tcp_keepalive = (user_timeout > 0) ? 1: 0; + int tcp_keepidle = user_timeout/5000000; + if (tcp_keepidle < 1) { + tcp_keepidle = 1; + } + int tcp_keepintvl = tcp_keepidle; + int tcp_keepcnt = 5; + int tcp_user_timeout = (tcp_keepcnt + 1) * tcp_keepidle * 1000 - 100; + if (1 == tcp_keepalive) { + if (set_tcpopt(fd, SO_KEEPALIVE, 1)) { + rk_warn("set SO_KEEPALIVE error: %d, fd=%d\n", errno, fd); + } else { + ignore_ret_value(set_tcpopt(fd, TCP_KEEPIDLE, tcp_keepidle)); + ignore_ret_value(set_tcpopt(fd, TCP_KEEPINTVL, tcp_keepintvl)); + ignore_ret_value(set_tcpopt(fd, TCP_KEEPCNT, tcp_keepcnt)); // TCP_USER_TIMEOUT will override keepalive to determine when to close a connection due to keepalive failure + ignore_ret_value(set_tcpopt(fd, TCP_USER_TIMEOUT, tcp_user_timeout)); + } + } +} + +int set_tcp_recv_buf(int fd, int size) { + return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&size, sizeof(size)); +} + +int set_tcp_send_buf(int fd, int size) { + return setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&size, sizeof(size)); +} + +const char* sock_fd_str(format_t* f, int fd) { + format_t tf; + addr_t local = get_local_addr(fd); + addr_t remote = get_remote_addr(fd); + format_init(&tf, sizeof(tf.buf)); + return format_sf(f, "fd:%d:local:%s:remote:%s", fd, addr_str(&tf, local), addr_str(&tf, remote)); +} diff --git a/deps/oblib/src/rpc/pnio/nio/inet.h b/deps/oblib/src/rpc/pnio/nio/inet.h new file mode 100644 index 000000000..e4e0846b1 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/inet.h @@ -0,0 +1,14 @@ +#include +extern int async_connect(addr_t dest); +extern int listen_create(addr_t src); +extern int tcp_accept(int fd); +extern int check_connect_result(int fd); +extern int set_tcp_reuse_addr(int fd); +extern int set_tcp_reuse_port(int fd); +extern int set_tcp_linger_on(int fd); +extern int set_tcp_nodelay(int fd); +extern int set_tcpopt(int fd, int option, int value); +extern void update_socket_keepalive_params(int fd, int64_t user_timeout); +extern int set_tcp_recv_buf(int fd, int size); +extern int set_tcp_send_buf(int fd, int size); +extern const char* sock_fd_str(format_t* f, int fd); diff --git a/deps/oblib/src/rpc/pnio/nio/listener.c b/deps/oblib/src/rpc/pnio/nio/listener.c new file mode 100644 index 000000000..f0c3e643f --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/listener.c @@ -0,0 +1,138 @@ +int pkt_nio_dispatch_externel(int accept_fd) { return 0; } +#ifndef DISPATCH_EXTERNAL +#define DISPATCH_EXTERNAL(accept_fd) pkt_nio_dispatch_externel(accept_fd) +#endif + +typedef struct dispatch_sk_t +{ + SOCK_COMMON; +} dispatch_sk_t; + +#define DISPATCH_MAGIC 0xdeadbeef +typedef struct dispatch_head_t +{ + uint32_t magic; + uint32_t len; +} dispatch_head_t; + +int send_dispatch_handshake(int fd, const char* b, int sz) +{ + int err = 0; + char buf[256]; + dispatch_head_t* h = (typeof(h))buf; + if (sz + sizeof(*h) > sizeof(buf)) { + err = -EINVAL; + } else { + h->magic = DISPATCH_MAGIC; + h->len = sz; + memcpy(h + 1, b, sz); + ssize_t wbytes = 0; + rk_info("send handshake: sz=%d", sz); + while((wbytes = write(fd, buf, sz + sizeof(*h))) < 0 + && EINTR == errno); + if ((uint64_t)wbytes != sz + sizeof(*h)) { + err = -EIO; + } + } + return err; +} + +static int call_dispatch_func(dispatch_sk_t* s, const char* b, int sz) +{ + int err = 0; + listen_t* l = structof(s->fty, listen_t, sf); + if (sz > 0) { + char buf[sz + sizeof(dispatch_head_t)]; + if ((ssize_t)sizeof(buf) != uintr_read(s->fd, buf, sizeof(buf))) { + err = EIO; + } + } + if (0 != err) { + } else if (0 != (err = eloop_unregist(&l->ep, (sock_t*)s))) { + } else if (0 == err && 0 == (err = l->dispatch_func(s->fd, b, sz))) { + s->fd = -1; + err = ENODATA; + } + return err; +} + +static int dispatch_handle_event(dispatch_sk_t* s) +{ + int err = 0; + char buf[256]; + ssize_t rbytes = recv(s->fd, buf, sizeof(buf), MSG_PEEK); + dispatch_head_t* h = (typeof(h))buf; + if (rbytes == 0) { + err = ENODATA; + } else if (rbytes < 0) { + if (EINTR == errno) { + // do nothing + } else if (EAGAIN == errno || EWOULDBLOCK == errno) { + s->mask &= ~EPOLLIN; + err = EAGAIN; + } else { + err = EIO; + } + } else if ((uint64_t)rbytes < sizeof(dispatch_head_t)) { + // do nothing; + } else if (h->magic != DISPATCH_MAGIC) { + listen_t* l = structof(s->fty, listen_t, sf); + int fd = 0; + int epoll_fd = 0; + fd = s->fd; + if (l != NULL) { + epoll_fd = l->ep.fd; + } + if (0 != eloop_unregist(&l->ep, (sock_t*)s)) { + rk_info("eloop_unregist failed, err = %d, fd = %d", err, s->fd); + } else if (DISPATCH_EXTERNAL(fd) != 0) { + // ObListener dispatch failed + rk_info("dispatch_external failed, ObListener might not be inited, connection should be destroyed. fd = %d", s->fd); + err = -EIO; + } else { + rk_info("dispatch_external sucecess, fd = %d", s->fd); + s->fd = -1; + err = ENODATA; + } + } else if (h->len + sizeof(*h) > sizeof(buf)) { + err = -EINVAL; + } else if (h->len + sizeof(*h) > (uint64_t)rbytes) { + // need read more + } else { + err = call_dispatch_func(s, (const char*)(h+1), h->len); + } + return err; +} + +static dispatch_sk_t* dispatch_sk_new(sf_t* sf) +{ + dispatch_sk_t* s = (typeof(s))salloc(sizeof(*s)); + if (s) { + s->handle_event = (handle_event_t)dispatch_handle_event; + } + rk_info("dispatch_sk_new: %p", s); + return s; +} + +static void dispatch_sk_delete(sf_t* sf, dispatch_sk_t* s) +{ + rk_info("dispatch_sk_delete: %p", s); + sfree(s); +} + +static int dispatch_sf_init(sf_t* sf) +{ + sf_init((sf_t*)sf, (void*)dispatch_sk_new, (void*)dispatch_sk_delete); + return 0; +} + +int listen_init(listen_t* l, addr_t addr, dispatch_fd_func_t dispatch_func) +{ + int err = 0; + l->dispatch_func = dispatch_func; + ef(err = dispatch_sf_init(&l->sf)); + ef(err = eloop_init(&l->ep)); + ef(err = listenfd_init(&l->ep, &l->listenfd, (sf_t*)&l->sf, listen_create(addr))); + el(); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/nio/listener.h b/deps/oblib/src/rpc/pnio/nio/listener.h new file mode 100644 index 000000000..d56f4ac16 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/listener.h @@ -0,0 +1,11 @@ +typedef int (*dispatch_fd_func_t)(int fd, const void* buf, int sz); +typedef struct listen_t +{ + eloop_t ep; + listenfd_t listenfd; + sf_t sf; + dispatch_fd_func_t dispatch_func; +} listen_t; + +extern int send_dispatch_handshake(int fd, const char* b, int sz); +extern int listen_init(listen_t* l, addr_t addr, dispatch_fd_func_t dispatch_func); diff --git a/deps/oblib/src/rpc/pnio/nio/listenfd.c b/deps/oblib/src/rpc/pnio/nio/listenfd.c new file mode 100644 index 000000000..c77a36311 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/listenfd.c @@ -0,0 +1,72 @@ +static int do_accept(int fd, int is_pipe) +{ + int ret = -1; + if (is_pipe) { + if (read(fd, &ret, sizeof(ret)) <= 0) { + ret = -1; + } + } else { + ret = tcp_accept(fd); + } + return ret; +} + +void on_accept(int fd, sf_t* sf, eloop_t* ep) +{ + bool add_succ = false; + sock_t* ns = sf->create(sf); + if (NULL != ns) { + set_tcp_nodelay(fd); + update_socket_keepalive_params(fd, pnio_keepalive_timeout); + ns->fd = fd; + ns->fty = sf; + if (eloop_regist(ep, ns, EPOLLIN | EPOLLOUT) == 0) { + add_succ = true; + rk_info("accept new connection, ns=%p, fd=%d", ns, ns->fd); + } + } + if (!add_succ) { + if (fd >= 0) { + close(fd); + } + if (NULL != ns) { + sf->destroy(sf, ns); + } + rk_error("accept newfd fail"); + } +} + +int listenfd_handle_event(listenfd_t* s) { + int err = 0; + int fd = do_accept(s->fd, s->is_pipe); + if (fd >= 0) { + on_accept(fd, s->sf, s->ep); + } else { + if (EINTR == errno) { + // do nothing + } else if (EAGAIN == errno || EWOULDBLOCK == errno) { + s->mask &= ~EPOLLIN; + err = EAGAIN; + } else { + err = EIO; + } + } + return err; +} + +int listenfd_init(eloop_t* ep, listenfd_t* s, sf_t* sf, int fd) { + sk_init((sock_t*)s, NULL, (void*)listenfd_handle_event, fd); + s->is_pipe = is_pipe(fd); + s->ep = ep; + s->sf = sf; + ef(s->fd < 0); + ef(eloop_regist(ep, (sock_t*)s, EPOLLIN) != 0); + rk_info("listen succ: %d", fd); + return 0; + el(); + rk_error("listen fd init fail: fd=%d", s->fd); + if (s->fd >= 0) { + close(s->fd); + } + return EIO; +} diff --git a/deps/oblib/src/rpc/pnio/nio/listenfd.h b/deps/oblib/src/rpc/pnio/nio/listenfd.h new file mode 100644 index 000000000..25e11de29 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/listenfd.h @@ -0,0 +1,9 @@ +#include +typedef struct listenfd_t { + SOCK_COMMON; + bool is_pipe; + eloop_t* ep; + sf_t* sf; +} listenfd_t; + +extern int listenfd_init(eloop_t* ep, listenfd_t* s, sf_t* sf, int fd); diff --git a/deps/oblib/src/rpc/pnio/nio/msg_decode.c b/deps/oblib/src/rpc/pnio/nio/msg_decode.c new file mode 100644 index 000000000..d7909a5e9 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/msg_decode.c @@ -0,0 +1,2 @@ +extern int64_t msg_decode(const char* b, int64_t s); +extern uint64_t msg_get_id(const char* b); diff --git a/deps/oblib/src/rpc/pnio/nio/msg_decode.h b/deps/oblib/src/rpc/pnio/nio/msg_decode.h new file mode 100644 index 000000000..79c4640f1 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/msg_decode.h @@ -0,0 +1,11 @@ +inline int64_t msg_decode(const char* b, int64_t s) { + if (s < 8) { + return 8; + } else { + return *(int64_t*)b; + } +} + +inline uint64_t msg_get_id(const char* b) { + return *((uint64_t*)b + 1); +} diff --git a/deps/oblib/src/rpc/pnio/nio/nio-tpl-ns.h b/deps/oblib/src/rpc/pnio/nio/nio-tpl-ns.h new file mode 100644 index 000000000..e1b27375a --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/nio-tpl-ns.h @@ -0,0 +1,41 @@ + +#ifndef __ns__ +#define __ns__ +#define my_flush_cb tns(_flush_cb) +#define my_sk_do_decode tns(_sk_do_decode) +#define my_req_t tns(_req_t) +#define my_flush_cb_exception tns(_flush_cb_exception) +#define my_sk_handle_event_ready tns(_sk_handle_event_ready) +#define my_sk_t tns(_sk_t) +#define my_sk_handle_msg tns(_sk_handle_msg) +#define my_flush_cb_after_flush tns(_flush_cb_after_flush) +#define my_flush_cb_on_post_fail tns(_flush_cb_on_post_fail) +#define my_decode tns(_decode) +#define my_sk_read tns(_sk_read) +#define my_msg_t tns(_msg_t) +#define my_t tns(_t) +#define my_sk_do_flush tns(_sk_do_flush) +#define my_sk_flush tns(_sk_flush) +#define my_write_queue_on_sk_destroy tns(_write_queue_on_sk_destroy) +#define my_sk_consume tns(_sk_consume) +#else +#undef __ns__ +#undef tns +#undef my_flush_cb +#undef my_sk_do_decode +#undef my_req_t +#undef my_flush_cb_exception +#undef my_sk_handle_event_ready +#undef my_sk_t +#undef my_sk_handle_msg +#undef my_flush_cb_after_flush +#undef my_flush_cb_on_post_fail +#undef my_decode +#undef my_sk_read +#undef my_msg_t +#undef my_t +#undef my_sk_do_flush +#undef my_sk_flush +#undef my_write_queue_on_sk_destroy +#undef my_sk_consume +#endif diff --git a/deps/oblib/src/rpc/pnio/nio/packet_client.c b/deps/oblib/src/rpc/pnio/nio/packet_client.c new file mode 100644 index 000000000..16a4c9cab --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/packet_client.c @@ -0,0 +1,44 @@ +typedef struct pktc_msg_t { + int64_t sz; + char* payload; +} pktc_msg_t; +static int64_t pktc_decode(char* b, int64_t s) { return eh_decode(b, s); } +static uint64_t pktc_get_id(pktc_msg_t* m) { return eh_packet_id(m->payload); } + +static int pktc_sk_read(void** b, pktc_sk_t* s, int64_t sz) { + return sk_read_with_ib(b, (sock_t*)s, &s->ib, sz); +} + +static void pktc_flush_cb(pktc_t* io, pktc_req_t* req) { + PNIO_DELAY_WARN(delay_warn("pktc_flush_cb", req->ctime_us, FLUSH_DELAY_WARN_US)); + req->flush_cb(req); +} + +#include "pktc_resp.h" + +#define tns(x) pktc ## x +#include "nio-tpl-ns.h" +#include "write_queue.t.h" +#include "decode.t.h" +#include "handle_io.t.h" +#include "nio-tpl-ns.h" + +#include "pktc_sk_factory.h" +#include "pktc_post.h" + +int64_t pktc_init(pktc_t* io, eloop_t* ep, uint64_t dispatch_id) { + int err = 0; + io->ep = ep; + io->dispatch_id = dispatch_id; + ef(err = pktc_sf_init(&io->sf)); + ef(err = evfd_init(io->ep, &io->evfd, (handle_event_t)pktc_evfd_cb)); + sc_queue_init(&io->req_queue); + ef(err = timerfd_init_tw(io->ep, &io->cb_timerfd)); + tw_init(&io->cb_tw, pktc_resp_cb_on_timeout); + hash_init(&io->sk_map, arrlen(io->sk_table)); + hash_init(&io->cb_map, arrlen(io->cb_table)); + dlink_init(&io->sk_list); + rk_info("pktc init succ"); + el(); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/nio/packet_client.h b/deps/oblib/src/rpc/pnio/nio/packet_client.h new file mode 100644 index 000000000..49253066c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/packet_client.h @@ -0,0 +1,60 @@ +typedef struct pktc_req_t pktc_req_t; +typedef struct pktc_cb_t pktc_cb_t; +typedef void (*pktc_flush_cb_func_t)(pktc_req_t* req); +typedef void (*pktc_resp_cb_func_t)(pktc_cb_t* cb, const char* resp, int64_t sz); + +struct pktc_cb_t { + dlink_t sk_dlink; + link_t hash_link; + uint64_t id; + dlink_t timer_dlink; + int64_t expire_us; + pktc_resp_cb_func_t resp_cb; + int errcode; +}; + +struct pktc_req_t { + struct pktc_sk_t* sk; // for debug + int16_t categ_id; + PNIO_DELAY_WARN(int64_t ctime_us); + pktc_flush_cb_func_t flush_cb; + pktc_cb_t* resp_cb; + addr_t dest; + link_t link; + str_t msg; +}; + +typedef struct pktc_t pktc_t; +extern int64_t pktc_init(pktc_t* io, eloop_t* ep, uint64_t dispatch_id); +extern int pktc_post(pktc_t* io, pktc_req_t* req); + +typedef struct pktc_sk_t { + SOCK_COMMON; + dlink_t list_link; + struct pktc_t* pc; // for debug + link_t hash; + addr_t dest; + write_queue_t wq; + ibuffer_t ib; + dlink_t cb_head; + int64_t user_keepalive_timeout; +} pktc_sk_t; + +typedef struct pktc_sf_t { + SOCK_FACTORY_COMMON; +} pktc_sf_t; + +typedef struct pktc_t { + eloop_t* ep; + uint64_t dispatch_id; + pktc_sf_t sf; + evfd_t evfd; + sc_queue_t req_queue; + timerfd_t cb_timerfd; + time_wheel_t cb_tw; + dlink_t sk_list; + hash_t sk_map; + link_t sk_table[1024]; + hash_t cb_map; + link_t cb_table[1<<16]; +} pktc_t; diff --git a/deps/oblib/src/rpc/pnio/nio/packet_server.c b/deps/oblib/src/rpc/pnio/nio/packet_server.c new file mode 100644 index 000000000..f9ca10de0 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/packet_server.c @@ -0,0 +1,52 @@ +typedef struct pkts_msg_t { + int64_t sz; + char* payload; +} pkts_msg_t; + +static int64_t pkts_decode(char* b, int64_t s) { return eh_decode(b, s);} + +void pkts_flush_cb(pkts_t* io, pkts_req_t* req) { + PNIO_DELAY_WARN(delay_warn("pkts_flush_cb", req->ctime_us, FLUSH_DELAY_WARN_US)); + req->flush_cb(req); +} + +static int pkts_sk_read(void** b, pkts_sk_t* s, int64_t sz) { + return sk_read_with_ib(b, (sock_t*)s, &s->ib, sz); +} + +static int pkts_sk_handle_msg(pkts_sk_t* s, pkts_msg_t* msg) { + pkts_t* pkts = structof(s->fty, pkts_t, sf); +#ifdef PERF_MODE + int ret = pkts->on_req(pkts, ib_ref(&s->ib), msg->payload, msg->sz, s->id); +#else + int ret = pkts->on_req(pkts, s->ib.b, msg->payload, msg->sz, s->id); +#endif + ib_consumed(&s->ib, msg->sz); + return ret; +} + +#define tns(x) pkts ## x +#include "nio-tpl-ns.h" +#include "write_queue.t.h" +#include "decode.t.h" +#include "handle_io.t.h" +#include "nio-tpl-ns.h" + +#include "pkts_sk_factory.h" +#include "pkts_post.h" + +int pkts_init(pkts_t* io, eloop_t* ep, pkts_cfg_t* cfg) { + int err = 0; + int lfd = -1; + io->ep = ep; + ef(err = pkts_sf_init(&io->sf, cfg)); + sc_queue_init(&io->req_queue); + ef(err = evfd_init(io->ep, &io->evfd, (handle_event_t)pkts_evfd_cb)); + lfd = cfg->accept_qfd >= 0 ?cfg->accept_qfd: listen_create(cfg->addr); + ef(err = listenfd_init(io->ep, &io->listenfd, (sf_t*)&io->sf, lfd)); + rk_info("pkts listen at %s", T2S(addr, cfg->addr)); + idm_init(&io->sk_map, arrlen(io->sk_table)); + io->on_req = cfg->handle_func; + el(); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/nio/packet_server.h b/deps/oblib/src/rpc/pnio/nio/packet_server.h new file mode 100644 index 000000000..83e1dc327 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/packet_server.h @@ -0,0 +1,45 @@ +typedef struct pkts_sk_t pkts_sk_t; +typedef struct pkts_req_t pkts_req_t; +typedef struct pkts_t pkts_t; +typedef int (*pkts_handle_func_t)(pkts_t* pkts, void* req_handle, const char* b, int64_t s, uint64_t chid); +typedef void (*pkts_flush_cb_func_t)(pkts_req_t* req); + +typedef struct pkts_cfg_t { + int accept_qfd; + addr_t addr; + pkts_handle_func_t handle_func; +} pkts_cfg_t; + +typedef struct pkts_req_t { + PNIO_DELAY_WARN(int64_t ctime_us); + int errcode; + pkts_flush_cb_func_t flush_cb; + uint64_t sock_id; + link_t link; + str_t msg; +} pkts_req_t; + +extern int pkts_init(pkts_t* io, eloop_t* ep, pkts_cfg_t* cfg); +extern int pkts_resp(pkts_t* pkts, pkts_req_t* req); + +typedef struct pkts_sk_t { + SOCK_COMMON; + uint64_t id; + write_queue_t wq; + ibuffer_t ib; +} pkts_sk_t; + +typedef struct pkts_sf_t { + SOCK_FACTORY_COMMON; +} pkts_sf_t; + +typedef struct pkts_t { + eloop_t* ep; + listenfd_t listenfd; + pkts_sf_t sf; + pkts_handle_func_t on_req; + evfd_t evfd; + sc_queue_t req_queue; + idm_t sk_map; + idm_item_t sk_table[1<<16]; +} pkts_t; diff --git a/deps/oblib/src/rpc/pnio/nio/pktc_post.h b/deps/oblib/src/rpc/pnio/nio/pktc_post.h new file mode 100644 index 000000000..784cf6c3d --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pktc_post.h @@ -0,0 +1,112 @@ +static pktc_sk_t* pktc_do_connect(pktc_t* cl, addr_t dest) { + pktc_sk_t* sk = NULL; + ef(!(sk = pktc_sk_new(&cl->sf))); + sk->pc = cl; + sk->dest = dest; + ef((sk->fd = async_connect(dest)) < 0); + rk_info("sk_new: sk=%p, fd=%d", sk, sk->fd); + ef(eloop_regist(cl->ep, (sock_t*)sk, EPOLLIN|EPOLLOUT)); + return sk; + el(); + if (sk) { + pktc_sk_delete(&cl->sf, sk); + } + return NULL; +} + +static pktc_sk_t* pktc_try_connect(pktc_t* cl, addr_t dest) { + pktc_sk_t* sk = NULL; + link_t* sk_link = ihash_get(&cl->sk_map, *(uint64_t*)&dest); + if (sk_link) { + sk = structof(sk_link, pktc_sk_t, hash); + } else { + ef(!(sk = pktc_do_connect(cl, dest))); + ihash_insert(&cl->sk_map, &sk->hash); + dlink_insert(&cl->sk_list, &sk->list_link); + } + return sk; + el(); + rk_error("sk create fail: %s sk=%p", T2S(addr, dest), sk); + if (sk) { + pktc_sk_destroy(&cl->sf, sk); + } + return NULL; +} + +static int pktc_wq_push_pre(write_queue_t* wq, pktc_req_t* r) { + int err = 0; + int16_t* bucket = wq->categ_count_bucket; + int16_t id = r->categ_id % arrlen(wq->categ_count_bucket); + if (wq->cnt >= MAX_WRITE_QUEUE_COUNT || bucket[id] >= MAX_CATEG_COUNT) { + if (PNIO_REACH_TIME_INTERVAL(500*1000)) { + rk_warn("too many requests in pktc write queue, wq_cnt=%ld, wq_sz=%ld, categ_id=%d, categ_cnt=%d, socket=(ptr=%p,fd=%d)", + wq->cnt, wq->sz, r->categ_id, bucket[id], r->sk, r->sk->fd); + } + err = -1; + } else { + bucket[id] ++; + } + return err; +} +static int pktc_do_post(pktc_t* io, pktc_sk_t* sk, pktc_req_t* r) { + pktc_cb_t* cb = r->resp_cb; + int err = pktc_wq_push_pre(&sk->wq, r); + if (err != 0) { + // drop req + } else { + if (cb) { + dlink_insert(&sk->cb_head, &cb->sk_dlink); + ihash_insert(&io->cb_map, &cb->hash_link); + tw_regist(&io->cb_tw, &cb->timer_dlink); + } + wq_push(&sk->wq, &r->link); + } + return err; +} + +static void pktc_post_io(pktc_t* io, pktc_req_t* r) { + int err = 0; + pktc_sk_t* sk = pktc_try_connect(io, r->dest); + r->sk = sk; + if (sk && 0 == (err = pktc_do_post(io, sk, r))) { + eloop_fire(io->ep, (sock_t*)sk); + } else { + rk_debug("req was dropped, req_id=%ld, sock=(%p,%d)", r->resp_cb->id, sk, sk->fd); + pktc_resp_cb_on_post_fail(r); + pktc_flush_cb_on_post_fail(io, r); + } +} + +int pktc_post(pktc_t* io, pktc_req_t* req) { + PNIO_DELAY_WARN(req->ctime_us = rk_get_corse_us()); + if (req->msg.s < (int64_t)sizeof(req->msg)) { + return -EINVAL; + } + int64_t queue_cnt = 0; + int64_t queue_sz = 0; + sc_queue_inc(&io->req_queue, &req->link, &queue_cnt, &queue_sz); + if (queue_cnt >= MAX_REQ_QUEUE_COUNT && PNIO_REACH_TIME_INTERVAL(500*1000)) { + rk_warn("too many requests in pktc req_queue, queue_cnt=%ld, queue_sz=%ld, pnio dispatch_id=%ld", queue_cnt, queue_sz, io->dispatch_id); + } + if (sc_queue_push(&io->req_queue, &req->link)) { + evfd_signal(io->evfd.fd); + } + return 0; +} + +static int pktc_handle_req_queue(pktc_t* io) { + link_t* l = NULL; + int cnt = 0; + while(cnt < 128 && (l = sc_queue_pop(&io->req_queue))) { + pktc_req_t* req = structof(l, pktc_req_t, link); + PNIO_DELAY_WARN(delay_warn("pktc_handle_req_queue", req->ctime_us, HANDLE_DELAY_WARN_US)); + pktc_post_io(io, req); + cnt++; + } + return cnt == 0? EAGAIN: 0; +} + +static int pktc_evfd_cb(sock_t* s) { + evfd_drain(s->fd); + return pktc_handle_req_queue(structof(s, pktc_t, evfd)); +} diff --git a/deps/oblib/src/rpc/pnio/nio/pktc_resp.h b/deps/oblib/src/rpc/pnio/nio/pktc_resp.h new file mode 100644 index 000000000..4b4b38ddc --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pktc_resp.h @@ -0,0 +1,54 @@ + +static void pktc_do_cb(pktc_cb_t* cb, pktc_msg_t* m) { + cb->resp_cb(cb, m->payload, m->sz); +} + +static void pktc_do_cb_exception(pktc_cb_t* cb) { + cb->resp_cb(cb, NULL, 0); +} + +static void pktc_resp_cb_on_sk_destroy(pktc_t* io, pktc_sk_t* s) { + dlink_for(&s->cb_head, p) { + pktc_cb_t* cb = structof(p, pktc_cb_t, sk_dlink); + ihash_del(&io->cb_map, cb->id); + dlink_delete(&cb->timer_dlink); + rk_info("resp_cb on sk_destroy: packet_id=%lu s=%p", cb->id, s); + cb->errcode = PNIO_DISCONNECT; + pktc_do_cb_exception(cb); + } +} + +static void pktc_resp_cb_on_timeout(time_wheel_t* tw, dlink_t* l) { + pktc_cb_t* cb = structof(l, pktc_cb_t, timer_dlink); + pktc_t* io = structof(tw, pktc_t, cb_tw); + ihash_del(&io->cb_map, cb->id); + dlink_delete(&cb->sk_dlink); + rk_info("resp_cb on timeout: packet_id=%lu expire_us=%ld", cb->id, cb->expire_us); + cb->errcode = PNIO_TIMEOUT; + pktc_do_cb_exception(cb); +} + +static void pktc_resp_cb_on_post_fail(pktc_req_t* r) { + r->resp_cb->errcode = PNIO_CONNECT_FAIL; + pktc_do_cb_exception(r->resp_cb); +} + +static void pktc_resp_cb_on_msg(pktc_t* io, pktc_msg_t* msg) { + uint64_t id = pktc_get_id(msg); + link_t* hlink = ihash_del(&io->cb_map, id); + if (hlink) { + pktc_cb_t* cb = structof(hlink, pktc_cb_t, hash_link); + dlink_delete(&cb->timer_dlink); + dlink_delete(&cb->sk_dlink); + pktc_do_cb(cb, msg); + } else { + rk_info("resp cb not found: packet_id=%lu", id); + } +} + +static int pktc_sk_handle_msg(pktc_sk_t* s, pktc_msg_t* m) { + pktc_t* io = structof(s->fty, pktc_t, sf); + pktc_resp_cb_on_msg(io, m); + ib_consumed(&s->ib, m->sz); + return 0; +} diff --git a/deps/oblib/src/rpc/pnio/nio/pktc_sk_factory.h b/deps/oblib/src/rpc/pnio/nio/pktc_sk_factory.h new file mode 100644 index 000000000..77a8909a2 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pktc_sk_factory.h @@ -0,0 +1,71 @@ +static int pktc_sk_check_connect(pktc_sk_t* s) { + int err = 0; + if (s->conn_ok) { + } else if (!skt(s, OUT)) { + rk_info("sock not ready: %p", s); + err = EAGAIN; + } else if (0 != check_connect_result(s->fd)) { + rk_info("sock not ready: %p", s); + err = EIO; + } else { + s->conn_ok = 1; + rk_info("sock connect OK: %p %s", s, T2S(sock_fd, s->fd)); + pktc_t* pc = structof(s->fty, pktc_t, sf); + if (pc->dispatch_id != 0) { + err = send_dispatch_handshake(s->fd, (const char*)&(pc->dispatch_id), sizeof(pc->dispatch_id)); + } + } + return err; +} + +static int pktc_sk_handle_event(pktc_sk_t* s) { + return pktc_sk_check_connect(s)?: pktc_sk_handle_event_ready(s); +} + +static void* pktc_sk_alloc(int64_t sz) { return salloc(sz); } +static void pktc_sk_free(void* p) { sfree(p); } + +static int pktc_sk_init(pktc_sf_t* sf, pktc_sk_t* s) { + unused(sf); + s->conn_ok = 0; + wq_init(&s->wq); + ib_init(&s->ib, MOD_PKTC_INBUF); + dlink_init(&s->cb_head); + dlink_init(&s->list_link); + s->user_keepalive_timeout = 0; + return 0; +} + +static void pktc_sk_destroy(pktc_sf_t* sf, pktc_sk_t* s) { + pktc_t* pc = structof(sf, pktc_t, sf); + if (s) { + ihash_del(&pc->sk_map, *(uint64_t*)&s->dest); + dlink_delete(&s->list_link); + } +} + +static pktc_sk_t* pktc_sk_new(pktc_sf_t* sf) { + pktc_sk_t* s = (pktc_sk_t*)pktc_sk_alloc(sizeof(*s)); + if (s) { + s->fty = (sf_t*)sf; + s->handle_event = (handle_event_t)pktc_sk_handle_event; + pktc_sk_init(sf, s); + } + rk_info("sk_new: s=%p", s); + return s; +} + +static void pktc_sk_delete(pktc_sf_t* sf, pktc_sk_t* s) { + pktc_t* io = structof(sf, pktc_t, sf); + rk_info("sk_destroy: s=%p io=%p", s, io); + pktc_sk_destroy(sf, s); + pktc_write_queue_on_sk_destroy(io, s); + pktc_resp_cb_on_sk_destroy(io, s); + ib_destroy(&s->ib); + pktc_sk_free(s); +} + +static int pktc_sf_init(pktc_sf_t* sf) { + sf_init((sf_t*)sf, (void*)pktc_sk_new, (void*)pktc_sk_delete); + return 0; +} diff --git a/deps/oblib/src/rpc/pnio/nio/pktc_wait.c b/deps/oblib/src/rpc/pnio/nio/pktc_wait.c new file mode 100644 index 000000000..0a9d849d4 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pktc_wait.c @@ -0,0 +1,2 @@ +extern void pktc_wait_cb(const char* b, int64_t s, void* arg); +extern char* pktc_wait(pktc_wait_t* w, int64_t* sz); diff --git a/deps/oblib/src/rpc/pnio/nio/pktc_wait.h b/deps/oblib/src/rpc/pnio/nio/pktc_wait.h new file mode 100644 index 000000000..1f79ea853 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pktc_wait.h @@ -0,0 +1,23 @@ +typedef struct pktc_wait_t { + int32_t done; + uint32_t sz; + char resp[]; +} pktc_wait_t; + +inline void pktc_wait_cb(const char* b, int64_t s, void* arg) { + pktc_wait_t* w = (pktc_wait_t*)arg; + memcpy(w->resp, b, s); + w->sz = s; + STORE(&w->done, 1); + rk_futex_wake(&w->done, 1); +} + +inline char* pktc_wait(pktc_wait_t* w, int64_t* sz) { + while(!w->done) { + rk_futex_wait(&w->done, 0, NULL); + } + if (NULL != sz) { + *sz = w->sz; + } + return w->resp; +} diff --git a/deps/oblib/src/rpc/pnio/nio/pkts_post.h b/deps/oblib/src/rpc/pnio/nio/pkts_post.h new file mode 100644 index 000000000..4db5554b4 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pkts_post.h @@ -0,0 +1,43 @@ +static void pkts_post_io(pkts_t* io, pkts_req_t* r) { + pkts_sk_t* sk = (typeof(sk))idm_get(&io->sk_map, r->sock_id); + if (sk && 0 == r->errcode) { + if (sk->wq.cnt >= MAX_WRITE_QUEUE_COUNT && PNIO_REACH_TIME_INTERVAL(500*1000)) { + rk_warn("too many requests in pkts write queue, wq_cnt=%ld, wq_sz=%ld, sock_id=%ld", sk->wq.cnt, sk->wq.sz, r->sock_id); + } + wq_push(&sk->wq, &r->link); + eloop_fire(io->ep, (sock_t*)sk); + } else { + pkts_flush_cb_on_post_fail(io, r); + } +} + +int pkts_resp(pkts_t* io, pkts_req_t* req) { + PNIO_DELAY_WARN(req->ctime_us = rk_get_corse_us()); + int64_t queue_cnt = 0; + int64_t queue_sz = 0; + sc_queue_inc(&io->req_queue, &req->link, &queue_cnt, &queue_sz); + if (queue_cnt >= MAX_REQ_QUEUE_COUNT && PNIO_REACH_TIME_INTERVAL(500*1000)) { + rk_warn("too many requests in pkts req_queue, queue_cnt=%ld, queue_sz=%ld", queue_cnt, queue_sz); + } + if (sc_queue_push(&io->req_queue, &req->link)) { + evfd_signal(io->evfd.fd); + } + return 0; +} + +static int pkts_handle_req_queue(pkts_t* io) { + link_t* l = NULL; + int cnt = 0; + while(cnt < 128 && (l = sc_queue_pop(&io->req_queue))) { + pkts_req_t* req = structof(l, pkts_req_t, link); + PNIO_DELAY_WARN(delay_warn("pkts_handle_req_queue", req->ctime_us, HANDLE_DELAY_WARN_US)); + pkts_post_io(io, req); + cnt++; + } + return cnt == 0? EAGAIN: 0; +} + +static int pkts_evfd_cb(sock_t* s) { + evfd_drain(s->fd); + return pkts_handle_req_queue(structof(s, pkts_t, evfd)); +} diff --git a/deps/oblib/src/rpc/pnio/nio/pkts_sk_factory.h b/deps/oblib/src/rpc/pnio/nio/pkts_sk_factory.h new file mode 100644 index 000000000..7c1b87bdb --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/pkts_sk_factory.h @@ -0,0 +1,45 @@ +static void* pkts_sk_alloc(int64_t sz) { return salloc(sz); } +static void pkts_sk_free(void* p) { sfree(p); } + +static int pkts_sk_init(pkts_sf_t* sf, pkts_sk_t* s) { + pkts_t* pkts = structof(sf, pkts_t, sf); + wq_init(&s->wq); + ib_init(&s->ib, MOD_PKTS_INBUF); + s->id = idm_set(&pkts->sk_map, s); + rk_info("set pkts_sk_t sock_id s=%p, s->id=%ld", s, s->id); + return 0; +} + +static void pkts_sk_destroy(pkts_sf_t* sf, pkts_sk_t* s) { + pkts_t* pkts = structof(sf, pkts_t, sf); + idm_del(&pkts->sk_map, s->id); +} + +static int pkts_sk_handle_event(pkts_sk_t* s) { + return pkts_sk_handle_event_ready(s); +} + +static pkts_sk_t* pkts_sk_new(pkts_sf_t* sf) { + pkts_sk_t* s = (pkts_sk_t*)pkts_sk_alloc(sizeof(*s)); + if (s) { + s->fty = (sf_t*)sf; + s->handle_event = (handle_event_t)pkts_sk_handle_event; + pkts_sk_init(sf, s); + } + rk_info("sk_new: s=%p", s); + return s; +} + +static void pkts_sk_delete(pkts_sf_t* sf, pkts_sk_t* s) { + pkts_t* io = structof(sf, pkts_t, sf); + rk_info("sk_destroy: s=%p io=%p", s, io); + pkts_sk_destroy(sf, s); + pkts_write_queue_on_sk_destroy(io, s); + ib_destroy(&s->ib); + pkts_sk_free(s); +} + +static int pkts_sf_init(pkts_sf_t* sf, void* cfg) { + sf_init((sf_t*)sf, (void*)pkts_sk_new, (void*)pkts_sk_delete); + return 0; +} diff --git a/deps/oblib/src/rpc/pnio/nio/timeout.h b/deps/oblib/src/rpc/pnio/nio/timeout.h new file mode 100644 index 000000000..ce51dc3e9 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/timeout.h @@ -0,0 +1,9 @@ +static bool is_epoll_handle_timeout(int64_t time_limit) +{ + return time_limit > 0 && rk_get_corse_us() > time_limit; +} + +static int64_t get_epoll_handle_time_limit() +{ + return EPOLL_HANDLE_TIME_LIMIT > 0? rk_get_corse_us() + EPOLL_HANDLE_TIME_LIMIT: -1; +} diff --git a/deps/oblib/src/rpc/pnio/nio/write_queue.t.h b/deps/oblib/src/rpc/pnio/nio/write_queue.t.h new file mode 100644 index 000000000..7a705e9c2 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/nio/write_queue.t.h @@ -0,0 +1,36 @@ +static void my_flush_cb_exception(my_t* io, my_req_t* r) { + return my_flush_cb(io, r); +} + +static void my_write_queue_on_sk_destroy(my_t* io, my_sk_t* s) { + link_t* h = queue_top(&s->wq.queue); + while(NULL != h) { + my_req_t* req = structof(h, my_req_t, link); + h = h->next; + my_flush_cb_exception(io, req); + } +} + +static void my_flush_cb_on_post_fail(my_t* io, my_req_t* r) { + return my_flush_cb_exception(io, r); +} + +static void my_flush_cb_after_flush(my_t* io, my_req_t* r) { + return my_flush_cb(io, r); +} + +static int my_sk_do_flush(my_sk_t* s, int64_t* remain) { + link_t* h = NULL; + int err = wq_flush((sock_t*)s, &s->wq, &h); + my_t* io = structof(s->fty, my_t, sf); + if (0 == err && NULL != h) { + link_t* stop = queue_top(&s->wq.queue); + while(h != stop) { + my_req_t* req = structof(h, my_req_t, link); + h = h->next; + my_flush_cb_after_flush(io, req); + } + } + *remain = !queue_empty(&s->wq.queue); + return err; +} diff --git a/deps/oblib/src/rpc/pnio/pkt-nio.c b/deps/oblib/src/rpc/pnio/pkt-nio.c new file mode 100644 index 000000000..e5c913d9a --- /dev/null +++ b/deps/oblib/src/rpc/pnio/pkt-nio.c @@ -0,0 +1,47 @@ +#include "pkt-nio.h" + +#include "r0/define.c" +#include "r0/get_us.c" +#include "r0/format.c" +#include "r0/log.c" +#include "r0/futex.c" +#include "r0/debug.c" + +#include "ds/link.c" +#include "ds/dlink.c" +#include "ds/queue.c" +#include "ds/sc_queue.c" +#include "ds/fixed_stack.c" +#include "ds/hash.c" +#include "ds/str_type.c" +#include "ds/hash_map.c" +#include "ds/ihash_map.c" +#include "ds/id_map.c" + +#include "alloc/mod_alloc.c" +#include "alloc/chunk_cache.c" +#include "alloc/ref_alloc.c" +#include "alloc/fifo_alloc.c" +#include "alloc/cfifo_alloc.c" + +#include "io/sock.c" +#include "io/eloop.c" +#include "io/iov.c" +#include "io/io_func.c" +#include "io/sock_io.c" +#include "io/write_queue.c" +#include "io/ibuffer.c" +#include "io/evfd.c" +#include "io/timerfd.c" +#include "io/time_wheel.c" + +#include "nio/addr.c" +#include "nio/inet.c" +#include "nio/listenfd.c" +#include "nio/easy_head.c" +#include "nio/listener.c" +#include "nio/packet_client.c" +#include "nio/pktc_wait.c" +#include "nio/packet_server.c" +#include "nio/msg_decode.c" +#include "interface/group.c" diff --git a/deps/oblib/src/rpc/pnio/pkt-nio.h b/deps/oblib/src/rpc/pnio/pkt-nio.h new file mode 100644 index 000000000..06487ccd6 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/pkt-nio.h @@ -0,0 +1,53 @@ +#pragma once +#include "config.h" +#include "r0/define.h" +#include "r0/atomic.h" +#include "r0/get_us.h" +#include "r0/format.h" +#include "r0/log.h" +#include "r0/futex.h" +#include "r0/debug.h" + +#include "ds/link.h" +#include "ds/dlink.h" +#include "ds/queue.h" +#include "ds/sc_queue.h" +#include "ds/fixed_stack.h" +#include "ds/hash.h" +#include "ds/str_type.h" +#include "ds/hash_map.h" +#include "ds/ihash_map.h" +#include "ds/id_map.h" +#include "ds/link-queue.h" +#include "ds/counter.h" + + +#include "alloc/mod_alloc.h" +#include "alloc/chunk_cache.h" +#include "alloc/ref_alloc.h" +#include "alloc/fifo_alloc.h" +#include "alloc/cfifo_alloc.h" + +#include "io/msg.h" +#include "io/sock.h" +#include "io/eloop.h" +#include "io/iov.h" +#include "io/io_func.h" +#include "io/sock_io.h" +#include "io/write_queue.h" +#include "io/ibuffer.h" +#include "io/evfd.h" +#include "io/timerfd.h" +#include "io/time_wheel.h" + +#include "nio/addr.h" +#include "nio/inet.h" +#include "nio/listenfd.h" +#include "nio/easy_head.h" +#include "nio/listener.h" +#include "nio/timeout.h" +#include "nio/packet_client.h" +#include "nio/pktc_wait.h" +#include "nio/packet_server.h" +#include "nio/msg_decode.h" +#include "interface/group.h" diff --git a/deps/oblib/src/rpc/pnio/r0/atomic.h b/deps/oblib/src/rpc/pnio/r0/atomic.h new file mode 100644 index 000000000..c52fc0122 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/atomic.h @@ -0,0 +1,19 @@ +#pragma once +#define BARRIER() asm volatile(""::: "memory") +#define MBARRIER() __sync_synchronize() + +#if defined(__x86_64__) +#define SPIN_PAUSE() asm("pause\n") +#elif defined(__aarch64__) +#define SPIN_PAUSE() asm("yield\n") +#endif + +#define LOAD(x) __atomic_load_n((x), __ATOMIC_ACQUIRE) +#define STORE(x, v) __atomic_store_n((x), (v), __ATOMIC_RELEASE) + +#define FAA(val, addv) __sync_fetch_and_add((val), (addv)) +#define AAF(val, addv) __sync_add_and_fetch((val), (addv)) +#define TAS(val, newv) __sync_lock_test_and_set((val), (newv)) +#define VCAS(val, cmpv, newv) __sync_val_compare_and_swap((val), (cmpv), (newv)) +#define BCAS(val, cmpv, newv) __sync_bool_compare_and_swap((val), (cmpv), (newv)) +#define TAS(val, newv) __sync_lock_test_and_set((val), (newv)) diff --git a/deps/oblib/src/rpc/pnio/r0/debug.c b/deps/oblib/src/rpc/pnio/r0/debug.c new file mode 100644 index 000000000..2a4f97594 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/debug.c @@ -0,0 +1,25 @@ +extern void delay_warn(const char* msg, int64_t start_us, int64_t warn_us); +extern void eloop_delay_warn(int64_t start_us, int64_t warn_us); +extern void reset_eloop_time_stat(); + +__thread int64_t eloop_malloc_count; +__thread int64_t eloop_malloc_time; +__thread int64_t eloop_write_count; +__thread int64_t eloop_write_time; +__thread int64_t eloop_read_count; +__thread int64_t eloop_read_time; +__thread int64_t eloop_client_cb_count; +__thread int64_t eloop_client_cb_time; +__thread int64_t eloop_server_process_count; +__thread int64_t eloop_server_process_time; + +void stat_cleanup(void *s) { + int64_t cost = rk_get_corse_us() - ((struct stat_time_guard_t *)s)->start; + int64_t *cnt = ((struct stat_time_guard_t *)s)->cnt; + *cnt += 1; + int64_t *time = ((struct stat_time_guard_t *)s)->time; + *time += cost; + if (cost > ELOOP_WARN_US) { + rk_info("eloop handle events cost too much time: %ldus, procedure: %s", cost, ((struct stat_time_guard_t *)s)->procedure); + } +} diff --git a/deps/oblib/src/rpc/pnio/r0/debug.h b/deps/oblib/src/rpc/pnio/r0/debug.h new file mode 100644 index 000000000..5537ae13b --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/debug.h @@ -0,0 +1,73 @@ + +struct stat_time_guard_t { + int64_t start; + int64_t *cnt; + int64_t *time; + const char *procedure; +}; + +extern __thread int64_t eloop_malloc_count; +extern __thread int64_t eloop_malloc_time; +extern __thread int64_t eloop_write_count; +extern __thread int64_t eloop_write_time; +extern __thread int64_t eloop_read_count; +extern __thread int64_t eloop_read_time; +extern __thread int64_t eloop_client_cb_count; +extern __thread int64_t eloop_client_cb_time; +extern __thread int64_t eloop_server_process_count; +extern __thread int64_t eloop_server_process_time; + +void stat_cleanup(void *s); +inline void reset_eloop_time_stat() { + eloop_malloc_count = 0; + eloop_malloc_time = 0; + eloop_write_count = 0; + eloop_write_time = 0; + eloop_read_count = 0; + eloop_read_time = 0; + eloop_client_cb_count = 0; + eloop_client_cb_time = 0; + eloop_server_process_count = 0; + eloop_server_process_time = 0; +} +#define STAT_TIME_GUARD(_cnt, _time) \ + struct stat_time_guard_t _tg_stat_time_guard __attribute__((cleanup(stat_cleanup))) = { \ + .start = rk_get_corse_us(), \ + .cnt = &(_cnt), \ + .time = &(_time), \ + .procedure = __FUNCTION__, \ + }; + +#define PNIO_REACH_TIME_INTERVAL(i) \ + ({ \ + bool bret = false; \ + static __thread int64_t last_time = 0; \ + int64_t cur_time = rk_get_us(); \ + if ((i + last_time < cur_time)) \ + { \ + last_time = cur_time; \ + bret = true; \ + } \ + bret; \ + }) + +inline void eloop_delay_warn(int64_t start_us, int64_t warn_us) { + if (warn_us > 0) { + int64_t delay = rk_get_corse_us() - start_us; + if (delay > warn_us) { + rk_info("eloop handle events delay high: %ld, malloc=%ld/%ld write=%ld/%ld read=%ld/%ld server_process=%ld/%ld client_cb=%ld/%ld", + delay, eloop_malloc_time, eloop_malloc_count, eloop_write_time, eloop_write_count, eloop_read_time, eloop_read_count, + eloop_server_process_time, eloop_server_process_count, eloop_client_cb_time, eloop_client_cb_count); + } + } +} + +void delay_warn(const char* msg, int64_t start_us, int64_t warn_us) +{ + if (warn_us > 0) { + int64_t delay = rk_get_corse_us() - start_us; + if (delay > warn_us && PNIO_REACH_TIME_INTERVAL(500*1000)) { + rk_info("%s delay high: %ld, start_us = %ld", msg, delay, start_us); + } + } +} diff --git a/deps/oblib/src/rpc/pnio/r0/define.c b/deps/oblib/src/rpc/pnio/r0/define.c new file mode 100644 index 000000000..2787f364c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/define.c @@ -0,0 +1 @@ +extern void __unused(void* p, ...); diff --git a/deps/oblib/src/rpc/pnio/r0/define.h b/deps/oblib/src/rpc/pnio/r0/define.h new file mode 100644 index 000000000..4fd779d4d --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/define.h @@ -0,0 +1,38 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include + +#define RK_CACHE_ALIGNED __attribute__((aligned(64))) + +inline void __unused(void* p, ...) { (void)p; } +#define unused(args...) __unused(NULL, args) +#define structof(p, T, m) (T*)((char*)p - offsetof(T, m)) +#define arrlen(x) (sizeof(x)/sizeof(x[0])) +#define ef(x) if ((x)) goto el +#define el() el: + +#define STR(x) XSTR(x) +#define XSTR(x) #x +#define RK_WEAK __attribute__((weak)) +#define rk_max(a,b) ({ typeof (a) _a = (a), _b = (b); _a > _b ? _a : _b; }) +#define rk_min(a,b) ({ typeof (a) _a = (a), _b = (b); _a < _b ? _a : _b; }) + +#include +//#define rk_debug(...) DEBUG(rk_info(__VA_ARGS__)) +#define rk_debug(...) + +#ifndef likely +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely + +#define unlikely(x) __builtin_expect((x),0) +#endif +static uint64_t upalign8(uint64_t x) { return (x + 7) & ~7ULL; } +#define ignore_ret_value(exp) {int ignore __attribute__ ((unused)) = (exp);} \ No newline at end of file diff --git a/deps/oblib/src/rpc/pnio/r0/format.c b/deps/oblib/src/rpc/pnio/r0/format.c new file mode 100644 index 000000000..6db01525c --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/format.c @@ -0,0 +1,52 @@ +void format_init(format_t* f, int64_t limit) { + f->limit = limit; + f->pos = 0; +} + +void format_reset(format_t* f) { + f->pos = 0; + f->buf[0] = 0; +} + +char* format_gets(format_t* f) { + return f->buf; +} + +char* format_vsf(format_t* f, const char* format, va_list ap) { + char* buf = f->buf + f->pos; + int64_t limit = f->limit - f->pos; + int64_t cnt = vsnprintf(buf, limit, format, ap); + if (cnt < 0 || cnt >= limit) { + format_reset(f); + } else { + f->pos += cnt; + } + return buf; +} + +char* format_append(format_t* f, const char* format, ...) { + char* ret = NULL; + va_list ap; + va_start(ap, format); + ret = format_vsf(f, format, ap); + va_end(ap); + return ret; +} + +char* format_sf(format_t* f, const char* format, ...) { + char* ret = NULL; + va_list ap; + f->pos++; + va_start(ap, format); + ret = format_vsf(f, format, ap); + va_end(ap); + return ret; +} + +char *strf(char* buf, int64_t size, const char *f, ...) { + va_list ap; + va_start(ap, f); + vsnprintf(buf, size, f, ap); + va_end(ap); + return buf; +} diff --git a/deps/oblib/src/rpc/pnio/r0/format.h b/deps/oblib/src/rpc/pnio/r0/format.h new file mode 100644 index 000000000..f5c95614d --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/format.h @@ -0,0 +1,13 @@ +#include +typedef struct format_t { + int64_t limit; + int64_t pos; + char buf[1024]; +} format_t; + +extern void format_init(format_t* f, int64_t limit); +extern void format_reset(format_t* f); +extern char* format_gets(format_t* f); +extern char* format_append(format_t* f, const char* format, ...) __attribute__((format(printf, 2, 3))); +extern char* format_sf(format_t* f, const char* format, ...) __attribute__((format(printf, 2, 3))); +extern char* strf(char* buf, int64_t size, const char *f, ...) __attribute__((format(printf, 3, 4))) ; diff --git a/deps/oblib/src/rpc/pnio/r0/futex.c b/deps/oblib/src/rpc/pnio/r0/futex.c new file mode 100644 index 000000000..147f61241 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/futex.c @@ -0,0 +1,22 @@ +#include +#ifdef futex +#define rk_futex(...) futex(__VA_ARGS__) +#else +#define rk_futex(...) ((int)syscall(SYS_futex, __VA_ARGS__)) +#endif + +int rk_futex_wake(int *p, int val) { + int err = 0; + if (0 != rk_futex((uint *)p, FUTEX_WAKE_PRIVATE, val, NULL)) { + err = errno; + } + return err; +} + +int rk_futex_wait(int *p, int val, const struct timespec *timeout) { + int err = 0; + if (0 != rk_futex((uint *)p, FUTEX_WAIT_PRIVATE, val, timeout)) { + err = errno; + } + return err; +} diff --git a/deps/oblib/src/rpc/pnio/r0/futex.h b/deps/oblib/src/rpc/pnio/r0/futex.h new file mode 100644 index 000000000..c3a94edbe --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/futex.h @@ -0,0 +1,2 @@ +extern int rk_futex_wake(int *p, int val); +extern int rk_futex_wait(int *p, int val, const struct timespec *timeout); diff --git a/deps/oblib/src/rpc/pnio/r0/get_us.c b/deps/oblib/src/rpc/pnio/r0/get_us.c new file mode 100644 index 000000000..1e2677ae7 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/get_us.c @@ -0,0 +1,13 @@ +#include +int64_t rk_get_us() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} + +int64_t rk_get_corse_us() +{ + struct timespec tp; + clock_gettime(CLOCK_REALTIME_COARSE, &tp); + return tp.tv_sec * 1000000 + tp.tv_nsec/1000; +} diff --git a/deps/oblib/src/rpc/pnio/r0/get_us.h b/deps/oblib/src/rpc/pnio/r0/get_us.h new file mode 100644 index 000000000..ad2cd437b --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/get_us.h @@ -0,0 +1,2 @@ +extern int64_t rk_get_us(); +extern int64_t rk_get_corse_us(); diff --git a/deps/oblib/src/rpc/pnio/r0/log.c b/deps/oblib/src/rpc/pnio/r0/log.c new file mode 100644 index 000000000..44d745665 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/log.c @@ -0,0 +1,42 @@ +__thread format_t g_log_fbuf = { sizeof(g_log_fbuf.buf), 0, "" }; +#include +void do_log(int level, const char* file, int lineno, const char* func, const char* format, ...) { + va_list ap; + va_start(ap, format); + g_log_func(level, file, lineno, func, format, ap); + va_end(ap); +} + +pid_t rk_gettid() { return syscall(SYS_gettid); } + +static const char* get_log_level_str(int level) { + const char* log_level_str[] = {"ERROR", "USER_ERROR", "WARN", "INFO", "TRACE", "DEBUG"}; + return (level >= 0 && level < (int)arrlen(log_level_str)) ? log_level_str[level]: "XXX"; +} + +static const char* format_ts(char* buf, int64_t limit, int64_t time_us) { + const char* format = "%Y-%m-%d %H:%M:%S"; + buf[0] = '\0'; + struct tm time_struct; + int64_t time_s = time_us / 1000000; + int64_t cur_second_time_us = time_us % 1000000; + if (NULL != localtime_r(&time_s, &time_struct)) { + int64_t pos = strftime(buf, limit, format, &time_struct); + if (pos < limit) { + snprintf(buf + pos, limit - pos, ".%.6ld", cur_second_time_us); + } + } + return buf; +} + +static void log_print(const char* s) { fprintf(stderr, "%s\n", s); } +void default_log_func(int level, const char* file, int lineno, const char* func, const char* format, va_list ap) { + char time_str[128] = ""; + format_t f = {sizeof(f.buf), 0, ""}; + format_append(&f, "[%s] %s %s %s:%d [%d] ", format_ts(time_str, sizeof(time_str), rk_get_us()), get_log_level_str(level), func, file, lineno, rk_gettid()); + format_vsf(&f, format, ap); + log_print(format_gets(&f)); +} + +int g_log_level = LOG_LEVEL_INFO; +log_func_t g_log_func = default_log_func; diff --git a/deps/oblib/src/rpc/pnio/r0/log.h b/deps/oblib/src/rpc/pnio/r0/log.h new file mode 100644 index 000000000..1269ae631 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/r0/log.h @@ -0,0 +1,22 @@ +#include +#include +#include + +typedef void (*log_func_t)(int level, const char *file, int line, const char *function, const char *fmt, va_list ap); +extern void do_log(int level, const char* file, int line, const char* func, const char* format, ...) __attribute__((format(printf, 5, 6))); + +extern log_func_t g_log_func; +extern int g_log_level; +enum { LOG_LEVEL_ERROR = 0, LOG_LEVEL_USER_LEVEL = 1, LOG_LEVEL_WARN = 2, LOG_LEVEL_INFO = 3, LOG_LEVEL_TRACE = 4, LOG_LEVEL_DEBUG = 5 }; + + +extern __thread format_t g_log_fbuf; +#ifndef rk_log_macro +#define rk_log_macro(level, ret, ...) { if (LOG_LEVEL_ ## level <= g_log_level) do_log(LOG_LEVEL_ ## level, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } +#endif +#define do_rk_log_macro(...) { format_reset(&g_log_fbuf); rk_log_macro(__VA_ARGS__); } +#define rk_error(...) do_rk_log_macro(ERROR, oceanbase::common::OB_ERR_SYS, ##__VA_ARGS__) +#define rk_info(...) do_rk_log_macro(INFO, oceanbase::common::OB_SUCCESS, ##__VA_ARGS__) +#define rk_warn(...) do_rk_log_macro(WARN, oceanbase::common::OB_SUCCESS, ##__VA_ARGS__) +#define rk_fatal(...) { rk_error(__VA_ARGS__); exit(1); } +#define T2S(type, obj) type ## _str(&g_log_fbuf, obj) diff --git a/deps/oblib/src/rpc/pnio/test/test-basic.c b/deps/oblib/src/rpc/pnio/test/test-basic.c new file mode 100644 index 000000000..295625bf3 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/test/test-basic.c @@ -0,0 +1,168 @@ +#include "interface/pkt-nio.h" +#include + +addr_t dest_addr; +#define N 1 +eloop_t ep_[N]; +pkts_t pkts_[N]; +pktc_t pktc_[N]; +pkts_cfg_t svr_cfg; + +char big_req[1<<21]; +void mock_msg_init(str_t* msg, int64_t id, int64_t sz) +{ + eh_copy_msg(msg, id, big_req, sz); +} + +void pkts_flush_cb_func(pkts_req_t* req) +{ + mod_free(req); +} + +int64_t handle_cnt; +pkts_req_t* create_resp(int64_t sz, uint64_t pkt_id, uint64_t sock_id) +{ + pkts_req_t* r = mod_alloc(sizeof(*r) + sizeof(easy_head_t) + sz, MOD_PKTS_RESP); + r->errcode = 0; + r->flush_cb = pkts_flush_cb_func; + r->sock_id = sock_id; + mock_msg_init(&r->msg, pkt_id, sz); + return r; +} + +int pkts_handle_func(pkts_t* pkts, void* req_handle, const char* b, int64_t s, uint64_t chid) +{ + uint64_t pkt_id = eh_packet_id(b); + if (pkt_id == 0) abort(); + //rk_info("pkts handle: chid=%lx pkt_id=%lx", chid, pkt_id); + FAA(&handle_cnt, 1); + ref_free(req_handle); + pkts_resp(pkts, create_resp(48, pkt_id, chid)); + return 0; +} + +void init_svr_cfg(pkts_cfg_t* cfg) +{ + cfg->accept_qfd = -1; + cfg->addr = dest_addr; + cfg->handle_func = pkts_handle_func; +} + +int64_t cb_cnt = 0; +void pktc_flush_cb_func(pktc_req_t* r) +{ + if (NULL == r->resp_cb) { + mod_free(r); + } +} + +void pktc_resp_cb(pktc_cb_t* cb, const char* resp, int64_t sz) +{ + FAA(&cb_cnt, 1); + mod_free(cb); +} + +pktc_req_t* create_req_with_cb(int64_t id, int64_t sz) +{ + pktc_cb_t* cb = mod_alloc(sizeof(*cb) + sizeof(pktc_req_t) + sizeof(easy_head_t) + sz, MOD_PKTC_CB); + cb->id = id; + cb->expire_us = rk_get_us() + 100000000; + cb->resp_cb = pktc_resp_cb; + pktc_req_t* r = (typeof(r))(cb + 1); + r->flush_cb = pktc_flush_cb_func; + r->resp_cb = cb; + r->dest = dest_addr; + mock_msg_init(&r->msg, id, sz); + return r; +} + +pktc_req_t* create_req(int64_t sz) +{ + pktc_req_t* r = mod_alloc(sizeof(pktc_req_t) + sizeof(easy_head_t) + sz, MOD_PKTC_REQ); + r->resp_cb = NULL; + r->dest = dest_addr; + mock_msg_init(&r->msg, 0, sz); + return r; +} + +int io_thread(int i) +{ + eloop_run(ep_ + i); + return 0; +} + +void stress_limit(uint64_t pkt_id) +{ + while(LOAD(&cb_cnt) + 1000 < pkt_id) + ; +} + +int64_t g_pkt_id = 0; +int stress_thread(int i) +{ + pktc_t* pktc = pktc_ + i; + int err = 0; + while(1) { + uint64_t pkt_id = AAF(&g_pkt_id, 1); + stress_limit(pkt_id); + int64_t req_sz = random() % sizeof(big_req); + err = pktc_post(pktc, create_req_with_cb(pkt_id, req_sz)); + //err = pktc_post(pktc, create_req(48)); + assert(0 == err); + } + return 0; +} + +void* thread_func(void* arg) +{ + int64_t idx = (int64_t)arg; + if (idx < N) { + io_thread(idx); + } else { + stress_thread(idx - N); + } + return NULL; +} + +void report() +{ + int64_t last_handle_cnt = 0; + int64_t last_cb_cnt = 0; + format_t f; + format_init(&f, sizeof(f.buf)); + while(1) { + format_reset(&f); + mod_report(&f); + printf("handle: %ld cb: %ld alloc: %s\n", handle_cnt - last_handle_cnt, cb_cnt - last_cb_cnt, format_gets(&f)); + last_handle_cnt = handle_cnt; + last_cb_cnt = cb_cnt; + usleep(1000 * 1000); + } +} + +int main() +{ + int err = 0; + addr_init(&dest_addr, "127.0.0.1", 8042); + init_svr_cfg(&svr_cfg); + for(int i = 0; i < N; i++) { + eloop_init(ep_ + i); + if (0 != (err = pkts_init(pkts_ + i, ep_ + i, &svr_cfg))) { + abort(); + } + if (0 != (err = pktc_init(pktc_ + i, ep_ + i, 0))) { + abort(); + } + } + pthread_t thd[2 * N]; + for(int64_t i = 0; i < 2 * N; i++) { + pthread_create(thd + i, NULL, thread_func, (void*)i); + } + report(); + for(int64_t i = 0; i < 2 * N; i++) { + pthread_join(thd[i], NULL); + } + return 0; +} + +#include "interface/pkt-nio.c" diff --git a/deps/oblib/src/rpc/pnio/test/test-cfifo.c b/deps/oblib/src/rpc/pnio/test/test-cfifo.c new file mode 100644 index 000000000..58a6f5b9d --- /dev/null +++ b/deps/oblib/src/rpc/pnio/test/test-cfifo.c @@ -0,0 +1,28 @@ +#include "interface/pkt-nio.h" +#include + +#define N 16 +cfifo_alloc_t alloc; +void* thread_func(void* arg) +{ + for(int i = 0; i < 10000000; i++) { + void* ret = cfifo_alloc(&alloc, 40); + cfifo_free(ret); + } + return NULL; +} + +int main() +{ + pthread_t th[N]; + cfifo_alloc_init(&alloc, 0); + for(int i = 0; i < N; i++) { + pthread_create(th + i, NULL, thread_func, NULL); + } + for(int i = 0; i < N; i++) { + pthread_join(th[i], NULL); + } + return 0; +} + +#include "interface/pkt-nio.c" diff --git a/deps/oblib/src/rpc/pnio/test/test-group.c b/deps/oblib/src/rpc/pnio/test/test-group.c new file mode 100644 index 000000000..255f2b9ce --- /dev/null +++ b/deps/oblib/src/rpc/pnio/test/test-group.c @@ -0,0 +1,133 @@ +const char* usage = "./usage:\n" + "./test-multi all\n" + "dest=127.0.0.1 stress_thread=1 ./test-multi client\n" + "stress_thread=1 io_thread=1 ./test-multi server\n"; +#include "interface/group.h" +#include "r0/futex.h" +#include "r0/atomic.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +static void thread_counter_reg(); +static int64_t thread_counter_sum(int64_t* addr); +extern int64_t rk_get_corse_us(); + +int grp = 1; +struct sockaddr_in dest_addr; +__thread int64_t handle_cnt; +__thread int64_t cb_cnt; + +int serve_cb(int grp, const char* b, int64_t sz, uint64_t req_id) +{ + handle_cnt++; + pn_resp(req_id, b, sz); + return 0; +} + +int client_cb(void* arg, int error, const char* b, int64_t sz) +{ + cb_cnt++; + int* cond = (typeof(cond))arg; + if (cond) { + (*cond)++; + rk_futex_wake(cond, 1); + } + return 0; +} + +void* stress_thread(void* arg) +{ + int64_t tid = (int64_t)arg; + int cond = 0; + thread_counter_reg(); + prctl(PR_SET_NAME, "stress"); + srand((unsigned)time(NULL)); + for(int i = 0; ;i++) { + int msg_length = 16 + rand() % 4080; +#ifndef LARGEPACKET_ERRSIM_FREQ +#define LARGEPACKET_ERRSIM_FREQ 10 +#endif +#ifdef PNIO_ERRSIM + if (rand() % LARGEPACKET_ERRSIM_FREQ == 0) { + msg_length = 8*1024*1024 + rand()%(8*1024*1024); + } +#endif + char *msg = (char*)malloc(msg_length); + int* pcond = (i & 0xff)? NULL: &cond; + pn_send(((int64_t)grp<<32) + tid, &dest_addr, msg, msg_length, 0, rk_get_corse_us() + 10000000, client_cb, pcond); + free(msg); + usleep(0.005*1000*1000); + if (pcond) { + int cur_cond = 0; + while((cur_cond = LOAD(pcond)) < ((i>>8) - 64)) { + rk_futex_wait(pcond, cur_cond, NULL); + } + } + } +} + +void report(); +static struct sockaddr_in* rk_make_unix_sockaddr(struct sockaddr_in *sin, in_addr_t ip, int port); +#define cfg(k, v) (getenv(k)?:v) +#define cfgi(k, v) atoi(getenv(k)?:v) +#define streq(s1, s2) (0 == strcmp(s1, s2)) +int main(int argc, char** argv) +{ +#ifdef PNIO_ERRSIM + srand((unsigned)time(NULL)); +#endif + if (argc != 2) { + fprintf(stderr, "%s\n", usage); + return 1; + } + signal(SIGPIPE, SIG_IGN); + const char* mode = argv[1]; + int lfd = -1; + if (streq(mode, "server") || streq(mode, "all")) { + lfd = pn_listen(8042, serve_cb); + } + int cnt = pn_provision(lfd, grp, cfgi("io_thread", "1")); + if (cnt != cfgi("io_thread", "1")) { + printf("pn_provision failed, cnt = %d", cnt); + if (cnt <= 0) { + exit(-1); + } + } + rk_make_unix_sockaddr(&dest_addr, inet_addr(cfg("dest", "127.0.0.1")), 8042); + if (streq(mode, "client") || streq(mode, "all")) { + int stress_count = cfgi("stress_thread", "1"); + pthread_t thd[1024]; + for(int64_t i = 0; i < stress_count; i++) { + pthread_create(thd +i, NULL, stress_thread, (void*)i); + } + } + report(); + return 0; +} + +#include "pkt-nio.c" + +void report() +{ + int64_t last_handle_cnt = 0; + int64_t last_cb_cnt = 0; + format_t f; + format_init(&f, sizeof(f.buf)); + while(1) { + format_reset(&f); + mod_report(&f); + int64_t cur_cb_cnt = thread_counter_sum(&cb_cnt); + int64_t cur_handle_cnt = thread_counter_sum(&handle_cnt); + printf("handle: %ld cb: %ld alloc: %s\n", cur_handle_cnt - last_handle_cnt, cur_cb_cnt - last_cb_cnt, format_gets(&f)); + last_handle_cnt = cur_handle_cnt; + last_cb_cnt = cur_cb_cnt; + usleep(1000 * 1000); + } +} diff --git a/deps/oblib/src/rpc/pnio/test/test-nio.cpp b/deps/oblib/src/rpc/pnio/test/test-nio.cpp new file mode 100644 index 000000000..212d08a57 --- /dev/null +++ b/deps/oblib/src/rpc/pnio/test/test-nio.cpp @@ -0,0 +1,82 @@ +const char* _usage = "io=1 client=1 server='' ./test-nio run\n"; +#include "cpp/rpc_interface.h" +#include "cpp/sync_resp_cb.h" + +Nio nio_; +addr_t dest_addr; +int64_t handle_cnt; +int64_t cb_cnt; + +class ReqHandler: public IReqHandler +{ +public: + ReqHandler() {} + virtual ~ReqHandler() {} + int handle_req(ReqHandleCtx* ctx, const char* buf, int64_t sz) { + const char resp[] = "hello from server"; + ctx->resp(resp, sizeof(resp)); + FAA(&handle_cnt, 1); + return 0; + } +private: + RpcMemPool pool_; +} req_handler; + +static char big_req[1<<21]; +void* thread_func(void* arg) +{ + unused(arg); + while(1) { + SyncRespCallback* resp_cb = SyncRespCallback::create(); + nio_.post(dest_addr, big_req, random() % sizeof(big_req), resp_cb, 1 * 1000000); + int64_t sz = 0; + resp_cb->wait(sz); + FAA(&cb_cnt, 1); + resp_cb->free_req(); + } + return NULL; +} + +void report() +{ + int64_t last_handle_cnt = 0; + int64_t last_cb_cnt = 0; + format_t f; + format_init(&f, sizeof(f.buf)); + while(1) { + format_reset(&f); + mod_report(&f); + printf("handle: %ld cb: %ld alloc: %s\n", handle_cnt - last_handle_cnt, cb_cnt - last_cb_cnt, format_gets(&f)); + last_handle_cnt = handle_cnt; + last_cb_cnt = cb_cnt; + usleep(1000 * 1000); + } +} + +#define cfg(k,v) (getenv(k)?:v) +#define cfgi(k,v) atoi(cfg(k,v)) +int main(int argc, char** argv) +{ + int io_thread_count = cfgi("io", "1"); + int client_thread_count = cfgi("client", "1"); + const char* svr_ip = cfg("server", ""); + if (argc < 2) { + fprintf(stderr, "%s", _usage); + return -1; + } + int listen_port = 8042; + int need_listen = svr_ip[0] == 0; + addr_init(&dest_addr, need_listen? "127.0.0.1": svr_ip, listen_port); + //memset(big_req, 1, sizeof(big_req)); + pthread_t pd[client_thread_count]; + nio_.start(&req_handler, need_listen? listen_port: 0, io_thread_count); + for(int64_t i = 0; i < client_thread_count; i++) { + pthread_create(pd + i, NULL, thread_func, (int64_t*)i); + } + report(); + return 0; +} + +extern "C" { + #include "pkt-nio.c" +}; diff --git a/deps/oblib/unittest/lib/allocator/test_allocator_performance.cpp b/deps/oblib/unittest/lib/allocator/test_allocator_performance.cpp index 2ffdc1bbd..d23a4d06d 100644 --- a/deps/oblib/unittest/lib/allocator/test_allocator_performance.cpp +++ b/deps/oblib/unittest/lib/allocator/test_allocator_performance.cpp @@ -188,39 +188,6 @@ private: DISALLOW_COPY_AND_ASSIGN(ObjPoolAllocator); }; -template -class ObjPoolTCAllocator : public BaseAllocator -{ -public: - ObjPoolTCAllocator() - { - - } - - virtual void reset() - { - } - - virtual void *alloc() - { - return(op_tc_alloc(TestObj)); - } - - virtual void free(void *p) - { - op_tc_free((TestObj*)p); - } - - virtual ~ObjPoolTCAllocator() - { - } - -private: - int64_t size_; - - DISALLOW_COPY_AND_ASSIGN(ObjPoolTCAllocator); -}; - class DirectAllocator : public BaseAllocator { public: @@ -732,18 +699,6 @@ TEST(TestSimpleAllocate, objpool) ASSERT_TRUE(engine.run() >= 0); } -TEST(TestSimpleAllocate, objpool_tc) -{ - int64_t max_thread = get_cpu_num() * 2; - Params params; - params.simple_param.times = ALLOC_TIME_PER_THREAD; - - ObjPoolTCAllocator allocator; - TestEngine engine(&allocator, max_thread, &simple_worker, params); - - ASSERT_TRUE(engine.run() >= 0); -} - TEST(TestSimpleAllocate, ob_malloc) { int64_t max_thread = get_cpu_num() * 2; @@ -795,19 +750,6 @@ TEST(TestWindowAllocate, objpool) ASSERT_TRUE(engine.run() >= 0); } -TEST(TestWindowAllocate, objpool_tc) -{ - int64_t max_thread = get_cpu_num() * 2; - Params params; - params.window_param.times = ALLOC_TIME_PER_THREAD; - params.window_param.window_len = WINDOW_SIZE; - - ObjPoolTCAllocator allocator; - TestEngine engine(&allocator, max_thread, &window_worker, params); - - ASSERT_TRUE(engine.run() >= 0); -} - TEST(TestWindowAllocate, ob_malloc) { int64_t max_thread = get_cpu_num() * 2; @@ -836,21 +778,6 @@ TEST(TestPairwiseAllocate, lf_fifo) free(params.pairwise_param.addr_queue); } -TEST(TestPairwiseAllocate, objpool_tc) -{ - int64_t max_thread = get_core_num() * 2; - Params params; - params.pairwise_param.times = ALLOC_TIME_PER_THREAD; - params.pairwise_param.addr_queue = (unsigned long int *)malloc(sizeof(unsigned long int) * MAX_THREAD * QUEUE_SIZE); - - ObjPoolTCAllocator allocator; - TestEngine engine(&allocator, max_thread, &pairwise_worker, params, true); - - ASSERT_TRUE(engine.run() >= 0); - - free(params.pairwise_param.addr_queue); -} - TEST(TestPairwiseAllocate, objpool) { int64_t max_thread = get_core_num() * 2; diff --git a/deps/oblib/unittest/lib/charset/test_charset.cpp b/deps/oblib/unittest/lib/charset/test_charset.cpp index c2c6aedec..ac085e4d0 100644 --- a/deps/oblib/unittest/lib/charset/test_charset.cpp +++ b/deps/oblib/unittest/lib/charset/test_charset.cpp @@ -15,6 +15,7 @@ #include #include #include +#include "lib/allocator/page_arena.h" #include "lib/charset/ob_charset.h" #include "lib/string/ob_string.h" #include "lib/utility/ob_print_utils.h" diff --git a/deps/oblib/unittest/lib/hash/test_cuckoo_hashmap.cpp b/deps/oblib/unittest/lib/hash/test_cuckoo_hashmap.cpp index cc633c251..093f53083 100644 --- a/deps/oblib/unittest/lib/hash/test_cuckoo_hashmap.cpp +++ b/deps/oblib/unittest/lib/hash/test_cuckoo_hashmap.cpp @@ -11,6 +11,7 @@ */ #include "gtest/gtest.h" +#include "lib/allocator/page_arena.h" #include "lib/hash/ob_cuckoo_hashmap.h" #include "lib/hash/ob_hashmap.h" diff --git a/deps/oblib/unittest/lib/queue/test_priority_queue.cpp b/deps/oblib/unittest/lib/queue/test_priority_queue.cpp index 18a644469..93f39a9a1 100644 --- a/deps/oblib/unittest/lib/queue/test_priority_queue.cpp +++ b/deps/oblib/unittest/lib/queue/test_priority_queue.cpp @@ -72,7 +72,7 @@ public: int err; QData* data = NULL; if (idx == 0) { - err = queue_.pop_high_high((ObLink*&)data, 10000); + err = queue_.pop_high((ObLink*&)data, 10000); } else { err = queue_.pop((ObLink*&)data, 10000); } diff --git a/deps/oblib/unittest/lib/stat/test_diagnose_info.cpp b/deps/oblib/unittest/lib/stat/test_diagnose_info.cpp index 41a9744bc..1b55c191b 100644 --- a/deps/oblib/unittest/lib/stat/test_diagnose_info.cpp +++ b/deps/oblib/unittest/lib/stat/test_diagnose_info.cpp @@ -42,22 +42,22 @@ namespace common TEST(ObDiagnoseSessionInfo, guard) { EVENT_INC(ELECTION_CHANGE_LEAER_COUNT); - EXPECT_EQ(1, ObDITls::get_instance()->get_tenant_id()); + EXPECT_EQ(1, GET_TSI(ObSessionDIBuffer)->get_tenant_id()); EXPECT_EQ(1, TENANT_EVENT_GET(ObStatEventIds::ELECTION_CHANGE_LEAER_COUNT)); { ObTenantStatEstGuard tenant_guard(2); EVENT_INC(ELECTION_CHANGE_LEAER_COUNT); - EXPECT_EQ(2, ObDITls::get_instance()->get_tenant_id()); + EXPECT_EQ(2, GET_TSI(ObSessionDIBuffer)->get_tenant_id()); EXPECT_EQ(1, TENANT_EVENT_GET(ObStatEventIds::ELECTION_CHANGE_LEAER_COUNT)); { ObTenantStatEstGuard tenant_guard(3); EVENT_INC(ELECTION_CHANGE_LEAER_COUNT); - EXPECT_EQ(3, ObDITls::get_instance()->get_tenant_id()); + EXPECT_EQ(3, GET_TSI(ObSessionDIBuffer)->get_tenant_id()); EXPECT_EQ(1, TENANT_EVENT_GET(ObStatEventIds::ELECTION_CHANGE_LEAER_COUNT)); } - EXPECT_EQ(2, ObDITls::get_instance()->get_tenant_id()); + EXPECT_EQ(2, GET_TSI(ObSessionDIBuffer)->get_tenant_id()); } - EXPECT_EQ(1, ObDITls::get_instance()->get_tenant_id()); + EXPECT_EQ(1, GET_TSI(ObSessionDIBuffer)->get_tenant_id()); } TEST(ObDISessionCache, multithread) diff --git a/deps/oblib/unittest/lib/thread/test_thread_pool.cpp b/deps/oblib/unittest/lib/thread/test_thread_pool.cpp index 20fb29faf..00571645d 100644 --- a/deps/oblib/unittest/lib/thread/test_thread_pool.cpp +++ b/deps/oblib/unittest/lib/thread/test_thread_pool.cpp @@ -33,7 +33,6 @@ TEST(TestThreadPool, DISABLED_Submit1) } } tp; tp.init(); - tp.set_thread_max_tasks(1); tp.start(); // submit would success since there's no tasks. @@ -81,7 +80,6 @@ TEST(TestThreadPool, DISABLED_SubmitX) } } tp; tp.init(); - tp.set_thread_max_tasks(1); tp.start(); TIME_LESS(100*1000L, [&tp] { @@ -109,7 +107,6 @@ TEST(TestThreadPool, DISABLED_Submit2) } } tp; tp.init(); - tp.set_thread_max_tasks(2); tp.start(); // submit would success since there's no tasks. @@ -153,7 +150,6 @@ TEST(TestThreadPool, DISABLED_SubmitN) } tp; tp.init(); tp.set_thread_count(4); - tp.set_thread_max_tasks(2); tp.start(); int ret = OB_SUCCESS; @@ -202,7 +198,6 @@ TEST(TestThreadPool, DISABLED_LoopCheckConcurrency) tp.init(); tp.set_thread_count(4); - tp.set_thread_max_tasks(1); tp.start(); for (int i = 0; i < 1000; i++) { diff --git a/deps/oblib/unittest/lib/utility/test_ob_unify_serialize.cpp b/deps/oblib/unittest/lib/utility/test_ob_unify_serialize.cpp index 0b203dbf1..5dc726a08 100644 --- a/deps/oblib/unittest/lib/utility/test_ob_unify_serialize.cpp +++ b/deps/oblib/unittest/lib/utility/test_ob_unify_serialize.cpp @@ -504,6 +504,7 @@ TEST_F(TestObUnifySerialize, CNested2) EXPECT_EQ(pos, n.get_serialize_size()); } +/* TEST_F(TestObUnifySerialize, CNestedCompatibility) { // encode a CNested object @@ -565,6 +566,7 @@ TEST_F(TestObUnifySerialize, CNestedCompatibility) EXPECT_EQ(nn.et_, ns.et_); } } +*/ TEST_F(TestObUnifySerialize, Dummy) { @@ -587,7 +589,6 @@ TEST_F(TestObUnifySerialize, Dummy) struct COptInt { OB_UNIS_VERSION(1); - public: COptInt() : valid_(true), value_(0) @@ -649,7 +650,7 @@ TEST_F(TestObUnifySerialize, OptionallySerialize) // unis compatibility support for refactor class CCompat { OB_UNIS_VERSION(1); - OB_UNIS_COMPAT(VER(2, 2, 3)); + //OB_UNIS_COMPAT(VER(2, 2, 3)); public: bool operator==(const CCompat &rhs) const { @@ -661,9 +662,9 @@ public: int i2_; }; -OB_SERIALIZE_MEMBER(CCompat, i1_, i2_); -OB_SERIALIZE_MEMBER_COMPAT(VER(2, 2, 3), CCompat, i2_, i1_); - +//OB_SERIALIZE_MEMBER(CCompat, i1_, i2_); +//OB_SERIALIZE_MEMBER_COMPAT(VER(2, 2, 3), CCompat, i2_, i1_); +/* class CCompat2 : public CCompat { OB_UNIS_VERSION(1); OB_UNIS_COMPAT(VER(2, 2, 3)); @@ -781,6 +782,7 @@ TEST_F(TestObUnifySerialize, Compat) } } +*/ int main(int argc, char *argv[]) { diff --git a/src/diagnose/lua/ob_lua_api.cpp b/src/diagnose/lua/ob_lua_api.cpp index 7061e7228..390f09f1c 100644 --- a/src/diagnose/lua/ob_lua_api.cpp +++ b/src/diagnose/lua/ob_lua_api.cpp @@ -19,6 +19,7 @@ #include #include "lib/alloc/memory_dump.h" +#include "lib/allocator/ob_mem_leak_checker.h" #include "lib/oblog/ob_log.h" #include "lib/stat/ob_di_cache.h" #include "observer/omt/ob_multi_tenant.h" @@ -26,7 +27,9 @@ #include "observer/virtual_table/ob_all_virtual_sys_stat.h" #include "share/inner_table/ob_inner_table_schema.h" #include "share/ob_tenant_mgr.h" +#include "share/scheduler/ob_dag_warning_history_mgr.h" #include "share/scheduler/ob_sys_task_stat.h" +#include "storage/compaction/ob_compaction_diagnose.h" #include "storage/memtable/ob_lock_wait_mgr.h" #include "storage/tx/ob_trans_ctx_mgr_v4.h" #include "storage/tx/ob_trans_service.h" @@ -64,10 +67,12 @@ public: void *alloc(const int64_t size) override { void *ret = nullptr; - if (0 != size) { - ret = ::mmap(nullptr, size + 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - *static_cast(ret) = size; - ret = (char*)ret + 8; + if (0 != size && ObLuaHandler::get_instance().memory_usage() + size + 8 < ObLuaHandler::LUA_MEMORY_LIMIT) { + if (OB_NOT_NULL(ret = ::mmap(nullptr, size + 8, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) { + *static_cast(ret) = size; + ret = (char*)ret + 8; + ObLuaHandler::get_instance().memory_update(size + 8); + } } return ret; } @@ -80,17 +85,28 @@ public: { if (OB_NOT_NULL(ptr)) { const uint64_t size = *(uint64_t *)((char *)ptr - 8); + ObLuaHandler::get_instance().memory_update(- 8 - size); ::munmap((void *)((char *)ptr - 8), size); } } }; } + +static ObFIFOAllocator &get_global_allocator() +{ + static ObFIFOAllocator allocator; + if (OB_UNLIKELY(!allocator.is_inited())) { + IGNORE_RETURN allocator.init(&LuaAllocator::get_instance(), (1 << 13) - 8, default_memattr, 0, 0, INT64_MAX); + } + return allocator; +} } static constexpr const char *usage_str = "API List:\n\n" "string = usage()\n" "print_to_client(arg1, arg2...)\n" +"int = now()\n" "{int, int, ...} = get_tenant_id_list()\n" "int = get_tenant_mem_limit(int)\n" "int = get_tenant_sysstat_by_id(int, int)\n" @@ -108,7 +124,15 @@ static constexpr const char *usage_str = "{{row1}, {row2}, ...} = select_disk_stat()\n" "{{row1}, {row2}, ...} = select_tenant_memory_info()\n" "string = show_log_probe()\n" -"int = set_log_probe(string)\n"; +"int = set_log_probe(string)\n" +"{{row1}, {row2}, ...} = select_mem_leak_checker_info()\n" +"{{row1}, {row2}, ...} = select_compaction_diagnose_info()\n" +"{{row1}, {row2}, ...} = select_dag_warning_history()\n" +"{{row1}, {row2}, ...} = select_server_schema_info()\n" +"{{row1}, {row2}, ...} = select_schema_slot()\n" +"{{row1}, {row2}, ...} = dump_thread_info()\n" +"{{row1}, {row2}, ...} = select_malloc_sample_info()\n" +; class LuaVtableGenerator { @@ -378,6 +402,19 @@ int print_to_client(lua_State* L) return 0; } +// int = now() +int now(lua_State* L) +{ + int argc = lua_gettop(L); + if (0 != argc) { + OB_LOG_RET(ERROR, OB_ERR_UNEXPECTED, "call get_tenant_id_list() failed, bad arguments count, should be 0."); + lua_pushinteger(L, 0); + } else { + lua_pushinteger(L, common::ObTimeUtility::fast_current_time()); + } + return 1; +} + // list = get_tenant_id_list() int get_tenant_id_list(lua_State* L) { @@ -1055,28 +1092,28 @@ int select_trans_stat(lua_State *L) static constexpr int64_t OB_MIN_BUFFER_SIZE = 128; std::vector columns = { "tenant_id", + "tx_type", + "tx_id", "session_id", "scheduler_addr", - "trans_type", - "trans_id", - "has_decided", + "is_decided", "ls_id", "participants", - "ctx_create_time", + "tx_ctx_create_time", "expired_time", "ref_cnt", "last_op_sn", "pending_write", "state", - "part_trans_action", - "trans_ctx_addr", + "part_tx_action", + "tx_ctx_addr", "mem_ctx_id", "pending_log_size", "flushed_log_size", - "role", + "role_state", "is_exiting", "coord", - "last_request_time", + "last_request_ts", "gtrid", "bqual", "format_id" @@ -1086,17 +1123,17 @@ int select_trans_stat(lua_State *L) gen.next_row(); // tenant_id gen.next_column(tx_stat.tenant_id_); + // tx_type + gen.next_column(tx_stat.tx_type_); + // tx_id + gen.next_column(tx_stat.tx_id_.get_id()); // session_id gen.next_column(tx_stat.session_id_); // scheduler_addr - char addr_buf[32]; - tx_stat.scheduler_addr_.to_string(addr_buf, 32); + char addr_buf[MAX_IP_PORT_LENGTH + 8]; + tx_stat.scheduler_addr_.to_string(addr_buf, MAX_IP_PORT_LENGTH + 8); gen.next_column(addr_buf); - // trans_type - gen.next_column(tx_stat.tx_type_); - // trans_id - gen.next_column(tx_stat.tx_id_.get_id()); - // has_decided + // is_decided gen.next_column(tx_stat.has_decided_); // ls_id gen.next_column(tx_stat.ls_id_.id()); @@ -1106,13 +1143,13 @@ int select_trans_stat(lua_State *L) tx_stat.participants_.to_string(participants_buffer, OB_MAX_BUFFER_SIZE); gen.next_column(participants_buffer); } else { - gen.next_column("NULL"); + ret = iter.get_next(tx_stat); } - // ctx_create_time + // tx_ctx_create_time gen.next_column(tx_stat.tx_ctx_create_time_); // expired_time gen.next_column(tx_stat.tx_expired_time_); - // refer + // ref_cnt gen.next_column(tx_stat.ref_cnt_); // last_op_sn gen.next_column(tx_stat.last_op_sn_); @@ -1120,17 +1157,17 @@ int select_trans_stat(lua_State *L) gen.next_column(tx_stat.pending_write_); // state gen.next_column(tx_stat.state_); - // part_trans_action + // part_tx_action gen.next_column(tx_stat.part_tx_action_); - // trans_ctx_addr - gen.next_column((int64_t)tx_stat.tx_ctx_addr_); + // tx_ctx_addr + gen.next_column((uint64_t)tx_stat.tx_ctx_addr_); // mem_ctx_id - lua_pushinteger(L, 0); + gen.next_column(-1); // pending_log_size - lua_pushinteger(L, tx_stat.pending_log_size_); + gen.next_column(tx_stat.pending_log_size_); // flushed_log_size - lua_pushinteger(L, tx_stat.flushed_log_size_); - // role + gen.next_column(tx_stat.flushed_log_size_); + // role_state gen.next_column(tx_stat.role_state_); // is_exiting gen.next_column(tx_stat.is_exiting_); @@ -1148,9 +1185,9 @@ int select_trans_stat(lua_State *L) gen.row_end(); ret = iter.get_next(tx_stat); } - if (OB_ITER_END != ret) { - OB_LOG(ERROR, "iter failed", K(ret)); - } + } + if (OB_FAIL(ret) && OB_ITER_END != ret) { + OB_LOG(ERROR, "iter failed", K(ret)); } } return 1; @@ -1357,17 +1394,17 @@ int select_dump_tenant_info(lua_State *L) // unit_max_cpu gen.next_column(t.unit_max_cpu_); // slice - gen.next_column(t.slice_); + gen.next_column(0); // remain_slice - gen.next_column(t.slice_remain_); + gen.next_column(0); // token_cnt gen.next_column(t.token_cnt_); // ass_token_cnt - gen.next_column(t.ass_token_cnt_); + gen.next_column(t.worker_count()); // lq_tokens - gen.next_column(t.lq_tokens_); + gen.next_column(0); // used_lq_tokens - gen.next_column(t.used_lq_tokens_); + gen.next_column(0); // stopped gen.next_column(t.stopped_); // idle_us @@ -1387,11 +1424,11 @@ int select_dump_tenant_info(lua_State *L) // recv_large_queries gen.next_column(t.tt_large_quries_); // actives - gen.next_column(t.actives_); + gen.next_column(t.workers_.get_size()); // workers gen.next_column(t.workers_.get_size()); // lq_warting_workers - gen.next_column(t.lq_waiting_workers_.get_size()); + gen.next_column(0); // req_queue_total_size gen.next_column(t.req_queue_.size()); // queue_0 @@ -1407,8 +1444,7 @@ int select_dump_tenant_info(lua_State *L) // queue_5 gen.next_column(t.req_queue_.queue_size(5)); // large_queued - gen.next_column(t.large_req_queue_.size()); - + gen.next_column(t.lq_retry_queue_size()); gen.row_end(); return OB_SUCCESS; }; @@ -1496,6 +1532,447 @@ int select_tenant_memory_info(lua_State *L) return 1; } +// list{list, list...} = select_mem_leak_checker_info() +int select_mem_leak_checker_info(lua_State *L) +{ + int argc = lua_gettop(L); + ObMemLeakChecker* leak_checker = &get_mem_leak_checker(); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_mem_leak_checker_info() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else if (OB_ISNULL(leak_checker)) { + OB_LOG_RET(ERROR, OB_ERR_UNEXPECTED, "leak checker is null"); + lua_pushnil(L); + } else { + int ret = OB_SUCCESS; + ObMemLeakChecker::mod_info_map_t info_map; + if (OB_FAIL(info_map.create(10000))) { + OB_LOG(ERROR, "failed to create hashmap", K(ret)); + } else if (OB_FAIL(leak_checker->load_leak_info_map(info_map))) { + OB_LOG(ERROR, "failed to collection leak info", K(ret)); + } else { + std::vector columns = { + "mod_name", + "mod_type", + "alloc_count", + "alloc_size", + "back_trace" + }; + LuaVtableGenerator gen(L, columns); + for (auto it = info_map->begin(); it != info_map->end() && !gen.is_end(); ++it) { + gen.next_row(); + // mod_name + gen.next_column(leak_checker->get_str()); + // mod_type + gen.next_column("user"); + // alloc_count + gen.next_column(it->second.first); + // alloc_size + gen.next_column(it->second.second); + // back_trace + gen.next_column(it->first.bt_); + + gen.row_end(); + } + } + } + return 1; +} + +// list{list, list...} = select_compaction_diagnose_info() +int select_compaction_diagnose_info(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_compaction_diagnose_info() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else { + int ret = OB_SUCCESS; + compaction::ObCompactionDiagnoseIterator diagnose_info_iter; + // OB_SYS_TENANT_ID means dump all + if (OB_FAIL(diagnose_info_iter.open(OB_SYS_TENANT_ID))) { + OB_LOG(ERROR, "Fail to open suggestion iter", K(ret)); + lua_pushnil(L); + } else { + std::vector columns = { + "tenant_id", + "merge_type", + "ls_id", + "tablet_id", + "status", + "create_time", + "diagnose_info" + }; + LuaVtableGenerator gen(L, columns); + compaction::ObCompactionDiagnoseInfo diagnose_info; + while (OB_SUCC(diagnose_info_iter.get_next_info(diagnose_info)) && !gen.is_end()) { + gen.next_row(); + // tenant_id + gen.next_column(diagnose_info.tenant_id_); + // merge_type + gen.next_column(merge_type_to_str(diagnose_info.merge_type_)); + // ls_id + gen.next_column(diagnose_info.ls_id_); + // tablet_id + gen.next_column(diagnose_info.tablet_id_); + // status + gen.next_column(diagnose_info.get_diagnose_status_str(diagnose_info.status_)); + // create_time + gen.next_column(diagnose_info.timestamp_); + // diagnose_info + gen.next_column(diagnose_info.diagnose_info_); + + gen.row_end(); + } + if (OB_FAIL(ret) && OB_ITER_END != ret) { + OB_LOG(ERROR, "Fail to get next suggestion info", K(ret)); + } + } + } + return 1; +} + +// list{list, list...} = select_dag_warning_history() +int select_dag_warning_history(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_dag_warning_history() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else { + int ret = OB_SUCCESS; + share::ObDagWarningInfoIterator dag_warning_info_iter; + // OB_SYS_TENANT_ID means dump all + if (OB_FAIL(dag_warning_info_iter.open(OB_SYS_TENANT_ID))) { + OB_LOG(ERROR, "Fail to open merge info iter", K(ret)); + lua_pushnil(L); + } else { + std::vector columns = { + "tenant_id", + "task_id", + "module", + "type", + "ret", + "status", + "gmt_create", + "gmt_modified", + "retry_cnt", + "warning_info" + }; + LuaVtableGenerator gen(L, columns); + share::ObDagWarningInfo dag_warning_info; + while (OB_SUCC(dag_warning_info_iter.get_next_info(dag_warning_info)) && !gen.is_end()) { + gen.next_row(); + // tenant_id + gen.next_column(dag_warning_info.tenant_id_); + // task_id + { + char task_id_buf[common::OB_TRACE_STAT_BUFFER_SIZE]; + int64_t n = dag_warning_info.task_id_.to_string(task_id_buf, sizeof(task_id_buf)); + if (n < 0 || n >= sizeof(task_id_buf)) { + ret = OB_BUF_NOT_ENOUGH; + } else { + gen.next_column(task_id_buf); + } + } + // module + gen.next_column(share::ObIDag::get_dag_module_str(dag_warning_info.dag_type_)); + // type + gen.next_column(share::ObIDag::get_dag_type_str(dag_warning_info.dag_type_)); + // ret + gen.next_column(common::ob_error_name(dag_warning_info.dag_ret_)); + // status + gen.next_column(ObDagWarningInfo::get_dag_status_str(dag_warning_info.dag_status_)); + // gmt_create + gen.next_column(dag_warning_info.gmt_create_); + // gmt_modified + gen.next_column(dag_warning_info.gmt_modified_); + // retry_cnt + gen.next_column(dag_warning_info.retry_cnt_); + // warning_info + gen.next_column(dag_warning_info.warning_info_); + + gen.row_end(); + } + } + } + return 1; +} + +// list{list, list...} = select_server_schema_info() +int select_server_schema_info(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_server_schema_info() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else { + int ret = OB_SUCCESS; + const static int64_t DEFAULT_TENANT_NUM = 10; + ObSEArray tenant_ids; + share::schema::ObSchemaGetterGuard guard; + auto& schema_service = OBSERVER.get_root_service().get_schema_service(); + if (OB_FAIL(schema_service.get_tenant_schema_guard(OB_SYS_TENANT_ID, guard))) { + OB_LOG(ERROR, "fail to get schema guard", K(ret)); + lua_pushnil(L); + } else if (OB_FAIL(guard.get_tenant_ids(tenant_ids))) { + OB_LOG(ERROR, "fail to get tenant_ids", K(ret)); + lua_pushnil(L); + } else { + std::vector columns = { + "tenant_id", + "refreshed_schema_version", + "received_schema_version", + "schema_count", + "schema_size", + "min_sstable_schema_version" + }; + LuaVtableGenerator gen(L, columns); + for (uint64_t idx = 0; idx < tenant_ids.count() && !gen.is_end(); ++idx) { + const uint64_t tenant_id = tenant_ids[idx]; + int64_t refreshed_schema_version = OB_INVALID_VERSION; + int64_t received_schema_version = OB_INVALID_VERSION; + int64_t schema_count = OB_INVALID_ID; + int64_t schema_size = OB_INVALID_ID; + if (OB_FAIL(schema_service.get_tenant_refreshed_schema_version(tenant_id, refreshed_schema_version))) { + OB_LOG(ERROR, "fail to get tenant refreshed schema version", K(ret), K(tenant_id), K(refreshed_schema_version)); + } else if (OB_FAIL(schema_service.get_tenant_received_broadcast_version(tenant_id, received_schema_version))) { + OB_LOG(ERROR, "fail to get tenant receieved schema version", K(ret), K(tenant_id), K(received_schema_version)); + } else { + int tmp_ret = OB_SUCCESS; + if (OB_SUCCESS != (tmp_ret = schema_service.get_tenant_schema_guard(tenant_id, guard))) { + OB_LOG(ERROR, "fail to get schema guard", K(tmp_ret), K(tenant_id)); + } else if (OB_SUCCESS != (tmp_ret = guard.get_schema_count(tenant_id, schema_count))) { + OB_LOG(ERROR, "fail to get schema count", K(tmp_ret), K(tenant_id)); + } else if (OB_SUCCESS != (tmp_ret = guard.get_schema_size(tenant_id, schema_size))) { + OB_LOG(ERROR, "fail to get schema size", K(tmp_ret), K(tenant_id)); + } + gen.next_row(); + // tenant_id + gen.next_column(tenant_id); + // refreshed_schema_version + gen.next_column(refreshed_schema_version); + // received_schema_version + gen.next_column(received_schema_version); + // schema_count + gen.next_column(schema_count); + // schema_size + gen.next_column(schema_size); + // min_sstable_schema_version + gen.next_column(OB_INVALID_VERSION); + + gen.row_end(); + } + } + } + } + return 1; +} + +// list{list, list...} = select_schema_slot() +int select_schema_slot(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_schema_slot() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else { + int ret = OB_SUCCESS; + auto& schema_service = OBSERVER.get_root_service().get_schema_service(); + const static int64_t DEFAULT_TENANT_NUM = 10; + ObSEArray tenant_ids; + if (OB_FAIL(schema_service.get_schema_store_tenants(tenant_ids))) { + OB_LOG(ERROR, "fail to get schema store tenants", K(ret)); + lua_pushnil(L); + } else { + std::vector columns = { + "tenant_id", + "slot_id", + "schema_version", + "schema_count", + "total_ref_cnt", + "ref_info" + }; + LuaVtableGenerator gen(L, columns); + for (int64_t idx = 0; idx < tenant_ids.count() && !gen.is_end(); ++idx) { + const static int64_t DEFAULT_SLOT_NUM = 32; + ObSEArray schema_slot_infos; + uint64_t tenant_id = tenant_ids[idx]; + if (OB_FAIL(schema_service.get_tenant_slot_info(get_global_allocator(), tenant_id, schema_slot_infos))) { + OB_LOG(ERROR, "fail to get tenant slot info", K(ret), K(tenant_id)); + } else { + for (int64_t slot_idx = 0; slot_idx < schema_slot_infos.count() && !gen.is_end(); ++slot_idx) { + auto& schema_slot = schema_slot_infos.at(slot_idx); + gen.next_row(); + // tenant_id + gen.next_column(schema_slot.get_tenant_id()); + // slot_id + gen.next_column(schema_slot.get_slot_id()); + // schema_version + gen.next_column(schema_slot.get_schema_version()); + // schema_count + gen.next_column(schema_slot.get_schema_count()); + // total_ref_cnt + gen.next_column(schema_slot.get_ref_cnt()); + // ref_info + if (OB_NOT_NULL(schema_slot.get_mod_ref_infos().ptr())) { + gen.next_column(schema_slot.get_mod_ref_infos()); + } else { + gen.next_column(""); + } + + gen.row_end(); + } + } + for (int64_t slot_idx = 0; slot_idx < schema_slot_infos.count(); ++slot_idx) { + auto* ptr = schema_slot_infos.at(slot_idx).get_mod_ref_infos().ptr(); + if (OB_NOT_NULL(ptr)) { + get_global_allocator().free((void*)ptr); + } + schema_slot_infos.at(slot_idx).reset(); + } + schema_slot_infos.reset(); + } + } + } + return 1; +} + +// list{list, list...} = dump_threads_info() +int dump_thread_info(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call dump_thread_info() failed, bad arguments count, should be less than 2."); + } else { + std::vector columns = { + "tname", + "tid", + "thread_base", + "loop_ts", + "lock_addr", + "lock_val", + "wait_addr", + "wait_val", + "is_blocking", + "has_req" + }; + LuaVtableGenerator gen(L, columns); + int64_t tname_offset = (int64_t)ob_get_tname() - (int64_t)pthread_self(); + int64_t tid_offset = (int64_t)(&get_tid_cache()) - (int64_t)pthread_self(); + int64_t loop_ts_offset = (int64_t)(&oceanbase::lib::Thread::loop_ts_) - (int64_t)pthread_self(); + int64_t lock_offset = (int64_t)(&ObLatch::current_lock) - (int64_t)pthread_self(); + int64_t wait_offset = (int64_t)(&ObLatch::current_wait) - (int64_t)pthread_self(); + int64_t worker_offset = (int64_t)(&oceanbase::lib::Worker::self_) - (int64_t)pthread_self(); + for(auto* header = g_stack_mgr.begin(); header != g_stack_mgr.end() && !gen.is_end(); header = header->next_) { + auto* thread_base = (char*)(header->pth_); + if (OB_NOT_NULL(thread_base)) { + // avoid SMART_CALL stack + char* tname = thread_base + tname_offset; + int64_t tid = *(int64_t*)(thread_base + tid_offset); + int64_t loop_ts = *(int64_t*)(thread_base + loop_ts_offset); + uint32_t* lock_addr = *(uint32_t**)(thread_base + lock_offset); + uint32_t* wait_addr = *(uint32_t**)(thread_base + wait_offset); + auto* worker_self = *(Worker**)(thread_base + worker_offset); + char addr[32]; + gen.next_row(); + // tname + gen.next_column(tname); + // tid + gen.next_column(tid); + // thread_base + snprintf(addr, 32, "%p", thread_base); + gen.next_column(addr); + // loop_ts + gen.next_column(loop_ts); + // lock_addr + // lock_val + if (OB_NOT_NULL(lock_addr)) { + snprintf(addr, 32, "%p", lock_addr); + gen.next_column(addr); + gen.next_column(*lock_addr); + } else { + gen.next_column("NULL"); + gen.next_column("NULL"); + } + // wait_addr + // wait_val + if (OB_NOT_NULL(wait_addr)) { + snprintf(addr, 32, "%p", wait_addr); + gen.next_column(addr); + gen.next_column(*wait_addr); + } else { + gen.next_column("NULL"); + gen.next_column("NULL"); + } + // is_blocking + // has_req + if (OB_NOT_NULL(worker_self)) { + gen.next_column(worker_self->is_blocking()); + gen.next_column(worker_self->has_req_flag()); + } else { + gen.next_column("NULL"); + gen.next_column("NULL"); + } + + gen.row_end(); + } + } + } + return 1; +} + +// list{list, list...} = select_malloc_sample_info() +int select_malloc_sample_info(lua_State *L) +{ + int ret = OB_SUCCESS; + int argc = lua_gettop(L); + ObMallocSampleMap malloc_sample_map; + if (argc > 1) { + OB_LOG_RET(ERROR, OB_INVALID_ARGUMENT, "call select_malloc_sample_info() failed, bad arguments count, should be less than 2."); + lua_pushnil(L); + } else if (OB_FAIL(malloc_sample_map.create(1000, "MallocInfoMap", "MallocInfoMap"))) { + OB_LOG(ERROR, "failed to create hashmap", K(ret)); + } else if (OB_FAIL(ObMemoryDump::get_instance().load_malloc_sample_map(malloc_sample_map))) { + OB_LOG(ERROR, "failed to create memory info map", K(ret)); + } else { + std::vector columns = { + "tenant_id", + "ctx_id", + "mod_name", + "back_trace", + "ctx_name", + "alloc_count", + "alloc_bytes" + }; + LuaVtableGenerator gen(L, columns); + for (auto it = malloc_sample_map.begin(); it != malloc_sample_map.end() && !gen.is_end(); ++it) { + gen.next_row(); + // tenant_id + gen.next_column(it->first.tenant_id_); + // ctx_id + gen.next_column(it->first.ctx_id_); + // mod_name + gen.next_column(it->first.label_); + // back_trace + { + char bt[512]; + parray(bt, sizeof(bt), (int64_t*)*&(it->first.bt_), it->first.bt_size_); + gen.next_column(bt); + } + // ctx_name + gen.next_column(get_global_ctx_info().get_ctx_name(it->first.ctx_id_)); + // alloc_count + gen.next_column(it->second.alloc_count_); + // alloc_bytes + gen.next_column(it->second.alloc_bytes_); + + gen.row_end(); + } + } + return 1; +} + // API end int get_tenant_sysstat(int64_t tenant_id, int64_t statistic, int64_t &value) @@ -1582,40 +2059,15 @@ int summary_each_eio_info(char *buf, int &pos, int buf_len, easy_io_t *eio, cons return ret; } -static ObFIFOAllocator &get_global_allocator() -{ - static ObFIFOAllocator allocator; - if (OB_UNLIKELY(!allocator.is_inited())) { - allocator.init(&LuaAllocator::get_instance(), (1 << 13) - 8, default_memattr, 0, 0, INT64_MAX); - } - return allocator; -} - void *diagnose::alloc(const int size) { - void *ret = nullptr; - if (0 == size) { - // do nothing - } else if (ObLuaHandler::get_instance().memory_usage() + size + 8 < ObLuaHandler::LUA_MEMORY_LIMIT) { - if (OB_NOT_NULL(ret = get_global_allocator().alloc(size + 8))) { - *static_cast(ret) = size; - ret = (char*)ret + 8; - ObLuaHandler::get_instance().memory_update(size + 8); - } else { - OB_LOG_RET(ERROR, OB_ALLOCATE_MEMORY_FAILED, "lua memory alloc failed", K(size), K(get_global_allocator().total())); - } - } else { - OB_LOG_RET(ERROR, OB_ERR_UNEXPECTED, "lua memory usage over limit", K(size)); - } - return ret; + return get_global_allocator().alloc(size); } void diagnose::free(void *ptr) { if (OB_NOT_NULL(ptr)) { - const uint64_t size = *(uint64_t *)((char *)ptr - 8); - ObLuaHandler::get_instance().memory_update(- 8 - size); - get_global_allocator().free((void *)((char *)ptr - 8)); + get_global_allocator().free(ptr); } } @@ -1623,6 +2075,7 @@ void APIRegister::register_api(lua_State* L) { lua_register(L, "usage", usage); lua_register(L, "print_to_client", print_to_client); + lua_register(L, "now", now); lua_register(L, "get_tenant_id_list", get_tenant_id_list); lua_register(L, "get_tenant_mem_limit", get_tenant_mem_limit); lua_register(L, "get_tenant_sysstat_by_id", get_tenant_sysstat_by_id); @@ -1641,6 +2094,13 @@ void APIRegister::register_api(lua_State* L) lua_register(L, "select_tenant_memory_info", select_tenant_memory_info); lua_register(L, "set_log_probe", set_log_probe); lua_register(L, "show_log_probe", show_log_probe); + lua_register(L, "select_mem_leak_checker_info", select_mem_leak_checker_info); + lua_register(L, "select_compaction_diagnose_info", select_compaction_diagnose_info); + lua_register(L, "select_dag_warning_history", select_dag_warning_history); + lua_register(L, "select_server_schema_info", select_server_schema_info); + lua_register(L, "select_schema_slot", select_schema_slot); + lua_register(L, "dump_thread_info", dump_thread_info); + lua_register(L, "select_malloc_sample_info", select_malloc_sample_info); } int APIRegister::flush() diff --git a/src/diagnose/lua/test.lua b/src/diagnose/lua/test.lua index 1afd3833e..b2310fb71 100644 --- a/src/diagnose/lua/test.lua +++ b/src/diagnose/lua/test.lua @@ -1,6 +1,8 @@ tenant_ids = {} print_to_client(usage()) +print_to_client("now:", now()) + tenant_ids = get_tenant_id_list() print_to_client("tenant_cnt:", #tenant_ids) @@ -14,223 +16,325 @@ print_to_client("rpc packet in bytes", get_tenant_sysstat_by_name(1, "rpc packet print_to_client("memory usage", get_tenant_sysstat_by_name(1, "memory usage"), get_tenant_sysstat_by_id(1001, 140003)) +-- to limit 10 rows +-- para["limit"] = {10} + +-- equal to {10} +-- para["limit"] = {0, 10} + +-- using dump mode, recommended +-- para["dump"] = true + para = {} -para["limit"] = {1, 10} +para["limit"] = {} para["dump"] = true - -sessions = select_processlist() -print_to_client("session_cnt:", #sessions) -for i=1,#sessions do - print_to_client(sessions[i]['id'], - sessions[i]['user'], - sessions[i]['tenant'], - sessions[i]['host'], - sessions[i]['db'], - sessions[i]['command'], - sessions[i]['sql_id'], - sessions[i]['time'], - sessions[i]['state'], - sessions[i]['info'], - sessions[i]['sql_port'], - sessions[i]['proxy_sessid'], - sessions[i]['master_sessid'], - sessions[i]['user_client_ip'], - sessions[i]['user_host'], - sessions[i]['trans_id'], - sessions[i]['thread_id'], - sessions[i]['ssl_cipher'], - sessions[i]['trace_id']) -end - -para["select"] = {"id", "tenant", "command"} +para["select"] = { + "id", + "user", + "tenant", + "host", + "db", + "command", + "sql_id", + "time", + "state", + "info", + "sql_port", + "proxy_sessid", + "master_sessid", + "user_client_ip", + "user_host", + "trans_id", + "thread_id", + "ssl_cipher", + "trace_id", + "trans_state", + "total_time", + "retry_cnt", + "retry_info", + "action", + "module", + "client_info" +} +print_to_client("select_processlist") select_processlist(para) -sysstats = select_sysstat() -print_to_client("sysstat_cnt:", #sysstats) -for i=1,10 do - print_to_client(sysstats[i]['tenant_id'], - sysstats[i]['statistic'], - sysstats[i]['value'], - sysstats[i]['value_type'], - sysstats[i]['stat_id'], - sysstats[i]['name'], - sysstats[i]['class'], - sysstats[i]['can_visible']) -end - -para["select"] = {"tenant_id", "statistic", "value"} +para = {} +para["limit"] = {10} +para["dump"] = true +para["select"] = { + "tenant_id", + "statistic", + "value", + "value_type", + "stat_id", + "name", + "class", + "can_visible" +} +print_to_client("select_sysstat") select_sysstat(para) -memory_info = select_memory_info() -print_to_client("memory_info_cnt", #memory_info) -for i=1,10 do - print_to_client(memory_info[i]['tenant_id'], - memory_info[i]['ctx_id'], - memory_info[i]['ctx_name'], - memory_info[i]['label'], - memory_info[i]['hold'], - memory_info[i]['used'], - memory_info[i]['count']) -end - +para = {} +para["limit"] = {10} +para["dump"] = true para["select"] = {"tenant_id", "ctx_name", "label", "hold"} +print_to_client("select_memory_info") select_memory_info(para) -tenant_ctx_memory_info = select_tenant_ctx_memory_info() -print_to_client("tenant_ctx_memory_info_cnt", #tenant_ctx_memory_info) -for i=1,10 do - print_to_client(tenant_ctx_memory_info[i]['tenant_id'], - tenant_ctx_memory_info[i]['ctx_id'], - tenant_ctx_memory_info[i]['ctx_name'], - tenant_ctx_memory_info[i]['hold'], - tenant_ctx_memory_info[i]['used']) -end - -para["select"] = {"tenant_id", "ctx_id", "ctx_name", "hold"} +para = {} +para["limit"] = {10} +para["dump"] = true +para["select"] = { + "tenant_id", + "ctx_id", + "ctx_name", + "hold", + "used", + "limit" +} +print_to_client("select_tenant_ctx_memory_info") select_tenant_ctx_memory_info(para) -trans_stat = select_trans_stat() -print_to_client("trans_stat_cnt", #trans_stat) -for i=1,#trans_stat do - print_to_client(trans_stat[i]['tenant_id'], - trans_stat[i]['trans_type'], - trans_stat[i]['trans_id'], - trans_stat[i]['session_id'], - trans_stat[i]['scheduler_addr'], - trans_stat[i]['is_decided'], - trans_stat[i]['ls_id'], - trans_stat[i]['participants'], - trans_stat[i]['trans_consistency'], - trans_stat[i]['ctx_create_time'], - trans_stat[i]['expired_time'], - trans_stat[i]['refer_cnt'], - trans_stat[i]['sql_no'], - trans_stat[i]['state'], - trans_stat[i]['part_trans_action'], - trans_stat[i]['lock_for_read_retry_count'], - trans_stat[i]['trans_ctx_addr'], - trans_stat[i]['trans_ctx_id'], - trans_stat[i]['pending_log_size'], - trans_stat[i]['flushed_log_size'], - trans_stat[i]['role'], - trans_stat[i]['is_exiting'], - trans_stat[i]['coord'], - trans_stat[i]['last_request_time'], - trans_stat[i]['gtrid'], - trans_stat[i]['bqual'], - trans_stat[i]['format_id']) -end - -para["select"] = {"tenant_id", "trans_id", "session_id"} +para = {} +para["limit"] = {10} +para["dump"] = true +para["select"] = { + "tenant_id", + "tx_type", + "tx_id", + "session_id", + "scheduler_addr", + "is_decided", + "ls_id", + "participants", + "tx_ctx_create_time", + "expired_time", + "ref_cnt", + "last_op_sn", + "pending_write", + "state", + "part_tx_action", + "tx_ctx_addr", + "mem_ctx_id", + "pending_log_size", + "flushed_log_size", + "role_state", + "is_exiting", + "coord", + "last_request_ts", + "gtrid", + "bqual", + "format_id" +} +print_to_client("select_trans_stat") select_trans_stat(para) --- tenant_disk_stat = select_tenant_disk_stat() --- print_to_client("tenant_disk_stat_cnt", #tenant_disk_stat) --- for i=1,#tenant_disk_stat do --- print_to_client(tenant_disk_stat[i]['tenant_id'], --- tenant_disk_stat[i]['zone'], --- tenant_disk_stat[i]['block_type'], --- tenant_disk_stat[i]['block_size']) --- end --- --- para["limit"] = {5} --- para["select"] = None --- select_tenant_disk_stat(para) - -sql_workarea_active = select_sql_workarea_active() -print_to_client("sql_workarea_active_cnt", #sql_workarea_active) -for i=1,#sql_workarea_active do - print_to_client(sql_workarea_active[i]['plan_id'], - sql_workarea_active[i]['sql_id'], - sql_workarea_active[i]['sql_exec_id'], - sql_workarea_active[i]['operation_type'], - sql_workarea_active[i]['operation_id'], - sql_workarea_active[i]['sid'], - sql_workarea_active[i]['active_time'], - sql_workarea_active[i]['work_area_size'], - sql_workarea_active[i]['expect_size'], - sql_workarea_active[i]['actual_mem_used'], - sql_workarea_active[i]['max_mem_used'], - sql_workarea_active[i]['number_passes'], - sql_workarea_active[i]['tempseg_size'], - sql_workarea_active[i]['tenant_id'], - sql_workarea_active[i]['policy']) -end - -para["select"] = {"plan_id", "sql_id"} +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "plan_id", + "sql_id", + "sql_exec_id", + "operation_type", + "operation_id", + "sid", + "active_time", + "work_area_size", + "expect_size", + "actual_mem_used", + "max_mem_used", + "number_passes", + "tempseg_size", + "tenant_id", + "policy" +} +print_to_client("select_sql_workarea_active") select_sql_workarea_active(para) -sys_task_status = select_sys_task_status() -print_to_client("sys_task_status_cnt", #sys_task_status) -for i=1,#sys_task_status do - print_to_client(sys_task_status[i]['start_time'], - sys_task_status[i]['task_type'], - sys_task_status[i]['task_id'], - sys_task_status[i]['tenant_id'], - sys_task_status[i]['comment'], - sys_task_status[i]['is_cancel']) -end - -para["select"] = {"start_time", "tenant_id"} +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "start_time", + "task_type", + "task_id", + "tenant_id", + "comment", + "is_cancel" +} +print_to_client("select_sys_task_status") select_sys_task_status(para) -dump_tenant_info = select_dump_tenant_info() -print_to_client("dump_tenant_info_cnt", #dump_tenant_info) -for i=1,#dump_tenant_info do - print_to_client(dump_tenant_info[i]['tenant_id'], - dump_tenant_info[i]['compat_mode'], - dump_tenant_info[i]['unit_min_cpu'], - dump_tenant_info[i]['unit_max_cpu'], - dump_tenant_info[i]['slice'], - dump_tenant_info[i]['remain_slice'], - dump_tenant_info[i]['token_cnt'], - dump_tenant_info[i]['ass_token_cnt'], - dump_tenant_info[i]['lq_tokens'], - dump_tenant_info[i]['used_lq_tokens'], - dump_tenant_info[i]['stopped'], - dump_tenant_info[i]['idle_us'], - dump_tenant_info[i]['recv_hp_rpc_cnt'], - dump_tenant_info[i]['recv_np_rpc_cnt'], - dump_tenant_info[i]['recv_lp_rpc_cnt'], - dump_tenant_info[i]['recv_mysql_cnt'], - dump_tenant_info[i]['recv_task_cnt'], - dump_tenant_info[i]['recv_large_req_cnt'], - dump_tenant_info[i]['recv_large_queries'], - dump_tenant_info[i]['actives'], - dump_tenant_info[i]['workers'], - dump_tenant_info[i]['lq_warting_workers'], - dump_tenant_info[i]['req_queue_total_size'], - dump_tenant_info[i]['queue_0'], - dump_tenant_info[i]['queue_1'], - dump_tenant_info[i]['queue_2'], - dump_tenant_info[i]['queue_3'], - dump_tenant_info[i]['queue_4'], - dump_tenant_info[i]['queue_5'], - dump_tenant_info[i]['large_queued']) -end - -para["select"] = {"tenant_id", "unit_min_cpu", "unit_max_cpu"} +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "tenant_id", + "compat_mode", + "unit_min_cpu", + "unit_max_cpu", + "slice", + "remain_slice", + "token_cnt", + "ass_token_cnt", + "lq_tokens", + "used_lq_tokens", + "stopped", + "idle_us", + "recv_hp_rpc_cnt", + "recv_np_rpc_cnt", + "recv_lp_rpc_cnt", + "recv_mysql_cnt", + "recv_task_cnt", + "recv_large_req_cnt", + "recv_large_queries", + "actives", + "workers", + "lq_warting_workers", + "req_queue_total_size", + "queue_0", + "queue_1", + "queue_2", + "queue_3", + "queue_4", + "queue_5", + "large_queued" +} +print_to_client("select_dump_tenant_info") select_dump_tenant_info(para) -disk_stat = select_disk_stat() -print_to_client("disk_stat_cnt", #disk_stat) -for i=1,#disk_stat do - print_to_client(disk_stat[i]['total_size'], - disk_stat[i]['used_size'], - disk_stat[i]['free_size'], - disk_stat[i]['is_disk_valid']) -end - -para["select"] = {"total_size", "used_size"} +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "total_size", + "used_size", + "free_size", + "is_disk_valid", + "disk_error_begin_ts" +} +print_to_client("select_disk_stat") select_disk_stat(para) -tenant_memory_info = select_tenant_memory_info() -print_to_client("tenant_memory_info_cnt", #tenant_memory_info) -for i=1,#tenant_memory_info do - print_to_client(tenant_memory_info[i]['tenant_id'], - tenant_memory_info[i]['hold'], - tenant_memory_info[i]['limit']) -end - -para["select"] = {"tenant_id", "hold"} +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "tenant_id", + "hold", + "limit" +} +print_to_client("select_tenant_memory_info") select_tenant_memory_info(para) + +print_to_client("show_log_probe") +print_to_client(show_log_probe()) + +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "mod_name", + "mod_type", + "alloc_count", + "alloc_size", + "back_trace" +} +print_to_client("select_mem_leak_checker_info") +select_mem_leak_checker_info(para) + +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "tenant_id", + "merge_type", + "ls_id", + "tablet_id", + "status", + "create_time", + "diagnose_info" +} +print_to_client("select_compaction_diagnose_info") +select_compaction_diagnose_info(para) + +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "tenant_id", + "task_id", + "module", + "type", + "ret", + "status", + "gmt_create", + "gmt_modified", + "retry_cnt", + "warning_info" +} +print_to_client("select_dag_warning_history") +select_dag_warning_history(para) + +para = {} +para["limit"] = {} +para["dump"] = true +para["select"] = { + "tenant_id", + "refreshed_schema_version", + "received_schema_version", + "schema_count", + "schema_size", + "min_sstable_schema_version" +} +print_to_client("select_server_schema_info") +select_server_schema_info(para) + +para = {} +para["limit"] = {10} +para["dump"] = true +para["select"] = { + "tenant_id", + "slot_id", + "schema_version", + "schema_count", + "total_ref_cnt", + "ref_info" +} +print_to_client("select_schema_slot") +select_schema_slot(para) + +para = {} +para["limit"] = {10} +para["dump"] = true +para["select"] = { + "tname", + "tid", + "thread_base", + "loop_ts", + "lock_addr", + "lock_val", + "wait_addr", + "wait_val", + "is_blocking", + "has_req" +} +print_to_client("dump_thread_info") +dump_thread_info(para) + +para = {} +para["limit"] = {0, 3} +para["dump"] = true +para["select"] = { + "tenant_id", + "ctx_id", + "mod_name", + "back_trace", + "ctx_name", + "alloc_count", + "alloc_bytes" +} +print_to_client("select_malloc_sample_info") +select_malloc_sample_info(para) \ No newline at end of file diff --git a/src/logservice/cdcservice/ob_cdc_service.cpp b/src/logservice/cdcservice/ob_cdc_service.cpp index c1f837a02..cfe96ca91 100644 --- a/src/logservice/cdcservice/ob_cdc_service.cpp +++ b/src/logservice/cdcservice/ob_cdc_service.cpp @@ -103,6 +103,7 @@ void ObCdcService::run1() while(! is_stoped()) { // archive is always off for sys tenant, no need to query archive dest int64_t current_ts = ObTimeUtility::current_time(); + IGNORE_RETURN lib::Thread::update_loop_ts(current_ts); if (OB_SYS_TENANT_ID != tenant_id) { if (current_ts - last_query_ts >= QUERY_INTERVAL) { // the change of archive dest info is not supported diff --git a/src/logservice/libobcdc/src/ob_concurrent_seq_queue.cpp b/src/logservice/libobcdc/src/ob_concurrent_seq_queue.cpp index 164d32dd0..24fc1ddaa 100644 --- a/src/logservice/libobcdc/src/ob_concurrent_seq_queue.cpp +++ b/src/logservice/libobcdc/src/ob_concurrent_seq_queue.cpp @@ -32,10 +32,10 @@ static struct timespec make_timespec(int64_t us) ts.tv_nsec = 1000 * (us % 1000000); return ts; } -#define futex(...) syscall(SYS_futex,__VA_ARGS__) + inline int futex_wake(volatile int *p, int val) { - return static_cast(futex((int *)p, FUTEX_WAKE_PRIVATE, val, NULL, NULL, 0)); + return static_cast(futex((uint *)p, FUTEX_WAKE_PRIVATE, val, NULL)); } // 0: Woken up by FUTEX_WAKE // ETIMEDOUT: Timeout diff --git a/src/observer/CMakeLists.txt b/src/observer/CMakeLists.txt index 0ce71f0a8..fb69293e4 100644 --- a/src/observer/CMakeLists.txt +++ b/src/observer/CMakeLists.txt @@ -110,9 +110,9 @@ ob_set_subtarget(ob_server omt omt/ob_tenant_timezone.cpp omt/ob_tenant_timezone_mgr.cpp omt/ob_th_worker.cpp - omt/ob_worker_pool.cpp omt/ob_worker_processor.cpp omt/ob_multi_tenant_operator.cpp + omt/ob_tenant_hook.cpp omt/ob_tenant_srs_mgr.cpp omt/ob_tenant_srs.cpp ) @@ -230,6 +230,7 @@ ob_set_subtarget(ob_server virtual_table virtual_table/ob_all_virtual_transaction_checkpoint.cpp virtual_table/ob_all_virtual_checkpoint.cpp virtual_table/ob_all_virtual_macro_block_marker_status.cpp + virtual_table/ob_all_virtual_malloc_sample_info.cpp virtual_table/ob_all_virtual_memory_context_stat.cpp virtual_table/ob_all_virtual_memory_info.cpp virtual_table/ob_all_virtual_memstore_info.cpp diff --git a/src/observer/layer_perf/ob_layer_perf.cpp b/src/observer/layer_perf/ob_layer_perf.cpp index 976048eb3..5950e0c99 100644 --- a/src/observer/layer_perf/ob_layer_perf.cpp +++ b/src/observer/layer_perf/ob_layer_perf.cpp @@ -129,13 +129,13 @@ int ObLayerPerf::do_clog_layer_perf() char *buf = (char*)"clog layer perf test"; PerfLogCb *cb = nullptr; palf::LSN lsn; - int64_t ts_ns; + share::SCN zero, ts_ns; LOG_INFO("perf layer append", KP(r_), KP(buf)); if (nullptr == (cb = static_cast(ob_malloc(sizeof(PerfLogCb))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allo mem", K(ret)); } else if (FALSE_IT(new (cb) PerfLogCb(r_))) { - } else if (OB_FAIL(ls->get_log_handler()->append(buf, strlen(buf), 0, true, cb, lsn, ts_ns))) { + } else if (OB_FAIL(ls->get_log_handler()->append(buf, strlen(buf), zero, true, cb, lsn, ts_ns))) { LOG_ERROR("append fail", K(ret)); } } diff --git a/src/observer/ob_server.cpp b/src/observer/ob_server.cpp index df63f2682..11429b832 100644 --- a/src/observer/ob_server.cpp +++ b/src/observer/ob_server.cpp @@ -1550,7 +1550,6 @@ int ObServer::init_config() } } } - get_unis_global_compat_version() = GET_MIN_CLUSTER_VERSION(); lib::g_runtime_enabled = true; return ret; diff --git a/src/observer/ob_server_reload_config.cpp b/src/observer/ob_server_reload_config.cpp index 667b51e2a..b01faa2fc 100644 --- a/src/observer/ob_server_reload_config.cpp +++ b/src/observer/ob_server_reload_config.cpp @@ -15,6 +15,7 @@ #include "ob_server_reload_config.h" #include "lib/alloc/alloc_func.h" #include "lib/alloc/ob_malloc_allocator.h" +#include "lib/alloc/ob_malloc_sample_struct.h" #include "lib/allocator/ob_tc_malloc.h" #include "lib/allocator/ob_mem_leak_checker.h" #include "share/scheduler/ob_dag_scheduler.h" @@ -150,7 +151,10 @@ int ObServerReloadConfig::operator()() #ifdef OB_USE_ASAN __MemoryContext__::set_enable_asan_allocator(GCONF.enable_asan_for_memory_context); #endif - +#if defined(__x86_64__) + ObMallocSampleLimiter::set_interval(GCONF._max_malloc_sample_interval, + GCONF._min_malloc_sample_interval); +#endif ObIOConfig io_config; int64_t cpu_cnt = GCONF.cpu_count; if (cpu_cnt <= 0) { @@ -261,7 +265,6 @@ int ObServerReloadConfig::operator()() share::ObTaskController::get().set_diag_per_error_limit( GCONF.diag_syslog_per_error_limit.get_value()); - get_unis_global_compat_version() = GET_MIN_CLUSTER_VERSION(); lib::g_runtime_enabled = true; common::ObKVGlobalCache::get_instance().reload_wash_interval(); diff --git a/src/observer/ob_srv_deliver.cpp b/src/observer/ob_srv_deliver.cpp index d8577f0ba..42fe2d14e 100644 --- a/src/observer/ob_srv_deliver.cpp +++ b/src/observer/ob_srv_deliver.cpp @@ -18,9 +18,11 @@ #include "util/easy_inet.h" #include "easy_define.h" #include "lib/stat/ob_session_stat.h" -#include "rpc/ob_request.h" #include "rpc/obrpc/ob_rpc_packet.h" +#include "rpc/obrpc/ob_rpc_session_handler.h" #include "rpc/obmysql/ob_mysql_packet.h" +#include "rpc/obmysql/packet/ompk_handshake_response.h" +#include "rpc/obmysql/ob_sql_nio_server.h" #include "rpc/frame/ob_net_easy.h" #include "share/ob_thread_mgr.h" #include "observer/ob_rpc_processor_simple.h" @@ -38,6 +40,115 @@ using namespace oceanbase::observer; using namespace oceanbase::omt; using namespace oceanbase::memtable; +namespace oceanbase +{ +int extract_tenant_id(ObRequest &req, uint64_t &tenant_id) +{ + int ret = OB_SUCCESS; + tenant_id = OB_INVALID_ID; + obmysql::OMPKHandshakeResponse hsr = + reinterpret_cast( + req.get_packet()); + if (OB_FAIL(hsr.decode())) { + LOG_WARN("decode hsr fail", K(ret)); + } else { + // resolve tenantname + ObString in = hsr.get_username(); + const char *user_pos = in.ptr(); + const char *at_pos = + in.find('@'); // use @ as seperator, e.g. xiaochu@tenant + const char *tenant_pos = at_pos + 1; + ObString tenant_name = ObString::make_empty_string(); + // sanity check + if (NULL == at_pos) { + tenant_id = OB_SYS_TENANT_ID; // default to sys tenant + LOG_INFO("tenantname", K(tenant_name)); + } else { + // Accept empty username. Empty username is one of normal + // usernames that we can create user with empty name. + + /* get tenant_name */ + if (at_pos - user_pos < 0) { + ret = OB_ERR_USER_EMPTY; + LOG_WARN("Must Provide user name to login", K(ret)); + } else { + int64_t tenant_len = in.length() - (tenant_pos - user_pos); + if (tenant_len > OB_MAX_TENANT_NAME_LENGTH || tenant_len <= 0) { + ret = OB_ERR_INVALID_TENANT_NAME; + LOG_WARN("Violate with tenant length limit", "max", + OB_MAX_TENANT_NAME_LENGTH, "actual", tenant_len, K(ret)); + } + // extract + if (OB_SUCC(ret)) { + ObString tenantname(in.length() - (tenant_pos - user_pos), + tenant_pos); + tenant_name = tenantname; + LOG_DEBUG("get tenantname", K(tenant_name)); + + /* get tenant_id */ + // OB_ASSERT(gctx_.schema_service_); + if (OB_ISNULL(GCTX.schema_service_)) { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("invalid schema service", K(ret), + K(GCTX.schema_service_)); + } else { + share::schema::ObSchemaGetterGuard guard; + if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard( + OB_SYS_TENANT_ID, guard))) { + LOG_WARN("get_schema_guard failed", K(ret)); + } else if (OB_FAIL(guard.get_tenant_id(tenant_name, tenant_id))) { + LOG_WARN("get_tenant_id failed", K(ret), K(tenant_name)); + } + } + } + } + } + } + return ret; +} + +int dispatch_req(ObRequest& req) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = OB_INVALID_ID; + if (OB_FAIL(extract_tenant_id(req, tenant_id))) { + LOG_WARN("extract tenant_id fail", K(ret), K(tenant_id), K(req)); + // handle all error by OB_TENANT_NOT_IN_SERVER + ret = OB_TENANT_NOT_IN_SERVER; + } else if (is_meta_tenant(tenant_id)) { + // cannot login meta tenant + ret = OB_TENANT_NOT_IN_SERVER; + LOG_WARN("cannot login meta tenant", K(ret), K(tenant_id)); + } else if (is_sys_tenant(tenant_id) || is_user_tenant(tenant_id)) { + MTL_SWITCH(tenant_id) { + QueueThread *mysql_queue = MTL(QueueThread *); + if (!mysql_queue->queue_.push(&req, + 10000)) { // MAX_QUEUE_LEN = 10000; + ret = OB_QUEUE_OVERFLOW; + EVENT_INC(MYSQL_DELIVER_FAIL); + LOG_ERROR("deliver request fail", K(ret), K(tenant_id), K(req)); + } + // print queue length per 10s + if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) { + LOG_INFO("mysql login queue", K(tenant_id), + K(mysql_queue->queue_.size())); + } + + // if (0 != MTL(obmysql::ObSqlNioServer *) + // ->get_nio() + // ->regist_sess(req.get_server_handle_context())) { + // ret = OB_ERR_UNEXPECTED; + // LOG_ERROR("regist sess for tenant fail", K(ret), K(tenant_id), K(req)); + // } + } else { + LOG_WARN("cannot switch to tenant", K(ret), K(tenant_id)); + } + } + return ret; +} + +} // namespace oceanbase + int64_t get_easy_per_src_memory_limit() { return GCONF.__easy_memory_limit; @@ -48,7 +159,8 @@ int check_easy_memory_limit(ObRequest &req) int ret = OB_SUCCESS; easy_mod_stat_t *stat = NULL; - if (req.get_nio_protocol() == ObRequest::TRANSPORT_PROTO_RDMA) { + if (req.get_nio_protocol() == ObRequest::TRANSPORT_PROTO_POC + || req.get_nio_protocol() == ObRequest::TRANSPORT_PROTO_RDMA) { // Todo: return ret; } @@ -99,7 +211,7 @@ int ObSrvDeliver::get_mysql_login_thread_count_to_set(int cfg_cnt) int ObSrvDeliver::set_mysql_login_thread_count(int cnt) { int ret = OB_SUCCESS; - if (OB_FAIL(TG_SET_THREAD_CNT(lib::TGDefIDs::MysqlQueueTh, cnt))) { + if (OB_FAIL(mysql_queue_->set_thread_count(cnt))) { SERVER_LOG(WARN, "set thread count for mysql login failed", K(ret)); } else { LOG_INFO("set mysql login thread count success", K(cnt)); @@ -159,21 +271,21 @@ void ObSrvDeliver::stop() stop_ = true; if (NULL != mysql_queue_) { // stop sql service first - TG_STOP(lib::TGDefIDs::MysqlQueueTh); - TG_WAIT(lib::TGDefIDs::MysqlQueueTh); + mysql_queue_->stop(); + mysql_queue_->wait(); } if (NULL != diagnose_queue_) { // stop sql service first - TG_STOP(lib::TGDefIDs::DiagnoseQueueTh); - TG_WAIT(lib::TGDefIDs::DiagnoseQueueTh); + diagnose_queue_->stop(); + diagnose_queue_->wait(); } if (NULL != lease_queue_) { - TG_STOP(lib::TGDefIDs::LeaseQueueTh); - TG_WAIT(lib::TGDefIDs::LeaseQueueTh); + lease_queue_->stop(); + lease_queue_->wait(); } if (NULL != ddl_queue_) { - TG_STOP(lib::TGDefIDs::DDLQueueTh); - TG_WAIT(lib::TGDefIDs::DDLQueueTh); + ddl_queue_->stop(); + ddl_queue_->wait(); } if (NULL != ddl_parallel_queue_) { TG_STOP(lib::TGDefIDs::DDLPQueueTh); @@ -191,6 +303,7 @@ int ObSrvDeliver::create_queue_thread(int tg_id, const char *thread_name, QueueT qthread->queue_.set_qhandler(&qhandler_); } if (OB_SUCC(ret) && OB_NOT_NULL(qthread)) { + qthread->tg_id_ = tg_id; ret = TG_SET_RUNNABLE_AND_START(tg_id, qthread->thread_); } return ret; @@ -226,6 +339,7 @@ int ObSrvDeliver::deliver_rpc_request(ObRequest &req) const int64_t now = ObTimeUtility::current_time(); const bool need_update_stat = !req.is_retry_on_lock(); + const bool is_stream = pkt.is_stream(); ObTenantStatEstGuard guard(pkt.get_tenant_id()); if (need_update_stat) { @@ -251,7 +365,7 @@ int ObSrvDeliver::deliver_rpc_request(ObRequest &req) if (!OB_SUCC(ret)) { } else if (!is_high_prio_rpc_req(req) && OB_FAIL(check_easy_memory_limit(req))) { - } else if (pkt.is_stream()) { + } else if (is_stream) { if (!session_handler_.wakeup_next_thread(req)) { ret = OB_SESSION_NOT_FOUND; LOG_WARN("receive stream rpc packet but session not found", @@ -300,7 +414,7 @@ int ObSrvDeliver::deliver_rpc_request(ObRequest &req) LOG_WARN("tenant receive request fail", K(*tenant), K(req)); } } - } else if (!pkt.is_stream()) { + } else if (!is_stream) { LOG_WARN("not stream packet, should not reach here."); ret = OB_ERR_UNEXPECTED; } @@ -312,12 +426,11 @@ int ObSrvDeliver::deliver_rpc_request(ObRequest &req) } if (!OB_SUCC(ret)) { - on_translate_fail(&req, ret); - EVENT_INC(RPC_DELIVER_FAIL); if (REACH_TIME_INTERVAL(5 * 1000 * 1000)) { SERVER_LOG(WARN, "can't deliver request", K(req), K(ret)); } + on_translate_fail(&req, ret); } return ret; @@ -386,14 +499,24 @@ int ObSrvDeliver::deliver_mysql_request(ObRequest &req) LOG_ERROR("deliver request fail", K(req)); } } else if (OB_NOT_NULL(mysql_queue_)) { - if (!mysql_queue_->queue_.push(&req, MAX_QUEUE_LEN)) { - ret = OB_QUEUE_OVERFLOW; - EVENT_INC(MYSQL_DELIVER_FAIL); - LOG_ERROR("deliver request fail", K(req)); - } - // print queue length per 10s - if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) { - LOG_INFO("mysql login queue", K(mysql_queue_->queue_.size())); + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread && + OB_SUCC(dispatch_req(req))) { + // do nothing + } else { + if (OB_TENANT_NOT_IN_SERVER == ret) { + LOG_WARN("cannot dispatch success", K(ret), K(req)); + // set OB_SUCCESS to go normal procedure + ret = OB_SUCCESS; + } + if (!mysql_queue_->queue_.push(&req, MAX_QUEUE_LEN)) { + ret = OB_QUEUE_OVERFLOW; + EVENT_INC(MYSQL_DELIVER_FAIL); + LOG_ERROR("deliver request fail", K(req)); + } + // print queue length per 10s + if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) { + LOG_INFO("mysql login queue", K(mysql_queue_->queue_.size())); + } } } } else { @@ -444,7 +567,7 @@ int ObSrvDeliver::deliver(rpc::ObRequest &req) if (ObRequest::OB_RPC == req.get_type()) { if (OB_FAIL(deliver_rpc_request(req))) { if (REACH_TIME_INTERVAL(5 * 1000 * 1000)) { - LOG_WARN("deliver rpc request fail", K(req), K(ret)); + LOG_WARN("deliver rpc request fail", KP(&req), K(ret)); } } //LOG_INFO("yzfdebug deliver rpc", K(ret), "pkt", req.get_packet()); diff --git a/src/observer/ob_srv_deliver.h b/src/observer/ob_srv_deliver.h index 287e3b19e..3731d4d72 100644 --- a/src/observer/ob_srv_deliver.h +++ b/src/observer/ob_srv_deliver.h @@ -17,6 +17,7 @@ #include "lib/thread/thread_mgr_interface.h" #include "rpc/frame/ob_req_deliver.h" #include "share/ob_thread_pool.h" +#include "share/resource_manager/ob_cgroup_ctrl.h" #include "observer/ob_server_struct.h" namespace oceanbase @@ -41,28 +42,55 @@ using obrpc::ObRpcSessionHandler; class QueueThread { public: - QueueThread(const char *thread_name=nullptr) - : thread_(queue_, thread_name) - {} + QueueThread(const char *thread_name = nullptr, + uint64_t tenant_id = common::OB_INVALID_ID) + : thread_(queue_, thread_name, tenant_id), tg_id_(0), + tenant_id_(tenant_id), n_thread_(0) {} + + ~QueueThread() { destroy(); } public: + int set_thread_count(int thread_cnt) { + int ret = OB_SUCCESS; + if (thread_cnt != n_thread_) { + ret = TG_SET_THREAD_CNT(tg_id_, thread_cnt); + n_thread_ = thread_cnt; + } + return ret; + } + void stop() { TG_STOP(tg_id_); } + void wait() { TG_WAIT(tg_id_); } + void destroy() { TG_DESTROY(tg_id_); } class Thread : public lib::TGRunnable { public: - Thread(ObReqQueue &queue, const char *thread_name) - : queue_(queue), thread_name_(thread_name) - {} + Thread(ObReqQueue &queue, const char *thread_name, const uint64_t tenant_id) + : queue_(queue), thread_name_(thread_name), tenant_id_(tenant_id) {} void run1() { if (thread_name_ != nullptr) { lib::set_thread_name(thread_name_, get_thread_idx()); } + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread && + tenant_id_ != common::OB_INVALID_ID && nullptr != GCTX.cgroup_ctrl_ && + OB_LIKELY(GCTX.cgroup_ctrl_->is_valid())) { + GCTX.cgroup_ctrl_->add_thread_to_cgroup( + static_cast(syscall(__NR_gettid)), tenant_id_, + share::OBCG_MYSQL_LOGIN); + } queue_.loop(); } + private: ObReqQueue &queue_; const char *thread_name_; + const uint64_t tenant_id_; } thread_; ObReqQueue queue_; + int tg_id_; + +private: + uint64_t tenant_id_; + int n_thread_; }; class ObSrvDeliver diff --git a/src/observer/ob_srv_network_frame.cpp b/src/observer/ob_srv_network_frame.cpp index bf30cb4f2..4bbe29b32 100644 --- a/src/observer/ob_srv_network_frame.cpp +++ b/src/observer/ob_srv_network_frame.cpp @@ -15,6 +15,8 @@ #include "observer/ob_srv_network_frame.h" #include "rpc/obmysql/ob_sql_nio_server.h" #include "observer/mysql/obsm_conn_callback.h" +#include "rpc/obrpc/ob_poc_rpc_server.h" +#include "src/share/rc/ob_tenant_base.h" #include "share/config/ob_server_config.h" #include "share/ob_rpc_share.h" @@ -160,7 +162,12 @@ int ObSrvNetworkFrame::init() } else if (hp_io_cnt > 0 && OB_FAIL(net_.high_prio_rpc_net_register(rpc_handler_, high_prio_rpc_transport_))) { LOG_ERROR("high prio rpc net register fail", K(ret)); } - else { + else { + if (OB_FAIL(obrpc::global_poc_server.start(rpc_port, io_cnt, &deliver_))) { + LOG_ERROR("poc rpc server start fail", K(ret)); + } else { + LOG_INFO("poc rpc server start successfully"); + } share::set_obrpc_transport(rpc_transport_); batch_rpc_transport_->set_bucket_count(opts.batch_rpc_io_cnt_); LOG_INFO("init rpc network frame successfully", @@ -182,16 +189,23 @@ int ObSrvNetworkFrame::start() int ret = net_.start(); if (OB_SUCC(ret)) { if (enable_new_sql_nio()) { - obmysql::global_sql_nio_server = OB_NEW(obmysql::ObSqlNioServer, "SqlNio", obmysql::global_sm_conn_callback, mysql_handler_); + obmysql::global_sql_nio_server = + OB_NEW(obmysql::ObSqlNioServer, "SqlNio", + obmysql::global_sm_conn_callback, mysql_handler_); if (NULL == obmysql::global_sql_nio_server) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("allocate memory for global_sql_nio_server failed", K(ret)); } else { - int net_thread_count = atoi(getenv("sql_nio_thread_count")?:"0")?: (int)(GCONF.net_thread_count); - if (0 == net_thread_count) { - net_thread_count = get_default_net_thread_count(); + int sql_net_thread_count = (int)GCONF.sql_net_thread_count; + if (sql_net_thread_count == 0) { + if (GCONF.net_thread_count == 0) { + sql_net_thread_count = get_default_net_thread_count(); + } else { + sql_net_thread_count = GCONF.net_thread_count; + } } - if(OB_FAIL(obmysql::global_sql_nio_server->start(GCONF.mysql_port, &deliver_, net_thread_count))) { + if (OB_FAIL(obmysql::global_sql_nio_server->start( + GCONF.mysql_port, &deliver_, sql_net_thread_count))) { LOG_ERROR("sql nio server start failed", K(ret)); } } @@ -229,6 +243,8 @@ int ObSrvNetworkFrame::reload_config() LOG_WARN("Failed to set easy keepalive."); } else if (OB_FAIL(net_.update_rpc_tcp_keepalive_params(user_timeout))) { LOG_WARN("Failed to set rpc tcp keepalive parameters."); + } else if (OB_FAIL(obrpc::global_poc_server.update_tcp_keepalive_params(user_timeout))) { + LOG_WARN("Failed to set pkt-nio rpc tcp keepalive parameters."); } else if (OB_FAIL(net_.update_sql_tcp_keepalive_params(user_timeout, enable_tcp_keepalive, tcp_keepidle, tcp_keepintvl, tcp_keepcnt))) { diff --git a/src/observer/ob_srv_network_frame.h b/src/observer/ob_srv_network_frame.h index ae1ba8705..192092d7c 100644 --- a/src/observer/ob_srv_network_frame.h +++ b/src/observer/ob_srv_network_frame.h @@ -57,6 +57,7 @@ public: int reload_ssl_config(); static int extract_expired_time(const char *const cert_file, int64_t &expired_time); static uint64_t get_ssl_file_hash(const char *intl_file[3], const char *sm_file[5], bool &file_exist); + ObSMHandler &get_mysql_handler() { return mysql_handler_; } ObSrvDeliver& get_deliver() { return deliver_; } int get_proxy(obrpc::ObRpcProxy &proxy); rpc::frame::ObReqTransport *get_req_transport(); @@ -65,6 +66,9 @@ public: inline rpc::frame::ObReqTranslator &get_xlator(); rpc::frame::ObNetEasy *get_net_easy(); void set_ratelimit_enable(int ratelimit_enabled); + int reload_sql_thread_config(); + int reload_tenant_sql_thread_config(const uint64_t tenant_id); + int reload_mysql_login_thread_config() { int cnt = deliver_.get_mysql_login_thread_count_to_set(static_cast(GCONF.sql_login_thread_count)); return deliver_.set_mysql_login_thread_count(cnt); @@ -100,6 +104,25 @@ ObSrvNetworkFrame::get_xlator() { return xlator_; } +static int get_default_net_thread_count() +{ + int cnt = 1; + int cpu_num = static_cast(get_cpu_num()); + + if (cpu_num <= 4) { + cnt = 2; + } else if (cpu_num <= 8) { + cnt = 3; + } else if (cpu_num <= 16) { + cnt = 5; + } else if (cpu_num <= 32) { + cnt = 7; + } else { + cnt = max(8, static_cast(get_cpu_num()) / 6); + } + return cnt; +} + } // end of namespace observer } // end of namespace oceanbase diff --git a/src/observer/ob_tenant_duty_task.cpp b/src/observer/ob_tenant_duty_task.cpp index fdb678943..4b41717f6 100644 --- a/src/observer/ob_tenant_duty_task.cpp +++ b/src/observer/ob_tenant_duty_task.cpp @@ -74,6 +74,10 @@ void ObTenantDutyTask::update_all_tenants() LOG_WARN("update tenant ctx throttle fail", K(ret)); ret = OB_SUCCESS; } + if (OB_FAIL(update_tenant_rpc_percentage(ids[i]))) { + LOG_WARN("update tenant rpc percentage fail", K(ret)); + ret = OB_SUCCESS; + } } } } @@ -241,6 +245,24 @@ int ObTenantDutyTask::update_tenant_wa_percentage(uint64_t tenant_id) return ret; } +int ObTenantDutyTask::update_tenant_rpc_percentage(uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id)); + if (!tenant_config.is_valid()) { + // do nothing + } else { + int64_t rpc_pct_lmt = tenant_config->tenant_rpc_memory_limit_percentage; + if (0 == rpc_pct_lmt) { + rpc_pct_lmt = 100; + } + if (OB_FAIL(set_rpc_limit(tenant_id, rpc_pct_lmt))) { + LOG_WARN("failed to set tenant rpc ctx limit", K(ret), K(tenant_id), K(rpc_pct_lmt)); + } + } + return ret; +} + int ObTenantDutyTask::read_obj( uint64_t tenant_id, ObSysVarClassType sys_var, common::ObObj &obj) { diff --git a/src/observer/ob_tenant_duty_task.h b/src/observer/ob_tenant_duty_task.h index 881cfe297..41e5ad745 100644 --- a/src/observer/ob_tenant_duty_task.h +++ b/src/observer/ob_tenant_duty_task.h @@ -51,6 +51,7 @@ private: int update_tenant_ctx_memory_throttle(uint64_t tenant_id); // Read tenant work area memory settings from tenant system variables. int read_tenant_wa_percentage(uint64_t tenant_id, int64_t &pctg); + int update_tenant_rpc_percentage(uint64_t tenant_id); private: common::ObArenaAllocator allocator_; }; diff --git a/src/observer/omt/ob_multi_tenant.cpp b/src/observer/omt/ob_multi_tenant.cpp index 071e588f4..0776e8c94 100644 --- a/src/observer/omt/ob_multi_tenant.cpp +++ b/src/observer/omt/ob_multi_tenant.cpp @@ -25,6 +25,7 @@ #include "share/resource_manager/ob_cgroup_ctrl.h" #include "ob_tenant.h" #include "rpc/ob_request.h" +#include "rpc/obmysql/ob_sql_nio_server.h" #include "storage/tx/ob_ts_mgr.h" #include "storage/ob_disk_usage_reporter.h" #include "storage/slog/ob_storage_log.h" @@ -32,6 +33,7 @@ #include "share/schema/ob_tenant_schema_service.h" #include "storage/slog/ob_storage_logger_manager.h" #include "observer/mysql/ob_mysql_request_manager.h" +#include "observer/mysql/obsm_conn_callback.h" #include "sql/dtl/ob_dtl_fc_server.h" #include "sql/dtl/ob_dtl_interm_result_manager.h" #include "sql/das/ob_das_id_service.h" @@ -246,6 +248,43 @@ static int init_compat_mode(lib::Worker::CompatMode &compat_mode) return ret; } +static int start_sql_nio_server(ObSqlNioServer *&sql_nio_server) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + ObSrvNetworkFrame *net_frame = GCTX.net_frame_; + sql_nio_server = OB_NEW(obmysql::ObSqlNioServer, "SqlNio", + obmysql::global_sm_conn_callback, + net_frame->get_mysql_handler(), tenant_id); + if (is_sys_tenant(tenant_id) || is_user_tenant(tenant_id)) { + if (NULL == sql_nio_server) { + ret = OB_NOT_INIT; + LOG_ERROR("sql_nio_server init failed", K(ret)); + } else { + int net_thread_count = 0; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id)); + if (tenant_config.is_valid()) { + net_thread_count = tenant_config->tenant_sql_net_thread_count; + } + if (0 == net_thread_count) { + ObTenant *tenant = NULL; + GCTX.omt_->get_tenant(tenant_id, tenant); + net_thread_count = + NULL == tenant ? 1 : std::max((int)tenant->unit_min_cpu(), 1); + } + sql_nio_server->get_nio()->set_run_wrapper(MTL_CTX()); + if (OB_FAIL(sql_nio_server->start(-1, &net_frame->get_deliver(), + net_thread_count))) { + LOG_WARN("sql nio server start failed", K(ret)); + } else { + LOG_INFO("tenant sql_nio_server mtl_start success", K(ret), + K(tenant_id)); + } + } + } + return ret; +} + template static int server_obj_pool_mtl_new(common::ObServerObjectPool *&pool) { @@ -261,6 +300,46 @@ static int server_obj_pool_mtl_new(common::ObServerObjectPool *&pool) return ret; } +static int init_mysql_queue(QueueThread *&qthread) +{ + int ret = OB_SUCCESS; + const uint64_t tenant_id = MTL_ID(); + qthread = OB_NEW(QueueThread, ObModIds::OB_RPC, "MysqlQueueTh", tenant_id); + if (is_sys_tenant(tenant_id) || is_user_tenant(tenant_id)) { + if (OB_ISNULL(qthread)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + } else if (OB_FAIL(TG_CREATE_TENANT(lib::TGDefIDs::MysqlQueueTh, + qthread->tg_id_))) { + LOG_WARN("mysql queue init failed", K(ret), K(tenant_id), + K(qthread->tg_id_)); + } else { + qthread->queue_.set_qhandler( + &GCTX.net_frame_->get_deliver().get_qhandler()); + ret = TG_SET_RUNNABLE_AND_START(qthread->tg_id_, qthread->thread_); + } + + if (OB_SUCC(ret) && OB_NOT_NULL(qthread)) { + int sql_thread_count = 0; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id)); + if (tenant_config.is_valid()) { + sql_thread_count = tenant_config->tenant_sql_login_thread_count; + } + if (0 == sql_thread_count) { + ObTenant *tenant = NULL; + GCTX.omt_->get_tenant(tenant_id, tenant); + sql_thread_count = + NULL == tenant ? 1 : std::max((int)tenant->unit_min_cpu(), 1); + } + qthread->set_thread_count(sql_thread_count); + LOG_INFO("tenant mysql_queue mtl_init success", K(ret), K(tenant_id)); + } else { + LOG_WARN("tenant mysql_queue mtl_init fail", K(ret), K(tenant_id), + K(qthread->tg_id_)); + } + } + return ret; +} + template static void server_obj_pool_mtl_destroy(common::ObServerObjectPool *&pool) { @@ -367,6 +446,12 @@ int ObMultiTenant::init(ObAddr myaddr, MTL_BIND2(mtl_new_default, ObPlanCache::mtl_init, nullptr, ObPlanCache::mtl_stop, nullptr, mtl_destroy_default); MTL_BIND2(mtl_new_default, ObPsCache::mtl_init, nullptr, ObPsCache::mtl_stop, nullptr, mtl_destroy_default); MTL_BIND2(server_obj_pool_mtl_new, nullptr, nullptr, nullptr, nullptr, server_obj_pool_mtl_destroy); + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread) { + MTL_BIND2(nullptr, init_mysql_queue, nullptr, mtl_stop_default, + mtl_wait_default, mtl_destroy_default); + // MTL_BIND2(nullptr, nullptr, start_sql_nio_server, mtl_stop_default, + // mtl_wait_default, mtl_destroy_default); + } } if (OB_SUCC(ret)) { @@ -1415,6 +1500,8 @@ int ObMultiTenant::remove_tenant(const uint64_t tenant_id, bool &try_clock_succ) } ObTenant *removed_tenant_tmp = nullptr; SpinWLockGuard guard(lock_); + // This locking should be held after tenant->wait + // because there maybe locking during tenant thread stopping. if (OB_FAIL(tenants_.remove_if(tenant_id, compare_with_tenant_id, equal_with_tenant_id, removed_tenant_tmp))) { LOG_WARN("fail to remove tenant", K(tenant_id), K(ret)); @@ -1989,33 +2076,12 @@ int ObMultiTenant::get_tenant_cpu( return ret; } -void ObMultiTenant::set_group_sug_token() -{ - int ret = OB_SUCCESS; - if (OB_FAIL(lock_tenant_list())) { - LOG_ERROR("fail to lock tenant list", K(ret)); - } else { - for (TenantList::iterator it = tenants_.begin(); it != tenants_.end(); it++) { - //set suggestion token for each tenant, all tenant use the fixed token. - if (!(*it)->has_stopped()) { // skip stopped tenant - ObTenantConfigGuard tenant_config(TENANT_CONF((*it)->id())); - (*it)->set_sug_token(std::max(1L, static_cast((*it)->unit_min_cpu() * - (tenant_config.is_valid() ? tenant_config->cpu_quota_concurrency : 4)))); - } - } - if (OB_FAIL(unlock_tenant_list())) { - LOG_ERROR("fail to unlock tenant list"); - } - } -} - void ObMultiTenant::run1() { lib::set_thread_name("MultiTenant"); while (!has_set_stop()) { { SpinRLockGuard guard(lock_); - set_group_sug_token(); for (TenantList::iterator it = tenants_.begin(); it != tenants_.end(); it++) { if (OB_ISNULL(*it)) { LOG_ERROR_RET(OB_ERR_UNEXPECTED, "unexpected condition"); @@ -2065,3 +2131,107 @@ int ObMultiTenant::check_if_unit_id_exist(const uint64_t unit_id, bool &exist) } return ret; } + +int obmysql::sql_nio_add_cgroup(const uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread && + nullptr != GCTX.cgroup_ctrl_ && + OB_LIKELY(GCTX.cgroup_ctrl_->is_valid())) { + ret = GCTX.cgroup_ctrl_->add_thread_to_cgroup(syscall(__NR_gettid), + tenant_id, OBCG_SQL_NIO); + } + return ret; +} + +int ObSrvNetworkFrame::reload_tenant_sql_thread_config(const uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + omt::ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_id)); + ObTenant *tenant = NULL; + GCTX.omt_->get_tenant(tenant_id, tenant); + + // reload tenant_sql_login_thread_count + int sql_login_thread_count = 0; + if (tenant_config.is_valid()) { + sql_login_thread_count = tenant_config->tenant_sql_login_thread_count; + } + if (0 == sql_login_thread_count) { + sql_login_thread_count = + NULL == tenant ? 1 : std::max((int)tenant->unit_min_cpu(), 1); + } + MTL_SWITCH(tenant_id) { + if (OB_FAIL(MTL(QueueThread *)->set_thread_count(sql_login_thread_count))) { + LOG_WARN("update tenant_sql_login_thread_count fail", K(ret)); + } + } + + // // reload tenant_sql_net_thread_count + // int sql_net_thread_count = 0; + // if (tenant_config.is_valid()) { + // sql_net_thread_count = tenant_config->tenant_sql_net_thread_count; + // if (0 == sql_net_thread_count) { + // sql_net_thread_count = + // NULL == tenant ? 1 : std::max((int)tenant->unit_min_cpu(), 1); + // } + // MTL_SWITCH(tenant_id) { + // ObSqlNioServer *sql_nio_server = MTL(ObSqlNioServer *); + // int cur_sql_net_thread_count = + // sql_nio_server->get_nio()->get_thread_count(); + // if (sql_net_thread_count < cur_sql_net_thread_count) { + // LOG_WARN("decrease tenant_sql_net_thread_count not allowed", K(ret), + // K(sql_net_thread_count), K(cur_sql_net_thread_count)); + // tenant_config->tenant_sql_net_thread_count = cur_sql_net_thread_count; + // } else if (OB_FAIL( + // sql_nio_server->set_thread_count(sql_net_thread_count))) { + // LOG_WARN("update tenant_sql_net_thread_count fail", K(ret), + // K(sql_net_thread_count)); + // } + // } + + return ret; + } + +int ObSrvNetworkFrame::reload_sql_thread_config() +{ + int ret = OB_SUCCESS; + int cnt = deliver_.get_mysql_login_thread_count_to_set( + GCONF.sql_login_thread_count); + if (OB_FAIL(deliver_.set_mysql_login_thread_count(cnt))) { + LOG_WARN("update sql_login_thread_count error", K(ret)); + } + + int sql_net_thread_count = (int)GCONF.sql_net_thread_count; + if (sql_net_thread_count == 0) { + if (GCONF.net_thread_count == 0) { + sql_net_thread_count = get_default_net_thread_count(); + } else { + sql_net_thread_count = GCONF.net_thread_count; + } + } + + if (OB_NOT_NULL(obmysql::global_sql_nio_server)) { + int cur_sql_net_thread_count = + obmysql::global_sql_nio_server->get_nio()->get_thread_count(); + if (sql_net_thread_count < cur_sql_net_thread_count) { + LOG_WARN("decrease sql_net_thread_count not allowed", K(ret), + K(sql_net_thread_count), K(cur_sql_net_thread_count)); + GCONF.sql_net_thread_count = cur_sql_net_thread_count; + } else if (OB_FAIL(obmysql::global_sql_nio_server->set_thread_count( + sql_net_thread_count))) { + LOG_WARN("update sql_net_thread_count error", K(ret)); + } + } + + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread) { + omt::TenantIdList ids; + GCTX.omt_->get_tenant_ids(ids); + for (int64_t i = 0; i < ids.size(); i++) { + int tenant_id = ids[i]; + if (is_sys_tenant(tenant_id) || is_user_tenant(tenant_id)) { + reload_tenant_sql_thread_config(tenant_id); + } + } + } + return ret; +} \ No newline at end of file diff --git a/src/observer/omt/ob_multi_tenant.h b/src/observer/omt/ob_multi_tenant.h index fd18bfc76..1e57a988e 100644 --- a/src/observer/omt/ob_multi_tenant.h +++ b/src/observer/omt/ob_multi_tenant.h @@ -17,7 +17,6 @@ #include #include "lib/container/ob_vector.h" #include "lib/lock/ob_bucket_lock.h" // ObBucketLock -#include "ob_worker_pool.h" #include "ob_tenant_node_balancer.h" namespace oceanbase @@ -162,7 +161,6 @@ public: inline bool has_synced() const; void set_workers_per_cpu(int64_t v); - void set_group_sug_token(); int write_create_tenant_abort_slog(uint64_t tenant_id); int write_delete_tenant_commit_slog(uint64_t tenant_id); int clear_persistent_data(const uint64_t tenant_id); diff --git a/src/observer/omt/ob_tenant.cpp b/src/observer/omt/ob_tenant.cpp index ffe268da8..c5ce48734 100644 --- a/src/observer/omt/ob_tenant.cpp +++ b/src/observer/omt/ob_tenant.cpp @@ -22,7 +22,6 @@ #include "sql/engine/px/ob_px_admission.h" #include "share/interrupt/ob_global_interrupt_call.h" #include "ob_th_worker.h" -#include "ob_worker_pool.h" #include "ob_multi_tenant.h" #include "observer/ob_server_struct.h" #include "share/schema/ob_schema_getter_guard.h" @@ -33,6 +32,8 @@ #include "logservice/palf/palf_options.h" #include "sql/dtl/ob_dtl_fc_server.h" #include "observer/mysql/ob_mysql_request_manager.h" +#include "observer/ob_srv_deliver.h" +#include "observer/ob_srv_network_frame.h" #include "storage/tx/wrs/ob_tenant_weak_read_service.h" #include "sql/engine/ob_tenant_sql_memory_manager.h" #include "storage/meta_mem/ob_tenant_meta_mem_mgr.h" @@ -43,10 +44,12 @@ #include "storage/slog/ob_storage_logger_manager.h" #include "storage/ob_file_system_router.h" #include "common/ob_smart_var.h" +#include "rpc/obmysql/ob_sql_nio_server.h" #include "rpc/obrpc/ob_rpc_stat.h" #include "rpc/obrpc/ob_rpc_packet.h" #include "lib/container/ob_array.h" #include "share/rc/ob_tenant_module_init_ctx.h" +#include "share/resource_manager/ob_cgroup_ctrl.h" #include "sql/engine/px/ob_px_worker.h" using namespace oceanbase::lib; @@ -59,6 +62,9 @@ using namespace oceanbase::storage; using namespace oceanbase::sql::dtl; using namespace oceanbase::obrpc; +#define EXPAND_INTERVAL (1L * 1000 * 1000) +#define SHRINK_INTERVAL (5L * 1000 * 1000) + void MultiLevelReqCnt::atomic_inc(const int32_t level) { if (level < 0 || level >= MAX_REQUEST_LEVEL) { @@ -109,7 +115,6 @@ int ObPxPools::create_pool(int64_t group_id, ObPxPool *&pool) } else { pool->set_tenant_id(tenant_id_); pool->set_group_id(group_id); - pool->set_thread_max_tasks(MAX_TASKS_PER_CPU); pool->set_run_wrapper(MTL_CTX()); if (OB_FAIL(pool->start())) { LOG_WARN("fail startup px pool", K(group_id), K(tenant_id_), K(ret)); @@ -221,8 +226,9 @@ void ObPxPool::handle(ObLink *task) void ObPxPool::set_px_thread_name() { char buf[32]; - snprintf(buf, 32, "PX_G%ld_%ld", group_id_, tenant_id_); - lib::set_thread_name_inner(buf); + snprintf(buf, 32, "PX_G%ld", group_id_); + ob_get_tenant_id() = tenant_id_; + lib::set_thread_name(buf); } void ObPxPool::run(int64_t idx) @@ -308,10 +314,7 @@ int ObResourceGroup::init() LOG_ERROR("group init failed"); } else { req_queue_.set_limit(common::ObServerConfig::get_instance().tenant_task_queue_size); - uint64_t worker_concurrency = ObCgSet::instance().get_worker_concurrency(group_id_); - set_token_cnt(worker_concurrency * static_cast(ceil(tenant_->unit_min_cpu()))); - set_min_token_cnt(token_cnt_); - set_max_token_cnt(worker_concurrency * static_cast(ceil(tenant_->unit_max_cpu()))); + token_cnt_ = min_worker_cnt(); inited_ = true; } return ret; @@ -332,26 +335,15 @@ int ObResourceGroup::acquire_more_worker(int64_t num, int64_t &succ_num) succ_num = 0; while (OB_SUCC(ret) && need_num > succ_num) { - ObThWorker *w = worker_pool_->alloc(); - if (w) { - w->reset(); - w->set_tidx(workers_.get_size() + 2000); - w->set_tenant(tenant_); - w->set_group(this); - w->set_group_id(group_id_); - if (OB_FAIL(w->start())) { - LOG_ERROR("worker start failed", K(ret)); - } else if (FALSE_IT(w->activate())) { - // do nothing - } else if (!workers_.add_last(&w->worker_node_)) { - OB_ASSERT(false); - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("add worker to list fail", K(ret)); - } else { - succ_num++; - } + ObThWorker *w = nullptr; + if (OB_FAIL(create_worker(w, tenant_, group_id_, INT32_MAX, this))) { + LOG_ERROR("create worker failed", K(ret)); + } else if (!workers_.add_last(&w->worker_node_)) { + OB_ASSERT(false); + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("add worker to list fail", K(ret)); } else { - ret = OB_SIZE_OVERFLOW; + succ_num++; } } @@ -366,79 +358,42 @@ int ObResourceGroup::acquire_more_worker(int64_t num, int64_t &succ_num) return ret; } -void ObResourceGroup::calibrate_token_count() -{ - int ret = OB_SUCCESS; - const auto current_time = ObTimeUtility::current_time(); - if (current_time - last_calibrate_token_ts_ > CALIBRATE_TOKEN_INTERVAL && - OB_SUCC(workers_lock_.trylock())) { - if (has_stop_) { - // do nothing - } else { - int64_t wait_worker = 0; - int64_t active_workers = 0; - DLIST_FOREACH_REMOVESAFE(wnode, workers_) { - const auto w = static_cast(wnode->get_data()); - if (w->is_active()) { - active_workers++; - if (!w->has_req_flag()) { - wait_worker++; - } - } - } - uint64_t worker_concurrency = ObCgSet::instance().get_worker_concurrency(group_id_); - if (worker_concurrency * static_cast(ceil(tenant_->unit_min_cpu())) != min_token_cnt_) { // If the user manually adjusts the tenant specifications, the dynamic token adjustment alone cannot respond quickly, and it needs to be adjusted forcibly - set_token_cnt(worker_concurrency * static_cast(ceil(tenant_->unit_min_cpu()))); - set_min_token_cnt(token_cnt_); - } - if (last_pop_req_cnt_ != 0 && pop_req_cnt_ == last_pop_req_cnt_ - && token_cnt_ == ass_token_cnt_) { - set_token_cnt(min(token_cnt_ + 1, max_token_cnt_)); - } - if (wait_worker > active_workers / 2) { - set_token_cnt(max(token_cnt_ - 1, min_token_cnt_)); - } - last_calibrate_token_ts_ = current_time; - last_pop_req_cnt_ = pop_req_cnt_; - } - - IGNORE_RETURN workers_lock_.unlock(); - } -} - void ObResourceGroup::check_worker_count() { int ret = OB_SUCCESS; if (OB_SUCC(workers_lock_.trylock())) { - if (has_stop_) { - // do nothing - } else { + int64_t token = 1; + bool enable_dynamic_worker = true; + { + ObTenantConfigGuard tenant_config(TENANT_CONF(tenant_->id())); + enable_dynamic_worker = tenant_config.is_valid() ? tenant_config->_ob_enable_dynamic_worker : true; + } + if (OB_LIKELY(enable_dynamic_worker)) { DLIST_FOREACH_REMOVESAFE(wnode, workers_) { const auto w = static_cast(wnode->get_data()); - const auto active_inactive_ts = w->get_active_inactive_ts(); - const auto sojourn_time = ObTimeUtility::current_time() - active_inactive_ts; - if (w->is_active()) { - //w->set_tidx(active_workers); - } else if (w->is_waiting_active() && - sojourn_time > PRESERVE_INACTIVE_WORKER_TIME) { - const auto active_inactive_ts = w->get_active_inactive_ts(); - const auto sojourn_time = ObTimeUtility::current_time() - active_inactive_ts; - if (sojourn_time > PRESERVE_INACTIVE_WORKER_TIME) { - workers_.remove(wnode); - w->reset(); - worker_pool_->free(w); - } + if (w->has_set_stop()) { + workers_.remove(wnode); + destroy_worker(w); + } else if (w->has_req_flag() && w->is_blocking() && w->is_default_worker()) { + ++token; } } - const auto diff = token_cnt_ - ass_token_cnt_; - if (diff > 0) { - int64_t succ_num = 0L; - acquire_more_worker(diff, succ_num); - ass_token_cnt_ += succ_num; - } else if (diff < 0) { - //ret = OB_NEED_WAIT; - } } + token = std::max(token, min_worker_cnt()); + token = std::min(token, max_worker_cnt()); + const auto diff = token - workers_.get_size(); + const auto now = ObTimeUtility::current_time(); + int64_t succ_num = 0L; + if (workers_.get_size() < min_worker_cnt()) { + acquire_more_worker(diff, succ_num); + token_change_ts_ = now; + } else if (diff > 0 + && now - token_change_ts_ >= EXPAND_INTERVAL + && ObMallocAllocator::get_instance()->get_tenant_remain(tenant_->id()) > ObMallocAllocator::get_instance()->get_tenant_limit(tenant_->id()) * 0.05) { + acquire_more_worker(1, succ_num); + token_change_ts_ = now; + } + token_cnt_ = token; IGNORE_RETURN workers_lock_.unlock(); } } @@ -446,22 +401,17 @@ void ObResourceGroup::check_worker_count() void ObResourceGroup::check_worker_count(ObThWorker &w) { int ret = OB_SUCCESS; - if (ass_token_cnt_ != token_cnt_ && + auto now = ObTimeUtility::current_time(); + if (token_cnt_ < workers_.get_size() && + now - token_change_ts_ > SHRINK_INTERVAL && OB_SUCC(workers_lock_.trylock())) { - const auto diff = token_cnt_ - ass_token_cnt_; - int tmp_ret = OB_SUCCESS; - if (has_stop_) { - // do nothing - } else if (diff > 0) { - int64_t succ_num = 0L; - acquire_more_worker(diff, succ_num); - ass_token_cnt_ += succ_num; - } else if (diff < 0) { - ass_token_cnt_--; - w.set_inactive(); + if (token_cnt_ < workers_.get_size()) { + w.stop(); + ATOMIC_INC(&token_cnt_); + ATOMIC_STORE(&token_change_ts_, now); if (cgroup_ctrl_->is_valid() - && OB_SUCCESS != (tmp_ret = cgroup_ctrl_->remove_thread_from_cgroup(w.get_tid(), tenant_->id()))) { - LOG_WARN("remove thread from cgroup failed", K(tmp_ret), "tenant:", tenant_->id(), K_(group_id)); + && OB_FAIL(cgroup_ctrl_->remove_thread_from_cgroup(w.get_tid(), tenant_->id()))) { + LOG_WARN("remove thread from cgroup failed", K(ret), "tenant:", tenant_->id(), K_(group_id)); } } IGNORE_RETURN workers_lock_.unlock(); @@ -476,12 +426,8 @@ int ObResourceGroup::clear_worker() int ret = OB_SUCCESS; DLIST_FOREACH_REMOVESAFE(wnode, workers_) { const auto w = static_cast(wnode->get_data()); - w->set_inactive(); - if (w->is_waiting_active()) { - w->reset(); - workers_.remove(wnode); - worker_pool_->free(w); - } + workers_.remove(wnode); + destroy_worker(w); } if (REACH_TIME_INTERVAL(10 * 1000L * 1000L)) { LOG_INFO( @@ -492,17 +438,13 @@ int ObResourceGroup::clear_worker() } ob_usleep(10L * 1000L); } - has_stop_ = true; return ret; } -int GroupMap::create_and_insert_group(int32_t group_id, ObTenant *tenant, ObWorkerPool *worker_pool, ObCgroupCtrl *cgroup_ctrl, ObResourceGroup *&group) +int GroupMap::create_and_insert_group(int32_t group_id, ObTenant *tenant, ObCgroupCtrl *cgroup_ctrl, ObResourceGroup *&group) { int ret = OB_SUCCESS; - int tmp_ret = OB_SUCCESS; - int64_t succ_num = 0; if (nullptr == tenant - || nullptr == worker_pool || nullptr == cgroup_ctrl) { ret = OB_INVALID_ARGUMENT; } else { @@ -511,11 +453,11 @@ int GroupMap::create_and_insert_group(int32_t group_id, ObTenant *tenant, ObWork if (nullptr == (buf = (ObResourceGroup*)ob_malloc(alloc_size, ObModIds::OMT_TENANT))) { ret = OB_ALLOCATE_MEMORY_FAILED; } else { - group = new(buf)ObResourceGroup(group_id, tenant, worker_pool, cgroup_ctrl); + group = new(buf)ObResourceGroup(group_id, tenant, cgroup_ctrl); if (OB_FAIL(group->init())) { LOG_ERROR("group init failed", K(ret), K(group_id)); - } else if (OB_FAIL(insert(group))) { - LOG_WARN("groupmap insert group failed", K(group->get_group_id()), K(tenant->id())); + } else if (OB_FAIL(err_code_map(insert(group)))) { + LOG_WARN("groupmap insert group failed", K(ret), K(group->get_group_id()), K(tenant->id())); } if (OB_SUCCESS != ret) { group->~ObResourceGroup(); @@ -546,7 +488,7 @@ void GroupMap::destroy_group() ObResourceGroupNode* iter = NULL; while (nullptr != (iter = quick_next(iter))) { ObResourceGroup *group = static_cast(iter); - if (OB_SUCC(del(iter, iter))) { + if (OB_SUCC(err_code_map(del(iter, iter)))) { group->~ObResourceGroup(); ob_free(group); iter = NULL; @@ -556,6 +498,21 @@ void GroupMap::destroy_group() } } +int GroupMap::err_code_map(int err) +{ + int ret = OB_SUCCESS; + switch (err) { + case 0: ret = OB_SUCCESS; break; + case -ENOENT: ret = OB_ENTRY_NOT_EXIST; break; + case -EAGAIN: ret = OB_EAGAIN; break; + case -ENOMEM: ret = OB_ALLOCATE_MEMORY_FAILED; break; + case -EEXIST: ret = OB_ENTRY_EXIST; break; + case -EOVERFLOW: ret = OB_SIZE_OVERFLOW; break; + default: ret = OB_ERROR; + } + return ret; +} + int64_t RpcStatInfo::to_string(char *buf, const int64_t len) const { int64_t pos = 0; @@ -605,26 +562,13 @@ ObTenant::ObTenant(const int64_t id, : ObTenantBase(id, true), meta_lock_(), tenant_meta_(), - times_of_workers_(times_of_workers), unit_max_cpu_(0), unit_min_cpu_(0), - slice_(0), - slice_remain_(0), - slice_remain_lock_(), - slice_remain_clear_flag_(true), - sug_token_cnt_(0), token_cnt_(0), - ass_token_cnt_(0), - lq_tokens_(0), - used_lq_tokens_(0), - last_calibrate_worker_ts_(0), - last_calibrate_token_ts_(0), - last_pop_normal_cnt_(0), - nesting_worker_has_init_(MULTI_LEVEL_THRESHOLD), + total_worker_cnt_(0), stopped_(true), wait_mtl_finished_(false), req_queue_(), - large_req_queue_(), recv_hp_rpc_cnt_(0), recv_np_rpc_cnt_(0), recv_lp_rpc_cnt_(0), @@ -636,24 +580,19 @@ ObTenant::ObTenant(const int64_t id, resume_cnt_(0), recv_retry_on_lock_rpc_cnt_(0), recv_retry_on_lock_mysql_cnt_(0), - actives_(0), tt_large_quries_(0), pop_normal_cnt_(0), - worker_pool_(), group_map_(group_map_buf_, sizeof(group_map_buf_)), lock_(), rpc_stat_info_(nullptr), mtl_init_ctx_(nullptr), workers_lock_(common::ObLatchIds::TENANT_WORKER_LOCK), - lq_waiting_workers_lock_(common::ObLatchIds::TENANT_WORKER_LOCK), cgroup_ctrl_(cgroup_ctrl), disable_user_sched_(false), token_usage_(.0), token_usage_check_ts_(0), - dynamic_modify_token_(false), - dynamic_modify_group_token_(true), + token_change_ts_(0), ctx_(nullptr), - px_pool_is_running_(false), st_metrics_(), sql_limiter_(), worker_us_(0), @@ -680,14 +619,10 @@ int ObTenant::init_ctx() int ObTenant::init(const ObTenantMeta &meta) { int ret = OB_SUCCESS; - int tmp_ret = OB_SUCCESS; if (OB_FAIL(ObTenantBase::init(&cgroup_ctrl_))) { LOG_WARN("fail to init tenant base", K(ret)); - } else if (FALSE_IT(req_queue_.set_limit(common::ObServerConfig::get_instance().tenant_task_queue_size))) { - } else if (worker_pool_.init(1, 1)) { - // useless now, but maybe useful later - LOG_WARN("init worker pool fail", K(ret)); + } else if (FALSE_IT(req_queue_.set_limit(GCONF.tenant_task_queue_size))) { } else if (OB_ISNULL(multi_level_queue_ = OB_NEW(ObMultiLevelQueue, ObModIds::OMT_TENANT))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloc ObMultiLevelQueue failed", K(ret), K(*this)); @@ -698,11 +633,7 @@ int ObTenant::init(const ObTenantMeta &meta) } else if (OB_FAIL(construct_mtl_init_ctx(meta, mtl_init_ctx_))) { LOG_WARN("construct_mtl_init_ctx failed", KR(ret), K(*this)); } else { - // set it into ObTenantBase, so it can be get by MTL ObTenantBase::mtl_init_ctx_ = mtl_init_ctx_; - } - - if (OB_SUCC(ret)) { tenant_meta_ = meta; set_unit_min_cpu(meta.unit_.config_.min_cpu()); set_unit_max_cpu(meta.unit_.config_.max_cpu()); @@ -712,10 +643,29 @@ int ObTenant::init(const ObTenantMeta &meta) update_mini_mode(memory_size <= MINI_MEM_UPPER); if (!is_virtual_tenant_id(id_)) { - ret = create_tenant_module(); + if (OB_FAIL(create_tenant_module())) { + // do nothing + } else if (OB_FAIL(OB_PX_TARGET_MGR.add_tenant(id_))) { + LOG_WARN("add tenant into px target mgr failed", K(ret), K(id_)); + } } else { disable_user_sched(); // disable_user_sched for virtual tenant } + int64_t succ_cnt = 0L; + if (OB_FAIL(acquire_more_worker(2, succ_cnt))) { + LOG_WARN("create worker in init failed", K(ret), K(succ_cnt)); + } else { + // there must be 2 workers. + static_cast(workers_.get_first()->get_data())->set_priority_limit(QQ_HIGH); + static_cast(workers_.get_last()->get_data())->set_priority_limit(QQ_NORMAL); + for (int level = MULTI_LEVEL_THRESHOLD; level < MAX_REQUEST_LEVEL; level++) { + if (OB_FAIL(acquire_level_worker(1, succ_cnt, level))) { + break; + } + succ_cnt = 0L; + } + timeup(); + } } if (OB_SUCC(ret) && !is_virtual_tenant_id(id_)) { if (OB_FAIL(OB_PX_TARGET_MGR.add_tenant(id_))) { @@ -796,12 +746,6 @@ ObTenantSuperBlock ObTenant::get_super_block() return tenant_meta_.super_block_; } -void ObTenant::set_tenant_meta(const ObTenantMeta &meta) -{ - TCWLockGuard guard(meta_lock_); - tenant_meta_ = meta; -} - void ObTenant::set_tenant_unit(const ObUnitInfoGetter::ObTenantConfig &unit) { TCWLockGuard guard(meta_lock_); @@ -884,39 +828,16 @@ int ObTenant::create_tenant_module() return ret; } -void ObTenant::set_stop(const bool is_stop) -{ - ATOMIC_STORE(&stopped_, is_stop); -} - -void ObTenant::stop() -{ - ATOMIC_STORE(&stopped_, true); // don't receive new request. -} void ObTenant::wait() { - while (has_task()) { - { - ObMutexGuard guard(lq_waiting_workers_lock_); - DLIST_FOREACH_NORET(wnode, lq_waiting_workers_) { - const auto w = static_cast(wnode->get_data()); - resume_it(*w); - } - } - ob_usleep(100L * 1000L); - } + int ret = OB_SUCCESS; while (workers_.get_size() > 0) { - int ret = OB_SUCCESS; if (OB_SUCC(workers_lock_.trylock())) { DLIST_FOREACH_REMOVESAFE(wnode, workers_) { const auto w = static_cast(wnode->get_data()); - w->set_inactive(); - if (w->is_waiting_active()) { - w->reset(); - workers_.remove(wnode); - worker_pool_.free(w); - } + workers_.remove(wnode); + destroy_worker(w); } IGNORE_RETURN workers_lock_.unlock(); if (REACH_TIME_INTERVAL(10 * 1000L * 1000L)) { @@ -934,14 +855,9 @@ void ObTenant::wait() int ret = OB_SUCCESS; if (OB_SUCC(workers_lock_.trylock())) { DLIST_FOREACH_REMOVESAFE(wnode, nesting_workers_) { - const auto w = static_cast(wnode->get_data()); - w->set_inactive(); - if (w->is_waiting_active()) { - w->reset(); - nesting_workers_.remove(wnode); - worker_pool_.free(w); - nesting_worker_has_init_--; - } + auto w = static_cast(wnode->get_data()); + nesting_workers_.remove(wnode); + destroy_worker(w); } IGNORE_RETURN workers_lock_.unlock(); if (REACH_TIME_INTERVAL(10 * 1000L * 1000L)) { @@ -981,7 +897,6 @@ void ObTenant::destroy() && OB_SUCCESS != (tmp_ret = cgroup_ctrl_.remove_tenant_cgroup(id_))) { LOG_WARN_RET(tmp_ret, "remove tenant cgroup failed", K(tmp_ret), K_(id)); } - worker_pool_.destroy(); group_map_.destroy_group(); ObTenantSwitchGuard guard(this); ObTenantBase::destroy(); @@ -1007,6 +922,7 @@ void ObTenant::set_unit_max_cpu(double cpu) const double default_cfs_period_us = 100000.0; int32_t cfs_quota_us = static_cast(default_cfs_period_us * cpu); if (cgroup_ctrl_.is_valid() + && !is_meta_tenant(id_) && OB_SUCCESS != (tmp_ret = cgroup_ctrl_.set_cpu_cfs_quota(cfs_quota_us, id_))) { LOG_WARN_RET(tmp_ret, "set cpu cfs quota failed", K(tmp_ret), K_(id), K(cfs_quota_us)); } @@ -1024,32 +940,13 @@ void ObTenant::set_unit_min_cpu(double cpu) } } -void ObTenant::set_token(const int64_t token) +int64_t ObTenant::min_worker_cnt() const { - if (token >= 0) { - token_cnt_ = token; - } + ObTenantConfigGuard tenant_config(TENANT_CONF(id_)); + return 2 + std::max(1L, static_cast(unit_min_cpu() * (tenant_config.is_valid() ? tenant_config->cpu_quota_concurrency : 4))); } -void ObTenant::set_sug_token(const int64_t token) -{ - if (token >= 0) { - if (id_ == OB_DATA_TENANT_ID) { // 509 tenant has it independent thread num - sug_token_cnt_ = 10; - token_cnt_ = sug_token_cnt_; - } else if (token != sug_token_cnt_){ - LOG_INFO("modify tenant sug_token_cnt", K(id()), K(sug_token_cnt_), K(token)); - sug_token_cnt_ = token; - token_cnt_ = sug_token_cnt_; - } - const auto lq_pctg = GCONF.large_query_worker_percentage.get(); - const auto lq_token = static_cast(sug_token_cnt_) * lq_pctg / 100.0; - const auto final_lq_token = std::max(1L, static_cast(lq_token)); - ATOMIC_SET(&lq_tokens_, final_lq_token); - } -} - -int64_t ObTenant::worker_count_bound() const +int64_t ObTenant::max_worker_cnt() const { // All max_cpu in unit won't beyond this node's cpu count, so worker // bound of all tenant in this node wont't exceeds number of the @@ -1058,8 +955,11 @@ int64_t ObTenant::worker_count_bound() const if (OB_UNLIKELY(id_ == OB_DATA_TENANT_ID)) { bound = 128; } else { - bound = static_cast( - unit_max_cpu_ * static_cast(times_of_workers_)); + // memory_size * 0.05 / 4M + bound = + static_cast(std::max(tenant_meta_.unit_.config_.memory_size() * + 0.05 / (GCONF.stack_size + (3 << 20) + (512 << 10)), + 150.0)); } return bound; } @@ -1070,16 +970,13 @@ int ObTenant::get_new_request( rpc::ObRequest *&req) { int ret = OB_SUCCESS; - int wk_level = 0; ObLink* task = nullptr; req = nullptr; - if (w.get_group() != nullptr) { + if (w.is_group_worker()) { w.set_large_query(false); w.set_curr_request_level(0); - wk_level = w.get_worker_level(); if (OB_SUCC(w.get_group()->req_queue_.pop(task, timeout))) { - w.get_group()->atomic_inc_pop_cnt(); EVENT_INC(REQUEST_DEQUEUE_COUNT); if (nullptr == req && nullptr != task) { req = static_cast(task); @@ -1089,6 +986,7 @@ int ObTenant::get_new_request( } } } else { + int wk_level = 0; w.set_large_query(false); w.set_curr_request_level(0); wk_level = w.get_worker_level(); @@ -1108,80 +1006,47 @@ int ObTenant::get_new_request( } else { LOG_ERROR("pop queue err", "tenant_id", id_, K(ret)); } - } else if (wk_level > 0) { + } else if (w.is_level_worker()) { ret = multi_level_queue_->pop(task, wk_level, timeout); } else { - const bool only_high_high_prio - = w.Worker::get_tidx() == 1 && workers_.get_size() > 2; - const bool only_high_prio - = w.Worker::get_tidx() == 0 && workers_.get_size() > 1; - - - if (!only_high_high_prio && !only_high_prio) { - for (int32_t level = MAX_REQUEST_LEVEL - 1; level >= 1; level--) { // Level 0 threads also need to look at the requests of non-level 0 queues first - IGNORE_RETURN multi_level_queue_->try_pop(task, level); - if (nullptr != task) { - ret = OB_SUCCESS; - break; - } - } - } - - - if (nullptr == task) { - if (OB_UNLIKELY(only_high_high_prio)) { - // We must ensure at least one worker can process the highest - // priority task. - ret = req_queue_.pop_high_high(task, timeout); - } else if (OB_UNLIKELY(only_high_prio)) { - // We must ensure at least number of tokens of workers which don't - // process low priority task. - ret = req_queue_.pop_high(task, timeout); - } else { - // If large requests exist and this worker doesn't have LQT but - // can acquire, do it. - ATOMIC_INC(&pop_normal_cnt_); - if (large_req_queue_.size() > 0 && - !w.has_lq_token() && - acquire_lq_token()) { - w.set_lq_token(); - } - if (OB_LIKELY(!w.has_lq_token())) { - ret = req_queue_.pop(task, 0L); - } - if (OB_UNLIKELY(nullptr == task)) { - // If large query flag is set, we prefer large query. - if (OB_SUCC(large_req_queue_.pop(task))) { - w.set_large_query(); - } else { - // Ignore return code from large queue and get request from - // normal queue. - ret = req_queue_.pop(task, timeout); + if (w.is_default_worker()) { + for (int32_t level = MAX_REQUEST_LEVEL - 1; level >= 1; level--) { // Level 0 threads also need to look at the requests of non-level 0 queues first + IGNORE_RETURN multi_level_queue_->try_pop(task, level); + if (nullptr != task) { + ret = OB_SUCCESS; + break; } } } - } - } - - if (OB_SUCC(ret)) { - EVENT_INC(REQUEST_DEQUEUE_COUNT); - if (nullptr == req && nullptr != task) { - req = static_cast(task); - } - if (nullptr != req && req->get_type() == ObRequest::OB_RPC) { - using obrpc::ObRpcPacket; - const ObRpcPacket &pkt - = static_cast(req->get_packet()); - w.set_curr_request_level(pkt.get_request_level()); - } - } - - if (w.has_lq_token() && - (nullptr == req || !w.large_query())) { - if (w.has_lq_token()) { - release_lq_token(); + if (OB_ISNULL(task)) { + if (OB_UNLIKELY(w.is_high_priority())) { + // We must ensure at least one worker can process the highest + // priority task. + ret = req_queue_.pop_high(task, timeout); + } else if (OB_UNLIKELY(w.is_normal_priority())) { + // We must ensure at least number of tokens of workers which don't + // process low priority task. + ret = req_queue_.pop_normal(task, timeout); + } else { + // If large requests exist and this worker doesn't have LQT but + // can acquire, do it. + ATOMIC_INC(&pop_normal_cnt_); + ret = req_queue_.pop(task, timeout); + } + } + } + + if (OB_SUCC(ret)) { + EVENT_INC(REQUEST_DEQUEUE_COUNT); + if (nullptr == req && nullptr != task) { + req = static_cast(task); + } + if (nullptr != req && req->get_type() == ObRequest::OB_RPC) { + using obrpc::ObRpcPacket; + const ObRpcPacket &pkt + = static_cast(req->get_packet()); + w.set_curr_request_level(pkt.get_request_level()); } - w.set_lq_token(false); } } @@ -1214,6 +1079,33 @@ inline bool is_warmup(const ObRpcPacket &pkt) return pkt.get_priority() == 11; } +int ObTenant::recv_group_request(ObRequest &req, int64_t group_id) +{ + int ret = OB_SUCCESS; + req.set_enqueue_timestamp(ObTimeUtility::current_time()); + ObResourceGroup* group = nullptr; + ObResourceGroupNode* node = nullptr; + ObResourceGroupNode key(group_id); + if (OB_SUCC(GroupMap::err_code_map(group_map_.get(&key, node)))) { + group = static_cast(node); + } else if (OB_FAIL(group_map_.create_and_insert_group(group_id, this, &cgroup_ctrl_, group))) { + if (OB_ENTRY_EXIST == ret && OB_SUCC(GroupMap::err_code_map(group_map_.get(&key, node)))) { + group = static_cast(node); + } else { + LOG_WARN("failed to create and insert group", K(ret), K(group_id), K(id_)); + } + } else { + LOG_INFO("create group successfully", K_(id), K(group_id), K(group)); + } + if (OB_SUCC(ret)) { + group->atomic_inc_recv_cnt(); + if (OB_FAIL(group->req_queue_.push(&req, 0))) { + LOG_ERROR("push request to queue fail", K(ret), K(this)); + } + } + return ret; +} + int ObTenant::recv_request(ObRequest &req) { int ret = OB_SUCCESS; @@ -1222,21 +1114,8 @@ int ObTenant::recv_request(ObRequest &req) ret = OB_IN_STOP_STATE; LOG_WARN("receive request but tenant has already stopped", K(ret), K(id_)); } else if (0 != req.get_group_id()) { - req.set_enqueue_timestamp(ObTimeUtility::current_time()); - int32_t group_id = req.get_group_id(); - ObResourceGroup* group = nullptr; - ObResourceGroupNode* node = nullptr; - ObResourceGroupNode key(group_id); - if (0 == group_map_.get(&key, node)) { - group = static_cast(node); - } else if (OB_FAIL(group_map_.create_and_insert_group(group_id, this, &worker_pool_, &cgroup_ctrl_, group))) { - LOG_WARN("failed to create and insert group", K(group_id), K(id_)); - } - if (OB_SUCC(ret)) { - group->atomic_inc_recv_cnt(); - if (OB_FAIL(group->req_queue_.push(&req, 0))) { - LOG_ERROR("push request to queue fail", K(ret), K(this)); - } + if (OB_FAIL(recv_group_request(req, req.get_group_id()))) { + LOG_ERROR("recv group request failed", K(ret), K(id_), K(req.get_group_id())); } } else { // Request would been pushed into corresponding queue by rule. @@ -1248,81 +1127,90 @@ int ObTenant::recv_request(ObRequest &req) // req.set_enqueue_timestamp(ObTimeUtility::current_time()); req.set_trace_point(ObRequest::OB_EASY_REQUEST_TENANT_RECEIVED); - if (req.get_type() == ObRequest::OB_RPC) { - using obrpc::ObRpcPacket; - const ObRpcPacket &pkt - = static_cast(req.get_packet()); - req_level = min(pkt.get_request_level(), MAX_REQUEST_LEVEL - 1); // Requests that exceed the limit are pushed to the highest-level queue - if (req_level < 0) { - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("unexpected level", K(req_level), K(id_)); - } else if (req_level >= MULTI_LEVEL_THRESHOLD) { - recv_level_rpc_cnt_.atomic_inc(req_level); - if (OB_FAIL(multi_level_queue_->push(req, req_level, 0))) { - LOG_WARN("push request to queue fail", K(ret), K(this)); - } - } else { - // (0,5) High priority - // (5,10) Normal priority - // 10 is the low priority used by ddl and should not appear here - // 11 Ultra-low priority for preheating - if (is_high_prio(pkt)) { // the less number the higher priority - ATOMIC_INC(&recv_hp_rpc_cnt_); - if (OB_FAIL(req_queue_.push(&req, QQ_HIGH))) { - if (REACH_TIME_INTERVAL(5 * 1000 * 1000)) { - LOG_WARN("push request to queue fail", K(ret), K(*this)); - } - } - } else if (req.is_retry_on_lock()) { - ATOMIC_INC(&recv_retry_on_lock_rpc_cnt_); - if (OB_FAIL(req_queue_.push(&req, QQ_PRIOR_TO_NORMAL))) { - LOG_WARN("push request to QQ_PRIOR_TO_NORMAL queue fail", K(ret), K(this)); - } - } else if (is_normal_prio(pkt) || is_low_prio(pkt)) { - ATOMIC_INC(&recv_np_rpc_cnt_); - if (OB_FAIL(req_queue_.push(&req, QQ_NORMAL))) { - LOG_WARN("push request to queue fail", K(ret), K(this)); - } - } else if (is_ddl(pkt)) { + switch (req.get_type()) { + case ObRequest::OB_RPC: { + using obrpc::ObRpcPacket; + const ObRpcPacket& pkt = static_cast(req.get_packet()); + req_level = min(pkt.get_request_level(), MAX_REQUEST_LEVEL - 1); // Requests that exceed the limit are pushed to the highest-level queue + if (req_level < 0) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("priority 10 should not come here", K(ret)); - } else if (is_warmup(pkt)) { - ATOMIC_INC(&recv_lp_rpc_cnt_); - if (OB_FAIL(req_queue_.push(&req, RQ_LOW))) { + LOG_ERROR("unexpected level", K(req_level), K(id_)); + } else if (req_level >= MULTI_LEVEL_THRESHOLD) { + recv_level_rpc_cnt_.atomic_inc(req_level); + if (OB_FAIL(multi_level_queue_->push(req, req_level, 0))) { LOG_WARN("push request to queue fail", K(ret), K(this)); } } else { - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("unexpected priority", K(ret), K(pkt.get_priority())); + // (0,5) High priority + // [5,10) Normal priority + // 10 is the low priority used by ddl and should not appear here + // 11 Ultra-low priority for preheating + if (is_high_prio(pkt)) { // the less number the higher priority + ATOMIC_INC(&recv_hp_rpc_cnt_); + if (OB_FAIL(req_queue_.push(&req, QQ_HIGH))) { + if (REACH_TIME_INTERVAL(5 * 1000 * 1000)) { + LOG_WARN("push request to queue fail", K(ret), K(*this)); + } + } + } else if (req.is_retry_on_lock()) { + ATOMIC_INC(&recv_retry_on_lock_rpc_cnt_); + if (OB_FAIL(req_queue_.push(&req, QQ_NORMAL))) { + LOG_WARN("push request to QQ_NORMAL queue fail", K(ret), K(this)); + } + } else if (is_normal_prio(pkt) || is_low_prio(pkt)) { + ATOMIC_INC(&recv_np_rpc_cnt_); + if (OB_FAIL(req_queue_.push(&req, QQ_LOW))) { + LOG_WARN("push request to queue fail", K(ret), K(this)); + } + } else if (is_ddl(pkt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("priority 10 should not come here", K(ret)); + } else if (is_warmup(pkt)) { + ATOMIC_INC(&recv_lp_rpc_cnt_); + if (OB_FAIL(req_queue_.push(&req, RQ_LOW))) { + LOG_WARN("push request to queue fail", K(ret), K(this)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("unexpected priority", K(ret), K(pkt.get_priority())); + } } + break; } - } else if (req.get_type() == ObRequest::OB_MYSQL) { - const obmysql::ObMySQLRawPacket &pkt = reinterpret_cast(req.get_packet()); - if (req.is_retry_on_lock()) { - ATOMIC_INC(&recv_retry_on_lock_mysql_cnt_); - if (OB_FAIL(req_queue_.push(&req, RQ_HIGH))) { - LOG_WARN("push request to RQ_HIGH queue fail", K(ret), K(this)); + case ObRequest::OB_MYSQL: { + if (req.is_retry_on_lock()) { + ATOMIC_INC(&recv_retry_on_lock_mysql_cnt_); + if (OB_FAIL(req_queue_.push(&req, RQ_HIGH))) { + LOG_WARN("push request to RQ_HIGH queue fail", K(ret), K(this)); + } + } else { + ATOMIC_INC(&recv_mysql_cnt_); + if (OB_FAIL(req_queue_.push(&req, RQ_NORMAL))) { + LOG_WARN("push request to queue fail", K(ret), K(this)); + } } - } else { - ATOMIC_INC(&recv_mysql_cnt_); + break; + } + case ObRequest::OB_TASK: + case ObRequest::OB_TS_TASK: { + ATOMIC_INC(&recv_task_cnt_); + if (OB_FAIL(req_queue_.push(&req, RQ_HIGH))) { + LOG_WARN("push request to queue fail", K(ret), K(this)); + } + break; + } + case ObRequest::OB_SQL_TASK: { + ATOMIC_INC(&recv_sql_task_cnt_); if (OB_FAIL(req_queue_.push(&req, RQ_NORMAL))) { LOG_WARN("push request to queue fail", K(ret), K(this)); } + break; } - - } else if (req.get_type() == ObRequest::OB_TASK || req.get_type() == ObRequest::OB_TS_TASK) { - ATOMIC_INC(&recv_task_cnt_); - if (OB_FAIL(req_queue_.push(&req, RQ_HIGH))) { - LOG_WARN("push request to queue fail", K(ret), K(this)); + default: { + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("unknown request type", K(ret)); + break; } - } else if (req.get_type() == ObRequest::OB_SQL_TASK) { - ATOMIC_INC(&recv_sql_task_cnt_); - if (OB_FAIL(req_queue_.push(&req, RQ_NORMAL))) { - LOG_WARN("push request to queue fail", K(ret), K(this)); - } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("unknown request type", K(ret)); } } @@ -1338,22 +1226,19 @@ int ObTenant::recv_large_request(rpc::ObRequest &req) { int ret = OB_SUCCESS; req.set_enqueue_timestamp(ObTimeUtility::current_time()); + req.set_large_retry_flag(true); if (ATOMIC_LOAD(&stopped_)) { ret = OB_IN_STOP_STATE; LOG_WARN("receive large request but tenant has already stopped", K(ret), K(id_)); } else if (0 != req.get_group_id()) { - req.set_large_retry_flag(true); if (OB_FAIL(recv_request(req))) { LOG_WARN("tenant receive large retry request fail", K(ret)); } + } else if (OB_FAIL(recv_group_request(req, OBCG_LQ))){ + LOG_ERROR("recv large request failed", K(id_)); } else { - ATOMIC_INC(&recv_large_req_cnt_); - if (OB_FAIL(large_req_queue_.push(&req))) { - LOG_WARN("push large request queue fail", K(req), K(ret)); - } else { - ObTenantStatEstGuard guard(id_); - EVENT_INC(REQUEST_ENQUEUE_COUNT); - } + ObTenantStatEstGuard guard(id_); + EVENT_INC(REQUEST_ENQUEUE_COUNT); } return ret; } @@ -1366,15 +1251,19 @@ int ObTenant::push_retry_queue(rpc::ObRequest &req, const uint64_t timestamp) int ObTenant::timeup() { int ret = OB_SUCCESS; - calibrate_group_token_count(); - check_group_worker_count(); - check_worker_count(); - update_token_usage(); - calibrate_worker_count(); - handle_retry_req(); - calibrate_token_count(); - update_queue_size(); - return ret; + ObLDHandle handle; + if (!stopped_ && OB_SUCC(try_rdlock(handle))) { + // it may fail during drop tenant, try next time. + if (!stopped_) { + check_group_worker_count(); + check_worker_count(); + update_token_usage(); + handle_retry_req(); + update_queue_size(); + } + IGNORE_RETURN unlock(handle); + } + return OB_SUCCESS; } void ObTenant::handle_retry_req() @@ -1405,219 +1294,84 @@ void ObTenant::update_queue_size() } } -void ObTenant::calibrate_token_count() -{ - if (dynamic_modify_token_ || OB_DATA_TENANT_ID == id_) { - int ret = OB_SUCCESS; - const auto current_time = ObTimeUtility::current_time(); - if (current_time - last_calibrate_token_ts_ > CALIBRATE_TOKEN_INTERVAL && - OB_SUCC(workers_lock_.trylock())) { - int64_t wait_worker = 0; - int64_t active_workers = 0; - DLIST_FOREACH_REMOVESAFE(wnode, workers_) { - const auto w = static_cast(wnode->get_data()); - if (w->is_active()) { - active_workers++; - if (!w->has_req_flag()) { - wait_worker++; - } - } - } - if (last_pop_normal_cnt_ != 0 && pop_normal_cnt_ == last_pop_normal_cnt_) { - set_token(min(token_cnt_ + 1, worker_count_bound())); - } - if (wait_worker > active_workers / 2) { - set_token(max(token_cnt_ - 1, sug_token_cnt_)); - } - last_calibrate_token_ts_ = current_time; - last_pop_normal_cnt_ = pop_normal_cnt_; - IGNORE_RETURN workers_lock_.unlock(); - } - } -} - -void ObTenant::calibrate_group_token_count() -{ - if (dynamic_modify_group_token_) { - ObResourceGroupNode* iter = NULL; - ObResourceGroup* group = nullptr; - while (NULL != (iter = group_map_.quick_next(iter))) { - group = static_cast(iter); - group->calibrate_token_count(); - } - } -} - -void ObTenant::calibrate_worker_count() +void ObTenant::check_worker_count() { int ret = OB_SUCCESS; - const auto current_time = ObTimeUtility::current_time(); - if (current_time - last_calibrate_worker_ts_ > CALIBRATE_WORKER_INTERVAL) { - if (OB_SUCC(workers_lock_.trylock())) { - int active_workers = 0; - DLIST_FOREACH_REMOVESAFE(wnode, workers_) { - const auto w = static_cast(wnode->get_data()); - if (w->is_active()) { - active_workers++; - } - } - int64_t new_ass_token_cnt = active_workers - lq_waiting_workers_.get_size(); - LOG_INFO("tenant calibrate worker", K_(id), K_(ass_token_cnt), K(new_ass_token_cnt)); - if (new_ass_token_cnt > 0) { - ass_token_cnt_ = new_ass_token_cnt; - } - last_calibrate_worker_ts_ = current_time; - IGNORE_RETURN workers_lock_.unlock(); - } - } -} - -int ObTenant::check_worker_count() -{ - int ret = OB_SUCCESS; - if (nesting_worker_has_init_ < MAX_REQUEST_LEVEL && OB_SUCC(workers_lock_.trylock())) { - LOG_WARN("tenant acquire nesting worker", K(nesting_worker_has_init_)); - int64_t need_cnt = 1L; - int64_t succ_cnt = 0L; - for (int level = nesting_worker_has_init_; level < MAX_REQUEST_LEVEL; level++,nesting_worker_has_init_++) { - if (OB_SUCCESS != acquire_level_worker(need_cnt, succ_cnt, level) || succ_cnt != need_cnt) { - break; - } - succ_cnt = 0L; - } - IGNORE_RETURN workers_lock_.unlock(); - LOG_WARN("tenant acquire nesting worker done", K(nesting_worker_has_init_)); - } if (OB_SUCC(workers_lock_.trylock())) { - // 1. update active workers count - // 2. remove inactive workers - // 3. update worker TIDX(tenant index) - auto active_workers = 0; - DLIST_FOREACH_REMOVESAFE(wnode, workers_) { - const auto w = static_cast(wnode->get_data()); - if (w->get_worker_level() == 0){ - const auto active_inactive_ts = w->get_active_inactive_ts(); - const auto sojourn_time = ObTimeUtility::current_time() - active_inactive_ts; - if (w->is_active()) { - w->set_tidx(active_workers); - active_workers++; - } else if (w->is_waiting_active() && - sojourn_time > PRESERVE_INACTIVE_WORKER_TIME) { - // Sojourn time may not correct before it's not atomic when we - // get active status and get active_inactive_ts. There are two - // exceptions: - // - // 1. If worker is changing status from inactive to active, - // time we get is its total inactive time but we treat it - // as its active time. It's OK since we do nothing with - // its sojourn time when worker is detected as active. - // - // 2. If worker is change status from active to inactive, - // then time we get is its total active time but we treat - // it as its inactive time. Because we need use worker's - // sojourn time to judge when to put inactive worker into - // global worker pool, recalculate its sojourn time is - // necessary to exclude this case. - // - // BTW, With lock of workers it's safe worker won't change - // status from inactive to active but not opposite. - const auto active_inactive_ts = w->get_active_inactive_ts(); - const auto sojourn_time = ObTimeUtility::current_time() - active_inactive_ts; - if (sojourn_time > PRESERVE_INACTIVE_WORKER_TIME) { - workers_.remove(wnode); - w->reset(); - worker_pool_.free(w); - } + int64_t token = 3; + bool enable_dynamic_worker = true; + { + ObTenantConfigGuard tenant_config(TENANT_CONF(id_)); + enable_dynamic_worker = tenant_config.is_valid() ? tenant_config->_ob_enable_dynamic_worker : true; + } + if (OB_LIKELY(enable_dynamic_worker)) { + // assume that high priority and normal priority were busy. + DLIST_FOREACH_REMOVESAFE(wnode, workers_) { + const auto w = static_cast(wnode->get_data()); + if (w->has_set_stop()) { + workers_.remove(wnode); + destroy_worker(w); + } else if (w->has_req_flag() && w->is_blocking() && w->is_default_worker()) { + ++token; } } } - actives_ = active_workers; - - const auto diff = token_cnt_ - ass_token_cnt_; - if (diff > 0) { - int64_t succ_num = 0L; + token = std::max(token, min_worker_cnt()); + token = std::min(token, max_worker_cnt()); + const auto diff = token - workers_.get_size(); + const auto now = ObTimeUtility::current_time(); + int64_t succ_num = 0L; + if (workers_.get_size() < min_worker_cnt()) { acquire_more_worker(diff, succ_num); - // diff is the number of fail workers. - ass_token_cnt_ += succ_num; - } else if (diff < 0) { - ret = OB_NEED_WAIT; + token_change_ts_ = now; + } else if (diff > 0 + && now - token_change_ts_ >= EXPAND_INTERVAL + && ObMallocAllocator::get_instance()->get_tenant_remain(id_) > ObMallocAllocator::get_instance()->get_tenant_limit(id_) * 0.05) { + acquire_more_worker(1, succ_num); + token_change_ts_ = now; } - + token_cnt_ = token; IGNORE_RETURN workers_lock_.unlock(); - } else { - ret = OB_EAGAIN; } - return ret; + + if (GCONF._enable_new_sql_nio && GCONF._enable_tenant_sql_net_thread && + (is_sys_tenant(id_) || is_user_tenant(id_))) { + GCTX.net_frame_->reload_tenant_sql_thread_config(id_); + } } -int ObTenant::check_group_worker_count() +void ObTenant::check_group_worker_count() { - int ret = OB_SUCCESS; ObResourceGroupNode* iter = NULL; ObResourceGroup* group = nullptr; while (NULL != (iter = group_map_.quick_next(iter))) { group = static_cast(iter); group->check_worker_count(); } - return ret; } -int ObTenant::check_worker_count(ObThWorker &w) +void ObTenant::check_worker_count(ObThWorker &w) { int ret = OB_SUCCESS; - if (nesting_worker_has_init_ < MAX_REQUEST_LEVEL && OB_SUCC(workers_lock_.trylock())) { - LOG_WARN("thread acquire nesting worker", K(w.get_tidx()), K(nesting_worker_has_init_)); - int64_t need_cnt = 1L; - int64_t succ_cnt = 0L; - for (int level = nesting_worker_has_init_; level < MAX_REQUEST_LEVEL; level++,nesting_worker_has_init_++) { - if (OB_SUCCESS != acquire_level_worker(need_cnt, succ_cnt, level) || succ_cnt != need_cnt) { - break; - } - succ_cnt = 0L; - } - IGNORE_RETURN workers_lock_.unlock(); - LOG_WARN("thread acquire nesting worker", K(w.get_tidx()), K(nesting_worker_has_init_)); - } - if (ass_token_cnt_ != token_cnt_ && + auto now = ObTimeUtility::current_time(); + if (token_cnt_ < workers_.get_size() && + now - token_change_ts_ > SHRINK_INTERVAL && OB_SUCC(workers_lock_.trylock())) { - const auto diff = token_cnt_ - ass_token_cnt_; - int tmp_ret = OB_SUCCESS; - // ass_token_cnt_ maybe change before having acquired lock so we - // check diff once more. - if (diff > 0) { - int64_t succ_num = 0L; - acquire_more_worker(diff, succ_num); - // acquire_count is the number of fail workers. - ass_token_cnt_ += succ_num; - } else if (diff < 0 && w.get_tidx() > 1) { - // tidx == 0 ==> process_high_prio_task() - // tidx == 1 ==> process_high_high_prio_task() - // - // These two workers mustn't be set inactive, since there may be - // no available workers process there types of task. - ass_token_cnt_--; - ret = OB_NEED_WAIT; - if (w.has_lq_token()) { - release_lq_token(); - } - w.set_lq_token(false); - w.set_inactive(); - if (cgroup_ctrl_.is_valid() - && OB_SUCCESS != (tmp_ret = cgroup_ctrl_.remove_thread_from_cgroup(w.get_tid(), id_))) { - LOG_WARN("remove thread from cgroup failed", K(tmp_ret), K_(id)); + if (token_cnt_ < workers_.get_size() && w.is_default_worker()) { + w.stop(); + ATOMIC_INC(&token_cnt_); + ATOMIC_STORE(&token_change_ts_, now); + if (cgroup_ctrl_.is_valid() && OB_FAIL(cgroup_ctrl_.remove_thread_from_cgroup(w.get_tid(), id_))) { + LOG_WARN("remove thread from cgroup failed", K(ret), K_(id)); } } IGNORE_RETURN workers_lock_.unlock(); - } else { - ret = OB_EAGAIN; } - return ret; } int ObTenant::acquire_level_worker(int64_t num, int64_t &succ_num, int32_t level) { int ret = OB_SUCCESS; - int tmp_ret = OB_SUCCESS; ObTenantSwitchGuard guard(this); const auto need_num = num; @@ -1628,25 +1382,15 @@ int ObTenant::acquire_level_worker(int64_t num, int64_t &succ_num, int32_t level LOG_ERROR("unexpected level", K(level), K(id_)); } else { while (OB_SUCC(ret) && need_num > succ_num) { - ObThWorker *w = worker_pool_.alloc(); - if (w) { - w->reset(); - w->set_tidx(nesting_workers_.get_size() + 1000); - w->set_worker_level(level); - w->set_tenant(this); - w->set_group_id(0); - if (OB_FAIL(w->start())) { - LOG_ERROR("worker start failed", K(ret)); - } else if (FALSE_IT(w->activate())) { - } else if (!nesting_workers_.add_last(&w->worker_node_)) { - OB_ASSERT(false); - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("add worker to list fail", K(ret)); - } else { - succ_num++; - } + ObThWorker *w = nullptr; + if (OB_FAIL(create_worker(w, this, 0, level))) { + LOG_ERROR("create worker failed", K(ret)); + } else if (!nesting_workers_.add_last(&w->worker_node_)) { + OB_ASSERT(false); + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("add worker to list fail", K(ret)); } else { - ret = OB_SIZE_OVERFLOW; + succ_num++; } } } @@ -1666,208 +1410,67 @@ int ObTenant::acquire_level_worker(int64_t num, int64_t &succ_num, int32_t level int ObTenant::acquire_more_worker(int64_t num, int64_t &succ_num) { int ret = OB_SUCCESS; - int tmp_ret = OB_SUCCESS; - const auto bound = worker_count_bound(); - const auto current = workers_.get_size(); - const auto need_num = std::min(num, bound - current); succ_num = 0; - // If tenant has inactive workers, wake up them first. - DLIST_FOREACH_X(wnode, workers_, need_num > succ_num) { - const auto w = static_cast(wnode->get_data()); - if (!w->is_active()) { - w->activate(); - succ_num++; - } - } - ObTenantSwitchGuard guard(this); - while (OB_SUCC(ret) && need_num > succ_num) { - ObThWorker *w = worker_pool_.alloc(); - if (w) { - w->reset(); - w->set_tidx(workers_.get_size()); - w->set_worker_level(0); - w->set_tenant(this); - w->set_group_id(0); - if (OB_FAIL(w->start())) { - LOG_ERROR("worker start failed", K(ret)); - } else if (FALSE_IT(w->activate())) { - // do nothing - } else if (!workers_.add_last(&w->worker_node_)) { - OB_ASSERT(false); - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("add worker to list fail", K(ret)); - } else { - succ_num++; - } + while (OB_SUCC(ret) && num > succ_num) { + ObThWorker *w = nullptr; + if (OB_FAIL(create_worker(w, this, 0, 0))) { + LOG_ERROR("create worker failed", K(ret)); + } else if (!workers_.add_last(&w->worker_node_)) { + OB_ASSERT(false); + ret = OB_ERR_UNEXPECTED; + LOG_ERROR("add worker to list fail", K(ret)); } else { - ret = OB_SIZE_OVERFLOW; - } - } - - if (need_num != num || // Reach worker count bound, - succ_num != need_num // or can't allocate enough worker. - ) { - if (TC_REACH_TIME_INTERVAL(10000000)) { - LOG_WARN("Alloc worker less than lack", K(num), K(need_num), K(succ_num)); + succ_num++; } } return ret; } -int ObTenant::link_worker(Worker &w) +void ObTenant::lq_end(ObThWorker &w) { - return workers_.add_last(&w.worker_node_); -} -void ObTenant::unlink_worker(Worker &w) -{ - workers_.remove(&w.worker_node_); -} -int ObTenant::link_lq_waiting_worker(Worker &w) -{ - return lq_waiting_workers_.add_last(&w.lq_waiting_worker_node_); -} -void ObTenant::unlink_lq_waiting_worker(Worker &w) -{ - lq_waiting_workers_.remove(&w.lq_waiting_worker_node_); -} - -void ObTenant::try_unlink_lq_waiting_worker_with_lock(Worker &w) -{ - if (w.lq_waiting_worker_node_.get_next() != nullptr) { - ObMutexGuard guard(lq_waiting_workers_lock_); - if (w.lq_waiting_worker_node_.get_next() != nullptr) { - unlink_lq_waiting_worker(w); - } - } -} - -// Called by worker self. -void ObTenant::check_paused_worker(ObThWorker &w) -{ - // Check whether there are waiting large queries and large query token is - // enough, if so wake up that query. - const auto lq_waitings = lq_waiting_workers_.get_size(); - // Only normal priority workers can wakeup awaiting LQ workers. - // Worker with tidx == 0/1 only process high priority tasks. - if (lq_waitings > 0 && w.get_tidx() > 1 && w.is_active()) { - if (w.has_lq_token() || acquire_lq_token()) { - w.set_lq_token(true); - } - if (w.has_lq_token() || req_queue_.size() == 0) { - ObMutexGuard guard(lq_waiting_workers_lock_); - auto *node = lq_waiting_workers_.remove_first(); - if (nullptr != node) { - OB_ASSERT(node->get_data()); - auto &nw = *static_cast(node->get_data()); - nw.set_lq_token(w.has_lq_token()); - resume_it(nw); - // LQT is transfer to the waked up worker, so just flag no LQT - // for current worker. - w.set_lq_token(false); - w.set_inactive(); - } else { - // lq_token would preserved if this worker has so that worker - // will prefer to process large query rather than normal - // query. - } - } - } -} - -// called each checkpoint for worker of this tenant. -int ObTenant::lq_check_status(ObThWorker &w) -{ - // Only normal priority workers take part in schedule. - if (w.get_tidx() <= 1) { - // High priority workers - if (!w.has_lq_token()) { - if (acquire_lq_token()) { - w.set_lq_token(); - } - } - } else { - ATOMIC_INC(&tt_large_quries_); - - bool has_newborn = false; // has newborn worker? - bool has_waiting_workers = lq_waiting_workers_.get_size() > 0; - - if (!w.has_lq_token() && !acquire_lq_token()) { - // Exceeds lq_token count. - // - // It's allowed to execute a large query even though it doesn't - // own a lq_token if there's no normal request waiting for. - if (get_request_queue_length() > 0) { - const int64_t cnt = 1; - int64_t succ_cnt = 0; - ObMutexGuard guard(workers_lock_); - acquire_more_worker(cnt, succ_cnt); - if (succ_cnt > 0) { - has_newborn = true; - } - } + int ret = OB_SUCCESS; + if (w.is_lq_yield()) { + if (OB_FAIL(cgroup_ctrl_.add_thread_to_cgroup(w.get_tid(), id_, w.get_group_id()))) { + LOG_WARN("move thread from lq group failed", K(ret), K(id_)); } else { - w.set_lq_token(); - } - - // If there isn't another newborn worker being woken up, then - // has_newborn would set false and we need ensure tenant has enough - // worker processes its requests. It has two situations. - // - // 1. lq_token hasn't been acquired and no new worker available. - // 2. lq_token has been acquired. - // - // Under either condition, we should choose a LARGE QUERY worker to - // run. The oldest waiting worker will be woken up, or current one - // if there's no waiting worker. - if (w.has_lq_token()) { // worker has lq token, allow to execute - } else if (has_newborn) { // Execution token has transferred a - // newborn worker. - ObMutexGuard guard(lq_waiting_workers_lock_); - link_lq_waiting_worker(w); - pause_it(w); - } else if (has_waiting_workers) { // No newborn worker but has - // waiting workers. - ObMutexGuard guard(lq_waiting_workers_lock_); - auto *node = lq_waiting_workers_.remove_first(); - if (nullptr != node) { - auto &nw = *static_cast(node->get_data()); - nw.set_lq_token(w.has_lq_token()); - resume_it(nw); - w.set_lq_token(false); - pause_it(w); - link_lq_waiting_worker(w); - has_newborn = true; - } - } else { // no lq token and no newborn worker and no waiting - // workers, allow to execute + w.set_lq_yield(false); } } - return w.is_active() ? OB_EAGAIN : OB_SUCCESS; } -bool ObTenant::has_task() const +void ObTenant::lq_wait(ObThWorker &w) { - bool result = false; - if (!result) { - result = req_queue_.size() > 0 || - large_req_queue_.size() > 0 || - lq_waiting_workers_.get_size() > 0; + int64_t last_query_us = ObTimeUtility::current_time() - w.get_last_wakeup_ts(); + int64_t lq_group_worker_cnt = w.get_group()->get_token_cnt(); + int64_t unit_min_cpu = unit_min_cpu_; + double large_query_percentage = GCONF.large_query_worker_percentage / 100.0; + int64_t wait_us = static_cast(last_query_us * lq_group_worker_cnt / + (unit_min_cpu * large_query_percentage) - + last_query_us); + wait_us = std::min(wait_us, min(100 * 1000, w.get_timeout_remain())); + if (wait_us > 10 * 1000) { + usleep(wait_us); + w.set_last_wakeup_ts(ObTimeUtility::current_time()); } - return result; } -int64_t ObTenant::get_request_queue_length() const +int ObTenant::lq_yield(ObThWorker &w) { - return req_queue_.size(); -} - -int64_t ObTenant::waiting_count() const -{ - // TODO: add waiting workers with paused task. - return req_queue_.size(); + int ret = OB_SUCCESS; + ATOMIC_INC(&tt_large_quries_); + if (!cgroup_ctrl_.is_valid() && w.get_group_id() == share::OBCG_LQ) { + lq_wait(w); + } else if (w.is_lq_yield()) { + // avoid duplicate change group + } else if (OB_FAIL(cgroup_ctrl_.add_thread_to_cgroup(w.get_tid(), id_, OBCG_LQ))) { + LOG_WARN("move thread to lq group failed", K(ret), K(id_)); + } else { + w.set_lq_yield(); + } + return ret; } // thread unsafe @@ -1878,8 +1481,6 @@ void ObTenant::update_token_usage() if (duration > 1000 * 1000) { // every second token_usage_check_ts_ = now; const auto idle_us = static_cast(ATOMIC_TAS(&idle_us_, 0)); - const auto tokens = static_cast(token_cnt()); - int group_worker_cnt = 0; ObResourceGroupNode* iter = NULL; ObResourceGroup* group = nullptr; @@ -1887,9 +1488,7 @@ void ObTenant::update_token_usage() group = static_cast(iter); group_worker_cnt += group->workers_.get_size(); } - - const auto total_us = duration * (tokens + group_worker_cnt + - nesting_worker_has_init_ - 1); + const auto total_us = duration * total_worker_cnt_; token_usage_ = (total_us - idle_us) / duration; token_usage_ = std::max(.0, token_usage_); } diff --git a/src/observer/omt/ob_tenant.h b/src/observer/omt/ob_tenant.h index 75e9b9be7..41b5c00fe 100644 --- a/src/observer/omt/ob_tenant.h +++ b/src/observer/omt/ob_tenant.h @@ -30,7 +30,6 @@ #include "share/rc/ob_tenant_base.h" #include "share/rc/ob_context.h" #include "observer/omt/ob_th_worker.h" -#include "observer/omt/ob_worker_pool.h" #include "observer/omt/ob_multi_level_queue.h" #include "ob_retry_queue.h" #include "lib/utility/ob_query_rate_limiter.h" @@ -197,7 +196,6 @@ struct ObSqlThrottleMetrics // Forward declarations class ObThWorker; -using lib::Worker; // Type aliases typedef common::ObDLinkNode WorkerNode; @@ -267,24 +265,17 @@ class ObResourceGroup : public ObResourceGroupNode // group container, storing t public: using WListNode = common::ObDLinkNode; using WList = common::ObDList; - enum { CALIBRATE_TOKEN_INTERVAL = 100 * 1000 }; static constexpr int64_t PRESERVE_INACTIVE_WORKER_TIME = 10 * 1000L * 1000L; - ObResourceGroup(int32_t group_id, ObTenant *tenant, ObWorkerPool *worker_pool, share::ObCgroupCtrl *cgroup_ctrl): + ObResourceGroup(int32_t group_id, ObTenant *tenant, share::ObCgroupCtrl *cgroup_ctrl): ObResourceGroupNode(group_id), workers_lock_(common::ObLatchIds::TENANT_WORKER_LOCK), inited_(false), recv_req_cnt_(0), - pop_req_cnt_(0), token_cnt_(0), - ass_token_cnt_(0), - min_token_cnt_(0), - max_token_cnt_(0), - last_calibrate_token_ts_(0), + token_change_ts_(0), tenant_(tenant), - worker_pool_(worker_pool), - cgroup_ctrl_(cgroup_ctrl), - has_stop_(false) + cgroup_ctrl_(cgroup_ctrl) { } ~ObResourceGroup() {} @@ -292,25 +283,16 @@ public: bool is_inited() const { return inited_; } void atomic_inc_recv_cnt() { ATOMIC_INC(&recv_req_cnt_); } uint64_t get_recv_req_cnt() const { return recv_req_cnt_; } - void atomic_inc_pop_cnt() { ATOMIC_INC(&pop_req_cnt_); } - uint64_t get_pop_req_cnt() const { return pop_req_cnt_; } - int64_t get_token_cnt() const { return token_cnt_; } - void set_token_cnt(const int64_t token_cnt) { token_cnt_ = token_cnt; }; - int64_t get_ass_token_cnt() const { return ass_token_cnt_; } - void set_ass_token_cnt(const int64_t ass_token_cnt) { ass_token_cnt_ = ass_token_cnt; } - int64_t get_min_token_cnt() const { return min_token_cnt_; } - void set_min_token_cnt(const int64_t min_token_cnt) { min_token_cnt_ = min_token_cnt; } - int64_t get_max_token_cnt() const { return max_token_cnt_; } - void set_max_token_cnt(const int64_t max_token_cnt) { max_token_cnt_ = max_token_cnt; } + int64_t min_worker_cnt() const; + int64_t max_worker_cnt() const; + int64_t get_token_cnt() { return token_cnt_; } ObTenant *get_tenant() { return tenant_; } - ObWorkerPool *get_worker_pool() { return worker_pool_; } share::ObCgroupCtrl *get_cgroup_ctrl() { return cgroup_ctrl_; } int init(); void update_queue_size(); int acquire_more_worker(int64_t num, int64_t &succ_num); - void calibrate_token_count(); void check_worker_count(); void check_worker_count(ObThWorker &w); int clear_worker(); @@ -322,22 +304,13 @@ protected: common::ObPriorityQueue2<0, 1> req_queue_; private: - bool inited_; // Mark whether the container has threads and queues allocated - - volatile uint64_t recv_req_cnt_; // Statistics requested to enqueue - volatile uint64_t pop_req_cnt_; // Statistics of Dequeue Requests - volatile uint64_t last_pop_req_cnt_; // Statistics of the request to leave the team the last time the token was dynamically adjusted - - int64_t token_cnt_; // The current number of target threads - int64_t ass_token_cnt_; // The number of threads actually allocated - int64_t min_token_cnt_; // Initial target number of threads - int64_t max_token_cnt_; // Max target number of threads - int64_t last_calibrate_token_ts_; // The timestamp of the last time the token was dynamically adjusted + bool inited_; // Mark whether the container has threads and queues allocated + volatile uint64_t recv_req_cnt_ CACHE_ALIGNED; // Statistics requested to enqueue + int64_t token_cnt_ CACHE_ALIGNED; // The current number of target threads + int64_t token_change_ts_ CACHE_ALIGNED; // when there is continus req_queue.count > token_cnt, shrink worker ObTenant *tenant_; - ObWorkerPool *worker_pool_; share::ObCgroupCtrl *cgroup_ctrl_; - bool has_stop_; }; typedef common::FixedHash2 GroupHash; @@ -349,7 +322,7 @@ public: { } ~GroupMap() {} - int create_and_insert_group(int32_t group_id, ObTenant *tenant, ObWorkerPool *worker_pool, share::ObCgroupCtrl *cgroup_ctrl, ObResourceGroup *&group); + int create_and_insert_group(int32_t group_id, ObTenant *tenant, share::ObCgroupCtrl *cgroup_ctrl, ObResourceGroup *&group); void wait_group(); void destroy_group(); int64_t to_string(char *buf, const int64_t buf_len) const @@ -363,22 +336,23 @@ public: "group_id = %d," "queue_size = %ld," "recv_req_cnt = %lu," - "pop_req_cnt = %lu," "token_cnt = %ld," - "min_token_cnt = %ld," - "max_token_cnt = %ld," - "ass_token_cnt = %ld ", + "min_worker_cnt = %ld," + "max_worker_cnt = %ld," + "worker_cnt = %d," + "token_change = %ld ", group->group_id_, group->req_queue_.size(), group->recv_req_cnt_, - group->pop_req_cnt_, group->token_cnt_, - group->min_token_cnt_, - group->max_token_cnt_, - group->ass_token_cnt_); + group->min_worker_cnt(), + group->max_worker_cnt(), + group->workers_.get_size(), + group->token_change_ts_); } return pos; } + static int err_code_map(int err); }; class RpcStatInfo @@ -401,21 +375,17 @@ class ObTenant : public share::ObTenantBase { friend class observer::ObAllVirtualDumpTenantInfo; friend int ::select_dump_tenant_info(lua_State*); + friend int create_worker(ObThWorker* &worker, ObTenant *tenant, int32_t group_id, + int32_t level, ObResourceGroup *group); + friend int destroy_worker(ObThWorker *worker); using WListNode = common::ObDLinkNode; using WList = common::ObDList; // How long to preserve inactive worker before free it to worker // pool. static constexpr int64_t PRESERVE_INACTIVE_WORKER_TIME = 10 * 1000L * 1000L; - enum { CALIBRATE_WORKER_INTERVAL = 30 * 1000 * 1000 }; - enum { CALIBRATE_TOKEN_INTERVAL = 100 * 1000 }; public: - // Quick Queue Priorities - enum { QQ_HIGH = 0, QQ_PRIOR_TO_NORMAL, QQ_NORMAL, QQ_MAX_PRIO }; - // Request queue priorities - enum { RQ_HIGH = QQ_MAX_PRIO, RQ_NORMAL, RQ_LOW, RQ_MAX_PRIO }; - enum { MAX_RESOURCE_GROUP = 8 }; ObTenant(const int64_t id, @@ -429,11 +399,10 @@ public: int init_ctx(); int init(const ObTenantMeta &meta); - void set_stop(const bool is_stop); - void stop(); + void stop() { ATOMIC_STORE(&stopped_, true); } void wait(); void destroy(); - bool has_stopped() const; + bool has_stopped() const { return ATOMIC_LOAD(&stopped_); } ObTenantMeta get_tenant_meta(); bool is_hidden(); @@ -445,7 +414,6 @@ public: share::ObUnitInfoGetter::ObTenantConfig get_unit(); uint64_t get_unit_id(); storage::ObTenantSuperBlock get_super_block(); - void set_tenant_meta(const ObTenantMeta &meta); void set_tenant_unit(const share::ObUnitInfoGetter::ObTenantConfig &unit); void set_tenant_super_block(const storage::ObTenantSuperBlock &super_block); void mark_tenant_is_removed(); @@ -453,55 +421,42 @@ public: share::ObUnitInfoGetter::ObUnitStatus get_unit_status(); void set_unit_max_cpu(double cpu); - double unit_max_cpu() const; + OB_INLINE double unit_max_cpu() const { return unit_max_cpu_; } void set_unit_min_cpu(double cpu); - double unit_min_cpu() const; - void set_token(const int64_t token); - void set_sug_token(const int64_t token); - int64_t token_cnt() const; - int64_t sug_token_cnt() const; + OB_INLINE double unit_min_cpu() const { return unit_min_cpu_; } + OB_INLINE int64_t total_worker_cnt() const { return total_worker_cnt_; } + int64_t min_worker_cnt() const; + int64_t max_worker_cnt() const; lib::Worker::CompatMode get_compat_mode() const; - share::ObTenantSpace &ctx(); - - void add_idle_time(int64_t idle_time); - void add_worker_time(int64_t req_time); + OB_INLINE share::ObTenantSpace &ctx() { return *ctx_; } + OB_INLINE void add_idle_time(int64_t idle_time) { IGNORE_RETURN ATOMIC_FAA(reinterpret_cast(&idle_us_), idle_time); } + OB_INLINE void add_worker_time(int64_t req_time) { IGNORE_RETURN ATOMIC_FAA(reinterpret_cast(&worker_us_), req_time); } int rdlock(common::ObLDHandle &handle); int wrlock(common::ObLDHandle &handle); int try_rdlock(common::ObLDHandle &handle); int try_wrlock(common::ObLDHandle &handle); virtual int unlock(common::ObLDHandle &handle) override; - bool has_task() const; - virtual int64_t waiting_count() const; - int64_t get_request_queue_length() const; - // get request from request queue, waiting at most TIMEOUT us. // if IN_HIGH_PRIORITY is set, get request from hp queue. - int get_new_request( - ObThWorker &w, - int64_t timeout, - rpc::ObRequest *&req); + int get_new_request(ObThWorker &w, int64_t timeout, rpc::ObRequest *&req); // receive request from network int recv_request(rpc::ObRequest &req); int recv_large_request(rpc::ObRequest &req); int push_retry_queue(rpc::ObRequest &req, const uint64_t idx); void handle_retry_req(); + void check_worker_count(ObThWorker &w); void update_queue_size(); - void calibrate_token_count(); - void calibrate_group_token_count(); - void calibrate_worker_count(); int timeup(); TO_STRING_KV(K_(id), K_(tenant_meta), - K_(unit_min_cpu), K_(unit_max_cpu), K_(slice), - K_(slice_remain), K_(token_cnt), K_(sug_token_cnt), - K_(ass_token_cnt), - K_(lq_tokens), - K_(used_lq_tokens), + K_(unit_min_cpu), K_(unit_max_cpu), K_(token_cnt), K_(total_worker_cnt), + "min_worker_cnt", min_worker_cnt(), + "max_worker_cnt", max_worker_cnt(), K_(stopped), K_(idle_us), K_(recv_hp_rpc_cnt), K_(recv_np_rpc_cnt), K_(recv_lp_rpc_cnt), K_(recv_mysql_cnt), @@ -509,49 +464,29 @@ public: K_(recv_large_req_cnt), K_(tt_large_quries), K_(pop_normal_cnt), - K_(actives), "workers", workers_.get_size(), "nesting workers", nesting_workers_.get_size(), - "lq waiting workers", lq_waiting_workers_.get_size(), K_(req_queue), - "large queued", large_req_queue_.size(), K_(multi_level_queue), K_(recv_level_rpc_cnt), K_(group_map), - K_(rpc_stat_info)) + K_(rpc_stat_info), + K_(token_change_ts)) public: static bool equal(const ObTenant *t1, const ObTenant *t2) { return (!OB_ISNULL(t1) && !OB_ISNULL(t2) && t1->id_ == t2->id_); } - // update CPU usage - void update_token_usage(); - - // acquire workers if tenant doesn't have sufficient worker. - int check_worker_count(); - int check_worker_count(ObThWorker &w); - int check_group_worker_count(); - - // Check if there's paused worker need be woken up. - // - // If paused worker has been woken up, current worker would be set - // to inactive and unlink from its queues. - void check_paused_worker(ObThWorker &w); - - int link_worker(lib::Worker &w); - void unlink_worker(lib::Worker &w); - int link_lq_waiting_worker(lib::Worker &w); - void unlink_lq_waiting_worker(lib::Worker &w); - void try_unlink_lq_waiting_worker_with_lock(lib::Worker &w); - + void lq_end(ObThWorker &w); // called each checkpoint for worker of this tenant. - int lq_check_status(ObThWorker &w); + void lq_wait(ObThWorker &w); + int lq_yield(ObThWorker &w); - void disable_user_sched(); - bool user_sched_enabled() const; - double get_token_usage() const; - int64_t get_worker_time() const; + OB_INLINE void disable_user_sched() { disable_user_sched_ = true; } + OB_INLINE bool user_sched_enabled() const { return !disable_user_sched_; } + OB_INLINE double get_token_usage() const { return token_usage_; } + OB_INLINE int64_t get_worker_time() const { return ATOMIC_LOAD(&worker_us_); } // sql throttle void update_sql_throttle_metrics(const ObSqlThrottleMetrics &metrics) { st_metrics_ = metrics; } @@ -572,20 +507,26 @@ public: // Node balance thread would periodically check tenant status by // calling this function. void periodically_check(); - + int64_t lq_retry_queue_size() + { + return 0; + } private: + // update CPU usage + void update_token_usage(); + // acquire workers if tenant doesn't have sufficient worker. + void check_worker_count(); + void check_group_worker_count(); // alloc NUM worker int acquire_level_worker(int64_t num, int64_t &succ_num, int32_t level); int acquire_more_worker(int64_t num, int64_t &succ_num); - bool acquire_lq_token(); - void release_lq_token(); - int64_t worker_count_bound() const; + int64_t worker_count() const { return workers_.get_size(); } inline void pause_it(ObThWorker &w); inline void resume_it(ObThWorker &w); - int pop_req(common::ObLink *&req, int64_t timeout); + OB_INLINE int pop_req(common::ObLink *&req, int64_t timeout) { return req_queue_.pop(req, timeout); } // read tenant variable PARALLEL_SERVERS_TARGET void check_parallel_servers_target(); @@ -599,39 +540,22 @@ private: int construct_mtl_init_ctx(const ObTenantMeta &meta, share::ObTenantModuleInitCtx *&ctx); + int recv_group_request(rpc::ObRequest &req, int64_t group_id); + protected: mutable common::TCRWLock meta_lock_; ObTenantMeta tenant_meta_; protected: - // times of workers of cpu slice this tenant can alloc. - const int64_t times_of_workers_; // max/min cpu read from unit double unit_max_cpu_; double unit_min_cpu_; - // tenant slice, it is calculated by quota. The slice is the average - // number of token a tenant can get in every 10ms. - double slice_; - // tenant slice remains, will reset every 10s. - double slice_remain_; - // locker for update slice remain - common::ObSpinLock slice_remain_lock_; - // if set, reset slice remain before add. - bool slice_remain_clear_flag_; - // number of active workers the tenant has owned. Only active // workers can make progress. - int64_t sug_token_cnt_; - int64_t token_cnt_; - int64_t ass_token_cnt_; - int64_t lq_tokens_; - int64_t used_lq_tokens_; - int64_t last_calibrate_worker_ts_; - int64_t last_calibrate_token_ts_; - int64_t last_pop_normal_cnt_; - int nesting_worker_has_init_; + int64_t token_cnt_ CACHE_ALIGNED; + int64_t total_worker_cnt_ CACHE_ALIGNED; bool stopped_; bool wait_mtl_finished_; @@ -639,7 +563,6 @@ protected: /// tenant task queue, // 'hp' for high priority and 'np' for normal priority common::ObPriorityQueue2<1, QQ_MAX_PRIO - 1, RQ_MAX_PRIO - QQ_MAX_PRIO> req_queue_; - common::ObLinkQueue large_req_queue_; //Create a request queue for each level of nested requests ObMultiLevelQueue *multi_level_queue_; @@ -659,13 +582,9 @@ protected: volatile uint64_t resume_cnt_; volatile uint64_t recv_retry_on_lock_rpc_cnt_; volatile uint64_t recv_retry_on_lock_mysql_cnt_; - volatile uint64_t actives_; volatile uint64_t tt_large_quries_; volatile uint64_t pop_normal_cnt_; - // free worker pool - ObWorkerPool worker_pool_; - private: GroupMap group_map_; // for group_map hash node @@ -676,13 +595,11 @@ public: // Variables for V2 WList workers_; - WList lq_waiting_workers_; WList nesting_workers_; RpcStatInfo *rpc_stat_info_; share::ObTenantModuleInitCtx *mtl_init_ctx_; lib::ObMutex workers_lock_; - lib::ObMutex lq_waiting_workers_lock_; share::ObCgroupCtrl &cgroup_ctrl_; @@ -690,59 +607,34 @@ public: double token_usage_; int64_t token_usage_check_ts_; - bool dynamic_modify_token_; - bool dynamic_modify_group_token_; + int64_t token_change_ts_ CACHE_ALIGNED; share::ObTenantSpace *ctx_; - bool px_pool_is_running_; ObSqlThrottleMetrics st_metrics_; lib::ObQueryRateLimiter sql_limiter_; // idle time between two checkpoints int64_t worker_us_ CACHE_ALIGNED; int64_t idle_us_ CACHE_ALIGNED; - }; // end of class ObTenant -inline bool ObTenant::has_stopped() const +OB_INLINE int64_t ObResourceGroup::min_worker_cnt() const { - return ATOMIC_LOAD(&stopped_); + const uint64_t worker_concurrency = share::ObCgSet::instance().get_worker_concurrency(group_id_); + int64_t cnt = worker_concurrency * (int64_t)ceil(tenant_->unit_min_cpu()); + return (share::OBCG_CLOG == group_id_ || share::OBCG_LQ == group_id_) ? std::max(cnt, 8L) : cnt; } -inline double ObTenant::unit_max_cpu() const +OB_INLINE int64_t ObResourceGroup::max_worker_cnt() const { - return unit_max_cpu_; -} - -inline double ObTenant::unit_min_cpu() const -{ - return unit_min_cpu_; -} - - -inline share::ObTenantSpace &ObTenant::ctx() -{ - return *ctx_; -} - -inline int64_t ObTenant::token_cnt() const -{ - return token_cnt_; -} - -inline int64_t ObTenant::sug_token_cnt() const -{ - return sug_token_cnt_; -} - -inline void ObTenant::add_idle_time(int64_t idle_time) -{ - (void)ATOMIC_FAA(reinterpret_cast(&idle_us_), idle_time); -} - -inline void ObTenant::add_worker_time(int64_t req_time) -{ - (void)ATOMIC_FAA(reinterpret_cast(&worker_us_), req_time); + const uint64_t worker_concurrency = share::ObCgSet::instance().get_worker_concurrency(group_id_); + int64_t cnt = worker_concurrency * (int64_t)ceil(tenant_->unit_max_cpu()); + if (share::OBCG_CLOG == group_id_) { + cnt = std::max(cnt, 8L); + } else if (share::OBCG_LQ == group_id_) { + cnt = std::max(cnt, tenant_->max_worker_cnt()); + } + return cnt; } inline void ObTenant::pause_it(ObThWorker &w) @@ -757,11 +649,6 @@ inline void ObTenant::resume_it(ObThWorker &w) w.resume(); } -OB_INLINE int ObTenant::pop_req(common::ObLink *&req, int64_t timeout) -{ - return req_queue_.pop(req, timeout); -} - inline int ObTenant::rdlock(common::ObLDHandle &handle) { return lock_.rdlock(handle, common::ObLatchIds::TENANT_LOCK) == common::OB_SUCCESS @@ -800,42 +687,6 @@ inline int ObTenant::unlock(common::ObLDHandle &handle) : common::OB_EAGAIN; } -inline void ObTenant::disable_user_sched() -{ - disable_user_sched_ = true; -} - -inline bool ObTenant::user_sched_enabled() const -{ - return !disable_user_sched_; -} - -inline double ObTenant::get_token_usage() const -{ - return token_usage_; -} - -inline int64_t ObTenant::get_worker_time() const -{ - return ATOMIC_LOAD(&worker_us_); -} - -inline bool ObTenant::acquire_lq_token() -{ - bool succ = true; - const auto v = ATOMIC_FAA(&used_lq_tokens_, 1); - if (v >= lq_tokens_) { - ATOMIC_DEC(&used_lq_tokens_); - succ = false; - } - return succ; -} - -inline void ObTenant::release_lq_token() -{ - ATOMIC_DEC(&used_lq_tokens_); -} - } // end of namespace omt } // end of namespace oceanbase diff --git a/src/observer/omt/ob_tenant_hook.cpp b/src/observer/omt/ob_tenant_hook.cpp new file mode 100644 index 000000000..1bac8e051 --- /dev/null +++ b/src/observer/omt/ob_tenant_hook.cpp @@ -0,0 +1,182 @@ +#ifndef _OCEABASE_TENANT_PRELOAD_H_ +#define _OCEABASE_TENANT_PRELOAD_H_ + +#ifndef PERF_MODE +#define _GNU_SOURCE 1 +#include "ob_tenant.h" +#include "observer/ob_server_struct.h" +#include "observer/omt/ob_multi_tenant.h" +#include "lib/worker.h" +#include "share/ob_define.h" +#include + +#define SYS_HOOK(func_name, ...) \ + ({ \ + int ret = 0; \ + oceanbase::omt::ObTenant *tenant = NULL; \ + if (!in_sys_hook++ && OB_NOT_NULL(oceanbase::lib::Worker::self_)) { \ + oceanbase::lib::Worker::self_->set_is_blocking(true); \ + ret = real_##func_name(__VA_ARGS__); \ + oceanbase::lib::Worker::self_->set_is_blocking(false); \ + } else { \ + ret = real_##func_name(__VA_ARGS__); \ + } \ + in_sys_hook--; \ + ret; \ + }) + +namespace oceanbase { +namespace omt { +thread_local int in_sys_hook = 0; +} +} + +using namespace oceanbase; +using namespace omt; + +extern "C" { + +ObTenant *sys_hook_get_tenant() +{ + ObTenant *tenant = NULL; + uint64_t tenant_id = 0; + if ((tenant_id = GET_TENANT_ID()) != 0 && OB_NOT_NULL(GCTX.omt_)) { + GCTX.omt_->get_tenant(tenant_id, tenant); + } + return tenant; +} + +int pthread_mutex_lock(pthread_mutex_t *__mutex) +{ + static int (*real_pthread_mutex_lock)(pthread_mutex_t * __mutex) = + (typeof(real_pthread_mutex_lock))dlsym(RTLD_NEXT, + "pthread_mutex_lock"); + int ret = 0; + ret = SYS_HOOK(pthread_mutex_lock, __mutex); + return ret; +} + +int pthread_mutex_timedlock(pthread_mutex_t *__restrict __mutex, + const struct timespec *__restrict __abstime) +{ + static int (*real_pthread_mutex_timedlock)( + pthread_mutex_t *__restrict __mutex, + const struct timespec *__restrict __abstime) = + (typeof(real_pthread_mutex_timedlock))dlsym(RTLD_NEXT, + "pthread_mutex_timedlock"); + int ret = 0; + ret = SYS_HOOK(pthread_mutex_timedlock, __mutex, __abstime); + return ret; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock) +{ + static int (*real_pthread_rwlock_rdlock)(pthread_rwlock_t * __rwlock) = + (typeof(real_pthread_rwlock_rdlock))dlsym(RTLD_NEXT, + "pthread_rwlock_rdlock"); + int ret = 0; + ret = SYS_HOOK(pthread_rwlock_rdlock, __rwlock); + return ret; +} + +#ifdef __USE_XOPEN2K +int pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict __rwlock, + const struct timespec *__restrict __abstime) +{ + static int (*real_pthread_rwlock_timedrdlock)( + pthread_rwlock_t *__restrict __rwlock, + const struct timespec *__restrict __abstime) = + (typeof(real_pthread_rwlock_timedrdlock))dlsym( + RTLD_NEXT, "pthread_rwlock_timedrdlock"); + int ret = 0; + ret = SYS_HOOK(pthread_rwlock_timedrdlock, __rwlock, __abstime); + return ret; +} +#endif + +int pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock) +{ + static int (*real_pthread_rwlock_wrlock)(pthread_rwlock_t * __rwlock) = + (typeof(real_pthread_rwlock_wrlock))dlsym(RTLD_NEXT, + "pthread_rwlock_wrlock"); + int ret = 0; + ret = SYS_HOOK(pthread_rwlock_wrlock, __rwlock); + return ret; +} + +#ifdef __USE_XOPEN2K +int pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict __rwlock, + const struct timespec *__restrict __abstime) +{ + static int (*real_pthread_rwlock_timedwrlock)( + pthread_rwlock_t *__restrict __rwlock, + const struct timespec *__restrict __abstime) = + (typeof(real_pthread_rwlock_timedwrlock))dlsym( + RTLD_NEXT, "pthread_rwlock_timedwrlock"); + int ret = 0; + ret = SYS_HOOK(pthread_rwlock_timedwrlock, __rwlock, __abstime); + return ret; +} +#endif + +// objdump -t /lib64/libpthread.so.0 | grep pthread_cond_wait +#if defined(__x86_64__) + #define __PTHREAD_COND_WAIT_GLIBC_VERSION "GLIBC_2.3.2" +#elif defined(__aarch64__) + #define __PTHREAD_COND_WAIT_GLIBC_VERSION "GLIBC_2.17" +#else + #error arch unsupported +#endif + +int pthread_cond_wait(pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex) +{ + static int (*real_pthread_cond_wait)(pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex) = + (typeof(real_pthread_cond_wait))dlvsym(RTLD_NEXT, "pthread_cond_wait", + __PTHREAD_COND_WAIT_GLIBC_VERSION); + int ret = 0; + ret = SYS_HOOK(pthread_cond_wait, __cond, __mutex); + return ret; +} + +// objdump -t /lib64/libpthread.so.0 | grep pthread_cond_timedwait +#if defined(__x86_64__) + #define __PTHREAD_COND_TIMEDWAIT_GLIBC_VERSION "GLIBC_2.3.2" +#elif defined(__aarch64__) + #define __PTHREAD_COND_TIMEDWAIT_GLIBC_VERSION "GLIBC_2.17" +#else + #error arch unsupported +#endif + +int pthread_cond_timedwait(pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex, + const struct timespec *__restrict __abstime) +{ + static int (*real_pthread_cond_timedwait)( + pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex, + const struct timespec *__restrict __abstime) = + (typeof(real_pthread_cond_timedwait))dlvsym( + RTLD_NEXT, "pthread_cond_timedwait", __PTHREAD_COND_TIMEDWAIT_GLIBC_VERSION); + int ret = 0; + ret = SYS_HOOK(pthread_cond_timedwait, __cond, __mutex, __abstime); + return ret; +} + +int futex_hook(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec* timeout) +{ + static long int (*real_syscall)(long int __sysno, ...) = + (typeof(real_syscall))dlsym(RTLD_NEXT, "syscall"); + int ret = 0; + if (futex_op == FUTEX_WAIT_PRIVATE) { + ret = (int)SYS_HOOK(syscall, SYS_futex, uaddr, futex_op, val, timeout, nullptr, 0u); + } else { + ret = (int)real_syscall(SYS_futex, uaddr, futex_op, val, timeout, nullptr, 0u); + } + return ret; +} + +} /* extern "C" */ + +#endif /* PERF_MODE */ +#endif /* _OCEABASE_TENANT_PRELOAD_H_ */ diff --git a/src/observer/omt/ob_th_worker.cpp b/src/observer/omt/ob_th_worker.cpp index 789f88436..ed95f73d0 100644 --- a/src/observer/omt/ob_th_worker.cpp +++ b/src/observer/omt/ob_th_worker.cpp @@ -42,17 +42,72 @@ namespace memtable { extern TLOCAL(bool, TLOCAL_NEED_WAIT_IN_LOCK_WAIT_MGR); } + +namespace omt +{ +int create_worker(ObThWorker* &worker, ObTenant *tenant, int32_t group_id, + int32_t level, ObResourceGroup *group) +{ + int ret = OB_SUCCESS; + if (tenant->total_worker_cnt() >= tenant->max_worker_cnt()) { + ret = OB_SIZE_OVERFLOW; + LOG_ERROR("create worker fail", K(ret), K(tenant->id()), K(group_id), K(level), + K(tenant->total_worker_cnt()), K(tenant->max_worker_cnt())); + } else if (OB_ISNULL(worker = OB_NEW(ObThWorker, + ObMemAttr(0 == GET_TENANT_ID() ? OB_SERVER_TENANT_ID : GET_TENANT_ID(), + "OMT_Worker", + ObCtxIds::DEFAULT_CTX_ID, OB_NORMAL_ALLOC)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("create worker fail", K(ret), K(tenant->id()), K(group_id), K(level)); + } else if (OB_FAIL(worker->init())) { + LOG_ERROR("init worker fail", K(ret), K(tenant->id()), K(group_id), K(level)); + ob_delete(worker); + worker = nullptr; + } else { + worker->reset(); + worker->set_tenant(tenant); + worker->set_group_id(group_id); + worker->set_worker_level(level); + worker->set_group(group); + if (OB_FAIL(worker->start())) { + ob_delete(worker); + worker = nullptr; + LOG_ERROR("worker start failed", K(ret), K(tenant->id()), K(group_id), K(level)); + } else { + ++tenant->total_worker_cnt_; + } + } + return ret; } +int destroy_worker(ObThWorker *worker) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(worker)) { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("invalid argument", K(worker), K(ret)); + } else { + auto* tenant = worker->get_tenant(); + worker->stop(); + worker->wait(); + worker->destroy(); + ob_delete(worker); + --tenant->total_worker_cnt_; + } + return ret; +} +}// end of namespace omt +}// end of namespace oceanbase + ObThWorker::ObThWorker() : procor_(ObServer::get_instance().get_net_frame().get_xlator(), ObServer::get_instance().get_self()), is_inited_(false), tenant_(nullptr), group_(nullptr), run_cond_(), pause_flag_(false), large_query_(false), + priority_limit_(RQ_LOW), is_lq_yield_(false), query_start_time_(0), last_check_time_(0), can_retry_(true), need_retry_(false), - active_(false), waiting_active_(false), - active_inactive_ts_(0L), lq_token_(false), has_add_to_cgroup_(false) + has_add_to_cgroup_(false), last_wakeup_ts_(0) { } @@ -109,77 +164,8 @@ void ObThWorker::resume() run_cond_.signal(); } -void ObThWorker::activate() -{ - ObThreadCondGuard guard(run_cond_); - active_inactive_ts_ = ObTimeUtility::current_time(); - active_ = true; - run_cond_.signal(); -} RLOCAL(uint64_t, serving_tenant_id); -void ObThWorker::wait_active() -{ - bool has_reset_pm = false; - auto *pm = common::ObPageManager::thread_local_instance(); - ObThreadCondGuard guard(run_cond_); - while (OB_UNLIKELY(!active_)) { - if (pm != nullptr && !has_reset_pm) { - pm->reset(); - has_reset_pm = true; - } - waiting_active_ = true; - share::ObTenantEnv::set_tenant(nullptr); - lib::set_thread_name("OMT_FREE_", NULL == tenant_ ? 0 : tenant_->id()); - serving_tenant_id = 0; - IGNORE_RETURN run_cond_.wait(); - waiting_active_ = false; - - } - - // set ObTenant Context thread_local - if (OB_NOT_NULL(tenant_)) { - if (static_cast(tenant_) != MTL_CTX() || tenant_->id() != MTL_ID()) { - LOG_INFO("ObThWorker set tenant ctx", K(tenant_->id()), K(MTL_ID()), KP(tenant_), KP(MTL_CTX())); - share::ObTenantEnv::set_tenant(tenant_); - } - if (tenant_->id() != MTL_ID()) { - abort(); - } - } -} - -inline void ObThWorker::wait_runnable() -{ - int64_t wait_us = std::max(0L, get_timeout_remain()); - if (OB_UNLIKELY(!tenant_->has_stopped()) && - wait_us > 0 && - pause_flag_) { - ObThreadCondGuard guard(run_cond_); - while (!tenant_->has_stopped() && - wait_us > 0 && - pause_flag_) { - WAIT_BEGIN(OMT_WAIT, wait_us, 0, 0, 0); - NG_TRACE(wait_start); - IGNORE_RETURN run_cond_.wait_us(wait_us); - NG_TRACE(wait_end); - WAIT_END(OMT_WAIT); - wait_us = std::max(0L, get_timeout_remain()); - } - } - // LQ Worker being woken up maybe has 2 reasons generally. - // - // 1. Scheduler thinks it should run, e.g. LQ token is enough or - // tenant is deleting. - // 2. The task has reached its timeout and this worker should run - // the cleanup process ASAP. - // - // In the second condition, current worker may be still in the - // waiting queue. So that we need try to remove it from the queue by - // invoking this function. - tenant_->try_unlink_lq_waiting_worker_with_lock(*this); - pause_flag_ = false; -} // Check only before user request starts ObThWorker::Status ObThWorker::check_qtime_throttle() @@ -250,17 +236,12 @@ ObThWorker::Status ObThWorker::check_wait() } else if (OB_UNLIKELY(!tenant_->user_sched_enabled())) { } else if (OB_UNLIKELY(true == get_disable_wait_flag())) { } else if (this->get_curr_request_level() >= MULTI_LEVEL_THRESHOLD) { - } else if (this->get_group() != nullptr) { + } else if (this->is_group_worker() && this->get_group_id() != share::OBCG_LQ) { } else if (curr_time > last_check_time_ + WORKER_CHECK_PERIOD) { st = check_throttle(); if (st != WS_OUT_OF_THROTTLE) { if (OB_UNLIKELY(curr_time > get_query_start_time() + threshold)) { - large_query_ = true; - tenant_->lq_check_status(*this); - wait_runnable(); - } else { - // no need to reset large query flag - //large_query_ = false; + tenant_->lq_yield(*this); } } last_check_time_ = curr_time; @@ -325,8 +306,7 @@ inline void ObThWorker::process_request(rpc::ObRequest &req) if (REACH_TIME_INTERVAL(10*1000*1000)) { auto *pm = common::ObPageManager::thread_local_instance(); const int64_t pm_hold = (pm != nullptr) ? pm->get_hold() : 0; - _OB_LOG(INFO, "worker= %ld thd_flag=%d total=%ld used=%ld pm_hold=%ld", - lib::Worker::get_tidx(), + _OB_LOG(INFO, "thd_flag=%d total=%ld used=%ld pm_hold=%ld", has_req_flag(), get_allocator().total(), get_allocator().used(), @@ -343,7 +323,7 @@ void ObThWorker::set_th_worker_thread_name(uint64_t tenant_id) char buf[32]; if (serving_tenant_id != tenant_->id()) { serving_tenant_id = tenant_->id(); - snprintf(buf, 32, "TNT_L%d_G%d", get_worker_level(), get_group_id()); + snprintf(buf, 32, "L%d_G%d", get_worker_level(), get_group_id()); lib::set_thread_name(buf); } } @@ -367,19 +347,17 @@ void ObThWorker::worker(int64_t &tenant_id, int64_t &req_recv_timestamp, int32_t this->set_worker_level(0); } while (!has_set_stop()) { - wait_active(); worker_level = this->get_worker_level(); // Update backtrace printing parameters if (nullptr != this->tenant_) { tenant_id = this->tenant_->id(); // Update backtrace printing parameters } - if (OB_UNLIKELY(has_set_stop())) { - // empty - } else if (OB_ISNULL(tenant_)) { + if (OB_ISNULL(tenant_)) { LOG_ERROR("invalid status, unexpected", K(tenant_)); } else { if (nullptr != GCTX.cgroup_ctrl_ && nullptr != tenant_ && OB_LIKELY(GCTX.cgroup_ctrl_->is_valid()) && !has_add_to_cgroup_) { - GCTX.cgroup_ctrl_->add_thread_to_cgroup(get_tid(), tenant_->id(), get_group_id()); - has_add_to_cgroup_ = true; + if (OB_SUCC(GCTX.cgroup_ctrl_->add_thread_to_cgroup(gettid(), tenant_->id(), get_group_id()))) { + has_add_to_cgroup_ = true; + } } if (OB_LIKELY(pm != nullptr)) { if (pm->get_used() != 0) { @@ -440,6 +418,7 @@ void ObThWorker::worker(int64_t &tenant_id, int64_t &req_recv_timestamp, int32_t query_start_time_ = wait_end_time; query_enqueue_time_ = req->get_enqueue_timestamp(); last_check_time_ = wait_end_time; + set_last_wakeup_ts(query_start_time_); set_rpc_stat_srv(&(tenant_->rpc_stat_info_->rpc_stat_srv_)); req_start_time = ObTimeUtility::current_time(); process_request(*req); @@ -458,10 +437,10 @@ void ObThWorker::worker(int64_t &tenant_id, int64_t &req_recv_timestamp, int32_t ret = OB_SUCCESS; } tenant_->add_idle_time(wait_end_time - wait_start_time); - if (this->get_worker_level() == 0 && this->get_group() == nullptr) { + if (this->get_worker_level() == 0 && !is_group_worker()) { tenant_->check_worker_count(*this); - tenant_->check_paused_worker(*this); - } else if (this->get_group() != nullptr) { + tenant_->lq_end(*this); + } else if (this->is_group_worker()) { group_->check_worker_count(*this); } } diff --git a/src/observer/omt/ob_th_worker.h b/src/observer/omt/ob_th_worker.h index d5d266faa..a211d1c4f 100644 --- a/src/observer/omt/ob_th_worker.h +++ b/src/observer/omt/ob_th_worker.h @@ -36,73 +36,73 @@ class ObResourceGroup; static const int64_t WORKER_CHECK_PERIOD = 500L; static const int64_t REQUEST_WAIT_TIME = 10 * 1000L; +// Quick Queue Priorities +enum { QQ_HIGH = 0, QQ_NORMAL, QQ_LOW, QQ_MAX_PRIO }; +// Request queue priorities +enum { RQ_HIGH = QQ_MAX_PRIO, RQ_NORMAL, RQ_LOW, RQ_MAX_PRIO }; + class ObThWorker : public lib::Worker, public lib::Threads { -public: - enum RequestType { RT_NOTASK, RT_NEW, RT_OLD }; - public: explicit ObThWorker(); virtual ~ObThWorker(); + virtual ObThWorker::Status check_wait() override; + virtual int check_status() override; + virtual int check_large_query_quota() override; + // retry relating + virtual bool can_retry() const override { return can_retry_; } + // Note: you CAN NOT call set_need_retry when can_retry_ == false + virtual void set_need_retry() override { need_retry_ = true; } + virtual bool need_retry() const override { return need_retry_; } + virtual void resume() override; + int init(); void destroy(); inline void reset(); - inline void set_tenant(ObTenant *tenant) -{ - tenant_ = tenant; - set_run_wrapper(MTL_CTX()); -} + OB_INLINE void set_tenant(ObTenant *tenant) + { + tenant_ = tenant; + set_run_wrapper(MTL_CTX()); + } - inline void set_group(ObResourceGroup *group); + OB_INLINE void set_group(ObResourceGroup *group) { group_ = group; } void worker(int64_t &tenant_id, int64_t &req_recv_timestamp, int32_t &worker_level); void run(int64_t idx); - void resume(); - void pause(); + OB_INLINE void pause() { pause_flag_ = true; } Status check_qtime_throttle(); Status check_throttle(); Status check_rate_limiter(); - virtual ObThWorker::Status check_wait(); - virtual int check_status() override; - virtual int check_large_query_quota(); - // retry relating - virtual bool can_retry() const; - virtual void set_need_retry(); - virtual bool need_retry() const; + OB_INLINE bool large_query() const { return large_query_; } + OB_INLINE void set_large_query(bool v=true) { large_query_ = v; } - // active relating - void wait_active(); - void activate(); - void set_inactive(); - bool is_active() { return active_; } - int64_t get_active_inactive_ts() const { return active_inactive_ts_; } - bool is_waiting_active() { return ATOMIC_LOAD(&waiting_active_); } + OB_INLINE bool is_group_worker() const { return OB_NOT_NULL(group_); } + OB_INLINE bool is_level_worker() const { return get_worker_level() > 0; } + OB_INLINE uint8_t priority_limit() const { return priority_limit_; } + OB_INLINE void set_priority_limit(bool v=true) { priority_limit_ = v; } + OB_INLINE bool is_high_priority() const { return priority_limit_ == QQ_HIGH; } + OB_INLINE bool is_normal_priority() const { return priority_limit_ == QQ_NORMAL; } + OB_INLINE bool is_default_worker() const { return !is_group_worker() && + !is_level_worker() && + priority_limit_ > QQ_NORMAL; } - bool large_query() const { return large_query_; } - void set_large_query(bool v=true) { large_query_ = v; } - - void set_lq_token(bool v=true) { lq_token_ = v; } - bool has_lq_token() const { return lq_token_; } - - int64_t get_query_start_time() const; - int64_t get_query_enqueue_time() const; - ObTenant *get_tenant() { return tenant_; } - ObResourceGroup *get_group() { return group_; } + OB_INLINE int64_t get_query_start_time() const { return query_start_time_; } + OB_INLINE int64_t get_query_enqueue_time() const { return query_enqueue_time_; } + OB_INLINE ObTenant* get_tenant() { return tenant_; } + OB_INLINE ObResourceGroup* get_group() { return group_; } + OB_INLINE bool is_lq_yield() const { return is_lq_yield_; } + OB_INLINE void set_lq_yield(bool v=true) { is_lq_yield_ = v; } + OB_INLINE int64_t get_last_wakeup_ts() { return last_wakeup_ts_; } + OB_INLINE void set_last_wakeup_ts(int64_t last_wakeup_ts) { last_wakeup_ts_ = last_wakeup_ts; } private: - // SQL layer should not call disable_retry directly - // it can only decide retry, don't need to decide no-retry as it is by default. - // ref: https://yuque.antfin-inc.com/xiaochu.yh/doc/sgl4x3#vhv1R - virtual void disable_retry(); - void set_th_worker_thread_name(uint64_t tenant_id); - void wait_runnable(); void process_request(rpc::ObRequest &req); void th_created(); @@ -119,6 +119,8 @@ private: bool pause_flag_; bool large_query_; + uint8_t priority_limit_; + bool is_lq_yield_; int64_t query_start_time_; int64_t query_enqueue_time_; @@ -129,87 +131,42 @@ private: // if upper scheduler support retry, need this request retry? bool need_retry_; - - // Set by other thread indicating the worker is going to be active - // or not. When it is set as false, current worker would be paused - // and no longer process request afterward. - bool active_; - // Flag for whether current worker is paused and waiting to be - // active. Worker itself maintain this variable, set true before - // wait and set false after. Others need check this variable and - // waiting it to be true before resource relating to the worker. - bool waiting_active_; - int64_t active_inactive_ts_; - bool lq_token_; bool has_add_to_cgroup_; + int64_t last_wakeup_ts_; + private: DISALLOW_COPY_AND_ASSIGN(ObThWorker); }; // end of class ObThWorker inline void ObThWorker::reset() { - OB_ASSERT(!pause_flag_ && !active_); - OB_ASSERT(!lq_token_); + OB_ASSERT(!pause_flag_); tenant_ = nullptr; group_ = nullptr; pause_flag_ = false; large_query_ = false; + priority_limit_ = RQ_LOW; query_start_time_ = 0; query_enqueue_time_ = 0; can_retry_ = true; need_retry_ = false; - active_ = false; has_add_to_cgroup_ = false; - unset_tidx(); + last_wakeup_ts_ = 0; } -inline void ObThWorker::set_group(ObResourceGroup *group) -{ - group_ = group; -} - -inline void ObThWorker::disable_retry() -{ - can_retry_ = false; -} - -inline bool ObThWorker::can_retry() const -{ - return can_retry_; -} - -inline bool ObThWorker::need_retry() const -{ - return need_retry_; -} - -// Note: you CAN NOT call set_need_retry when can_retry_ == false -inline void ObThWorker::set_need_retry() -{ - need_retry_ = true; -} - -inline void ObThWorker::pause() -{ - pause_flag_ = true; -} - -inline void ObThWorker::set_inactive() -{ - active_inactive_ts_ = common::ObTimeUtility::current_time(); - active_ = false; -} - -inline int64_t ObThWorker::get_query_start_time() const -{ - return query_start_time_; -} - -inline int64_t ObThWorker::get_query_enqueue_time() const -{ - return query_enqueue_time_; -} +/* create a worker +worker: save the new ObThWorker, +tidx: set worker's tidx_, an index of worker +tenant: set worker's tenant, which the worker belongs to +group_id: set worker's group_id +level: set worker's level, in ObResourceGroup level = INT32_MAX, in ObTenant level = 0, +group: set worker's group, in ObResourceGroup level = this, in ObTenant level = nullptr, +*/ +int create_worker(ObThWorker* &worker, ObTenant *tenant, int32_t group_id, + int32_t level = INT32_MAX, ObResourceGroup *group = nullptr); + // defalut level=INT32_MAX, group=nullptr +int destroy_worker(ObThWorker *worker); #define THIS_THWORKER static_cast(THIS_WORKER) #define THIS_THWORKER_SAFE dynamic_cast(&THIS_WORKER) @@ -217,4 +174,5 @@ inline int64_t ObThWorker::get_query_enqueue_time() const } // end of namespace omt } // end of namespace oceanbase + #endif /* _OCEABASE_OBSERVER_OMT_OB_TH_WORKER_H_ */ diff --git a/src/observer/omt/ob_worker_pool.cpp b/src/observer/omt/ob_worker_pool.cpp deleted file mode 100644 index 9c1d95c41..000000000 --- a/src/observer/omt/ob_worker_pool.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/** - * 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 SERVER_OMT -#include "ob_worker_pool.h" - -#include "share/ob_define.h" -#include "ob_th_worker.h" -#include "share/rc/ob_tenant_base.h" - -using namespace oceanbase::common; -using namespace oceanbase::omt; -using namespace oceanbase::share; - -ObWorkerPool::ObWorkerPool() - : is_inited_(false), - init_cnt_(0), - idle_cnt_(0), - worker_cnt_(0) -{ -} - -ObWorkerPool::~ObWorkerPool() -{ - destroy(); -} - -int ObWorkerPool::Queue::push(ObThWorker *worker) -{ - int ret = OB_SUCCESS; - if (NULL == worker) { - LOG_ERROR("invalid argument", K(worker)); - } else if (OB_FAIL(queue_.push(&worker->wpool_link_))) { - LOG_ERROR("failed push queue", K(ret)); - } - return ret; -} - -int ObWorkerPool::Queue::pop(ObThWorker *&worker) -{ - int ret = OB_SUCCESS; - ObLink *link = nullptr; - if (OB_FAIL(queue_.pop(link))) { - if (OB_EAGAIN != ret) { - LOG_ERROR("failed pop queue", K(ret)); - } else { - ret = OB_ENTRY_NOT_EXIST; - } - } else { - worker = CONTAINER_OF(link, ObThWorker, wpool_link_); - } - return ret; -} - -int ObWorkerPool::init( - int64_t init_cnt, - int64_t idle_cnt) -{ - int ret = OB_SUCCESS; - if (is_inited_) { - ret = OB_INIT_TWICE; - } else if (init_cnt < 1 - || idle_cnt < init_cnt) { - ret = OB_INVALID_ARGUMENT; - LOG_ERROR("invalid arguments", - K(init_cnt), K(idle_cnt), K(ret)); - } else { - ObThWorker *worker = nullptr; - for (int64_t i = 0; i < init_cnt && OB_SUCC(ret); i++) { - if (OB_FAIL(create_worker(worker))) { - LOG_ERROR("create worker fail", K(ret)); - } else if (OB_FAIL(workers_.push(worker))) { - LOG_ERROR("add worker into worker list fail", K(ret)); - destroy_worker(worker); - } - } - } - - if (OB_SUCC(ret)) { - is_inited_ = true; - init_cnt_ = init_cnt; - idle_cnt_ = idle_cnt; - } else { - destroy(); - } - return ret; -} - -void ObWorkerPool::destroy() -{ - ObThWorker *worker = NULL; - while (OB_SUCCESS == workers_.pop(worker)) { - destroy_worker(worker); - } - is_inited_ = false; -} - -ObThWorker *ObWorkerPool::alloc() -{ - int ret = OB_SUCCESS; - - ObThWorker *worker = nullptr; - if (OB_FAIL(workers_.pop(worker))) { - if (OB_ENTRY_NOT_EXIST != ret) { - LOG_ERROR("failed to pop worker", K(ret)); - } else { - LOG_DEBUG("no available worker right now", K(ret)); - } - } - if (OB_FAIL(ret) && nullptr == worker) { - if (OB_SUCC(create_worker(worker))) { - } else { - worker = nullptr; - LOG_ERROR("create worker fail", K(ret)); - } - } - return worker; -} - -void ObWorkerPool::free(ObThWorker *worker) -{ - int ret = OB_SUCCESS; - if (OB_ISNULL(worker)) { - ret = OB_INVALID_ARGUMENT; - LOG_ERROR("invalid argument", K(worker), K(ret)); - } else { - // TODO: destroy or add free list. - if (worker_cnt_ > idle_cnt_) { - destroy_worker(worker); - } else if (OB_FAIL(workers_.push(worker))) { - LOG_ERROR("add worker to free list fail, destroy worker", K(ret)); - destroy_worker(worker); - } - } -} - -int ObWorkerPool::create_worker(ObThWorker *&worker) -{ - int ret = OB_SUCCESS; - worker = OB_NEW(ObThWorker, ObModIds::OMT); - if (NULL == worker) { - ret = OB_ALLOCATE_MEMORY_FAILED; - } else if (OB_FAIL(worker->init())) { - LOG_ERROR("init worker fail", K(ret)); - } - if (OB_FAIL(ret) && nullptr != worker) { - ob_delete(worker); - } - if (OB_SUCC(ret)) { - ATOMIC_INC(&worker_cnt_); - } - return ret; -} - -void ObWorkerPool::destroy_worker(ObThWorker *worker) -{ - if (!OB_ISNULL(worker)) { - worker->stop(); - worker->activate(); - worker->wait(); - worker->destroy(); - ob_delete(worker); - worker_cnt_--; - } -} diff --git a/src/observer/omt/ob_worker_pool.h b/src/observer/omt/ob_worker_pool.h deleted file mode 100644 index 3829a8f48..000000000 --- a/src/observer/omt/ob_worker_pool.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * 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 _OCEABASE_OBSERVER_OMT_OB_WORKER_POOL_H_ -#define _OCEABASE_OBSERVER_OMT_OB_WORKER_POOL_H_ - -#include -#include "lib/queue/ob_link_queue.h" -#include "observer/ob_srv_xlator.h" - -namespace oceanbase -{ - -namespace rpc -{ -namespace frame -{ -class ObReqTranslator; -} -} - -namespace omt -{ - -class ObThWorker; - -// This class isn't thread safe. -class ObWorkerPool -{ -public: - class Queue - { - public: - Queue() {} - virtual ~Queue() {} - int push(ObThWorker *worker); - int pop(ObThWorker *&worker); - private: - common::ObLinkQueue queue_; - }; - -public: - explicit ObWorkerPool(); - virtual ~ObWorkerPool(); - - int init(int64_t init_cnt, int64_t idle_cnt); - void destroy(); - - ObThWorker *alloc(); - void free(ObThWorker *worker); - -private: - int create_worker(ObThWorker *&worker); - void destroy_worker(ObThWorker *worker); - -private: - bool is_inited_; - int64_t init_cnt_; - int64_t idle_cnt_; - int64_t worker_cnt_; - Queue workers_; -}; // end of class ObWorkerPool - -} // end of namespace omt -} // end of namespace oceanbase - - -#endif /* _OCEABASE_OBSERVER_OMT_OB_WORKER_POOL_H_ */ diff --git a/src/observer/virtual_table/ob_all_virtual_dump_tenant_info.cpp b/src/observer/virtual_table/ob_all_virtual_dump_tenant_info.cpp index 12e4c4b23..406b31776 100644 --- a/src/observer/virtual_table/ob_all_virtual_dump_tenant_info.cpp +++ b/src/observer/virtual_table/ob_all_virtual_dump_tenant_info.cpp @@ -70,11 +70,11 @@ int ObAllVirtualDumpTenantInfo::inner_get_next_row(common::ObNewRow *&row) break; case OB_APP_MIN_COLUMN_ID + 6: //slice - cells[i].set_double(t.slice_); + cells[i].set_double(0); break; case OB_APP_MIN_COLUMN_ID + 7: //slice_remain - cells[i].set_double(t.slice_remain_); + cells[i].set_double(0); break; case OB_APP_MIN_COLUMN_ID + 8: //token_cnt @@ -82,15 +82,15 @@ int ObAllVirtualDumpTenantInfo::inner_get_next_row(common::ObNewRow *&row) break; case OB_APP_MIN_COLUMN_ID + 9: //ass_token_cnt - cells[i].set_int(t.ass_token_cnt_); + cells[i].set_int(t.worker_count()); break; case OB_APP_MIN_COLUMN_ID + 10: //lq_tokens - cells[i].set_int(t.lq_tokens_); + cells[i].set_int(0); break; case OB_APP_MIN_COLUMN_ID + 11: //used_lq_tokens - cells[i].set_int(t.used_lq_tokens_); + cells[i].set_int(0); break; case OB_APP_MIN_COLUMN_ID + 12: //stopped @@ -130,7 +130,7 @@ int ObAllVirtualDumpTenantInfo::inner_get_next_row(common::ObNewRow *&row) break; case OB_APP_MIN_COLUMN_ID + 21: //actives - cells[i].set_int(t.actives_); + cells[i].set_int(t.workers_.get_size()); break; case OB_APP_MIN_COLUMN_ID + 22: //workers @@ -138,7 +138,7 @@ int ObAllVirtualDumpTenantInfo::inner_get_next_row(common::ObNewRow *&row) break; case OB_APP_MIN_COLUMN_ID + 23: //lq_waiting_workers - cells[i].set_int(t.lq_waiting_workers_.get_size()); + cells[i].set_int(0); break; case OB_APP_MIN_COLUMN_ID + 24: //req_queue_total_size @@ -170,7 +170,7 @@ int ObAllVirtualDumpTenantInfo::inner_get_next_row(common::ObNewRow *&row) break; case OB_APP_MIN_COLUMN_ID + 31: //large_queued - cells[i].set_int(t.large_req_queue_.size()); + cells[i].set_int(t.lq_retry_queue_size()); break; default: ret = OB_ERR_UNEXPECTED; diff --git a/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.cpp b/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.cpp new file mode 100644 index 000000000..d7f035a50 --- /dev/null +++ b/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.cpp @@ -0,0 +1,149 @@ +/** + * 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. + */ + +#include "ob_all_virtual_malloc_sample_info.h" +#include "rpc/obrpc/ob_rpc_packet.h" +#include "lib/alloc/memory_dump.h" +#include "observer/ob_server.h" +#include "observer/ob_server_utils.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace observer +{ +ObMallocSampleInfo::ObMallocSampleInfo() + : ObVirtualTableScannerIterator(), + col_count_(0), + opened_(false) +{} + +ObMallocSampleInfo::~ObMallocSampleInfo() +{ + reset(); +} + +int ObMallocSampleInfo::inner_open() +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(ObServerConfig::get_instance().self_addr_.ip_to_string(ip_buf_, sizeof(ip_buf_)) + == false)) { + ret = OB_ERR_UNEXPECTED; + SERVER_LOG(WARN, "ip_to_string() fail", K(ret)); + } + return ret; +} +void ObMallocSampleInfo::reset() +{ + col_count_ = 0; + opened_ = false; +} +int ObMallocSampleInfo::inner_get_next_row(ObNewRow *&row) +{ + int ret = OB_SUCCESS; + if (!opened_) { + col_count_ = output_column_ids_.count(); + if (OB_FAIL(malloc_sample_map_.create(1000, "MallocInfoMap", "MallocInfoMap"))) { + SERVER_LOG(WARN, "create memory info map failed", K(ret)); + } else { + ret = ObMemoryDump::get_instance().load_malloc_sample_map(malloc_sample_map_); + if (OB_SUCC(ret)) { + it_ = malloc_sample_map_.begin(); + opened_ = true; + } + } + } + if (OB_SUCC(ret)) { + if (it_ != malloc_sample_map_.end()) { + if (OB_FAIL(fill_row(row))) { + SERVER_LOG(WARN, "failed to fill row", K(ret)); + } + ++it_; + } else { + ret = OB_ITER_END; + } + } + return ret; +} +int ObMallocSampleInfo::fill_row(ObNewRow *&row) +{ + int ret = OB_SUCCESS; + ObObj *cells = NULL; + if (OB_ISNULL(cells = cur_row_.cells_)) { + ret = OB_ERR_UNEXPECTED; + SERVER_LOG(WARN, "cur row cell is NULL", K(ret)); + } else if (is_sys_tenant(effective_tenant_id_) || effective_tenant_id_ == it_->first.tenant_id_) { + for (int64_t i = 0; OB_SUCC(ret) && i < col_count_; ++i) { + const uint64_t col_id = output_column_ids_.at(i); + switch (col_id) { + case SVR_IP: { + cells[i].set_varchar(ip_buf_); + cells[i].set_collation_type( + ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case SVR_PORT: { + cells[i].set_int(GCONF.self_addr_.get_port()); + break; + } + case TENANT_ID: { + cells[i].set_int(it_->first.tenant_id_); + break; + } + case CTX_ID: { + cells[i].set_int(it_->first.ctx_id_); + break; + } + case MOD_NAME: { + cells[i].set_varchar(it_->first.label_); + cells[i].set_collation_type( + ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case BACKTRACE: { + parray(bt_, sizeof(bt_), (int64_t*)*&(it_->first.bt_), it_->first.bt_size_); + cells[i].set_varchar(bt_); + cells[i].set_collation_type( + ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case CTX_NAME: { + cells[i].set_varchar(get_global_ctx_info().get_ctx_name(it_->first.ctx_id_)); + cells[i].set_collation_type( + ObCharset::get_default_collation(ObCharset::get_default_charset())); + break; + } + case ALLOC_COUNT: { + cells[i].set_int(it_->second.alloc_count_); + break; + } + case ALLOC_BYTES: { + cells[i].set_int(it_->second.alloc_bytes_); + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + SERVER_LOG(WARN, "unexpected column id", K(col_id), K(i), K(ret)); + break; + } + } + } + } + if (OB_SUCC(ret)) { + row = &cur_row_; + } + return ret; +} + +} +} diff --git a/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.h b/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.h new file mode 100644 index 000000000..d66cffab5 --- /dev/null +++ b/src/observer/virtual_table/ob_all_virtual_malloc_sample_info.h @@ -0,0 +1,59 @@ +/** + * 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_OBSERVER_VIRTUAL_TABLE_OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_H_ +#define OCEANBASE_OBSERVER_VIRTUAL_TABLE_OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_H_ + +#include "lib/container/ob_array.h" +#include "lib/alloc/ob_malloc_sample_struct.h" +#include "share/ob_virtual_table_scanner_iterator.h" + +namespace oceanbase +{ +namespace observer +{ +class ObMallocSampleInfo : public common::ObVirtualTableScannerIterator +{ +public: + ObMallocSampleInfo(); + virtual ~ObMallocSampleInfo(); + virtual int inner_open(); + virtual void reset(); + virtual int inner_get_next_row(common::ObNewRow *&row); +private: + int fill_row(common::ObNewRow *&row); +private: + enum CACHE_COLUMN + { + SVR_IP = common::OB_APP_MIN_COLUMN_ID, + SVR_PORT, + TENANT_ID, + CTX_ID, + MOD_NAME, + BACKTRACE, + CTX_NAME, + ALLOC_COUNT, + ALLOC_BYTES, + }; + char ip_buf_[common::OB_IP_STR_BUFF]; + char bt_[512]; + lib::ObMallocSampleMap::const_iterator it_; + lib::ObMallocSampleMap malloc_sample_map_; + int64_t col_count_; + bool opened_; +private: + DISALLOW_COPY_AND_ASSIGN(ObMallocSampleInfo); +}; +} +} + +#endif diff --git a/src/observer/virtual_table/ob_virtual_table_iterator_factory.cpp b/src/observer/virtual_table/ob_virtual_table_iterator_factory.cpp index f5c89ca09..967a1c77e 100644 --- a/src/observer/virtual_table/ob_virtual_table_iterator_factory.cpp +++ b/src/observer/virtual_table/ob_virtual_table_iterator_factory.cpp @@ -52,6 +52,7 @@ #include "observer/virtual_table/ob_all_virtual_session_stat.h" #include "observer/virtual_table/ob_all_disk_stat.h" #include "observer/virtual_table/ob_mem_leak_checker_info.h" +#include "observer/virtual_table/ob_all_virtual_malloc_sample_info.h" #include "observer/virtual_table/ob_all_latch.h" #include "observer/virtual_table/ob_all_data_type_class_table.h" #include "observer/virtual_table/ob_all_data_type_table.h" @@ -1292,6 +1293,14 @@ int ObVTIterCreator::create_vt_iter(ObVTableScanParam ¶ms, } break; } + case OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TID: { + ObMallocSampleInfo *malloc_sample_info = NULL; + if (OB_SUCC(NEW_VIRTUAL_TABLE(ObMallocSampleInfo, malloc_sample_info))) { + malloc_sample_info->set_allocator(&allocator); + vt_iter = static_cast(malloc_sample_info); + } + break; + } case OB_ALL_VIRTUAL_MEM_LEAK_CHECKER_INFO_TID: { ObMemLeakCheckerInfo *leak_checker = NULL; if (OB_SUCC(NEW_VIRTUAL_TABLE(ObMemLeakCheckerInfo, leak_checker))) { diff --git a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp index ea242ec31..76785ffd0 100644 --- a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp +++ b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp @@ -587,7 +587,7 @@ void ObDDLScheduler::run1() int ret = OB_SUCCESS; ObDDLTask *task = nullptr; ObDDLTask *first_retry_task = nullptr; - (void)prctl(PR_SET_NAME, "DDLTaskExecutor", 0, 0, 0); + lib::set_thread_name("DDLTaskExecutor"); while (!has_set_stop()) { THIS_WORKER.set_worker_level(1); THIS_WORKER.set_curr_request_level(1); diff --git a/src/rootserver/ob_root_service.cpp b/src/rootserver/ob_root_service.cpp index 6970731e7..2db8d77b9 100644 --- a/src/rootserver/ob_root_service.cpp +++ b/src/rootserver/ob_root_service.cpp @@ -10093,8 +10093,6 @@ void ObRootService::update_cpu_quota_concurrency_in_memory_() omt::ObTenantConfigGuard tenant_config(TENANT_CONF(OB_SYS_TENANT_ID)); tenant_config->cpu_quota_concurrency = MAX(10, tenant_config->cpu_quota_concurrency); } - // update now - GCTX.omt_->set_group_sug_token(); } int ObRootService::set_cpu_quota_concurrency_config_() diff --git a/src/rootserver/ob_rs_reentrant_thread.cpp b/src/rootserver/ob_rs_reentrant_thread.cpp index d52dfe2ca..349445b7f 100644 --- a/src/rootserver/ob_rs_reentrant_thread.cpp +++ b/src/rootserver/ob_rs_reentrant_thread.cpp @@ -37,8 +37,10 @@ ObRsReentrantThread::~ObRsReentrantThread() void ObRsReentrantThread::update_last_run_timestamp() { + auto time = ObTimeUtility::current_time(); + IGNORE_RETURN lib::Thread::update_loop_ts(time); if (ATOMIC_LOAD(&last_run_timestamp_) != -1) { - ATOMIC_STORE(&last_run_timestamp_, ObTimeUtility::current_time()); + ATOMIC_STORE(&last_run_timestamp_, time); } } diff --git a/src/rootserver/ob_thread_idling.cpp b/src/rootserver/ob_thread_idling.cpp index 17cb4d1f2..15df0eb11 100644 --- a/src/rootserver/ob_thread_idling.cpp +++ b/src/rootserver/ob_thread_idling.cpp @@ -15,6 +15,8 @@ #include "ob_thread_idling.h" #include "share/ob_define.h" #include "lib/time/ob_time_utility.h" +#include "lib/thread/thread.h" + namespace oceanbase { namespace rootserver @@ -56,6 +58,7 @@ int ObThreadIdling::idle(const int64_t max_idle_time_us) const int64_t now_ms = ObTimeUtility::current_time() / 1000; const int64_t idle_time_ms = std::min(max_idle_time_us, get_idle_interval_us()) / 1000; int64_t wait_time_ms = begin_time_ms + idle_time_ms - now_ms; + IGNORE_RETURN lib::Thread::update_loop_ts(); if (wait_time_ms <= 0) { break; } diff --git a/src/share/config/ob_config_manager.cpp b/src/share/config/ob_config_manager.cpp index 7f323c50f..d49a28b84 100644 --- a/src/share/config/ob_config_manager.cpp +++ b/src/share/config/ob_config_manager.cpp @@ -84,7 +84,7 @@ int ObConfigManager::reload_config() LOG_WARN("reload ssl config for net frame fail", K(ret)); } else if (OB_FAIL(OBSERVER.get_rl_mgr().reload_config())) { LOG_WARN("reload config for ratelimit manager fail", K(ret)); - } else if (OB_FAIL(OBSERVER.get_net_frame().reload_mysql_login_thread_config())) { + } else if (OB_FAIL(OBSERVER.get_net_frame().reload_sql_thread_config())) { LOG_WARN("reload config for mysql login thread count failed", K(ret)); } else if (OB_FAIL(ObTdeEncryptEngineLoader::get_instance().reload_config())) { LOG_WARN("reload config for tde encrypt engine fail", K(ret)); diff --git a/src/share/config/ob_server_config.cpp b/src/share/config/ob_server_config.cpp index a58f147ee..14dd97a27 100644 --- a/src/share/config/ob_server_config.cpp +++ b/src/share/config/ob_server_config.cpp @@ -298,7 +298,7 @@ int ObServerConfig::serialize_(char *buf, const int64_t buf_len, int64_t &pos) c int ObServerConfig::serialize(char *buf, const int64_t buf_len, int64_t &pos) const { int ret = OB_SUCCESS; - SERIALIZE_HEADER(UNIS_VERSION); + OB_UNIS_ENCODE(UNIS_VERSION); if (OB_SUCC(ret)) { int64_t size_nbytes = NS_::OB_SERIALIZE_SIZE_NEED_BYTES; int64_t pos_bak = (pos += size_nbytes); @@ -363,6 +363,11 @@ OB_DEF_SERIALIZE_SIZE(ObServerConfig) } } // end of namespace common +namespace obrpc { +bool enable_pkt_nio() { + return GCONF._enable_pkt_nio && GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_4_1_0_0; +} +} } // end of namespace oceanbase namespace easy diff --git a/src/share/deadlock/ob_lcl_scheme/ob_lcl_batch_sender_thread.cpp b/src/share/deadlock/ob_lcl_scheme/ob_lcl_batch_sender_thread.cpp index 5af1b038f..deb6fc19c 100644 --- a/src/share/deadlock/ob_lcl_scheme/ob_lcl_batch_sender_thread.cpp +++ b/src/share/deadlock/ob_lcl_scheme/ob_lcl_batch_sender_thread.cpp @@ -219,6 +219,7 @@ void ObLCLBatchSenderThread::run1() ObLCLBatchSenderThread::RemoveIfOp op(mock_lcl_message_list); lib::set_thread_name("LCLSender"); while(ATOMIC_LOAD(&is_running_)) { + IGNORE_RETURN lib::Thread::update_loop_ts(); int64_t _lcl_op_interval = ObServerConfig::get_instance()._lcl_op_interval; if (_lcl_op_interval == 0) {// 0 means deadlock is disabled if (lcl_msg_map_.count() != 0) { diff --git a/src/share/inner_table/ob_inner_table_schema.12351_12400.cpp b/src/share/inner_table/ob_inner_table_schema.12351_12400.cpp index 190387f5f..b063ea3a9 100644 --- a/src/share/inner_table/ob_inner_table_schema.12351_12400.cpp +++ b/src/share/inner_table/ob_inner_table_schema.12351_12400.cpp @@ -1761,6 +1761,195 @@ int ObInnerTableSchema::all_virtual_core_table_schema(ObTableSchema &table_schem return ret; } +int ObInnerTableSchema::all_virtual_malloc_sample_info_schema(ObTableSchema &table_schema) +{ + int ret = OB_SUCCESS; + uint64_t column_id = OB_APP_MIN_COLUMN_ID - 1; + + //generated fields: + table_schema.set_tenant_id(OB_SYS_TENANT_ID); + table_schema.set_tablegroup_id(OB_INVALID_ID); + table_schema.set_database_id(OB_SYS_DATABASE_ID); + table_schema.set_table_id(OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TID); + table_schema.set_rowkey_split_pos(0); + table_schema.set_is_use_bloomfilter(false); + table_schema.set_progressive_merge_num(0); + table_schema.set_rowkey_column_num(0); + table_schema.set_load_type(TABLE_LOAD_TYPE_IN_DISK); + table_schema.set_table_type(VIRTUAL_TABLE); + table_schema.set_index_type(INDEX_TYPE_IS_NOT); + table_schema.set_def_type(TABLE_DEF_TYPE_INTERNAL); + + if (OB_SUCC(ret)) { + if (OB_FAIL(table_schema.set_table_name(OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TNAME))) { + LOG_ERROR("fail to set table_name", K(ret)); + } + } + + if (OB_SUCC(ret)) { + if (OB_FAIL(table_schema.set_compress_func_name(OB_DEFAULT_COMPRESS_FUNC_NAME))) { + LOG_ERROR("fail to set compress_func_name", K(ret)); + } + } + table_schema.set_part_level(PARTITION_LEVEL_ZERO); + table_schema.set_charset_type(ObCharset::get_default_charset()); + table_schema.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("svr_ip", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 1, //part_key_pos + ObVarcharType, //column_type + CS_TYPE_INVALID, //column_collation_type + MAX_IP_ADDR_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("svr_port", //column_name + ++column_id, //column_id + 0, //rowkey_id + 0, //index_id + 2, //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("tenant_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("ctx_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("mod_name", //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_CHAR_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("back_trace", //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 + DEFAULT_BUF_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("ctx_name", //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_CHAR_LENGTH, //column_length + -1, //column_precision + -1, //column_scale + false, //is_nullable + false); //is_autoincrement + } + + if (OB_SUCC(ret)) { + ADD_COLUMN_SCHEMA("alloc_count", //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("alloc_bytes", //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)) { + table_schema.get_part_option().set_part_num(1); + table_schema.set_part_level(PARTITION_LEVEL_ONE); + table_schema.get_part_option().set_part_func_type(PARTITION_FUNC_TYPE_LIST_COLUMNS); + if (OB_FAIL(table_schema.get_part_option().set_part_expr("svr_ip, svr_port"))) { + LOG_WARN("set_part_expr failed", K(ret)); + } else if (OB_FAIL(table_schema.mock_list_partition_array())) { + LOG_WARN("mock list partition array failed", K(ret)); + } + } + table_schema.set_index_using_type(USING_HASH); + table_schema.set_row_store_type(ENCODING_ROW_STORE); + table_schema.set_store_format(OB_STORE_FORMAT_DYNAMIC_MYSQL); + table_schema.set_progressive_merge_round(1); + table_schema.set_storage_format_version(3); + table_schema.set_tablet_id(0); + + table_schema.set_max_used_column_id(column_id); + return ret; +} + int ObInnerTableSchema::all_virtual_ls_arb_replica_task_schema(ObTableSchema &table_schema) { int ret = OB_SUCCESS; diff --git a/src/share/inner_table/ob_inner_table_schema.h b/src/share/inner_table/ob_inner_table_schema.h index d7db05278..79f3f3807 100644 --- a/src/share/inner_table/ob_inner_table_schema.h +++ b/src/share/inner_table/ob_inner_table_schema.h @@ -865,6 +865,7 @@ public: static int all_virtual_rls_attribute_history_schema(share::schema::ObTableSchema &table_schema); static int all_virtual_tenant_mysql_sys_agent_schema(share::schema::ObTableSchema &table_schema); static int all_virtual_core_table_schema(share::schema::ObTableSchema &table_schema); + static int all_virtual_malloc_sample_info_schema(share::schema::ObTableSchema &table_schema); static int all_virtual_ls_arb_replica_task_schema(share::schema::ObTableSchema &table_schema); static int all_virtual_ls_arb_replica_task_history_schema(share::schema::ObTableSchema &table_schema); static int all_virtual_archive_dest_status_schema(share::schema::ObTableSchema &table_schema); @@ -2904,6 +2905,7 @@ const schema_create_func virtual_table_schema_creators [] = { ObInnerTableSchema::all_virtual_rls_attribute_history_schema, ObInnerTableSchema::all_virtual_tenant_mysql_sys_agent_schema, ObInnerTableSchema::all_virtual_core_table_schema, + ObInnerTableSchema::all_virtual_malloc_sample_info_schema, ObInnerTableSchema::all_virtual_ls_arb_replica_task_schema, ObInnerTableSchema::all_virtual_ls_arb_replica_task_history_schema, ObInnerTableSchema::all_virtual_archive_dest_status_schema, @@ -4264,6 +4266,7 @@ const uint64_t tenant_space_tables [] = { OB_ALL_VIRTUAL_LS_REPLICA_TASK_PLAN_TID, OB_ALL_VIRTUAL_SHOW_TRACE_TID, OB_ALL_VIRTUAL_TENANT_MYSQL_SYS_AGENT_TID, + OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TID, OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_TID, OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_HISTORY_TID, OB_ALL_VIRTUAL_ARCHIVE_DEST_STATUS_TID, @@ -6174,6 +6177,7 @@ const char* const tenant_space_table_names [] = { OB_ALL_VIRTUAL_LS_REPLICA_TASK_PLAN_TNAME, OB_ALL_VIRTUAL_SHOW_TRACE_TNAME, OB_ALL_VIRTUAL_TENANT_MYSQL_SYS_AGENT_TNAME, + OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TNAME, OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_TNAME, OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_HISTORY_TNAME, OB_ALL_VIRTUAL_ARCHIVE_DEST_STATUS_TNAME, @@ -7607,6 +7611,7 @@ const uint64_t tenant_distributed_vtables [] = { OB_ALL_VIRTUAL_DML_STATS_TID, OB_ALL_VIRTUAL_QUERY_RESPONSE_TIME_TID, OB_ALL_VIRTUAL_TABLET_COMPACTION_INFO_TID, + OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TID, OB_ALL_VIRTUAL_SQL_AUDIT_ORA_TID, OB_ALL_VIRTUAL_SQL_AUDIT_ORA_ALL_VIRTUAL_SQL_AUDIT_I1_TID, OB_ALL_VIRTUAL_PLAN_STAT_ORA_TID, @@ -9797,11 +9802,11 @@ static inline int get_sys_table_lob_aux_schema(const uint64_t tid, const int64_t OB_CORE_TABLE_COUNT = 4; const int64_t OB_SYS_TABLE_COUNT = 230; -const int64_t OB_VIRTUAL_TABLE_COUNT = 574; +const int64_t OB_VIRTUAL_TABLE_COUNT = 575; const int64_t OB_SYS_VIEW_COUNT = 654; -const int64_t OB_SYS_TENANT_TABLE_COUNT = 1463; +const int64_t OB_SYS_TENANT_TABLE_COUNT = 1464; const int64_t OB_CORE_SCHEMA_VERSION = 1; -const int64_t OB_BOOTSTRAP_SCHEMA_VERSION = 1466; +const int64_t OB_BOOTSTRAP_SCHEMA_VERSION = 1467; } // end namespace share } // end namespace oceanbase diff --git a/src/share/inner_table/ob_inner_table_schema_constants.h b/src/share/inner_table/ob_inner_table_schema_constants.h index b87f1afe5..dd095d64a 100644 --- a/src/share/inner_table/ob_inner_table_schema_constants.h +++ b/src/share/inner_table/ob_inner_table_schema_constants.h @@ -607,6 +607,7 @@ const uint64_t OB_ALL_VIRTUAL_RLS_ATTRIBUTE_TID = 12356; // "__all_virtual_rls_a const uint64_t OB_ALL_VIRTUAL_RLS_ATTRIBUTE_HISTORY_TID = 12357; // "__all_virtual_rls_attribute_history" const uint64_t OB_ALL_VIRTUAL_TENANT_MYSQL_SYS_AGENT_TID = 12358; // "__all_virtual_tenant_mysql_sys_agent" const uint64_t OB_ALL_VIRTUAL_CORE_TABLE_TID = 12362; // "__all_virtual_core_table" +const uint64_t OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TID = 12363; // "__all_virtual_malloc_sample_info" const uint64_t OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_TID = 12364; // "__all_virtual_ls_arb_replica_task" const uint64_t OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_HISTORY_TID = 12365; // "__all_virtual_ls_arb_replica_task_history" const uint64_t OB_ALL_VIRTUAL_ARCHIVE_DEST_STATUS_TID = 12366; // "__all_virtual_archive_dest_status" @@ -2630,6 +2631,7 @@ const char *const OB_ALL_VIRTUAL_RLS_ATTRIBUTE_TNAME = "__all_virtual_rls_attrib const char *const OB_ALL_VIRTUAL_RLS_ATTRIBUTE_HISTORY_TNAME = "__all_virtual_rls_attribute_history"; const char *const OB_ALL_VIRTUAL_TENANT_MYSQL_SYS_AGENT_TNAME = "__all_virtual_tenant_mysql_sys_agent"; const char *const OB_ALL_VIRTUAL_CORE_TABLE_TNAME = "__all_virtual_core_table"; +const char *const OB_ALL_VIRTUAL_MALLOC_SAMPLE_INFO_TNAME = "__all_virtual_malloc_sample_info"; const char *const OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_TNAME = "__all_virtual_ls_arb_replica_task"; const char *const OB_ALL_VIRTUAL_LS_ARB_REPLICA_TASK_HISTORY_TNAME = "__all_virtual_ls_arb_replica_task_history"; const char *const OB_ALL_VIRTUAL_ARCHIVE_DEST_STATUS_TNAME = "__all_virtual_archive_dest_status"; 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 065fcd126..bb26d0970 100644 --- a/src/share/inner_table/ob_inner_table_schema_def.py +++ b/src/share/inner_table/ob_inner_table_schema_def.py @@ -11321,7 +11321,29 @@ def_table_schema(**gen_iterate_virtual_table_def( table_name = '__all_virtual_core_table', keywords = all_def_keywords['__all_core_table'])) -# 12363: __all_virtual_malloc_sample_info +def_table_schema( + owner = 'tushicheng.tsc', + table_name = '__all_virtual_malloc_sample_info', + table_id = '12363', + table_type = 'VIRTUAL_TABLE', + gm_columns = [], + in_tenant_space = True, + rowkey_columns = [], + + normal_columns = [ + ('svr_ip', 'varchar:MAX_IP_ADDR_LENGTH'), + ('svr_port', 'int'), + ('tenant_id', 'int'), + ('ctx_id', 'int'), + ('mod_name', 'varchar:OB_MAX_CHAR_LENGTH'), + ('back_trace', 'varchar:DEFAULT_BUF_LENGTH'), + ('ctx_name', 'varchar:OB_MAX_CHAR_LENGTH'), + ('alloc_count', 'int'), + ('alloc_bytes', 'int'), + ], + vtable_route_policy = 'distributed', + partition_columns = ['svr_ip', 'svr_port'], +) def_table_schema(**gen_iterate_private_virtual_table_def( table_id = '12364', diff --git a/src/share/location_cache/ob_tablet_ls_service.cpp b/src/share/location_cache/ob_tablet_ls_service.cpp index 4270b7415..407ef69a5 100644 --- a/src/share/location_cache/ob_tablet_ls_service.cpp +++ b/src/share/location_cache/ob_tablet_ls_service.cpp @@ -45,7 +45,7 @@ int ObTabletLSService::init(common::ObMySQLProxy &sql_proxy) LOG_WARN("init twice", KR(ret)); } else if (OB_FAIL(inner_cache_.init())) { LOG_WARN("inner_cache init failed", KR(ret)); - } else if (OB_FAIL(async_queue_.init(this, user_thread_cnt, user_queue_size))) { + } else if (OB_FAIL(async_queue_.init(this, user_thread_cnt, user_queue_size, "TbltLSSrv"))) { LOG_WARN("async_queue init failed", KR(ret), K(user_thread_cnt), K(user_queue_size)); } else { diff --git a/src/share/ob_common_rpc_proxy.h b/src/share/ob_common_rpc_proxy.h index 56e091130..6abea37c6 100644 --- a/src/share/ob_common_rpc_proxy.h +++ b/src/share/ob_common_rpc_proxy.h @@ -398,25 +398,6 @@ protected: CALL_WITH_RETRY(ObRpcProxy::rpc_call(pcode, args, result, handle, opts)); } - template - int rpc_call(ObRpcPacketCode pcode, - const Input &args, Handle *handle, const ObRpcOpts &opts) - { - CALL_WITH_RETRY(ObRpcProxy::rpc_call(pcode, args, handle, opts)); - } - - template - int rpc_call(ObRpcPacketCode pcode, Output &result, - Handle *handle, const ObRpcOpts &opts) - { - CALL_WITH_RETRY(ObRpcProxy::rpc_call(pcode, result, handle, opts)); - } - - int rpc_call(ObRpcPacketCode pcode, Handle *handle, const ObRpcOpts &opts) - { - CALL_WITH_RETRY(ObRpcProxy::rpc_call(pcode, handle, opts)); - } - template int rpc_post(ObRpcPacketCode pcode, const Input &args, rpc::frame::ObReqTransport::AsyncCB *cb, const ObRpcOpts &opts) diff --git a/src/share/ob_ddl_task_executor.cpp b/src/share/ob_ddl_task_executor.cpp index 420200d8d..984dcba0e 100644 --- a/src/share/ob_ddl_task_executor.cpp +++ b/src/share/ob_ddl_task_executor.cpp @@ -240,7 +240,7 @@ void ObDDLTaskExecutor::run1() int64_t executed_task_count = 0; ObIDDLTask *task = NULL; ObIDDLTask *first_retry_task = NULL; - (void)prctl(PR_SET_NAME, "DDLTaskExecutor", 0, 0, 0); + lib::set_thread_name("DDLTaskExecutor"); while (!has_set_stop()) { while (!has_set_stop() && executed_task_count < BATCH_EXECUTE_COUNT) { if (OB_FAIL(task_queue_.get_next_task(task))) { diff --git a/src/share/ob_debug_sync.cpp b/src/share/ob_debug_sync.cpp index a583bcfa6..2860d0da9 100644 --- a/src/share/ob_debug_sync.cpp +++ b/src/share/ob_debug_sync.cpp @@ -982,7 +982,7 @@ ObDebugSync &ObDebugSync::instance() ObDSActionArray *ObDebugSync::thread_local_actions() const { - return GET_TSI_MULT(ObDSActionArray, TSI_COMMON_DEBUG_SYNC_ARRAY); + return GET_TSI(ObDSActionArray); } ObDSActionArray &ObDebugSync::rpc_spread_actions() const diff --git a/src/share/ob_occam_thread_pool.h b/src/share/ob_occam_thread_pool.h index 2f1a17bc9..57539c14a 100644 --- a/src/share/ob_occam_thread_pool.h +++ b/src/share/ob_occam_thread_pool.h @@ -341,6 +341,7 @@ private: int ret = OB_SUCCESS; ObFunction function; while (true) { // keep fetching task and do the task until thread pool is stopped + IGNORE_RETURN lib::Thread::update_loop_ts(ObTimeUtility::fast_current_time()); bool is_stopped = false; { ObThreadCondGuard guard(cv_); diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 7c479fbac..966815e0e 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -250,6 +250,16 @@ DEF_INT_WITH_CHECKER(_enable_defensive_check, OB_CLUSTER_PARAMETER, "1", "2 means more strict defensive check is enabled, such as check partition id validity", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(_min_malloc_sample_interval, OB_CLUSTER_PARAMETER, "16", "[1, 10000]", + "the min malloc times between two samples, " + "which is not more than _max_malloc_sample_interval. " + "10000 means not to sample any malloc, Range: [1, 10000]", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(_max_malloc_sample_interval, OB_CLUSTER_PARAMETER, "256", "[1, 10000]", + "the max malloc times between two samples, " + "which is not less than _min_malloc_sample_interval. " + "1 means to sample all malloc, Range: [1, 10000]", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); //// tenant config DEF_TIME_WITH_CHECKER(max_stale_time_for_weak_consistency, OB_TENANT_PARAMETER, "5s", common::ObConfigStaleTimeChecker, @@ -331,7 +341,9 @@ DEF_STR_WITH_CHECKER(_ctx_memory_limit, OB_TENANT_PARAMETER, "", DEF_BOOL(_enable_convert_real_to_decimal, OB_TENANT_PARAMETER, "False", "specifies whether convert column type float(M,D), double(M,D) to decimal(M,D) in DDL", ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); - +DEF_BOOL(_ob_enable_dynamic_worker, OB_TENANT_PARAMETER, "True", + "specifies whether worker count increases when all workers were in blocking.", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::STATIC_EFFECTIVE)); // tenant memtable consumption related DEF_INT(memstore_limit_percentage, OB_CLUSTER_PARAMETER, "50", "(0, 100)", @@ -679,6 +691,14 @@ DEF_TIME(_ob_get_gts_ahead_interval, OB_CLUSTER_PARAMETER, "0s", "[0s, 1s]", DEF_TIME(rpc_timeout, OB_CLUSTER_PARAMETER, "2s", "the time during which a RPC request is permitted to execute before it is terminated", ObParameterAttr(Section::RPC, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_enable_pkt_nio, OB_CLUSTER_PARAMETER, "False", + "enable pkt-nio, the new RPC framework" + "Value: True:turned on; False: turned off", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(tenant_rpc_memory_limit_percentage, OB_TENANT_PARAMETER, "0", "[0,100]", + "maximum memory for rpc in a tenant, as a percentage of total tenant memory, " + "and 0 means no limit to rpc memory", + ObParameterAttr(Section::RPC, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); //// location cache config DEF_TIME(virtual_table_location_cache_expire_time, OB_CLUSTER_PARAMETER, "8s", "[1s,)", @@ -1306,6 +1326,19 @@ DEF_INT(sql_login_thread_count, OB_CLUSTER_PARAMETER, "0", "[0,32]", "the number of threads for sql login request. Range: [0, 32] in integer, 0 stands for use default thread count defined in TG." "the default thread count for login request in TG is normal:6 mini-mode:2", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(tenant_sql_login_thread_count, OB_TENANT_PARAMETER, "0", "[0,32]", + "the number of threads for sql login request of each tenant. Range: [0, 32] in integer, 0 stands for unit_min_cpu", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(tenant_sql_net_thread_count, OB_TENANT_PARAMETER, "0", "[0, 64]", + "the number of mysql I/O threads for a tenant. Range: [0, 64] in integer, 0 stands for unit_min_cpu", + ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_INT(sql_net_thread_count, OB_CLUSTER_PARAMETER, "0", "[0,64]", + "the number of global mysql I/O threads. Range: [0, 64] in integer, " + "default value is 0, 0 stands for old value GCONF.net_thread_count", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_enable_tenant_sql_net_thread, OB_CLUSTER_PARAMETER, "True", + "Dispatch mysql request to each tenant with True, or disable with False", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); #ifndef ENABLE_SANITY #else DEF_STR_LIST(sanity_whitelist, OB_CLUSTER_PARAMETER, "", "vip who wouldn't leading to coredump", diff --git a/src/share/rc/ob_tenant_base.h b/src/share/rc/ob_tenant_base.h index 3cba99d8c..77866cc0c 100644 --- a/src/share/rc/ob_tenant_base.h +++ b/src/share/rc/ob_tenant_base.h @@ -34,7 +34,10 @@ namespace omt { class ObPxPools; class ObTenant; } -namespace obmysql { class ObMySQLRequestManager; } +namespace obmysql { + class ObMySQLRequestManager; + class ObSqlNioServer; +} namespace sql { namespace dtl { class ObTenantDfc; } class ObTenantSqlMemoryManager; @@ -131,6 +134,7 @@ namespace rootserver namespace observer { class ObTenantMetaChecker; + class QueueThread; class ObTableLoadService; } @@ -192,6 +196,7 @@ using ObPartTransCtxObjPool = common::ObServerObjectPoold_name, ".") || 0 == strcmp(subdir->d_name, "..")) { + // skip . and .. + } else { + snprintf(sub_path, PATH_BUFSIZE, "%s/%s", curr_path, subdir->d_name); + if (OB_FAIL(FileDirectoryUtils::is_directory(sub_path, tmp_result))) { + LOG_WARN("judge is directory failed", K(sub_path)); + } else if (true == tmp_result) { + type = REGULAR_DIR; + break; + } + } + } + } + return ret; +} + +int ObCgroupCtrl::remove_dir_(const char *curr_dir) +{ + int ret = OB_SUCCESS; + char group_task_path[PATH_BUFSIZE]; + char parent_task_path[PATH_BUFSIZE]; + snprintf(group_task_path, PATH_BUFSIZE, "%s/tasks", curr_dir); + snprintf(parent_task_path, PATH_BUFSIZE, "%s/../tasks", curr_dir); + FILE* group_task_file = nullptr; + if (OB_ISNULL(group_task_file = fopen(group_task_path, "r"))) { + ret = OB_IO_ERROR; + LOG_WARN("open group failed", K(ret), K(group_task_path), K(errno), KERRMSG); + } else { + char tid_buf[VALUE_BUFSIZE]; + while (fgets(tid_buf, VALUE_BUFSIZE, group_task_file)) { + if (OB_FAIL(write_string_to_file_(parent_task_path, tid_buf))) { + LOG_WARN("remove tenant task failed", K(ret), K(parent_task_path)); + break; + } + } + fclose(group_task_file); + } + if (OB_SUCC(ret) && OB_FAIL(FileDirectoryUtils::delete_directory(curr_dir))) { + LOG_WARN("remove group directory failed", K(ret), K(curr_dir)); + } else { + LOG_INFO("remove group directory success", K(curr_dir)); + } + return ret; +} + +int ObCgroupCtrl::recursion_remove_group_(const char *curr_path) +{ + int ret = OB_SUCCESS; + int type = NOT_DIR; + if (OB_FAIL(which_type_dir_(curr_path, type))) { + LOG_WARN("check dir type failed", K(ret), K(curr_path)); + } else if (NOT_DIR == type) { + // not directory, skip + } else if (LEAF_DIR == type) { + if (OB_FAIL(remove_dir_(curr_path))) { + LOG_WARN("remove sub group directory failed", K(ret), K(curr_path)); + } else { + LOG_INFO("remove sub group directory success", K(curr_path)); + } + } else { + DIR *dir = nullptr; + if (NULL == (dir = opendir(curr_path))){ + ret = OB_ERR_UNEXPECTED; + LOG_WARN("open dir failed", K(curr_path)); + } else { + struct dirent *subdir = nullptr; + char sub_path[PATH_BUFSIZE]; + while (OB_SUCCESS == ret && (NULL != (subdir = readdir(dir)))) { + if (0 == strcmp(subdir->d_name, ".") || 0 == strcmp(subdir->d_name, "..")) { + // skip . and .. + } else if (PATH_BUFSIZE <= snprintf(sub_path, PATH_BUFSIZE, "%s/%s", curr_path, subdir->d_name)) { // to prevent infinite recursion when path string is over size and cut off + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sub_path is oversize has been cut off", K(ret), K(sub_path), K(curr_path)); + } else if (OB_FAIL(recursion_remove_group_(sub_path))) { + LOG_WARN("remove path failed", K(sub_path)); + } + } + if (OB_FAIL(remove_dir_(curr_path))) { + LOG_WARN("remove sub group directory failed", K(ret), K(curr_path)); + } else { + LOG_INFO("remove sub group directory success", K(curr_path)); + } + } + } + return ret; +} + int ObCgroupCtrl::remove_tenant_cgroup(const uint64_t tenant_id) { int ret = OB_SUCCESS; char tenant_path[PATH_BUFSIZE]; - char tenant_task_path[PATH_BUFSIZE]; - char other_task_path[PATH_BUFSIZE]; - snprintf(tenant_path, PATH_BUFSIZE, "%s/tenant_%04lu", root_cgroup_, tenant_id); - snprintf(tenant_task_path, PATH_BUFSIZE, "%s/tenant_%04lu/tasks", root_cgroup_, tenant_id); - snprintf(other_task_path, PATH_BUFSIZE, "%s/tasks", other_cgroup_); - FILE* tenant_task_file = nullptr; - if (OB_ISNULL(tenant_task_file = fopen(tenant_task_path, "r"))) { - ret = OB_IO_ERROR; - LOG_WARN("open tenant task path failed", K(ret), K(tenant_task_path), K(errno), KERRMSG); - } else { - char tid_buf[VALUE_BUFSIZE]; - while (fgets(tid_buf, VALUE_BUFSIZE, tenant_task_file)) { - if (OB_FAIL(write_string_to_file_(other_task_path, tid_buf))) { - LOG_WARN("remove tenant task failed", K(ret), K(other_task_path), K(tenant_id)); - break; - } - } - fclose(tenant_task_file); - } - if (OB_SUCC(ret) && OB_FAIL(FileDirectoryUtils::delete_directory(tenant_path))) { + if (OB_FAIL(get_group_path(tenant_path, PATH_BUFSIZE, tenant_id))) { + LOG_WARN("fail get group path", K(tenant_id), K(ret)); + } else if (OB_FAIL(recursion_remove_group_(tenant_path))) { LOG_WARN("remove tenant cgroup directory failed", K(ret), K(tenant_path), K(tenant_id)); } else { LOG_INFO("remove tenant cgroup directory success", K(tenant_path), K(tenant_id)); @@ -186,14 +274,20 @@ int ObCgroupCtrl::get_group_path( int ret = OB_SUCCESS; char *group_name = nullptr; share::ObGroupName g_name; + char tenant_path[PATH_BUFSIZE]; + if (is_meta_tenant(tenant_id)) { + snprintf(tenant_path, PATH_BUFSIZE, "tenant_%04lu/tenant_%04lu", gen_user_tenant_id(tenant_id), tenant_id); + } else { + snprintf(tenant_path, PATH_BUFSIZE, "tenant_%04lu", tenant_id); + } if (INT64_MAX == group_id) { - snprintf(group_path, path_bufsize, "%s/tenant_%04lu", - root_cgroup_, tenant_id); + snprintf(group_path, path_bufsize, "%s/%s", + root_cgroup_, tenant_path); } else if (group_id < OBCG_MAXNUM) { ObCgSet &set = ObCgSet::instance(); group_name = const_cast(set.name_of_id(group_id)); - snprintf(group_path, path_bufsize, "%s/tenant_%04lu/%s", - root_cgroup_, tenant_id, group_name); + snprintf(group_path, path_bufsize, "%s/%s/%s", + root_cgroup_, tenant_path, group_name); } else if (OB_FAIL(get_group_info_by_group_id(tenant_id, group_id, g_name))){ LOG_WARN("get group_name by id failed", K(group_id), K(ret)); } else { diff --git a/src/share/resource_manager/ob_cgroup_ctrl.h b/src/share/resource_manager/ob_cgroup_ctrl.h index 3e8424b78..4ca1fd455 100644 --- a/src/share/resource_manager/ob_cgroup_ctrl.h +++ b/src/share/resource_manager/ob_cgroup_ctrl.h @@ -225,7 +225,10 @@ private: int get_group_info_by_group_id(const uint64_t tenant_id, int64_t group_id, share::ObGroupName &group_name); - + enum { NOT_DIR = 0, LEAF_DIR, REGULAR_DIR }; + int which_type_dir_(const char *curr_path, int &result); + int remove_dir_(const char *curr_dir); + int recursion_remove_group_(const char *curr_path); }; } // share diff --git a/src/share/resource_manager/ob_group_list.h b/src/share/resource_manager/ob_group_list.h index 447591743..43e628de1 100644 --- a/src/share/resource_manager/ob_group_list.h +++ b/src/share/resource_manager/ob_group_list.h @@ -11,3 +11,6 @@ CGID_DEF(OBCG_ID_SQL_REQ_LEVEL2, 7, 4) CGID_DEF(OBCG_ID_SQL_REQ_LEVEL3, 8, 4) CGID_DEF(OBCG_DETECT_RS, 9) CGID_DEF(OBCG_LOC_CACHE, 10) +CGID_DEF(OBCG_SQL_NIO, 11) +CGID_DEF(OBCG_MYSQL_LOGIN, 12) +CGID_DEF(OBCG_LQ, 100) diff --git a/src/share/restore/ob_log_restore_source.h b/src/share/restore/ob_log_restore_source.h index d83ad6137..d3759217f 100644 --- a/src/share/restore/ob_log_restore_source.h +++ b/src/share/restore/ob_log_restore_source.h @@ -18,8 +18,10 @@ #include "lib/utility/ob_macro_utils.h" #include "lib/utility/ob_print_utils.h" #include "lib/worker.h" +#include "lib/allocator/page_arena.h" #include "share/scn.h" #include + namespace oceanbase { namespace share @@ -61,7 +63,7 @@ struct ObLogRestoreSourceItem ObLogRestoreSourceType type_; common::ObString value_; SCN until_scn_; - lib::ObArenaAllocator allocator_; + common::ObArenaAllocator allocator_; ObLogRestoreSourceItem() : tenant_id_(), id_(), diff --git a/src/share/scheduler/ob_dag_scheduler.h b/src/share/scheduler/ob_dag_scheduler.h index 7408933a4..4d8d9148a 100644 --- a/src/share/scheduler/ob_dag_scheduler.h +++ b/src/share/scheduler/ob_dag_scheduler.h @@ -15,6 +15,7 @@ #include "lib/ob_define.h" #include "lib/allocator/ob_concurrent_fifo_allocator.h" +#include "lib/allocator/ob_fifo_allocator.h" #include "lib/container/ob_se_array.h" #include "lib/hash/ob_hashmap.h" #include "lib/list/ob_dlink_node.h" diff --git a/src/sql/executor/ob_maintain_dependency_info_task.cpp b/src/sql/executor/ob_maintain_dependency_info_task.cpp index 92a7ab2ad..1946190bb 100644 --- a/src/sql/executor/ob_maintain_dependency_info_task.cpp +++ b/src/sql/executor/ob_maintain_dependency_info_task.cpp @@ -212,6 +212,7 @@ void ObMaintainDepInfoTaskQueue::run2() } else { ObAddr zero_addr; while (!stop_) { + IGNORE_RETURN lib::Thread::update_loop_ts(); if (REACH_TIME_INTERVAL(6 * 1000 * 1000)) { if (0 == queue_.size() && 0 != view_info_set_.size()) { LOG_WARN("queue size not match", K(queue_.size()), K(view_info_set_.size())); diff --git a/src/sql/resolver/ob_resolver_define.h b/src/sql/resolver/ob_resolver_define.h index 12c0100b7..a1f0bd2b8 100644 --- a/src/sql/resolver/ob_resolver_define.h +++ b/src/sql/resolver/ob_resolver_define.h @@ -126,11 +126,12 @@ inline const char *get_scope_name(const ObStmtScope &scope) //don't use me in other place enum { CSTRING_BUFFER_LEN = 1024 }; + inline char *get_sql_string_buffer() { char *ret = nullptr; const int64_t BUF_COUNT = 8; - char *buf = reinterpret_cast(GET_TSI(char[BUF_COUNT*CSTRING_BUFFER_LEN])); + char *buf = reinterpret_cast(GET_TSI(ByteBuf)); RLOCAL_INLINE(uint32_t, cur_buf_idx); if (OB_LIKELY(buf != nullptr)) { char (&BUFFERS)[BUF_COUNT][CSTRING_BUFFER_LEN] diff --git a/src/storage/blocksstable/ob_micro_block_cache.cpp b/src/storage/blocksstable/ob_micro_block_cache.cpp index 02d45d4f1..c7563b641 100644 --- a/src/storage/blocksstable/ob_micro_block_cache.cpp +++ b/src/storage/blocksstable/ob_micro_block_cache.cpp @@ -171,6 +171,7 @@ int ObMicroBlockCacheValue::deep_copy(char *buf, const int64_t buf_len, ObIKVCac ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate decoder allocator", K(ret)); } else if (OB_ISNULL(transformer = GET_TSI_MULT(ObIndexBlockDataTransformer, 1))) { + // There must be get_decoder_allocator before GET_TSI_MULT(ObIndexBlockDataTransformer) ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Fail to get thread local index block data transformer", K(ret)); } else if (OB_FAIL(transformer->update_index_block( @@ -1258,7 +1259,12 @@ int ObIndexMicroBlockCache::write_extra_buf(const ObTableReadInfo &read_info, int ret = OB_SUCCESS; ObIndexBlockDataTransformer *transformer = nullptr; - if (OB_ISNULL(transformer = GET_TSI_MULT(ObIndexBlockDataTransformer, 1))) { + ObDecoderAllocator* allocator = nullptr; + if (OB_ISNULL(allocator = get_decoder_allocator())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate decoder allocator", K(ret)); + } else if (OB_ISNULL(transformer = GET_TSI_MULT(ObIndexBlockDataTransformer, 1))) { + // There must be get_decoder_allocator before GET_TSI_MULT(ObIndexBlockDataTransformer) ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Fail to allocate ObIndexBlockDataTransformer", K(ret)); } else if (OB_FAIL(transformer->transform(read_info, micro_data, extra_buf, extra_size))) { diff --git a/src/storage/blocksstable/ob_sstable_meta_info.cpp b/src/storage/blocksstable/ob_sstable_meta_info.cpp index ad3a3e323..15a3e9c06 100644 --- a/src/storage/blocksstable/ob_sstable_meta_info.cpp +++ b/src/storage/blocksstable/ob_sstable_meta_info.cpp @@ -231,6 +231,7 @@ int ObRootBlockInfo::transform_root_block_data(const ObTableReadInfo &read_info) ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate decoder allocator", K(ret)); } else if (OB_ISNULL(transformer = GET_TSI_MULT(ObIndexBlockDataTransformer, 1))) { + // There must be get_decoder_allocator before GET_TSI_MULT(ObIndexBlockDataTransformer) ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate transformer", K(ret)); } else { diff --git a/src/storage/slog/ob_storage_log_writer.cpp b/src/storage/slog/ob_storage_log_writer.cpp index 914b2e540..0f0c9f283 100644 --- a/src/storage/slog/ob_storage_log_writer.cpp +++ b/src/storage/slog/ob_storage_log_writer.cpp @@ -689,7 +689,7 @@ void ObStorageLogWriter::ObSLogWriteRunner::wait() void ObStorageLogWriter::ObSLogWriteRunner::run1() { STORAGE_REDO_LOG(INFO, "ObSLogWriteRunner run", K(tg_id_), K(is_inited_)); - lib::set_thread_name_inner(log_writer_->get_thread_name()); + lib::set_thread_name(log_writer_->get_thread_name()); log_writer_->flush_log(); } diff --git a/src/storage/tablet/ob_tablet_memtable_mgr.cpp b/src/storage/tablet/ob_tablet_memtable_mgr.cpp index f000c15a4..fe79c88ca 100644 --- a/src/storage/tablet/ob_tablet_memtable_mgr.cpp +++ b/src/storage/tablet/ob_tablet_memtable_mgr.cpp @@ -40,7 +40,7 @@ ObTabletMemtableMgr::ObTabletMemtableMgr() medium_info_recorder_() { #if defined(__x86_64__) - static_assert(sizeof(ObTabletMemtableMgr) <= 448, "The size of ObTabletMemtableMgr will affect the meta memory manager, and the necessity of adding new fields needs to be considered."); + static_assert(sizeof(ObTabletMemtableMgr) <= 480, "The size of ObTabletMemtableMgr will affect the meta memory manager, and the necessity of adding new fields needs to be considered."); #endif } diff --git a/src/storage/tx/ob_trans_ctx_lock.h b/src/storage/tx/ob_trans_ctx_lock.h index 22d2b4605..74265a7cf 100644 --- a/src/storage/tx/ob_trans_ctx_lock.h +++ b/src/storage/tx/ob_trans_ctx_lock.h @@ -54,22 +54,6 @@ public: memtable::ObIMemtableCtx *p_mt_ctx_; }; -class LocalTaskFactory -{ -public: - static LocalTask *alloc(int64_t msg_type) - { return op_reclaim_alloc_args(LocalTask, msg_type); } - static void release(const LocalTask *task) - { - if (NULL == task) { - TRANS_LOG_RET(ERROR, common::OB_INVALID_ARGUMENT, "task is null", KP(task)); - } else { - op_reclaim_free(const_cast(task)); - task = NULL; - } - } -}; - class CtxLock { public: diff --git a/src/storage/tx/ob_tx_api.cpp b/src/storage/tx/ob_tx_api.cpp index 3c4269200..ace43d374 100644 --- a/src/storage/tx/ob_tx_api.cpp +++ b/src/storage/tx/ob_tx_api.cpp @@ -1679,7 +1679,12 @@ int ObTransService::start_epoch_(ObTxDesc &tx) TRANS_LOG(INFO, "tx start new epoch", K(ret), K(tx)); } ObTransTraceLog &tlog = tx.get_tlog(); - REC_TRANS_TRACE_EXT(&tlog, start_epoch, OB_Y(ret), OB_ID(opid), tx.op_sn_); + int tlog_truncate_cnt = 0; + if (OB_SUCC(ret) && tlog.count() > 50) { + tlog_truncate_cnt = tlog.count() - 10; + tlog.set_count(10); + } + REC_TRANS_TRACE_EXT(&tlog, start_epoch, OB_Y(ret), OB_ID(opid), tx.op_sn_, OB_ID(tag1), tlog_truncate_cnt); return ret; } diff --git a/src/storage/tx/ob_tx_free_route_msg.h b/src/storage/tx/ob_tx_free_route_msg.h index 130b953b3..7ad2253ec 100644 --- a/src/storage/tx/ob_tx_free_route_msg.h +++ b/src/storage/tx/ob_tx_free_route_msg.h @@ -11,9 +11,7 @@ struct ObTxFreeRouteMsg const int type_; virtual bool is_valid() const = 0; DECLARE_PURE_VIRTUAL_TO_STRING; - virtual SERIALIZE_SIGNATURE(serialize) = 0; - virtual DESERIALIZE_SIGNATURE(deserialize) = 0; - virtual GET_SERIALIZE_SIZE_SIGNATURE(get_serialize_size) = 0; + PURE_VIRTUAL_NEED_SERIALIZE_AND_DESERIALIZE; }; struct ObTxFreeRoutePushState diff --git a/src/storage/tx/ob_tx_serialization.h b/src/storage/tx/ob_tx_serialization.h index e1c7ece6d..1a0100fd1 100644 --- a/src/storage/tx/ob_tx_serialization.h +++ b/src/storage/tx/ob_tx_serialization.h @@ -232,43 +232,27 @@ private: } #define OB_TX_SERIALIZE_MEMBER(CLS, COMPAT_ARG, ...) \ - OB_TX_SERIALIZE_MEMBER_TEMP(, CLS, COMPAT_ARG, ##__VA_ARGS__) - -#define OB_TX_SERIALIZE_MEMBER_TEMP(TEMP, CLS, COMPAT_ARG, ...) \ - OB_TX_SERIALIZE_MEMBER_TEMP_IF(TEMP, CLS, COMPAT_ARG, true, ##__VA_ARGS__) - -#define OB_TX_SERIALIZE_MEMBER_TEMP_IF(TEMP, CLS, COMPAT_ARG, PRED, ...) \ - OB_TX_SERIALIZE_MEMBER_COMPAT_TEMP_IF(, TEMP, CLS, COMPAT_ARG, PRED, ##__VA_ARGS__) - -#define OB_TX_SERIALIZE_MEMBER_COMPAT_TEMP_IF(COMPAT, TEMP, CLS, COMPAT_ARG, PRED, ...) \ - OB_DEF_SERIALIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ + OB_DEF_SERIALIZE(CLS) \ { \ int ret = OK_; \ UNF_UNUSED_SER; \ - BASE_SER(CLS); \ - if (PRED) { \ TX_SER_COMPAT_BYTES(COMPAT_ARG); \ TX_LST_DO_CODE(OB_TX_UNIS_ENCODE, COMPAT_ARG, ##__VA_ARGS__); \ - } \ return ret; \ } \ - OB_DEF_DESERIALIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ + OB_DEF_DESERIALIZE(CLS) \ { \ int ret = OK_; \ UNF_UNUSED_DES; \ - BASE_DESER(CLS); \ TX_DSER_COMPAT_BYTES(COMPAT_ARG); \ TX_LST_DO_CODE(OB_TX_UNIS_DECODE, COMPAT_ARG, ##__VA_ARGS__); \ return ret; \ } \ - OB_DEF_SERIALIZE_SIZE##COMPAT(UNF_MYCLS(CLS), TEMP) \ + OB_DEF_SERIALIZE_SIZE(CLS) \ { \ int64_t len = 0; \ - BASE_ADD_LEN(CLS); \ - if (PRED) { \ TX_SER_SIZE_COMPAT_BYTES(COMPAT_ARG); \ TX_LST_DO_CODE(OB_TX_UNIS_ADD_LEN, COMPAT_ARG, ##__VA_ARGS__); \ - } \ return len; \ } 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 78ceee219..930171147 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 @@ -188,6 +188,7 @@ server_cpu_quota_max server_cpu_quota_min server_permanent_offline_time sql_login_thread_count +sql_net_thread_count sql_work_area ssl_client_authentication ssl_external_kms_info @@ -209,6 +210,9 @@ tcp_keepidle tcp_keepintvl tde_method tenant_cpu_variation_per_server +tenant_rpc_memory_limit_percentage +tenant_sql_login_thread_count +tenant_sql_net_thread_count tenant_task_queue_size token_reserved_percentage trace_log_sampling_interval @@ -252,12 +256,14 @@ _enable_new_sql_nio _enable_oracle_priv_check _enable_parallel_minor_merge _enable_partition_level_retry +_enable_pkt_nio _enable_plan_cache_mem_diagnosis _enable_protocol_diagnose _enable_px_batch_rescan _enable_px_bloom_filter_sync _enable_px_ordered_coord _enable_resource_limit_spec +_enable_tenant_sql_net_thread _enable_trace_session_leak _enable_transaction_internal_routing _fast_commit_callback_count @@ -272,14 +278,17 @@ _large_query_io_percentage _lcl_op_interval _load_tde_encrypt_engine _max_elr_dependent_trx_count +_max_malloc_sample_interval _max_schema_slot_num _migrate_block_verify_level _minor_compaction_amplification_factor _minor_compaction_interval +_min_malloc_sample_interval _mvcc_gc_using_min_txn_snapshot _ob_ddl_timeout _ob_elr_fast_freeze_threshold _ob_enable_direct_load +_ob_enable_dynamic_worker _ob_enable_fast_freeze _ob_enable_fast_parser _ob_enable_prepared_statement diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/inner_table_overall.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/inner_table_overall.result index 2773aab3b..a5598a8ed 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/inner_table_overall.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/inner_table_overall.result @@ -579,6 +579,7 @@ select 0xffffffffff & table_id, table_name, table_type, database_id, part_num fr 12357 __all_virtual_rls_attribute_history 2 201001 1 12358 __all_virtual_tenant_mysql_sys_agent 2 201001 1 12362 __all_virtual_core_table 2 201001 1 +12363 __all_virtual_malloc_sample_info 2 201001 1 12364 __all_virtual_ls_arb_replica_task 2 201001 1 12365 __all_virtual_ls_arb_replica_task_history 2 201001 1 12366 __all_virtual_archive_dest_status 2 201001 1 diff --git a/unittest/observer/CMakeLists.txt b/unittest/observer/CMakeLists.txt index 1074cfb96..5bcbeb5db 100644 --- a/unittest/observer/CMakeLists.txt +++ b/unittest/observer/CMakeLists.txt @@ -1,5 +1,4 @@ #ob_unittest(test_manage_tenant omt/test_manage_tenant.cpp) -storage_unittest(test_worker_pool omt/test_worker_pool.cpp) storage_unittest(test_hfilter_parser table/test_hfilter_parser.cpp) storage_unittest(test_query_response_time mysql/test_query_response_time.cpp) storage_unittest(test_create_executor table/test_create_executor.cpp) diff --git a/unittest/observer/omt/test_worker_pool.cpp b/unittest/observer/omt/test_worker_pool.cpp deleted file mode 100644 index a7a7e960c..000000000 --- a/unittest/observer/omt/test_worker_pool.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 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. - */ - -#include - -#include "observer/omt/ob_worker_pool.h" -#include "observer/omt/ob_worker_processor.h" -#include "observer/ob_server_struct.h" - -using namespace oceanbase::common; -using namespace oceanbase::omt; -using namespace oceanbase::observer; - -class TestWorkerPool - : public ::testing::Test -{ -public: - TestWorkerPool() - : pool_() - {} - - virtual void SetUp() - { - ASSERT_EQ(OB_SUCCESS, pool_.init(1, 5)); - } - - virtual void TearDown() - { - pool_.destroy(); - } - -protected: - ObGlobalContext gctx_; - ObWorkerPool pool_; -}; - -TEST_F(TestWorkerPool, TestName) -{ - ObThWorker* ws[10] = {NULL}; - for (int i = 0; i < 10; ++i) { - ObThWorker *w = pool_.alloc(); - EXPECT_TRUE(w); - ws[i] = w; - } - //EXPECT_FALSE(pool_.alloc()); - for (int i = 0; i < 10; ++i) { - pool_.free(ws[i]); - } -} - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}