Compare commits

..

194 Commits

Author SHA1 Message Date
vazmin 795b328bd6 gh actions: upgrade to 1.0.83-1 2025-11-23 10:47:37 +00:00
vazmin ac5f4a584f gh actions: upgrade to 1.0.83-1 2025-11-23 10:00:00 +00:00
vazmin c044906e63 gh actions: upgrade to 1.0.83-1 2025-11-23 09:05:57 +00:00
YuQing ccc84945d3 INSTALL changed 2025-11-18 14:47:17 +08:00
YuQing c4b6f1fcb5 upgrade version to 1.0.83 2025-11-16 17:00:25 +08:00
YuQing 017ca1efe7 comment out useless codes 2025-11-16 16:54:16 +08:00
YuQing 71b2229427 fast_task_queue.h: remove field finish_callback 2025-11-15 11:13:15 +08:00
YuQing 446fa6b815 libfastcommon.spec: correct expr statement 2025-11-12 16:39:36 +08:00
YuQing 98948c11bf downgrade required liburing from V2.5 to V2.4 2025-11-12 10:28:44 +08:00
YuQing d60b141a21 upgrade version to 1.0.82 2025-11-09 19:00:41 +08:00
YuQing 86bab518c6 remove compile warning under RockLinux 10 2025-11-09 18:19:20 +08:00
YuQing 4b9ef52da2 fix compile warning 2025-11-05 10:47:44 +08:00
YuQing e8a9967801 set use_io_uring explicitly 2025-11-04 15:34:25 +08:00
YuQing 96c896b09a INSTALL changed for v1.0.81 2025-10-30 15:38:27 +08:00
YuQing 8d9feff6e2 restore function ioevent_reset 2025-10-29 11:18:56 +08:00
YuQing cbcd38a9af upgrade version to 1.0,81 2025-10-26 12:26:07 +08:00
YuQing cd55792a89 Merge remote-tracking branch 'origin/use_iouring' 2025-10-26 12:24:55 +08:00
YuQing 511b1066c4 add macro function fc_string_equals_ex 2025-10-24 11:59:43 +08:00
YuQing ddf6b5dfe9 send zc done notify callback for recycling buffer 2025-10-19 20:10:12 +08:00
YuQing 23cd03bc76 add macro IPV4_ADDRESS_SIZE and IPV6_ADDRESS_SIZE 2025-10-18 15:48:31 +08:00
YuQing 065184a203 batch ioevent_uring_submit for RDMA network 2025-10-07 19:52:48 +08:00
YuQing de80dc19dc struct ioevent_puller add field service_name 2025-10-06 20:53:14 +08:00
YuQing dac653d694 IOEventCallback: change event type from short to int 2025-10-05 09:44:24 +08:00
YuQing d5dbe3d030 free_queue support parameter: need_shrink and set task->shrinked 2025-10-03 21:03:31 +08:00
YuQing 7973d81b69 struct fast_task_info add fields: is_client and op_type for io_uring 2025-10-03 10:18:25 +08:00
YuQing 4576f22e24 add function uring_prep_connect 2025-09-30 10:12:41 +08:00
YuQing cb6f6f13f3 support Linux io_uring OK 2025-09-27 15:37:56 +08:00
YuQing 012b2038ee add functions uring_prep_xxx 2025-09-25 14:49:37 +08:00
YuQing 48a0ea2e30 ioevent_set support io_uring 2025-09-24 15:54:03 +08:00
YuQing aa48e3cd9a upgrade version in spec file 2025-09-20 17:12:30 +08:00
YuQing 47fa7f99df ioevent.[hc] and ioevent_loop.[hc] support io_uring 2025-09-17 03:49:21 +08:00
YuQing ec8e47f831 tests/test_fast_buffer.c support all types 2025-09-12 14:08:46 +08:00
YuQing d9d6255621 test_fast_buffer.c support int2hex 2025-09-11 12:07:45 +08:00
YuQing 2f75958a4a test_fast_buffer.c support -t option 2025-09-11 10:05:25 +08:00
YuQing a4cae13e07 add function fc_ftoa 2025-09-10 15:06:17 +08:00
YuQing f136821c0d getIpaddrByNameEx: IPv4 has priority over IPv6 2025-09-10 15:05:15 +08:00
YuQing b97f23ced2 bytes_to_human_str support round off 2025-09-03 15:23:27 +08:00
YuQing 84a1f90a9a bytes to human readalbe string more gracefully 2025-08-29 13:25:58 +08:00
YuQing 3f19715e45 add function bytes_to_human_str 2025-08-29 11:36:10 +08:00
YuQing ce4c5e23d4 upgrade version to 1.0.79 2025-08-24 22:58:33 +08:00
YuQing d59da03d60 use size_t instead int to avoid compile warning 2025-08-21 20:52:35 +08:00
YuQing 8e51f4de3e logger.h export function log_it_ex3 2025-08-20 17:54:29 +08:00
vazmin 0afae48142 gh actions: upgrade to 1.0.78-1 2025-08-16 16:31:05 +00:00
YuQing 158924f259 upgrade version to 1.0.78 2025-08-14 09:43:38 +08:00
YuQing bf7c6e5144 add function fc_get_two/three_subdirs_full_filepath etc. 2025-08-13 15:40:39 +08:00
YuQing 6f4b3b7cd8 rename fc_combine_two_string to fc_combine_two_strings 2025-08-09 15:21:08 +08:00
YuQing b1f3c7894e add functions short2HEX, int2HEX, long2HEX 2025-08-08 21:49:43 +08:00
YuQing ec2db7cd33 replace sprintf and snprintf as necessary 2025-08-07 19:55:41 +08:00
YuQing 63ef9aa8f4 add functions short2hex, int2hex, long2hex etc. 2025-08-06 14:16:06 +08:00
YuQing 1d2f938a30 add null terminator after fc_itoa 2025-08-05 21:14:45 +08:00
YuQing e4898affdd fast_buffer support options: binary_mode and check_capacity 2025-08-05 11:44:04 +08:00
YuQing 558670bc63 performance opt.: replace sprintf as necessary 2025-08-04 17:34:57 +08:00
YuQing cf16c41054 src/connection_pool.[hc]: restore pthread mutex lock 2025-08-03 15:18:23 +08:00
YuQing 7fbb5c620b change int2buff, buff2int etc. functions to static inline 2025-08-03 15:10:28 +08:00
YuQing 9acc202481 connection_pool.[hc]: use CAS instead of pthread mutex lock 2025-08-02 19:16:03 +08:00
YuQing dd0d4dbc19 func conn_pool_get_key performance optimization 2025-07-26 16:58:25 +08:00
YuQing a1ae1cbcb0 add file: src/tests/cpool_benchmark.c 2025-07-26 15:02:23 +08:00
YuQing fda2679435 fast_mblock.[hc] remove counter: free node count 2025-07-22 16:37:36 +08:00
YuQing f0484579e0 tests/Makefile add mblock_benchmark 2025-07-18 11:21:18 +08:00
YuQing 6a18162a12 add src/tests/mblock_benchmark.c 2025-07-18 11:06:36 +08:00
YuQing 8e834f7165 src/spinlock.[hc]: use pthread spinlock 2025-07-18 11:04:53 +08:00
YuQing a256976600 fast_mblock.[hc] add counter: free node count 2025-07-09 09:20:41 +08:00
YuQing 62a29b55a5 spinlock functions return error no 2025-07-08 17:25:37 +08:00
YuQing a6dc24e2f3 add files: spinlock.[hc] 2025-07-07 17:30:43 +08:00
YuQing 70f6ad56ed getIpaddrByName: normalize ip addr when input addr is IPv4 or IPv6 2025-06-19 16:13:10 +08:00
vazmin 7f1a85b025 gh actions: upgrade to 1.0.77-1 2025-04-06 16:55:50 +00:00
YuQing eafb8aae74 upgrade version to 1.0.77 2025-04-01 16:48:17 +08:00
YuQing de1e9e7ec4 add function fc_compare_int64_ptr 2025-03-18 08:42:39 +08:00
YuQing aa144b5981 process_stop_ex add parameter: force 2025-02-19 15:07:48 +08:00
YuQing a0654b83c0 Merge branch 'master' of gitee.com:fastdfs100/libfastcommon 2025-02-03 20:09:51 +08:00
YuQing 19dcd0c5c4 impl. shorten_path for /./ and /../ 2025-02-03 20:07:29 +08:00
YuQing d764571f6e upgrade version to 1.0.76 2025-01-27 20:49:05 +08:00
YuQing 13fc696432 conn_pool_get_connection_ex add parameter: shared 2025-01-27 10:55:26 +08:00
YuQing e4a9fccddb set extra_params for socket gracefully 2025-01-26 13:02:07 +08:00
YuQing 5477593ce8 log error on thread local hashtable exception 2025-01-26 11:43:38 +08:00
YuQing ce0c23358f fix src/tests/Makefile under fedora 40 2024-12-18 11:48:58 +08:00
YuQing f4020e7622 remove compile warning under some gcc versions 2024-12-08 09:26:37 +08:00
YuQing ed65725833 explicit cast for fast_mblock_alloc_object 2024-11-21 10:21:07 +08:00
YuQing 13e213e3f8 small changes for src/system_info.c 2024-11-19 09:44:15 +08:00
YuQing 83f757672b add function is_rotational_device_by_path 2024-11-01 11:31:46 +08:00
YuQing 21366a4a2e add function get_statfs_by_path 2024-10-31 10:31:43 +08:00
YuQing aad48cc03d Merge branch 'master' of gitee.com:fastdfs100/libfastcommon 2024-10-31 09:37:09 +08:00
YuQing 7a108ec5a2 get_mounted_filesystems act as program df 2024-10-30 17:05:26 +08:00
vazmin 98e3471433 gh actions: upgrade to 1.0.75-1 2024-09-29 15:23:57 +00:00
YuQing 8a97e84e1c connection pool performance optimization 2024-09-22 12:19:50 +08:00
YuQing 8ce0119aa2 upgrade version to 1.0.75 2024-09-17 11:23:14 +08:00
YuQing 1b777792ab task init callback support extra argument 2024-09-15 12:03:18 +08:00
YuQing 2ab381d5e3 set comm_type for connection 2024-06-23 15:05:31 +08:00
vazmin a0f1ac59c8 gh actions: upgrade to 1.0.74-1 2024-06-15 14:45:01 +00:00
YuQing 13b31434e0 upgrade version to 1.0.74 2024-06-11 09:37:59 +08:00
YuQing 8aceec92ee add macro define ENODATA for other Unix 2024-05-20 08:22:35 +08:00
YuQing fef0a4a7f3 adapt to FreeBSD 13 2024-05-19 11:11:42 +08:00
YuQing 7f699688c0 add functions: get_log_level and get_log_level_caption 2024-04-08 15:15:34 +08:00
vazmin e0f47116c5 gh actions: upgrade to 1.0.73-1 2024-03-17 15:10:21 +00:00
YuQing 6cd9d6d842 upgrade version to V1.0.73 2024-03-11 11:17:47 +08:00
YuQing f4fef93061 add function is_loopback_ip 2024-03-05 16:28:04 +08:00
YuQing 226fd0d378 format ip address for IPv6 2024-03-05 10:58:09 +08:00
YuQing 9a720533ce server_id_func.[hc]: service group can overwrite buffer_size 2024-02-21 10:25:43 +08:00
YuQing 55ff532f92 struct fast_task_info remove fields: connect_timeout and network_timeout 2024-02-20 09:48:24 +08:00
YuQing d18ad54c2b add macro FC_SET_STRING_EMPTY 2024-02-15 16:44:00 +08:00
vazmin 2205cae6f3 gh actions: upgrade to 1.0.72-1 2024-01-31 11:59:25 +00:00
YuQing 5bceed4e32 upgrade version to 1.0.72 2024-01-30 10:48:31 +08:00
YuQing e0e7b9ef35 fc_queue.[hc]: add function fc_queue_remove 2024-01-21 09:22:43 +08:00
YuQing 05f3d62ee1 call fast_mblock_ref_counter_dec for delay free node correctly 2024-01-07 14:59:00 +08:00
vazmin 01f35da9d2 gh actions: upgrade to 1.0.71-1 2024-01-01 11:23:55 +00:00
YuQing 02f4659a32 log IPv6 address and port gracefully 2023-12-25 17:01:43 +08:00
YuQing 7816a28c53 use strtok_r instead of strtok for thread safety 2023-12-23 16:19:11 +08:00
YuQing 3f5eed3af2 upgrade version to 1.0.71 2023-12-08 15:22:51 +08:00
YuQing c9083ae0cf add file tests/test_memcpy.c 2023-12-04 21:41:08 +08:00
YuQing 5283a55bda tests/test_uniq_skiplist.c changed 2023-12-04 15:27:00 +08:00
YuQing 78caf9224b replace inet_ntop to getnameinfo for IPv6 2023-12-01 11:31:26 +08:00
YuQing dd77da144f field socket_domain rename to af 2023-11-29 18:35:00 +08:00
YuQing 700a5bcaec replace type in_addr_t to in_addr_64_t 2023-11-24 15:25:14 +08:00
YuQing 4eb30adb1a code adjust for pull request #47 2023-11-23 15:40:58 +08:00
YuQing 06f0ce67fd
Merge pull request #47 from sunqiangwei1988/master
Added: 增加IPv6支持
2023-11-23 08:53:32 +08:00
YuQing 7018f4e337
Merge branch 'master' into master 2023-11-23 08:53:07 +08:00
vazmin d68c9aff32 gh actions: upgrade to 1.0.70-3 2023-11-21 14:35:29 +00:00
YuQing 89e70977d5 logger.c: log_set_prefix and log_set_filename support re-entry 2023-11-21 15:56:51 +08:00
vazmin 5bda2dfef6 gh actions: upgrade to 1.0.70-2 2023-11-20 13:23:17 +00:00
vazmin 8b545fcfc0 gh actions: upgrade to 1.0.70-1 2023-11-19 14:45:34 +00:00
YuQing 6843acb456 add RDMA callback set_busy_polling 2023-11-18 10:40:37 +08:00
YuQing 894477753c upgrade version to 1.0.70 2023-11-16 11:04:18 +08:00
YuQing 6a5d4b1402 set comm_type to default correctly 2023-11-15 16:40:56 +08:00
YuQing 1c1ea296e7 global configs for communication and smart_polling etc. 2023-11-15 09:56:39 +08:00
YuQing 961ea11c4f struct fast_task_info add field pending_send_count 2023-11-06 10:51:08 +08:00
sunqiangwei1988 718906e477 Added: 增加IPv6支持
1、将IP_ADDRESS_SIZE的值由16修改为INET6_ADDRSTRLEN(46)。
2、新定义in_addr_64结构体替换in_addr结构体,以支持IPv6地址长度。
3、将connection_pool相关文件的socket_domain预设值由AF_INET修改为AF_UNSPEC。
4、增加IPv6的本地回环地址判断。
5、新增从字符串中解析IP地址和端口号方法(支持IPv4和IPv6)。
6、sockopt增加IPv6的支持
2023-11-02 10:13:42 +08:00
YuQing eafe769759 struct fast_task_queue support release callback 2023-10-12 21:53:29 +08:00
YuQing a1914ea249 add functions: fc_queue_push_with_check and fc_queue_peek 2023-09-30 14:46:56 +08:00
YuQing 61e07a4c0f add RDMA callbacks: send_done post_recv 2023-09-28 22:19:30 +08:00
YuQing 6151ea721b function conn_pool_set_rdma_extra_params_ex support double_buffers 2023-09-27 11:36:29 +08:00
YuQing 255defa788 rdma callback get_buffer rename to get_recv_buffer 2023-09-27 11:22:37 +08:00
YuQing acaf94db0c struct fast_task_info support send and recv double buffers 2023-09-25 18:36:15 +08:00
YuQing 2e176a9d1b send_by_buf1 and recv_data callback for rdma 2023-09-24 14:32:42 +08:00
YuQing e0b93756ab add functions: fc_server_[close|destroy]_connection 2023-09-23 11:06:56 +08:00
YuQing 7b0631e37a load connection_thread_local from cluster.conf 2023-09-20 10:43:05 +08:00
YuQing e0bbe89d23 connection_pool.[hc] support thread local for performance 2023-09-20 07:40:14 +08:00
YuQing 1c1cb6d5e7 restore epoll timeout when polling_queue is empty 2023-09-19 09:30:11 +08:00
YuQing 70c44ea490 nio thread data support busy_polling_callback 2023-09-18 16:17:34 +08:00
YuQing b4e5a26ba0 function ioevent_reset impl. for RDMA 2023-09-15 16:02:31 +08:00
YuQing f49c5d134a init extra_params when comm_type == fc_comm_type_sock 2023-09-14 09:55:59 +08:00
YuQing db49d54a37 conn_pool_alloc_connection impl. 2023-09-12 16:01:29 +08:00
YuQing c9687df03a ConnectionCallbacks struct changed 2023-09-12 07:53:34 +08:00
YuQing d24023aee7 function fc_alloc_rdma_pd impl. 2023-09-11 11:32:32 +08:00
YuQing 5139ec4682 connection_pool.[hc] support callbacks for RDMA 2023-09-10 20:54:24 +08:00
YuQing bc3a65ee19 add function fc_server_get_group_by_index 2023-09-07 09:34:45 +08:00
YuQing 44f827f291 server_id_func.[hc]: support communication type 2023-09-06 17:24:44 +08:00
YuQing 4a86162913 struct fast_task_info add field conn for RDMA connection 2023-09-05 09:20:07 +08:00
YuQing d5f6a192a5 type define for RDMA network 2023-09-04 08:51:35 +08:00
YuQing 05a694df77 get full mac address of infiniband NIC under Linux 2023-08-27 14:54:51 +08:00
vazmin 45e958cc1c gh actions: upgrade to 1.0.69-1 2023-08-06 07:21:50 +00:00
YuQing d9c14d602a upgrade version to 1.0.69 2023-08-06 09:03:40 +08:00
YuQing 4480669e03 uniq_skiplist support arg for free callback 2023-08-05 20:46:35 +08:00
YuQing fafbbb557e bugfixed: array_allocator_alloc MUST init the array 2023-08-02 14:59:57 +08:00
vazmin 1969fbba8d gh actions: upgrade to 1.0.68-1 2023-07-23 14:27:27 +00:00
YuQing 896b35603f add macros: MEM_ALIGN_FLOOR/CEIL_BY_MASK 2023-07-09 09:12:37 +08:00
YuQing 15facf395b upgrade version to 1.0.68 2023-07-07 08:25:18 +08:00
YuQing 3924213c9a sorted_queue.[hc]: pop_compare_func support argument 2023-07-05 16:39:57 +08:00
YuQing 643ecdc906 add functions sorted_queue_lock and sorted_queue_unlock 2023-06-29 16:47:30 +08:00
vazmin 7726d0223f gh actions: upgrade to 1.0.67-1 2023-06-04 10:51:06 +00:00
YuQing 4df1107fa3 add function fc_safe_writev 2023-05-29 18:15:59 +08:00
YuQing 0c588d965e bugfixed: fast_mblock_batch_alloc correct return value 2023-05-28 16:31:53 +08:00
YuQing 8de24ad5b5 add file src/tests/test_thread_local.c 2023-05-24 17:32:06 +08:00
YuQing 8cea8632d7 sorted_queue.[hc] support pop_compare_func 2023-05-23 20:13:38 +08:00
YuQing ccbc201636 bugfixed: MUST set tail->next to mblock->free_chain_head 2023-05-21 10:54:15 +08:00
YuQing e02bb4edc3 fast_mblock_init_ex2 add parameter prealloc_trunk_count 2023-05-19 11:20:30 +08:00
YuQing 085e06aac1 upgrade version to 1.0.67 2023-05-16 09:40:12 +08:00
YuQing 0806435fcc fast_allocator.c adapt fast_mblock_malloc_trunk_notify_func 2023-05-15 15:10:01 +08:00
YuQing c00a159fd3 fast_mblock_malloc_trunk_notify_func prototype changed 2023-05-14 20:06:27 +08:00
YuQing 5247caa71a uniq_skiplist_clear impl. more optimization 2023-05-09 07:45:11 +08:00
YuQing 2c5734ab22 add function uniq_skiplist_clear 2023-05-08 17:48:28 +08:00
YuQing a19119f962 sorted_queue_pop_all rename to sorted_queue_pop_to_chain 2023-05-05 08:09:08 +08:00
YuQing 428d13a07b sorted_queue.[hc]: sorted_queue_pop and sorted_queue_pop_all 2023-05-04 20:05:32 +08:00
YuQing 6dbc8b8937 sorted queue use double link chain for quick push 2023-05-04 17:08:51 +08:00
YuQing f1691b7480 lc_pair in struct fc_queue change to lcp 2023-03-27 16:18:32 +08:00
YuQing 595a8c5664 make.sh: link with -lrt when glibc versions less than 2.17 in Linux 2023-03-14 15:23:30 +08:00
vazmin 8b298570b3 gh actions: upgrade to 1.0.66-1 2023-02-18 05:43:58 +00:00
YuQing d81b75e4da upgrade version to 1.0.66 2023-02-15 21:06:06 +08:00
YuQing ee3631d426 struct fast_task_info remove field nio_stages.next 2023-02-12 20:00:48 +08:00
YuQing 6d3d082c6d add field notify_next for nio notify queue 2023-02-12 17:09:32 +08:00
YuQing c5138cc7cf struct fast_task_info add field: nio_stages.next for epoll edge trigger 2023-02-12 10:30:42 +08:00
vazmin 73ab695fc8 gh actions: upgrade to 1.0.65-1 2023-01-15 13:49:19 +00:00
YuQing be9c7c394a upgrade version to 1.0.65 2023-01-14 08:37:06 +08:00
YuQing 0113263e87 add function get_groups 2023-01-09 16:47:57 +08:00
YuQing fd8fbfe644 parse_bytes support space charactors 2023-01-04 12:20:45 +08:00
YuQing 8ab3420bce add function tcp_socket_connected 2022-12-30 17:18:28 +08:00
YuQing aa2fc62cbb add functions locked_list_move and locked_list_move_tail 2022-12-20 09:00:24 +08:00
YuQing ee70efcd09 fc_fallocate fail back to ftruncate under Linux 2022-12-11 12:43:24 +08:00
vazmin 86288bf99e gh actions: upgrade to 1.0.63-1 2022-11-21 14:54:56 +00:00
vazmin c0ea8349d3 debian: installation dir changes 2022-11-21 22:32:52 +08:00
YuQing 8ea9848047 upgrade version to 1.0.64 2022-11-21 08:15:28 +08:00
YuQing d07058934b bugfixed: can't use global malloc_allocator 2022-11-19 17:13:02 +08:00
YuQing 8e4adccb83 Makefile.in: force symlink library 2022-11-13 17:15:44 +08:00
YuQing 1eb603cfd1 bugfixed: common_blocked_queue_[alloc|free]_node must use lock 2022-11-10 08:47:07 +08:00
YuQing 22c7e31752 shared_func.[hc]: normalize_path use type string_t for general purpose 2022-11-07 08:27:43 +08:00
76 changed files with 7399 additions and 2589 deletions

7
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Makefile.in # Makefile.in
src/Makefile src/Makefile
src/tests/Makefile
# Prerequisites # Prerequisites
*.d *.d
@ -59,6 +60,12 @@ src/tests/test_mutex_lock_perf
src/tests/test_queue_perf src/tests/test_queue_perf
src/tests/test_normalize_path src/tests/test_normalize_path
src/tests/test_sorted_array src/tests/test_sorted_array
src/tests/test_sorted_queue
src/tests/test_thread_local
src/tests/test_memcpy
src/tests/mblock_benchmark
src/tests/cpool_benchmark
src/tests/test_fast_buffer
# other # other
*.swp *.swp

98
HISTORY
View File

@ -1,4 +1,102 @@
Version 1.83 2025-11-15
* fast_task_queue.h: remove field finish_callback
Version 1.82 2025-11-04
* set use_io_uring explicitly
Version 1.81 2025-10-05
* support Linux io_uring
* free_queue support parameter: need_shrink and set task->shrinked
* IOEventCallback: change event type from short to int
Version 1.80 2025-09-10
* getIpaddrByNameEx: IPv4 has priority over IPv6
* shared_func.[hc]: add function fc_ftoa
Version 1.79 2025-08-29
* logger.h export function log_it_ex3
* shared_func.[hc]: add function bytes_to_human_str
Version 1.78 2025-08-07
* getIpaddrByName: normalize ip addr when input addr is IPv4 or IPv6
* add files: spinlock.[hc]
* shared_func.[hc]: change int2buff, buff2int etc. functions to static inline
* shared_func.[hc]: add functions short2hex, int2hex, long2hex etc.
* performance opt.: replace sprintf and snprintf as necessary
Version 1.77 2025-03-18
* impl. shorten_path for /./ and /../
* add function fc_compare_int64_ptr
Version 1.76 2025-01-27
* get_mounted_filesystems act as program df
* add function get_statfs_by_path
* add function is_rotational_device_by_path
* conn_pool_get_connection_ex add parameter: shared
Version 1.75 2024-09-22
* task init callback support extra argument
* connection pool performance optimization
Version 1.74 2024-05-18
* add functions: get_log_level and get_log_level_caption
* adapt to FreeBSD 13
Version 1.73 2024-03-05
* add macro FC_SET_STRING_EMPTY
* struct fast_task_info remove fields: connect_timeout and network_timeout
* format ip address for IPv6
Version 1.72 2024-01-21
* call fast_mblock_ref_counter_dec for delay free node correctly
* fc_queue.[hc]: add function fc_queue_remove
Version 1.71 2023-12-23
* full support IPv6 by pull request #47
* replace inet_ntop to getnameinfo for IPv6
Version 1.70 2023-09-30
* get full mac address of infiniband NIC under Linux
* struct fast_task_info add field conn for RDMA connection
* server_id_func.[hc]: support communication type
* connection_pool.[hc] support callbacks for RDMA
* nio thread data support busy_polling_callback
* connection_pool.[hc] support thread local for performance
* struct fast_task_info support send and recv double buffers
* add functions: fc_queue_push_with_check and fc_queue_peek
Version 1.69 2023-08-05
* bugfixed: array_allocator_alloc MUST init the array
* uniq_skiplist support arg for free callback
Version 1.68 2023-07-05
* sorted_queue.[hc]: pop_compare_func support argument
Version 1.67 2023-05-29
* lc_pair in struct fc_queue change to lcp
* sorted queue use double link chain for quick push
* add function uniq_skiplist_clear
* fast_mblock_malloc_trunk_notify_func prototype changed
* fast_mblock_init_ex2 add parameter prealloc_trunk_count
* sorted_queue.[hc] support pop_compare_func
* bugfixed: fast_mblock_batch_alloc correct return value
* add function fc_safe_writev
Version 1.66 2023-02-12
* struct fast_task_info add field: notify_next for nio notify queue
Version 1.65 2023-01-09
* locked_list.h: add functions locked_list_move and locked_list_move_tail
* add function tcp_socket_connected
* parse_bytes support space charactors (before and after the unit)
* add function get_groups
Version 1.64 2022-11-19
* shared_func.[hc]: normalize_path use type string_t for general purpose
* bugfixed: common_blocked_queue_[alloc|free]_node must use lock
* bugfixed: can't use global malloc_allocator
Version 1.63 2022-10-16 Version 1.63 2022-10-16
* sockopt.[hc]: getIpAndPort support ipv6 * sockopt.[hc]: getIpAndPort support ipv6

13
INSTALL
View File

@ -6,11 +6,20 @@ Please visit the libfastcommon Home Page for more detail.
English language: https://github.com/happyfish100/libfastcommon English language: https://github.com/happyfish100/libfastcommon
Chinese language: http://www.fastken.com/ Chinese language: http://www.fastken.com/
[Optional Step]
You can enable io_uring for higher performance when Linux kernel version >= 6.2,
CentOS, RockyLinux, AlmaLinux, RHEL etc.:
sudo yum install liburing-devel -y
Debian, Ubuntu etc.:
sudo apt install liburing-dev -y
# download libfastcommon source codes and install it, # download libfastcommon source codes and install it,
# github address: https://github.com/happyfish100/libfastcommon.git # github address: https://github.com/happyfish100/libfastcommon.git
# gitee address: https://gitee.com/fastdfs100/libfastcommon.git # gitee address: https://gitee.com/fastdfs100/libfastcommon.git
# the command lines as: # the command lines as:
git clone https://github.com/happyfish100/libfastcommon.git git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon; git checkout V1.0.59 cd libfastcommon; git checkout V1.0.83
./make.sh clean && ./make.sh && ./make.sh install ./make.sh clean && ./make.sh && sudo ./make.sh install

114
debian/changelog vendored
View File

@ -1,3 +1,117 @@
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:47:37 +0000
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:00:00 +0000
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 09:05:57 +0000
libfastcommon (1.0.78-1) unstable; urgency=medium
* upgrade to 1.0.78-1
-- YuQing <384681@qq.com> Sat, 16 Aug 2025 16:31:05 +0000
libfastcommon (1.0.77-1) unstable; urgency=medium
* upgrade to 1.0.77-1
-- YuQing <384681@qq.com> Sun, 06 Apr 2025 16:55:50 +0000
libfastcommon (1.0.75-1) unstable; urgency=medium
* upgrade to 1.0.75-1
-- YuQing <384681@qq.com> Sun, 29 Sep 2024 15:23:57 +0000
libfastcommon (1.0.74-1) unstable; urgency=medium
* upgrade to 1.0.74-1
-- YuQing <384681@qq.com> Sat, 15 Jun 2024 14:45:01 +0000
libfastcommon (1.0.73-1) unstable; urgency=medium
* upgrade to 1.0.73-1
-- YuQing <384681@qq.com> Sun, 17 Mar 2024 15:10:21 +0000
libfastcommon (1.0.72-1) unstable; urgency=medium
* upgrade to 1.0.72-1
-- YuQing <384681@qq.com> Wed, 31 Jan 2024 11:59:25 +0000
libfastcommon (1.0.71-1) unstable; urgency=medium
* upgrade to 1.0.71-1
-- YuQing <384681@qq.com> Mon, 01 Jan 2024 11:23:54 +0000
libfastcommon (1.0.70-3) unstable; urgency=medium
* upgrade to 1.0.70-3
-- YuQing <384681@qq.com> Tue, 21 Nov 2023 14:35:29 +0000
libfastcommon (1.0.70-2) unstable; urgency=medium
* upgrade to 1.0.70-2
-- YuQing <384681@qq.com> Mon, 20 Nov 2023 13:23:17 +0000
libfastcommon (1.0.70-1) unstable; urgency=medium
* upgrade to 1.0.70-1
-- YuQing <384681@qq.com> Sun, 19 Nov 2023 14:45:34 +0000
libfastcommon (1.0.69-1) unstable; urgency=medium
* upgrade to 1.0.69-1
-- YuQing <384681@qq.com> Sun, 06 Aug 2023 07:21:50 +0000
libfastcommon (1.0.68-1) unstable; urgency=medium
* upgrade to 1.0.68-1
-- YuQing <384681@qq.com> Sun, 23 Jul 2023 14:27:27 +0000
libfastcommon (1.0.67-1) unstable; urgency=medium
* upgrade to 1.0.67-1
-- YuQing <384681@qq.com> Sun, 04 Jun 2023 10:51:06 +0000
libfastcommon (1.0.66-1) unstable; urgency=medium
* upgrade to 1.0.66-1
-- YuQing <384681@qq.com> Sat, 18 Feb 2023 05:43:58 +0000
libfastcommon (1.0.65-1) unstable; urgency=medium
* upgrade to 1.0.65-1
-- YuQing <384681@qq.com> Sun, 15 Jan 2023 13:49:19 +0000
libfastcommon (1.0.63-1) unstable; urgency=medium
* upgrade to 1.0.63-1
-- YuQing <384681@qq.com> Mon, 21 Nov 2022 14:54:56 +0000
libfastcommon (1.0.62-1) unstable; urgency=medium libfastcommon (1.0.62-1) unstable; urgency=medium
* upgrade to 1.0.62-1 * upgrade to 1.0.62-1

View File

@ -1 +1 @@
usr/lib64/libfastcommon.so* usr/lib/ usr/lib/libfastcommon.so*

View File

@ -3,7 +3,7 @@
%define CommitVersion %(echo $COMMIT_VERSION) %define CommitVersion %(echo $COMMIT_VERSION)
Name: libfastcommon Name: libfastcommon
Version: 1.0.63 Version: 1.0.83
Release: 1%{?dist} Release: 1%{?dist}
Summary: c common functions library extracted from my open source projects FastDFS Summary: c common functions library extracted from my open source projects FastDFS
License: LGPL License: LGPL
@ -17,6 +17,14 @@ BuildRequires: libcurl-devel
Requires: libcurl Requires: libcurl
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
%define kernel_major %(uname -r | cut -d'.' -f1)
%define kernel_minor %(uname -r | cut -d'.' -f2)
%define kernel_ver_int %(expr %{kernel_major} \\* 100 + %{kernel_minor})
%if %{kernel_ver_int} >= 514
BuildRequires: liburing-devel >= 2.4
Requires: liburing >= 2.4
%endif
%description %description
c common functions library extracted from my open source projects FastDFS. c common functions library extracted from my open source projects FastDFS.
this library is very simple and stable. functions including: string, logger, this library is very simple and stable. functions including: string, logger,

69
make.sh
View File

@ -13,6 +13,9 @@ int main()
{ {
printf("%d\n", (int)sizeof(void*)); printf("%d\n", (int)sizeof(void*));
printf("%d\n", (int)sizeof(off_t)); printf("%d\n", (int)sizeof(off_t));
#ifdef __GLIBC_MINOR__
printf("%d\n", __GLIBC_MINOR__);
#endif
return 0; return 0;
} }
EOF EOF
@ -39,13 +42,16 @@ fi
count=0 count=0
int_bytes=4 int_bytes=4
off_bytes=8 off_bytes=8
glibc_minor=0
LIB_VERSION=lib64 LIB_VERSION=lib64
for col in $output; do for col in $output; do
if [ $count -eq 0 ]; then if [ $count -eq 0 ]; then
int_bytes=$col int_bytes=$col
else elif [ $count -eq 1 ]; then
off_bytes=$col off_bytes=$col
else
glibc_minor=$col
fi fi
count=$($EXPR $count + 1) count=$($EXPR $count + 1)
@ -53,19 +59,30 @@ done
/bin/rm -f a.out $tmp_src_filename /bin/rm -f a.out $tmp_src_filename
uname=$(uname)
TARGET_PREFIX=$DESTDIR/usr TARGET_PREFIX=$DESTDIR/usr
if [ "$int_bytes" -eq 8 ]; then if [ "$int_bytes" -eq 8 ]; then
OS_BITS=64 OS_BITS=64
LIB_VERSION=lib64 if [ $uname = 'Linux' ]; then
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
if [ $osname = 'Ubuntu' -o $osname = 'Debian' ]; then
LIB_VERSION=lib
else
LIB_VERSION=lib64
fi
else
LIB_VERSION=lib
fi
else else
OS_BITS=32 OS_BITS=32
LIB_VERSION=lib LIB_VERSION=lib
fi fi
if [ "$off_bytes" -eq 8 ]; then if [ "$off_bytes" -eq 8 ]; then
OFF_BITS=64 OFF_BITS=64
else else
OFF_BITS=32 OFF_BITS=32
fi fi
DEBUG_FLAG=0 DEBUG_FLAG=0
@ -82,6 +99,7 @@ else
CFLAGS="$CFLAGS -g -O3" CFLAGS="$CFLAGS -g -O3"
fi fi
INCS=''
LIBS='-lm -ldl' LIBS='-lm -ldl'
if [ -f /usr/include/curl/curl.h ] || [ -f /usr/local/include/curl/curl.h ]; then if [ -f /usr/include/curl/curl.h ] || [ -f /usr/local/include/curl/curl.h ]; then
CFLAGS="$CFLAGS -DUSE_LIBCURL" CFLAGS="$CFLAGS -DUSE_LIBCURL"
@ -94,14 +112,33 @@ HAVE_VMMETER_H=0
HAVE_USER_H=0 HAVE_USER_H=0
if [ "$uname" = "Linux" ]; then if [ "$uname" = "Linux" ]; then
OS_NAME=OS_LINUX OS_NAME=OS_LINUX
IOEVENT_USE=IOEVENT_USE_EPOLL
major_version=$(uname -r | awk -F . '{print $1;}')
minor_version=$(uname -r | awk -F . '{print $2;}')
if [ $major_version -eq 5 -a $minor_version -ge 14 ] || [ $major_version -gt 5 ]; then
out=$(grep -F IORING_OP_SEND_ZC /usr/include/liburing/io_uring.h 2>/dev/null)
if [ -n "$out" ]; then
IOEVENT_USE=IOEVENT_USE_URING
LIBS="$LIBS -luring"
else
IOEVENT_USE=IOEVENT_USE_EPOLL
fi
else
IOEVENT_USE=IOEVENT_USE_EPOLL
fi
if [ $glibc_minor -lt 17 ]; then
LIBS="$LIBS -lrt"
fi
elif [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then elif [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
OS_NAME=OS_FREEBSD OS_NAME=OS_FREEBSD
IOEVENT_USE=IOEVENT_USE_KQUEUE IOEVENT_USE=IOEVENT_USE_KQUEUE
if [ "$uname" = "Darwin" ]; then if [ "$uname" = "Darwin" ]; then
CFLAGS="$CFLAGS -DDARWIN" CFLAGS="$CFLAGS -DDARWIN"
TARGET_PREFIX=$TARGET_PREFIX/local TARGET_PREFIX=$TARGET_PREFIX/local
LIB_VERSION=lib else
INCS="$INCS -I/usr/local/include"
LIBS="$LIBS -L/usr/local/lib"
fi fi
if [ -f /usr/include/sys/vmmeter.h ]; then if [ -f /usr/include/sys/vmmeter.h ]; then
@ -203,12 +240,12 @@ done
if [ -n "$pthread_path" ]; then if [ -n "$pthread_path" ]; then
LIBS="$LIBS -lpthread" LIBS="$LIBS -lpthread"
line=$(nm $pthread_path 2>/dev/null | fgrep pthread_rwlockattr_setkind_np | fgrep -w T) line=$(nm $pthread_path 2>/dev/null | grep -F pthread_rwlockattr_setkind_np | grep -w T)
if [ -n "$line" ]; then if [ -n "$line" ]; then
CFLAGS="$CFLAGS -DWITH_PTHREAD_RWLOCKATTR_SETKIND_NP=1" CFLAGS="$CFLAGS -DWITH_PTHREAD_RWLOCKATTR_SETKIND_NP=1"
fi fi
elif [ -f /usr/lib/libc_r.so ]; then elif [ -f /usr/lib/libc_r.so ]; then
line=$(nm -D /usr/lib/libc_r.so 2>/dev/null | grep pthread_create | grep -w T) line=$(nm -D /usr/lib/libc_r.so 2>/dev/null | grep -F pthread_create | grep -w T)
if [ -n "$line" ]; then if [ -n "$line" ]; then
LIBS="$LIBS -lc_r" LIBS="$LIBS -lc_r"
fi fi
@ -227,7 +264,9 @@ sed_replace()
cd src cd src
cp Makefile.in Makefile cp Makefile.in Makefile
sed_replace "s#\\\$(CC)#gcc#g" Makefile
sed_replace "s#\\\$(CFLAGS)#$CFLAGS#g" Makefile sed_replace "s#\\\$(CFLAGS)#$CFLAGS#g" Makefile
sed_replace "s#\\\$(INCS)#$INCS#g" Makefile
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
sed_replace "s#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile sed_replace "s#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile
sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile
@ -237,3 +276,11 @@ if [ "$1" = "clean" ]; then
/bin/rm -f Makefile _os_define.h /bin/rm -f Makefile _os_define.h
fi fi
cd tests
cp Makefile.in Makefile
sed_replace "s#\\\$(CC)#gcc#g" Makefile
sed_replace "s#\\\$(INCS)#$INCS#g" Makefile
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
if [ "$1" = "clean" ]; then
/bin/rm -f Makefile
fi

View File

@ -1,7 +1,7 @@
.SUFFIXES: .c .o .lo .SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS) COMPILE = $(CC) $(CFLAGS)
INC_PATH = INC_PATH = $(INCS)
LIB_PATH = $(LIBS) LIB_PATH = $(LIBS)
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION) TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
@ -17,7 +17,7 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \ multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \
json_parser.lo buffered_file_writer.lo server_id_func.lo \ json_parser.lo buffered_file_writer.lo server_id_func.lo \
fc_queue.lo sorted_queue.lo fc_memory.lo shared_buffer.lo \ fc_queue.lo sorted_queue.lo fc_memory.lo shared_buffer.lo \
thread_pool.lo array_allocator.lo sorted_array.lo thread_pool.lo array_allocator.lo sorted_array.lo spinlock.lo
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
logger.o sockopt.o base64.o sched_thread.o \ logger.o sockopt.o base64.o sched_thread.o \
@ -31,7 +31,7 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
multi_socket_client.o skiplist_set.o uniq_skiplist.o \ multi_socket_client.o skiplist_set.o uniq_skiplist.o \
json_parser.o buffered_file_writer.o server_id_func.o \ json_parser.o buffered_file_writer.o server_id_func.o \
fc_queue.o sorted_queue.o fc_memory.o shared_buffer.o \ fc_queue.o sorted_queue.o fc_memory.o shared_buffer.o \
thread_pool.o array_allocator.o sorted_array.o thread_pool.o array_allocator.o sorted_array.o spinlock.o
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \ shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
@ -47,7 +47,7 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
fc_list.h locked_list.h json_parser.h buffered_file_writer.h \ fc_list.h locked_list.h json_parser.h buffered_file_writer.h \
server_id_func.h fc_queue.h sorted_queue.h fc_memory.h \ server_id_func.h fc_queue.h sorted_queue.h fc_memory.h \
shared_buffer.h thread_pool.h fc_atomic.h array_allocator.h \ shared_buffer.h thread_pool.h fc_atomic.h array_allocator.h \
sorted_array.h sorted_array.h spinlock.h
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS) ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
@ -78,7 +78,7 @@ install:
install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon
@BUILDROOT=$$(echo "$(TARGET_PREFIX)" | grep BUILDROOT); \ @BUILDROOT=$$(echo "$(TARGET_PREFIX)" | grep BUILDROOT); \
if [ -z "$$BUILDROOT" ] && [ ! -e $(TARGET_PREFIX)/lib/libfastcommon.so ]; then ln -s $(TARGET_LIB)/libfastcommon.so $(TARGET_PREFIX)/lib/libfastcommon.so; fi if [ -z "$$BUILDROOT" ] && [ "$(TARGET_LIB)" != "$(TARGET_PREFIX)/lib" ]; then ln -sf $(TARGET_LIB)/libfastcommon.so $(TARGET_PREFIX)/lib/libfastcommon.so; fi
clean: clean:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS) rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)

View File

@ -47,7 +47,7 @@ int array_allocator_init_ex(ArrayAllocatorContext *ctx,
start = end; start = end;
} }
snprintf(name, sizeof(name), "%s-array", name_prefix); fc_combine_two_strings(name_prefix, "array", '-', name);
return fast_allocator_init_ex(&ctx->allocator, name, return fast_allocator_init_ex(&ctx->allocator, name,
obj_size, NULL, regions, region - regions, 0, obj_size, NULL, regions, region - regions, 0,
0.9999, reclaim_interval, need_lock); 0.9999, reclaim_interval, need_lock);
@ -58,6 +58,7 @@ VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
{ {
int alloc; int alloc;
int bytes; int bytes;
VoidArray *array;
if (target_count <= ctx->min_count) { if (target_count <= ctx->min_count) {
alloc = ctx->min_count; alloc = ctx->min_count;
@ -71,7 +72,11 @@ VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
} }
bytes = sizeof(VoidArray) + alloc * ctx->element_size; bytes = sizeof(VoidArray) + alloc * ctx->element_size;
return (VoidArray *)fast_allocator_alloc(&ctx->allocator, bytes); if ((array=fast_allocator_alloc(&ctx->allocator, bytes)) != NULL) {
array->alloc = alloc;
array->count = 0;
}
return array;
} }
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx, VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,

View File

@ -78,7 +78,6 @@ extern "C" {
static inline void array_allocator_free(ArrayAllocatorContext *ctx, static inline void array_allocator_free(ArrayAllocatorContext *ctx,
VoidArray *array) VoidArray *array)
{ {
array->count = 0;
fast_allocator_free(&ctx->allocator, array); fast_allocator_free(&ctx->allocator, array);
} }

View File

@ -24,6 +24,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include "fc_memory.h" #include "fc_memory.h"
#include "shared_func.h"
#include "base64.h" #include "base64.h"
/** /**
@ -53,15 +54,11 @@ void base64_set_line_length(struct base64_context *context, const int length)
* Usually contains only a combination of chars \n and \r. * Usually contains only a combination of chars \n and \r.
* Could be any chars not in set A-Z a-z 0-9 + /. * Could be any chars not in set A-Z a-z 0-9 + /.
*/ */
void base64_set_line_separator(struct base64_context *context, \ void base64_set_line_separator(struct base64_context *context,
const char *pLineSeparator) const char *pLineSeparator)
{ {
context->line_sep_len = snprintf(context->line_separator, \ context->line_sep_len = fc_safe_strcpy(context->
sizeof(context->line_separator), "%s", pLineSeparator); line_separator, pLineSeparator);
if (context->line_sep_len >= sizeof(context->line_separator))
{
context->line_sep_len = sizeof(context->line_separator) - 1;
}
} }
void base64_init_ex(struct base64_context *context, const int nLineLength, \ void base64_init_ex(struct base64_context *context, const int nLineLength, \

View File

@ -48,7 +48,7 @@ int buffered_file_writer_open_ex(BufferedFileWriter *writer,
return ENOMEM; return ENOMEM;
} }
snprintf(writer->filename, sizeof(writer->filename), "%s", filename); fc_safe_strcpy(writer->filename, filename);
writer->fd = open(writer->filename, O_WRONLY | writer->fd = open(writer->filename, O_WRONLY |
O_CREAT | O_TRUNC | O_CLOEXEC, mode); O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (writer->fd < 0) if (writer->fd < 0)

View File

@ -97,14 +97,21 @@ static inline int common_blocked_queue_push(struct common_blocked_queue
static inline struct common_blocked_node *common_blocked_queue_alloc_node( static inline struct common_blocked_node *common_blocked_queue_alloc_node(
struct common_blocked_queue *queue) struct common_blocked_queue *queue)
{ {
return fast_mblock_alloc_object(&queue->mblock); struct common_blocked_node *node;
pthread_mutex_lock(&(queue->lc_pair.lock));
node = (struct common_blocked_node *)fast_mblock_alloc_object(&queue->mblock);
pthread_mutex_unlock(&(queue->lc_pair.lock));
return node;
} }
static inline void common_blocked_queue_free_node( static inline void common_blocked_queue_free_node(
struct common_blocked_queue *queue, struct common_blocked_queue *queue,
struct common_blocked_node *node) struct common_blocked_node *node)
{ {
pthread_mutex_lock(&(queue->lc_pair.lock));
fast_mblock_free_object(&queue->mblock, node); fast_mblock_free_object(&queue->mblock, node);
pthread_mutex_unlock(&(queue->lc_pair.lock));
} }
void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue, void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue,
@ -175,7 +182,7 @@ struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
common_blocked_queue_pop_all_nodes_ex(queue, false) common_blocked_queue_pop_all_nodes_ex(queue, false)
#define common_blocked_queue_free_one_node(queue, node) \ #define common_blocked_queue_free_one_node(queue, node) \
fast_mblock_free_object(&queue->mblock, node) common_blocked_queue_free_node(&queue->mblock, node)
void common_blocked_queue_free_all_nodes(struct common_blocked_queue *queue, void common_blocked_queue_free_all_nodes(struct common_blocked_queue *queue,
struct common_blocked_node *node); struct common_blocked_node *node);

View File

@ -48,6 +48,9 @@ typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
//#include <sys/syscall.h> //#include <sys/syscall.h>
#endif #endif
/* Internet address (兼容IPv6长度). */
typedef uint64_t in_addr_64_t;
#define FILE_SEPERATOR "/" #define FILE_SEPERATOR "/"
typedef int SOCKET; typedef int SOCKET;
#define closesocket close #define closesocket close
@ -109,7 +112,23 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define SYNC_LOG_BUFF_DEF_INTERVAL 10 #define SYNC_LOG_BUFF_DEF_INTERVAL 10
#define TIME_NONE -1 #define TIME_NONE -1
#define IP_ADDRESS_SIZE 16 #define FC_BYTES_ONE_KB ( 1 << 10)
#define FC_BYTES_ONE_MB ( 1 << 20)
#define FC_BYTES_ONE_GB ( 1 << 30)
#define FC_BYTES_ONE_TB (1LL << 40)
#define FC_BYTES_ONE_PB (1LL << 50)
#define FC_BYTES_ONE_EB (1LL << 60)
#if defined(IOV_MAX) && IOV_MAX > 256
#define FC_IOV_BATCH_SIZE 256
#else
#define FC_IOV_BATCH_SIZE IOV_MAX
#endif
#define IPV4_ADDRESS_SIZE INET_ADDRSTRLEN //16
#define IPV6_ADDRESS_SIZE INET6_ADDRSTRLEN //46
#define IP_ADDRESS_SIZE INET6_ADDRSTRLEN //46
#define FORMATTED_IP_SIZE (IP_ADDRESS_SIZE + 2)
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL) #define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
#define FILE_RESOURCE_TAG_STR "file://" #define FILE_RESOURCE_TAG_STR "file://"
@ -119,6 +138,11 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
(strncasecmp(filename, FILE_RESOURCE_TAG_STR, \ (strncasecmp(filename, FILE_RESOURCE_TAG_STR, \
FILE_RESOURCE_TAG_LEN) == 0) FILE_RESOURCE_TAG_LEN) == 0)
#define IS_FILE_RESOURCE_EX(filename) \
((filename)->len >= FILE_RESOURCE_TAG_LEN && \
memcmp((filename)->str, FILE_RESOURCE_TAG_STR, \
FILE_RESOURCE_TAG_LEN) == 0)
#ifndef byte #ifndef byte
#define byte signed char #define byte signed char
#endif #endif
@ -137,6 +161,10 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define ECANCELED 125 #define ECANCELED 125
#endif #endif
#ifndef ENODATA
#define ENODATA 61 /* No data available */
#endif
#ifndef ENONET #ifndef ENONET
#define ENONET 64 /* Machine is not on the network */ #define ENONET 64 /* Machine is not on the network */
#endif #endif
@ -187,10 +215,12 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define st_ctimensec st_ctim.tv_nsec #define st_ctimensec st_ctim.tv_nsec
#endif #endif
#elif defined(OS_FREEBSD) #elif defined(OS_FREEBSD)
#ifndef st_atimensec
#define st_atimensec st_atimespec.tv_nsec #define st_atimensec st_atimespec.tv_nsec
#define st_mtimensec st_mtimespec.tv_nsec #define st_mtimensec st_mtimespec.tv_nsec
#define st_ctimensec st_ctimespec.tv_nsec #define st_ctimensec st_ctimespec.tv_nsec
#endif #endif
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -327,11 +357,15 @@ typedef void* (*MallocFunc)(size_t size);
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c) #define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
#define MEM_ALIGN_FLOOR(x, align_size) ((x) & (~(align_size - 1))) #define MEM_ALIGN_FLOOR(x, align_size) ((x) & (~(align_size - 1)))
#define MEM_ALIGN_CEIL(x, align_size) \ #define MEM_ALIGN_CEIL(x, align_size) \
(((x) + (align_size - 1)) & (~(align_size - 1))) (((x) + (align_size - 1)) & (~(align_size - 1)))
#define MEM_ALIGN(x) MEM_ALIGN_CEIL(x, 8) #define MEM_ALIGN(x) MEM_ALIGN_CEIL(x, 8)
#define MEM_ALIGN_FLOOR_BY_MASK(x, align_mask) ((x) & (~align_mask))
#define MEM_ALIGN_CEIL_BY_MASK(x, align_mask) \
(((x) + align_mask) & (~align_mask))
#define FC_INIT_CHAIN(chain) (chain).head = (chain).tail = NULL #define FC_INIT_CHAIN(chain) (chain).head = (chain).tail = NULL
#define FC_IS_CHAIN_EMPTY(chain) ((chain).head == NULL) #define FC_IS_CHAIN_EMPTY(chain) ((chain).head == NULL)
@ -387,6 +421,8 @@ typedef void* (*MallocFunc)(size_t size);
(dest).len = l; \ (dest).len = l; \
} while (0) } while (0)
#define FC_SET_STRING_EMPTY(dest, s) FC_SET_STRING_EX(dest, s, 0)
#define FC_SET_STRING_NULL(dest) \ #define FC_SET_STRING_NULL(dest) \
do { \ do { \
(dest).str = NULL; \ (dest).str = NULL; \
@ -419,6 +455,14 @@ static inline int fc_string_compare(const string_t *s1, const string_t *s2)
} }
} }
static inline bool fc_string_equal_ex(const char *str1,
const int len1, const char *str2, const int len2)
{
return (len1 == len2) && (memcmp(str1, str2, len1) == 0);
}
#define fc_string_equals_ex(str1, len1, str2, len2) \
fc_string_equal_ex(str1, len1, str2, len2)
static inline bool fc_string_equal(const string_t *s1, const string_t *s2) static inline bool fc_string_equal(const string_t *s1, const string_t *s2)
{ {
return (s1->len == s2->len) && (memcmp(s1->str, s2->str, s1->len) == 0); return (s1->len == s2->len) && (memcmp(s1->str, s2->str, s1->len) == 0);
@ -480,7 +524,18 @@ static inline int fc_compare_int64(const int64_t n1, const int64_t n2)
} }
#ifdef OS_LINUX #ifdef OS_LINUX
#define fc_fallocate(fd, size) fallocate(fd, 0, 0, size) static inline int fc_fallocate(int fd, const int64_t size)
{
if (fallocate(fd, 0, 0, size) < 0) {
if (errno == EOPNOTSUPP) {
return ftruncate(fd, size);
}
return -1;
}
return 0;
}
#else #else
#define fc_fallocate(fd, size) ftruncate(fd, size) #define fc_fallocate(fd, size) ftruncate(fd, size)
#define posix_fadvise(fd, offset, len, advice) 0 #define posix_fadvise(fd, offset, len, advice) 0
@ -501,6 +556,8 @@ static inline int fc_compare_int64(const int64_t n1, const int64_t n2)
#endif #endif
#define FC_MACRO_STRINGIFY(x) #x
#define FC_MACRO_TOSTRING(x) FC_MACRO_STRINGIFY(x)
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#include "fast_mblock.h" #include "fast_mblock.h"
#include "ini_file_reader.h" #include "ini_file_reader.h"
#include "pthread_func.h" #include "pthread_func.h"
#include "sockopt.h"
#include "hash.h" #include "hash.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -40,16 +41,105 @@ extern "C" {
(strcmp((conn1).ip_addr, (conn2).ip_addr) == 0 && \ (strcmp((conn1).ip_addr, (conn2).ip_addr) == 0 && \
(conn1).port == (conn2).port) (conn1).port == (conn2).port)
typedef struct typedef enum {
{ fc_comm_type_sock = 0,
int sock; fc_comm_type_rdma,
uint16_t port; fc_comm_type_both
short socket_domain; //socket domain, AF_INET, AF_INET6 or AF_UNSPEC for auto dedect } FCCommunicationType;
typedef struct {
int sock;
uint16_t port;
uint8_t af; //address family, AF_INET, AF_INET6 or AF_UNSPEC for auto dedect
bool shared; //for connection pool
FCCommunicationType comm_type;
bool validate_flag; //for connection pool bool validate_flag; //for connection pool
char ip_addr[INET6_ADDRSTRLEN]; char ip_addr[IP_ADDRESS_SIZE];
void *arg1; //for RDMA
char args[0]; //for extra data char args[0]; //for extra data
} ConnectionInfo; } ConnectionInfo;
struct fc_server_config;
struct ibv_pd;
typedef void (*fc_set_busy_polling_callback)(const bool busy_polling);
typedef struct ibv_pd *(*fc_alloc_pd_callback)(const char **ip_addrs,
const int count, const int port);
typedef int (*fc_get_connection_size_callback)();
typedef int (*fc_init_connection_callback)(ConnectionInfo *conn,
const bool double_buffers, const int buffer_size, void *arg);
typedef int (*fc_make_connection_callback)(ConnectionInfo *conn,
const char *service_name, const int timeout_ms,
const char *bind_ipaddr, const bool log_connect_error);
typedef bool (*fc_is_connected_callback)(ConnectionInfo *conn);
typedef bool (*fc_send_done_callback)(ConnectionInfo *conn);
typedef void (*fc_close_connection_callback)(ConnectionInfo *conn);
typedef void (*fc_destroy_connection_callback)(ConnectionInfo *conn);
typedef BufferInfo *(*fc_rdma_get_recv_buffer_callback)(ConnectionInfo *conn);
typedef int (*fc_rdma_request_by_buf1_callback)(ConnectionInfo *conn,
const char *data, const int length, const int timeout_ms);
typedef int (*fc_rdma_request_by_buf2_callback)(ConnectionInfo *conn,
const char *data1, const int length1, const char *data2,
const int length2, const int timeout_ms);
typedef int (*fc_rdma_request_by_iov_callback)(ConnectionInfo *conn,
const struct iovec *iov, const int iovcnt,
const int timeout_ms);
typedef int (*fc_rdma_request_by_mix_callback)(ConnectionInfo *conn,
const char *data, const int length, const struct iovec *iov,
const int iovcnt, const int timeout_ms);
typedef int (*fc_rdma_send_by_buf1_callback)(ConnectionInfo *conn,
const char *data, const int length);
typedef int (*fc_rdma_recv_data_callback)(ConnectionInfo *conn,
const bool call_post_recv, const int timeout_ms);
typedef int (*fc_rdma_post_recv_callback)(ConnectionInfo *conn);
typedef struct {
fc_make_connection_callback make_connection;
fc_close_connection_callback close_connection;
fc_is_connected_callback is_connected;
} CommonConnectionCallbacks;
typedef struct {
fc_set_busy_polling_callback set_busy_polling;
fc_alloc_pd_callback alloc_pd;
fc_get_connection_size_callback get_connection_size;
fc_init_connection_callback init_connection;
fc_make_connection_callback make_connection;
fc_close_connection_callback close_connection;
fc_destroy_connection_callback destroy_connection;
fc_is_connected_callback is_connected;
fc_send_done_callback send_done;
fc_rdma_get_recv_buffer_callback get_recv_buffer;
fc_rdma_request_by_buf1_callback request_by_buf1;
fc_rdma_request_by_buf2_callback request_by_buf2;
fc_rdma_request_by_iov_callback request_by_iov;
fc_rdma_request_by_mix_callback request_by_mix;
fc_rdma_send_by_buf1_callback send_by_buf1;
fc_rdma_recv_data_callback recv_data;
fc_rdma_post_recv_callback post_recv;
} RDMAConnectionCallbacks;
typedef struct {
bool inited;
CommonConnectionCallbacks common_callbacks[2];
RDMAConnectionCallbacks rdma_callbacks;
} ConnectionCallbacks;
typedef struct {
struct {
bool enabled;
int htable_capacity;
} tls; //for thread local
struct {
bool double_buffers;
int buffer_size;
struct ibv_pd *pd;
} rdma;
} ConnectionExtraParams;
typedef int (*fc_connection_callback_func)(ConnectionInfo *conn, void *args); typedef int (*fc_connection_callback_func)(ConnectionInfo *conn, void *args);
struct tagConnectionManager; struct tagConnectionManager;
@ -62,16 +152,32 @@ typedef struct tagConnectionNode {
} ConnectionNode; } ConnectionNode;
typedef struct tagConnectionManager { typedef struct tagConnectionManager {
ConnectionNode *head; string_t key;
int total_count; //total connections ConnectionNode *head;
int free_count; //free connections int total_count; //total connections
pthread_mutex_t lock; int free_count; //free connections
struct tagConnectionManager *next;
} ConnectionManager; } ConnectionManager;
typedef struct tagConnectionBucket {
ConnectionManager *head;
pthread_mutex_t lock;
} ConnectionBucket;
struct tagConnectionPool;
typedef struct {
ConnectionNode **buckets;
struct tagConnectionPool *cp;
} ConnectionThreadHashTable;
typedef struct tagConnectionPool { typedef struct tagConnectionPool {
HashArray hash_array; //key is ip:port, value is ConnectionManager struct {
pthread_mutex_t lock; ConnectionBucket *buckets;
int connect_timeout; uint32_t capacity;
} hashtable;
int connect_timeout_ms;
int max_count_per_entry; //0 means no limit int max_count_per_entry; //0 means no limit
/* /*
@ -79,7 +185,6 @@ typedef struct tagConnectionPool {
unit: second unit: second
*/ */
int max_idle_time; int max_idle_time;
int socket_domain; //socket domain
struct fast_mblock_man manager_allocator; struct fast_mblock_man manager_allocator;
struct fast_mblock_man node_allocator; struct fast_mblock_man node_allocator;
@ -93,8 +198,29 @@ typedef struct tagConnectionPool {
fc_connection_callback_func func; fc_connection_callback_func func;
void *args; void *args;
} validate_callback; } validate_callback;
int extra_data_size;
ConnectionExtraParams extra_params;
pthread_key_t tls_key; //for ConnectionThreadHashTable
} ConnectionPool; } ConnectionPool;
typedef struct {
int htable_capacity;
int bucket_used;
int server_count;
struct {
int total_count;
int free_count;
} connection;
} ConnectionPoolStat;
extern ConnectionCallbacks g_connection_callbacks;
int conn_pool_global_init_for_rdma();
#define G_COMMON_CONNECTION_CALLBACKS g_connection_callbacks.common_callbacks
#define G_RDMA_CONNECTION_CALLBACKS g_connection_callbacks.rdma_callbacks
/** /**
* init ex function * init ex function
* parameters: * parameters:
@ -102,21 +228,22 @@ typedef struct tagConnectionPool {
* connect_timeout: the connect timeout in seconds * connect_timeout: the connect timeout in seconds
* max_count_per_entry: max connection count per host:port * max_count_per_entry: max connection count per host:port
* max_idle_time: reconnect the server after max idle time in seconds * max_idle_time: reconnect the server after max idle time in seconds
* socket_domain: the socket domain * af: the socket domain
* htable_init_capacity: the init capacity of connection hash table * htable_capacity: the capacity of connection hash table
* connect_done_func: the connect done connection callback * connect_done_func: the connect done connection callback
* connect_done_args: the args for connect done connection callback * connect_done_args: the args for connect done connection callback
* validate_func: the validate connection callback * validate_func: the validate connection callback
* validate_args: the args for validate connection callback * validate_args: the args for validate connection callback
* extra_data_size: the extra data size of connection * extra_data_size: the extra data size of connection
* extra_params: for RDMA
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
int conn_pool_init_ex1(ConnectionPool *cp, int connect_timeout, int conn_pool_init_ex1(ConnectionPool *cp, const int connect_timeout,
const int max_count_per_entry, const int max_idle_time, const int max_count_per_entry, const int max_idle_time,
const int socket_domain, const int htable_init_capacity, const int htable_capacity, fc_connection_callback_func connect_done_func,
fc_connection_callback_func connect_done_func, void *connect_done_args, void *connect_done_args, fc_connection_callback_func validate_func,
fc_connection_callback_func validate_func, void *validate_args, void *validate_args, const int extra_data_size,
const int extra_data_size); const ConnectionExtraParams *extra_params);
/** /**
* init ex function * init ex function
@ -125,18 +252,18 @@ int conn_pool_init_ex1(ConnectionPool *cp, int connect_timeout,
* connect_timeout: the connect timeout in seconds * connect_timeout: the connect timeout in seconds
* max_count_per_entry: max connection count per host:port * max_count_per_entry: max connection count per host:port
* max_idle_time: reconnect the server after max idle time in seconds * max_idle_time: reconnect the server after max idle time in seconds
* socket_domain: the socket domain
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
static inline int conn_pool_init_ex(ConnectionPool *cp, int connect_timeout, static inline int conn_pool_init_ex(ConnectionPool *cp,
const int max_count_per_entry, const int max_idle_time, const int connect_timeout, const int max_count_per_entry,
const int socket_domain) const int max_idle_time)
{ {
const int htable_init_capacity = 0; const int htable_capacity = 0;
const int extra_data_size = 0; const int extra_data_size = 0;
const ConnectionExtraParams *extra_params = NULL;
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry, return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
max_idle_time, socket_domain, htable_init_capacity, max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, extra_data_size); extra_data_size, extra_params);
} }
/** /**
@ -148,15 +275,15 @@ static inline int conn_pool_init_ex(ConnectionPool *cp, int connect_timeout,
* max_idle_time: reconnect the server after max idle time in seconds * max_idle_time: reconnect the server after max idle time in seconds
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
static inline int conn_pool_init(ConnectionPool *cp, int connect_timeout, static inline int conn_pool_init(ConnectionPool *cp, const int connect_timeout,
const int max_count_per_entry, const int max_idle_time) const int max_count_per_entry, const int max_idle_time)
{ {
const int socket_domain = AF_INET; const int htable_capacity = 0;
const int htable_init_capacity = 0;
const int extra_data_size = 0; const int extra_data_size = 0;
const ConnectionExtraParams *extra_params = NULL;
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry, return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
max_idle_time, socket_domain, htable_init_capacity, max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, extra_data_size); extra_data_size, extra_params);
} }
/** /**
@ -173,14 +300,16 @@ void conn_pool_destroy(ConnectionPool *cp);
* cp: the ConnectionPool * cp: the ConnectionPool
* conn: the connection * conn: the connection
* service_name: the service name to log * service_name: the service name to log
* shared: if the connection shared
* err_no: return the the errno, 0 for success * err_no: return the the errno, 0 for success
* return != NULL for success, NULL for error * return != NULL for success, NULL for error
*/ */
ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp, ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp,
const ConnectionInfo *conn, const char *service_name, int *err_no); const ConnectionInfo *conn, const char *service_name,
const bool shared, int *err_no);
#define conn_pool_get_connection(cp, conn, err_no) \ #define conn_pool_get_connection(cp, conn, err_no) \
conn_pool_get_connection_ex(cp, conn, NULL, err_no) conn_pool_get_connection_ex(cp, conn, NULL, false, err_no)
#define conn_pool_close_connection(cp, conn) \ #define conn_pool_close_connection(cp, conn) \
conn_pool_close_connection_ex(cp, conn, false) conn_pool_close_connection_ex(cp, conn, false)
@ -193,82 +322,94 @@ ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp,
* bForce: set true to close the socket, else only push back to connection pool * bForce: set true to close the socket, else only push back to connection pool
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn, int conn_pool_close_connection_ex(ConnectionPool *cp,
const bool bForce); ConnectionInfo *conn, const bool bForce);
/** /**
* disconnect from the server * disconnect from the server
* parameters: * parameters:
* pConnection: the connection * conn: the connection
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
void conn_pool_disconnect_server(ConnectionInfo *pConnection); static inline void conn_pool_disconnect_server(ConnectionInfo *conn)
{
if (conn->sock >= 0)
{
close(conn->sock);
conn->sock = -1;
}
}
static inline bool conn_pool_is_connected(ConnectionInfo *conn)
{
return (conn->sock >= 0);
}
/** /**
* connect to the server * connect to the server
* parameters: * parameters:
* pConnection: the connection * pConnection: the connection
* service_name: the service name to log * service_name: the service name to log
* connect_timeout: the connect timeout in seconds * connect_timeout_ms: the connect timeout in milliseconds
* bind_ipaddr: the ip address to bind, NULL or empty for any * bind_ipaddr: the ip address to bind, NULL or empty for any
* log_connect_error: if log error info when connect fail * log_connect_error: if log error info when connect fail
* NOTE: pConnection->sock will be closed when it >= 0 before connect * NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
int conn_pool_connect_server_ex1(ConnectionInfo *conn, int conn_pool_connect_server_ex1(ConnectionInfo *conn,
const char *service_name, const int connect_timeout, const char *service_name, const int connect_timeout_ms,
const char *bind_ipaddr, const bool log_connect_error); const char *bind_ipaddr, const bool log_connect_error);
/** /**
* connect to the server * connect to the server
* parameters: * parameters:
* pConnection: the connection * pConnection: the connection
* connect_timeout: the connect timeout in seconds * connect_timeout_ms: the connect timeout in milliseconds
* bind_ipaddr: the ip address to bind, NULL or empty for any * bind_ipaddr: the ip address to bind, NULL or empty for any
* log_connect_error: if log error info when connect fail * log_connect_error: if log error info when connect fail
* NOTE: pConnection->sock will be closed when it >= 0 before connect * NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
static inline int conn_pool_connect_server_ex(ConnectionInfo *pConnection, static inline int conn_pool_connect_server_ex(ConnectionInfo *pConnection,
const int connect_timeout, const char *bind_ipaddr, const int connect_timeout_ms, const char *bind_ipaddr,
const bool log_connect_error) const bool log_connect_error)
{ {
const char *service_name = NULL; const char *service_name = NULL;
return conn_pool_connect_server_ex1(pConnection, service_name, return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout, bind_ipaddr, log_connect_error); connect_timeout_ms, bind_ipaddr, log_connect_error);
} }
/** /**
* connect to the server * connect to the server
* parameters: * parameters:
* pConnection: the connection * pConnection: the connection
* connect_timeout: the connect timeout in seconds * connect_timeout_ms: the connect timeout in seconds
* NOTE: pConnection->sock will be closed when it >= 0 before connect * NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
static inline int conn_pool_connect_server(ConnectionInfo *pConnection, static inline int conn_pool_connect_server(ConnectionInfo *pConnection,
const int connect_timeout) const int connect_timeout_ms)
{ {
const char *service_name = NULL; const char *service_name = NULL;
const char *bind_ipaddr = NULL; const char *bind_ipaddr = NULL;
return conn_pool_connect_server_ex1(pConnection, service_name, return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout, bind_ipaddr, true); connect_timeout_ms, bind_ipaddr, true);
} }
/** /**
* connect to the server * connect to the server
* parameters: * parameters:
* pConnection: the connection * pConnection: the connection
* connect_timeout: the connect timeout in seconds * connect_timeout_ms: the connect timeout in seconds
* return 0 for success, != 0 for error * return 0 for success, != 0 for error
*/ */
static inline int conn_pool_connect_server_anyway(ConnectionInfo *pConnection, static inline int conn_pool_connect_server_anyway(ConnectionInfo *pConnection,
const int connect_timeout) const int connect_timeout_ms)
{ {
const char *service_name = NULL; const char *service_name = NULL;
const char *bind_ipaddr = NULL; const char *bind_ipaddr = NULL;
pConnection->sock = -1; pConnection->sock = -1;
return conn_pool_connect_server_ex1(pConnection, service_name, return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout, bind_ipaddr, true); connect_timeout_ms, bind_ipaddr, true);
} }
/** /**
@ -287,12 +428,13 @@ int conn_pool_async_connect_server_ex(ConnectionInfo *conn,
/** /**
* get connection count of the pool * connection pool stat
* parameters: * parameters:
* cp: the ConnectionPool * cp: the ConnectionPool
* return current connection count * stat: the output stat
* return none
*/ */
int conn_pool_get_connection_count(ConnectionPool *cp); void conn_pool_stat(ConnectionPool *cp, ConnectionPoolStat *stat);
/** /**
* load server info from config file * load server info from config file
@ -330,10 +472,9 @@ int conn_pool_parse_server_info(const char *pServerStr,
static inline void conn_pool_set_server_info(ConnectionInfo *pServerInfo, static inline void conn_pool_set_server_info(ConnectionInfo *pServerInfo,
const char *ip_addr, const int port) const char *ip_addr, const int port)
{ {
snprintf(pServerInfo->ip_addr, sizeof(pServerInfo->ip_addr), fc_safe_strcpy(pServerInfo->ip_addr, ip_addr);
"%s", ip_addr);
pServerInfo->port = port; pServerInfo->port = port;
pServerInfo->socket_domain = AF_UNSPEC; pServerInfo->af = is_ipv6_addr(ip_addr) ? AF_INET6 : AF_INET;
pServerInfo->sock = -1; pServerInfo->sock = -1;
} }
@ -347,6 +488,55 @@ static inline int conn_pool_compare_ip_and_port(const char *ip1,
return port1 - port2; return port1 - port2;
} }
ConnectionInfo *conn_pool_alloc_connection_ex(
const FCCommunicationType comm_type,
const int extra_data_size,
const ConnectionExtraParams *extra_params,
int *err_no);
static inline ConnectionInfo *conn_pool_alloc_connection(
const FCCommunicationType comm_type,
const ConnectionExtraParams *extra_params,
int *err_no)
{
const int extra_data_size = 0;
return conn_pool_alloc_connection_ex(comm_type,
extra_data_size, extra_params, err_no);
}
static inline void conn_pool_free_connection(ConnectionInfo *conn)
{
free(conn);
}
int conn_pool_set_rdma_extra_params_ex(ConnectionExtraParams *extra_params,
struct fc_server_config *server_cfg, const int server_group_index,
const bool double_buffers);
static inline int conn_pool_set_rdma_extra_params(
ConnectionExtraParams *extra_params,
struct fc_server_config *server_cfg,
const int server_group_index)
{
const bool double_buffers = false;
return conn_pool_set_rdma_extra_params_ex(extra_params,
server_cfg, server_group_index, double_buffers);
}
static inline const char *fc_comm_type_str(const FCCommunicationType type)
{
switch (type) {
case fc_comm_type_sock:
return "socket";
case fc_comm_type_rdma:
return "rdma";
case fc_comm_type_both:
return "both";
default:
return "unkown";
}
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -25,8 +25,6 @@
#define BYTES_ALIGN(x, pad_mask) (((x) + pad_mask) & (~pad_mask)) #define BYTES_ALIGN(x, pad_mask) (((x) + pad_mask) & (~pad_mask))
static struct fast_allocator_info malloc_allocator;
#define ADD_ALLOCATOR_TO_ARRAY(acontext, allocator, _pooled) \ #define ADD_ALLOCATOR_TO_ARRAY(acontext, allocator, _pooled) \
do { \ do { \
(allocator)->index = acontext->allocator_array.count; \ (allocator)->index = acontext->allocator_array.count; \
@ -57,17 +55,19 @@ static int fast_allocator_malloc_trunk_check(const int alloc_bytes, void *args)
acontext->allocator_array.malloc_bytes_limit ? 0 : EOVERFLOW; acontext->allocator_array.malloc_bytes_limit ? 0 : EOVERFLOW;
} }
static void fast_allocator_malloc_trunk_notify_func(const int alloc_bytes, void *args) static void fast_allocator_malloc_trunk_notify_func(
const enum fast_mblock_notify_type type,
const struct fast_mblock_malloc *node, void *args)
{ {
if (alloc_bytes > 0) if (type == fast_mblock_notify_type_alloc)
{ {
__sync_add_and_fetch(&((struct fast_allocator_context *)args)-> __sync_add_and_fetch(&((struct fast_allocator_context *)args)->
allocator_array.malloc_bytes, alloc_bytes); allocator_array.malloc_bytes, node->trunk_size);
} }
else else
{ {
__sync_sub_and_fetch(&((struct fast_allocator_context *)args)-> __sync_sub_and_fetch(&((struct fast_allocator_context *)args)->
allocator_array.malloc_bytes, -1 * alloc_bytes); allocator_array.malloc_bytes, node->trunk_size);
} }
} }
@ -140,6 +140,7 @@ static int region_init(struct fast_allocator_context *acontext,
*object_callbacks, struct fast_region_info *region) *object_callbacks, struct fast_region_info *region)
{ {
const int64_t alloc_elements_limit = 0; const int64_t alloc_elements_limit = 0;
const int prealloc_trunk_count = 0;
int result; int result;
int bytes; int bytes;
int element_size; int element_size;
@ -194,7 +195,8 @@ static int region_init(struct fast_allocator_context *acontext,
trunk_callbacks.args = acontext; trunk_callbacks.args = acontext;
result = fast_mblock_init_ex2(&allocator->mblock, name, element_size, result = fast_mblock_init_ex2(&allocator->mblock, name, element_size,
region->alloc_elements_once, alloc_elements_limit, region->alloc_elements_once, alloc_elements_limit,
object_callbacks, acontext->need_lock, &trunk_callbacks); prealloc_trunk_count, object_callbacks,
acontext->need_lock, &trunk_callbacks);
if (result != 0) if (result != 0)
{ {
break; break;
@ -341,7 +343,9 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
return result; return result;
} }
ADD_ALLOCATOR_TO_ARRAY(acontext, &malloc_allocator, false); ADD_ALLOCATOR_TO_ARRAY(acontext, &acontext->
allocator_array.malloc_allocator, false);
/* /*
logInfo("sizeof(struct fast_allocator_wrapper): %d, allocator_array count: %d", logInfo("sizeof(struct fast_allocator_wrapper): %d, allocator_array count: %d",
(int)sizeof(struct fast_allocator_wrapper), acontext->allocator_array.count); (int)sizeof(struct fast_allocator_wrapper), acontext->allocator_array.count);
@ -414,7 +418,7 @@ static struct fast_allocator_info *get_allocator(struct fast_allocator_context
} }
} }
return &malloc_allocator; return &acontext->allocator_array.malloc_allocator;
} }
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext, int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
@ -459,6 +463,15 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
return *total_reclaim_bytes > 0 ? 0 : EAGAIN; return *total_reclaim_bytes > 0 ? 0 : EAGAIN;
} }
static inline void malloc_trunk_notify(
const enum fast_mblock_notify_type type,
const int alloc_bytes, void *args)
{
struct fast_mblock_malloc node;
node.trunk_size = alloc_bytes;
fast_allocator_malloc_trunk_notify_func(type, &node, args);
}
void *fast_allocator_alloc(struct fast_allocator_context *acontext, void *fast_allocator_alloc(struct fast_allocator_context *acontext,
const int bytes) const int bytes)
{ {
@ -512,7 +525,8 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
{ {
return NULL; return NULL;
} }
fast_allocator_malloc_trunk_notify_func(alloc_bytes, acontext); malloc_trunk_notify(fast_mblock_notify_type_alloc,
alloc_bytes, acontext);
obj = (char *)ptr + sizeof(struct fast_allocator_wrapper); obj = (char *)ptr + sizeof(struct fast_allocator_wrapper);
if (acontext->allocator_array.allocators[0]->mblock. if (acontext->allocator_array.allocators[0]->mblock.
@ -576,7 +590,7 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
} }
else else
{ {
fast_allocator_malloc_trunk_notify_func(-1 * malloc_trunk_notify(fast_mblock_notify_type_reclaim,
pWrapper->alloc_bytes, acontext); pWrapper->alloc_bytes, acontext);
if (acontext->allocator_array.allocators[0]->mblock. if (acontext->allocator_array.allocators[0]->mblock.

View File

@ -46,14 +46,15 @@ struct fast_region_info
struct fast_allocator_array struct fast_allocator_array
{ {
int count; int count;
int alloc; int alloc;
int reclaim_interval; //< 0 for never reclaim int reclaim_interval; //< 0 for never reclaim
int last_reclaim_time; int last_reclaim_time;
volatile int64_t malloc_bytes; //total alloc bytes volatile int64_t malloc_bytes; //total alloc bytes
int64_t malloc_bytes_limit; //water mark bytes for malloc int64_t malloc_bytes_limit; //water mark bytes for malloc
double expect_usage_ratio; double expect_usage_ratio;
struct fast_allocator_info **allocators; struct fast_allocator_info malloc_allocator;
struct fast_allocator_info **allocators;
}; };
struct fast_allocator_wrapper { struct fast_allocator_wrapper {

View File

@ -26,23 +26,28 @@
#include "fc_memory.h" #include "fc_memory.h"
#include "fast_buffer.h" #include "fast_buffer.h"
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity) int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity,
const bool binary_mode, const bool check_capacity)
{ {
buffer->length = 0; buffer->length = 0;
buffer->binary_mode = binary_mode;
if (init_capacity > 0) if (init_capacity > 0)
{ {
buffer->alloc_size = init_capacity; buffer->alloc_size = init_capacity;
buffer->check_capacity = check_capacity;
} }
else else
{ {
buffer->alloc_size = 256; buffer->alloc_size = 256;
buffer->check_capacity = true;
} }
buffer->data = (char *)fc_malloc(buffer->alloc_size); buffer->data = (char *)fc_malloc(buffer->alloc_size);
if (buffer->data == NULL) if (buffer->data == NULL)
{ {
return ENOMEM; return ENOMEM;
} }
*(buffer->data) = '\0';
fast_buffer_set_null_terminator(buffer);
return 0; return 0;
} }
@ -88,7 +93,9 @@ int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity)
if (buffer->length > 0) { if (buffer->length > 0) {
memcpy(buff, buffer->data, buffer->length); memcpy(buff, buffer->data, buffer->length);
*(buff + buffer->length) = '\0'; if (!buffer->binary_mode) {
*(buff + buffer->length) = '\0';
}
} }
free(buffer->data); free(buffer->data);
@ -127,7 +134,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
} }
else else
{ {
*(buffer->data + buffer->length) = '\0'; //restore fast_buffer_set_null_terminator(buffer); //restore
} }
} }
return result; return result;
@ -148,7 +155,7 @@ int fast_buffer_append_buff(FastBuffer *buffer, const char *data, const int len)
memcpy(buffer->data + buffer->length, data, len); memcpy(buffer->data + buffer->length, data, len);
buffer->length += len; buffer->length += len;
*(buffer->data + buffer->length) = '\0'; fast_buffer_set_null_terminator(buffer);
return 0; return 0;
} }
@ -171,32 +178,6 @@ int fast_buffer_append_binary(FastBuffer *buffer,
return 0; return 0;
} }
int fast_buffer_append_int(FastBuffer *buffer, const int n)
{
int result;
if ((result=fast_buffer_check(buffer, 16)) != 0)
{
return result;
}
buffer->length += sprintf(buffer->data + buffer->length, "%d", n);
return 0;
}
int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n)
{
int result;
if ((result=fast_buffer_check(buffer, 32)) != 0)
{
return result;
}
buffer->length += sprintf(buffer->data + buffer->length, "%"PRId64, n);
return 0;
}
int fast_buffer_append_file(FastBuffer *buffer, const char *filename) int fast_buffer_append_file(FastBuffer *buffer, const char *filename)
{ {
struct stat st; struct stat st;

View File

@ -17,12 +17,14 @@
#define __FAST_BUFFER_H__ #define __FAST_BUFFER_H__
#include <stdint.h> #include <stdint.h>
#include "common_define.h" #include "shared_func.h"
typedef struct fast_buffer { typedef struct fast_buffer {
char *data; char *data;
int alloc_size; int alloc_size;
int length; int length;
bool binary_mode;
bool check_capacity;
} FastBuffer; } FastBuffer;
#ifdef __cplusplus #ifdef __cplusplus
@ -39,26 +41,39 @@ static inline char *fast_buffer_data(FastBuffer *buffer)
return buffer->data; return buffer->data;
} }
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity); int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity,
const bool binary_mode, const bool check_capacity);
static inline int fast_buffer_init1(FastBuffer *buffer, const int init_capacity)
{
const bool binary_mode = false;
const bool check_capacity = true;
return fast_buffer_init_ex(buffer, init_capacity,
binary_mode, check_capacity);
}
static inline int fast_buffer_init(FastBuffer *buffer) static inline int fast_buffer_init(FastBuffer *buffer)
{ {
return fast_buffer_init_ex(buffer, 0); const int init_capacity = 0;
return fast_buffer_init1(buffer, init_capacity);
} }
#define fast_buffer_set_null_terminator(buffer) \
if (!buffer->binary_mode) *(buffer->data + buffer->length) = '\0'
#define fast_buffer_check(buffer, inc_len) \
((buffer)->check_capacity ? fast_buffer_check_inc_size(buffer, inc_len) : 0)
#define fast_buffer_clear(buffer) fast_buffer_reset(buffer) #define fast_buffer_clear(buffer) fast_buffer_reset(buffer)
static inline void fast_buffer_reset(FastBuffer *buffer) static inline void fast_buffer_reset(FastBuffer *buffer)
{ {
buffer->length = 0; buffer->length = 0;
*buffer->data = '\0'; fast_buffer_set_null_terminator(buffer);
} }
void fast_buffer_destroy(FastBuffer *buffer); void fast_buffer_destroy(FastBuffer *buffer);
#define fast_buffer_check(buffer, inc_len) \
fast_buffer_check_inc_size(buffer, inc_len)
int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity); int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity);
static inline int fast_buffer_check_capacity(FastBuffer *buffer, static inline int fast_buffer_check_capacity(FastBuffer *buffer,
@ -86,9 +101,50 @@ int fast_buffer_append_buff(FastBuffer *buffer,
int fast_buffer_append_binary(FastBuffer *buffer, int fast_buffer_append_binary(FastBuffer *buffer,
const void *data, const int len); const void *data, const int len);
int fast_buffer_append_int(FastBuffer *buffer, const int n); static inline int fast_buffer_append_char(FastBuffer *buffer, const char ch)
{
int result;
int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n); if ((result=fast_buffer_check(buffer, 1)) != 0)
{
return result;
}
*(buffer->data + buffer->length++) = ch;
fast_buffer_set_null_terminator(buffer);
return 0;
}
static inline int fast_buffer_append_int32(FastBuffer *buffer, const int n)
{
int result;
if ((result=fast_buffer_check(buffer, 16)) != 0)
{
return result;
}
buffer->length += fc_itoa(n, buffer->data + buffer->length);
fast_buffer_set_null_terminator(buffer);
return 0;
}
static inline int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n)
{
int result;
if ((result=fast_buffer_check(buffer, 32)) != 0)
{
return result;
}
buffer->length += fc_itoa(n, buffer->data + buffer->length);
fast_buffer_set_null_terminator(buffer);
return 0;
}
#define fast_buffer_append_int(buffer, n) \
fast_buffer_append_int64(buffer, n)
int fast_buffer_append_file(FastBuffer *buffer, const char *filename); int fast_buffer_append_file(FastBuffer *buffer, const char *filename);

View File

@ -42,9 +42,6 @@ struct _fast_mblock_manager
static struct _fast_mblock_manager mblock_manager = {false, 0}; static struct _fast_mblock_manager mblock_manager = {false, 0};
#define fast_mblock_get_trunk_size(mblock, block_size, element_count) \
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
int fast_mblock_manager_init() int fast_mblock_manager_init()
{ {
int result; int result;
@ -328,10 +325,10 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
{ {
amem = (int64_t)pStat->trunk_size * pStat->trunk_total_count; amem = (int64_t)pStat->trunk_size * pStat->trunk_total_count;
alloc_mem += amem; alloc_mem += amem;
used_mem += GET_BLOCK_SIZE(*pStat) * used_mem += fast_mblock_get_block_size(pStat->
pStat->element_used_count; element_size) * pStat->element_used_count;
delay_free_mem += GET_BLOCK_SIZE(*pStat) * delay_free_mem += fast_mblock_get_block_size(pStat->
pStat->delay_free_elements; element_size) * pStat->delay_free_elements;
} }
else else
{ {
@ -401,100 +398,6 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
return 0; return 0;
} }
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit,
struct fast_mblock_object_callbacks *object_callbacks,
const bool need_lock, struct fast_mblock_trunk_callbacks
*trunk_callbacks)
{
int result;
if (element_size <= 0)
{
logError("file: "__FILE__", line: %d, " \
"invalid block size: %d", \
__LINE__, element_size);
return EINVAL;
}
mblock->info.element_size = MEM_ALIGN(element_size);
mblock->alloc_elements.limit = alloc_elements_limit;
mblock->info.block_size = fast_mblock_get_block_size(mblock);
if (alloc_elements_once > 0)
{
mblock->alloc_elements.once = alloc_elements_once;
}
else
{
mblock->alloc_elements.once = (1024 * 1024) / mblock->info.block_size;
}
if (mblock->alloc_elements.limit > 0 && mblock->alloc_elements.once >
mblock->alloc_elements.limit)
{
mblock->alloc_elements.once = mblock->alloc_elements.limit;
}
if (need_lock && (result=init_pthread_lock_cond_pair(&(mblock->lcp))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if (object_callbacks == NULL)
{
mblock->object_callbacks.init_func = NULL;
mblock->object_callbacks.destroy_func = NULL;
mblock->object_callbacks.args = NULL;
}
else
{
mblock->object_callbacks = *object_callbacks;
}
INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->info.delay_free_elements = 0;
mblock->free_chain_head = NULL;
mblock->delay_free_chain.head = NULL;
mblock->delay_free_chain.tail = NULL;
mblock->info.element_total_count = 0;
mblock->info.element_used_count = 0;
mblock->info.instance_count = 1;
mblock->info.trunk_size = fast_mblock_get_trunk_size(mblock,
mblock->info.block_size, mblock->alloc_elements.once);
mblock->need_lock = need_lock;
mblock->alloc_elements.need_wait = false;
mblock->alloc_elements.pcontinue_flag = NULL;
mblock->alloc_elements.exceed_log_level = LOG_ERR;
if (trunk_callbacks == NULL)
{
mblock->trunk_callbacks.check_func = NULL;
mblock->trunk_callbacks.notify_func = NULL;
mblock->trunk_callbacks.args = NULL;
}
else
{
mblock->trunk_callbacks = *trunk_callbacks;
}
if (name != NULL)
{
snprintf(mblock->info.name, sizeof(mblock->info.name), "%s", name);
}
else
{
*mblock->info.name = '\0';
}
add_to_mblock_list(mblock);
return 0;
}
static int fast_mblock_prealloc(struct fast_mblock_man *mblock) static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
{ {
struct fast_mblock_node *pNode; struct fast_mblock_node *pNode;
@ -526,7 +429,7 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
alloc_count = avail_count > mblock->alloc_elements.once ? alloc_count = avail_count > mblock->alloc_elements.once ?
mblock->alloc_elements.once : avail_count; mblock->alloc_elements.once : avail_count;
trunk_size = fast_mblock_get_trunk_size(mblock, trunk_size = fast_mblock_get_trunk_size(
mblock->info.block_size, alloc_count); mblock->info.block_size, alloc_count);
} }
else else
@ -574,8 +477,8 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
#endif #endif
} }
((struct fast_mblock_node *)pLast)->next = NULL; ((struct fast_mblock_node *)pLast)->next = mblock->freelist.head;
mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart; mblock->freelist.head = (struct fast_mblock_node *)pTrunkStart;
pMallocNode->ref_count = 0; pMallocNode->ref_count = 0;
pMallocNode->alloc_count = alloc_count; pMallocNode->alloc_count = alloc_count;
@ -589,8 +492,114 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
mblock->info.element_total_count += alloc_count; mblock->info.element_total_count += alloc_count;
if (mblock->trunk_callbacks.notify_func != NULL) if (mblock->trunk_callbacks.notify_func != NULL)
{ {
mblock->trunk_callbacks.notify_func(trunk_size, mblock->trunk_callbacks.notify_func(fast_mblock_notify_type_alloc,
mblock->trunk_callbacks.args); pMallocNode, mblock->trunk_callbacks.args);
}
return 0;
}
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, const int prealloc_trunk_count,
struct fast_mblock_object_callbacks *object_callbacks,
const bool need_lock, struct fast_mblock_trunk_callbacks
*trunk_callbacks)
{
int result;
int i;
if (element_size <= 0)
{
logError("file: "__FILE__", line: %d, " \
"invalid block size: %d", \
__LINE__, element_size);
return EINVAL;
}
mblock->info.element_size = MEM_ALIGN(element_size);
mblock->alloc_elements.limit = alloc_elements_limit;
mblock->info.block_size = fast_mblock_get_block_size(
mblock->info.element_size);
if (alloc_elements_once > 0)
{
mblock->alloc_elements.once = alloc_elements_once;
}
else
{
mblock->alloc_elements.once = (1024 * 1024) / mblock->info.block_size;
}
if (mblock->alloc_elements.limit > 0 && mblock->alloc_elements.once >
mblock->alloc_elements.limit)
{
mblock->alloc_elements.once = mblock->alloc_elements.limit;
}
if (need_lock && (result=init_pthread_lock_cond_pair(&(mblock->lcp))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if (object_callbacks == NULL)
{
mblock->object_callbacks.init_func = NULL;
mblock->object_callbacks.destroy_func = NULL;
mblock->object_callbacks.args = NULL;
}
else
{
mblock->object_callbacks = *object_callbacks;
}
INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->info.delay_free_elements = 0;
mblock->freelist.head = NULL;
mblock->delay_free_chain.head = NULL;
mblock->delay_free_chain.tail = NULL;
mblock->info.element_total_count = 0;
mblock->info.element_used_count = 0;
mblock->info.instance_count = 1;
mblock->info.trunk_size = fast_mblock_get_trunk_size(
mblock->info.block_size, mblock->alloc_elements.once);
mblock->need_lock = need_lock;
mblock->alloc_elements.need_wait = false;
mblock->alloc_elements.pcontinue_flag = NULL;
mblock->alloc_elements.exceed_log_level = LOG_ERR;
if (trunk_callbacks == NULL)
{
mblock->trunk_callbacks.check_func = NULL;
mblock->trunk_callbacks.notify_func = NULL;
mblock->trunk_callbacks.args = NULL;
}
else
{
mblock->trunk_callbacks = *trunk_callbacks;
}
if (name != NULL)
{
fc_safe_strcpy(mblock->info.name, name);
}
else
{
*mblock->info.name = '\0';
}
add_to_mblock_list(mblock);
for (i=0; i<prealloc_trunk_count; i++)
{
if ((result=fast_mblock_prealloc(mblock)) != 0)
{
fast_mblock_destroy(mblock);
return result;
}
} }
return 0; return 0;
@ -606,8 +615,8 @@ static inline void fast_mblock_remove_trunk(struct fast_mblock_man *mblock,
if (mblock->trunk_callbacks.notify_func != NULL) if (mblock->trunk_callbacks.notify_func != NULL)
{ {
mblock->trunk_callbacks.notify_func(-1 * pMallocNode->trunk_size, mblock->trunk_callbacks.notify_func(fast_mblock_notify_type_reclaim,
mblock->trunk_callbacks.args); pMallocNode, mblock->trunk_callbacks.args);
} }
} }
@ -657,9 +666,11 @@ static inline void fast_mblock_ref_counter_op(struct fast_mblock_man *mblock,
} }
#define fast_mblock_ref_counter_inc(mblock, pNode) \ #define fast_mblock_ref_counter_inc(mblock, pNode) \
mblock->info.element_used_count++; \
fast_mblock_ref_counter_op(mblock, pNode, true) fast_mblock_ref_counter_op(mblock, pNode, true)
#define fast_mblock_ref_counter_dec(mblock, pNode) \ #define fast_mblock_ref_counter_dec(mblock, pNode) \
mblock->info.element_used_count--; \
fast_mblock_ref_counter_op(mblock, pNode, false) fast_mblock_ref_counter_op(mblock, pNode, false)
static void fast_mblock_free_trunk(struct fast_mblock_man *mblock, static void fast_mblock_free_trunk(struct fast_mblock_man *mblock,
@ -703,7 +714,7 @@ void fast_mblock_destroy(struct fast_mblock_man *mblock)
INIT_HEAD(&mblock->trunks.head); INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0; mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0; mblock->info.trunk_used_count = 0;
mblock->free_chain_head = NULL; mblock->freelist.head = NULL;
mblock->info.element_used_count = 0; mblock->info.element_used_count = 0;
mblock->info.delay_free_elements = 0; mblock->info.delay_free_elements = 0;
mblock->info.element_total_count = 0; mblock->info.element_total_count = 0;
@ -721,10 +732,10 @@ static inline struct fast_mblock_node *alloc_node(
while (1) while (1)
{ {
if (mblock->free_chain_head != NULL) if (mblock->freelist.head != NULL)
{ {
pNode = mblock->free_chain_head; pNode = mblock->freelist.head;
mblock->free_chain_head = pNode->next; mblock->freelist.head = pNode->next;
break; break;
} }
@ -739,14 +750,15 @@ static inline struct fast_mblock_node *alloc_node(
mblock->delay_free_chain.tail = NULL; mblock->delay_free_chain.tail = NULL;
} }
fast_mblock_ref_counter_dec(mblock, pNode);
mblock->info.delay_free_elements--; mblock->info.delay_free_elements--;
break; break;
} }
if ((result=fast_mblock_prealloc(mblock)) == 0) if ((result=fast_mblock_prealloc(mblock)) == 0)
{ {
pNode = mblock->free_chain_head; pNode = mblock->freelist.head;
mblock->free_chain_head = pNode->next; mblock->freelist.head = pNode->next;
break; break;
} }
@ -766,7 +778,6 @@ static inline struct fast_mblock_node *alloc_node(
if (pNode != NULL) if (pNode != NULL)
{ {
mblock->info.element_used_count++;
fast_mblock_ref_counter_inc(mblock, pNode); fast_mblock_ref_counter_inc(mblock, pNode);
} }
@ -818,10 +829,9 @@ int fast_mblock_free(struct fast_mblock_man *mblock,
return result; return result;
} }
notify = (mblock->free_chain_head == NULL); notify = (mblock->freelist.head == NULL);
pNode->next = mblock->free_chain_head; pNode->next = mblock->freelist.head;
mblock->free_chain_head = pNode; mblock->freelist.head = pNode;
mblock->info.element_used_count--;
fast_mblock_ref_counter_dec(mblock, pNode); fast_mblock_ref_counter_dec(mblock, pNode);
if (mblock->alloc_elements.need_wait && notify) if (mblock->alloc_elements.need_wait && notify)
@ -845,19 +855,21 @@ static inline void batch_free(struct fast_mblock_man *mblock,
struct fast_mblock_chain *chain) struct fast_mblock_chain *chain)
{ {
bool notify; bool notify;
int count;
struct fast_mblock_node *pNode; struct fast_mblock_node *pNode;
count = 0;
pNode = chain->head; pNode = chain->head;
while (pNode != NULL) while (pNode != NULL)
{ {
mblock->info.element_used_count--; ++count;
fast_mblock_ref_counter_dec(mblock, pNode); fast_mblock_ref_counter_dec(mblock, pNode);
pNode = pNode->next; pNode = pNode->next;
} }
notify = (mblock->free_chain_head == NULL); notify = (mblock->freelist.head == NULL);
chain->tail->next = mblock->free_chain_head; chain->tail->next = mblock->freelist.head;
mblock->free_chain_head = chain->head; mblock->freelist.head = chain->head;
if (mblock->alloc_elements.need_wait && notify) if (mblock->alloc_elements.need_wait && notify)
{ {
pthread_cond_broadcast(&mblock->lcp.cond); pthread_cond_broadcast(&mblock->lcp.cond);
@ -869,16 +881,17 @@ int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
{ {
struct fast_mblock_node *pNode; struct fast_mblock_node *pNode;
int i; int i;
int lr;
int result; int result;
if (mblock->need_lock && (result=pthread_mutex_lock( if (mblock->need_lock && (lr=pthread_mutex_lock(
&mblock->lcp.lock)) != 0) &mblock->lcp.lock)) != 0)
{ {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"call pthread_mutex_lock fail, " "call pthread_mutex_lock fail, "
"errno: %d, error info: %s", "errno: %d, error info: %s",
__LINE__, result, STRERROR(result)); __LINE__, lr, STRERROR(lr));
return result; return lr;
} }
if ((chain->head=alloc_node(mblock)) != NULL) { if ((chain->head=alloc_node(mblock)) != NULL) {
@ -905,13 +918,13 @@ int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
result = ENOMEM; result = ENOMEM;
} }
if (mblock->need_lock && (result=pthread_mutex_unlock( if (mblock->need_lock && (lr=pthread_mutex_unlock(
&mblock->lcp.lock)) != 0) &mblock->lcp.lock)) != 0)
{ {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"call pthread_mutex_unlock fail, " \ "call pthread_mutex_unlock fail, "
"errno: %d, error info: %s", \ "errno: %d, error info: %s",
__LINE__, result, STRERROR(result)); __LINE__, lr, STRERROR(lr));
} }
return result; return result;
@ -1003,9 +1016,7 @@ int fast_mblock_delay_free(struct fast_mblock_man *mblock,
mblock->delay_free_chain.tail = pNode; mblock->delay_free_chain.tail = pNode;
pNode->next = NULL; pNode->next = NULL;
mblock->info.element_used_count--;
mblock->info.delay_free_elements++; mblock->info.delay_free_elements++;
fast_mblock_ref_counter_dec(mblock, pNode);
if (mblock->need_lock && (result=pthread_mutex_unlock( if (mblock->need_lock && (result=pthread_mutex_unlock(
&mblock->lcp.lock)) != 0) &mblock->lcp.lock)) != 0)
@ -1058,7 +1069,7 @@ static int fast_mblock_chain_count(struct fast_mblock_man *mblock,
int fast_mblock_free_count(struct fast_mblock_man *mblock) int fast_mblock_free_count(struct fast_mblock_man *mblock)
{ {
return fast_mblock_chain_count(mblock, mblock->free_chain_head); return fast_mblock_chain_count(mblock, mblock->freelist.head);
} }
int fast_mblock_delay_free_count(struct fast_mblock_man *mblock) int fast_mblock_delay_free_count(struct fast_mblock_man *mblock)
@ -1070,65 +1081,65 @@ static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count, const int reclaim_target, int *reclaim_count,
struct fast_mblock_malloc **ppFreelist) struct fast_mblock_malloc **ppFreelist)
{ {
struct fast_mblock_node *pPrevious; struct fast_mblock_node *free_chain_prev;
struct fast_mblock_node *pCurrent; struct fast_mblock_node *current;
struct fast_mblock_malloc *pMallocNode; struct fast_mblock_malloc *malloc_node;
struct fast_mblock_malloc *freelist; struct fast_mblock_malloc *freelist;
bool lookup_done; bool lookup_done;
lookup_done = false; lookup_done = false;
*reclaim_count = 0; *reclaim_count = 0;
freelist = NULL; freelist = NULL;
pPrevious = NULL; free_chain_prev = NULL;
pCurrent = mblock->free_chain_head; current = mblock->freelist.head;
mblock->free_chain_head = NULL; mblock->freelist.head = NULL;
while (pCurrent != NULL) while (current != NULL)
{ {
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); malloc_node = FAST_MBLOCK_GET_TRUNK(current);
if (pMallocNode->ref_count > 0 || if (malloc_node->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done)) (malloc_node->ref_count == 0 && lookup_done))
{ //keep in free chain { /* keep in the free chain */
if (pPrevious != NULL) if (free_chain_prev != NULL)
{ {
pPrevious->next = pCurrent; free_chain_prev->next = current;
} }
else else
{ {
mblock->free_chain_head = pCurrent; mblock->freelist.head = current;
} }
pPrevious = pCurrent; free_chain_prev = current;
pCurrent = pCurrent->next; current = current->next;
if (pCurrent == NULL) if (current == NULL)
{ {
goto OUTER; goto OUTER;
} }
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); malloc_node = FAST_MBLOCK_GET_TRUNK(current);
while (pMallocNode->ref_count > 0 || while (malloc_node->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done)) (malloc_node->ref_count == 0 && lookup_done))
{ {
pPrevious = pCurrent; free_chain_prev = current;
pCurrent = pCurrent->next; current = current->next;
if (pCurrent == NULL) if (current == NULL)
{ {
goto OUTER; goto OUTER;
} }
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); malloc_node = FAST_MBLOCK_GET_TRUNK(current);
} }
} }
while (pMallocNode->ref_count < 0 || while (malloc_node->ref_count < 0 ||
(pMallocNode->ref_count == 0 && !lookup_done)) (malloc_node->ref_count == 0 && !lookup_done))
{ {
if (pMallocNode->ref_count == 0) //trigger by the first node if (malloc_node->ref_count == 0) //trigger by the first node only
{ {
fast_mblock_remove_trunk(mblock, pMallocNode); fast_mblock_remove_trunk(mblock, malloc_node);
pMallocNode->ref_count = -1; malloc_node->ref_count = -1;
pMallocNode->next = freelist; malloc_node->next = freelist;
freelist = pMallocNode; freelist = malloc_node;
(*reclaim_count)++; (*reclaim_count)++;
if (reclaim_target > 0 && *reclaim_count == reclaim_target) if (reclaim_target > 0 && *reclaim_count == reclaim_target)
{ {
@ -1136,23 +1147,23 @@ static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock,
} }
} }
pCurrent = pCurrent->next; current = current->next;
if (pCurrent == NULL) if (current == NULL)
{ {
goto OUTER; goto OUTER;
} }
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent); malloc_node = FAST_MBLOCK_GET_TRUNK(current);
} }
} }
OUTER: OUTER:
if (pPrevious != NULL) if (free_chain_prev != NULL)
{ {
pPrevious->next = NULL; free_chain_prev->next = NULL;
} }
/*
{ {
bool old_need_lock; bool old_need_lock;
old_need_lock = mblock->need_lock; old_need_lock = mblock->need_lock;
@ -1163,6 +1174,7 @@ OUTER:
mblock, *reclaim_count, fast_mblock_free_count(mblock)); mblock, *reclaim_count, fast_mblock_free_count(mblock));
mblock->need_lock = old_need_lock; mblock->need_lock = old_need_lock;
} }
*/
*ppFreelist = freelist; *ppFreelist = freelist;
return (freelist != NULL ? 0 : ENOENT); return (freelist != NULL ? 0 : ENOENT);

View File

@ -39,6 +39,11 @@
#define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2 #define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2
#define FAST_MBLOCK_ORDER_BY_USED_RATIO 3 #define FAST_MBLOCK_ORDER_BY_USED_RATIO 3
enum fast_mblock_notify_type {
fast_mblock_notify_type_alloc,
fast_mblock_notify_type_reclaim,
};
/* free node chain */ /* free node chain */
struct fast_mblock_node struct fast_mblock_node
{ {
@ -77,7 +82,8 @@ typedef int (*fast_mblock_malloc_trunk_check_func)(
const int alloc_bytes, void *args); const int alloc_bytes, void *args);
typedef void (*fast_mblock_malloc_trunk_notify_func)( typedef void (*fast_mblock_malloc_trunk_notify_func)(
const int alloc_bytes, void *args); const enum fast_mblock_notify_type type,
const struct fast_mblock_malloc *node, void *args);
struct fast_mblock_info struct fast_mblock_info
{ {
@ -121,7 +127,11 @@ struct fast_mblock_man
int64_t limit; //<= 0 for no limit int64_t limit; //<= 0 for no limit
bool *pcontinue_flag; bool *pcontinue_flag;
} alloc_elements; } alloc_elements;
struct fast_mblock_node *free_chain_head; //free node chain
struct {
struct fast_mblock_node *head;
} freelist; //free node chain
struct fast_mblock_trunks trunks; struct fast_mblock_trunks trunks;
struct fast_mblock_chain delay_free_chain; //delay free node chain struct fast_mblock_chain delay_free_chain; //delay free node chain
@ -134,10 +144,11 @@ struct fast_mblock_man
struct fast_mblock_man *next; //for stat manager struct fast_mblock_man *next; //for stat manager
}; };
#define GET_BLOCK_SIZE(info) \ #define fast_mblock_get_block_size(element_size) \
(MEM_ALIGN(sizeof(struct fast_mblock_node) + (info).element_size)) (MEM_ALIGN(sizeof(struct fast_mblock_node) + element_size))
#define fast_mblock_get_block_size(mblock) GET_BLOCK_SIZE(mblock->info) #define fast_mblock_get_trunk_size(block_size, element_count) \
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
#define fast_mblock_to_node_ptr(data_ptr) \ #define fast_mblock_to_node_ptr(data_ptr) \
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \ (struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
@ -159,6 +170,7 @@ parameters:
element_size: element size, such as sizeof(struct xxx) element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit alloc_elements_limit: malloc elements limit, <= 0 for no limit
prealloc_trunk_count: prealloc trunk node count
object_callbacks: the object callback functions and args object_callbacks: the object callback functions and args
need_lock: if need lock need_lock: if need lock
trunk_callbacks: the trunk callback functions and args trunk_callbacks: the trunk callback functions and args
@ -166,7 +178,7 @@ return error no, 0 for success, != 0 fail
*/ */
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name, int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
const int element_size, const int alloc_elements_once, const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, const int64_t alloc_elements_limit, const int prealloc_trunk_count,
struct fast_mblock_object_callbacks *object_callbacks, struct fast_mblock_object_callbacks *object_callbacks,
const bool need_lock, struct fast_mblock_trunk_callbacks const bool need_lock, struct fast_mblock_trunk_callbacks
*trunk_callbacks); *trunk_callbacks);
@ -190,6 +202,7 @@ static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
fast_mblock_object_init_func init_func, void *init_args, fast_mblock_object_init_func init_func, void *init_args,
const bool need_lock) const bool need_lock)
{ {
const int prealloc_trunk_count = 0;
struct fast_mblock_object_callbacks object_callbacks; struct fast_mblock_object_callbacks object_callbacks;
object_callbacks.init_func = init_func; object_callbacks.init_func = init_func;
@ -197,7 +210,8 @@ static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
object_callbacks.args = init_args; object_callbacks.args = init_args;
return fast_mblock_init_ex2(mblock, name, element_size, return fast_mblock_init_ex2(mblock, name, element_size,
alloc_elements_once, alloc_elements_limit, alloc_elements_once, alloc_elements_limit,
&object_callbacks, need_lock, NULL); prealloc_trunk_count, &object_callbacks,
need_lock, NULL);
} }
/** /**
@ -213,9 +227,8 @@ return error no, 0 for success, != 0 fail
*/ */
static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock, static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock,
const int element_size, const int alloc_elements_once, const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, const int64_t alloc_elements_limit, fast_mblock_object_init_func
fast_mblock_object_init_func init_func, void *init_args, init_func, void *init_args, const bool need_lock)
const bool need_lock)
{ {
return fast_mblock_init_ex1(mblock, NULL, element_size, return fast_mblock_init_ex1(mblock, NULL, element_size,
alloc_elements_once, alloc_elements_limit, alloc_elements_once, alloc_elements_limit,
@ -398,7 +411,7 @@ return the delay free node count of the mblock, return -1 if fail
*/ */
int fast_mblock_delay_free_count(struct fast_mblock_man *mblock); int fast_mblock_delay_free_count(struct fast_mblock_man *mblock);
#define fast_mblock_total_count(mblock) (mblock)->total_count #define fast_mblock_total_count(mblock) (mblock)->info.element_total_count
/** /**
init mblock manager init mblock manager

View File

@ -25,668 +25,214 @@
#include "fc_memory.h" #include "fc_memory.h"
#include "fast_task_queue.h" #include "fast_task_queue.h"
static struct fast_task_queue g_free_queue; static int task_alloc_init(struct fast_task_info *task,
struct fast_task_queue *queue)
struct mpool_node {
struct fast_task_info *blocks;
struct fast_task_info *last_block; //last block
struct mpool_node *next;
};
struct mpool_chain {
struct mpool_node *head;
struct mpool_node *tail;
};
static struct mpool_chain g_mpool = {NULL, NULL};
int task_queue_init(struct fast_task_queue *pQueue)
{ {
int result; task->arg = (char *)task + ALIGNED_TASK_INFO_SIZE + queue->padding_size;
task->send.ptr = &task->send.holder;
if ((result=init_pthread_lock(&(pQueue->lock))) != 0) task->send.ptr->size = queue->min_buff_size;
{ if (queue->malloc_whole_block) {
logError("file: "__FILE__", line: %d, " \ task->send.ptr->data = (char *)task->arg + queue->arg_size;
"init_pthread_lock fail, errno: %d, error info: %s", \ } else {
__LINE__, result, STRERROR(result)); task->send.ptr->data = (char *)fc_malloc(task->send.ptr->size);
return result; if (task->send.ptr->data == NULL) {
}
pQueue->head = NULL;
pQueue->tail = NULL;
return 0;
}
static void free_mpool(struct mpool_node *mpool, char *end)
{
char *pt;
for (pt=(char *)mpool->blocks; pt < end; pt += g_free_queue.block_size)
{
free(((struct fast_task_info *)pt)->data);
}
free(mpool->blocks);
free(mpool);
}
static struct mpool_node *malloc_mpool(const int total_alloc_size)
{
struct fast_task_info *pTask;
char *p;
char *pCharEnd;
struct mpool_node *mpool;
mpool = (struct mpool_node *)fc_malloc(sizeof(struct mpool_node));
if (mpool == NULL)
{
return NULL;
}
mpool->next = NULL;
mpool->blocks = (struct fast_task_info *)fc_malloc(total_alloc_size);
if (mpool->blocks == NULL)
{
free(mpool);
return NULL;
}
memset(mpool->blocks, 0, total_alloc_size);
pCharEnd = ((char *)mpool->blocks) + total_alloc_size;
for (p=(char *)mpool->blocks; p<pCharEnd; p += g_free_queue.block_size)
{
pTask = (struct fast_task_info *)p;
pTask->size = g_free_queue.min_buff_size;
pTask->arg = p + ALIGNED_TASK_INFO_SIZE;
if (g_free_queue.malloc_whole_block)
{
pTask->data = (char *)pTask->arg + \
g_free_queue.arg_size;
}
else
{
pTask->data = (char *)fc_malloc(pTask->size);
if (pTask->data == NULL)
{
free_mpool(mpool, p);
return NULL;
}
}
if (g_free_queue.init_callback != NULL)
{
if (g_free_queue.init_callback(pTask) != 0)
{
free_mpool(mpool, p);
return NULL;
}
}
}
mpool->last_block = (struct fast_task_info *)
(pCharEnd - g_free_queue.block_size);
for (p=(char *)mpool->blocks; p<(char *)mpool->last_block;
p += g_free_queue.block_size)
{
pTask = (struct fast_task_info *)p;
pTask->next = (struct fast_task_info *)(p + g_free_queue.block_size);
}
mpool->last_block->next = NULL;
return mpool;
}
int free_queue_init_ex2(const int max_connections, const int init_connections,
const int alloc_task_once, const int min_buff_size,
const int max_buff_size, const int arg_size,
TaskInitCallback init_callback)
{
#define MAX_DATA_SIZE (256 * 1024 * 1024)
int64_t total_size;
struct mpool_node *mpool;
int alloc_size;
int alloc_once;
int result;
int loop_count;
int aligned_min_size;
int aligned_max_size;
int aligned_arg_size;
rlim_t max_data_size;
if ((result=init_pthread_lock(&(g_free_queue.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
aligned_min_size = MEM_ALIGN(min_buff_size);
aligned_max_size = MEM_ALIGN(max_buff_size);
aligned_arg_size = MEM_ALIGN(arg_size);
g_free_queue.block_size = ALIGNED_TASK_INFO_SIZE + aligned_arg_size;
alloc_size = g_free_queue.block_size * init_connections;
if (aligned_max_size > aligned_min_size)
{
total_size = alloc_size;
g_free_queue.malloc_whole_block = false;
max_data_size = 0;
}
else
{
struct rlimit rlimit_data;
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0)
{
logError("file: "__FILE__", line: %d, " \
"call getrlimit fail, " \
"errno: %d, error info: %s", \
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
if (rlimit_data.rlim_cur == RLIM_INFINITY)
{
max_data_size = MAX_DATA_SIZE;
}
else
{
max_data_size = rlimit_data.rlim_cur;
if (max_data_size > MAX_DATA_SIZE)
{
max_data_size = MAX_DATA_SIZE;
}
}
if (max_data_size >= (int64_t)(g_free_queue.block_size +
aligned_min_size) * (int64_t)init_connections)
{
total_size = alloc_size + (int64_t)aligned_min_size *
init_connections;
g_free_queue.malloc_whole_block = true;
g_free_queue.block_size += aligned_min_size;
}
else
{
total_size = alloc_size;
g_free_queue.malloc_whole_block = false;
max_data_size = 0;
}
}
g_free_queue.max_connections = max_connections;
g_free_queue.alloc_connections = init_connections;
if (alloc_task_once <= 0)
{
g_free_queue.alloc_task_once = 256;
alloc_once = MAX_DATA_SIZE / g_free_queue.block_size;
if (g_free_queue.alloc_task_once > alloc_once)
{
g_free_queue.alloc_task_once = alloc_once > 0 ? alloc_once : 1;
}
}
else
{
g_free_queue.alloc_task_once = alloc_task_once;
}
g_free_queue.min_buff_size = aligned_min_size;
g_free_queue.max_buff_size = aligned_max_size;
g_free_queue.arg_size = aligned_arg_size;
g_free_queue.init_callback = init_callback;
logDebug("file: "__FILE__", line: %d, "
"max_connections: %d, init_connections: %d, alloc_task_once: %d, "
"min_buff_size: %d, max_buff_size: %d, block_size: %d, "
"arg_size: %d, max_data_size: %d, total_size: %"PRId64,
__LINE__, max_connections, init_connections,
g_free_queue.alloc_task_once, aligned_min_size, aligned_max_size,
g_free_queue.block_size, aligned_arg_size, (int)max_data_size, total_size);
if ((!g_free_queue.malloc_whole_block) || (total_size <= max_data_size))
{
loop_count = 1;
mpool = malloc_mpool(total_size);
if (mpool == NULL)
{
return errno != 0 ? errno : ENOMEM;
}
g_mpool.head = mpool;
g_mpool.tail = mpool;
}
else
{
int remain_count;
int alloc_count;
int current_alloc_size;
loop_count = 0;
remain_count = init_connections;
alloc_once = max_data_size / g_free_queue.block_size;
while (remain_count > 0)
{
alloc_count = (remain_count > alloc_once) ?
alloc_once : remain_count;
current_alloc_size = g_free_queue.block_size * alloc_count;
mpool = malloc_mpool(current_alloc_size);
if (mpool == NULL)
{
free_queue_destroy();
return errno != 0 ? errno : ENOMEM;
}
if (g_mpool.tail == NULL)
{
g_mpool.head = mpool;
}
else
{
g_mpool.tail->next = mpool;
g_mpool.tail->last_block->next = mpool->blocks; //link previous mpool to current
}
g_mpool.tail = mpool;
remain_count -= alloc_count;
loop_count++;
}
logDebug("file: "__FILE__", line: %d, " \
"alloc_once: %d", __LINE__, alloc_once);
}
logDebug("file: "__FILE__", line: %d, " \
"malloc task info as whole: %d, malloc loop count: %d", \
__LINE__, g_free_queue.malloc_whole_block, loop_count);
if (g_mpool.head != NULL)
{
g_free_queue.head = g_mpool.head->blocks;
g_free_queue.tail = g_mpool.tail->last_block;
}
return 0;
}
void free_queue_destroy()
{
struct mpool_node *mpool;
struct mpool_node *mp;
if (g_mpool.head == NULL)
{
return;
}
if (!g_free_queue.malloc_whole_block)
{
char *p;
char *pCharEnd;
struct fast_task_info *pTask;
mpool = g_mpool.head;
while (mpool != NULL)
{
pCharEnd = (char *)mpool->last_block + g_free_queue.block_size;
for (p=(char *)mpool->blocks; p<pCharEnd; p += g_free_queue.block_size)
{
pTask = (struct fast_task_info *)p;
if (pTask->data != NULL)
{
free(pTask->data);
pTask->data = NULL;
}
}
mpool = mpool->next;
}
}
mpool = g_mpool.head;
while (mpool != NULL)
{
mp = mpool;
mpool = mpool->next;
free(mp->blocks);
free(mp);
}
g_mpool.head = g_mpool.tail = NULL;
pthread_mutex_destroy(&(g_free_queue.lock));
}
static int free_queue_realloc()
{
struct mpool_node *mpool;
struct fast_task_info *head;
struct fast_task_info *tail;
int remain_count;
int alloc_count;
int current_alloc_size;
head = tail = NULL;
remain_count = g_free_queue.max_connections -
g_free_queue.alloc_connections;
alloc_count = (remain_count > g_free_queue.alloc_task_once) ?
g_free_queue.alloc_task_once : remain_count;
if (alloc_count > 0)
{
current_alloc_size = g_free_queue.block_size * alloc_count;
mpool = malloc_mpool(current_alloc_size);
if (mpool == NULL)
{
return ENOMEM; return ENOMEM;
} }
if (g_mpool.tail == NULL)
{
g_mpool.head = mpool;
}
else
{
g_mpool.tail->next = mpool;
}
g_mpool.tail = mpool;
head = mpool->blocks;
tail = mpool->last_block;
remain_count -= alloc_count;
}
else {
return ENOSPC;
} }
if (g_free_queue.head == NULL) if (queue->double_buffers) {
{ task->recv.ptr = &task->recv.holder;
g_free_queue.head = head; task->recv.ptr->size = queue->min_buff_size;
task->recv.ptr->data = (char *)fc_malloc(task->recv.ptr->size);
if (task->recv.ptr->data == NULL) {
return ENOMEM;
}
} else {
task->recv.ptr = &task->send.holder;
} }
if (g_free_queue.tail != NULL)
{ task->free_queue = queue;
g_free_queue.tail->next = head; if (queue->init_callback != NULL) {
return queue->init_callback(task, queue->init_arg);
} }
g_free_queue.tail = tail;
g_free_queue.alloc_connections += alloc_count;
logDebug("file: "__FILE__", line: %d, "
"alloc_connections: %d, realloc %d elements", __LINE__,
g_free_queue.alloc_connections, alloc_count);
return 0; return 0;
} }
struct fast_task_info *free_queue_pop() int free_queue_init_ex2(struct fast_task_queue *queue, const char *name,
const bool double_buffers, const bool need_shrink,
const int max_connections, const int alloc_task_once,
const int min_buff_size, const int max_buff_size,
const int padding_size, const int arg_size,
TaskInitCallback init_callback, void *init_arg)
{ {
struct fast_task_info *pTask; #define MAX_DATA_SIZE (256 * 1024 * 1024)
int i; int alloc_once;
int aligned_min_size;
int aligned_max_size;
int aligned_padding_size;
int aligned_arg_size;
rlim_t max_data_size;
char aname[64];
if ((pTask=task_queue_pop(&g_free_queue)) != NULL) aligned_min_size = MEM_ALIGN(min_buff_size);
{ aligned_max_size = MEM_ALIGN(max_buff_size);
return pTask; aligned_padding_size = MEM_ALIGN(padding_size);
aligned_arg_size = MEM_ALIGN(arg_size);
queue->block_size = ALIGNED_TASK_INFO_SIZE +
aligned_padding_size + aligned_arg_size;
if (alloc_task_once <= 0) {
alloc_once = FC_MIN(MAX_DATA_SIZE / queue->block_size, 256);
if (alloc_once == 0) {
alloc_once = 1;
}
} else {
alloc_once = alloc_task_once;
} }
if (g_free_queue.alloc_connections >= g_free_queue.max_connections) if (aligned_max_size > aligned_min_size) {
{ queue->malloc_whole_block = false;
return NULL; max_data_size = 0;
} } else {
struct rlimit rlimit_data;
for (i=0; i<10; i++) if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0) {
{ logError("file: "__FILE__", line: %d, "
pthread_mutex_lock(&g_free_queue.lock); "call getrlimit fail, "
if (g_free_queue.alloc_connections >= g_free_queue.max_connections) "errno: %d, error info: %s",
{ __LINE__, errno, STRERROR(errno));
if (g_free_queue.head == NULL) return errno != 0 ? errno : EPERM;
{ }
pthread_mutex_unlock(&g_free_queue.lock); if (rlimit_data.rlim_cur == RLIM_INFINITY) {
return NULL; max_data_size = MAX_DATA_SIZE;
} else {
max_data_size = rlimit_data.rlim_cur;
if (max_data_size > MAX_DATA_SIZE) {
max_data_size = MAX_DATA_SIZE;
} }
} }
else
{
if (g_free_queue.head == NULL && free_queue_realloc() != 0)
{
pthread_mutex_unlock(&g_free_queue.lock);
return NULL;
}
}
pthread_mutex_unlock(&g_free_queue.lock);
if ((pTask=task_queue_pop(&g_free_queue)) != NULL) if (max_data_size >= (int64_t)(queue->block_size +
aligned_min_size) * (int64_t)alloc_once)
{ {
return pTask; queue->malloc_whole_block = true;
queue->block_size += aligned_min_size;
} else {
queue->malloc_whole_block = false;
max_data_size = 0;
} }
} }
return NULL; queue->double_buffers = double_buffers;
queue->need_shrink = need_shrink;
queue->min_buff_size = aligned_min_size;
queue->max_buff_size = aligned_max_size;
queue->padding_size = aligned_padding_size;
queue->arg_size = aligned_arg_size;
queue->init_callback = init_callback;
queue->init_arg = init_arg;
queue->release_callback = NULL;
/*
logInfo("file: "__FILE__", line: %d, [%s] double_buffers: %d, "
"max_connections: %d, alloc_once: %d, malloc_whole_block: %d, "
"min_buff_size: %d, max_buff_size: %d, block_size: %d, "
"padding_size: %d, arg_size: %d, max_data_size: %"PRId64,
__LINE__, name, double_buffers, max_connections, alloc_once,
queue->malloc_whole_block, aligned_min_size, aligned_max_size,
queue->block_size, aligned_padding_size, aligned_arg_size,
(int64_t)max_data_size);
*/
fc_combine_two_strings(name, "task", '-', aname);
return fast_mblock_init_ex1(&queue->allocator, aname,
queue->block_size, alloc_once, max_connections,
(fast_mblock_object_init_func)task_alloc_init,
queue, true);
} }
static int _realloc_buffer(struct fast_task_info *pTask, const int new_size, void free_queue_destroy(struct fast_task_queue *queue)
const bool copy_data) {
fast_mblock_destroy(&queue->allocator);
}
static int _realloc_buffer(struct fast_net_buffer *buffer,
const int new_size, const bool copy_data)
{ {
char *new_buff; char *new_buff;
new_buff = (char *)fc_malloc(new_size); new_buff = (char *)fc_malloc(new_size);
if (new_buff == NULL) if (new_buff == NULL) {
{
return ENOMEM; return ENOMEM;
} }
else
{ if (copy_data && buffer->offset > 0) {
if (copy_data && pTask->offset > 0) { memcpy(new_buff, buffer->data, buffer->offset);
memcpy(new_buff, pTask->data, pTask->offset);
}
free(pTask->data);
pTask->size = new_size;
pTask->data = new_buff;
return 0;
} }
free(buffer->data);
buffer->size = new_size;
buffer->data = new_buff;
return 0;
} }
int free_queue_push(struct fast_task_info *pTask) void free_queue_push(struct fast_task_info *task)
{ {
int result; if (task->free_queue->release_callback != NULL) {
task->free_queue->release_callback(task);
}
*(pTask->client_ip) = '\0'; *(task->client_ip) = '\0';
pTask->length = 0; task->send.ptr->length = 0;
pTask->offset = 0; task->send.ptr->offset = 0;
pTask->req_count = 0; task->req_count = 0;
if (task->free_queue->need_shrink && task->send.
ptr->size > task->free_queue->min_buff_size)
{ //need thrink
_realloc_buffer(task->send.ptr, task->free_queue->
min_buff_size, false);
task->shrinked = true;
}
if (pTask->size > g_free_queue.min_buff_size) //need thrink if (task->free_queue->double_buffers) {
{ task->recv.ptr->length = 0;
_realloc_buffer(pTask, g_free_queue.min_buff_size, false); task->recv.ptr->offset = 0;
} if (task->free_queue->need_shrink && task->recv.
ptr->size > task->free_queue->min_buff_size)
{
_realloc_buffer(task->recv.ptr, task->free_queue->
min_buff_size, false);
task->shrinked = true;
}
}
if ((result=pthread_mutex_lock(&g_free_queue.lock)) != 0) fast_mblock_free_object(&task->free_queue->allocator, task);
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
pTask->next = g_free_queue.head;
g_free_queue.head = pTask;
if (g_free_queue.tail == NULL)
{
g_free_queue.tail = pTask;
}
if ((result=pthread_mutex_unlock(&g_free_queue.lock)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return result;
} }
int free_queue_count() int free_queue_get_new_buffer_size(const int min_buff_size,
{
return task_queue_count(&g_free_queue);
}
int free_queue_alloc_connections()
{
return g_free_queue.alloc_connections;
}
int free_queue_set_buffer_size(struct fast_task_info *pTask,
const int expect_size)
{
return task_queue_set_buffer_size(&g_free_queue, pTask, expect_size);
}
int free_queue_realloc_buffer(struct fast_task_info *pTask,
const int expect_size)
{
return task_queue_realloc_buffer(&g_free_queue, pTask, expect_size);
}
int free_queue_set_max_buffer_size(struct fast_task_info *pTask)
{
return task_queue_set_buffer_size(&g_free_queue, pTask,
g_free_queue.max_buff_size);
}
int free_queue_realloc_max_buffer(struct fast_task_info *pTask)
{
return task_queue_realloc_buffer(&g_free_queue, pTask,
g_free_queue.max_buff_size);
}
int task_queue_push(struct fast_task_queue *pQueue, \
struct fast_task_info *pTask)
{
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
pTask->next = NULL;
if (pQueue->tail == NULL)
{
pQueue->head = pTask;
}
else
{
pQueue->tail->next = pTask;
}
pQueue->tail = pTask;
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return 0;
}
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return NULL;
}
pTask = pQueue->head;
if (pTask != NULL)
{
pQueue->head = pTask->next;
if (pQueue->head == NULL)
{
pQueue->tail = NULL;
}
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return pTask;
}
int task_queue_count(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int count;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return 0;
}
count = 0;
pTask = pQueue->head;
while (pTask != NULL)
{
pTask = pTask->next;
count++;
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return count;
}
int task_queue_get_new_buffer_size(const int min_buff_size,
const int max_buff_size, const int expect_size, int *new_size) const int max_buff_size, const int expect_size, int *new_size)
{ {
if (min_buff_size == max_buff_size) if (min_buff_size == max_buff_size) {
{
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"can't change buffer size because NOT supported", __LINE__); "can't change buffer size because NOT supported", __LINE__);
return EOPNOTSUPP; return EOPNOTSUPP;
} }
if (expect_size > max_buff_size) if (expect_size > max_buff_size) {
{
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"can't change buffer size because expect buffer size: %d " "can't change buffer size because expect buffer size: %d "
"exceeds max buffer size: %d", __LINE__, expect_size, "exceeds max buffer size: %d", __LINE__, expect_size,
max_buff_size); max_buff_size);
return EOVERFLOW; return EOVERFLOW;
} else if (expect_size == max_buff_size) {
*new_size = max_buff_size;
return 0;
} }
*new_size = min_buff_size; *new_size = min_buff_size;
if (expect_size > min_buff_size) if (expect_size > min_buff_size) {
{ while (*new_size < expect_size) {
while (*new_size < expect_size)
{
*new_size *= 2; *new_size *= 2;
} }
if (*new_size > max_buff_size) if (*new_size > max_buff_size) {
{
*new_size = max_buff_size; *new_size = max_buff_size;
} }
} }
@ -694,41 +240,43 @@ int task_queue_get_new_buffer_size(const int min_buff_size,
return 0; return 0;
} }
#define _get_new_buffer_size(pQueue, expect_size, new_size) \ #define _get_new_buffer_size(queue, expect_size, new_size) \
task_queue_get_new_buffer_size(pQueue->min_buff_size, \ free_queue_get_new_buffer_size(queue->min_buff_size, \
pQueue->max_buff_size, expect_size, new_size) queue->max_buff_size, expect_size, new_size)
int task_queue_set_buffer_size(struct fast_task_queue *pQueue, int free_queue_set_buffer_size(struct fast_task_info *task,
struct fast_task_info *pTask, const int expect_size) struct fast_net_buffer *buffer, const int expect_size)
{ {
int result; int result;
int new_size; int new_size;
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) { if ((result=_get_new_buffer_size(task->free_queue,
expect_size, &new_size)) != 0)
{
return result; return result;
} }
if (pTask->size == new_size) //do NOT need change buffer size if (buffer->size == new_size) { //do NOT need change buffer size
{
return 0; return 0;
} }
return _realloc_buffer(pTask, new_size, false); return _realloc_buffer(buffer, new_size, false);
} }
int task_queue_realloc_buffer(struct fast_task_queue *pQueue, int free_queue_realloc_buffer(struct fast_task_info *task,
struct fast_task_info *pTask, const int expect_size) struct fast_net_buffer *buffer, const int expect_size)
{ {
int result; int result;
int new_size; int new_size;
if (pTask->size >= expect_size) //do NOT need change buffer size if (buffer->size >= expect_size) { //do NOT need change buffer size
{
return 0; return 0;
} }
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) { if ((result=_get_new_buffer_size(task->free_queue,
expect_size, &new_size)) != 0)
{
return result; return result;
} }
return _realloc_buffer(pTask, new_size, true); return _realloc_buffer(buffer, new_size, true);
} }

View File

@ -23,8 +23,10 @@
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include "common_define.h" #include "common_define.h"
#include "fc_list.h"
#include "ioevent.h" #include "ioevent.h"
#include "fast_timer.h" #include "fast_timer.h"
#include "fast_mblock.h"
#define FC_NOTIFY_READ_FD(tdata) (tdata)->pipe_fds[0] #define FC_NOTIFY_READ_FD(tdata) (tdata)->pipe_fds[0]
#define FC_NOTIFY_WRITE_FD(tdata) (tdata)->pipe_fds[1] #define FC_NOTIFY_WRITE_FD(tdata) (tdata)->pipe_fds[1]
@ -35,19 +37,27 @@ struct nio_thread_data;
struct fast_task_info; struct fast_task_info;
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData); typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
typedef int (*TaskFinishCallback) (struct fast_task_info *pTask); typedef void (*TaskCleanUpCallback) (struct fast_task_info *task);
typedef void (*TaskCleanUpCallback) (struct fast_task_info *pTask); typedef int (*TaskInitCallback)(struct fast_task_info *task, void *arg);
typedef int (*TaskInitCallback)(struct fast_task_info *pTask); typedef void (*TaskReleaseCallback)(struct fast_task_info *task);
typedef void (*IOEventCallback) (int sock, short event, void *arg); typedef void (*IOEventCallback) (int sock, const int event, void *arg);
typedef int (*TaskContinueCallback)(struct fast_task_info *task); typedef int (*TaskContinueCallback)(struct fast_task_info *task);
struct sf_network_handler;
struct fast_task_info; struct fast_task_info;
#if IOEVENT_USE_URING
#define FC_URING_OP_TYPE(task) (task)->uring.op_type
#define FC_URING_IS_CLIENT(task) (task)->uring.is_client
#define FC_URING_IS_SEND_ZC(task) ((task)->uring.op_type == IORING_OP_SEND_ZC)
#endif
typedef struct ioevent_entry typedef struct ioevent_entry
{ {
FastTimerEntry timer; //must first FastTimerEntry timer; //must first
int fd; int fd;
int res; //just for io_uring, since v1.0.81
IOEventCallback callback; IOEventCallback callback;
} IOEventEntry; } IOEventEntry;
@ -58,6 +68,7 @@ struct nio_thread_data
int pipe_fds[2]; //for notify int pipe_fds[2]; //for notify
struct fast_task_info *deleted_list; //tasks for cleanup struct fast_task_info *deleted_list; //tasks for cleanup
ThreadLoopCallback thread_loop_callback; ThreadLoopCallback thread_loop_callback;
ThreadLoopCallback busy_polling_callback;
void *arg; //extra argument pointer void *arg; //extra argument pointer
struct { struct {
struct fast_task_info *head; struct fast_task_info *head;
@ -69,6 +80,9 @@ struct nio_thread_data
bool enabled; bool enabled;
volatile int64_t counter; volatile int64_t counter;
} notify; //for thread notify } notify; //for thread notify
int timeout_ms; //for restore
struct fc_list_head polling_queue; //for RDMA busy polling
}; };
struct ioevent_notify_entry struct ioevent_notify_entry
@ -77,15 +91,29 @@ struct ioevent_notify_entry
struct nio_thread_data *thread_data; struct nio_thread_data *thread_data;
}; };
struct fast_net_buffer
{
int size; //alloc size
int length; //data length
int offset; //current offset
char *data; //buffer for write or read
};
struct fast_net_buffer_wrapper
{
struct fast_net_buffer holder;
struct fast_net_buffer *ptr;
};
struct fast_task_queue;
struct fast_task_info struct fast_task_info
{ {
IOEventEntry event; //must first IOEventEntry event; //must first
union { union {
char server_ip[IP_ADDRESS_SIZE]; char server_ip[IP_ADDRESS_SIZE];
char client_ip[IP_ADDRESS_SIZE]; char client_ip[IP_ADDRESS_SIZE];
}; };
void *arg; //extra argument pointer void *arg; //extra argument pointer
char *data; //buffer for write or read
char *recv_body; //for extra (dynamic) recv buffer char *recv_body; //for extra (dynamic) recv buffer
struct { struct {
@ -93,94 +121,195 @@ struct fast_task_info
int count; int count;
} iovec_array; //for writev } iovec_array; //for writev
int size; //alloc size struct fast_net_buffer_wrapper send; //send buffer
int length; //data length struct fast_net_buffer_wrapper recv; //recv buffer
int offset; //current offset
uint16_t port; //peer port uint16_t port; //peer port
struct {
int8_t is_client;
uint8_t op_type;
} uring; //just for io_uring, since v1.0.81
struct { struct {
uint8_t current; uint8_t current;
volatile uint8_t notify; volatile uint8_t notify;
} nio_stages; //stages for network IO } nio_stages; //stages for network IO
TaskContinueCallback continue_callback; //for continue stage
volatile int8_t reffer_count;
volatile int8_t canceled; //if task canceled volatile int8_t canceled; //if task canceled
short connect_timeout; //for client side volatile int8_t shrinked; //if task shrinked, since V1.0.81
short network_timeout; volatile int reffer_count;
int64_t req_count; //request count int pending_send_count;
TaskFinishCallback finish_callback; int64_t req_count; //request count
struct nio_thread_data *thread_data; struct {
void *ctx; //context pointer for libserverframe nio int64_t last_req_count;
struct fast_task_info *next; uint32_t last_calc_time;
uint16_t continuous_count;
bool in_queue;
struct fc_list_head dlink; //for polling queue
} polling; //for RDMA busy polling
TaskContinueCallback continue_callback; //for continue stage
struct nio_thread_data *thread_data;
struct sf_network_handler *handler; //network handler for libserverframe nio
struct fast_task_info *next; //for free queue and deleted list
struct fast_task_info *notify_next; //for nio notify queue
struct fast_task_queue *free_queue; //task allocator
char conn[0]; //for RDMA connection
}; };
struct fast_task_queue struct fast_task_queue
{ {
struct fast_task_info *head; int min_buff_size;
struct fast_task_info *tail; int max_buff_size;
pthread_mutex_t lock; int padding_size; //for last field: conn[0]
int max_connections; int arg_size; //for arg pointer
int alloc_connections; int block_size;
int alloc_task_once; bool malloc_whole_block;
int min_buff_size; bool double_buffers; //if send buffer and recv buffer are independent
int max_buff_size; bool need_shrink;
int arg_size; struct fast_mblock_man allocator;
int block_size;
bool malloc_whole_block;
TaskInitCallback init_callback; TaskInitCallback init_callback;
void *init_arg;
TaskReleaseCallback release_callback;
}; };
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int free_queue_init_ex2(const int max_connections, const int init_connections, int free_queue_init_ex2(struct fast_task_queue *queue, const char *name,
const bool double_buffers, const bool need_shrink,
const int max_connections, const int alloc_task_once,
const int min_buff_size, const int max_buff_size,
const int padding_size, const int arg_size,
TaskInitCallback init_callback, void *init_arg);
static inline int free_queue_init_ex(struct fast_task_queue *queue,
const char *name, const bool double_buffers,
const bool need_shrink, const int max_connections,
const int alloc_task_once, const int min_buff_size, const int alloc_task_once, const int min_buff_size,
const int max_buff_size, const int arg_size, const int max_buff_size, const int arg_size)
TaskInitCallback init_callback);
static inline int free_queue_init_ex(const int max_connections,
const int init_connections, const int alloc_task_once,
const int min_buff_size, const int max_buff_size, const int arg_size)
{ {
return free_queue_init_ex2(max_connections, init_connections, const int padding_size = 0;
alloc_task_once, min_buff_size, max_buff_size, arg_size, NULL); return free_queue_init_ex2(queue, name, double_buffers, need_shrink,
max_connections, alloc_task_once, min_buff_size, max_buff_size,
padding_size, arg_size, NULL, NULL);
} }
static inline int free_queue_init(const int max_connections, static inline int free_queue_init(struct fast_task_queue *queue,
const int min_buff_size, const int max_buff_size, const int arg_size) const int max_connections, const int alloc_task_once,
const int min_buff_size, const int max_buff_size)
{ {
return free_queue_init_ex2(max_connections, max_connections, const char *name = "";
0, min_buff_size, max_buff_size, arg_size, NULL); const bool double_buffers = false;
const bool need_shrink = true;
const int arg_size = 0;
return free_queue_init_ex(queue, name, double_buffers,
need_shrink, max_connections, alloc_task_once,
min_buff_size, max_buff_size, arg_size);
} }
void free_queue_destroy(); static inline void free_queue_set_release_callback(
struct fast_task_queue *queue,
TaskReleaseCallback callback)
{
queue->release_callback = callback;
}
int free_queue_push(struct fast_task_info *pTask); void free_queue_destroy(struct fast_task_queue *queue);
struct fast_task_info *free_queue_pop();
int free_queue_count();
int free_queue_alloc_connections();
int free_queue_set_buffer_size(struct fast_task_info *pTask,
const int expect_size);
int free_queue_realloc_buffer(struct fast_task_info *pTask,
const int expect_size);
int free_queue_set_max_buffer_size(struct fast_task_info *pTask); static inline struct fast_task_info *free_queue_pop(
struct fast_task_queue *queue)
{
return (struct fast_task_info *)fast_mblock_alloc_object(&queue->allocator);
}
int free_queue_realloc_max_buffer(struct fast_task_info *pTask); void free_queue_push(struct fast_task_info *task);
int task_queue_init(struct fast_task_queue *pQueue); static inline int free_queue_count(struct fast_task_queue *queue)
int task_queue_push(struct fast_task_queue *pQueue, \ {
struct fast_task_info *pTask); return queue->allocator.info.element_total_count -
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue); queue->allocator.info.element_used_count;
int task_queue_count(struct fast_task_queue *pQueue); }
int task_queue_set_buffer_size(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size);
int task_queue_realloc_buffer(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size);
int task_queue_get_new_buffer_size(const int min_buff_size, static inline int free_queue_alloc_connections(struct fast_task_queue *queue)
{
return queue->allocator.info.element_total_count;
}
int free_queue_get_new_buffer_size(const int min_buff_size,
const int max_buff_size, const int expect_size, int *new_size); const int max_buff_size, const int expect_size, int *new_size);
int free_queue_set_buffer_size(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size);
static inline int free_queue_set_max_buffer_size(
struct fast_task_info *task,
struct fast_net_buffer *buffer)
{
return free_queue_set_buffer_size(task, buffer,
task->free_queue->max_buff_size);
}
int free_queue_realloc_buffer(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size);
static inline int free_queue_realloc_max_buffer(
struct fast_task_info *task,
struct fast_net_buffer *buffer)
{
return free_queue_realloc_buffer(task, buffer,
task->free_queue->max_buff_size);
}
/* send and recv buffer operations */
static inline int free_queue_set_send_buffer_size(
struct fast_task_info *task, const int expect_size)
{
return free_queue_set_buffer_size(task, task->send.ptr, expect_size);
}
static inline int free_queue_set_recv_buffer_size(
struct fast_task_info *task, const int expect_size)
{
return free_queue_set_buffer_size(task, task->recv.ptr, expect_size);
}
static inline int free_queue_set_send_max_buffer_size(
struct fast_task_info *task)
{
return free_queue_set_max_buffer_size(task, task->send.ptr);
}
static inline int free_queue_set_recv_max_buffer_size(
struct fast_task_info *task)
{
return free_queue_set_max_buffer_size(task, task->recv.ptr);
}
static inline int free_queue_realloc_send_buffer(
struct fast_task_info *task, const int expect_size)
{
return free_queue_realloc_buffer(task, task->send.ptr, expect_size);
}
static inline int free_queue_realloc_recv_buffer(
struct fast_task_info *task, const int expect_size)
{
return free_queue_realloc_buffer(task, task->recv.ptr, expect_size);
}
static inline int free_queue_realloc_send_max_buffer(
struct fast_task_info *task)
{
return free_queue_realloc_max_buffer(task, task->send.ptr);
}
static inline int free_queue_realloc_recv_max_buffer(
struct fast_task_info *task)
{
return free_queue_realloc_max_buffer(task, task->recv.ptr);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -105,6 +105,7 @@ int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
if ((result=fast_timer_remove(timer, entry)) == 0) { if ((result=fast_timer_remove(timer, entry)) == 0) {
fast_timer_add_ex(timer, entry, new_expires, true); fast_timer_add_ex(timer, entry, new_expires, true);
} }
return result; return result;
} }
return 0; return 0;
@ -185,6 +186,7 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
} else { } else {
last->rehash = false; last->rehash = false;
} }
continue; continue;
} }
} else { //expired } else { //expired

View File

@ -45,6 +45,16 @@ fc_list_add_before (struct fc_list_head *_new, struct fc_list_head *current)
_new->next->prev = _new; _new->next->prev = _new;
} }
static inline void
fc_list_add_after (struct fc_list_head *_new, struct fc_list_head *current)
{
_new->prev = current;
_new->next = current->next;
current->next->prev = _new;
current->next = _new;
}
static inline void static inline void
fc_list_add_internal (struct fc_list_head *_new, struct fc_list_head *prev, fc_list_add_internal (struct fc_list_head *_new, struct fc_list_head *prev,
struct fc_list_head *next) struct fc_list_head *next)

View File

@ -22,7 +22,7 @@ int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
{ {
int result; int result;
if ((result=init_pthread_lock_cond_pair(&queue->lc_pair)) != 0) if ((result=init_pthread_lock_cond_pair(&queue->lcp)) != 0)
{ {
return result; return result;
} }
@ -35,12 +35,12 @@ int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
void fc_queue_destroy(struct fc_queue *queue) void fc_queue_destroy(struct fc_queue *queue)
{ {
destroy_pthread_lock_cond_pair(&queue->lc_pair); destroy_pthread_lock_cond_pair(&queue->lcp);
} }
void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify) void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify)
{ {
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
FC_QUEUE_NEXT_PTR(queue, data) = NULL; FC_QUEUE_NEXT_PTR(queue, data) = NULL;
if (queue->tail == NULL) { if (queue->tail == NULL) {
queue->head = data; queue->head = data;
@ -50,15 +50,58 @@ void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify)
*notify = false; *notify = false;
} }
queue->tail = data; queue->tail = data;
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
}
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); static inline bool fc_queue_exists(struct fc_queue *queue, void *data)
{
void *current;
if (queue->head == NULL) {
return false;
}
current = queue->head;
do {
if (current == data) {
return true;
}
current = FC_QUEUE_NEXT_PTR(queue, current);
} while (current != NULL);
return false;
}
int fc_queue_push_with_check_ex(struct fc_queue *queue,
void *data, bool *notify)
{
int result;
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
if (fc_queue_exists(queue, data)) {
result = EEXIST;
*notify = false;
} else {
result = 0;
FC_QUEUE_NEXT_PTR(queue, data) = NULL;
if (queue->tail == NULL) {
queue->head = data;
*notify = true;
} else {
FC_QUEUE_NEXT_PTR(queue, queue->tail) = data;
*notify = false;
}
queue->tail = data;
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return result;
} }
void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked) void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
{ {
void *data; void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
do { do {
data = queue->head; data = queue->head;
if (data == NULL) { if (data == NULL) {
@ -66,7 +109,7 @@ void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
break; break;
} }
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock); pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head; data = queue->head;
} }
@ -78,7 +121,7 @@ void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
} }
} while (0); } while (0);
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data; return data;
} }
@ -86,7 +129,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
{ {
void *data; void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
do { do {
data = queue->head; data = queue->head;
if (data == NULL) { if (data == NULL) {
@ -94,7 +137,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
break; break;
} }
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock); pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head; data = queue->head;
} }
@ -103,7 +146,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
} }
} while (0); } while (0);
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data; return data;
} }
@ -115,7 +158,7 @@ void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
return; return;
} }
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
FC_QUEUE_NEXT_PTR(queue, qinfo->tail) = queue->head; FC_QUEUE_NEXT_PTR(queue, qinfo->tail) = queue->head;
queue->head = qinfo->head; queue->head = qinfo->head;
if (queue->tail == NULL) { if (queue->tail == NULL) {
@ -124,7 +167,7 @@ void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
} else { } else {
*notify = false; *notify = false;
} }
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
} }
void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue, void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
@ -135,7 +178,7 @@ void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
return; return;
} }
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
if (queue->head == NULL) { if (queue->head == NULL) {
queue->head = qinfo->head; queue->head = qinfo->head;
*notify = true; *notify = true;
@ -144,16 +187,16 @@ void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
*notify = false; *notify = false;
} }
queue->tail = qinfo->tail; queue->tail = qinfo->tail;
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
} }
void fc_queue_pop_to_queue_ex(struct fc_queue *queue, void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, const bool blocked) struct fc_queue_info *qinfo, const bool blocked)
{ {
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
if (queue->head == NULL) { if (queue->head == NULL) {
if (blocked) { if (blocked) {
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock); pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
} }
} }
@ -164,7 +207,7 @@ void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
} else { } else {
qinfo->head = qinfo->tail = NULL; qinfo->head = qinfo->tail = NULL;
} }
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
} }
void *fc_queue_timedpop(struct fc_queue *queue, void *fc_queue_timedpop(struct fc_queue *queue,
@ -172,10 +215,10 @@ void *fc_queue_timedpop(struct fc_queue *queue,
{ {
void *data; void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
data = queue->head; data = queue->head;
if (data == NULL) { if (data == NULL) {
fc_cond_timedwait(&queue->lc_pair, timeout, time_unit); fc_cond_timedwait(&queue->lcp, timeout, time_unit);
data = queue->head; data = queue->head;
} }
@ -185,7 +228,7 @@ void *fc_queue_timedpop(struct fc_queue *queue,
queue->tail = NULL; queue->tail = NULL;
} }
} }
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data; return data;
} }
@ -195,13 +238,13 @@ void *fc_queue_timedpeek(struct fc_queue *queue,
{ {
void *data; void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
data = queue->head; data = queue->head;
if (data == NULL) { if (data == NULL) {
fc_cond_timedwait(&queue->lc_pair, timeout, time_unit); fc_cond_timedwait(&queue->lcp, timeout, time_unit);
data = queue->head; data = queue->head;
} }
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data; return data;
} }
@ -252,3 +295,49 @@ int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
chain.tail = previous; chain.tail = previous;
return fast_mblock_batch_free(mblock, &chain); return fast_mblock_batch_free(mblock, &chain);
} }
int fc_queue_remove(struct fc_queue *queue, void *data)
{
void *previous;
void *current;
int result;
pthread_mutex_lock(&queue->lcp.lock);
if (queue->head == NULL)
{
result = ENOENT;
}
else if (queue->head == data)
{
queue->head = FC_QUEUE_NEXT_PTR(queue, queue->head);
if (queue->head == NULL)
{
queue->tail = NULL;
}
result = 0;
}
else
{
result = ENOENT;
previous = queue->head;
while ((current=FC_QUEUE_NEXT_PTR(queue, previous)) != NULL)
{
if (current == data)
{
FC_QUEUE_NEXT_PTR(queue, previous) =
FC_QUEUE_NEXT_PTR(queue, current);
if (queue->tail == current)
{
queue->tail = previous;
}
result = 0;
break;
}
previous = current;
}
}
pthread_mutex_unlock(&queue->lcp.lock);
return result;
}

View File

@ -31,7 +31,7 @@ struct fc_queue
{ {
void *head; void *head;
void *tail; void *tail;
pthread_lock_cond_pair_t lc_pair; pthread_lock_cond_pair_t lcp;
int next_ptr_offset; int next_ptr_offset;
}; };
@ -49,7 +49,7 @@ void fc_queue_destroy(struct fc_queue *queue);
static inline void fc_queue_terminate(struct fc_queue *queue) static inline void fc_queue_terminate(struct fc_queue *queue)
{ {
pthread_cond_signal(&queue->lc_pair.cond); pthread_cond_signal(&queue->lcp.cond);
} }
static inline void fc_queue_terminate_all( static inline void fc_queue_terminate_all(
@ -57,7 +57,7 @@ static inline void fc_queue_terminate_all(
{ {
int i; int i;
for (i=0; i<count; i++) { for (i=0; i<count; i++) {
pthread_cond_signal(&(queue->lc_pair.cond)); pthread_cond_signal(&(queue->lcp.cond));
} }
} }
@ -68,6 +68,8 @@ static inline void fc_queue_terminate_all(
//notify by the caller //notify by the caller
void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify); void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify);
int fc_queue_push_with_check_ex(struct fc_queue *queue,
void *data, bool *notify);
static inline void fc_queue_push(struct fc_queue *queue, void *data) static inline void fc_queue_push(struct fc_queue *queue, void *data)
{ {
@ -75,10 +77,23 @@ static inline void fc_queue_push(struct fc_queue *queue, void *data)
fc_queue_push_ex(queue, data, &notify); fc_queue_push_ex(queue, data, &notify);
if (notify) { if (notify) {
pthread_cond_signal(&(queue->lc_pair.cond)); pthread_cond_signal(&(queue->lcp.cond));
} }
} }
static inline int fc_queue_push_with_check(struct fc_queue *queue, void *data)
{
int result;
bool notify;
result = fc_queue_push_with_check_ex(queue, data, &notify);
if (notify) {
pthread_cond_signal(&(queue->lcp.cond));
}
return result;
}
static inline void fc_queue_push_silence(struct fc_queue *queue, void *data) static inline void fc_queue_push_silence(struct fc_queue *queue, void *data)
{ {
bool notify; bool notify;
@ -95,7 +110,7 @@ static inline void fc_queue_push_queue_to_head(struct fc_queue *queue,
fc_queue_push_queue_to_head_ex(queue, qinfo, &notify); fc_queue_push_queue_to_head_ex(queue, qinfo, &notify);
if (notify) { if (notify) {
pthread_cond_signal(&(queue->lc_pair.cond)); pthread_cond_signal(&(queue->lcp.cond));
} }
} }
@ -116,7 +131,7 @@ static inline void fc_queue_push_queue_to_tail(struct fc_queue *queue,
fc_queue_push_queue_to_tail_ex(queue, qinfo, &notify); fc_queue_push_queue_to_tail_ex(queue, qinfo, &notify);
if (notify) { if (notify) {
pthread_cond_signal(&(queue->lc_pair.cond)); pthread_cond_signal(&(queue->lcp.cond));
} }
} }
@ -148,9 +163,9 @@ static inline bool fc_queue_empty(struct fc_queue *queue)
{ {
bool empty; bool empty;
pthread_mutex_lock(&queue->lc_pair.lock); pthread_mutex_lock(&queue->lcp.lock);
empty = (queue->head == NULL); empty = (queue->head == NULL);
pthread_mutex_unlock(&queue->lc_pair.lock); pthread_mutex_unlock(&queue->lcp.lock);
return empty; return empty;
} }
@ -160,17 +175,27 @@ static inline int fc_queue_count(struct fc_queue *queue)
void *data; void *data;
count = 0; count = 0;
pthread_mutex_lock(&queue->lc_pair.lock); pthread_mutex_lock(&queue->lcp.lock);
data = queue->head; data = queue->head;
while (data != NULL) while (data != NULL)
{ {
++count; ++count;
data = FC_QUEUE_NEXT_PTR(queue, data); data = FC_QUEUE_NEXT_PTR(queue, data);
} }
pthread_mutex_unlock(&queue->lc_pair.lock); pthread_mutex_unlock(&queue->lcp.lock);
return count; return count;
} }
static inline void *fc_queue_peek(struct fc_queue *queue)
{
void *data;
pthread_mutex_lock(&queue->lcp.lock);
data = queue->head;
pthread_mutex_unlock(&queue->lcp.lock);
return data;
}
void *fc_queue_timedpop(struct fc_queue *queue, void *fc_queue_timedpop(struct fc_queue *queue,
const int timeout, const int time_unit); const int timeout, const int time_unit);
@ -201,6 +226,8 @@ int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, struct fc_queue_info *qinfo); *mblock, struct fc_queue_info *qinfo);
int fc_queue_remove(struct fc_queue *queue, void *data);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -768,23 +768,22 @@ int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
{ {
if (old_data->value_len < *new_value_len) if (old_data->value_len < *new_value_len)
{ {
memcpy(new_value, old_data->value, old_data->value_len); memcpy(new_value, old_data->value, old_data->value_len);
new_value[old_data->value_len] = '\0'; new_value[old_data->value_len] = '\0';
n = strtoll(new_value, NULL, 10); n = strtoll(new_value, NULL, 10);
n += inc; n += inc;
} }
else else
{ {
n = inc; n = inc;
} }
*new_value_len = sprintf(new_value, "%"PRId64, n);
} }
else else
{ {
n = inc; n = inc;
*new_value_len = sprintf(new_value, "%"PRId64, n);
} }
*new_value_len = fc_itoa(n, new_value);
return n; return n;
} }

View File

@ -27,6 +27,10 @@
((strncasecmp(str, "http://", 7) == 0) || \ ((strncasecmp(str, "http://", 7) == 0) || \
(strncasecmp(str, "https://", 8) == 0)) (strncasecmp(str, "https://", 8) == 0))
#define IS_URL_RESOURCE_EX(s) \
((s)->len >= 8 && ((memcmp((s)->str, "http://", 7) == 0) || \
(memcmp((s)->str, "https://", 8) == 0)))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -84,6 +84,7 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
const char *local_ip; const char *local_ip;
const char *private_ip; const char *private_ip;
struct in_addr ip_addr; struct in_addr ip_addr;
struct in6_addr ip6_addr;
private_ip = get_first_local_private_ip(); private_ip = get_first_local_private_ip();
if (private_ip != NULL) if (private_ip != NULL)
@ -100,16 +101,28 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
context->fd = -1; context->fd = -1;
return ENOENT; return ENOENT;
} }
else if (strcmp(local_ip, LOCAL_LOOPBACK_IP) == 0) else if (strcmp(local_ip, LOCAL_LOOPBACK_IPv4) == 0)
{ {
/* 注意当系统存在IPv6回环地址时为了简化系统的改动
IPv6IPv4
IPv6
*/
logWarning("file: "__FILE__", line: %d, " logWarning("file: "__FILE__", line: %d, "
"can't get local ip address, set to %s", "can't get local ip address, set to %s or %s",
__LINE__, LOCAL_LOOPBACK_IP); __LINE__, LOCAL_LOOPBACK_IPv4, LOCAL_LOOPBACK_IPv6);
} }
} }
if (inet_pton(AF_INET, local_ip, &ip_addr) != 1) if (inet_pton(AF_INET, local_ip, &ip_addr) == 1)
{ {
//do nothing
}
else if(inet_pton(AF_INET6, local_ip, &ip6_addr) == 1)
{
ip_addr.s_addr = *((in_addr_64_t *)&ip6_addr);
}
else
{
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"invalid local ip address: %s", "invalid local ip address: %s",
__LINE__, local_ip); __LINE__, local_ip);

View File

@ -198,7 +198,7 @@ static int iniAnnotationFuncLocalIpGet(IniContext *context,
(int)(square_start - param), param); (int)(square_start - param), param);
index = atoi(square_start + 1); index = atoi(square_start + 1);
} else { } else {
snprintf(name_part, sizeof(name_part) - 1, "%s", param); fc_safe_strcpy(name_part, param);
index = -2; index = -2;
} }
@ -322,7 +322,7 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
logWarning("file: "__FILE__", line: %d, " logWarning("file: "__FILE__", line: %d, "
"NO set directives before, set value to %s", "NO set directives before, set value to %s",
__LINE__, param); __LINE__, param);
snprintf(output, FAST_INI_ITEM_VALUE_SIZE, "%s", param); fc_strlcpy(output, param, FAST_INI_ITEM_VALUE_SIZE);
return output; return output;
} }
@ -652,7 +652,7 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
if (IS_URL_RESOURCE(szFilename)) if (IS_URL_RESOURCE(szFilename))
{ {
*pContext->config_path = '\0'; *pContext->config_path = '\0';
snprintf(full_filename, sizeof(full_filename), "%s", szFilename); fc_safe_strcpy(full_filename, szFilename);
} }
else else
{ {
@ -675,8 +675,7 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
memcpy(pContext->config_path, szFilename, len); memcpy(pContext->config_path, szFilename, len);
*(pContext->config_path + len) = '\0'; *(pContext->config_path + len) = '\0';
snprintf(full_filename, sizeof(full_filename), \ fc_safe_strcpy(full_filename, szFilename);
"%s", szFilename);
} }
else else
{ {
@ -699,9 +698,8 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
*(pContext->config_path + len) = '\0'; *(pContext->config_path + len) = '\0';
} }
snprintf(full_filename, sizeof(full_filename), \ fc_combine_full_filename(pContext->config_path,
"%s/%s", pContext->config_path, szFilename); szFilename, full_filename);
pLast = strrchr(szFilename, '/'); pLast = strrchr(szFilename, '/');
if (pLast != NULL) if (pLast != NULL)
{ {
@ -914,7 +912,7 @@ static int iniAddAnnotation(char *params)
return EFAULT; return EFAULT;
} }
snprintf(symbol, sizeof(symbol), "%s_init_annotation", func_name); fc_combine_two_strings(func_name, "init_annotation", '_', symbol);
init_func = dlsym(dlhandle, symbol); init_func = dlsym(dlhandle, symbol);
if (init_func == NULL) if (init_func == NULL)
{ {
@ -1013,14 +1011,12 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
strncasecmp(pLine+1, "include", 7) == 0 && \ strncasecmp(pLine+1, "include", 7) == 0 && \
(*(pLine+8) == ' ' || *(pLine+8) == '\t')) (*(pLine+8) == ' ' || *(pLine+8) == '\t'))
{ {
snprintf(pIncludeFilename, sizeof(pIncludeFilename), fc_safe_strcpy(pIncludeFilename, pLine + 9);
"%s", pLine + 9);
fc_trim(pIncludeFilename); fc_trim(pIncludeFilename);
if (IS_URL_RESOURCE(pIncludeFilename)) if (IS_URL_RESOURCE(pIncludeFilename))
{ {
snprintf(full_filename, sizeof(full_filename), fc_safe_strcpy(full_filename, pIncludeFilename);
"%s", pIncludeFilename); }
}
else else
{ {
if (IS_FILE_RESOURCE(pIncludeFilename)) if (IS_FILE_RESOURCE(pIncludeFilename))
@ -1034,25 +1030,23 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
if (*pTrueFilename == '/') if (*pTrueFilename == '/')
{ {
snprintf(full_filename, sizeof(full_filename), \ fc_safe_strcpy(full_filename, pTrueFilename);
"%s", pTrueFilename);
} }
else else
{ {
snprintf(full_filename, sizeof(full_filename), \ fc_combine_full_filename(pContext->config_path,
"%s/%s", pContext->config_path, \ pTrueFilename, full_filename);
pTrueFilename); }
}
if (!fileExists(full_filename)) if (!fileExists(full_filename))
{ {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"include file \"%s\" not exists, " \ "include file \"%s\" not exists, "
"line: \"%s\"", __LINE__, \ "line: \"%s\"", __LINE__,
pTrueFilename, pLine); pTrueFilename, pLine);
result = ENOENT; result = ENOENT;
break; break;
} }
} }
pContext->current_section = &pContext->global; pContext->current_section = &pContext->global;
@ -2629,8 +2623,7 @@ static char *iniProccessFor(char *content, const int content_len,
char *pRemain; char *pRemain;
int remainLen; int remainLen;
valueLen = sprintf(value, "%d", i); valueLen = fc_itoa(i, value);
pRemain = pForBlock; pRemain = pForBlock;
remainLen = forBlockLen; remainLen = forBlockLen;
while (remainLen >= tagLen) while (remainLen >= tagLen)
@ -2817,7 +2810,7 @@ do { \
break; \ break; \
} \ } \
\ \
snprintf(targetItem.name, sizeof(targetItem.name), "%s", szItemName); \ fc_safe_strcpy(targetItem.name, szItemName); \
pItem = (IniItem *)bsearch(&targetItem, pSection->items, \ pItem = (IniItem *)bsearch(&targetItem, pSection->items, \
pSection->count, sizeof(IniItem), iniCompareByItemName); \ pSection->count, sizeof(IniItem), iniCompareByItemName); \
} while (0) } while (0)

View File

@ -45,71 +45,119 @@ int kqueue_ev_convert(int16_t event, uint16_t flags)
} }
#endif #endif
int ioevent_init(IOEventPoller *ioevent, const int size, int ioevent_init(IOEventPoller *ioevent, const char *service_name,
const int timeout_ms, const int extra_events) const bool use_io_uring, const int size, const int timeout_ms,
const int extra_events)
{ {
int bytes; int bytes;
ioevent->size = size; ioevent->iterator.index = 0;
ioevent->extra_events = extra_events; ioevent->iterator.count = 0;
ioevent->iterator.index = 0; ioevent->service_name = service_name;
ioevent->iterator.count = 0; ioevent->size = size;
ioevent->extra_events = extra_events;
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
ioevent->poll_fd = epoll_create(ioevent->size); #if IOEVENT_USE_URING
if (ioevent->poll_fd < 0) { ioevent->use_io_uring = use_io_uring;
return errno != 0 ? errno : ENOMEM; if (use_io_uring) {
} int result;
bytes = sizeof(struct epoll_event) * size; if ((result=io_uring_queue_init(size, &ioevent->ring, 0)) < 0) {
ioevent->events = (struct epoll_event *)fc_malloc(bytes); return -result;
}
ioevent->cqe = NULL;
ioevent->submit_count = 0;
ioevent->send_zc_logged = false;
ioevent->send_zc_done_notify = false;
} else {
#endif
ioevent->poll_fd = epoll_create(ioevent->size);
if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM;
}
bytes = sizeof(struct epoll_event) * size;
ioevent->events = (struct epoll_event *)fc_malloc(bytes);
#if IOEVENT_USE_URING
}
#endif
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
ioevent->poll_fd = kqueue(); ioevent->poll_fd = kqueue();
if (ioevent->poll_fd < 0) { if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM; return errno != 0 ? errno : ENOMEM;
} }
bytes = sizeof(struct kevent) * size; bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)fc_malloc(bytes); ioevent->events = (struct kevent *)fc_malloc(bytes);
#elif IOEVENT_USE_PORT #elif IOEVENT_USE_PORT
ioevent->poll_fd = port_create(); ioevent->poll_fd = port_create();
if (ioevent->poll_fd < 0) { if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM; return errno != 0 ? errno : ENOMEM;
} }
bytes = sizeof(port_event_t) * size; bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)fc_malloc(bytes); ioevent->events = (port_event_t *)fc_malloc(bytes);
#endif #endif
if (ioevent->events == NULL) { #if IOEVENT_USE_URING
close(ioevent->poll_fd); if (!ioevent->use_io_uring) {
ioevent->poll_fd = -1; #endif
return ENOMEM; if (ioevent->events == NULL) {
} close(ioevent->poll_fd);
ioevent_set_timeout(ioevent, timeout_ms); ioevent->poll_fd = -1;
return ENOMEM;
}
#if IOEVENT_USE_URING
}
#endif
return 0; ioevent_set_timeout(ioevent, timeout_ms);
return 0;
} }
void ioevent_destroy(IOEventPoller *ioevent) void ioevent_destroy(IOEventPoller *ioevent)
{ {
if (ioevent->events != NULL) { #if IOEVENT_USE_URING
free(ioevent->events); if (ioevent->use_io_uring) {
ioevent->events = NULL; io_uring_queue_exit(&ioevent->ring);
} } else {
#endif
if (ioevent->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
if (ioevent->poll_fd >= 0) { if (ioevent->poll_fd >= 0) {
close(ioevent->poll_fd); close(ioevent->poll_fd);
ioevent->poll_fd = -1; ioevent->poll_fd = -1;
} }
#if IOEVENT_USE_URING
}
#endif
} }
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e, int ioevent_attach(IOEventPoller *ioevent, const int fd,
void *data) const int e, void *data)
{ {
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
struct epoll_event ev; #if IOEVENT_USE_URING
memset(&ev, 0, sizeof(ev)); if (ioevent->use_io_uring) {
ev.events = e | ioevent->extra_events; struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
ev.data.ptr = data; if (sqe == NULL) {
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev); return ENOSPC;
}
io_uring_prep_poll_multishot(sqe, fd, e | ioevent->extra_events);
sqe->user_data = (long)data;
ioevent->submit_count++;
return 0;
} else {
#endif
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
#if IOEVENT_USE_URING
}
#endif
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
struct kevent ev[2]; struct kevent ev[2];
int n = 0; int n = 0;
@ -128,15 +176,32 @@ int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
#endif #endif
} }
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e, int ioevent_modify(IOEventPoller *ioevent, const int fd,
void *data) const int e, void *data)
{ {
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
struct epoll_event ev; #if IOEVENT_USE_URING
memset(&ev, 0, sizeof(ev)); if (ioevent->use_io_uring) {
ev.events = e | ioevent->extra_events; struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
ev.data.ptr = data; if (sqe == NULL) {
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev); return ENOSPC;
}
io_uring_prep_poll_update(sqe, sqe->user_data, sqe->user_data,
e | ioevent->extra_events, IORING_POLL_UPDATE_EVENTS);
sqe->user_data = (long)data;
ioevent->submit_count++;
return 0;
} else {
#endif
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
#if IOEVENT_USE_URING
}
#endif
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
struct kevent ev[2]; struct kevent ev[2];
int result; int result;
@ -171,8 +236,25 @@ int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
int ioevent_detach(IOEventPoller *ioevent, const int fd) int ioevent_detach(IOEventPoller *ioevent, const int fd)
{ {
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL); #if IOEVENT_USE_URING
if (ioevent->use_io_uring) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
if (sqe == NULL) {
return ENOSPC;
}
io_uring_prep_cancel_fd(sqe, fd, 0);
/* set sqe->flags MUST after io_uring_prep_xxx */
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
ioevent->submit_count++;
return 0;
} else {
#endif
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
#if IOEVENT_USE_URING
}
#endif
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
struct kevent ev[1]; struct kevent ev[1];
int r, w; int r, w;
@ -191,15 +273,33 @@ int ioevent_detach(IOEventPoller *ioevent, const int fd)
int ioevent_poll(IOEventPoller *ioevent) int ioevent_poll(IOEventPoller *ioevent)
{ {
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout); #if IOEVENT_USE_URING
if (ioevent->use_io_uring) {
int result;
result = io_uring_wait_cqe_timeout(&ioevent->ring,
&ioevent->cqe, &ioevent->timeout);
if (result < 0) {
errno = -result;
return -1;
}
return 0;
} else {
#endif
return epoll_wait(ioevent->poll_fd, ioevent->events,
ioevent->size, ioevent->timeout_ms);
#if IOEVENT_USE_URING
}
#endif
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout); return kevent(ioevent->poll_fd, NULL, 0, ioevent->events,
ioevent->size, &ioevent->timeout);
#elif IOEVENT_USE_PORT #elif IOEVENT_USE_PORT
int result; int result;
int retval; int retval;
unsigned int nget = 1; unsigned int nget = 1;
if((retval = port_getn(ioevent->poll_fd, ioevent->events, if((retval=port_getn(ioevent->poll_fd, ioevent->events,
ioevent->size, &nget, &ioevent->timeout)) == 0) ioevent->size, &nget, &ioevent->timeout)) == 0)
{ {
result = (int)nget; result = (int)nget;
@ -225,4 +325,3 @@ int ioevent_poll(IOEventPoller *ioevent)
#error port me #error port me
#endif #endif
} }

View File

@ -20,17 +20,28 @@
#include <poll.h> #include <poll.h>
#include <sys/time.h> #include <sys/time.h>
#include "_os_define.h" #include "_os_define.h"
#include "logger.h"
#define IOEVENT_TIMEOUT 0x8000 #define IOEVENT_TIMEOUT (1 << 20)
#define IOEVENT_NOTIFY (1 << 21) //for io_uring send_zc done callback
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
#include <sys/epoll.h> #include <sys/epoll.h>
#define IOEVENT_EDGE_TRIGGER EPOLLET #define IOEVENT_EDGE_TRIGGER EPOLLET
#endif
#if IOEVENT_USE_EPOLL
#define IOEVENT_READ EPOLLIN #define IOEVENT_READ EPOLLIN
#define IOEVENT_WRITE EPOLLOUT #define IOEVENT_WRITE EPOLLOUT
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP) #define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
#elif IOEVENT_USE_URING
#include <sys/mount.h>
#include <liburing.h>
#define IOEVENT_READ POLLIN
#define IOEVENT_WRITE POLLOUT
#define IOEVENT_ERROR (POLLERR | POLLPRI | POLLHUP)
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
#include <sys/event.h> #include <sys/event.h>
#include <sys/poll.h> #include <sys/poll.h>
@ -65,18 +76,33 @@ int kqueue_ev_convert(int16_t event, uint16_t flags);
#endif #endif
typedef struct ioevent_puller { typedef struct ioevent_puller {
const char *service_name;
int size; //max events (fd) int size; //max events (fd)
int extra_events; int extra_events;
int poll_fd;
#if IOEVENT_USE_URING
struct io_uring ring;
int submit_count;
bool send_zc_logged;
bool send_zc_done_notify; //if callback when send_zc done
bool use_io_uring;
#endif
int poll_fd;
struct { struct {
int index; int index;
int count; int count;
} iterator; //for deal event loop } iterator; //for deal event loop
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
struct epoll_event *events; struct epoll_event *events;
int timeout; int timeout_ms; //for epoll
#if IOEVENT_USE_URING
struct io_uring_cqe *cqe;
struct __kernel_timespec timeout;
#endif
bool zero_timeout;
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
struct kevent *events; struct kevent *events;
struct timespec timeout; struct timespec timeout;
@ -84,9 +110,10 @@ typedef struct ioevent_puller {
port_event_t *events; port_event_t *events;
timespec_t timeout; timespec_t timeout;
#endif #endif
} IOEventPoller; } IOEventPoller;
#if IOEVENT_USE_EPOLL #if OS_LINUX
#define IOEVENT_GET_EVENTS(ioevent, index) \ #define IOEVENT_GET_EVENTS(ioevent, index) \
(ioevent)->events[index].events (ioevent)->events[index].events
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
@ -99,7 +126,7 @@ typedef struct ioevent_puller {
#error port me #error port me
#endif #endif
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
#define IOEVENT_GET_DATA(ioevent, index) \ #define IOEVENT_GET_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr (ioevent)->events[index].data.ptr
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
@ -112,7 +139,7 @@ typedef struct ioevent_puller {
#error port me #error port me
#endif #endif
#if IOEVENT_USE_EPOLL #ifdef OS_LINUX
#define IOEVENT_CLEAR_DATA(ioevent, index) \ #define IOEVENT_CLEAR_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr = NULL (ioevent)->events[index].data.ptr = NULL
#elif IOEVENT_USE_KQUEUE #elif IOEVENT_USE_KQUEUE
@ -129,24 +156,39 @@ typedef struct ioevent_puller {
extern "C" { extern "C" {
#endif #endif
int ioevent_init(IOEventPoller *ioevent, const int size, int ioevent_init(IOEventPoller *ioevent, const char *service_name,
const int timeout_ms, const int extra_events); const bool use_io_uring, const int size, const int timeout_ms,
const int extra_events);
void ioevent_destroy(IOEventPoller *ioevent); void ioevent_destroy(IOEventPoller *ioevent);
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e, int ioevent_attach(IOEventPoller *ioevent, const int fd,
void *data); const int e, void *data);
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e, int ioevent_modify(IOEventPoller *ioevent, const int fd,
void *data); const int e, void *data);
int ioevent_detach(IOEventPoller *ioevent, const int fd); int ioevent_detach(IOEventPoller *ioevent, const int fd);
int ioevent_poll(IOEventPoller *ioevent); int ioevent_poll(IOEventPoller *ioevent);
static inline void ioevent_set_timeout(IOEventPoller *ioevent, const int timeout_ms) static inline void ioevent_set_timeout(IOEventPoller *ioevent,
const int timeout_ms)
{ {
#if IOEVENT_USE_EPOLL #if IOEVENT_USE_EPOLL
ioevent->timeout = timeout_ms; ioevent->timeout_ms = timeout_ms;
#else #else
ioevent->timeout.tv_sec = timeout_ms / 1000; #if IOEVENT_USE_URING
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000); if (!ioevent->use_io_uring) {
ioevent->timeout_ms = timeout_ms;
} else {
#endif
ioevent->timeout.tv_sec = timeout_ms / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000);
#if IOEVENT_USE_URING
}
#endif
#endif
#ifdef OS_LINUX
ioevent->zero_timeout = (timeout_ms == 0);
#endif #endif
} }
@ -156,6 +198,114 @@ static inline int ioevent_poll_ex(IOEventPoller *ioevent, const int timeout_ms)
return ioevent_poll(ioevent); return ioevent_poll(ioevent);
} }
#if IOEVENT_USE_URING
static inline void ioevent_set_send_zc_done_notify(
IOEventPoller *ioevent, const bool need_notify)
{
ioevent->send_zc_done_notify = need_notify;
}
static inline int ioevent_uring_submit(IOEventPoller *ioevent)
{
int result;
ioevent->submit_count = 0;
while (1) {
result = io_uring_submit(&ioevent->ring);
if (result < 0) {
if (result != -EINTR) {
return -result;
}
} else {
return 0;
}
}
}
static inline struct io_uring_sqe *ioevent_uring_get_sqe(IOEventPoller *ioevent)
{
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
if (sqe == NULL) {
logError("file: "__FILE__", line: %d, "
"io_uring_get_sqe fail", __LINE__);
}
return sqe;
}
static inline void ioevent_uring_prep_recv(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t size, void *user_data)
{
io_uring_prep_recv(sqe, sockfd, buf, size, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_send(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t len, void *user_data)
{
io_uring_prep_send(sqe, sockfd, buf, len, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_writev(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd, const struct iovec *iovecs,
unsigned nr_vecs, void *user_data)
{
io_uring_prep_writev(sqe, sockfd, iovecs, nr_vecs, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_send_zc(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t len, void *user_data)
{
io_uring_prep_send_zc(sqe, sockfd, buf, len, 0,
#ifdef IORING_SEND_ZC_REPORT_USAGE
IORING_SEND_ZC_REPORT_USAGE
#else
0
#endif
);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_close(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int fd, void *user_data)
{
io_uring_prep_close(sqe, fd);
if (user_data == NULL) {
/* set sqe->flags MUST after io_uring_prep_xxx */
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
} else {
sqe->user_data = (long)user_data;
}
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_cancel(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, void *user_data)
{
io_uring_prep_cancel(sqe, user_data, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_connect(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int fd, const struct sockaddr *addr,
socklen_t addrlen, void *user_data)
{
io_uring_prep_connect(sqe, fd, addr, addrlen);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -17,6 +17,76 @@
#include "logger.h" #include "logger.h"
#include "ioevent_loop.h" #include "ioevent_loop.h"
#if IOEVENT_USE_URING
static int ioevent_process_by_uring(IOEventPoller *ioevent)
{
int result;
unsigned head;
unsigned count = 0;
IOEventEntry *pEntry;
result = io_uring_wait_cqe_timeout(&ioevent->ring,
&ioevent->cqe, &ioevent->timeout);
switch (result) {
case 0:
break;
case -ETIME:
case -EINTR:
return 0;
default:
result *= -1;
logError("file: "__FILE__", line: %d, "
"io_uring_wait_cqe fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
io_uring_for_each_cqe(&ioevent->ring, head, ioevent->cqe) {
count++;
pEntry = (IOEventEntry *)ioevent->cqe->user_data;
if (pEntry != NULL) {
if (ioevent->cqe->flags & IORING_CQE_F_NOTIF) {
if (ioevent->send_zc_done_notify) {
pEntry->callback(pEntry->fd, IOEVENT_NOTIFY, pEntry);
}
#ifdef IORING_NOTIF_USAGE_ZC_COPIED
if (!ioevent->send_zc_logged) {
struct fast_task_info *task;
task = (struct fast_task_info *)pEntry;
ioevent->send_zc_logged = true;
if (ioevent->cqe->res & IORING_NOTIF_USAGE_ZC_COPIED) {
logWarning("file: "__FILE__", line: %d, %s "
"client %s:%u, io_uring send_zc: memory "
"copy instead of zero copy!", __LINE__,
ioevent->service_name, task->client_ip,
task->port);
} else {
logInfo("file: "__FILE__", line: %d, %s "
"client %s:%u, io_uring send_zc: zero "
"copy OK.", __LINE__, ioevent->service_name,
task->client_ip, task->port);
}
}
#endif
} else {
pEntry->res = ioevent->cqe->res;
pEntry->callback(pEntry->fd, 0, pEntry);
}
} else {
logWarning("file: "__FILE__", line: %d, "
"io_uring unexpected flags: %d, result: %d", __LINE__,
ioevent->cqe->flags, ioevent->cqe->res);
}
}
io_uring_cq_advance(&ioevent->ring, count);
return 0;
}
#endif
static void deal_ioevents(IOEventPoller *ioevent) static void deal_ioevents(IOEventPoller *ioevent)
{ {
int event; int event;
@ -39,35 +109,25 @@ static void deal_ioevents(IOEventPoller *ioevent)
} }
} }
int ioevent_remove(IOEventPoller *ioevent, void *data) static int ioevent_process_by_poll(IOEventPoller *ioevent)
{ {
IOEventEntry *pEntry; int result;
int index;
if (ioevent->iterator.index >= ioevent->iterator.count) ioevent->iterator.count = ioevent_poll(ioevent);
{ if (ioevent->iterator.count > 0) {
return ENOENT; deal_ioevents(ioevent);
} }
else if (ioevent->iterator.count < 0) {
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, result = errno != 0 ? errno : EINVAL;
ioevent->iterator.index); if (result != EINTR) {
if (pEntry != NULL && (void *)pEntry == data) { logError("file: "__FILE__", line: %d, "
return 0; //do NOT clear current entry "ioevent_poll fail, errno: %d, error info: %s",
} __LINE__, result, STRERROR(result));
return result;
for (index=ioevent->iterator.index + 1; index < ioevent->iterator.count;
index++)
{
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, index);
if (pEntry != NULL && (void *)pEntry == data) {
logDebug("file: "__FILE__", line: %d, "
"clear ioevent data: %p", __LINE__, data);
IOEVENT_CLEAR_DATA(ioevent, index);
return 0;
} }
} }
return ENOENT; return 0;
} }
static void deal_timeouts(FastTimerEntry *head) static void deal_timeouts(FastTimerEntry *head)
@ -82,16 +142,14 @@ static void deal_timeouts(FastTimerEntry *head)
current = entry; current = entry;
entry = entry->next; entry = entry->next;
current->prev = current->next = NULL; //must set NULL because NOT in time wheel /* must set NULL because NOT in time wheel */
current->prev = current->next = NULL;
pEventEntry = (IOEventEntry *)current; pEventEntry = (IOEventEntry *)current;
if (pEventEntry != NULL) pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT, current);
{
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT, current);
}
} }
} }
int ioevent_loop(struct nio_thread_data *pThreadData, int ioevent_loop(struct nio_thread_data *thread_data,
IOEventCallback recv_notify_callback, TaskCleanUpCallback IOEventCallback recv_notify_callback, TaskCleanUpCallback
clean_up_callback, volatile bool *continue_flag) clean_up_callback, volatile bool *continue_flag)
{ {
@ -100,90 +158,133 @@ int ioevent_loop(struct nio_thread_data *pThreadData,
FastTimerEntry head; FastTimerEntry head;
struct fast_task_info *task; struct fast_task_info *task;
time_t last_check_time; time_t last_check_time;
int save_extra_events;
int count; int count;
#ifdef OS_LINUX
uint32_t sched_counter;
#endif
bool sched_pull;
memset(&ev_notify, 0, sizeof(ev_notify)); memset(&ev_notify, 0, sizeof(ev_notify));
ev_notify.event.fd = FC_NOTIFY_READ_FD(pThreadData); ev_notify.event.fd = FC_NOTIFY_READ_FD(thread_data);
ev_notify.event.callback = recv_notify_callback; ev_notify.event.callback = recv_notify_callback;
ev_notify.thread_data = pThreadData; ev_notify.thread_data = thread_data;
if (ioevent_attach(&pThreadData->ev_puller,
pThreadData->pipe_fds[0], IOEVENT_READ, save_extra_events = thread_data->ev_puller.extra_events;
&ev_notify) != 0) thread_data->ev_puller.extra_events = 0; //disable edge trigger temporarily
if (ioevent_attach(&thread_data->ev_puller, ev_notify.
event.fd, IOEVENT_READ, &ev_notify) != 0)
{ {
result = errno != 0 ? errno : ENOMEM; result = errno != 0 ? errno : ENOMEM;
logCrit("file: "__FILE__", line: %d, " \ logCrit("file: "__FILE__", line: %d, "
"ioevent_attach fail, " \ "ioevent_attach fail, errno: %d, error info: %s",
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result)); __LINE__, result, STRERROR(result));
return result; return result;
} }
thread_data->ev_puller.extra_events = save_extra_events; //restore
pThreadData->deleted_list = NULL; #ifdef OS_LINUX
sched_counter = 0;
#endif
thread_data->deleted_list = NULL;
last_check_time = g_current_time; last_check_time = g_current_time;
while (*continue_flag) while (*continue_flag) {
{ #ifdef OS_LINUX
pThreadData->ev_puller.iterator.count = ioevent_poll( if (thread_data->ev_puller.zero_timeout) {
&pThreadData->ev_puller); sched_pull = (sched_counter++ & 8) != 0;
if (pThreadData->ev_puller.iterator.count > 0) } else {
{ sched_pull = true;
deal_ioevents(&pThreadData->ev_puller); }
} #else
else if (pThreadData->ev_puller.iterator.count < 0) sched_pull = true;
{ #endif
result = errno != 0 ? errno : EINVAL;
if (result != EINTR)
{
logError("file: "__FILE__", line: %d, " \
"ioevent_poll fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
}
if (pThreadData->deleted_list != NULL) #if IOEVENT_USE_URING
{ if (thread_data->ev_puller.use_io_uring) {
count = 0; if (thread_data->ev_puller.submit_count > 0) {
while (pThreadData->deleted_list != NULL) if ((result=ioevent_uring_submit(&thread_data->
{ ev_puller)) != 0)
task = pThreadData->deleted_list; {
pThreadData->deleted_list = task->next; logError("file: "__FILE__", line: %d, "
"io_uring_submit fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
}
}
#endif
if (sched_pull) {
#if IOEVENT_USE_URING
if (thread_data->ev_puller.use_io_uring) {
if ((result=ioevent_process_by_uring(&thread_data->
ev_puller)) != 0)
{
return result;
}
} else {
#endif
if ((result=ioevent_process_by_poll(&thread_data->
ev_puller)) != 0)
{
return result;
}
#if IOEVENT_USE_URING
}
#endif
}
if (thread_data->busy_polling_callback != NULL) {
thread_data->busy_polling_callback(thread_data);
}
if (thread_data->deleted_list != NULL) {
//count = 0;
while (thread_data->deleted_list != NULL) {
task = thread_data->deleted_list;
thread_data->deleted_list = task->next;
if (task->polling.in_queue) {
fc_list_del_init(&task->polling.dlink);
task->polling.in_queue = false;
if (fc_list_empty(&task->thread_data->polling_queue)) {
ioevent_set_timeout(&task->thread_data->ev_puller,
task->thread_data->timeout_ms);
}
}
clean_up_callback(task); clean_up_callback(task);
count++; //count++;
} }
//logInfo("cleanup task count: %d", count); //logInfo("cleanup task count: %d", count);
} }
if (g_current_time - last_check_time > 0) if (g_current_time - last_check_time > 0) {
{
last_check_time = g_current_time; last_check_time = g_current_time;
count = fast_timer_timeouts_get( count = fast_timer_timeouts_get(
&pThreadData->timer, g_current_time, &head); &thread_data->timer, g_current_time, &head);
if (count > 0) if (count > 0)
{ {
deal_timeouts(&head); deal_timeouts(&head);
} }
} }
if (pThreadData->notify.enabled) if (thread_data->notify.enabled) {
{
int64_t n; int64_t n;
if ((n=__sync_fetch_and_add(&pThreadData->notify.counter, 0)) != 0) if ((n=__sync_fetch_and_add(&thread_data->notify.counter, 0)) != 0)
{ {
__sync_fetch_and_sub(&pThreadData->notify.counter, n); __sync_fetch_and_sub(&thread_data->notify.counter, n);
/* /*
logInfo("file: "__FILE__", line: %d, " logInfo("file: "__FILE__", line: %d, "
"n ==== %"PRId64", now: %"PRId64, "n ==== %"PRId64", now: %"PRId64,
__LINE__, n, __sync_fetch_and_add( __LINE__, n, __sync_fetch_and_add(
&pThreadData->notify.counter, 0)); &thread_data->notify.counter, 0));
*/ */
} }
} }
if (pThreadData->thread_loop_callback != NULL) if (thread_data->thread_loop_callback != NULL) {
{ thread_data->thread_loop_callback(thread_data);
pThreadData->thread_loop_callback(pThreadData);
} }
} }
@ -191,25 +292,64 @@ int ioevent_loop(struct nio_thread_data *pThreadData,
} }
int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread, int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback, const int timeout) int sock, short event, IOEventCallback callback,
const int timeout)
{ {
int result; int result;
task->thread_data = pThread; task->thread_data = pThread;
task->event.fd = sock; task->event.fd = sock;
task->event.callback = callback; task->event.callback = callback;
if (ioevent_attach(&pThread->ev_puller, #if IOEVENT_USE_URING
sock, event, task) < 0) if (pThread->ev_puller.use_io_uring) {
{ if (FC_URING_OP_TYPE(task) == IORING_OP_NOP) {
result = errno != 0 ? errno : ENOENT; if ((result=uring_prep_first_recv(task)) != 0) {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"ioevent_attach fail, " \ "uring_prep_recv fail, fd: %d, "
"errno: %d, error info: %s", \ "errno: %d, error info: %s",
__LINE__, result, STRERROR(result)); __LINE__, sock, result, STRERROR(result));
return result; return result;
} }
} else {
/*
logWarning("file: "__FILE__", line: %d, "
"skip uring_prep_recv, fd: %d, port: %d, "
"in progress op type: %d, timeout: %"PRId64,
__LINE__, sock, task->port, FC_URING_OP_TYPE(task),
task->event.timer.expires);
*/
}
} else {
#endif
if (ioevent_attach(&pThread->ev_puller, sock, event, task) < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"ioevent_attach fail, fd: %d, "
"errno: %d, error info: %s",
__LINE__, sock, result, STRERROR(result));
return result;
}
#if IOEVENT_USE_URING
}
#endif
task->event.timer.expires = g_current_time + timeout; task->event.timer.expires = g_current_time + timeout;
fast_timer_add(&pThread->timer, &task->event.timer); fast_timer_add(&pThread->timer, &task->event.timer);
return 0; return 0;
} }
int ioevent_reset(struct fast_task_info *task, int new_fd, short event)
{
if (task->event.fd == new_fd)
{
return 0;
}
if (task->event.fd >= 0)
{
ioevent_detach(&task->thread_data->ev_puller, task->event.fd);
}
task->event.fd = new_fd;
return ioevent_attach(&task->thread_data->ev_puller, new_fd, event, task);
}

View File

@ -17,20 +17,28 @@
#define _IOEVENT_LOOP_H #define _IOEVENT_LOOP_H
#include "fast_task_queue.h" #include "fast_task_queue.h"
#if IOEVENT_USE_URING
#include "sockopt.h"
#endif
#define fc_hold_task_ex(task, inc_count) __sync_add_and_fetch( \
&task->reffer_count, inc_count)
#define fc_hold_task(task) fc_hold_task_ex(task, 1)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int ioevent_loop(struct nio_thread_data *pThreadData, int ioevent_loop(struct nio_thread_data *thread_data,
IOEventCallback recv_notify_callback, TaskCleanUpCallback IOEventCallback recv_notify_callback, TaskCleanUpCallback
clean_up_callback, volatile bool *continue_flag); clean_up_callback, volatile bool *continue_flag);
//remove entry from ready list int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
int ioevent_remove(IOEventPoller *ioevent, void *data); int sock, short event, IOEventCallback callback,
const int timeout);
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread, int ioevent_reset(struct fast_task_info *task, int new_fd, short event);
int sock, short event, IOEventCallback callback, const int timeout);
static inline bool ioevent_is_canceled(struct fast_task_info *task) static inline bool ioevent_is_canceled(struct fast_task_info *task)
{ {
@ -73,9 +81,170 @@ static inline int ioevent_notify_thread(struct nio_thread_data *thread_data)
return 0; return 0;
} }
#if IOEVENT_USE_URING
#define SET_OP_TYPE_AND_HOLD_TASK(task, _op_type) \
struct io_uring_sqe *sqe; \
if ((sqe=ioevent_uring_get_sqe(&task->thread_data->ev_puller)) == NULL) { \
return ENOSPC; \
} \
FC_URING_OP_TYPE(task) = _op_type; \
fc_hold_task(task)
static inline int uring_prep_recv_data(struct fast_task_info *task,
char *buff, const int len)
{
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
ioevent_uring_prep_recv(&task->thread_data->ev_puller,
sqe, task->event.fd, buff, len, task);
return 0;
}
static inline int uring_prep_first_recv(struct fast_task_info *task)
{
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
ioevent_uring_prep_recv(&task->thread_data->ev_puller,
sqe, task->event.fd, task->recv.ptr->data,
task->recv.ptr->size, task);
return 0;
}
static inline int uring_prep_next_recv(struct fast_task_info *task)
{
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
ioevent_uring_prep_recv(&task->thread_data->ev_puller, sqe,
task->event.fd, task->recv.ptr->data + task->recv.ptr->offset,
task->recv.ptr->length - task->recv.ptr->offset, task);
return 0;
}
static inline int uring_prep_first_send(struct fast_task_info *task)
{
if (task->iovec_array.iovs != NULL) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
sqe, task->event.fd, task->iovec_array.iovs,
FC_MIN(task->iovec_array.count, IOV_MAX),
task);
} else {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
ioevent_uring_prep_send(&task->thread_data->ev_puller,
sqe, task->event.fd, task->send.ptr->data,
task->send.ptr->length, task);
}
return 0;
}
static inline int uring_prep_next_send(struct fast_task_info *task)
{
if (task->iovec_array.iovs != NULL) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
sqe, task->event.fd, task->iovec_array.iovs,
FC_MIN(task->iovec_array.count, IOV_MAX),
task);
} else {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
ioevent_uring_prep_send(&task->thread_data->ev_puller, sqe,
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
task->send.ptr->length - task->send.ptr->offset, task);
}
return 0;
}
static inline int uring_prep_first_send_zc(struct fast_task_info *task)
{
if (task->iovec_array.iovs != NULL) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
sqe, task->event.fd, task->iovec_array.iovs,
FC_MIN(task->iovec_array.count, IOV_MAX),
task);
} else if (task->send.ptr->length < 4096) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
ioevent_uring_prep_send(&task->thread_data->ev_puller,
sqe, task->event.fd, task->send.ptr->data,
task->send.ptr->length, task);
} else {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND_ZC);
ioevent_uring_prep_send_zc(&task->thread_data->ev_puller,
sqe, task->event.fd, task->send.ptr->data,
task->send.ptr->length, task);
}
return 0;
}
static inline int uring_prep_next_send_zc(struct fast_task_info *task)
{
if (task->iovec_array.iovs != NULL) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
sqe, task->event.fd, task->iovec_array.iovs,
FC_MIN(task->iovec_array.count, IOV_MAX),
task);
} else if (task->send.ptr->length - task->send.ptr->offset < 4096) {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
ioevent_uring_prep_send(&task->thread_data->ev_puller, sqe,
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
task->send.ptr->length - task->send.ptr->offset, task);
} else {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND_ZC);
ioevent_uring_prep_send_zc(&task->thread_data->ev_puller, sqe,
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
task->send.ptr->length - task->send.ptr->offset, task);
}
return 0;
}
static inline int uring_prep_close_fd(struct fast_task_info *task)
{
struct io_uring_sqe *sqe;
if ((sqe=ioevent_uring_get_sqe(&task->thread_data->ev_puller)) == NULL) {
return ENOSPC;
}
/* do NOT need callback */
ioevent_uring_prep_close(&task->thread_data->
ev_puller, sqe, task->event.fd, NULL);
return 0;
}
static inline int uring_prep_cancel(struct fast_task_info *task)
{
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_ASYNC_CANCEL);
ioevent_uring_prep_cancel(&task->thread_data->ev_puller, sqe, task);
return 0;
}
static inline int uring_prep_connect(struct fast_task_info *task)
{
int result;
sockaddr_convert_t *convert;
if ((task->event.fd=socketCreateEx2(AF_UNSPEC, task->server_ip,
O_NONBLOCK, NULL, &result)) < 0)
{
return result;
}
convert = (sockaddr_convert_t *)(task->send.ptr->data +
task->send.ptr->size - 2 * sizeof(sockaddr_convert_t));
if ((result=setsockaddrbyip(task->server_ip, task->port, convert)) != 0) {
return result;
}
do {
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_CONNECT);
ioevent_uring_prep_connect(&task->thread_data->ev_puller, sqe,
task->event.fd, &convert->sa.addr, convert->len, task);
} while (0);
return 0;
}
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

View File

@ -31,7 +31,7 @@ bool is_local_host_ip(const char *client_ip)
char *p; char *p;
char *pEnd; char *pEnd;
pEnd = g_local_host_ip_addrs + \ pEnd = g_local_host_ip_addrs +
IP_ADDRESS_SIZE * g_local_host_ip_count; IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE) for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{ {
@ -56,9 +56,8 @@ int insert_into_local_host_ip(const char *client_ip)
return -1; return -1;
} }
strcpy(g_local_host_ip_addrs + \ strcpy(g_local_host_ip_addrs + IP_ADDRESS_SIZE *
IP_ADDRESS_SIZE * g_local_host_ip_count, \ g_local_host_ip_count, client_ip);
client_ip);
g_local_host_ip_count++; g_local_host_ip_count++;
return 1; return 1;
} }
@ -83,7 +82,7 @@ const char *local_host_ip_addrs_to_string(char *buff, const int size)
void log_local_host_ip_addrs() void log_local_host_ip_addrs()
{ {
char buff[512]; char buff[1024];
logInfo("%s", local_host_ip_addrs_to_string(buff, sizeof(buff))); logInfo("%s", local_host_ip_addrs_to_string(buff, sizeof(buff)));
} }
@ -96,7 +95,7 @@ void load_local_host_ip_addrs()
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT]; char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
int alias_count; int alias_count;
insert_into_local_host_ip(LOCAL_LOOPBACK_IP); insert_into_local_host_ip(LOCAL_LOOPBACK_IPv4);
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes)); memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
if (*g_if_alias_prefix == '\0') if (*g_if_alias_prefix == '\0')
@ -160,8 +159,8 @@ const char *get_next_local_ip(const char *previous_ip)
pEnd = g_local_host_ip_addrs + \ pEnd = g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count; IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE) for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{ {
if (strcmp(p, LOCAL_LOOPBACK_IP) != 0) if (!is_loopback_ip(p))
{ {
if (found) if (found)
{ {
@ -172,7 +171,7 @@ const char *get_next_local_ip(const char *previous_ip)
found = true; found = true;
} }
} }
} }
return NULL; return NULL;
} }
@ -187,7 +186,10 @@ const char *get_first_local_ip()
} }
else else
{ {
return LOCAL_LOOPBACK_IP; /* 注意当系统存在IPv6回环地址时为了简化系统的改动
IPv6IPv4
*/
return LOCAL_LOOPBACK_IPv4;
} }
} }
@ -212,3 +214,17 @@ const char *get_first_local_private_ip()
return NULL; return NULL;
} }
void stat_local_host_ip(int *ipv4_count, int *ipv6_count)
{
const char *ip_addr;
*ipv4_count = *ipv6_count = 0;
ip_addr = NULL;
while ((ip_addr=get_next_local_ip(ip_addr)) != NULL) {
if (is_ipv6_addr(ip_addr)) {
++(*ipv6_count);
} else {
++(*ipv4_count);
}
}
}

View File

@ -25,22 +25,32 @@
#include "common_define.h" #include "common_define.h"
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32 #define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
#define FAST_MAX_LOCAL_IP_ADDRS 16 #define FAST_MAX_LOCAL_IP_ADDRS 32
#define LOCAL_LOOPBACK_IP "127.0.0.1" #define LOCAL_LOOPBACK_IPv4 "127.0.0.1"
#define LOCAL_LOOPBACK_IPv6 "::1"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern int g_local_host_ip_count; extern int g_local_host_ip_count;
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \ extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS *
IP_ADDRESS_SIZE]; IP_ADDRESS_SIZE];
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE]; extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
void load_local_host_ip_addrs(); void load_local_host_ip_addrs();
bool is_local_host_ip(const char *client_ip); bool is_local_host_ip(const char *client_ip);
static inline bool is_loopback_ip(const char *ip_addr)
{
return (strcmp(ip_addr, LOCAL_LOOPBACK_IPv4) == 0 ||
strcmp(ip_addr, LOCAL_LOOPBACK_IPv6) == 0 ||
strcasecmp(ip_addr, "fe80::1") == 0);
}
void stat_local_host_ip(int *ipv4_count, int *ipv6_count);
const char *get_first_local_ip(); const char *get_first_local_ip();
const char *get_next_local_ip(const char *previous_ip); const char *get_next_local_ip(const char *previous_ip);

View File

@ -13,6 +13,9 @@ typedef struct fc_locked_list {
extern "C" { extern "C" {
#endif #endif
#define LOCKED_LIST_LOCK(list) PTHREAD_MUTEX_LOCK(&(list)->lock)
#define LOCKED_LIST_UNLOCK(list) PTHREAD_MUTEX_UNLOCK(&(list)->lock)
static inline int locked_list_init(FCLockedList *list) static inline int locked_list_init(FCLockedList *list)
{ {
int result; int result;
@ -45,6 +48,22 @@ extern "C" {
PTHREAD_MUTEX_UNLOCK(&list->lock); PTHREAD_MUTEX_UNLOCK(&list->lock);
} }
static inline void locked_list_move(struct fc_list_head *obj,
FCLockedList *list)
{
PTHREAD_MUTEX_LOCK(&list->lock);
fc_list_move(obj, &list->head);
PTHREAD_MUTEX_UNLOCK(&list->lock);
}
static inline void locked_list_move_tail(struct fc_list_head *obj,
FCLockedList *list)
{
PTHREAD_MUTEX_LOCK(&list->lock);
fc_list_move_tail(obj, &list->head);
PTHREAD_MUTEX_UNLOCK(&list->lock);
}
static inline void locked_list_del(struct fc_list_head *old, static inline void locked_list_del(struct fc_list_head *old,
FCLockedList *list) FCLockedList *list)
{ {

View File

@ -50,21 +50,21 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock);
static int check_and_mk_log_dir(const char *base_path) static int check_and_mk_log_dir(const char *base_path)
{ {
char data_path[MAX_PATH_SIZE]; char log_path[MAX_PATH_SIZE];
snprintf(data_path, sizeof(data_path), "%s/logs", base_path); fc_combine_full_filename(base_path, "logs", log_path);
if (!fileExists(data_path)) if (!fileExists(log_path))
{ {
if (mkdir(data_path, 0755) != 0) if (mkdir(log_path, 0755) != 0)
{ {
fprintf(stderr, "mkdir \"%s\" fail, " \ fprintf(stderr, "mkdir \"%s\" fail, "
"errno: %d, error info: %s\n", \ "errno: %d, error info: %s\n",
data_path, errno, STRERROR(errno)); log_path, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM; return errno != 0 ? errno : EPERM;
} }
} }
return 0; return 0;
} }
int log_init() int log_init()
@ -112,7 +112,7 @@ int log_init_ex(LogContext *pContext)
} }
pContext->pcurrent_buff = pContext->log_buff; pContext->pcurrent_buff = pContext->log_buff;
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0) if ((result=init_pthread_lock(&(pContext->lock))) != 0)
{ {
return result; return result;
} }
@ -136,8 +136,8 @@ static int log_print_header(LogContext *pContext)
if (pContext->current_size < 0) if (pContext->current_size < 0)
{ {
result = errno != 0 ? errno : EACCES; result = errno != 0 ? errno : EACCES;
fprintf(stderr, "lseek file \"%s\" fail, " \ fprintf(stderr, "lseek file \"%s\" fail, "
"errno: %d, error info: %s\n", \ "errno: %d, error info: %s\n",
pContext->log_filename, result, STRERROR(result)); pContext->log_filename, result, STRERROR(result));
} }
else { else {
@ -225,28 +225,41 @@ int log_reopen_ex(LogContext *pContext)
int log_set_prefix_ex(LogContext *pContext, const char *base_path, int log_set_prefix_ex(LogContext *pContext, const char *base_path,
const char *filename_prefix) const char *filename_prefix)
{ {
int result; int result;
char log_filename[MAX_PATH_SIZE];
if ((result=check_and_mk_log_dir(base_path)) != 0) if ((result=check_and_mk_log_dir(base_path)) != 0)
{ {
return result; return result;
} }
snprintf(pContext->log_filename, MAX_PATH_SIZE, snprintf(log_filename, MAX_PATH_SIZE, "%s/logs/%s.log",
"%s/logs/%s.log", base_path, filename_prefix); base_path, filename_prefix);
return log_set_filename_ex(pContext, log_filename);
return log_open(pContext);
} }
int log_set_filename_ex(LogContext *pContext, const char *log_filename) int log_set_filename_ex(LogContext *pContext, const char *log_filename)
{ {
if (log_filename == NULL) { if (log_filename == NULL || *log_filename == '\0')
fprintf(stderr, "file: "__FILE__", line: %d, " \ {
"log_filename is NULL!\n", __LINE__); fprintf(stderr, "file: "__FILE__", line: %d, "
"log_filename is NULL or empty!\n", __LINE__);
return EINVAL; return EINVAL;
} }
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
return log_open(pContext); if (*(pContext->log_filename) == '\0')
{
fc_strlcpy(pContext->log_filename, log_filename, MAX_PATH_SIZE);
return log_open(pContext);
}
if (strcmp(log_filename, pContext->log_filename) == 0)
{
return 0;
}
fc_strlcpy(pContext->log_filename, log_filename, MAX_PATH_SIZE);
return log_reopen_ex(pContext);
} }
void log_set_cache_ex(LogContext *pContext, const bool bLogCache) void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
@ -283,9 +296,9 @@ void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_call
{ {
int64_t current_size; int64_t current_size;
pthread_mutex_lock(&(pContext->log_thread_lock)); pthread_mutex_lock(&(pContext->lock));
current_size = pContext->current_size; current_size = pContext->current_size;
pthread_mutex_unlock(&(pContext->log_thread_lock)); pthread_mutex_unlock(&(pContext->lock));
if (current_size == 0) if (current_size == 0)
{ {
log_print_header(pContext); log_print_header(pContext);
@ -334,7 +347,7 @@ void log_destroy_ex(LogContext *pContext)
close(pContext->log_fd); close(pContext->log_fd);
pContext->log_fd = STDERR_FILENO; pContext->log_fd = STDERR_FILENO;
pthread_mutex_destroy(&pContext->log_thread_lock); pthread_mutex_destroy(&pContext->lock);
} }
if (pContext->log_buff != NULL) if (pContext->log_buff != NULL)
@ -372,12 +385,11 @@ static int log_delete_old_file(LogContext *pContext,
char full_filename[MAX_PATH_SIZE + 128]; char full_filename[MAX_PATH_SIZE + 128];
if (NEED_COMPRESS_LOG(pContext->compress_log_flags)) if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
{ {
snprintf(full_filename, sizeof(full_filename), "%s%s", fc_concat_two_strings(old_filename, GZIP_EXT_NAME_STR, full_filename);
old_filename, GZIP_EXT_NAME_STR);
} }
else else
{ {
snprintf(full_filename, sizeof(full_filename), "%s", old_filename); fc_safe_strcpy(full_filename, old_filename);
} }
if (unlink(full_filename) != 0) if (unlink(full_filename) != 0)
@ -577,7 +589,9 @@ static int log_get_matched_files(LogContext *pContext,
the_time = get_current_time() - days_before * 86400; the_time = get_current_time() - days_before * 86400;
localtime_r(&the_time, &tm); localtime_r(&the_time, &tm);
memset(filename_prefix, 0, sizeof(filename_prefix)); memset(filename_prefix, 0, sizeof(filename_prefix));
len = sprintf(filename_prefix, "%s.", log_filename); len = strlen(log_filename);
memcpy(filename_prefix, log_filename, len);
*(filename_prefix + len++) = '.';
strftime(filename_prefix + len, sizeof(filename_prefix) - len, strftime(filename_prefix + len, sizeof(filename_prefix) - len,
rotate_time_format_prefix, &tm); rotate_time_format_prefix, &tm);
prefix_filename_len = strlen(filename_prefix); prefix_filename_len = strlen(filename_prefix);
@ -638,8 +652,8 @@ static int log_delete_matched_old_files(LogContext *pContext,
log_get_file_path(pContext, log_filepath); log_get_file_path(pContext, log_filepath);
for (i=0; i<filename_array.count; i++) for (i=0; i<filename_array.count; i++)
{ {
snprintf(full_filename, sizeof(full_filename), "%s%s", fc_concat_two_strings(log_filepath, filename_array.
log_filepath, filename_array.filenames[i]); filenames[i], full_filename);
if (unlink(full_filename) != 0) if (unlink(full_filename) != 0)
{ {
if (errno != ENOENT) if (errno != ENOENT)
@ -690,7 +704,9 @@ int log_delete_old_files(void *args)
the_time -= 86400; the_time -= 86400;
localtime_r(&the_time, &tm); localtime_r(&the_time, &tm);
memset(old_filename, 0, sizeof(old_filename)); memset(old_filename, 0, sizeof(old_filename));
len = sprintf(old_filename, "%s.", pContext->log_filename); len = strlen(pContext->log_filename);
memcpy(old_filename, pContext->log_filename, len);
*(old_filename + len++) = '.';
strftime(old_filename + len, sizeof(old_filename) - len, strftime(old_filename + len, sizeof(old_filename) - len,
pContext->rotate_time_format, &tm); pContext->rotate_time_format, &tm);
if ((result=log_delete_old_file(pContext, old_filename)) != 0) if ((result=log_delete_old_file(pContext, old_filename)) != 0)
@ -720,6 +736,7 @@ static void *log_gzip_func(void *args)
char log_filepath[MAX_PATH_SIZE]; char log_filepath[MAX_PATH_SIZE];
char full_filename[MAX_PATH_SIZE + 32]; char full_filename[MAX_PATH_SIZE + 32];
char output[512]; char output[512];
const char *gzip_cmd_filename;
int prefix_len; int prefix_len;
int result; int result;
int i; int i;
@ -747,11 +764,10 @@ static void *log_gzip_func(void *args)
continue; continue;
} }
snprintf(full_filename, sizeof(full_filename), "%s%s", gzip_cmd_filename = get_gzip_command_filename();
log_filepath, filename_array.filenames[i]); fc_concat_two_strings(log_filepath, filename_array.
snprintf(cmd, sizeof(cmd), "%s %s", filenames[i], full_filename);
get_gzip_command_filename(), full_filename); fc_combine_two_strings(gzip_cmd_filename, full_filename, ' ', cmd);
result = getExecResult(cmd, output, sizeof(output)); result = getExecResult(cmd, output, sizeof(output));
if (result != 0) if (result != 0)
{ {
@ -830,7 +846,9 @@ int log_rotate(LogContext *pContext)
localtime_r(&current_time, &tm); localtime_r(&current_time, &tm);
memset(old_filename, 0, sizeof(old_filename)); memset(old_filename, 0, sizeof(old_filename));
len = sprintf(old_filename, "%s.", pContext->log_filename); len = strlen(pContext->log_filename);
memcpy(old_filename, pContext->log_filename, len);
*(old_filename + len++) = '.';
strftime(old_filename + len, sizeof(old_filename) - len, strftime(old_filename + len, sizeof(old_filename) - len,
pContext->rotate_time_format, &tm); pContext->rotate_time_format, &tm);
if (access(old_filename, F_OK) == 0) if (access(old_filename, F_OK) == 0)
@ -900,19 +918,19 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
{ {
if (bNeedLock) if (bNeedLock)
{ {
pthread_mutex_lock(&(pContext->log_thread_lock)); pthread_mutex_lock(&(pContext->lock));
} }
result = log_check_rotate(pContext); result = log_check_rotate(pContext);
if (bNeedLock) if (bNeedLock)
{ {
pthread_mutex_unlock(&(pContext->log_thread_lock)); pthread_mutex_unlock(&(pContext->lock));
} }
return result; return result;
} }
} }
if (bNeedLock && ((lock_res=pthread_mutex_lock( \ if (bNeedLock && ((lock_res=pthread_mutex_lock( \
&(pContext->log_thread_lock))) != 0)) &(pContext->lock))) != 0))
{ {
fprintf(stderr, "file: "__FILE__", line: %d, " \ fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \ "call pthread_mutex_lock fail, " \
@ -948,7 +966,7 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
} }
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \ if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
&(pContext->log_thread_lock))) != 0)) &(pContext->lock))) != 0))
{ {
fprintf(stderr, "file: "__FILE__", line: %d, " \ fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \ "call pthread_mutex_unlock fail, " \
@ -959,8 +977,8 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
return result; return result;
} }
static void doLogEx(LogContext *pContext, struct timeval *tv, \ void log_it_ex3(LogContext *pContext, struct timeval *tv,
const char *caption, const char *text, const int text_len, \ const char *caption, const char *text, const int text_len,
const bool bNeedSync, const bool bNeedLock) const bool bNeedSync, const bool bNeedLock)
{ {
struct tm tm; struct tm tm;
@ -985,7 +1003,7 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
} }
} }
if (bNeedLock && (result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0) if (bNeedLock && (result=pthread_mutex_lock(&pContext->lock)) != 0)
{ {
fprintf(stderr, "file: "__FILE__", line: %d, " \ fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \ "call pthread_mutex_lock fail, " \
@ -1000,12 +1018,12 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
__LINE__, LOG_BUFF_SIZE, text_len + 64); __LINE__, LOG_BUFF_SIZE, text_len + 64);
if (bNeedLock) if (bNeedLock)
{ {
pthread_mutex_unlock(&(pContext->log_thread_lock)); pthread_mutex_unlock(&(pContext->lock));
} }
return; return;
} }
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \ if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64
> LOG_BUFF_SIZE) > LOG_BUFF_SIZE)
{ {
log_fsync(pContext, false); log_fsync(pContext, false);
@ -1032,10 +1050,14 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
} }
if (caption != NULL) if (caption != NULL)
{ {
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption); buff_len = strlen(caption);
pContext->pcurrent_buff += buff_len; memcpy(pContext->pcurrent_buff, caption, buff_len);
} pContext->pcurrent_buff += buff_len;
*pContext->pcurrent_buff++ = ' ';
*pContext->pcurrent_buff++ = '-';
*pContext->pcurrent_buff++ = ' ';
}
memcpy(pContext->pcurrent_buff, text, text_len); memcpy(pContext->pcurrent_buff, text, text_len);
pContext->pcurrent_buff += text_len; pContext->pcurrent_buff += text_len;
*pContext->pcurrent_buff++ = '\n'; *pContext->pcurrent_buff++ = '\n';
@ -1045,7 +1067,7 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
log_fsync(pContext, false); log_fsync(pContext, false);
} }
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0) if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->lock))) != 0)
{ {
fprintf(stderr, "file: "__FILE__", line: %d, " \ fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \ "call pthread_mutex_unlock fail, " \
@ -1054,8 +1076,8 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
} }
} }
void log_it_ex2(LogContext *pContext, const char *caption, \ void log_it_ex2(LogContext *pContext, const char *caption,
const char *text, const int text_len, \ const char *text, const int text_len,
const bool bNeedSync, const bool bNeedLock) const bool bNeedSync, const bool bNeedLock)
{ {
struct timeval tv; struct timeval tv;
@ -1070,10 +1092,10 @@ void log_it_ex2(LogContext *pContext, const char *caption, \
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
} }
doLogEx(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock); log_it_ex3(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock);
} }
void log_it_ex1(LogContext *pContext, const int priority, \ void log_it_ex1(LogContext *pContext, const int priority,
const char *text, const int text_len) const char *text, const int text_len)
{ {
bool bNeedSync; bool bNeedSync;
@ -1269,45 +1291,12 @@ void logAccess(LogContext *pContext, struct timeval *tvStart, \
{ {
len = sizeof(text) - 1; len = sizeof(text) - 1;
} }
doLogEx(pContext, tvStart, NULL, text, len, false, true); log_it_ex3(pContext, tvStart, NULL, text, len, false, true);
} }
const char *log_get_level_caption_ex(LogContext *pContext) const char *log_get_level_caption_ex(LogContext *pContext)
{ {
const char *caption; return get_log_level_caption(pContext->log_level);
switch (pContext->log_level)
{
case LOG_DEBUG:
caption = "DEBUG";
break;
case LOG_INFO:
caption = "INFO";
break;
case LOG_NOTICE:
caption = "NOTICE";
break;
case LOG_WARNING:
caption = "WARNING";
break;
case LOG_ERR:
caption = "ERROR";
break;
case LOG_CRIT:
caption = "CRIT";
break;
case LOG_ALERT:
caption = "ALERT";
break;
case LOG_EMERG:
caption = "EMERG";
break;
default:
caption = "UNKOWN";
break;
}
return caption;
} }
#ifndef LOG_FORMAT_CHECK #ifndef LOG_FORMAT_CHECK

View File

@ -62,7 +62,7 @@ typedef struct log_context
char *pcurrent_buff; char *pcurrent_buff;
/* mutext lock */ /* mutext lock */
pthread_mutex_t log_thread_lock; pthread_mutex_t lock;
/* /*
rotate the log when the log file exceeds this parameter rotate the log when the log file exceeds this parameter
@ -343,7 +343,7 @@ void log_it_ex(LogContext *pContext, const int priority, \
* text_len: text string length (bytes) * text_len: text string length (bytes)
* return: none * return: none
*/ */
void log_it_ex1(LogContext *pContext, const int priority, \ void log_it_ex1(LogContext *pContext, const int priority,
const char *text, const int text_len); const char *text, const int text_len);
/** log to file /** log to file
@ -355,10 +355,13 @@ void log_it_ex1(LogContext *pContext, const int priority, \
* bNeedSync: if sync to file immediatelly * bNeedSync: if sync to file immediatelly
* return: none * return: none
*/ */
void log_it_ex2(LogContext *pContext, const char *caption, \ void log_it_ex2(LogContext *pContext, const char *caption,
const char *text, const int text_len, \ const char *text, const int text_len,
const bool bNeedSync, const bool bNeedLock); const bool bNeedSync, const bool bNeedLock);
void log_it_ex3(LogContext *pContext, struct timeval *tv,
const char *caption, const char *text, const int text_len,
const bool bNeedSync, const bool bNeedLock);
/** sync log buffer to log file /** sync log buffer to log file
* parameters: * parameters:

View File

@ -46,6 +46,7 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
fms_client_get_current_time_ms_func get_current_time_ms_func, fms_client_get_current_time_ms_func get_current_time_ms_func,
const int init_recv_buffer_size, const int timeout_ms) const int init_recv_buffer_size, const int timeout_ms)
{ {
const bool use_io_uring = false;
int result; int result;
int new_init_recv_buffer_size; int new_init_recv_buffer_size;
int i; int i;
@ -65,8 +66,8 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
return EINVAL; return EINVAL;
} }
if ((result=ioevent_init(&client->ioevent, entry_count, if ((result=ioevent_init(&client->ioevent, "client",
timeout_ms, 0)) != 0) use_io_uring, entry_count, timeout_ms, 0)) != 0)
{ {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"ioevent_init fail, errno: %d, error info: %s", "ioevent_init fail, errno: %d, error info: %s",
@ -85,7 +86,7 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
} }
for (i=0; i<entry_count; i++) { for (i=0; i<entry_count; i++) {
if ((result=fast_buffer_init_ex(&entries[i].recv_buffer, if ((result=fast_buffer_init1(&entries[i].recv_buffer,
new_init_recv_buffer_size)) != 0) new_init_recv_buffer_size)) != 0)
{ {
return result; return result;
@ -128,6 +129,7 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
{ {
int bytes; int bytes;
int result; int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0; result = 0;
while (entry->remain > 0) { while (entry->remain > 0) {
@ -139,27 +141,26 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
break; break;
} else if (errno == EINTR) { //should retry } else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, " logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal", "server: %s:%u, ignore interupt signal", __LINE__,
__LINE__, entry->conn->ip_addr, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port); entry->conn->port);
continue; continue;
} else { } else {
result = errno != 0 ? errno : ECONNRESET; result = errno != 0 ? errno : ECONNRESET;
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"send to server %s:%u fail, " "send to server %s:%u fail, "
"errno: %d, error info: %s", "errno: %d, error info: %s", __LINE__,
__LINE__, entry->conn->ip_addr, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->port, result, strerror(result));
result, strerror(result));
break; break;
} }
} else if (bytes == 0) { } else if (bytes == 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"send to server %s:%u, sock: %d fail, " "send to server %s:%u, sock: %d fail, "
"connection disconnected", "connection disconnected", __LINE__,
__LINE__, entry->conn->ip_addr, entry->conn->port, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->sock); entry->conn->port, entry->conn->sock);
result = ECONNRESET; result = ECONNRESET;
break; break;
@ -190,6 +191,7 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
{ {
int i; int i;
int result; int result;
char formatted_ip[FORMATTED_IP_SIZE];
for (i=0; i<client->entry_count; i++) { for (i=0; i<client->entry_count; i++) {
client->entries[i].remain = send_buffer->length; client->entries[i].remain = send_buffer->length;
@ -202,9 +204,9 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
client->entries[i].error_no = ENOTCONN; client->entries[i].error_no = ENOTCONN;
client->entries[i].done = true; client->entries[i].done = true;
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"NOT connected to %s:%u", "NOT connected to %s:%u", __LINE__,
__LINE__, client->entries[i].conn->ip_addr, format_ip_address(client->entries[i].conn->ip_addr,
client->entries[i].conn->port); formatted_ip), client->entries[i].conn->port);
continue; continue;
} }
@ -244,6 +246,7 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
{ {
int bytes; int bytes;
int result; int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0; result = 0;
while (entry->remain > 0) { while (entry->remain > 0) {
@ -254,27 +257,26 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
break; break;
} else if (errno == EINTR) { //should retry } else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, " logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal", "server: %s:%u, ignore interupt signal", __LINE__,
__LINE__, entry->conn->ip_addr, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port); entry->conn->port);
continue; continue;
} else { } else {
result = errno != 0 ? errno : ECONNRESET; result = errno != 0 ? errno : ECONNRESET;
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv failed, " "server: %s:%u, recv failed, "
"errno: %d, error info: %s", "errno: %d, error info: %s", __LINE__,
__LINE__, entry->conn->ip_addr, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->port, result, strerror(result));
result, strerror(result));
break; break;
} }
} else if (bytes == 0) { } else if (bytes == 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"server: %s:%u, sock: %d, recv failed, " "server: %s:%u, sock: %d, recv failed, "
"connection disconnected", "connection disconnected", __LINE__,
__LINE__, entry->conn->ip_addr, entry->conn->port, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->sock); entry->conn->port, entry->conn->sock);
result = ECONNRESET; result = ECONNRESET;
break; break;
@ -289,8 +291,8 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
body_length = client->get_body_length_func(&entry->recv_buffer); body_length = client->get_body_length_func(&entry->recv_buffer);
if (body_length < 0) { if (body_length < 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"server: %s:%u, body_length: %d < 0", "server: %s:%u, body_length: %d < 0", __LINE__,
__LINE__, entry->conn->ip_addr, format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, body_length); entry->conn->port, body_length);
result = EPIPE; result = EPIPE;
break; break;
@ -315,11 +317,16 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
static int fast_multi_sock_client_deal_io(FastMultiSockClient *client) static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
{ {
int result; int result;
int event;
int count; int count;
#if IOEVENT_USE_URING
unsigned head;
#else
int event;
int index; int index;
#endif
int remain_timeout; int remain_timeout;
FastMultiSockEntry *entry; FastMultiSockEntry *entry;
char formatted_ip[FORMATTED_IP_SIZE];
while (client->pulling_count > 0) { while (client->pulling_count > 0) {
remain_timeout = client->deadline_time_ms - remain_timeout = client->deadline_time_ms -
@ -328,8 +335,39 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
break; break;
} }
#if IOEVENT_USE_URING
result = io_uring_wait_cqe_timeout(&client->ioevent.ring,
&client->ioevent.cqe, &client->ioevent.timeout);
switch (result) {
case 0:
break;
case -ETIME:
case -EAGAIN:
case -EINTR:
continue;
default:
result *= -1;
logError("file: "__FILE__", line: %d, "
"io_uring_wait_cqe fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
count = 0;
io_uring_for_each_cqe(&client->ioevent.ring, head, client->ioevent.cqe) {
count++;
entry = (FastMultiSockEntry *)client->ioevent.cqe->user_data;
//logInfo("sock: %d, event: %d", entry->conn->sock, event);
result = entry->io_callback(client, entry);
if (result != 0 || entry->remain == 0) {
fast_multi_sock_client_finish(client, entry, result);
}
}
io_uring_cq_advance(&client->ioevent.ring, count);
#else
count = ioevent_poll_ex(&client->ioevent, remain_timeout); count = ioevent_poll_ex(&client->ioevent, remain_timeout);
logInfo("poll count: %d\n", count); //logInfo("poll count: %d\n", count);
for (index=0; index<count; index++) { for (index=0; index<count; index++) {
event = IOEVENT_GET_EVENTS(&client->ioevent, index); event = IOEVENT_GET_EVENTS(&client->ioevent, index);
entry = (FastMultiSockEntry *)IOEVENT_GET_DATA( entry = (FastMultiSockEntry *)IOEVENT_GET_DATA(
@ -337,21 +375,22 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
if (event & IOEVENT_ERROR) { if (event & IOEVENT_ERROR) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv error event: %d, " "server: %s:%u, recv error event: %d, connection "
"connection reset", __LINE__, "reset", __LINE__, format_ip_address(entry->conn->
entry->conn->ip_addr, entry->conn->port, event); ip_addr, formatted_ip), entry->conn->port, event);
fast_multi_sock_client_finish(client, entry, ECONNRESET); fast_multi_sock_client_finish(client, entry, ECONNRESET);
continue; continue;
} }
logInfo("sock: %d, event: %d", entry->conn->sock, event); //logInfo("sock: %d, event: %d", entry->conn->sock, event);
result = entry->io_callback(client, entry); result = entry->io_callback(client, entry);
if (result != 0 || entry->remain == 0) { if (result != 0 || entry->remain == 0) {
fast_multi_sock_client_finish(client, entry, result); fast_multi_sock_client_finish(client, entry, result);
} }
} }
#endif
} }
/* /*
@ -366,9 +405,9 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
fast_multi_sock_client_finish(client, fast_multi_sock_client_finish(client,
client->entries + i, ETIMEDOUT); client->entries + i, ETIMEDOUT);
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"recv from %s:%u timedout", "recv from %s:%u timedout", __LINE__,
__LINE__, client->entries[i].conn->ip_addr, format_ip_address(client->entries[i].conn->ip_addr,
client->entries[i].conn->port); formatted_ip), client->entries[i].conn->port);
} }
} }
} }

View File

@ -50,14 +50,14 @@ int write_to_pid_file(const char *pidFilename)
char buff[32]; char buff[32];
int len; int len;
len = sprintf(buff, "%d", (int)getpid()); len = fc_itoa(getpid(), buff);
return writeToFile(pidFilename, buff, len); return writeToFile(pidFilename, buff, len);
} }
int delete_pid_file(const char *pidFilename) int delete_pid_file(const char *pidFilename)
{ {
int result; int result;
pid_t pid; pid_t pid = 0;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) { if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
return result; return result;
@ -112,14 +112,16 @@ static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
} }
} }
int process_stop_ex(const char *pidFilename, const bool bShowError) int process_stop_ex(const char *pidFilename,
const bool bShowError, bool *force)
{ {
#define MAX_WAIT_COUNT 300 #define MAX_WAIT_COUNT 300
pid_t pid; pid_t pid = 0;
int result; int result;
int sig; int sig;
int i; int i;
*force = false;
if ((result=do_stop(pidFilename, bShowError, &pid)) != 0) { if ((result=do_stop(pidFilename, bShowError, &pid)) != 0) {
return result; return result;
} }
@ -131,14 +133,15 @@ int process_stop_ex(const char *pidFilename, const bool bShowError)
break; break;
} }
usleep(100 * 1000); fc_sleep_ms(100);
} }
if (i == MAX_WAIT_COUNT) { if (i == MAX_WAIT_COUNT) {
if (kill(pid, SIGKILL) == 0) { if (kill(pid, SIGKILL) == 0) {
fprintf(stderr, "waiting for pid [%d] exit timeout, " fprintf(stderr, "waiting for pid [%d] exit timeout, "
"force kill!\n", (int)pid); "force kill!\n", (int)pid);
usleep(100 * 1000); *force = true;
fc_sleep_ms(100);
} }
} }
@ -149,12 +152,16 @@ int process_stop_ex(const char *pidFilename, const bool bShowError)
int process_restart(const char *pidFilename) int process_restart(const char *pidFilename)
{ {
const bool bShowError = false; const bool bShowError = false;
bool force;
int result; int result;
result = process_stop_ex(pidFilename, bShowError); result = process_stop_ex(pidFilename, bShowError, &force);
if (result == ENOENT || result == ESRCH) { if (result == ENOENT || result == ESRCH) {
result = 0; result = 0;
} else if (result == 0) { } else if (result == 0) {
if (force) {
sleep(1);
}
fprintf(stderr, "starting ...\n"); fprintf(stderr, "starting ...\n");
} }
@ -192,7 +199,7 @@ static const char *get_exename_by_pid(const pid_t pid, char *buff,
int process_start(const char* pidFilename) int process_start(const char* pidFilename)
{ {
pid_t pid; pid_t pid = 0;
int result; int result;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) { if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
@ -278,6 +285,7 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
const int path_size, const int noent_log_level) const int path_size, const int noent_log_level)
{ {
char *pBasePath; char *pBasePath;
string_t path_string;
IniContext iniContext; IniContext iniContext;
int result; int result;
@ -303,7 +311,8 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
break; break;
} }
normalize_path(NULL, pBasePath, base_path, path_size); FC_SET_STRING(path_string, pBasePath);
normalize_path(NULL, &path_string, base_path, path_size);
chopPath(base_path); chopPath(base_path);
if (!fileExists(base_path)) if (!fileExists(base_path))
{ {
@ -330,7 +339,6 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
int process_action(const char *pidFilename, const char *action, bool *stop) int process_action(const char *pidFilename, const char *action, bool *stop)
{ {
const bool bShowError = true;
int result; int result;
pid_t pid; pid_t pid;
@ -343,7 +351,7 @@ int process_action(const char *pidFilename, const char *action, bool *stop)
if (strcmp(action, "stop") == 0) if (strcmp(action, "stop") == 0)
{ {
*stop = true; *stop = true;
return process_stop_ex(pidFilename, bShowError); return process_stop(pidFilename);
} }
else if (strcmp(action, "status") == 0) else if (strcmp(action, "status") == 0)
{ {

View File

@ -39,9 +39,15 @@ int write_to_pid_file(const char *pidFilename);
int delete_pid_file(const char *pidFilename); int delete_pid_file(const char *pidFilename);
int process_stop_ex(const char *pidFilename, const bool bShowError); int process_stop_ex(const char *pidFilename,
const bool bShowError, bool *force);
#define process_stop(pidFilename) process_stop_ex(pidFilename, true) static inline int process_stop(const char *pidFilename)
{
const bool bShowError = true;
bool force;
return process_stop_ex(pidFilename, bShowError, &force);
}
int process_restart(const char *pidFilename); int process_restart(const char *pidFilename);

View File

@ -244,6 +244,7 @@ static int fc_server_check_ip_port(FCServerConfig *ctx,
FCServerMap *previous; FCServerMap *previous;
FCServerMap *current; FCServerMap *current;
FCServerMap *end; FCServerMap *end;
char formatted_ip[FORMATTED_IP_SIZE];
int id1; int id1;
int id2; int id2;
@ -261,8 +262,8 @@ static int fc_server_check_ip_port(FCServerConfig *ctx,
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config file: %s, duplicate ip:port %s:%u, " "config file: %s, duplicate ip:port %s:%u, "
"the server ids: %d, %d", __LINE__, "the server ids: %d, %d", __LINE__,
config_filename, previous->ip_addr.str, config_filename, format_ip_address(previous->ip_addr.str,
previous->port, id1, id2); formatted_ip), previous->port, id1, id2);
return EEXIST; return EEXIST;
} }
@ -293,15 +294,18 @@ FCServerInfo *fc_server_get_by_ip_port_ex(FCServerConfig *ctx,
static inline void fc_server_set_group_ptr_name(FCServerGroupInfo *ginfo, static inline void fc_server_set_group_ptr_name(FCServerGroupInfo *ginfo,
const char *group_name) const char *group_name)
{ {
int len;
ginfo->group_name.str = ginfo->name_buff; ginfo->group_name.str = ginfo->name_buff;
ginfo->group_name.len = snprintf(ginfo->name_buff, len = strlen(group_name);
sizeof(ginfo->name_buff) - 1, "%s", group_name); if (len >= sizeof(ginfo->name_buff)) {
if (ginfo->group_name.len == 0) { len = sizeof(ginfo->name_buff) - 1;
return;
} }
fc_trim(ginfo->group_name.str); memcpy(ginfo->name_buff, group_name, len);
ginfo->group_name.len = strlen(ginfo->group_name.str); *(ginfo->name_buff + len) = '\0';
fc_trim(ginfo->name_buff);
ginfo->group_name.len = strlen(ginfo->name_buff);
} }
static inline void fc_server_set_ip_prefix(FCServerGroupInfo *ginfo, static inline void fc_server_set_ip_prefix(FCServerGroupInfo *ginfo,
@ -309,40 +313,111 @@ static inline void fc_server_set_ip_prefix(FCServerGroupInfo *ginfo,
{ {
ginfo->filter.ip_prefix.str = ginfo->filter.prefix_buff; ginfo->filter.ip_prefix.str = ginfo->filter.prefix_buff;
if (ip_prefix != NULL) { if (ip_prefix != NULL) {
ginfo->filter.ip_prefix.len = snprintf(ginfo->filter.prefix_buff, ginfo->filter.ip_prefix.len = fc_safe_strcpy(
sizeof(ginfo->filter.prefix_buff) - 1, "%s", ip_prefix); ginfo->filter.prefix_buff, ip_prefix);
} }
} }
static int fc_server_load_one_group(FCServerConfig *ctx, static inline int fc_server_set_comm_type(FCCommunicationType *comm_type,
const char *config_filename, IniContext *ini_context, const char *config_filename, const char *section_name,
const int group_count, const char *section_name) const char *comm_type_str, const FCCommunicationType default_comm_type)
{ {
if (comm_type_str == NULL) {
*comm_type = default_comm_type;
return 0;
} else if (strcasecmp(comm_type_str, "socket") == 0) {
*comm_type = fc_comm_type_sock;
return 0;
} else if (strcasecmp(comm_type_str, "rdma") == 0) {
*comm_type = fc_comm_type_rdma;
return 0;
} else {
logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, "
"invalid communication: %s!", __LINE__,
config_filename, section_name, comm_type_str);
return EINVAL;
}
}
static int load_comm_type_and_smart_polling(IniFullContext *ini_ctx,
FCCommunicationType *comm_type, FCSmartPollingConfig *smart_polling,
const FCCommunicationType default_comm_type,
const FCSmartPollingConfig *default_smart_polling)
{
int result;
char *comm_type_str;
comm_type_str = iniGetStrValue(ini_ctx->section_name,
"communication", ini_ctx->context);
if (comm_type_str == NULL) {
comm_type_str = iniGetStrValue(ini_ctx->section_name,
"comm_type", ini_ctx->context);
}
if ((result=fc_server_set_comm_type(comm_type, ini_ctx->filename,
ini_ctx->section_name, comm_type_str,
default_comm_type)) != 0)
{
return result;
}
if (*comm_type == fc_comm_type_sock) {
smart_polling->enabled = false;
smart_polling->switch_on_iops = 0;
smart_polling->switch_on_count = 0;
} else {
smart_polling->enabled = iniGetBoolValue(ini_ctx->section_name,
"smart_polling", ini_ctx->context,
default_smart_polling->enabled);
smart_polling->switch_on_iops = iniGetIntValue(ini_ctx->section_name,
"polling_switch_on_iops", ini_ctx->context,
default_smart_polling->switch_on_iops);
smart_polling->switch_on_count = iniGetIntValue(ini_ctx->section_name,
"polling_switch_on_count", ini_ctx->context,
default_smart_polling->switch_on_count);
}
return 0;
}
static inline int load_buffer_size(IniFullContext *ini_ctx,
const int default_buffer_size)
{
int buffer_size;
buffer_size = iniGetByteValue(ini_ctx->section_name, "buffer_size",
ini_ctx->context, default_buffer_size);
return iniCheckAndCorrectIntValue(ini_ctx, "buffer_size",
buffer_size, 8 * 1024, 8 * 1024 * 1024);
}
static int fc_server_load_one_group(FCServerConfig *ctx,
IniFullContext *ini_ctx, const int group_count)
{
int result;
FCServerGroupInfo *group; FCServerGroupInfo *group;
char new_name[FAST_INI_ITEM_NAME_SIZE]; char new_name[FAST_INI_ITEM_NAME_SIZE];
char *port_str; char *port_str;
char *net_type; char *net_type;
char *ip_prefix; char *ip_prefix;
strcpy(new_name, section_name); strcpy(new_name, ini_ctx->section_name);
group = ctx->group_array.groups + ctx->group_array.count; group = ctx->group_array.groups + ctx->group_array.count;
fc_server_set_group_ptr_name(group, new_name + GROUP_SECTION_PREFIX_LEN); fc_server_set_group_ptr_name(group, new_name + GROUP_SECTION_PREFIX_LEN);
if (group->group_name.len == 0) { if (group->group_name.len == 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, no group name!", "config filename: %s, section: %s, no group name!",
__LINE__, config_filename, section_name); __LINE__, ini_ctx->filename, ini_ctx->section_name);
return EINVAL; return EINVAL;
} }
port_str = iniGetStrValue(section_name, SERVER_ITEM_PORT_STR, ini_context); port_str = iniGetStrValue(ini_ctx->section_name,
SERVER_ITEM_PORT_STR, ini_ctx->context);
if (port_str == NULL) { if (port_str == NULL) {
if (group_count == 1) { if (group_count == 1) {
group->port = ctx->default_port; group->port = ctx->default_port;
} else { } else {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, no item: %s!", "config filename: %s, section: %s, no item: %s!",
__LINE__, config_filename, section_name, __LINE__, ini_ctx->filename, ini_ctx->section_name,
SERVER_ITEM_PORT_STR); SERVER_ITEM_PORT_STR);
return ENOENT; return ENOENT;
} }
@ -352,24 +427,39 @@ static int fc_server_load_one_group(FCServerConfig *ctx,
if (group->port <= 0 || (endptr != NULL && *endptr != '\0')) { if (group->port <= 0 || (endptr != NULL && *endptr != '\0')) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, item: %s, " "config filename: %s, section: %s, item: %s, "
"invalid port: %s", __LINE__, config_filename, "invalid port: %s", __LINE__, ini_ctx->filename,
section_name, SERVER_ITEM_PORT_STR, port_str); ini_ctx->section_name, SERVER_ITEM_PORT_STR, port_str);
return EINVAL; return EINVAL;
} }
} }
net_type = iniGetStrValue(section_name, "net_type", ini_context); net_type = iniGetStrValue(ini_ctx->section_name,
"net_type", ini_ctx->context);
group->filter.net_type = fc_get_net_type_by_name(net_type); group->filter.net_type = fc_get_net_type_by_name(net_type);
if (group->filter.net_type == FC_NET_TYPE_NONE) { if (group->filter.net_type == FC_NET_TYPE_NONE) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, invalid net_type: %s", "config filename: %s, section: %s, invalid net_type: %s",
__LINE__, config_filename, group->group_name.str, net_type); __LINE__, ini_ctx->filename, group->group_name.str, net_type);
return EINVAL; return EINVAL;
} }
ip_prefix = iniGetStrValue(section_name, "ip_prefix", ini_context); ip_prefix = iniGetStrValue(ini_ctx->section_name,
"ip_prefix", ini_ctx->context);
fc_server_set_ip_prefix(group, ip_prefix); fc_server_set_ip_prefix(group, ip_prefix);
if ((result=load_comm_type_and_smart_polling(ini_ctx,
&group->comm_type, &group->smart_polling,
ctx->comm_type, &ctx->smart_polling)) != 0)
{
return result;
}
if (group->comm_type == fc_comm_type_sock) {
group->buffer_size = 0;
} else {
group->buffer_size = load_buffer_size(ini_ctx, ctx->buffer_size);
}
ctx->group_array.count++; ctx->group_array.count++;
return 0; return 0;
} }
@ -429,7 +519,7 @@ static void fc_server_sort_groups(FCServerConfig *ctx)
} }
static int fc_server_load_groups(FCServerConfig *ctx, static int fc_server_load_groups(FCServerConfig *ctx,
const char *config_filename, IniContext *ini_context) IniFullContext *ini_ctx)
{ {
int result; int result;
int count; int count;
@ -437,30 +527,30 @@ static int fc_server_load_groups(FCServerConfig *ctx,
IniSectionInfo *section; IniSectionInfo *section;
IniSectionInfo *end; IniSectionInfo *end;
if ((result=iniGetSectionNamesByPrefix(ini_context, if ((result=iniGetSectionNamesByPrefix(ini_ctx->context,
GROUP_SECTION_PREFIX_STR, sections, GROUP_SECTION_PREFIX_STR, sections,
FC_MAX_GROUP_COUNT, &count)) != 0) FC_MAX_GROUP_COUNT, &count)) != 0)
{ {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"config filename: %s, get sections by prefix %s fail, " "config filename: %s, get sections by prefix %s fail, "
"errno: %d, error info: %s", __LINE__, config_filename, "errno: %d, error info: %s", __LINE__, ini_ctx->filename,
GROUP_SECTION_PREFIX_STR, result, STRERROR(result)); GROUP_SECTION_PREFIX_STR, result, STRERROR(result));
return result; return result;
} }
if (count == 0) { if (count == 0) {
ctx->group_array.count = 1; ctx->group_array.count = 1;
memset(ctx->group_array.groups, 0, sizeof(FCServerGroupInfo));
fc_server_set_group_ptr_name(ctx->group_array.groups + 0, ""); fc_server_set_group_ptr_name(ctx->group_array.groups + 0, "");
ctx->group_array.groups[0].port = iniGetIntValue(NULL, "port", ctx->group_array.groups[0].port = iniGetIntValue(NULL, "port",
ini_context, ctx->default_port); ini_ctx->context, ctx->default_port);
return 0; return 0;
} }
end = sections + count; end = sections + count;
for (section=sections; section<end; section++) { for (section=sections; section<end; section++) {
if ((result=fc_server_load_one_group(ctx, config_filename, ini_ctx->section_name = section->section_name;
ini_context, count, section->section_name)) != 0) if ((result=fc_server_load_one_group(ctx, ini_ctx, count)) != 0) {
{
return result; return result;
} }
} }
@ -612,6 +702,7 @@ static int check_addresses_duplicate(FCServerConfig *ctx,
FCAddressInfo **ppaddr; FCAddressInfo **ppaddr;
FCAddressInfo **ppend; FCAddressInfo **ppend;
FCAddressInfo **pprevious; FCAddressInfo **pprevious;
char formatted_ip[FORMATTED_IP_SIZE];
if (group_addr->address_array.count <= 1) { if (group_addr->address_array.count <= 1) {
return 0; return 0;
@ -629,7 +720,8 @@ static int check_addresses_duplicate(FCServerConfig *ctx,
config_filename, section_name, config_filename, section_name,
group_addr->server_group->group_name.len, group_addr->server_group->group_name.len,
group_addr->server_group->group_name.str, group_addr->server_group->group_name.str,
(*ppaddr)->conn.ip_addr, (*ppaddr)->conn.port); format_ip_address((*ppaddr)->conn.ip_addr, formatted_ip),
(*ppaddr)->conn.port);
return EEXIST; return EEXIST;
} }
pprevious = ppaddr; pprevious = ppaddr;
@ -794,6 +886,7 @@ static int fc_server_load_group_server(FCServerConfig *ctx,
return result; return result;
} }
address.conn.comm_type = group->comm_type;
if ((result=fc_server_set_group_server_address(server, if ((result=fc_server_set_group_server_address(server,
group_addr, &address)) != 0) group_addr, &address)) != 0)
{ {
@ -812,6 +905,7 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
FCGroupAddresses *group_addr; FCGroupAddresses *group_addr;
const FCAddressInfo *new_addr; const FCAddressInfo *new_addr;
FCAddressInfo addr_holder; FCAddressInfo addr_holder;
char formatted_ip[FORMATTED_IP_SIZE];
int result; int result;
int count; int count;
int group_index; int group_index;
@ -835,9 +929,16 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
if (addr->conn.port == 0) { if (addr->conn.port == 0) {
addr_holder = *addr; addr_holder = *addr;
addr_holder.conn.port = FC_SERVER_GROUP_PORT(group); addr_holder.conn.port = FC_SERVER_GROUP_PORT(group);
addr_holder.conn.comm_type = group->comm_type;
new_addr = &addr_holder; new_addr = &addr_holder;
} else { } else {
new_addr = addr; if (addr->conn.comm_type == group->comm_type) {
new_addr = addr;
} else {
addr_holder = *addr;
addr_holder.conn.comm_type = group->comm_type;
new_addr = &addr_holder;
}
} }
if ((result=fc_server_set_group_server_address(server, if ((result=fc_server_set_group_server_address(server,
@ -870,7 +971,8 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
"config filename: %s, section: %s, " "config filename: %s, section: %s, "
"host %s:%u belongs to %d groups", "host %s:%u belongs to %d groups",
__LINE__, config_filename, section_name, __LINE__, config_filename, section_name,
addr->conn.ip_addr, addr->conn.port, count); format_ip_address(addr->conn.ip_addr, formatted_ip),
addr->conn.port, count);
return EEXIST; return EEXIST;
} }
@ -1167,17 +1269,71 @@ static int fc_server_load_servers(FCServerConfig *ctx,
return result; return result;
} }
static void load_connection_thread_local(FCServerConfig *ctx,
IniContext *ini_context, const char *config_filename)
{
char *connection_thread_local;
connection_thread_local = iniGetStrValue(NULL,
"connection_thread_local", ini_context);
if (connection_thread_local == NULL || *connection_thread_local == '\0') {
ctx->connection_thread_local = fc_connection_thread_local_auto;
} else if (strcasecmp(connection_thread_local, "auto") == 0) {
ctx->connection_thread_local = fc_connection_thread_local_auto;
} else if (strcasecmp(connection_thread_local, "yes") == 0) {
ctx->connection_thread_local = fc_connection_thread_local_yes;
} else if (strcasecmp(connection_thread_local, "no") == 0) {
ctx->connection_thread_local = fc_connection_thread_local_no;
} else {
logWarning("file: "__FILE__", line: %d, "
"config file: %s, invalid connection_thread_local: %s, "
"set to auto!", __LINE__, config_filename,
connection_thread_local);
ctx->connection_thread_local = fc_connection_thread_local_auto;
}
}
static int fc_server_load_data(FCServerConfig *ctx, static int fc_server_load_data(FCServerConfig *ctx,
IniContext *ini_context, const char *config_filename) IniContext *ini_context, const char *config_filename)
{ {
int result; int result;
bool have_rdma;
IniFullContext full_ini_ctx;
FCSmartPollingConfig default_smart_polling;
FCServerGroupInfo *group;
FCServerGroupInfo *end;
if ((result=fc_server_load_groups(ctx, config_filename, FAST_INI_SET_FULL_CTX_EX(full_ini_ctx,
ini_context)) != 0) config_filename, NULL, ini_context);
default_smart_polling.enabled = true;
default_smart_polling.switch_on_iops = 10240;
default_smart_polling.switch_on_count = 3;
if ((result=load_comm_type_and_smart_polling(&full_ini_ctx,
&ctx->comm_type, &ctx->smart_polling,
fc_comm_type_sock, &default_smart_polling)) != 0)
{ {
return result; return result;
} }
ctx->buffer_size = load_buffer_size(&full_ini_ctx, 256 * 1024);
if ((result=fc_server_load_groups(ctx, &full_ini_ctx)) != 0) {
return result;
}
have_rdma = false;
end = ctx->group_array.groups + ctx->group_array.count;
for (group=ctx->group_array.groups; group<end; group++) {
if (group->comm_type != fc_comm_type_sock) {
have_rdma = true;
break;
}
}
if (!have_rdma) {
ctx->buffer_size = 0;
}
load_connection_thread_local(ctx, ini_context, config_filename);
if ((result=fc_server_load_servers(ctx, config_filename, if ((result=fc_server_load_servers(ctx, config_filename,
ini_context)) != 0) ini_context)) != 0)
{ {
@ -1340,13 +1496,31 @@ static int fc_groups_to_string(FCServerConfig *ctx, FastBuffer *buffer)
fast_buffer_append(buffer, fast_buffer_append(buffer,
"[%s%.*s]\n" "[%s%.*s]\n"
"port = %d\n" "port = %d\n",
"net_type = %s\n"
"ip_prefix = %.*s\n\n",
GROUP_SECTION_PREFIX_STR, GROUP_SECTION_PREFIX_STR,
group->group_name.len, group->group_name.str, group->group_name.len, group->group_name.str,
group->port, net_type_caption, group->port);
group->filter.ip_prefix.len,
if (group->comm_type != fc_comm_type_sock) {
fast_buffer_append(buffer,
"communication = %s\n"
"smart_polling = %d\n"
"polling_switch_on_iops = %d\n"
"polling_switch_on_count = %d\n",
fc_comm_type_str(group->comm_type),
group->smart_polling.enabled,
group->smart_polling.switch_on_iops,
group->smart_polling.switch_on_count);
if (group->buffer_size != ctx->buffer_size) {
fast_buffer_append(buffer, "buffer_size = %d KB\n",
group->buffer_size / 1024);
}
}
fast_buffer_append(buffer,
"net_type = %s\n"
"ip_prefix = %.*s\n\n",
net_type_caption, group->filter.ip_prefix.len,
group->filter.ip_prefix.str); group->filter.ip_prefix.str);
} }
return 0; return 0;
@ -1357,6 +1531,7 @@ static void fc_group_servers_to_string(FCServerConfig *ctx,
{ {
FCAddressInfo **addr; FCAddressInfo **addr;
FCAddressInfo **end; FCAddressInfo **end;
char formatted_ip[FORMATTED_IP_SIZE];
end = gaddr->address_array.addrs + gaddr->address_array.count; end = gaddr->address_array.addrs + gaddr->address_array.count;
for (addr=gaddr->address_array.addrs; addr<end; addr++) { for (addr=gaddr->address_array.addrs; addr<end; addr++) {
@ -1370,7 +1545,8 @@ static void fc_group_servers_to_string(FCServerConfig *ctx,
SERVER_ITEM_HOST_AFFIX_STR); SERVER_ITEM_HOST_AFFIX_STR);
} }
fast_buffer_append(buffer, " = %s:%u\n", fast_buffer_append(buffer, " = %s:%u\n",
(*addr)->conn.ip_addr, (*addr)->conn.port); format_ip_address((*addr)->conn.ip_addr, formatted_ip),
(*addr)->conn.port);
} }
} }
@ -1423,6 +1599,14 @@ int fc_server_to_config_string(FCServerConfig *ctx, FastBuffer *buffer)
{ {
int result; int result;
if (ctx->buffer_size > 0) {
if ((result=fast_buffer_check(buffer, 1024)) != 0) {
return result;
}
fast_buffer_append(buffer, "buffer_size = %d KB\n",
ctx->buffer_size / 1024);
}
fc_server_clear_server_port(&ctx->group_array); fc_server_clear_server_port(&ctx->group_array);
if ((result=fc_groups_to_string(ctx, buffer)) != 0) { if ((result=fc_groups_to_string(ctx, buffer)) != 0) {
return result; return result;
@ -1435,13 +1619,31 @@ static void fc_server_log_groups(FCServerConfig *ctx)
{ {
FCServerGroupInfo *group; FCServerGroupInfo *group;
FCServerGroupInfo *end; FCServerGroupInfo *end;
char buff[1024];
char *p;
end = ctx->group_array.groups + ctx->group_array.count; end = ctx->group_array.groups + ctx->group_array.count;
for (group=ctx->group_array.groups; group<end; group++) { for (group=ctx->group_array.groups; group<end; group++) {
logInfo("group_name: %.*s, port: %d, net_type: %s, ip_prefix: %.*s", p = buff + sprintf(buff, "group_name: %.*s, port: %d",
group->group_name.len, group->group_name.str, group->port, group->group_name.len, group->group_name.str,
group->port);
if (group->comm_type != fc_comm_type_sock) {
p += sprintf(p, ", communication: %s, smart_polling: %d, "
"polling_switch_on_iops: %d, polling_switch_on_count: %d",
fc_comm_type_str(group->comm_type),
group->smart_polling.enabled,
group->smart_polling.switch_on_iops,
group->smart_polling.switch_on_count);
if (group->buffer_size != ctx->buffer_size) {
p += sprintf(p, ", buffer_size = %d KB",
group->buffer_size / 1024);
}
}
p += sprintf(p, ", net_type: %s, ip_prefix: %.*s",
get_net_type_caption(group->filter.net_type), get_net_type_caption(group->filter.net_type),
group->filter.ip_prefix.len, group->filter.ip_prefix.str); group->filter.ip_prefix.len, group->filter.ip_prefix.str);
log_it1(LOG_INFO, buff, p - buff);
} }
} }
@ -1449,11 +1651,13 @@ static void fc_server_log_group_servers(FCGroupAddresses *gaddr)
{ {
FCAddressInfo **addr; FCAddressInfo **addr;
FCAddressInfo **end; FCAddressInfo **end;
char formatted_ip[FORMATTED_IP_SIZE];
end = gaddr->address_array.addrs + gaddr->address_array.count; end = gaddr->address_array.addrs + gaddr->address_array.count;
for (addr=gaddr->address_array.addrs; addr<end; addr++) { for (addr=gaddr->address_array.addrs; addr<end; addr++) {
logInfo(" %d. %s:%u", (int)(addr - gaddr->address_array.addrs + 1), logInfo(" %d. %s:%u", (int)(addr - gaddr->address_array.addrs + 1),
(*addr)->conn.ip_addr, (*addr)->conn.port); format_ip_address((*addr)->conn.ip_addr, formatted_ip),
(*addr)->conn.port);
} }
} }
@ -1491,67 +1695,20 @@ static void fc_server_log_servers(FCServerConfig *ctx)
void fc_server_to_log(FCServerConfig *ctx) void fc_server_to_log(FCServerConfig *ctx)
{ {
char buff[256];
char *p;
p = buff + sprintf(buff, "connection_thread_local: %s",
fc_connection_thread_local_str(ctx->connection_thread_local));
if (ctx->buffer_size > 0) {
p += sprintf(p, ", buffer_size: %d KB", ctx->buffer_size / 1024);
}
log_it1(LOG_INFO, buff, p - buff);
fc_server_log_groups(ctx); fc_server_log_groups(ctx);
fc_server_log_servers(ctx); fc_server_log_servers(ctx);
} }
ConnectionInfo *fc_server_check_connect_ex(FCAddressPtrArray *addr_array,
const char *service_name, const int connect_timeout,
const char *bind_ipaddr, const bool log_connect_error, int *err_no)
{
FCAddressInfo **current;
FCAddressInfo **addr;
FCAddressInfo **end;
if (addr_array->count <= 0) {
*err_no = ENOENT;
return NULL;
}
current = addr_array->addrs + addr_array->index;
if ((*current)->conn.sock >= 0) {
return &(*current)->conn;
}
if ((*err_no=conn_pool_connect_server_ex1(&(*current)->conn,
service_name, connect_timeout, bind_ipaddr,
log_connect_error)) == 0)
{
return &(*current)->conn;
}
if (addr_array->count == 1) {
return NULL;
}
end = addr_array->addrs + addr_array->count;
for (addr=addr_array->addrs; addr<end; addr++) {
if (addr == current) {
continue;
}
if ((*err_no=conn_pool_connect_server_ex1(&(*addr)->conn,
service_name, connect_timeout, bind_ipaddr,
log_connect_error)) == 0)
{
addr_array->index = addr - addr_array->addrs;
return &(*addr)->conn;
}
}
return NULL;
}
void fc_server_disconnect(FCAddressPtrArray *addr_array)
{
FCAddressInfo **current;
current = addr_array->addrs + addr_array->index;
if ((*current)->conn.sock >= 0) {
close((*current)->conn.sock);
(*current)->conn.sock = -1;
}
}
int fc_server_make_connection_ex(FCAddressPtrArray *addr_array, int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
ConnectionInfo *conn, const char *service_name, ConnectionInfo *conn, const char *service_name,
const int connect_timeout, const char *bind_ipaddr, const int connect_timeout, const char *bind_ipaddr,
@ -1567,10 +1724,11 @@ int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
} }
current = addr_array->addrs + addr_array->index; current = addr_array->addrs + addr_array->index;
*conn = (*current)->conn; conn_pool_set_server_info(conn, (*current)->conn.ip_addr,
conn->sock = -1; (*current)->conn.port);
if ((result=conn_pool_connect_server_ex1(conn, conn->comm_type = (*current)->conn.comm_type;
service_name, connect_timeout, if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
make_connection(conn, service_name, connect_timeout * 1000,
bind_ipaddr, log_connect_error)) == 0) bind_ipaddr, log_connect_error)) == 0)
{ {
return 0; return 0;
@ -1586,10 +1744,11 @@ int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
continue; continue;
} }
*conn = (*addr)->conn; conn_pool_set_server_info(conn, (*addr)->conn.ip_addr,
conn->sock = -1; (*addr)->conn.port);
if ((result=conn_pool_connect_server_ex1(conn, conn->comm_type = (*addr)->conn.comm_type;
service_name, connect_timeout, if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
make_connection(conn, service_name, connect_timeout * 1000,
bind_ipaddr, log_connect_error)) == 0) bind_ipaddr, log_connect_error)) == 0)
{ {
addr_array->index = addr - addr_array->addrs; addr_array->index = addr - addr_array->addrs;
@ -1624,3 +1783,36 @@ const FCAddressInfo *fc_server_get_address_by_peer(
return *(addr_array->addrs); return *(addr_array->addrs);
} }
struct ibv_pd *fc_alloc_rdma_pd(fc_alloc_pd_callback alloc_pd,
FCAddressPtrArray *address_array, int *result)
{
char *ip_addrs[FC_MAX_SERVER_IP_COUNT];
char **ip_addr;
FCAddressInfo **addr;
FCAddressInfo **end;
struct ibv_pd *pd;
int port;
if (address_array->count == 0) {
port = 0;
} else {
port = address_array->addrs[0]->conn.port;
}
end = address_array->addrs + address_array->count;
for (addr=address_array->addrs, ip_addr=ip_addrs;
addr<end; addr++, ip_addr++)
{
*ip_addr = (*addr)->conn.ip_addr;
}
if ((pd=alloc_pd((const char **)ip_addrs, address_array->
count, port)) != NULL)
{
*result = 0;
} else {
*result = ENODEV;
}
return pd;
}

View File

@ -52,11 +52,21 @@ typedef struct {
FCAddressInfo **addrs; FCAddressInfo **addrs;
} FCAddressPtrArray; } FCAddressPtrArray;
typedef struct
{
bool enabled;
int switch_on_iops;
int switch_on_count;
} FCSmartPollingConfig;
typedef struct typedef struct
{ {
string_t group_name; string_t group_name;
int port; //default port int port; //default port
int server_port; //port in server section int server_port; //port in server section
int buffer_size; //for RDMA
FCCommunicationType comm_type;
FCSmartPollingConfig smart_polling;
struct { struct {
int net_type; int net_type;
string_t ip_prefix; string_t ip_prefix;
@ -111,11 +121,21 @@ typedef struct
FCServerMap *maps; FCServerMap *maps;
} FCServerMapArray; } FCServerMapArray;
typedef struct typedef enum {
fc_connection_thread_local_auto,
fc_connection_thread_local_yes,
fc_connection_thread_local_no
} FCServerConnThreadLocal;
typedef struct fc_server_config
{ {
int default_port; int default_port;
int min_hosts_each_group; int min_hosts_each_group;
bool share_between_groups; //if an address shared between different groups bool share_between_groups; //if an address shared between different groups
int buffer_size; //for RDMA
FCCommunicationType comm_type;
FCSmartPollingConfig smart_polling;
FCServerConnThreadLocal connection_thread_local;
FCServerGroupArray group_array; FCServerGroupArray group_array;
struct { struct {
FCServerInfoArray by_id; //sorted by server id FCServerInfoArray by_id; //sorted by server id
@ -140,6 +160,16 @@ static inline FCServerInfo *fc_server_get_by_ip_port(FCServerConfig *ctx,
FCServerGroupInfo *fc_server_get_group_by_name(FCServerConfig *ctx, FCServerGroupInfo *fc_server_get_group_by_name(FCServerConfig *ctx,
const string_t *group_name); const string_t *group_name);
static inline FCServerGroupInfo *fc_server_get_group_by_index(
FCServerConfig *ctx, const int index)
{
if (index < 0 || index >= ctx->group_array.count) {
return NULL;
}
return ctx->group_array.groups + index;
}
static inline int fc_server_get_group_index_ex(FCServerConfig *ctx, static inline int fc_server_get_group_index_ex(FCServerConfig *ctx,
const string_t *group_name) const string_t *group_name)
{ {
@ -211,17 +241,6 @@ int fc_server_to_config_string(FCServerConfig *ctx, FastBuffer *buffer);
void fc_server_to_log(FCServerConfig *ctx); void fc_server_to_log(FCServerConfig *ctx);
ConnectionInfo *fc_server_check_connect_ex(FCAddressPtrArray *addr_array,
const char *service_name, const int connect_timeout,
const char *bind_ipaddr, const bool log_connect_error, int *err_no);
#define fc_server_check_connect(addr_array, service_name, \
connect_timeout, err_no) \
fc_server_check_connect_ex(addr_array, service_name, \
connect_timeout, NULL, true, err_no)
void fc_server_disconnect(FCAddressPtrArray *addr_array);
const FCAddressInfo *fc_server_get_address_by_peer( const FCAddressInfo *fc_server_get_address_by_peer(
FCAddressPtrArray *addr_array, const char *peer_ip); FCAddressPtrArray *addr_array, const char *peer_ip);
@ -235,6 +254,35 @@ int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
fc_server_make_connection_ex(addr_array, conn, \ fc_server_make_connection_ex(addr_array, conn, \
service_name, connect_timeout, NULL, true) service_name, connect_timeout, NULL, true)
static inline void fc_server_close_connection(ConnectionInfo *conn)
{
G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].close_connection(conn);
}
static inline void fc_server_destroy_connection(ConnectionInfo *conn)
{
fc_server_close_connection(conn);
conn_pool_free_connection(conn);
}
struct ibv_pd *fc_alloc_rdma_pd(fc_alloc_pd_callback alloc_pd,
FCAddressPtrArray *address_array, int *result);
static inline const char *fc_connection_thread_local_str(
const FCServerConnThreadLocal value)
{
switch (value) {
case fc_connection_thread_local_auto:
return "auto";
case fc_connection_thread_local_yes:
return "yes";
case fc_connection_thread_local_no:
return "no";
default:
return "unkown";
}
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/uio.h>
#include "common_define.h" #include "common_define.h"
#ifdef OS_LINUX #ifdef OS_LINUX
#include <sys/syscall.h> #include <sys/syscall.h>
@ -37,10 +38,6 @@
#define NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS \ #define NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS \
(NORMALIZE_FLAGS_URL_ENABLED | NORMALIZE_FLAGS_URL_APPEND_PARAMS) (NORMALIZE_FLAGS_URL_ENABLED | NORMALIZE_FLAGS_URL_APPEND_PARAMS)
#define resolve_path(from, filename, full_filename, size) \
normalize_path_ex(from, filename, full_filename, size, \
NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS)
#define FC_SET_CLOEXEC(fd) \ #define FC_SET_CLOEXEC(fd) \
if (g_set_cloexec) fd_set_cloexec(fd) if (g_set_cloexec) fd_set_cloexec(fd)
@ -49,6 +46,8 @@ extern "C" {
#endif #endif
extern bool g_set_cloexec; extern bool g_set_cloexec;
extern const char *g_lower_hex_chars;
extern const char *g_upper_hex_chars;
static inline void fc_enable_fd_cloexec(const bool cloexec) static inline void fc_enable_fd_cloexec(const bool cloexec)
{ {
@ -199,14 +198,24 @@ void printBuffHex(const char *s, const int len);
* buff: the buffer, at least 2 bytes space, no tail \0 * buff: the buffer, at least 2 bytes space, no tail \0
* return: none * return: none
*/ */
void short2buff(const short n, char *buff); static inline void short2buff(const short n, char *buff)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = (n >> 8) & 0xFF;
*p++ = n & 0xFF;
}
/** buffer convert to 16 bits int /** buffer convert to 16 bits int
* parameters: * parameters:
* buff: big-endian 2 bytes buffer * buff: big-endian 2 bytes buffer
* return: 16 bits int value * return: 16 bits int value
*/ */
short buff2short(const char *buff); static inline short buff2short(const char *buff)
{
return (short)((((unsigned char)(*(buff))) << 8) |
((unsigned char)(*(buff+1))));
}
/** 32 bits int convert to buffer (big-endian) /** 32 bits int convert to buffer (big-endian)
* parameters: * parameters:
@ -214,14 +223,28 @@ short buff2short(const char *buff);
* buff: the buffer, at least 4 bytes space, no tail \0 * buff: the buffer, at least 4 bytes space, no tail \0
* return: none * return: none
*/ */
void int2buff(const int n, char *buff); static inline void int2buff(const int n, char *buff)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = (n >> 24) & 0xFF;
*p++ = (n >> 16) & 0xFF;
*p++ = (n >> 8) & 0xFF;
*p++ = n & 0xFF;
}
/** buffer convert to 32 bits int /** buffer convert to 32 bits int
* parameters: * parameters:
* buff: big-endian 4 bytes buffer * buff: big-endian 4 bytes buffer
* return: 32 bits int value * return: 32 bits int value
*/ */
int buff2int(const char *buff); static inline int buff2int(const char *buff)
{
return (((unsigned char)(*buff)) << 24) |
(((unsigned char)(*(buff+1))) << 16) |
(((unsigned char)(*(buff+2))) << 8) |
((unsigned char)(*(buff+3)));
}
/** long (64 bits) convert to buffer (big-endian) /** long (64 bits) convert to buffer (big-endian)
* parameters: * parameters:
@ -229,15 +252,38 @@ int buff2int(const char *buff);
* buff: the buffer, at least 8 bytes space, no tail \0 * buff: the buffer, at least 8 bytes space, no tail \0
* return: none * return: none
*/ */
void long2buff(int64_t n, char *buff); static inline void long2buff(int64_t n, char *buff)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = (n >> 56) & 0xFF;
*p++ = (n >> 48) & 0xFF;
*p++ = (n >> 40) & 0xFF;
*p++ = (n >> 32) & 0xFF;
*p++ = (n >> 24) & 0xFF;
*p++ = (n >> 16) & 0xFF;
*p++ = (n >> 8) & 0xFF;
*p++ = n & 0xFF;
}
/** buffer convert to 64 bits int /** buffer convert to 64 bits int
* parameters: * parameters:
* buff: big-endian 8 bytes buffer * buff: big-endian 8 bytes buffer
* return: 64 bits int value * return: 64 bits int value
*/ */
int64_t buff2long(const char *buff); static inline int64_t buff2long(const char *buff)
{
unsigned char *p;
p = (unsigned char *)buff;
return (((int64_t)(*p)) << 56) |
(((int64_t)(*(p+1))) << 48) |
(((int64_t)(*(p+2))) << 40) |
(((int64_t)(*(p+3))) << 32) |
(((int64_t)(*(p+4))) << 24) |
(((int64_t)(*(p+5))) << 16) |
(((int64_t)(*(p+6))) << 8) |
((int64_t)(*(p+7)));
}
/** 32 bits float convert to buffer (big-endian) /** 32 bits float convert to buffer (big-endian)
* parameters: * parameters:
@ -295,6 +341,154 @@ static inline double buff2double(const char *buff)
return *p; return *p;
} }
static inline int padding_hex(char *buff, const int len, const int padding_len)
{
char *p;
char *end;
char *stop;
int new_len;
int fill_len;
if (padding_len == len) {
return len;
} else if (padding_len > len) {
fill_len = padding_len - len;
memmove(buff + fill_len, buff, len + 1);
memset(buff, '0', fill_len);
return padding_len;
} else if (*buff != '0') {
return len;
}
end = buff + len;
if (padding_len <= 0) {
stop = end - 1;
} else {
stop = end - padding_len;
}
p = buff + 1;
while (p < stop && *p == '0') {
++p;
}
new_len = end - p;
memmove(buff, p, new_len + 1);
return new_len;
}
static inline int short2hex(const short n, char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_lower_hex_chars[(n >> 12) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 8) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 4) & 0x0F];
*p++ = g_lower_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 4, padding_len);
}
static inline int short2HEX(const short n, char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_upper_hex_chars[(n >> 12) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 8) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 4) & 0x0F];
*p++ = g_upper_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 4, padding_len);
}
static inline int int2hex(const int n, char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_lower_hex_chars[(n >> 28) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 24) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 20) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 16) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 12) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 8) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 4) & 0x0F];
*p++ = g_lower_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 8, padding_len);
}
static inline int int2HEX(const int n, char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_upper_hex_chars[(n >> 28) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 24) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 20) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 16) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 12) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 8) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 4) & 0x0F];
*p++ = g_upper_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 8, padding_len);
}
static inline int long2hex(const int64_t n,
char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_lower_hex_chars[(n >> 60) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 56) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 52) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 48) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 44) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 40) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 36) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 32) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 28) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 24) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 20) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 16) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 12) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 8) & 0x0F];
*p++ = g_lower_hex_chars[(n >> 4) & 0x0F];
*p++ = g_lower_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 16, padding_len);
}
static inline int long2HEX(const int64_t n,
char *buff, const int padding_len)
{
unsigned char *p;
p = (unsigned char *)buff;
*p++ = g_upper_hex_chars[(n >> 60) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 56) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 52) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 48) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 44) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 40) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 36) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 32) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 28) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 24) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 20) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 16) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 12) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 8) & 0x0F];
*p++ = g_upper_hex_chars[(n >> 4) & 0x0F];
*p++ = g_upper_hex_chars[n & 0x0F];
*p = '\0';
return padding_hex(buff, 16, padding_len);
}
/** trim leading spaces ( \t\r\n) /** trim leading spaces ( \t\r\n)
* parameters: * parameters:
* pStr: the string to trim * pStr: the string to trim
@ -534,11 +728,26 @@ int load_log_level_ex(const char *conf_filename);
/** set global log level /** set global log level
* parameters: * parameters:
* pLogLevel: log level string value * pLogLevel: the log level string value
* return: none * return: none
*/ */
void set_log_level(char *pLogLevel); void set_log_level(char *pLogLevel);
/** get log level by caption
* parameters:
* pLogLevel: the log level string value
* default_value: the default log level
* return: the log level integer value
*/
int get_log_level(char *pLogLevel, const int default_value);
/** get log level caption
* parameters:
* log_level: the log level integer value
* return: the log level caption
*/
const char *get_log_level_caption(const int log_level);
/** load allow hosts from config context /** load allow hosts from config context
* parameters: * parameters:
* pIniContext: the config context * pIniContext: the config context
@ -547,7 +756,7 @@ void set_log_level(char *pLogLevel);
* return: error no , 0 success, != 0 fail * return: error no , 0 success, != 0 fail
*/ */
int load_allow_hosts(IniContext *pIniContext, \ int load_allow_hosts(IniContext *pIniContext, \
in_addr_t **allow_ip_addrs, int *allow_ip_count); in_addr_64_t **allow_ip_addrs, int *allow_ip_count);
/** get time item from config context /** get time item from config context
@ -757,7 +966,7 @@ int fd_set_cloexec(int fd);
*/ */
int set_run_by(const char *group_name, const char *username); int set_run_by(const char *group_name, const char *username);
/** compare ip address, type is (in_addr_t *) /** compare ip address, type is (in_addr_64_t *)
* parameters: * parameters:
* p1: the first ip address * p1: the first ip address
* p2: the second ip address * p2: the second ip address
@ -765,6 +974,8 @@ int set_run_by(const char *group_name, const char *username);
*/ */
int cmp_by_ip_addr_t(const void *p1, const void *p2); int cmp_by_ip_addr_t(const void *p1, const void *p2);
int fc_compare_int64_ptr(const int64_t *n1, const int64_t *n2);
/** parse bytes /** parse bytes
* parameters: * parameters:
* pStr: the string to parse * pStr: the string to parse
@ -810,6 +1021,15 @@ double get_line_distance_km(const double lat1, const double lon1,
*/ */
bool is_private_ip(const char* ip); bool is_private_ip(const char* ip);
/** 从字符串中解析IP地址和端口号
* parameters:
* src: the source string, will be modified by this function
* parts: store split strings
* return: string array / column count
*/
int parseAddress(char *src, char *parts[2]);
/** get current time in ns /** get current time in ns
* return: current time * return: current time
*/ */
@ -890,7 +1110,7 @@ bool isLeadingSpacesLine(const char *content, const char *current);
*/ */
bool isTrailingSpacesLine(const char *tail, const char *end); bool isTrailingSpacesLine(const char *tail, const char *end);
/** write to file /** safe write wrapper
* parameters: * parameters:
* fd: the fd to write * fd: the fd to write
* buf: the buffer * buf: the buffer
@ -899,6 +1119,15 @@ bool isTrailingSpacesLine(const char *tail, const char *end);
*/ */
ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte); ssize_t fc_safe_write(int fd, const char *buf, const size_t nbyte);
/** safe writev wrapper
* parameters:
* fd: the fd to write
* iov: the iov array
* iovcnt: the iov count
* return: written bytes for success, -1 when fail
*/
ssize_t fc_safe_writev(int fd, const struct iovec *iov, int iovcnt);
/** lock and write to file /** lock and write to file
* parameters: * parameters:
* fd: the fd to write * fd: the fd to write
@ -962,6 +1191,8 @@ static inline const char *long_to_comma_str(const int64_t n, char *buff)
return long2str(n, buff, true); return long2str(n, buff, true);
} }
const char *bytes_to_human_str(const int64_t bytes, char *buff);
/** if the string starts with the needle string /** if the string starts with the needle string
* parameters: * parameters:
* str: the string to detect * str: the string to detect
@ -1019,19 +1250,19 @@ char *format_http_date(time_t t, BufferInfo *buffer);
* size: the max size of full_filename * size: the max size of full_filename
* return: length of the resolved full path * return: length of the resolved full path
*/ */
int normalize_path(const char *from, const char *filename, int normalize_path(const string_t *from, const string_t *filename,
char *full_filename, const int size); char *full_filename, const int size);
/** return absolute uri (the second parameter) static inline int normalize_path1(const char *from, const char *filename,
* parameters: char *full_filename, const int size)
* from: the input uri to get base path {
* uri: the uri to resolve string_t from_string;
* dest: store the resolved absolute uri string_t filename_string;
* size: the max size of dest
* return: length of the resolved uri FC_SET_STRING(from_string, (char *)from);
*/ FC_SET_STRING(filename_string, (char *)filename);
int normalize_uri(const string_t *from, const char *uri, return normalize_path(&from_string, &filename_string, full_filename, size);
char *dest, const int size); }
/** return full path for the filename (the second parameter) /** return full path for the filename (the second parameter)
* parameters: * parameters:
@ -1044,9 +1275,204 @@ int normalize_uri(const string_t *from, const char *uri,
* NORMALIZE_FLAGS_URL_APPEND_PARAMS: append params of from * NORMALIZE_FLAGS_URL_APPEND_PARAMS: append params of from
* return: length of the resolved full path * return: length of the resolved full path
*/ */
int normalize_path_ex(const char *from, const char *filename, int normalize_path_ex(const string_t *from, const string_t *filename,
char *full_filename, const int size, const int flags); char *full_filename, const int size, const int flags);
static inline int resolve_path(const char *from, const char *filename,
char *full_filename, const int size)
{
string_t from_string;
string_t filename_string;
FC_SET_STRING(from_string, (char *)from);
FC_SET_STRING(filename_string, (char *)filename);
return normalize_path_ex(&from_string, &filename_string, full_filename,
size, NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS);
}
static inline int fc_combine_two_strings_ex(
const char *first_str, const int first_len,
const char *second_str, const int second_len,
const char seperator, char *combined_str, const int size)
{
char *p;
if (first_len + 1 + second_len >= size) {
return snprintf(combined_str, size, "%s%c%s",
first_str, seperator, second_str);
}
memcpy(combined_str, first_str, first_len);
p = combined_str + first_len;
if (seperator != '\0') {
*p++ = seperator;
}
memcpy(p, second_str, second_len);
p += second_len;
*p = '\0';
return p - combined_str;
}
#define fc_combine_two_strings_s(first, second, seperator, combined, size) \
fc_combine_two_strings_ex(first, strlen(first), second, strlen(second), \
seperator, combined, size)
#define fc_combine_two_strings(first, second, seperator, combined) \
fc_combine_two_strings_s(first, second, seperator, \
combined, sizeof(combined))
#define fc_concat_two_strings(first, second, combined) \
fc_combine_two_strings(first, second, '\0', combined)
static inline int fc_get_full_filename_ex(
const char *base_path_str, const int base_path_len,
const char *filename_str, const int filename_len,
char *full_filename, const int size)
{
const char seperator = '/';
return fc_combine_two_strings_ex(base_path_str, base_path_len,
filename_str, filename_len, seperator, full_filename, size);
}
#define fc_get_full_filename(base_path_str, base_path_len, \
filename_str, filename_len, full_filename) \
fc_get_full_filename_ex(base_path_str, base_path_len, \
filename_str, filename_len, full_filename, sizeof(full_filename))
#define fc_combine_full_filename(base_path, filename, full_filename) \
fc_get_full_filename(base_path, strlen(base_path), \
filename, strlen(filename), full_filename)
#define fc_get_full_filepath_ex(base_path_str, base_path_len, \
filepath_str, filepath_len, full_filename, size) \
fc_get_full_filename_ex(base_path_str, base_path_len, \
filepath_str, filepath_len, full_filename, size)
#define fc_get_full_filepath(base_path_str, base_path_len, \
filepath_str, filepath_len, full_filename) \
fc_get_full_filename(base_path_str, base_path_len, \
filepath_str, filepath_len, full_filename)
#define fc_combine_full_filepath(base_path, filepath, full_filename) \
fc_combine_full_filename(base_path, filepath, full_filename)
static inline int fc_get_hex_subdir_filepath(const char *base_path,
const int base_len, const int subdir_index, char *file_path)
{
const int padding_len = 2;
char *p;
memcpy(file_path, base_path, base_len);
p = file_path + base_len;
*p++ = '/';
if (subdir_index <= UINT8_MAX) {
*p++ = g_upper_hex_chars[(subdir_index >> 4) & 0x0F];
*p++ = g_upper_hex_chars[subdir_index & 0x0F];
*p = '\0';
} else {
if (subdir_index <= UINT16_MAX) {
p += short2HEX(subdir_index, p, padding_len);
} else {
p += int2HEX(subdir_index, p, padding_len);
}
}
return p - file_path;
}
static inline int fc_get_two_subdirs_full_filepath_ex(
const char *base_path, const int base_len,
const char *subdir_str1, const int subdir_len1,
const char *subdir_str2, const int subdir_len2,
char *file_path, const int size)
{
char *p;
if (base_len + 1 + subdir_len1 + 1 + subdir_len2 >= size) {
return snprintf(file_path, size, "%s/%s/%s",
base_path, subdir_str1, subdir_str2);
}
memcpy(file_path, base_path, base_len);
p = file_path + base_len;
*p++ = '/';
memcpy(p, subdir_str1, subdir_len1);
p += subdir_len1;
*p++ = '/';
memcpy(p, subdir_str2, subdir_len2);
p += subdir_len2;
*p = '\0';
return p - file_path;
}
#define fc_get_two_subdirs_full_filepath(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, file_path) \
fc_get_two_subdirs_full_filepath_ex(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
file_path, sizeof(file_path))
#define fc_get_one_subdir_full_filename_ex(base_path, base_len, subdir_str, \
subdir_len, filename_str, filename_len, full_filename, size) \
fc_get_two_subdirs_full_filepath_ex(base_path, base_len, \
subdir_str, subdir_len, filename_str, filename_len, \
full_filename, size)
#define fc_get_one_subdir_full_filename(base_path, base_len, subdir_str, \
subdir_len, filename_str, filename_len, full_filename) \
fc_get_one_subdir_full_filename_ex(base_path, base_len, \
subdir_str, subdir_len, filename_str, filename_len, \
full_filename, sizeof(full_filename))
static inline int fc_get_three_subdirs_full_filepath_ex(
const char *base_path, const int base_len,
const char *subdir_str1, const int subdir_len1,
const char *subdir_str2, const int subdir_len2,
const char *subdir_str3, const int subdir_len3,
char *file_path, const int size)
{
char *p;
if (base_len + 1 + subdir_len1 + 1 + subdir_len2 + subdir_len3 >= size) {
return snprintf(file_path, size, "%s/%s/%s/%s",
base_path, subdir_str1, subdir_str2, subdir_str3);
}
memcpy(file_path, base_path, base_len);
p = file_path + base_len;
*p++ = '/';
memcpy(p, subdir_str1, subdir_len1);
p += subdir_len1;
*p++ = '/';
memcpy(p, subdir_str2, subdir_len2);
p += subdir_len2;
*p++ = '/';
memcpy(p, subdir_str3, subdir_len3);
p += subdir_len3;
*p = '\0';
return p - file_path;
}
#define fc_get_three_subdirs_full_filepath(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
subdir_str3, subdir_len3, file_path) \
fc_get_three_subdirs_full_filepath_ex(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
subdir_str3, subdir_len3, file_path, sizeof(file_path))
#define fc_get_two_subdirs_full_filename_ex(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
filename_str, filename_len, full_filename, size) \
fc_get_three_subdirs_full_filepath_ex(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
filename_str, filename_len, full_filename, size)
#define fc_get_two_subdirs_full_filename(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
filename_str, filename_len, full_filename) \
fc_get_two_subdirs_full_filename_ex(base_path, base_len, \
subdir_str1, subdir_len1, subdir_str2, subdir_len2, \
filename_str, filename_len, full_filename, sizeof(full_filename))
/** get gzip command full filename /** get gzip command full filename
* return: the gzip command full filename * return: the gzip command full filename
@ -1177,12 +1603,82 @@ bool fc_path_contains(const string_t *path, const string_t *needle,
/** itoa output as decimal number /** itoa output as decimal number
* parameters: * parameters:
* n: the number to convert * n: the integer number to convert
* buff: store the converted string * buff: store the converted string, NOT null-terminated
* return: string length * return: converted string length
*/ */
int fc_itoa(int64_t n, char *buff); int fc_itoa(int64_t n, char *buff);
/** ftoa output as decimal number
* parameters:
* d: the double number to convert
* scale: number of decimal places (round off)
* buff: store the converted string, NOT null-terminated
* return: converted string length
*/
int fc_ftoa(double d, const int scale, char *buff);
/** output as decimal number
* parameters:
* n: the integer number to convert
* buff: store the converted string, null-terminated
* padding_len: padding length (padding with charactor '0')
* return: converted string length
*/
static inline int fc_ltostr_ex(int64_t n, char *buff, const int padding_len)
{
int len;
int fill_len;
len = fc_itoa(n, buff);
*(buff + len) = '\0';
if (padding_len <= len) {
return len;
}
#if defined(OS_LINUX) && defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
fill_len = padding_len - len;
memmove(buff + fill_len, buff, len + 1);
memset(buff, '0', fill_len);
#if defined(OS_LINUX) && defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
return padding_len;
}
static inline int fc_ltostr(int64_t n, char *buff)
{
int len;
len = fc_itoa(n, buff);
*(buff + len) = '\0';
return len;
}
static inline size_t fc_strlcpy(char *dest, const char *src, const size_t size)
{
size_t len;
len = strlen(src);
if (len < size) {
memcpy(dest, src, len + 1);
} else {
len = size - 1;
memcpy(dest, src, len);
*(dest + len) = '\0';
}
return len;
}
#define fc_safe_strcpy(dest, src) fc_strlcpy(dest, src, sizeof(dest))
/** sleep in microseconds /** sleep in microseconds
* parameters: * parameters:
* microseconds: microseconds to sleep * microseconds: microseconds to sleep

View File

@ -33,12 +33,6 @@
#define SUB_NET_TYPE_INNER_172_STR3 "inner172" #define SUB_NET_TYPE_INNER_172_STR3 "inner172"
#define SUB_NET_TYPE_INNER_192_STR3 "inner192" #define SUB_NET_TYPE_INNER_192_STR3 "inner192"
#if defined(IOV_MAX) && IOV_MAX > 256
#define FC_IOV_BATCH_SIZE 256
#else
#define FC_IOV_BATCH_SIZE IOV_MAX
#endif
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
#include <ifaddrs.h> #include <ifaddrs.h>
#endif #endif
@ -808,27 +802,46 @@ int tcpwritev_nb(int sock, const struct iovec *iov,
return 0; return 0;
} }
int setsockaddrbyip(const char *ip, const uint16_t port, sockaddr_convert_t *convert) int setsockaddrbyip(const char *ip, const uint16_t port,
sockaddr_convert_t *convert)
{ {
int af; int af;
int result;
void *dest; void *dest;
if (is_ipv6_addr(ip)) if (is_ipv6_addr(ip))
{ {
convert->len = sizeof(convert->sa.addr6); convert->len = sizeof(convert->sa.addr6);
dest = &convert->sa.addr6.sin6_addr; if (strchr(ip, '%') != NULL)
{
struct addrinfo hints, *res;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET6;
if ((result=getaddrinfo(ip, NULL, &hints, &res)) != 0)
{
return result;
}
convert->sa.addr6 = *((struct sockaddr_in6 *)res->ai_addr);
convert->sa.addr6.sin6_port = htons(port);
freeaddrinfo(res);
return 0;
}
af = AF_INET6; af = AF_INET6;
convert->sa.addr6.sin6_family = PF_INET6; dest = &convert->sa.addr6.sin6_addr;
convert->sa.addr6.sin6_family = AF_INET6;
convert->sa.addr6.sin6_port = htons(port); convert->sa.addr6.sin6_port = htons(port);
convert->sa.addr6.sin6_flowinfo = 0;
convert->sa.addr6.sin6_scope_id = 0;
} }
else //ipv4 else //ipv4
{ {
af = AF_INET;
convert->len = sizeof(convert->sa.addr4); convert->len = sizeof(convert->sa.addr4);
dest = &convert->sa.addr4.sin_addr; dest = &convert->sa.addr4.sin_addr;
convert->sa.addr4.sin_family = AF_INET;
af = AF_INET;
convert->sa.addr4.sin_family = PF_INET;
convert->sa.addr4.sin_port = htons(port); convert->sa.addr4.sin_port = htons(port);
} }
@ -860,8 +873,8 @@ int connectserverbyip(int sock, const char *server_ip, const uint16_t server_por
return 0; return 0;
} }
int connectserverbyip_nb_ex(int sock, const char *server_ip, \ int connectserverbyip_nb_ex(int sock, const char *server_ip,
const uint16_t server_port, const int timeout, \ const uint16_t server_port, const int timeout,
const bool auto_detect) const bool auto_detect)
{ {
int result; int result;
@ -928,7 +941,6 @@ int connectserverbyip_nb_ex(int sock, const char *server_ip, \
break; break;
} }
#ifdef USE_SELECT #ifdef USE_SELECT
FD_ZERO(&rset); FD_ZERO(&rset);
FD_ZERO(&wset); FD_ZERO(&wset);
@ -1044,6 +1056,7 @@ int socketClientEx2(int af, const char *server_ip,
{ {
int sock; int sock;
bool auto_detect; bool auto_detect;
char formatted_ip[FORMATTED_IP_SIZE];
sock = socketCreateEx2(af, server_ip, sock = socketCreateEx2(af, server_ip,
flags, bind_ipaddr, err_no); flags, bind_ipaddr, err_no);
@ -1057,10 +1070,11 @@ int socketClientEx2(int af, const char *server_ip,
server_port, timeout, auto_detect); server_port, timeout, auto_detect);
if (*err_no != 0) if (*err_no != 0)
{ {
format_ip_address(server_ip, formatted_ip);
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"connect to %s:%u fail, " "connect to %s:%u fail, "
"errno: %d, error info: %s", "errno: %d, error info: %s",
__LINE__, server_ip, server_port, __LINE__, formatted_ip, server_port,
*err_no, STRERROR(*err_no)); *err_no, STRERROR(*err_no));
close(sock); close(sock);
return -4; return -4;
@ -1072,13 +1086,12 @@ int socketClientEx2(int af, const char *server_ip,
const char *fc_inet_ntop(const struct sockaddr *addr, const char *fc_inet_ntop(const struct sockaddr *addr,
char *buff, const int bufferSize) char *buff, const int bufferSize)
{ {
void *sin_addr; int len;
const char *output;
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
sin_addr = &((struct sockaddr_in *)addr)->sin_addr; len = sizeof(struct sockaddr_in);
} else if (addr->sa_family == AF_INET6) { } else if (addr->sa_family == AF_INET6) {
sin_addr = &((struct sockaddr_in6 *)addr)->sin6_addr; len = sizeof(struct sockaddr_in6);
} else { } else {
*buff = '\0'; *buff = '\0';
logWarning("file: "__FILE__", line: %d, " logWarning("file: "__FILE__", line: %d, "
@ -1086,41 +1099,46 @@ const char *fc_inet_ntop(const struct sockaddr *addr,
return NULL; return NULL;
} }
if ((output=inet_ntop(addr->sa_family, sin_addr, buff, bufferSize)) == NULL) if (getnameinfo(addr, len, buff, bufferSize, NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV) != 0)
{ {
*buff = '\0'; *buff = '\0';
logWarning("file: "__FILE__", line: %d, " return NULL;
"call inet_ntop fail, "
"errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno));
} }
return buff;
return output;
} }
in_addr_t getIpaddr(getnamefunc getname, int sock, \ in_addr_64_t getIpaddr(getnamefunc getname, int sock,
char *buff, const int bufferSize) char *buff, const int bufferSize)
{ {
sockaddr_convert_t convert; sockaddr_convert_t convert;
memset(&convert, 0, sizeof(convert)); memset(&convert, 0, sizeof(convert));
convert.len = sizeof(convert.sa); convert.len = sizeof(convert.sa);
if (getname(sock, &convert.sa.addr, &convert.len) != 0) if (getname(sock, &convert.sa.addr, &convert.len) != 0)
{ {
*buff = '\0'; *buff = '\0';
return INADDR_NONE; return INADDR_NONE;
} }
if (convert.len > 0)
{
fc_inet_ntop(&convert.sa.addr, buff, bufferSize);
}
else
{
*buff = '\0';
}
return convert.sa.addr4.sin_addr.s_addr; //DO NOT support IPv6 if (convert.len > 0)
{
if (getnameinfo(&convert.sa.addr, convert.len, buff, bufferSize,
NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
{
*buff = '\0';
}
}
else
{
*buff = '\0';
}
if (convert.sa.addr.sa_family == AF_INET) {
return convert.sa.addr4.sin_addr.s_addr;
} else {
return *((in_addr_64_t *)((char *)&convert.sa.addr6.sin6_addr + 8));
}
} }
int getIpAndPort(getnamefunc getname, int sock, int getIpAndPort(getnamefunc getname, int sock,
@ -1138,7 +1156,11 @@ int getIpAndPort(getnamefunc getname, int sock,
if (convert.len > 0) if (convert.len > 0)
{ {
fc_inet_ntop(&convert.sa.addr, buff, bufferSize); if (getnameinfo(&convert.sa.addr, convert.len, buff, bufferSize,
NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0)
{
*buff = '\0';
}
} }
else else
{ {
@ -1172,59 +1194,109 @@ char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize)
} }
else else
{ {
snprintf(buff, bufferSize, "%s", ent->h_name); fc_strlcpy(buff, ent->h_name, bufferSize);
} }
return buff; return buff;
} }
in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize) in_addr_64_t getIpaddrByNameEx(const char *name, char *buff,
const int bufferSize, uint8_t *af)
{ {
struct in_addr ip_addr; struct addrinfo hints, *res, *p;
struct hostent *ent; struct in_addr addr4;
in_addr_t **addr_list; struct in6_addr addr6;
in_addr_64_t ip_addr;
if ((*name >= '0' && *name <= '9') && if (strchr(name, ':') != NULL) //IPv6
inet_pton(AF_INET, name, &ip_addr) == 1) {
{ if (strchr(name, '%') == NULL &&
if (buff != NULL) inet_pton(AF_INET6, name, &addr6) == 1)
{ {
snprintf(buff, bufferSize, "%s", name); if (buff != NULL)
} {
return ip_addr.s_addr; if (inet_ntop(AF_INET6, &addr6, buff, bufferSize) == NULL)
} {
*buff = '\0';
}
}
*af = AF_INET6;
return *((in_addr_64_t *)((char *)&addr6 + 8));
}
}
else if ((*name >= '0' && *name <= '9') &&
inet_pton(AF_INET, name, &addr4) == 1)
{
if (buff != NULL)
{
if (inet_ntop(AF_INET, &addr4, buff, bufferSize) == NULL)
{
*buff = '\0';
}
}
*af = AF_INET;
return addr4.s_addr;
}
ent = gethostbyname(name); *af = AF_UNSPEC;
if (ent == NULL) memset(&hints, 0, sizeof hints);
{ hints.ai_family = AF_UNSPEC;
return INADDR_NONE; if (getaddrinfo(name, NULL, &hints, &res) != 0)
} {
return INADDR_NONE;
}
addr_list = (in_addr_t **)ent->h_addr_list; ip_addr = INADDR_NONE;
if (addr_list[0] == NULL) for (p = res; p != NULL; p = p->ai_next)
{ {
return INADDR_NONE; if (p->ai_family == AF_INET) //IPv4 address
} {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
if (buff != NULL)
{
if (inet_ntop(AF_INET, &(ipv4->sin_addr), buff, bufferSize) == NULL)
{
*buff = '\0';
}
}
memset(&ip_addr, 0, sizeof(ip_addr)); *af = p->ai_family;
ip_addr.s_addr = *(addr_list[0]); ip_addr = ipv4->sin_addr.s_addr;
if (buff != NULL) break;
{ }
if (inet_ntop(AF_INET, &ip_addr, buff, bufferSize) == NULL) else if (p->ai_family == AF_INET6) //IPv6 address
{ {
*buff = '\0'; struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
} if (buff != NULL)
} {
if (getnameinfo((struct sockaddr *)ipv6, sizeof(*ipv6),
buff, bufferSize, NULL, 0, NI_NUMERICHOST |
NI_NUMERICSERV) != 0)
{
if (inet_ntop(AF_INET6, &(ipv6->sin6_addr),
buff, bufferSize) == NULL)
{
*buff = '\0';
}
}
}
return ip_addr.s_addr; *af = p->ai_family;
ip_addr = *((in_addr_64_t *)((char *)&ipv6->sin6_addr + 8));
continue;
}
}
freeaddrinfo(res);
return ip_addr;
} }
int getIpaddrsByName(const char *name, int getIpaddrsByName(const char *name,
ip_addr_t *ip_addr_arr, const int ip_addr_arr_size) ip_addr_t *ip_addr_arr, const int ip_addr_arr_size)
{ {
int result;
int ip_count; int ip_count;
struct sockaddr_in *addr; int len;
struct sockaddr_in6 *addr6;
struct addrinfo hints, *res, *res0; struct addrinfo hints, *res, *res0;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -1236,11 +1308,20 @@ int getIpaddrsByName(const char *name,
} }
for (ip_count = 0, res = res0; res; res = res->ai_next) { for (ip_count = 0, res = res0; res; res = res->ai_next) {
if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { if (res->ai_family == AF_INET)
logError("file: "__FILE__", line: %d, " \ {
"unsupported family %d, " \ len = sizeof(struct sockaddr_in);
"only suppport AF_INET6 and AF_INET", \ }
__LINE__, res->ai_family); else if (res->ai_family == AF_INET6)
{
len = sizeof(struct sockaddr_in6);
}
else
{
logError("file: "__FILE__", line: %d, "
"unsupported family %d, "
"only suppport AF_INET and AF_INET6",
__LINE__, res->ai_family);
continue; continue;
} }
@ -1248,29 +1329,17 @@ int getIpaddrsByName(const char *name,
break; break;
} }
if (res->ai_family == AF_INET6) { if ((result=getnameinfo(res->ai_addr, len, ip_addr_arr[ip_count].
addr6 = (struct sockaddr_in6 *) res->ai_addr; ip_addr, IP_ADDRESS_SIZE, NULL, 0,
if (inet_ntop(res->ai_family, &addr6->sin6_addr, NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
ip_addr_arr[ip_count].ip_addr, INET6_ADDRSTRLEN) == NULL) {
{ logError("file: "__FILE__", line: %d, "
logError("file: "__FILE__", line: %d, " \ "getnameinfo fail, errno: %d, error info: %s",
"inet_ntop failed: %d, %s", \ __LINE__, result, gai_strerror(result));
__LINE__, errno, strerror(errno)); continue;
continue;
}
} else {
addr = (struct sockaddr_in *) res->ai_addr;
if (inet_ntop(res->ai_family, &addr->sin_addr,
ip_addr_arr[ip_count].ip_addr, INET6_ADDRSTRLEN) == NULL)
{
logError("file: "__FILE__", line: %d, " \
"inet_ntop failed: %d, %s", \
__LINE__, errno, strerror(errno));
continue;
}
} }
ip_addr_arr[ip_count++].socket_domain = res->ai_family; ip_addr_arr[ip_count++].af = res->ai_family;
} }
freeaddrinfo(res0); freeaddrinfo(res0);
@ -1332,13 +1401,12 @@ int nbaccept(int sock, const int timeout, int *err_no)
int socketBind2(int af, int sock, const char *bind_ipaddr, const int port) int socketBind2(int af, int sock, const char *bind_ipaddr, const int port)
{ {
sockaddr_convert_t convert; sockaddr_convert_t convert;
char bind_ip_prompt[256];
int result; int result;
memset(&convert, 0, sizeof(convert));
convert.sa.addr.sa_family = af; convert.sa.addr.sa_family = af;
if (bind_ipaddr == NULL || *bind_ipaddr == '\0') if (bind_ipaddr == NULL || *bind_ipaddr == '\0')
{ {
*bind_ip_prompt = '\0';
if (af == AF_INET) if (af == AF_INET)
{ {
convert.len = sizeof(convert.sa.addr4); convert.len = sizeof(convert.sa.addr4);
@ -1358,11 +1426,15 @@ int socketBind2(int af, int sock, const char *bind_ipaddr, const int port)
{ {
return result; return result;
} }
sprintf(bind_ip_prompt, "bind ip %s, ", bind_ipaddr);
} }
if (bind(sock, &convert.sa.addr, convert.len) < 0) if (bind(sock, &convert.sa.addr, convert.len) < 0) {
{ char bind_ip_prompt[256];
if (bind_ipaddr == NULL || *bind_ipaddr == '\0') {
*bind_ip_prompt = '\0';
} else {
sprintf(bind_ip_prompt, "bind ip %s, ", bind_ipaddr);
}
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"%sbind port %d failed, " "%sbind port %d failed, "
"errno: %d, error info: %s.", "errno: %d, error info: %s.",
@ -1403,16 +1475,32 @@ int socketServer2(int af, const char *bind_ipaddr, const int port, int *err_no)
SET_SOCKOPT_NOSIGPIPE(sock); SET_SOCKOPT_NOSIGPIPE(sock);
result = 1; result = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &result, sizeof(int))<0) if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
&result, sizeof(int)) < 0)
{ {
*err_no = errno != 0 ? errno : ENOMEM; *err_no = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"setsockopt failed, errno: %d, error info: %s", \ "setsockopt failed, errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno)); __LINE__, errno, STRERROR(errno));
close(sock); close(sock);
return -2; return -2;
} }
if (af == AF_INET6 && (bind_ipaddr == NULL || *bind_ipaddr == '\0'))
{
result = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&result, sizeof(result)) < 0)
{
*err_no = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, "
"setsockopt failed, errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno));
close(sock);
return -2;
}
}
if ((*err_no=socketBind2(af, sock, bind_ipaddr, port)) != 0) if ((*err_no=socketBind2(af, sock, bind_ipaddr, port)) != 0)
{ {
close(sock); close(sock);
@ -2102,10 +2190,10 @@ int tcpprintkeepalive(int fd)
return errno != 0 ? errno : EINVAL; return errno != 0 ? errno : EINVAL;
} }
logInfo("keepAlive=%d, keepIdle=%d, keepInterval=%d, keepCount=%d", logDebug("keepAlive=%d, keepIdle=%d, keepInterval=%d, keepCount=%d",
keepAlive, keepIdle, keepInterval, keepCount); keepAlive, keepIdle, keepInterval, keepCount);
#else #else
logInfo("keepAlive=%d", keepAlive); logDebug("keepAlive=%d", keepAlive);
#endif #endif
return 0; return 0;
@ -2163,6 +2251,8 @@ int tcpsetnodelay(int fd, const int timeout)
int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
const int max_count, int *count) const int max_count, int *count)
{ {
int result;
int len;
struct ifaddrs *ifc; struct ifaddrs *ifc;
struct ifaddrs *ifc1; struct ifaddrs *ifc1;
@ -2179,32 +2269,47 @@ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
ifc1 = ifc; ifc1 = ifc;
while (NULL != ifc) while (NULL != ifc)
{ {
struct sockaddr *s; if (NULL == ifc->ifa_addr ) {
s = ifc->ifa_addr; ifc = ifc->ifa_next;
if (NULL != s && AF_INET == s->sa_family) continue;
{ }
if (max_count <= *count)
if (max_count <= *count)
{
logError("file: "__FILE__", line: %d, "\
"max_count: %d < iterface count: %d", \
__LINE__, max_count, *count);
freeifaddrs(ifc1);
return ENOSPC;
}
do {
if (ifc->ifa_addr->sa_family == AF_INET)
{ {
logError("file: "__FILE__", line: %d, "\ len = sizeof(struct sockaddr_in);
"max_count: %d < iterface count: %d", \ }
__LINE__, max_count, *count); else if (ifc->ifa_addr->sa_family == AF_INET6)
freeifaddrs(ifc1); {
return ENOSPC; len = sizeof(struct sockaddr_in6);
}
else
{
break;
} }
if (inet_ntop(AF_INET, &((struct sockaddr_in *)s)-> \ if ((result=getnameinfo(ifc->ifa_addr, len, ip_addrs[*count],
sin_addr, ip_addrs[*count], IP_ADDRESS_SIZE) != NULL) IP_ADDRESS_SIZE, NULL, 0, NI_NUMERICHOST |
NI_NUMERICSERV)) == 0)
{ {
(*count)++; (*count)++;
} }
else else
{ {
logWarning("file: "__FILE__", line: %d, " \ logWarning("file: "__FILE__", line: %d, "
"call inet_ntop fail, " \ "getnameinfo fail, errno: %d, error info: %s",
"errno: %d, error info: %s", \ __LINE__, result, gai_strerror(result));
__LINE__, errno, STRERROR(errno));
} }
} } while (0);
ifc = ifc->ifa_next; ifc = ifc->ifa_next;
} }
@ -2218,7 +2323,8 @@ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
const int max_count, int *count) const int max_count, int *count)
{ {
int s; int sock;
int len;
struct ifconf ifconf; struct ifconf ifconf;
struct ifreq ifr[32]; struct ifreq ifr[32];
struct ifreq *ifrp; struct ifreq *ifrp;
@ -2226,60 +2332,60 @@ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
int result; int result;
*count = 0; *count = 0;
s = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) if (sock < 0)
{ {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"socket create fail, errno: %d, error info: %s", \ "socket create fail, errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno)); __LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EMFILE; return errno != 0 ? errno : EMFILE;
} }
ifconf.ifc_buf = (char *) ifr; ifconf.ifc_buf = (char *) ifr;
ifconf.ifc_len = sizeof(ifr); ifconf.ifc_len = sizeof(ifr);
if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
{ {
result = errno != 0 ? errno : EMFILE; result = errno != 0 ? errno : EMFILE;
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"call ioctl fail, errno: %d, error info: %s", \ "call ioctl fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result)); __LINE__, result, STRERROR(result));
close(s); close(sock);
return result; return result;
} }
ifrp = ifconf.ifc_req; ifrp = ifconf.ifc_req;
p_end = (char *)ifr + ifconf.ifc_len; p_end = (char *)ifr + ifconf.ifc_len;
while ((char *)ifrp < p_end) while ((char *)ifrp < p_end)
{ {
struct sockaddr *sa = &ifrp->ifr_addr; struct sockaddr *sa = &ifrp->ifr_addr;
struct sockaddr_in *s_in;
if (*count >= max_count) if (*count >= max_count)
{
logError("file: "__FILE__", line: %d, " \
"max_count: %d < iterface count: %d", \
__LINE__, max_count, *count);
close(s);
return ENOSPC;
}
s_in = (struct sockaddr_in *) &ifrp->ifr_addr;
if (sa->sa_family == AF_INET)
{ {
if (!inet_ntop(AF_INET, &s_in->sin_addr, \ logError("file: "__FILE__", line: %d, "
ip_addrs[*count], IP_ADDRESS_SIZE)) "max_count: %d < iterface count: %d",
{ __LINE__, max_count, *count);
result = errno != 0 ? errno : EMFILE; close(sock);
logError("file: "__FILE__", line: %d, " \ return ENOSPC;
"call inet_ntop fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
close(s);
return result;
}
(*count)++;
} }
if (sa->sa_family == AF_INET6)
{
len = sizeof(struct sockaddr_in6);
} else
{
len = sizeof(struct sockaddr_in);
}
if ((result=getnameinfo(sa, len, ip_addrs[*count], IP_ADDRESS_SIZE,
NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
{
logError("file: "__FILE__", line: %d, "
"call getnameinfo fail, errno: %d, error info: %s",
__LINE__, result, gai_strerror(result));
close(sock);
return result;
}
(*count)++;
#ifdef OS_FREEBSD #ifdef OS_FREEBSD
ifrp = (struct ifreq*)((caddr_t)&ifrp->ifr_addr + sa->sa_len); ifrp = (struct ifreq*)((caddr_t)&ifrp->ifr_addr + sa->sa_len);
#else #else
@ -2287,7 +2393,7 @@ int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
#endif #endif
} }
close(s); close(sock);
return *count > 0 ? 0 : ENOENT; return *count > 0 ? 0 : ENOENT;
} }
@ -2303,9 +2409,10 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
int true_count; int true_count;
int i; int i;
int k; int k;
int len;
int sock; int sock;
struct ifreq req; struct ifreq req;
struct sockaddr_in *addr; struct sockaddr *addr;
int ret; int ret;
*count = 0; *count = 0;
@ -2365,16 +2472,24 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
break; break;
} }
addr = (struct sockaddr_in*)&req.ifr_addr; addr = &req.ifr_addr;
if (inet_ntop(AF_INET, &addr->sin_addr, ip_addrs[*count], \ if (addr->sa_family == AF_INET6)
IP_ADDRESS_SIZE) != NULL) {
{ len = sizeof(struct sockaddr_in6);
}
else
{
len = sizeof(struct sockaddr_in);
}
if (getnameinfo(addr, len, ip_addrs[*count], IP_ADDRESS_SIZE,
NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) == 0)
{
(*count)++; (*count)++;
if (*count >= max_count) if (*count >= max_count)
{ {
break; break;
} }
} }
} }
} }
@ -2393,7 +2508,7 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
return errno != 0 ? errno : EFAULT; return errno != 0 ? errno : EFAULT;
} }
ent = gethostbyname(hostname); ent = gethostbyname(hostname);
if (ent == NULL) if (ent == NULL)
{ {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, " \
@ -2411,8 +2526,8 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
break; break;
} }
if (inet_ntop(ent->h_addrtype, ent->h_addr_list[k], \ if (inet_ntop(ent->h_addrtype, ent->h_addr_list[k],
ip_addrs[*count], IP_ADDRESS_SIZE) != NULL) ip_addrs[*count], IP_ADDRESS_SIZE) != NULL)
{ {
(*count)++; (*count)++;
} }
@ -2425,34 +2540,64 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
static inline void formatifmac(char *buff, const int buff_size, unsigned char *hwaddr) static inline int formatifmac(char *buff, const int buff_size,
unsigned char *hwaddr, const int addr_size)
{ {
int i; int len;
for (i=0; i<6; i++) unsigned char *ptr;
unsigned char *end;
char *dest;
for (end=hwaddr+(addr_size-1); end>=hwaddr; end--)
{ {
if (hwaddr[i] != 0) if (*end != 0)
{ {
break; break;
} }
} }
++end;
if (i == 6) len = end - hwaddr;
if (len == 0)
{ {
*buff = '\0'; *buff = '\0';
return; return 0;
} }
snprintf(buff, buff_size, if (len < 6)
"%02X:%02X:%02X:%02X:%02X:%02X", {
*hwaddr, *(hwaddr+1), *(hwaddr+2), len = 6;
*(hwaddr+3), *(hwaddr+4), *(hwaddr+5)); end = hwaddr + len;
}
if (len * 3 > buff_size)
{
logError("file: "__FILE__", line: %d, "
"buff size: %d is too small, expect size: %d",
__LINE__, buff_size, len * 3);
*buff = '\0';
return 0;
}
dest = buff;
*dest++ = g_lower_hex_chars[*hwaddr >> 4];
*dest++ = g_lower_hex_chars[*hwaddr & 0x0F];
for (ptr=hwaddr+1; ptr<end; ptr++)
{
*dest++ = ':';
*dest++ = g_lower_hex_chars[*ptr >> 4];
*dest++ = g_lower_hex_chars[*ptr & 0x0F];
}
return dest - buff;
} }
#if defined(OS_LINUX) #if defined(OS_LINUX)
static int getifmac(FastIFConfig *config) static int getifmac(FastIFConfig *config)
{ {
int sockfd; int sockfd;
int len;
struct ifreq req[1]; struct ifreq req[1];
char cmd[256];
char output[64];
sockfd = socket(AF_INET, SOCK_DGRAM, 0); sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) if (sockfd < 0)
@ -2476,8 +2621,24 @@ static int getifmac(FastIFConfig *config)
} }
close(sockfd); close(sockfd);
formatifmac(config->mac, sizeof(config->mac),
(unsigned char *)req->ifr_hwaddr.sa_data); len = formatifmac(config->mac, sizeof(config->mac),
(unsigned char *)req->ifr_hwaddr.sa_data,
sizeof(req->ifr_hwaddr.sa_data));
if (len > 6)
{
snprintf(cmd, sizeof(cmd), "ip link | fgrep -A 1 %s: | "
"fgrep link/ | awk '{print $2}'", config->name);
if (getExecResult(cmd, output, sizeof(output)) == 0)
{
fc_trim(output);
if (*output != '\0')
{
fc_safe_strcpy(config->mac, output);
}
}
}
return 0; return 0;
} }
#else //FreeBSD #else //FreeBSD
@ -2489,6 +2650,7 @@ static int getifmac(FastIFConfig *config)
unsigned char *ptr; unsigned char *ptr;
struct if_msghdr *ifm; struct if_msghdr *ifm;
struct sockaddr_dl *sdl; struct sockaddr_dl *sdl;
int size;
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = AF_ROUTE; mib[1] = AF_ROUTE;
@ -2515,10 +2677,12 @@ static int getifmac(FastIFConfig *config)
return errno != 0 ? errno : EPERM; return errno != 0 ? errno : EPERM;
} }
ifm = (struct if_msghdr *)buf; ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1); sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl); ptr = (unsigned char *)LLADDR(sdl);
formatifmac(config->mac, sizeof(config->mac), ptr); size = (unsigned char *)(sdl->sdl_data + sizeof(sdl->sdl_data)) - ptr;
formatifmac(config->mac, sizeof(config->mac), ptr, size);
return 0; return 0;
} }
#endif #endif
@ -2529,8 +2693,9 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count)
struct ifaddrs *ifc1; struct ifaddrs *ifc1;
FastIFConfig *config; FastIFConfig *config;
char *buff; char *buff;
void *sin_addr; int result;
int buff_size; int buff_size;
int len;
int i; int i;
*count = 0; *count = 0;
@ -2573,7 +2738,7 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count)
return ENOSPC; return ENOSPC;
} }
sprintf(config->name, "%s", ifc->ifa_name); strcpy(config->name, ifc->ifa_name);
(*count)++; (*count)++;
} }
@ -2581,21 +2746,21 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count)
{ {
buff = config->ipv4; buff = config->ipv4;
buff_size = sizeof(config->ipv4); buff_size = sizeof(config->ipv4);
sin_addr = &((struct sockaddr_in *)s)->sin_addr; len = sizeof(struct sockaddr_in);
} }
else else
{ {
buff = config->ipv6; buff = config->ipv6;
buff_size = sizeof(config->ipv6); buff_size = sizeof(config->ipv6);
sin_addr = &((struct sockaddr_in6 *)s)->sin6_addr; len = sizeof(struct sockaddr_in6);
} }
if (inet_ntop(s->sa_family, sin_addr, buff, buff_size) == NULL) if ((result=getnameinfo(s, len, buff, buff_size, NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
{ {
logWarning("file: "__FILE__", line: %d, " \ logWarning("file: "__FILE__", line: %d, "
"call inet_ntop fail, " \ "getnameinfo fail, errno: %d, error info: %s",
"errno: %d, error info: %s", \ __LINE__, result, gai_strerror(result));
__LINE__, errno, STRERROR(errno));
} }
} }
} }
@ -2604,7 +2769,6 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count)
} }
freeifaddrs(ifc1); freeifaddrs(ifc1);
for (i=0; i<*count; i++) for (i=0; i<*count; i++)
{ {
getifmac(if_configs + i); getifmac(if_configs + i);
@ -2690,3 +2854,40 @@ int fc_get_net_type_by_name(const char *net_type)
} }
} }
bool tcp_socket_connected(int sock)
{
socklen_t len;
#if defined(OS_LINUX) || defined(OS_FREEBSD)
#ifdef OS_LINUX
struct tcp_info info;
#else
#include <netinet/tcp_fsm.h>
#define TCP_ESTABLISHED TCPS_ESTABLISHED
#ifndef TCP_INFO
#define TCP_INFO TCP_CONNECTION_INFO
struct tcp_connection_info info;
#else
struct tcp_info info;
#endif
#endif
len = sizeof(info);
if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &len) < 0) {
return false;
}
if (info.tcpi_state == TCP_ESTABLISHED) {
return true;
} else {
return false;
}
#else
int result;
len = sizeof(result);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &result, &len) < 0) {
return false;
} else {
return (result == 0);
}
#endif
}

View File

@ -18,15 +18,18 @@
#ifndef _SOCKETOPT_H_ #ifndef _SOCKETOPT_H_
#define _SOCKETOPT_H_ #define _SOCKETOPT_H_
#include <net/if.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <net/if.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netdb.h>
#include "common_define.h" #include "common_define.h"
#include "shared_func.h"
#define FC_NET_TYPE_NONE 0 #define FC_NET_TYPE_NONE 0
#define FC_NET_TYPE_OUTER 1 //extranet IP #define FC_NET_TYPE_OUTER 1 //extranet IP
@ -53,14 +56,14 @@
typedef struct fast_if_config { typedef struct fast_if_config {
char name[IF_NAMESIZE]; //if name char name[IF_NAMESIZE]; //if name
char mac[32]; char mac[64];
char ipv4[IP_ADDRESS_SIZE]; char ipv4[IP_ADDRESS_SIZE];
char ipv6[48]; char ipv6[IP_ADDRESS_SIZE];
} FastIFConfig; } FastIFConfig;
typedef struct ip_addr_s { typedef struct ip_addr_s {
char ip_addr[INET6_ADDRSTRLEN]; char ip_addr[IP_ADDRESS_SIZE];
int socket_domain; int af;
} ip_addr_t; } ip_addr_t;
typedef struct sockaddr_convert_s { typedef struct sockaddr_convert_s {
@ -344,9 +347,9 @@ int tcpprintkeepalive(int fd);
* sock: the socket * sock: the socket
* buff: buffer to store the ip address * buff: buffer to store the ip address
* bufferSize: the buffer size (max bytes) * bufferSize: the buffer size (max bytes)
* return: in_addr_t, INADDR_NONE for fail * return: in_addr_64_t, INADDR_NONE for fail
*/ */
in_addr_t getIpaddr(getnamefunc getname, int sock, \ in_addr_64_t getIpaddr(getnamefunc getname, int sock, \
char *buff, const int bufferSize); char *buff, const int bufferSize);
/** get ip address /** get ip address
@ -370,14 +373,23 @@ int getIpAndPort(getnamefunc getname, int sock,
*/ */
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize); char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
/** get by IPv4 address by it's hostname /** get by IPv4 or IPv6 address by it's hostname
* parameters: * parameters:
* name: the hostname * name: the hostname
* buff: buffer to store the ip address * buff: buffer to store the ip address
* bufferSize: the buffer size (max bytes) * bufferSize: the buffer size (max bytes)
* return: in_addr_t, INADDR_NONE for fail * af: store the address family
* return: in_addr_64_t, INADDR_NONE for fail
*/ */
in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize); in_addr_64_t getIpaddrByNameEx(const char *name, char *buff,
const int bufferSize, uint8_t *af);
static inline in_addr_64_t getIpaddrByName(const char *name,
char *buff, const int bufferSize)
{
uint8_t af;
return getIpaddrByNameEx(name, buff, bufferSize, &af);
}
/** get by ip addresses by it's hostname /** get by ip addresses by it's hostname
* parameters: * parameters:
@ -686,13 +698,64 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count);
* convert: the convert struct for IPv4 and IPv6 compatibility * convert: the convert struct for IPv4 and IPv6 compatibility
* return: error no, 0 success, != 0 fail * return: error no, 0 success, != 0 fail
*/ */
int setsockaddrbyip(const char *ip, const uint16_t port, sockaddr_convert_t *convert); int setsockaddrbyip(const char *ip, const uint16_t port,
sockaddr_convert_t *convert);
static inline bool is_ipv6_addr(const char *ip) static inline bool is_ipv6_addr(const char *ip)
{ {
return (*ip == ':' || strchr(ip, ':') != NULL); //ipv6 return (*ip == ':' || strchr(ip, ':') != NULL); //ipv6
} }
static inline const char *format_ip_address(const char *ip, char *buff)
{
if (is_ipv6_addr(ip))
{
int ip_len;
char *p;
ip_len = strlen(ip);
p = buff;
*p++ = '[';
memcpy(p, ip, ip_len);
p += ip_len;
*p++ = ']';
*p = '\0';
}
else
{
strcpy(buff, ip);
}
return buff;
}
static inline const char *format_ip_port(const char *ip,
const int port, char *buff)
{
int ip_len;
bool is_ipv6;
char *p;
is_ipv6 = is_ipv6_addr(ip);
ip_len = strlen(ip);
p = buff;
if (is_ipv6)
{
*p++ = '[';
}
memcpy(p, ip, ip_len);
p += ip_len;
if (is_ipv6)
{
*p++ = ']';
}
*p++ = ':';
p += fc_itoa(port, p);
*p = '\0';
return buff;
}
void tcp_set_try_again_when_interrupt(const bool value); void tcp_set_try_again_when_interrupt(const bool value);
static inline void tcp_dont_try_again_when_interrupt() static inline void tcp_dont_try_again_when_interrupt()
@ -702,10 +765,15 @@ static inline void tcp_dont_try_again_when_interrupt()
void tcp_set_quick_ack(const bool value); void tcp_set_quick_ack(const bool value);
bool tcp_socket_connected(int sock);
int fc_get_net_type_by_name(const char *net_type); int fc_get_net_type_by_name(const char *net_type);
int fc_get_net_type_by_ip(const char *ip); int fc_get_net_type_by_ip(const char *ip);
const char *fc_inet_ntop(const struct sockaddr *addr,
char *buff, const int bufferSize);
static inline bool is_network_error(const int err_no) static inline bool is_network_error(const int err_no)
{ {
switch (err_no) switch (err_no)

View File

@ -18,135 +18,177 @@
#include "pthread_func.h" #include "pthread_func.h"
#include "sorted_queue.h" #include "sorted_queue.h"
int sorted_queue_init(struct sorted_queue *sq, const int next_ptr_offset, int sorted_queue_init(struct sorted_queue *sq, const int dlink_offset,
int (*compare_func)(const void *, const void *)) int (*push_compare_func)(const void *data1, const void *data2),
int (*pop_compare_func)(const void *data, const
void *less_equal, void *arg), void *arg)
{ {
sq->compare_func = compare_func; int result;
return fc_queue_init(&sq->queue, next_ptr_offset);
if ((result=init_pthread_lock_cond_pair(&sq->lcp)) != 0) {
return result;
}
FC_INIT_LIST_HEAD(&sq->head);
sq->dlink_offset = dlink_offset;
sq->arg = arg;
sq->push_compare_func = push_compare_func;
sq->pop_compare_func = pop_compare_func;
return 0;
} }
void sorted_queue_destroy(struct sorted_queue *sq) void sorted_queue_destroy(struct sorted_queue *sq)
{ {
fc_queue_destroy(&sq->queue); destroy_pthread_lock_cond_pair(&sq->lcp);
} }
void sorted_queue_push_ex(struct sorted_queue *sq, void *data, bool *notify) void sorted_queue_push_ex(struct sorted_queue *sq, void *data, bool *notify)
{ {
void *previous; struct fc_list_head *dlink;
void *current; struct fc_list_head *current;
PTHREAD_MUTEX_LOCK(&sq->queue.lc_pair.lock); dlink = FC_SORTED_QUEUE_DLINK_PTR(sq, data);
if (sq->queue.tail == NULL) { PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
FC_QUEUE_NEXT_PTR(&sq->queue, data) = NULL; if (fc_list_empty(&sq->head)) {
sq->queue.head = sq->queue.tail = data; fc_list_add(dlink, &sq->head);
*notify = true; *notify = true;
} else { } else {
if (sq->compare_func(data, sq->queue.tail) >= 0) { if (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
FC_QUEUE_NEXT_PTR(&sq->queue, data) = NULL; sq, sq->head.prev)) >= 0)
FC_QUEUE_NEXT_PTR(&sq->queue, sq->queue.tail) = data; {
sq->queue.tail = data; fc_list_add_tail(dlink, &sq->head);
*notify = false; *notify = false;
} else if (sq->compare_func(data, sq->queue.head) < 0) { } else if (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
FC_QUEUE_NEXT_PTR(&sq->queue, data) = sq->queue.head; sq, sq->head.next)) < 0)
sq->queue.head = data; {
fc_list_add(dlink, &sq->head);
*notify = true; *notify = true;
} else { } else {
previous = sq->queue.head; current = sq->head.prev->prev;
current = FC_QUEUE_NEXT_PTR(&sq->queue, previous); while (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
while (sq->compare_func(data, current) >= 0) { sq, current)) < 0)
previous = current; {
current = FC_QUEUE_NEXT_PTR(&sq->queue, previous); current = current->prev;
} }
fc_list_add_after(dlink, current);
FC_QUEUE_NEXT_PTR(&sq->queue, data) = FC_QUEUE_NEXT_PTR(
&sq->queue, previous);
FC_QUEUE_NEXT_PTR(&sq->queue, previous) = data;
*notify = false; *notify = false;
} }
} }
PTHREAD_MUTEX_UNLOCK(&sq->queue.lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
} }
void *sorted_queue_pop_ex(struct sorted_queue *sq, void *sorted_queue_pop_ex(struct sorted_queue *sq,
void *less_equal, const bool blocked) void *less_equal, const bool blocked)
{ {
void *data; void *data;
struct fc_list_head *current;
PTHREAD_MUTEX_LOCK(&sq->queue.lc_pair.lock); PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
do { do {
if (sq->queue.head == NULL || sq->compare_func( if (fc_list_empty(&sq->head)) {
sq->queue.head, less_equal) > 0)
{
if (!blocked) { if (!blocked) {
data = NULL; data = NULL;
break; break;
} }
pthread_cond_wait(&sq->queue.lc_pair.cond, pthread_cond_wait(&sq->lcp.cond,
&sq->queue.lc_pair.lock); &sq->lcp.lock);
} if (fc_list_empty(&sq->head)) {
if (sq->queue.head == NULL) {
data = NULL;
} else {
if (sq->compare_func(sq->queue.head, less_equal) <= 0) {
data = sq->queue.head;
sq->queue.head = FC_QUEUE_NEXT_PTR(&sq->queue, data);
if (sq->queue.head == NULL) {
sq->queue.tail = NULL;
}
} else {
data = NULL; data = NULL;
break;
} }
} }
} while (0);
PTHREAD_MUTEX_UNLOCK(&sq->queue.lc_pair.lock); current = sq->head.next;
return data; data = FC_SORTED_QUEUE_DATA_PTR(sq, current);
if (sq->pop_compare_func(data, less_equal, sq->arg) <= 0) {
fc_list_del_init(current);
} else {
data = NULL;
}
} while (0);
PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
return data;
} }
void sorted_queue_pop_to_queue_ex(struct sorted_queue *sq, void sorted_queue_pop_to_chain_ex(struct sorted_queue *sq,
void *less_equal, struct fc_queue_info *qinfo, void *less_equal, struct fc_list_head *head,
const bool blocked) const bool blocked)
{ {
PTHREAD_MUTEX_LOCK(&sq->queue.lc_pair.lock); struct fc_list_head *current;
PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
do { do {
if (sq->queue.head == NULL) { if (fc_list_empty(&sq->head)) {
if (!blocked) { if (!blocked) {
qinfo->head = qinfo->tail = NULL; FC_INIT_LIST_HEAD(head);
break; break;
} }
pthread_cond_wait(&sq->queue.lc_pair.cond, pthread_cond_wait(&sq->lcp.cond,
&sq->queue.lc_pair.lock); &sq->lcp.lock);
} }
if (sq->queue.head == NULL) { if (fc_list_empty(&sq->head)) {
qinfo->head = qinfo->tail = NULL; FC_INIT_LIST_HEAD(head);
} else { } else {
if (sq->compare_func(sq->queue.head, less_equal) <= 0) { current = sq->head.next;
qinfo->head = qinfo->tail = sq->queue.head; if (sq->pop_compare_func(FC_SORTED_QUEUE_DATA_PTR(
sq->queue.head = FC_QUEUE_NEXT_PTR(&sq->queue, sq, current), less_equal, sq->arg) <= 0)
sq->queue.head); {
while (sq->queue.head != NULL && sq->compare_func( head->next = current;
sq->queue.head, less_equal) <= 0) current->prev = head;
current = current->next;
while (current != &sq->head && sq->pop_compare_func(
FC_SORTED_QUEUE_DATA_PTR(sq, current),
less_equal, sq->arg) <= 0)
{ {
qinfo->tail = sq->queue.head; current = current->next;
sq->queue.head = FC_QUEUE_NEXT_PTR(
&sq->queue, sq->queue.head);
} }
if (sq->queue.head == NULL) { head->prev = current->prev;
sq->queue.tail = NULL; current->prev->next = head;
if (current == &sq->head) {
FC_INIT_LIST_HEAD(&sq->head);
} else { } else {
FC_QUEUE_NEXT_PTR(&sq->queue, qinfo->tail) = NULL; sq->head.next = current;
current->prev = &sq->head;
} }
} else { } else {
qinfo->head = qinfo->tail = NULL; FC_INIT_LIST_HEAD(head);
} }
} }
} while (0); } while (0);
PTHREAD_MUTEX_UNLOCK(&sq->queue.lc_pair.lock); PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
}
int sorted_queue_free_chain(struct sorted_queue *sq,
struct fast_mblock_man *mblock, struct fc_list_head *head)
{
struct fast_mblock_node *previous;
struct fast_mblock_node *current;
struct fast_mblock_chain chain;
struct fc_list_head *node;
if (fc_list_empty(&sq->head)) {
return 0;
}
node = head->next;
chain.head = previous = fast_mblock_to_node_ptr(
FC_SORTED_QUEUE_DATA_PTR(sq, node));
node = node->next;
while (node != head) {
current = fast_mblock_to_node_ptr(FC_SORTED_QUEUE_DATA_PTR(sq, node));
previous->next = current;
previous = current;
node = node->next;
}
previous->next = NULL;
chain.tail = previous;
return fast_mblock_batch_free(mblock, &chain);
} }

View File

@ -18,32 +18,50 @@
#ifndef _FC_SORTED_QUEUE_H #ifndef _FC_SORTED_QUEUE_H
#define _FC_SORTED_QUEUE_H #define _FC_SORTED_QUEUE_H
#include "fc_queue.h" #include "fast_mblock.h"
#include "fc_list.h"
#include "pthread_func.h"
struct sorted_queue struct sorted_queue
{ {
struct fc_queue queue; struct fc_list_head head;
int (*compare_func)(const void *, const void *); pthread_lock_cond_pair_t lcp;
int dlink_offset;
void *arg;
int (*push_compare_func)(const void *data1, const void *data2);
int (*pop_compare_func)(const void *data,
const void *less_equal, void *arg);
}; };
#define FC_SORTED_QUEUE_DLINK_PTR(sq, data) \
((void *)(((char *)data) + (sq)->dlink_offset))
#define FC_SORTED_QUEUE_DATA_PTR(sq, dlink) \
((void *)((char *)(dlink) - (sq)->dlink_offset))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
int sorted_queue_init(struct sorted_queue *sq, const int next_ptr_offset, int sorted_queue_init(struct sorted_queue *sq, const int dlink_offset,
int (*compare_func)(const void *, const void *)); int (*push_compare_func)(const void *data1, const void *data2),
int (*pop_compare_func)(const void *data, const
void *less_equal, void *arg), void *arg);
void sorted_queue_destroy(struct sorted_queue *sq); void sorted_queue_destroy(struct sorted_queue *sq);
static inline void sorted_queue_terminate(struct sorted_queue *sq) static inline void sorted_queue_terminate(struct sorted_queue *sq)
{ {
fc_queue_terminate(&sq->queue); pthread_cond_signal(&sq->lcp.cond);
} }
static inline void sorted_queue_terminate_all( static inline void sorted_queue_terminate_all(
struct sorted_queue *sq, const int count) struct sorted_queue *sq, const int count)
{ {
fc_queue_terminate_all(&sq->queue, count); int i;
for (i=0; i<count; i++) {
pthread_cond_signal(&(sq->lcp.cond));
}
} }
//notify by the caller //notify by the caller
@ -55,11 +73,12 @@ static inline void sorted_queue_push(struct sorted_queue *sq, void *data)
sorted_queue_push_ex(sq, data, &notify); sorted_queue_push_ex(sq, data, &notify);
if (notify) { if (notify) {
pthread_cond_signal(&(sq->queue.lc_pair.cond)); pthread_cond_signal(&(sq->lcp.cond));
} }
} }
static inline void sorted_queue_push_silence(struct sorted_queue *sq, void *data) static inline void sorted_queue_push_silence(
struct sorted_queue *sq, void *data)
{ {
bool notify; bool notify;
sorted_queue_push_ex(sq, data, &notify); sorted_queue_push_ex(sq, data, &notify);
@ -68,62 +87,38 @@ static inline void sorted_queue_push_silence(struct sorted_queue *sq, void *data
void *sorted_queue_pop_ex(struct sorted_queue *sq, void *sorted_queue_pop_ex(struct sorted_queue *sq,
void *less_equal, const bool blocked); void *less_equal, const bool blocked);
#define sorted_queue_pop(sq, less_equal) \ #define sorted_queue_pop(sq, less_equal) \
sorted_queue_pop_ex(sq, less_equal, true) sorted_queue_pop_ex(sq, less_equal, true)
#define sorted_queue_try_pop(sq, less_equal) \ #define sorted_queue_try_pop(sq, less_equal) \
sorted_queue_pop_ex(sq, less_equal, false) sorted_queue_pop_ex(sq, less_equal, false)
void sorted_queue_pop_to_chain_ex(struct sorted_queue *sq,
void sorted_queue_pop_to_queue_ex(struct sorted_queue *sq, void *less_equal, struct fc_list_head *head,
void *less_equal, struct fc_queue_info *qinfo,
const bool blocked); const bool blocked);
#define sorted_queue_pop_to_queue(sq, less_equal, qinfo) \ #define sorted_queue_pop_to_chain(sq, less_equal, head) \
sorted_queue_pop_to_queue_ex(sq, less_equal, qinfo, true) sorted_queue_pop_to_chain_ex(sq, less_equal, head, true)
#define sorted_queue_try_pop_to_queue(sq, less_equal, qinfo) \ #define sorted_queue_try_pop_to_chain(sq, less_equal, head) \
sorted_queue_pop_to_queue_ex(sq, less_equal, qinfo, false) sorted_queue_pop_to_chain_ex(sq, less_equal, head, false)
static inline void *sorted_queue_pop_all_ex(struct sorted_queue *sq,
void *less_equal, const bool blocked)
{
struct fc_queue_info chain;
sorted_queue_pop_to_queue_ex(sq, less_equal, &chain, blocked);
return chain.head;
}
#define sorted_queue_pop_all(sq, less_equal) \
sorted_queue_pop_all_ex(sq, less_equal, true)
#define sorted_queue_try_pop_all(sq, less_equal) \
sorted_queue_pop_all_ex(sq, less_equal, false)
static inline bool sorted_queue_empty(struct sorted_queue *sq) static inline bool sorted_queue_empty(struct sorted_queue *sq)
{ {
return fc_queue_empty(&sq->queue); return fc_list_empty(&sq->head);
} }
static inline void *sorted_queue_timedpeek(struct sorted_queue *sq, int sorted_queue_free_chain(struct sorted_queue *sq,
const int timeout, const int time_unit) struct fast_mblock_man *mblock, struct fc_list_head *head);
static inline void sorted_queue_lock(struct sorted_queue *sq)
{ {
return fc_queue_timedpeek(&sq->queue, timeout, time_unit); PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
} }
#define sorted_queue_timedpeek_sec(sq, timeout) \ static inline void sorted_queue_unlock(struct sorted_queue *sq)
sorted_queue_timedpeek(sq, timeout, FC_TIME_UNIT_SECOND)
#define sorted_queue_timedpeek_ms(sq, timeout_ms) \
sorted_queue_timedpeek(sq, timeout_ms, FC_TIME_UNIT_MSECOND)
#define sorted_queue_timedpeek_us(sq, timeout_us) \
sorted_queue_timedpeek(sq, timeout_us, FC_TIME_UNIT_USECOND)
static inline int sorted_queue_free_chain(struct sorted_queue *sq,
struct fast_mblock_man *mblock, struct fc_queue_info *qinfo)
{ {
return fc_queue_free_chain(&sq->queue, mblock, qinfo); PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
} }
#ifdef __cplusplus #ifdef __cplusplus

116
src/spinlock.c Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2025 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "common_define.h"
#ifdef OS_LINUX
#include <sys/syscall.h>
#include <linux/futex.h>
#define FUTEX(ptr, op, val) syscall(SYS_futex, ptr, op, val, NULL, NULL, 0)
#else
#include "pthread_func.h"
#endif
#include "logger.h"
#include "spinlock.h"
#ifdef OS_LINUX
static inline int fc_futex(int *ptr, int op, int val)
{
if (FUTEX(ptr, op, val) == 0) {
return 0;
} else {
return errno != 0 ? errno : EBUSY;
}
}
#endif
int fc_spinlock_init(FCSpinlock *lock, int *cond)
{
#ifdef OS_LINUX
lock->cond = cond;
return pthread_spin_init(&lock->mutex, 0);
#else
return init_pthread_lock_cond_pair(&lock->lcp);
#endif
}
void fc_spinlock_destroy(FCSpinlock *lock)
{
#ifdef OS_LINUX
#else
destroy_pthread_lock_cond_pair(&lock->lcp);
#endif
}
int fc_spinlock_lock(FCSpinlock *lock)
{
#ifdef OS_LINUX
return pthread_spin_lock(&lock->mutex);
#else
return pthread_mutex_lock(&lock->lcp.lock);
#endif
}
int fc_spinlock_trylock(FCSpinlock *lock)
{
#ifdef OS_LINUX
return pthread_spin_trylock(&lock->mutex);
#else
return pthread_mutex_trylock(&lock->lcp.lock);
#endif
}
int fc_spinlock_unlock(FCSpinlock *lock)
{
#ifdef OS_LINUX
return pthread_spin_unlock(&lock->mutex);
#else
return pthread_mutex_unlock(&lock->lcp.lock);
#endif
}
int fc_spinlock_wait(FCSpinlock *lock, const int expected)
{
#ifdef OS_LINUX
int result;
int lock_ret;
if ((result=pthread_spin_unlock(&lock->mutex)) != 0) {
return result;
}
result = fc_futex(lock->cond, FUTEX_WAIT_PRIVATE, expected);
lock_ret = pthread_spin_lock(&lock->mutex);
return result == 0 ? lock_ret : result;
#else
return pthread_cond_wait(&lock->lcp.cond, &lock->lcp.lock);
#endif
}
int fc_spinlock_wake_ex(FCSpinlock *lock, const int count)
{
#ifdef OS_LINUX
if (FUTEX(lock->cond, FUTEX_WAKE_PRIVATE, count) >= 0) {
return 0;
} else {
return errno != 0 ? errno : EBUSY;
}
#else
if (count == 1) {
return pthread_cond_signal(&lock->lcp.cond);
} else {
return pthread_cond_broadcast(&lock->lcp.cond);
}
#endif
}

59
src/spinlock.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2025 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FC_SPINLOCK_H
#define FC_SPINLOCK_H
#include <pthread.h>
#include "common_define.h"
typedef struct fc_spinlock_t {
#ifdef OS_LINUX
pthread_spinlock_t mutex;
int *cond;
#else
pthread_lock_cond_pair_t lcp;
#endif
} FCSpinlock;
#ifdef __cplusplus
extern "C" {
#endif
int fc_spinlock_init(FCSpinlock *lock, int *cond);
void fc_spinlock_destroy(FCSpinlock *lock);
int fc_spinlock_lock(FCSpinlock *lock);
int fc_spinlock_trylock(FCSpinlock *lock);
int fc_spinlock_unlock(FCSpinlock *lock);
int fc_spinlock_wait(FCSpinlock *lock, const int expected);
int fc_spinlock_wake_ex(FCSpinlock *lock, const int count);
static inline int fc_spinlock_wake(FCSpinlock *lock)
{
const int count = 1;
return fc_spinlock_wake_ex(lock, count);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -72,7 +72,11 @@ int get_sys_total_mem_size(int64_t *mem_size)
size_t len; size_t len;
mib[0] = CTL_HW; mib[0] = CTL_HW;
#ifdef DARWIN
mib[1] = HW_MEMSIZE; mib[1] = HW_MEMSIZE;
#else
mib[1] = HW_PHYSMEM;
#endif
len = sizeof(*mem_size); len = sizeof(*mem_size);
if (sysctl(mib, 2, mem_size, &len, NULL, 0) != 0) if (sysctl(mib, 2, mem_size, &len, NULL, 0) != 0)
{ {
@ -190,11 +194,54 @@ int get_boot_time(struct timeval *boot_time)
#define SET_MNT_FIELDS(left, fstypename, mntfromname, mntonname) \ #define SET_MNT_FIELDS(left, fstypename, mntfromname, mntonname) \
do { \ do { \
snprintf(left.f_fstypename, sizeof(left.f_fstypename), "%s", fstypename); \ fc_safe_strcpy(left.f_fstypename, fstypename); \
snprintf(left.f_mntfromname, sizeof(left.f_mntfromname), "%s", mntfromname); \ fc_safe_strcpy(left.f_mntfromname, mntfromname); \
snprintf(left.f_mntonname, sizeof(left.f_mntonname), "%s", mntonname); \ fc_safe_strcpy(left.f_mntonname, mntonname); \
} while (0) } while (0)
#ifdef OS_LINUX
static int get_device_type(const char *type_name, FastDeviceType *device_type)
{
int i;
const char *disk_ftypes[] = {"ext2", "ext3", "ext4", "xfs",
"btrfs", "f2fs", "jfs", "reiserfs", "nilfs", "zfs",
"ufs", "ntfs", "vfat", "udf", "romfs", "squashfs"};
const int disk_ftype_count = sizeof(disk_ftypes) / sizeof(char *);
for (i=0; i<disk_ftype_count; i++)
{
if (strcmp(type_name, disk_ftypes[i]) == 0)
{
*device_type = fast_device_type_disk;
return 0;
}
}
if (strcmp(type_name, "tmpfs") == 0 || strcmp(type_name, "devtmpfs") == 0
|| strcmp(type_name, "ramfs") == 0)
{
*device_type = fast_device_type_memory;
return 0;
}
if (strcmp(type_name, "nfs") == 0 || strcmp(type_name, "smb") == 0 ||
strcmp(type_name, "cifs") == 0 || strcmp(type_name, "afp") == 0)
{
*device_type = fast_device_type_network;
return 0;
}
if (strcmp(type_name, "fuse") == 0)
{
*device_type = fast_device_type_fuse;
return 0;
}
*device_type = fast_device_type_unkown;
return ENOENT;
}
#endif
int get_mounted_filesystems(struct fast_statfs *stats, int get_mounted_filesystems(struct fast_statfs *stats,
const int size, int *count) const int size, int *count)
{ {
@ -236,15 +283,14 @@ int get_mounted_filesystems(struct fast_statfs *stats,
mntfromname = strsep(&p, " \t"); mntfromname = strsep(&p, " \t");
mntonname = strsep(&p, " \t"); mntonname = strsep(&p, " \t");
fstypename = strsep(&p, " \t"); fstypename = strsep(&p, " \t");
toLowercase(fstypename);
snprintf(stats[*count].f_mntfromname, if (get_device_type(fstypename, &stats[*count].device_type) == 0)
sizeof(stats[*count].f_mntfromname), "%s", mntfromname); {
snprintf(stats[*count].f_mntonname, fc_safe_strcpy(stats[*count].f_mntfromname, mntfromname);
sizeof(stats[*count].f_mntonname), "%s", mntonname); fc_safe_strcpy(stats[*count].f_mntonname, mntonname);
snprintf(stats[*count].f_fstypename, fc_safe_strcpy(stats[*count].f_fstypename, fstypename);
sizeof(stats[*count].f_fstypename), "%s", fstypename); (*count)++;
}
(*count)++;
} }
fclose(fp); fclose(fp);
@ -275,7 +321,7 @@ int get_mounted_filesystems(struct fast_statfs *stats,
int i; int i;
mnts = NULL; mnts = NULL;
*count = getmntinfo(&mnts, 0); *count = getmntinfo(&mnts, MNT_NOWAIT);
if (*count == 0) if (*count == 0)
{ {
result = errno != 0 ? errno : EPERM; result = errno != 0 ? errno : EPERM;
@ -302,6 +348,7 @@ int get_mounted_filesystems(struct fast_statfs *stats,
#ifdef HAVE_FILE_SYSTEM_ID #ifdef HAVE_FILE_SYSTEM_ID
stats[i].f_fsid = mnts[i].f_fsid; stats[i].f_fsid = mnts[i].f_fsid;
#endif #endif
stats[i].device_type = fast_device_type_unkown;
SET_MNT_FIELDS(stats[i], mnts[i].f_fstypename, SET_MNT_FIELDS(stats[i], mnts[i].f_fstypename,
mnts[i].f_mntfromname, mnts[i].f_mntonname); mnts[i].f_mntfromname, mnts[i].f_mntonname);
} }
@ -314,6 +361,114 @@ int get_mounted_filesystems(struct fast_statfs *stats,
#endif #endif
} }
int get_statfs_by_path(const char *path, FastStatFS *statfs)
{
#define MAX_STATFS_COUNT 256
int result;
int count;
int path_len;
int mnt_len;
int matched_len;
char resolved_path[PATH_MAX];
struct fast_statfs stats[MAX_STATFS_COUNT];
struct fast_statfs *entry;
struct fast_statfs *end;
if ((result=get_mounted_filesystems(stats, MAX_STATFS_COUNT,
&count)) != 0)
{
return result;
}
if (realpath(path, resolved_path) == NULL)
{
return errno != 0 ? errno : ENOENT;
}
path_len = strlen(resolved_path);
matched_len = 0;
end = stats + count;
for (entry=stats; entry<end; entry++)
{
mnt_len = strlen(entry->f_mntonname);
if (mnt_len <= path_len && memcmp(resolved_path, entry->
f_mntonname, mnt_len) == 0)
{
if ((mnt_len > 1 && mnt_len < path_len) &&
*(resolved_path + mnt_len) != '/')
{
continue;
}
if (mnt_len > matched_len)
{
matched_len = mnt_len;
*statfs = *entry;
}
}
}
return (matched_len > 0 ? 0 : ENOENT);
}
bool is_rotational_device_by_path(const char *path)
{
#if defined(OS_LINUX)
#define DEV_PATH_PREFIX_STR "/dev/"
#define DEV_PATH_PREFIX_LEN (sizeof(DEV_PATH_PREFIX_STR) - 1)
int result;
int fd;
int len;
FastStatFS statfs;
char resolved_path[PATH_MAX];
char filename[PATH_MAX];
char buff[8];
char *device_name;
if ((result=get_statfs_by_path(path, &statfs)) != 0) {
return true;
}
if (statfs.device_type == fast_device_type_memory) {
return false;
}
if (!(statfs.device_type == fast_device_type_disk &&
strncmp(statfs.f_mntfromname, DEV_PATH_PREFIX_STR,
DEV_PATH_PREFIX_LEN) == 0))
{
return true;
}
if (realpath(statfs.f_mntfromname, resolved_path) == NULL) {
return true;
}
if (strncmp(resolved_path, DEV_PATH_PREFIX_STR,
DEV_PATH_PREFIX_LEN) != 0)
{
return true;
}
device_name = resolved_path + DEV_PATH_PREFIX_LEN;
sprintf(filename, "/sys/class/block/%s/queue/rotational", device_name);
if ((fd=open(filename, O_RDONLY)) < 0) {
sprintf(filename, "/sys/class/block/%s/../queue/rotational", device_name);
if ((fd=open(filename, O_RDONLY)) < 0) {
return true;
}
}
len = read(fd, buff, sizeof(buff));
close(fd);
if (len == 1 || len == 2) {
return (buff[0] != '0');
} else {
return true;
}
#else
return true;
#endif
}
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
typedef struct fast_process_array { typedef struct fast_process_array {
@ -613,7 +768,7 @@ int get_processes(struct fast_process_info **processes, int *count)
mib[0] = CTL_KERN; mib[0] = CTL_KERN;
mib[1] = KERN_PROC; mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ALL; mib[2] = KERN_PROC_ALL;
mib[3] = 0; mib[3] = 0;
size = 0; size = 0;
if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0) if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0)
{ {
@ -683,8 +838,7 @@ int get_processes(struct fast_process_info **processes, int *count)
for (i=0; i<nproc; i++) for (i=0; i<nproc; i++)
{ {
process->field_count = 9; process->field_count = 9;
snprintf(process->comm, sizeof(process->comm), fc_safe_strcpy(process->comm, procs[i].ki_comm);
"%s", procs[i].ki_comm);
process->pid = procs[i].ki_pid; process->pid = procs[i].ki_pid;
process->ppid = procs[i].ki_ppid; process->ppid = procs[i].ki_ppid;
process->starttime = procs[i].ki_start; process->starttime = procs[i].ki_start;
@ -883,8 +1037,7 @@ static int get_block_size_by_write(const char *path, int *block_size)
return result; return result;
} }
snprintf(tmp_filename, sizeof(tmp_filename), fc_combine_full_filename(path, ".blksize-test.tmp", tmp_filename);
"%s/.blksize-test.tmp", path);
if ((fd=open(tmp_filename, O_WRONLY | O_CREAT | if ((fd=open(tmp_filename, O_WRONLY | O_CREAT |
O_DIRECT | O_CLOEXEC, 0755)) < 0) O_DIRECT | O_CLOEXEC, 0755)) < 0)
{ {
@ -957,4 +1110,94 @@ int get_path_block_size(const char *path, int *block_size)
return get_block_size_by_write(path, block_size); return get_block_size_by_write(path, block_size);
} }
int get_groups(const pid_t pid, const gid_t gid, const int size, gid_t *list)
{
#define GROUPS_TAG_STR "\nGroups:"
#define GROUPS_TAG_LEN (sizeof(GROUPS_TAG_STR) - 1)
char filename[64];
char buff[1024];
char *p;
char *end;
int fd;
int len;
gid_t val;
int count;
sprintf(filename, "/proc/%d/status", pid);
fd = open(filename, O_RDONLY);
if (fd < 0) {
return 0;
}
len = read(fd, buff, sizeof(buff));
close(fd);
if (len <= 0) {
return 0;
}
buff[len - 1] = '\0';
if ((p=strstr(buff, GROUPS_TAG_STR)) == NULL) {
return 0;
}
p += GROUPS_TAG_LEN;
count = 0;
while (count < size) {
val = strtoul(p, &end, 10);
if (end == p) {
break;
}
if (val != gid) {
list[count++] = val;
}
p = end;
}
return count;
}
#elif defined(OS_FREEBSD)
int get_groups(const pid_t pid, const gid_t gid, const int size, gid_t *list)
{
int mibpath[4];
struct kinfo_proc kp;
size_t kplen;
int count;
int i;
#if defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PID)
mibpath[0] = CTL_KERN;
mibpath[1] = KERN_PROC;
mibpath[2] = KERN_PROC_PID;
#else
kplen = 4;
sysctlnametomib("kern.proc.pid", mibpath, &kplen);
#endif
mibpath[3] = pid;
kplen = sizeof(kp);
memset(&kp,0,sizeof(kp));
if (sysctl(mibpath, 4, &kp, &kplen, NULL, 0) != 0) {
return 0;
}
#if defined(DARWIN)
#define ki_ngroups kp_eproc.e_ucred.cr_ngroups
#define ki_groups kp_eproc.e_ucred.cr_groups
#endif
count = 0;
for (i=0; i<kp.ki_ngroups && count<size; i++) {
if (kp.ki_groups[i] != gid) {
list[count++] = kp.ki_groups[i];
}
}
return count;
}
#endif #endif

View File

@ -42,6 +42,14 @@ extern "C" {
#define MNAMELEN 128 #define MNAMELEN 128
#endif #endif
typedef enum fast_device_type {
fast_device_type_unkown = 0,
fast_device_type_disk,
fast_device_type_memory,
fast_device_type_fuse,
fast_device_type_network
} FastDeviceType;
typedef struct fast_statfs { typedef struct fast_statfs {
long f_type; /* type of file system (see below) */ long f_type; /* type of file system (see below) */
long f_bsize; /* optimal transfer block size */ long f_bsize; /* optimal transfer block size */
@ -56,6 +64,7 @@ extern "C" {
char f_fstypename[MFSNAMELEN]; /* fs type name */ char f_fstypename[MFSNAMELEN]; /* fs type name */
char f_mntfromname[MNAMELEN]; /* mounted file system */ char f_mntfromname[MNAMELEN]; /* mounted file system */
char f_mntonname[MNAMELEN]; /* directory on which mounted */ char f_mntonname[MNAMELEN]; /* directory on which mounted */
FastDeviceType device_type;
} FastStatFS; } FastStatFS;
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
@ -120,6 +129,23 @@ extern "C" {
} FastProcessInfo; } FastProcessInfo;
#endif #endif
static inline const char *get_device_type_caption(
const FastDeviceType device_type)
{
switch (device_type) {
case fast_device_type_disk:
return "disk";
case fast_device_type_memory:
return "memory";
case fast_device_type_fuse:
return "fuse";
case fast_device_type_network:
return "network";
default:
return "unkown";
}
}
/** get system total memory size /** get system total memory size
* parameters: * parameters:
* mem_size: return the total memory size * mem_size: return the total memory size
@ -151,6 +177,21 @@ int get_boot_time(struct timeval *boot_time);
int get_mounted_filesystems(struct fast_statfs *stats, int get_mounted_filesystems(struct fast_statfs *stats,
const int size, int *count); const int size, int *count);
/** get statfs by path
* parameters:
* path: the path
* statfs: return the statfs
* return: error no, 0 success, != 0 fail
*/
int get_statfs_by_path(const char *path, FastStatFS *statfs);
/** is rotational device by path
* parameters:
* path: the path
* return: true for rotational device, otherwise false
*/
bool is_rotational_device_by_path(const char *path);
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
/** get processes /** get processes
* parameters: * parameters:
@ -164,6 +205,8 @@ int get_sysinfo(struct fast_sysinfo *info);
int get_kernel_version(Version *version); int get_kernel_version(Version *version);
int get_groups(const pid_t pid, const gid_t gid, const int size, gid_t *list);
#ifdef OS_LINUX #ifdef OS_LINUX
int get_device_block_size(const char *device, int *block_size); int get_device_block_size(const char *device, int *block_size);
int get_path_block_size(const char *path, int *block_size); int get_path_block_size(const char *path, int *block_size);

View File

@ -1,8 +1,8 @@
.SUFFIXES: .c .o .SUFFIXES: .c .o
COMPILE = $(CC) -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -g -DDEBUG_FLAG COMPILE = $(CC) -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -DDEBUG_FLAG
INC_PATH = -I/usr/local/include INC_PATH = $(INCS)
LIB_PATH = -lfastcommon -lpthread LIB_PATH = -lfastcommon $(LIBS)
ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blocked_queue \ ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blocked_queue \
test_id_generator test_ini_parser test_char_convert test_char_convert_loader \ test_id_generator test_ini_parser test_char_convert test_char_convert_loader \
@ -10,9 +10,11 @@ ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blo
test_json_parser test_pthread_lock test_uniq_skiplist test_split_string \ test_json_parser test_pthread_lock test_uniq_skiplist test_split_string \
test_server_id_func test_pipe test_atomic test_file_write_hole test_file_lock \ test_server_id_func test_pipe test_atomic test_file_write_hole test_file_lock \
test_pthread_wait test_thread_pool test_data_visible test_mutex_lock_perf \ test_pthread_wait test_thread_pool test_data_visible test_mutex_lock_perf \
test_queue_perf test_normalize_path test_sorted_array test_queue_perf test_normalize_path test_sorted_array test_sorted_queue \
test_thread_local test_memcpy test_fast_buffer mblock_benchmark cpool_benchmark
all: $(ALL_PRGS) all: $(ALL_PRGS)
.c: .c:
$(COMPILE) -o $@ $< $(LIB_PATH) $(INC_PATH) $(COMPILE) -o $@ $< $(LIB_PATH) $(INC_PATH)
.c.o: .c.o:

211
src/tests/cpool_benchmark.c Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2025 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/connection_pool.h"
#define USE_CONN_POOL 1
//#define USE_CAS_LOCK 1
static int thread_count = 16;
static int64_t loop_count = 10000000;
static ConnectionPool cpool;
static char buff[1024];
static pthread_mutex_t lock;
volatile int mutex = 0;
#ifndef USE_CONN_POOL
static int64_t test_var1 = 0;
static int64_t test_var2 = 0;
#endif
static inline void conn_pool_get_key(const ConnectionInfo *conn,
char *key, int *key_len)
{
*key_len = strlen(conn->ip_addr);
memcpy(key, conn->ip_addr, *key_len);
*(key + (*key_len)++) = '-';
*(key + (*key_len)++) = (conn->port >> 8) & 0xFF;
*(key + (*key_len)++) = conn->port & 0xFF;
}
static void *thread_run(void *args)
{
int thread_index;
int result;
int64_t i;
ConnectionInfo cinfo;
#ifdef USE_CONN_POOL
ConnectionInfo *conn;
#endif
thread_index = (long)args;
printf("thread #%d start\n", thread_index);
if ((result=conn_pool_parse_server_info("127.0.0.1", &cinfo, 23000)) != 0) {
return NULL;
}
for (i=0; i<loop_count; i++) {
#ifdef USE_CONN_POOL
if ((conn=conn_pool_get_connection_ex(&cpool, &cinfo,
NULL, true, &result)) == NULL)
{
break;
}
//fc_sleep_us(1);
conn_pool_close_connection(&cpool, conn);
#else
char key_buff[INET6_ADDRSTRLEN + 8];
string_t key;
uint32_t hash_code;
for (int j=0; j<2; j++) {
key.str = key_buff;
conn_pool_get_key(&cinfo, key.str, &key.len);
hash_code = fc_simple_hash(key.str, key.len);
#ifdef USE_CAS_LOCK
while (!__sync_bool_compare_and_swap(&mutex, 0, 1)) {
sched_yield();
}
__sync_fetch_and_add(&test_var1, 1);
__sync_fetch_and_add(&test_var2, 1);
#else
PTHREAD_MUTEX_LOCK(&lock);
test_var1++;
test_var2++;
#endif
#ifdef USE_CAS_LOCK
__sync_bool_compare_and_swap(&mutex, 1, 0);
#else
PTHREAD_MUTEX_UNLOCK(&lock);
#endif
}
#endif
}
if (i == loop_count) {
printf("thread #%d done\n", thread_index);
} else {
printf("thread #%d loop count: %"PRId64"\n", thread_index, i);
}
return NULL;
}
int main(int argc, char *argv[])
{
const int stack_size = 64 * 1024;
const int connect_timeout = 2;
const int max_count_per_entry = 0;
const int max_idle_time = 3600;
const int htable_capacity = 163;
const int extra_data_size = 0;
int result;
int i;
int64_t qps;
pthread_t *tids;
pthread_attr_t thread_attr;
int64_t start_time;
int64_t end_time;
int64_t time_used;
ConnectionExtraParams params;
log_init();
g_log_context.log_level = LOG_INFO;
g_schedule_flag = true;
g_current_time = time(NULL);
memset(&params, 0, sizeof(params));
params.tls.enabled = false;
params.tls.htable_capacity = 13;
if ((result=conn_pool_init_ex1(&cpool, connect_timeout, max_count_per_entry,
max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
extra_data_size, &params)) != 0)
{
return result;
}
memset(buff, 0, sizeof(buff));
if ((result=init_pthread_lock(&lock)) != 0) {
return result;
}
if ((result=pthread_attr_init(&thread_attr)) != 0) {
logError("file: "__FILE__", line: %d, "
"call pthread_attr_init fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_attr_setstacksize(&thread_attr,
stack_size)) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_attr_setstacksize to %d fail, "
"errno: %d, error info: %s", __LINE__,
stack_size, result, STRERROR(result));
return result;
}
tids = fc_malloc(sizeof(pthread_t) * thread_count);
start_time = get_current_time_us();
for (i=0; i<thread_count; i++) {
if ((result=pthread_create(tids + i, &thread_attr,
thread_run, (void *)((long)i))) != 0)
{
logError("file: "__FILE__", line: %d, "
"create thread failed, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
}
for (i=0; i<thread_count; i++) {
pthread_join(tids[i], NULL);
}
end_time = get_current_time_us();
time_used = end_time - start_time;
qps = (thread_count * loop_count * 1000 * 1000) / time_used;
printf("time used: %"PRId64" ms, QPS: %"PRId64"\n", time_used / 1000, qps);
{
ConnectionPoolStat stat;
conn_pool_stat(&cpool, &stat);
printf("htable_capacity: %d, bucket_used: %d, server_count: %d, "
"connection {total_count: %d, free_count: %d}\n",
stat.htable_capacity, stat.bucket_used, stat.server_count,
stat.connection.total_count, stat.connection.free_count);
}
free(tids);
conn_pool_destroy(&cpool);
return 0;
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2025 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/fast_mblock.h"
static int thread_count = 4;
static int64_t loop_count = 10000000;
static struct fast_mblock_man mblock;
static void *thread_run(void *args)
{
int thread_index;
int i;
void *obj;
thread_index = (long)args;
printf("thread #%d start\n", thread_index);
for (i=0; i<loop_count; i++) {
obj = fast_mblock_alloc_object(&mblock);
fast_mblock_free_object(&mblock, obj);
}
printf("thread #%d done\n", thread_index);
return NULL;
}
int main(int argc, char *argv[])
{
const int stack_size = 64 * 1024;
int result;
int limit;
int i;
bool continue_flag = true;
int64_t qps;
pthread_t *tids;
pthread_attr_t thread_attr;
int64_t start_time;
int64_t end_time;
int64_t time_used;
log_init();
g_log_context.log_level = LOG_DEBUG;
limit = (thread_count + 1) / 2;
fast_mblock_manager_init();
if ((result=fast_mblock_init_ex1(&mblock, "mblock", 1024,
limit, limit, NULL, NULL, true)) != 0)
{
return result;
}
fast_mblock_set_need_wait(&mblock, true, &continue_flag);
if ((result=pthread_attr_init(&thread_attr)) != 0) {
logError("file: "__FILE__", line: %d, "
"call pthread_attr_init fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_attr_setstacksize(&thread_attr,
stack_size)) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_attr_setstacksize to %d fail, "
"errno: %d, error info: %s", __LINE__,
stack_size, result, STRERROR(result));
return result;
}
tids = fc_malloc(sizeof(pthread_t) * thread_count);
start_time = get_current_time_us();
for (i=0; i<thread_count; i++) {
if ((result=pthread_create(tids + i, &thread_attr,
thread_run, (void *)((long)i))) != 0)
{
logError("file: "__FILE__", line: %d, "
"create thread failed, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
}
for (i=0; i<thread_count; i++) {
pthread_join(tids[i], NULL);
}
end_time = get_current_time_us();
time_used = end_time - start_time;
qps = (thread_count * loop_count * 1000 * 1000) / time_used;
printf("time used: %"PRId64" ms, QPS: %"PRId64"\n", time_used / 1000, qps);
free(tids);
fast_mblock_manager_stat_print(false);
fast_mblock_destroy(&mblock);
return 0;
}

View File

@ -30,6 +30,7 @@
static bool g_continue_flag = true; static bool g_continue_flag = true;
static int64_t produce_count = 0; static int64_t produce_count = 0;
static int64_t consume_count = 0; static int64_t consume_count = 0;
static struct fast_task_queue free_queue;
static struct fast_blocked_queue blocked_queue; static struct fast_blocked_queue blocked_queue;
#define MAX_USLEEP 10000 #define MAX_USLEEP 10000
@ -51,7 +52,7 @@ void *producer_thread(void *arg)
printf("produce count: %"PRId64"\n", count); printf("produce count: %"PRId64"\n", count);
} }
pTask = free_queue_pop(); pTask = free_queue_pop(&free_queue);
if (pTask != NULL) { if (pTask != NULL) {
blocked_queue_push(&blocked_queue, pTask); blocked_queue_push(&blocked_queue, pTask);
} }
@ -99,7 +100,7 @@ int main(int argc, char *argv[])
return errno; return errno;
} }
result = free_queue_init(1024, min_buff_size, \ result = free_queue_init(&free_queue, 1024, min_buff_size,
max_buff_size, arg_size); max_buff_size, arg_size);
if (result != 0) { if (result != 0) {
return result; return result;

View File

@ -0,0 +1,331 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include "fastcommon/logger.h"
#include "fastcommon/fast_buffer.h"
#include "fastcommon/sched_thread.h"
typedef enum {
TEST_TYPE_NONE = 0,
TEST_TYPE_ITOA,
TEST_TYPE_FTOA,
TEST_TYPE_INT2HEX,
TEST_TYPE_APPEND
} TestType;
typedef enum {
DA_SLICE_TYPE_FILE = 'F', /* in file slice */
DA_SLICE_TYPE_CACHE = 'C', /* in memory cache */
DA_SLICE_TYPE_ALLOC = 'A' /* allocate slice (index and space allocate only) */
} DASliceType;
typedef struct {
int64_t version;
uint64_t trunk_id; //0 for not inited
uint32_t length; //data length
uint32_t offset; //space offset
uint32_t size; //space size
} DAPieceFieldStorage;
typedef struct {
int64_t version; //for stable sort only
uint64_t oid; //object ID
uint64_t fid; //field ID (key)
uint32_t extra; //such as slice offset
char op_type;
DASliceType slice_type;
DAPieceFieldStorage storage;
} DATrunkSpaceLogRecord;
static inline void log_pack_by_append(const DATrunkSpaceLogRecord
*record, FastBuffer *buffer, const bool have_extra_field)
{
fast_buffer_append_int64(buffer, (uint32_t)g_current_time);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->storage.version);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->oid);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->fid);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_char(buffer, record->op_type);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->storage.trunk_id);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->storage.length);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->storage.offset);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_int64(buffer, record->storage.size);
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_char(buffer, record->slice_type);
if (have_extra_field) {
fast_buffer_append_char(buffer, ' ');
fast_buffer_append_char(buffer, record->extra);
fast_buffer_append_char(buffer, '\n');
} else {
fast_buffer_append_char(buffer, '\n');
}
}
static inline void log_pack_by_sprintf(const DATrunkSpaceLogRecord
*record, FastBuffer *buffer, const bool have_extra_field)
{
buffer->length += sprintf(buffer->data + buffer->length,
"%u %"PRId64" %"PRId64" %"PRId64" %c %"PRId64" %u %u %u %c",
(uint32_t)g_current_time, record->storage.version,
record->oid, record->fid, record->op_type,
record->storage.trunk_id, record->storage.length,
record->storage.offset, record->storage.size,
record->slice_type);
if (have_extra_field) {
buffer->length += sprintf(buffer->data + buffer->length,
" %u\n", record->extra);
} else {
*(buffer->data + buffer->length++) = '\n';
}
}
#define BINLOG_FILENAME_PREFIX_STR "binlog."
#define BINLOG_FILENAME_PREFIX_LEN (sizeof(BINLOG_FILENAME_PREFIX_STR) - 1)
static inline int cache_binlog_filename_by_sprintf(
const char *data_path, const char *subdir_name,
const uint32_t subdirs, const uint64_t id,
char *full_filename, const int size)
{
int path_index;
path_index = id % subdirs;
return sprintf(full_filename, "%s/%s/%02X/%02X/%s%08"PRIX64,
data_path, subdir_name, path_index, path_index,
BINLOG_FILENAME_PREFIX_STR, id);
}
static inline int cache_binlog_filename_by_append(
const char *data_path, const char *subdir_name,
const uint32_t subdirs, const uint64_t id,
char *full_filename, const int size)
{
int path_index;
int path_len;
int subdir_len;
char *p;
path_index = id % subdirs;
path_len = strlen(data_path);
subdir_len = strlen(subdir_name);
p = full_filename;
memcpy(p, data_path, path_len);
p += path_len;
*p++ = '/';
memcpy(p, subdir_name, subdir_len);
p += subdir_len;
*p++ = '/';
*p++ = g_upper_hex_chars[(path_index >> 4) & 0x0F];
*p++ = g_upper_hex_chars[path_index & 0x0F];
*p++ = '/';
*p++ = g_upper_hex_chars[(path_index >> 4) & 0x0F];
*p++ = g_upper_hex_chars[path_index & 0x0F];
*p++ = '/';
memcpy(p, BINLOG_FILENAME_PREFIX_STR, BINLOG_FILENAME_PREFIX_LEN);
p += BINLOG_FILENAME_PREFIX_LEN;
if (id <= UINT32_MAX) {
p += int2HEX(id, p, 8);
} else {
p += long2HEX(id, p, 8);
}
return p - full_filename;
}
static void usage(const char *program)
{
fprintf(stderr, "Usage: %s [-t {itoa | ftoa | int2hex | append | all}]\n",
program);
}
int main(int argc, char *argv[])
{
const bool binary_mode = true;
const bool check_capacity = false;
const bool have_extra_field = false;
const int LOOP = 10 * 1000 * 1000;
const char *data_path = "/opt/fastcfs/fdir/data";
const char *subdir_name = "binlog";
const uint32_t subdirs = 256;
int result;
TestType test_type = TEST_TYPE_ITOA;
TestType type_start;
TestType type_last;
uint64_t id = 123456;
double d = 123.456;
int ch;
int i;
int len;
int64_t start_time_us;
int convert_time_us;
int sprintf_time_us;
double ratio;
FastBuffer buffer;
DATrunkSpaceLogRecord record;
char full_filename1[PATH_MAX];
char full_filename2[PATH_MAX];
char buff[32] = {0};
char *caption;
log_init();
g_current_time = time(NULL);
if ((result=fast_buffer_init_ex(&buffer, 256,
binary_mode, check_capacity)) != 0)
{
return result;
}
type_start = type_last = TEST_TYPE_ITOA;
while ((ch=getopt(argc, argv, "ht:")) != -1) {
switch (ch) {
case 'h':
usage(argv[0]);
return 0;
case 't':
if (strcasecmp(optarg, "itoa") == 0) {
type_start = type_last = TEST_TYPE_ITOA;
} else if (strcasecmp(optarg, "ftoa") == 0) {
type_start = type_last = TEST_TYPE_FTOA;
} else if (strcasecmp(optarg, "int2hex") == 0) {
type_start = type_last = TEST_TYPE_INT2HEX;
} else if (strcasecmp(optarg, "append") == 0) {
type_start = type_last = TEST_TYPE_APPEND;
} else if (strcasecmp(optarg, "all") == 0) {
type_start = TEST_TYPE_ITOA;
type_last = TEST_TYPE_APPEND;
} else {
fprintf(stderr, "invalid type: %s\n", optarg);
return EINVAL;
}
break;
default:
usage(argv[0]);
return EINVAL;
}
}
for (test_type=type_start; test_type<=type_last; test_type++) {
if (test_type == TEST_TYPE_APPEND) {
memset(&record, 0, sizeof(record));
record.op_type = 'C';
record.slice_type = DA_SLICE_TYPE_FILE;
record.storage.version = 1111;
record.oid = 9007211709265131LL;
record.fid = 0;
record.storage.trunk_id = 61;
record.storage.length = 62;
record.storage.offset = 12345;
record.storage.size = 64;
}
start_time_us = get_current_time_us();
for (i=0; i<LOOP; i++) {
switch (test_type) {
case TEST_TYPE_APPEND:
cache_binlog_filename_by_sprintf(data_path, subdir_name,
subdirs, ++id, full_filename1, sizeof(full_filename1));
fast_buffer_reset(&buffer);
log_pack_by_sprintf(&record, &buffer, have_extra_field);
break;
case TEST_TYPE_ITOA:
sprintf(buff, "%"PRId64, id);
break;
case TEST_TYPE_FTOA:
sprintf(buff, "%.2f", d);
break;
case TEST_TYPE_INT2HEX:
sprintf(buff, "%x", (int)id);
break;
default:
break;
}
}
sprintf_time_us = (get_current_time_us() - start_time_us);
start_time_us = get_current_time_us();
for (i=0; i<LOOP; i++) {
switch (test_type) {
case TEST_TYPE_APPEND:
cache_binlog_filename_by_append(data_path, subdir_name,
subdirs, ++id, full_filename2, sizeof(full_filename2));
fast_buffer_reset(&buffer);
log_pack_by_append(&record, &buffer, have_extra_field);
break;
case TEST_TYPE_ITOA:
len = fc_itoa(id, buff);
*(buff + len) = '\0';
break;
case TEST_TYPE_FTOA:
len = fc_ftoa(d, 2, buff);
*(buff + len) = '\0';
break;
case TEST_TYPE_INT2HEX:
int2hex(id, buff, 0);
break;
default:
break;
}
}
convert_time_us = (get_current_time_us() - start_time_us);
if (convert_time_us > 0) {
ratio = (double)sprintf_time_us / (double)convert_time_us;
} else {
ratio = 1.0;
}
switch (test_type) {
case TEST_TYPE_ITOA:
caption = "itoa";
break;
case TEST_TYPE_FTOA:
caption = "ftoa";
break;
case TEST_TYPE_INT2HEX:
caption = "int2hex";
break;
case TEST_TYPE_APPEND:
caption = "append";
break;
default:
caption = "unkown";
break;
}
printf("sprintf time: %d ms, %s time: %d ms, "
"sprintf time / %s time: %d%%\n",
sprintf_time_us / 1000, caption, convert_time_us / 1000,
caption, (int)(ratio * 100.00));
}
fast_buffer_destroy(&buffer);
return 0;
}

View File

@ -25,6 +25,7 @@
#include <sys/file.h> #include <sys/file.h>
#include "fastcommon/logger.h" #include "fastcommon/logger.h"
#include "fastcommon/shared_func.h" #include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#define OneArgument(a) printf("One Argument func is called!\n") #define OneArgument(a) printf("One Argument func is called!\n")
#define TwoArguments(a, b) printf("Two Arguments func is called!\n") #define TwoArguments(a, b) printf("Two Arguments func is called!\n")
@ -36,7 +37,6 @@ static inline int get_lock_info(int fd, struct flock *lock)
{ {
int result; int result;
memset(lock, 0, sizeof(struct flock));
lock->l_whence = SEEK_SET; lock->l_whence = SEEK_SET;
lock->l_type = F_WRLCK; lock->l_type = F_WRLCK;
lock->l_pid = getpid(); lock->l_pid = getpid();
@ -53,6 +53,69 @@ static inline int get_lock_info(int fd, struct flock *lock)
return result; return result;
} }
static inline int set_lock(int fd, const int operation,
const int start, const int length)
{
int result;
struct flock lock;
memset(&lock, 0, sizeof(struct flock));
lock.l_whence = SEEK_SET;
lock.l_type = operation;
lock.l_start = start;
lock.l_len = length;
lock.l_pid = getpid();
do {
if ((result=fcntl(fd, F_SETLKW, &lock)) != 0)
{
result = errno != 0 ? errno : ENOMEM;
fprintf(stderr, "line: %d, call fcntl fail, "
"errno: %d, error info: %s\n", __LINE__,
result, STRERROR(result));
} else {
printf("line: %d, call fcntl %d result: %d\n",
__LINE__, operation, result);
}
} while (result == EINTR);
return result;
}
static void *unlock_thread(void *args)
{
char *filename;
int result;
int fd;
struct flock lock;
filename = (char *)args;
fd = open(filename, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"open file %s fail, "
"errno: %d, error info: %s",
__LINE__, filename,
result, STRERROR(result));
return NULL;
}
memset(&lock, 0, sizeof(struct flock));
lock.l_start = 100;
if ((result=get_lock_info(fd, &lock)) == 0) {
logInfo("lock info: { type: %d, whence: %d, start: %"PRId64", "
"len: %"PRId64", pid: %d }",
lock.l_type, lock.l_whence, (int64_t)lock.l_start,
(int64_t)lock.l_len, lock.l_pid);
}
//set_lock(fd, F_WRLCK, 0, 0);
sleep(5);
//set_lock(fd, F_UNLCK, 0, 0);
close(fd);
return NULL;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#define SEEK_POS (2 * 1024) #define SEEK_POS (2 * 1024)
@ -61,12 +124,15 @@ int main(int argc, char *argv[])
int result; int result;
int sleep_seconds; int sleep_seconds;
int n = 0; int n = 0;
pthread_t tid;
char buf[1024]; char buf[1024];
struct flock lock; struct flock lock;
Macro(1); Macro(1);
Macro(1, 2); Macro(1, 2);
Macro(1, 2, 3); Macro(1, 2, 3);
printf("%0*d\n", 3, 1);
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]); fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1; return 1;
@ -80,7 +146,7 @@ int main(int argc, char *argv[])
sleep_seconds = 1; sleep_seconds = 1;
} }
fd = open(filename, O_RDWR | O_CREAT, 0644); fd = open(filename, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0) { if (fd < 0) {
result = errno != 0 ? errno : EIO; result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
@ -91,6 +157,61 @@ int main(int argc, char *argv[])
return result; return result;
} }
{
int flags;
flags = fcntl(fd, F_GETFD, 0);
if (flags < 0)
{
logError("file: "__FILE__", line: %d, " \
"fcntl failed, errno: %d, error info: %s.", \
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EACCES;
}
printf("flags: %d, on: %d\n", flags, (flags & FD_CLOEXEC));
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
{
logError("file: "__FILE__", line: %d, " \
"fcntl failed, errno: %d, error info: %s.", \
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EACCES;
}
flags = fcntl(fd, F_GETFD, 0);
printf("flags: %d, on: %d\n", flags, (flags & FD_CLOEXEC));
}
fork();
memset(&lock, 0, sizeof(struct flock));
lock.l_start = 1024;
if ((result=get_lock_info(fd, &lock)) == 0) {
logInfo("pid: %d, lock info: { type: %d, whence: %d, "
"start: %"PRId64", len: %"PRId64", pid: %d }", getpid(),
lock.l_type, lock.l_whence, (int64_t)lock.l_start,
(int64_t)lock.l_len, lock.l_pid);
}
set_lock(fd, F_WRLCK, 0, 10);
set_lock(fd, F_WRLCK, 10, 10);
set_lock(fd, F_WRLCK, 30, 10);
//set_lock(fd, F_WRLCK, 0, 0);
//set_lock(fd, F_UNLCK, 0, 10);
//set_lock(fd, F_UNLCK, 5, 35);
fc_create_thread(&tid, unlock_thread, filename, 64 * 1024);
sleep(100);
memset(&lock, 0, sizeof(struct flock));
lock.l_start = 100;
if ((result=get_lock_info(fd, &lock)) == 0) {
logInfo("lock info: { type: %d, whence: %d, start: %"PRId64", "
"len: %"PRId64", pid: %d }",
lock.l_type, lock.l_whence, (int64_t)lock.l_start,
(int64_t)lock.l_len, lock.l_pid);
}
if (flock(fd, LOCK_EX) < 0) { if (flock(fd, LOCK_EX) < 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
"flock file %s fail, " "flock file %s fail, "

View File

@ -32,6 +32,7 @@ int main(int argc, char *argv[])
int fd; int fd;
int result; int result;
int n; int n;
int i;
char buf[1024]; char buf[1024];
if (argc < 2) { if (argc < 2) {
@ -50,7 +51,7 @@ int main(int argc, char *argv[])
*/ */
//fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); //fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
fd = open(filename, O_RDWR | O_CREAT, 0644); fd = open(filename, O_RDWR | O_CREAT | O_APPEND, 0644);
if (fd < 0) { if (fd < 0) {
result = errno != 0 ? errno : EIO; result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, " \
@ -69,7 +70,8 @@ int main(int argc, char *argv[])
return errno != 0 ? errno : EIO; return errno != 0 ? errno : EIO;
} }
if (lseek(fd, SEEK_POS, SEEK_SET) < 0) { for (i=0; i<5; i++) {
if (lseek(fd, 0, SEEK_SET) < 0) {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, " \
"lseek file %s fail, " \ "lseek file %s fail, " \
"errno: %d, error info: %s", __LINE__, \ "errno: %d, error info: %s", __LINE__, \
@ -86,6 +88,7 @@ int main(int argc, char *argv[])
return errno != 0 ? errno : EIO; return errno != 0 ? errno : EIO;
} }
printf("write bytes: %d\n", n); printf("write bytes: %d\n", n);
}
if (lseek(fd, 0, SEEK_SET) < 0) { if (lseek(fd, 0, SEEK_SET) < 0) {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, " \

View File

@ -22,6 +22,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/file.h>
#include "fastcommon/logger.h" #include "fastcommon/logger.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -35,6 +36,15 @@ int main(int argc, char *argv[])
log_take_over_stderr(); log_take_over_stderr();
log_take_over_stdout(); log_take_over_stdout();
log_set_compress_log_flags(LOG_COMPRESS_FLAGS_ENABLED | LOG_COMPRESS_FLAGS_NEW_THREAD); log_set_compress_log_flags(LOG_COMPRESS_FLAGS_ENABLED | LOG_COMPRESS_FLAGS_NEW_THREAD);
log_set_filename("/opt/fastcfs/fuse/test.log");
if (flock(g_log_context.log_fd, LOCK_EX) != 0) {
logError("flock fail");
}
flock(g_log_context.log_fd, LOCK_UN);
printf("sizeof(LogContext): %d, time_precision: %d, compress_log_flags: %d, " printf("sizeof(LogContext): %d, time_precision: %d, compress_log_flags: %d, "
"use_file_write_lock: %d\n", (int)sizeof(LogContext), "use_file_write_lock: %d\n", (int)sizeof(LogContext),
@ -46,7 +56,7 @@ int main(int argc, char *argv[])
"by log_it_ex, timestamp: %d", (int)time(NULL)); "by log_it_ex, timestamp: %d", (int)time(NULL));
len = sprintf(buff, "this is by log_it_ex1, " len = sprintf(buff, "this is by log_it_ex1, "
"timestamp: %d", (int)time(NULL)); "timestamp: %ld", (long)time(NULL));
log_it_ex1(&g_log_context, LOG_INFO, buff, len); log_it_ex1(&g_log_context, LOG_INFO, buff, len);
return 0; return 0;

View File

@ -64,6 +64,8 @@ int main(int argc, char *argv[])
volatile bool continue_flag = true; volatile bool continue_flag = true;
FastIFConfig if_configs[32]; FastIFConfig if_configs[32];
struct fast_statfs stats[32]; struct fast_statfs stats[32];
char *path;
FastStatFS statfs;
start_time = get_current_time_ms(); start_time = get_current_time_ms();
srand(time(NULL)); srand(time(NULL));
@ -86,10 +88,19 @@ int main(int argc, char *argv[])
printf("mounted fs count: %d\n", count); printf("mounted fs count: %d\n", count);
for (i=0; i<count; i++) { for (i=0; i<count; i++) {
printf("%s => %s %s %ld %ld %ld %ld %ld %ld %ld\n", printf("%s => %s %s %ld %ld %ld %ld %ld %ld %ld\n",
stats[i].f_mntfromname, stats[i].f_mntonname, stats[i].f_fstypename, stats[i].f_mntfromname, stats[i].f_mntonname,
stats[i].f_type, stats[i].f_bsize, stats[i].f_blocks, stats[i].f_fstypename, stats[i].f_type, stats[i].f_bsize,
stats[i].f_bfree, stats[i].f_bavail, stats[i].f_files, stats[i].f_blocks, stats[i].f_bfree, stats[i].f_bavail,
stats[i].f_ffree); stats[i].f_files, stats[i].f_ffree);
}
path = "/";
if (get_statfs_by_path(path, &statfs) == 0) {
printf("\ninput path: %s, %s => %s, type: %s, category: %s, "
"rotational: %d\n\n", path, statfs.f_mntfromname,
statfs.f_mntonname, statfs.f_fstypename,
get_device_type_caption(statfs.device_type),
is_rotational_device_by_path(path));
} }
#if defined(OS_LINUX) || defined(OS_FREEBSD) #if defined(OS_LINUX) || defined(OS_FREEBSD)
@ -139,31 +150,6 @@ int main(int argc, char *argv[])
#endif #endif
/*
{
int result;
char *filename;
IniContext iniContext;
if (argc > 1) {
filename = argv[1];
} else {
filename = "/etc/mc/worker.conf";
}
if ((result=iniLoadFromFile(filename, &iniContext)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, ret code: %d",
__LINE__, filename, result);
return result;
}
//iniPrintItems(&iniContext);
iniFreeContext(&iniContext);
}
*/
sched_enable_delay_task(); sched_enable_delay_task();
scheduleArray.entries = scheduleEntries; scheduleArray.entries = scheduleEntries;
scheduleArray.count = 0; scheduleArray.count = 0;
@ -176,7 +162,7 @@ int main(int argc, char *argv[])
printf("cpu count: %d\n", get_sys_cpu_count()); printf("cpu count: %d\n", get_sys_cpu_count());
end_time = get_current_time_ms(); end_time = get_current_time_ms();
logInfo("time used: %d ms", (int)(end_time - start_time)); logInfo("time used: %d ms\n", (int)(end_time - start_time));
fast_mblock_manager_init(); fast_mblock_manager_init();
@ -196,19 +182,33 @@ int main(int argc, char *argv[])
sched_add_delay_task(test_delay, objs + i, delay, false); sched_add_delay_task(test_delay, objs + i, delay, false);
} }
printf("mblock1 total count: %"PRId64", free count: %u\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1));
/* /*
for (i=0; i<count; i++) for (i=0; i<count; i++)
{ {
fast_mblock_free_object(&mblock1, objs[i]); fast_mblock_free_object(objs[i].mblock, objs[i].obj);
} }
*/ */
obj1 = fast_mblock_alloc_object(&mblock1); obj1 = fast_mblock_alloc_object(&mblock1);
obj2 = fast_mblock_alloc_object(&mblock1); obj2 = fast_mblock_alloc_object(&mblock1);
fast_mblock_free_object(&mblock1, obj1); fast_mblock_free_object(&mblock1, obj1);
printf("mblock1 total count: %"PRId64", free count: %u\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1));
//fast_mblock_delay_free_object(&mblock1, obj2, 10); //fast_mblock_delay_free_object(&mblock1, obj2, 10);
fast_mblock_free_object(&mblock1, obj2); fast_mblock_free_object(&mblock1, obj2);
printf("mblock1 total count: %"PRId64", free count: %u\n\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1));
obj1 = fast_mblock_alloc_object(&mblock2); obj1 = fast_mblock_alloc_object(&mblock2);
obj2 = fast_mblock_alloc_object(&mblock2); obj2 = fast_mblock_alloc_object(&mblock2);
fast_mblock_delay_free_object(&mblock2, obj1, 20); fast_mblock_delay_free_object(&mblock2, obj1, 20);
@ -220,6 +220,13 @@ int main(int argc, char *argv[])
fast_mblock_reclaim(&mblock1, reclaim_target, &reclaim_count, NULL); fast_mblock_reclaim(&mblock1, reclaim_target, &reclaim_count, NULL);
fast_mblock_reclaim(&mblock2, reclaim_target, &reclaim_count, NULL); fast_mblock_reclaim(&mblock2, reclaim_target, &reclaim_count, NULL);
printf("\nmblock1 total count: %"PRId64", free count: %u, "
"mblock2 total count: %"PRId64", free count: %u\n\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1),
fast_mblock_total_count(&mblock2),
fast_mblock_free_count(&mblock2));
fast_mblock_manager_stat_print(false); fast_mblock_manager_stat_print(false);
sleep(31); sleep(31);
@ -231,11 +238,25 @@ int main(int argc, char *argv[])
fast_mblock_reclaim(&mblock1, reclaim_target, &reclaim_count, NULL); fast_mblock_reclaim(&mblock1, reclaim_target, &reclaim_count, NULL);
fast_mblock_reclaim(&mblock2, reclaim_target, &reclaim_count, NULL); fast_mblock_reclaim(&mblock2, reclaim_target, &reclaim_count, NULL);
printf("\nmblock1 total count: %"PRId64", free count: %u, "
"mblock2 total count: %"PRId64", free count: %u\n\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1),
fast_mblock_total_count(&mblock2),
fast_mblock_free_count(&mblock2));
fast_mblock_manager_stat_print(false); fast_mblock_manager_stat_print(false);
obj1 = fast_mblock_alloc_object(&mblock1); obj1 = fast_mblock_alloc_object(&mblock1);
obj2 = fast_mblock_alloc_object(&mblock2); obj2 = fast_mblock_alloc_object(&mblock2);
printf("mblock1 total count: %"PRId64", free count: %u, "
"mblock2 total count: %"PRId64", free count: %u\n\n",
fast_mblock_total_count(&mblock1),
fast_mblock_free_count(&mblock1),
fast_mblock_total_count(&mblock2),
fast_mblock_free_count(&mblock2));
fast_mblock_manager_stat_print(false); fast_mblock_manager_stat_print(false);
fast_mblock_destroy(&mblock1); fast_mblock_destroy(&mblock1);

54
src/tests/test_memcpy.c Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fastcommon/shared_func.h"
#define BUFF_SIZE (4 * 1024 * 1024)
int main(int argc, char *argv[])
{
char *buff1;
char *buff2;
char *dest;
int64_t start_time, end_time;
char time_buff[32];
int i;
buff1 = malloc(BUFF_SIZE);
buff2 = malloc(BUFF_SIZE);
dest = malloc(BUFF_SIZE);
memset(buff1, 'a', BUFF_SIZE);
memset(buff2, 'b', BUFF_SIZE);
memset(dest, 0, BUFF_SIZE);
start_time = get_current_time_us();
for (i=0; i<16 * 1024; i++) {
if (i % 2 == 0) {
memcpy(buff2, buff1, BUFF_SIZE);
} else {
memcpy(dest, buff2, BUFF_SIZE);
}
}
end_time = get_current_time_us();
printf("time used: %s us\n", long_to_comma_str(
end_time - start_time, time_buff));
return 0;
}

View File

@ -27,8 +27,8 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char full_filename[PATH_MAX]; char full_filename[PATH_MAX];
const char *from; string_t from;
const char *filename; string_t filename;
int filename_len; int filename_len;
int result; int result;
@ -38,12 +38,14 @@ int main(int argc, char *argv[])
} }
log_init(); log_init();
from = argv[1];
filename = argv[2]; FC_SET_STRING(from, argv[1]);
filename_len = normalize_path_ex(from, filename, FC_SET_STRING(filename, argv[2]);
filename_len = normalize_path_ex(&from, &filename,
full_filename, sizeof(full_filename), full_filename, sizeof(full_filename),
NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS); NORMALIZE_FLAGS_URL_ENABLED_AND_APPEND_PARAMS);
printf("%s\n", full_filename); printf("%s => {len1: %d, len2: %d}\n", full_filename,
(int)strlen(full_filename), filename_len);
if (IS_URL_RESOURCE(full_filename)) { if (IS_URL_RESOURCE(full_filename)) {
const int connect_timeout = 2; const int connect_timeout = 2;

View File

@ -84,6 +84,56 @@ static void sigQuitHandler(int sig)
__LINE__, sig); __LINE__, sig);
} }
static void test_remove()
{
#define COUNT 8
typedef struct node {
int n;
struct node *next;
} Node;
struct fc_queue queue;
Node nodes[COUNT];
Node *node;
Node *end;
int result;
if ((result=fc_queue_init(&queue, (long)&((Node *)NULL)->next)) != 0)
{
return;
}
fc_queue_push(&queue, nodes);
printf("remove: %d\n", fc_queue_remove(&queue, nodes + 1));
printf("remove: %d\n", fc_queue_remove(&queue, nodes + 2));
printf("remove: %d\n", fc_queue_remove(&queue, nodes));
printf("count: %d\n", fc_queue_count(&queue));
end = nodes + COUNT / 2;
for (node=nodes; node<end; node++) {
node->n = (node - nodes) + 1;
fc_queue_push(&queue, node);
}
printf("remove: %d\n", fc_queue_remove(&queue, node));
printf("remove: %d\n", fc_queue_remove(&queue, node - 1));
printf("remove: %d\n", fc_queue_remove(&queue, node - 3));
printf("remove: %d\n", fc_queue_remove(&queue, nodes));
end = nodes + COUNT;
for (; node<end; node++) {
node->n = (node - nodes) + 1;
fc_queue_push(&queue, node);
}
printf("count: %d\n\n", fc_queue_count(&queue));
for (node=end-1; node>=nodes; node--) {
printf("remove: %d\n", fc_queue_remove(&queue, node));
fc_queue_push(&queue, node);
}
printf("count: %d\n", fc_queue_count(&queue));
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const int alloc_elements_once = 8 * 1024; const int alloc_elements_once = 8 * 1024;
@ -107,6 +157,9 @@ int main(int argc, char *argv[])
log_init(); log_init();
g_log_context.log_level = LOG_DEBUG; g_log_context.log_level = LOG_DEBUG;
test_remove();
return 0;
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask); sigemptyset(&act.sa_mask);
act.sa_handler = sigQuitHandler; act.sa_handler = sigQuitHandler;

View File

@ -112,7 +112,7 @@ int main(int argc, char *argv[])
setup_mblock_stat_task(); setup_mblock_stat_task();
if ((result=fast_buffer_init_ex(&buffer, 1024)) != 0) { if ((result=fast_buffer_init1(&buffer, 1024)) != 0) {
return result; return result;
} }
fc_server_to_config_string(&ctx, &buffer); fc_server_to_config_string(&ctx, &buffer);

View File

@ -66,6 +66,12 @@ static int test_i64()
return ENOMEM; return ENOMEM;
} }
if (!silence) {
printf("input alloc count: %d, output alloc count: %d\n",
input->alloc, output->alloc);
}
input->count = ELEMENT_COUNT; input->count = ELEMENT_COUNT;
for (i=0; i<input->count; i++) { for (i=0; i<input->count; i++) {
input->elts[i] = i + 1; input->elts[i] = i + 1;

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <inttypes.h>
#include <sys/time.h>
#include "fastcommon/sorted_queue.h"
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#define COUNT 100
#define LAST_INDEX (COUNT - 1)
typedef struct {
int n;
struct fc_list_head dlink;
} DoubleLinkNumber;
static DoubleLinkNumber *numbers;
static struct sorted_queue sq;
static int push_compare_func(const void *p1, const void *p2)
{
return ((DoubleLinkNumber *)p1)->n - ((DoubleLinkNumber *)p2)->n;
}
static int pop_compare_func(const void *data,
const void *less_equal, void *arg)
{
return ((DoubleLinkNumber *)data)->n -
((DoubleLinkNumber *)less_equal)->n;
}
void set_rand_numbers(const int multiple)
{
int i;
int tmp;
int index1;
int index2;
for (i=0; i<COUNT; i++) {
numbers[i].n = multiple * i + 1;
}
for (i=0; i<COUNT; i++) {
index1 = (LAST_INDEX * (int64_t)rand()) / (int64_t)RAND_MAX;
index2 = (LAST_INDEX * (int64_t)rand()) / (int64_t)RAND_MAX;
if (index1 == index2) {
continue;
}
tmp = numbers[index1].n;
numbers[index1].n = numbers[index2].n;
numbers[index2].n = tmp;
}
}
static void test1()
{
int i;
DoubleLinkNumber less_equal;
DoubleLinkNumber *number;
struct fc_list_head head;
set_rand_numbers(1);
for (i=0; i<COUNT; i++) {
sorted_queue_push_silence(&sq, numbers + i);
}
less_equal.n = COUNT;
sorted_queue_try_pop_to_chain(&sq, &less_equal, &head);
assert(sorted_queue_empty(&sq));
i = 0;
fc_list_for_each_entry (number, &head, dlink) {
i++;
if (i != number->n) {
fprintf(stderr, "i: %d != value: %d\n", i, number->n);
break;
}
}
assert(i == COUNT);
sorted_queue_try_pop_to_chain(&sq, &less_equal, &head);
assert(fc_list_empty(&head));
}
static void test2()
{
#define MULTIPLE 2
int i;
int n;
DoubleLinkNumber less_equal;
DoubleLinkNumber *number;
struct fc_list_head head;
set_rand_numbers(MULTIPLE);
for (i=0; i<COUNT; i++) {
sorted_queue_push_silence(&sq, numbers + i);
}
less_equal.n = 0;
sorted_queue_try_pop_to_chain(&sq, &less_equal, &head);
assert(fc_list_empty(&head));
less_equal.n = COUNT;
sorted_queue_try_pop_to_chain(&sq, &less_equal, &head);
assert(!sorted_queue_empty(&sq));
i = 0;
fc_list_for_each_entry (number, &head, dlink) {
n = i++ * MULTIPLE + 1;
if (n != number->n) {
fprintf(stderr, "%d. n: %d != value: %d\n", i, n, number->n);
break;
}
}
less_equal.n = 2 * COUNT + 1;
sorted_queue_try_pop_to_chain(&sq, &less_equal, &head);
assert(sorted_queue_empty(&sq));
fc_list_for_each_entry (number, &head, dlink) {
n = i++ * MULTIPLE + 1;
if (n != number->n) {
fprintf(stderr, "%d. n: %d != value: %d\n", i, n, number->n);
break;
}
}
assert(i == COUNT);
}
static void test3()
{
int i;
DoubleLinkNumber less_equal;
DoubleLinkNumber *number;
set_rand_numbers(1);
for (i=0; i<COUNT; i++) {
sorted_queue_push_silence(&sq, numbers + i);
}
less_equal.n = COUNT;
for (i=1; i<=COUNT; i++) {
number = sorted_queue_try_pop(&sq, &less_equal);
assert(number != NULL);
if (i != number->n) {
fprintf(stderr, "i: %d != value: %d\n", i, number->n);
break;
}
}
assert(sorted_queue_try_pop(&sq, &less_equal) == NULL);
}
int main(int argc, char *argv[])
{
int result;
int64_t start_time;
int64_t end_time;
start_time = get_current_time_ms();
log_init();
numbers = (DoubleLinkNumber *)malloc(sizeof(DoubleLinkNumber) * COUNT);
srand(time(NULL));
if ((result=sorted_queue_init(&sq, (long)(&((DoubleLinkNumber *)
NULL)->dlink), push_compare_func,
pop_compare_func, NULL)) != 0)
{
return result;
}
test1();
test2();
test3();
end_time = get_current_time_ms();
printf("pass OK, time used: %"PRId64" ms\n", end_time - start_time);
return 0;
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#define THREAD_COUNT 16
static pthread_key_t key;
volatile int running_count;
static void destroy(void *ptr)
{
printf("destroy ptr: %p\n", ptr);
}
static void test_fetch(void *ptr)
{
int i;
for (i=0; i<10000000; i++) {
if (pthread_getspecific(key) != ptr) {
logError("pthread_getspecific fail");
}
}
}
static void *thread_run(void *args)
{
void *ptr;
ptr = pthread_getspecific(key);
if (ptr == NULL) {
ptr = malloc(64);
pthread_setspecific(key, ptr);
printf("create ptr: %p\n", ptr);
}
fc_sleep_ms(1);
test_fetch(ptr);
__sync_fetch_and_sub(&running_count, 1);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tid;
int64_t start_time;
int i;
int result;
log_init();
start_time = get_current_time_ms();
if ((result=pthread_key_create(&key, destroy)) != 0) {
logError("pthread_key_create fail");
return result;
}
running_count = THREAD_COUNT;
for (i=0; i<THREAD_COUNT; i++) {
if ((result=fc_create_thread(&tid, thread_run, NULL, 64 * 1024)) != 0) {
return result;
}
}
fc_sleep_ms(1);
printf("\nwaiting thread exit ...\n");
while (__sync_fetch_and_add(&running_count, 0) != 0) {
fc_sleep_ms(1);
}
printf("time used: %"PRId64" ms\n", get_current_time_ms() - start_time);
return 0;
}

View File

@ -36,7 +36,8 @@ static UniqSkiplist *sl = NULL;
static UniqSkiplistIterator iterator; static UniqSkiplistIterator iterator;
static int instance_count = 0; static int instance_count = 0;
static void free_test_func(void *ptr, const int delay_seconds) static void free_test_func(UniqSkiplist *sl,
void *ptr, const int delay_seconds)
{ {
instance_count--; instance_count--;
} }
@ -92,13 +93,13 @@ static int test_insert()
end_time = get_current_time_ms(); end_time = get_current_time_ms();
printf("insert time used: %"PRId64" ms\n", end_time - start_time); printf("insert time used: %"PRId64" ms\n", end_time - start_time);
start_time = get_current_time_ms(); start_time = get_current_time_us();
for (i=0; i<COUNT; i++) { for (i=0; i<COUNT; i++) {
value = uniq_skiplist_find(sl, numbers + i); value = uniq_skiplist_find(sl, numbers + i);
assert(value != NULL && *((int *)value) == numbers[i]); assert(value != NULL && *((int *)value) == numbers[i]);
} }
end_time = get_current_time_ms(); end_time = get_current_time_us();
printf("find time used: %"PRId64" ms\n", end_time - start_time); printf("find time used: %"PRId64" us\n", end_time - start_time);
start_time = get_current_time_ms(); start_time = get_current_time_ms();
i = 0; i = 0;
@ -117,6 +118,30 @@ static int test_insert()
return 0; return 0;
} }
static void test_array_find()
{
int i;
int bytes;
int64_t start_time;
int64_t end_time;
int *new_numbers;
int *value;
bytes = sizeof(int) * COUNT;
new_numbers = (int *)malloc(bytes);
memcpy(new_numbers, numbers, bytes);
qsort(new_numbers, COUNT, sizeof(int), compare_func);
start_time = get_current_time_us();
for (i=0; i<COUNT; i++) {
value = bsearch(numbers + i, new_numbers,
COUNT, sizeof(int), compare_func);
assert(value != NULL && *value == numbers[i]);
}
end_time = get_current_time_us();
printf("array find time used: %"PRId64" us\n\n", end_time - start_time);
}
static void test_delete() static void test_delete()
{ {
int i; int i;
@ -149,6 +174,19 @@ static void test_delete()
assert(i==0); assert(i==0);
} }
static void test_clear()
{
int64_t start_time;
int64_t end_time;
start_time = get_current_time_ms();
uniq_skiplist_clear(sl);
assert(uniq_skiplist_empty(sl));
assert(instance_count == 0);
end_time = get_current_time_ms();
printf("clear time used: %"PRId64" ms\n", end_time - start_time);
}
static void test_find_range() static void test_find_range()
{ {
int n_start; int n_start;
@ -273,8 +311,9 @@ int main(int argc, char *argv[])
srand(time(NULL)); srand(time(NULL));
fast_mblock_manager_init(); fast_mblock_manager_init();
result = uniq_skiplist_init_ex2(&factory, LEVEL_COUNT, compare_func, result = uniq_skiplist_init_ex2(&factory, LEVEL_COUNT,
free_test_func, 0, MIN_ALLOC_ONCE, 0, true, allocator_use_lock); compare_func, free_test_func, 0, MIN_ALLOC_ONCE,
0, true, allocator_use_lock, NULL);
if (result != 0) { if (result != 0) {
return result; return result;
} }
@ -287,6 +326,8 @@ int main(int argc, char *argv[])
test_insert(); test_insert();
printf("\n"); printf("\n");
test_array_find();
fast_mblock_manager_stat_print(false); fast_mblock_manager_stat_print(false);
test_delete(); test_delete();
@ -299,15 +340,17 @@ int main(int argc, char *argv[])
test_delete(); test_delete();
printf("\n"); printf("\n");
test_clear();
printf("\n");
test_insert(); test_insert();
printf("\n"); printf("\n");
/* test_clear();
test_delete();
printf("\n"); printf("\n");
*/
printf("skiplist level_count: %d\n", sl->top_level_index + 1); test_insert();
printf("\n");
uniq_skiplist_free(sl); uniq_skiplist_free(sl);
fast_mblock_manager_stat_print(false); fast_mblock_manager_stat_print(false);

View File

@ -210,7 +210,7 @@ int fc_thread_pool_init_ex(FCThreadPool *pool, const char *name,
return result; return result;
} }
snprintf(pool->name, sizeof(pool->name), "%s", name); fc_safe_strcpy(pool->name, name);
pool->stack_size = stack_size; pool->stack_size = stack_size;
pool->max_idle_time = max_idle_time; pool->max_idle_time = max_idle_time;
if (min_idle_count > limit) { if (min_idle_count > limit) {

View File

@ -54,7 +54,7 @@ int uniq_skiplist_init_ex2(UniqSkiplistFactory *factory,
const int max_level_count, skiplist_compare_func compare_func, const int max_level_count, skiplist_compare_func compare_func,
uniq_skiplist_free_func free_func, const int alloc_skiplist_once, uniq_skiplist_free_func free_func, const int alloc_skiplist_once,
const int min_alloc_elements_once, const int delay_free_seconds, const int min_alloc_elements_once, const int delay_free_seconds,
const bool bidirection, const bool allocator_use_lock) const bool bidirection, const bool allocator_use_lock, void *arg)
{ {
const int64_t alloc_elements_limit = 0; const int64_t alloc_elements_limit = 0;
char name[64]; char name[64];
@ -136,6 +136,7 @@ int uniq_skiplist_init_ex2(UniqSkiplistFactory *factory,
factory->compare_func = compare_func; factory->compare_func = compare_func;
factory->free_func = free_func; factory->free_func = free_func;
factory->delay_free_seconds = delay_free_seconds; factory->delay_free_seconds = delay_free_seconds;
factory->arg = arg;
srand(time(NULL)); srand(time(NULL));
return 0; return 0;
@ -161,12 +162,24 @@ void uniq_skiplist_destroy(UniqSkiplistFactory *factory)
factory->node_allocators = NULL; factory->node_allocators = NULL;
} }
static inline void init_chain(UniqSkiplist *sl)
{
int i;
if (sl->factory->bidirection) {
LEVEL0_DOUBLE_CHAIN_TAIL(sl) = sl->top;
}
for (i=0; i<=sl->top_level_index; i++) {
sl->top->links[i] = sl->factory->tail;
}
}
UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory, UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory,
const int level_count) const int level_count)
{ {
UniqSkiplist *sl; UniqSkiplist *sl;
struct fast_mblock_man *top_mblock; struct fast_mblock_man *top_mblock;
int i;
if (level_count <= 0) { if (level_count <= 0) {
logError("file: "__FILE__", line: %d, " logError("file: "__FILE__", line: %d, "
@ -199,13 +212,7 @@ UniqSkiplist *uniq_skiplist_new(UniqSkiplistFactory *factory,
} }
memset(sl->top, 0, top_mblock->info.element_size); memset(sl->top, 0, top_mblock->info.element_size);
sl->top->level_index = sl->top_level_index; sl->top->level_index = sl->top_level_index;
if (sl->factory->bidirection) { init_chain(sl);
LEVEL0_DOUBLE_CHAIN_TAIL(sl) = sl->top;
}
for (i=0; i<level_count; i++) {
sl->top->links[i] = sl->factory->tail;
}
return sl; return sl;
} }
@ -257,22 +264,18 @@ static int uniq_skiplist_grow(UniqSkiplist *sl)
return 0; return 0;
} }
void uniq_skiplist_free(UniqSkiplist *sl) static void do_clear(UniqSkiplist *sl)
{ {
volatile UniqSkiplistNode *node; volatile UniqSkiplistNode *node;
volatile UniqSkiplistNode *deleted; volatile UniqSkiplistNode *deleted;
if (sl->top == NULL) {
return;
}
node = sl->top->links[0]; node = sl->top->links[0];
if (sl->factory->free_func != NULL) { if (sl->factory->free_func != NULL) {
while (node != sl->factory->tail) { while (node != sl->factory->tail) {
deleted = node; deleted = node;
node = node->links[0]; node = node->links[0];
sl->factory->free_func(deleted->data, 0); sl->factory->free_func(sl, deleted->data, 0);
fast_mblock_free_object(sl->factory->node_allocators + fast_mblock_free_object(sl->factory->node_allocators +
deleted->level_index, (void *)deleted); deleted->level_index, (void *)deleted);
} }
@ -286,11 +289,30 @@ void uniq_skiplist_free(UniqSkiplist *sl)
} }
} }
sl->element_count = 0;
}
void uniq_skiplist_clear(UniqSkiplist *sl)
{
if (!uniq_skiplist_empty(sl)) {
do_clear(sl);
init_chain(sl);
}
}
void uniq_skiplist_free(UniqSkiplist *sl)
{
if (sl->top == NULL) {
return;
}
if (!uniq_skiplist_empty(sl)) {
do_clear(sl);
}
fast_mblock_free_object(sl->factory->node_allocators + fast_mblock_free_object(sl->factory->node_allocators +
sl->top_level_index, sl->top); sl->top_level_index, sl->top);
sl->top = NULL; sl->top = NULL;
sl->element_count = 0;
sl->top_level_index = 0; sl->top_level_index = 0;
fast_mblock_free_object(&sl->factory->skiplist_allocator, sl); fast_mblock_free_object(&sl->factory->skiplist_allocator, sl);
} }
@ -484,7 +506,7 @@ void uniq_skiplist_delete_node_ex(UniqSkiplist *sl,
} }
if (need_free && sl->factory->free_func != NULL) { if (need_free && sl->factory->free_func != NULL) {
sl->factory->free_func(deleted->data, sl->factory->free_func(sl, deleted->data,
sl->factory->delay_free_seconds); sl->factory->delay_free_seconds);
} }
@ -527,7 +549,8 @@ int uniq_skiplist_replace_ex(UniqSkiplist *sl, void *data,
deleted_data = current->data; deleted_data = current->data;
current->data = data; current->data = data;
sl->factory->free_func(deleted_data, sl->factory->delay_free_seconds); sl->factory->free_func(sl, deleted_data,
sl->factory->delay_free_seconds);
} else { } else {
current->data = data; current->data = data;
} }

View File

@ -25,7 +25,9 @@
#include "skiplist_common.h" #include "skiplist_common.h"
#include "fast_mblock.h" #include "fast_mblock.h"
typedef void (*uniq_skiplist_free_func)(void *ptr, const int delay_seconds); struct uniq_skiplist;
typedef void (*uniq_skiplist_free_func)(struct uniq_skiplist *skiplist,
void *ptr, const int delay_seconds);
typedef struct uniq_skiplist_node typedef struct uniq_skiplist_node
{ {
@ -44,6 +46,7 @@ typedef struct uniq_skiplist_factory
UniqSkiplistNode *tail; //the tail node for interator UniqSkiplistNode *tail; //the tail node for interator
struct fast_mblock_man skiplist_allocator; struct fast_mblock_man skiplist_allocator;
struct fast_mblock_man *node_allocators; struct fast_mblock_man *node_allocators;
void *arg;
} UniqSkiplistFactory; } UniqSkiplistFactory;
typedef struct uniq_skiplist typedef struct uniq_skiplist
@ -72,15 +75,15 @@ extern "C" {
#define uniq_skiplist_init_ex(factory, max_level_count, compare_func, \ #define uniq_skiplist_init_ex(factory, max_level_count, compare_func, \
free_func, alloc_skiplist_once, min_alloc_elements_once, \ free_func, alloc_skiplist_once, min_alloc_elements_once, \
delay_free_seconds) \ delay_free_seconds, arg) \
uniq_skiplist_init_ex2(factory, max_level_count, compare_func, \ uniq_skiplist_init_ex2(factory, max_level_count, compare_func, \
free_func, alloc_skiplist_once, min_alloc_elements_once, \ free_func, alloc_skiplist_once, min_alloc_elements_once, \
delay_free_seconds, false, false) delay_free_seconds, false, false, arg)
#define uniq_skiplist_init(factory, max_level_count, compare_func, free_func) \ #define uniq_skiplist_init(factory, max_level_count, compare_func, free_func) \
uniq_skiplist_init_ex(factory, max_level_count, \ uniq_skiplist_init_ex(factory, max_level_count, \
compare_func, free_func, 64 * 1024, \ compare_func, free_func, 64 * 1024, \
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE, 0) SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE, 0, NULL)
#define uniq_skiplist_init_pair(pair, init_level_count, max_level_count, \ #define uniq_skiplist_init_pair(pair, init_level_count, max_level_count, \
compare_func, free_func, min_alloc_elements_once, delay_free_seconds) \ compare_func, free_func, min_alloc_elements_once, delay_free_seconds) \
@ -102,7 +105,7 @@ int uniq_skiplist_init_ex2(UniqSkiplistFactory *factory,
const int max_level_count, skiplist_compare_func compare_func, const int max_level_count, skiplist_compare_func compare_func,
uniq_skiplist_free_func free_func, const int alloc_skiplist_once, uniq_skiplist_free_func free_func, const int alloc_skiplist_once,
const int min_alloc_elements_once, const int delay_free_seconds, const int min_alloc_elements_once, const int delay_free_seconds,
const bool bidirection, const bool allocator_use_lock); const bool bidirection, const bool allocator_use_lock, void *arg);
void uniq_skiplist_destroy(UniqSkiplistFactory *factory); void uniq_skiplist_destroy(UniqSkiplistFactory *factory);
@ -124,7 +127,7 @@ static inline int uniq_skiplist_init_pair_ex(UniqSkiplistPair *pair,
if ((result=uniq_skiplist_init_ex2(&pair->factory, max_level_count, if ((result=uniq_skiplist_init_ex2(&pair->factory, max_level_count,
compare_func, free_func, alloc_skiplist_once, compare_func, free_func, alloc_skiplist_once,
min_alloc_elements_once, delay_free_seconds, min_alloc_elements_once, delay_free_seconds,
bidirection, allocator_use_lock)) != 0) bidirection, allocator_use_lock, NULL)) != 0)
{ {
return result; return result;
} }
@ -253,6 +256,8 @@ static inline bool uniq_skiplist_empty(UniqSkiplist *sl)
return sl->top->links[0] == sl->factory->tail; return sl->top->links[0] == sl->factory->tail;
} }
void uniq_skiplist_clear(UniqSkiplist *sl);
#define LEVEL0_DOUBLE_CHAIN_NEXT_LINK(node) node->links[0] #define LEVEL0_DOUBLE_CHAIN_NEXT_LINK(node) node->links[0]
#define LEVEL0_DOUBLE_CHAIN_PREV_LINK(node) node->links[node->level_index + 1] #define LEVEL0_DOUBLE_CHAIN_PREV_LINK(node) node->links[node->level_index + 1]
#define LEVEL0_DOUBLE_CHAIN_TAIL(sl) LEVEL0_DOUBLE_CHAIN_PREV_LINK(sl->top) #define LEVEL0_DOUBLE_CHAIN_TAIL(sl) LEVEL0_DOUBLE_CHAIN_PREV_LINK(sl->top)