Compare commits

...

312 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
YuQing c18e864220 upgrade version to 1.0.63 2022-10-26 09:57:22 +08:00
YuQing 7289215470 sockopt.[hc]: getIpAndPort support ipv6 2022-10-17 15:58:27 +08:00
vazmin b52e516aee gh actions: upgrade to 1.0.62-1 2022-10-08 13:28:15 +00:00
YuQing 9c967d8d4b upgrade version to 1.0.62 2022-10-08 09:27:32 +08:00
YuQing 2b0796b166 fc_itoa small refine 2022-09-29 20:55:05 +08:00
YuQing 6ea757f492 add function fc_itoa 2022-09-28 22:13:57 +08:00
YuQing cf66174cf9 add function fc_sleep_us 2022-09-27 20:28:29 +08:00
vazmin 117b723274 fix: debian/rules Permission denied 2022-09-24 14:40:18 +08:00
vazmin 5e8dc1fcb5 gh actions: upgrade to 1.0.61-1 2022-09-22 12:22:09 +00:00
YuQing c416c6eeb0 upgrade version to 1.0.61 2022-09-22 09:12:38 +08:00
YuQing 88ad619902 add function common_blocked_queue_push_chain 2022-09-21 21:48:34 +08:00
YuQing 47fb7b2abd get_base_path_from_conf_file_ex support parameter: noent_log_level 2022-09-21 11:35:32 +08:00
vazmin 6b70919699 gh actions: upgrade to 1.0.60-1 2022-09-07 13:36:01 +00:00
YuQing a9b0f20f2d upgrade version to 1.0.60 2022-09-04 13:49:44 +08:00
YuQing 48ec9c64c6 add func fc_free_iovec_array 2022-09-04 11:29:13 +08:00
YuQing b0d57b325d export struct fast_allocator_wrapper 2022-08-28 17:20:20 +08:00
YuQing 82bbc013b2 fast_allocator.[hc] support object size 2022-08-27 21:24:16 +08:00
YuQing 7e52e7607a fast_allocator.[hc] support object callbacks 2022-08-27 09:49:20 +08:00
YuQing f47f136f56 add functions: iniGetDoubleCorrectValueEx and iniGetPercentCorrectValueEx 2022-08-26 11:02:36 +08:00
YuQing e11b22ad7d struct fast_task_info add field recv_body for dynamic recv buffer 2022-08-25 18:20:41 +08:00
YuQing ed66409220 normalize_path for base_path 2022-08-20 10:04:25 +08:00
vazmin 51715f26aa gh actions: upgrade to 1.0.59-1 2022-07-25 13:51:25 +00:00
YuQing 68360c1bd1 Merge branch 'replication_quorum' 2022-07-24 15:11:07 +08:00
YuQing 138e06fd6c upgrade version to V1.0.59 2022-07-24 14:57:30 +08:00
YuQing a9e82600b7 add function fc_get_first_lines 2022-07-21 18:30:53 +08:00
YuQing 599d0f1446 add global var g_set_cloexec and macro FC_SET_CLOEXEC 2022-06-25 11:23:43 +08:00
YuQing 4a7d852409 correct O_CLOEXEC to FD_CLOEXEC for F_SETFL 2022-06-25 09:22:25 +08:00
YuQing e254b8e1d3 open file with flag O_CLOEXEC 2022-06-24 18:52:39 +08:00
vazmin fe862d887e gh actions: upgrade to 1.0.58-1 2022-06-15 14:26:02 +00:00
YuQing aa5506191f add struct type FilenameFDPair 2022-06-12 21:24:37 +08:00
YuQing 5a90576bdc libfastcommon.spec: upgrade version 2022-06-06 20:35:56 +08:00
YuQing 7e5acf144b fast_mpool add stat fields: alloc_count, alloc_bytes and reset_count 2022-06-04 22:05:09 +08:00
YuQing 0b539bbba2 json decode supports memory pool for persistency 2022-06-04 12:41:07 +08:00
YuQing 009d33480f tests/test_json_parser.c OK. 2022-06-03 22:03:31 +08:00
YuQing 5f34bc872b add functions common_blocked_queue_empty/count 2022-06-03 15:30:49 +08:00
YuQing 793d683d2a add function fast_mblock_set_exceed_log_level 2022-05-31 18:39:52 +08:00
YuQing 64e9499de6 json decode support unicode 2022-05-29 21:13:00 +08:00
YuQing 275279a264 json_parser.[hc] refined for better performance 2022-05-29 10:55:16 +08:00
YuQing f24c558761 add function iniGetCharValueEx 2022-05-26 10:37:52 +08:00
YuQing 1f83e66306 add function conn_pool_get_connection_ex to support service name 2022-05-08 11:26:17 +08:00
YuQing 630a6a2af6 add function conn_pool_connect_server_ex1 to support service name 2022-05-07 16:53:02 +08:00
vazmin 23628e85f2 gh actions: upgrade to 1.0.57-1 2022-04-28 11:53:21 +00:00
YuQing 082902d28b add macro posix_fadvise for non-Linux 2022-04-24 08:13:44 +08:00
YuQing 5802203f9f upgrade version to V1.0.57 2022-04-22 14:55:55 +08:00
YuQing f836b1a9e2 bugfixed: fc_get_file_line_count_ex should rewind file 2022-04-14 16:48:32 +08:00
YuQing 26abf68ebd fast_mblock.[hc] support object destroy callback 2022-03-17 20:50:06 +08:00
YuQing ba011767f8 add functions: fc_get_path_child_count and fc_copy_file 2022-03-16 11:46:43 +08:00
YuQing 7d5e94f9dd rename fc_format_path to fc_remove_redundant_slashes 2022-03-15 08:51:20 +08:00
YuQing 80b751980b add function fc_format_path 2022-03-14 17:10:43 +08:00
vazmin 776a875c84 add changlog 1.0.56 2022-03-13 17:17:02 +08:00
YuQing 3fd3b167a8 small changes for logger.[hc] 2022-03-09 09:53:36 +08:00
YuQing 08f74db732 add function fc_check_rename_ex 2022-03-09 08:21:07 +08:00
YuQing 6836337d0a upgrade version to 1.0.56 2022-03-03 10:18:19 +08:00
YuQing 1cb1847b29 add function locked_list_destroy 2022-03-01 15:03:22 +08:00
YuQing c9cba5298a php-fastcommon compile OK 2022-02-25 14:48:19 +08:00
YuQing 7b9c257652 rename trim to fc_trim 2022-02-25 09:44:15 +08:00
YuQing 9f1d1b6d48 rename hash_xxx to fc_hash_xxx 2022-02-09 22:35:40 +08:00
YuQing 3331b927b3 add function log_try_init2 2022-02-14 09:41:21 +08:00
YuQing e9d186ce99 make.sh: generate macros for dirent fields 2022-02-10 22:18:53 +08:00
YuQing 29cc5af134 add function fc_iov_get_bytes 2022-02-02 20:37:13 +08:00
YuQing 21cd3a9798 make.sh refined 2022-02-02 09:32:07 +08:00
YuQing 3f20211a52 add const modifier for unification 2022-02-01 21:30:47 +08:00
YuQing a19a0071db sockopt.[hc] support tcpwritev and tcpreadv 2022-01-31 17:03:42 +08:00
YuQing 787eb3a7d6 NULL from parameter for getcwd 2022-01-29 17:18:13 +08:00
YuQing 4b9e2d6517 add function fc_gettid 2022-01-29 15:56:41 +08:00
YuQing 505893dc4c change include <sys/poll.h> to #include <poll.h> 2022-01-28 18:16:28 +08:00
YuQing 34f8c3abb9 correct pthread_rwlockattr getkind_np to setkind_np 2022-01-28 18:05:27 +08:00
YuQing a39005253b check pthread_rwlockattr_getkind_np for porting 2022-01-28 12:44:21 +08:00
vazmin 013b7888ea upgrade version to 1.0.55 2022-01-15 19:56:31 +08:00
YuQing f734710832 upgrade version to 1.0.55 2022-01-13 10:13:06 +08:00
YuQing 0410c7fedd add function sched_delay_free_ptr 2022-01-12 11:03:50 +08:00
YuQing 0381982ac2 function fast_mblock_batch_alloc changed 2022-01-09 15:26:27 +08:00
YuQing af68bf5d6a add macros: fc_queue_notify and fc_queue_notify_all 2022-01-06 20:32:05 +08:00
YuQing 7fbdb0cece add macros: ptr_array_allocator_xxx 2022-01-03 10:24:28 +08:00
YuQing c3f22aa867 fix arginfo_get_next_local_ip parameter 2021-12-31 22:41:57 +08:00
YuQing 89e1a99129 fastcommon php extension adapt to php 8 2021-12-31 03:15:38 +08:00
YuQing 59acf16fae php7_ext_wrapper.h adapt to php 8 2021-12-31 01:51:50 +08:00
vazmin 7fe16fd1b5 update debian package version 2021-12-27 21:34:40 +08:00
YuQing d9097001b5 mblock stat output support order by used ratio 2021-12-24 17:16:39 +08:00
YuQing d5d317f912 fix cmp_mblock_info for fast_mblock_manager_stat 2021-12-24 11:40:52 +08:00
YuQing b4f6152776 upgrade version to 1.0.54 2021-12-23 11:23:45 +08:00
YuQing 750c2c5e8a normalize_path removes prefix one ./ and multi ../ 2021-12-23 10:04:48 +08:00
YuQing fdb6bfb233 fix test_uniq_skiplist.c compile error 2021-12-16 09:44:16 +08:00
YuQing f6c5256264 fast path for sorted_array_insert 2021-12-14 21:18:30 +08:00
YuQing 0c437d3799 array_allocator.[hc] add parameter: need_lock 2021-12-14 21:15:30 +08:00
YuQing 64ae0757d7 pthread_rwlock_init: use NULL attr for non-Linux 2021-12-12 20:43:20 +08:00
YuQing 720c4a686d mblock add macro FAST_MBLOCK_MAGIC_CHECK for debug 2021-12-12 10:16:06 +08:00
YuQing 87377981ec sorted_queue.h: remove useless field: next_ptr_offset 2021-12-10 10:34:47 +08:00
YuQing 740272e303 typedef TaskContinueCallback function pointer 2021-11-28 10:34:01 +08:00
YuQing 4f29fd71eb sorted_array.[hc]: add function sorted_array_delete_by_index 2021-11-17 20:37:18 +08:00
YuQing 976872192a add macros id_name_array_allocator_xxx 2021-11-17 11:41:53 +08:00
YuQing b03963d4f6 add function sorted_array_find and marco sorted_id_name_array_init 2021-11-16 19:47:14 +08:00
YuQing ce2ee0f482 add macros FC_ATOMIC_SET_LARGER/SMALLER 2021-11-10 16:04:42 +08:00
YuQing 9ca9592326 shared_func.[hc]: add function fc_read_lines 2021-10-19 20:29:15 +08:00
YuQing 09e00bcf5e add functions fc_safe_write_file_init/open/close 2021-10-10 14:45:08 +08:00
YuQing a439b8e62d add macro FC_INIT_CHAIN and FC_IS_CHAIN_EMPTY 2021-10-09 20:54:35 +08:00
YuQing 8acd5e031b sched_thread.[hc]: add function sched_make_first_call_time 2021-09-27 15:51:45 +08:00
YuQing 2432e0bc79 add function fc_queue_alloc_chain 2021-09-22 09:25:28 +08:00
YuQing 1b35cbc094 sorted_queue.c: set notify correctly 2021-09-20 10:40:17 +08:00
YuQing 8491c5d155 add comments for sorted_array.h 2021-09-14 10:05:27 +08:00
YuQing 8717f85608 fast_allocator.c: optimize for the region with single allocator 2021-09-14 08:28:03 +08:00
YuQing 55f1e139a9 add file src/tests/test_sorted_array.c 2021-09-13 16:54:09 +08:00
YuQing 2993b34e80 add files: sorted_array.[hc] 2021-09-13 11:18:45 +08:00
YuQing 81950ac246 add function fc_queue_free_chain 2021-09-11 18:40:26 +08:00
YuQing 7614f789c8 add function sorted_queue_pop_to_queue_ex 2021-09-11 11:47:05 +08:00
YuQing f5fa33611f add files: array_allocator.[hc] 2021-09-10 16:36:14 +08:00
YuQing 6957c19992 fast_mblock.[hc]: add function fast_mblock_free_objects 2021-09-09 08:39:51 +08:00
YuQing a66370d0f8 add files: sorted_queue.[hc] 2021-09-02 21:05:09 +08:00
YuQing e1ef38d6a4 add type void_array_t 2021-08-20 11:01:50 +08:00
YuQing 45da326ce2 add types int32_array_t and int64_array_t 2021-08-19 19:28:15 +08:00
YuQing ebe7d87ca4 locked_list.h adds macros: locked_list_empty, locked_list_first_entry etc. 2021-08-17 15:39:01 +08:00
YuQing c6b2c32fe2 add function: fast_allocator_avail_memory 2021-08-17 10:01:42 +08:00
YuQing b7ecd0d4c4 add function init_pthread_rwlock 2021-08-13 21:10:05 +08:00
YuQing 2fafa215fd add function fc_queue_timedpeek 2021-08-11 11:32:23 +08:00
YuQing 44dcf4f821 add functions getFileContentEx1 and getFileContent1 2021-08-08 15:11:29 +08:00
YuQing 47c4eaeb13 fast_allocator.[hc]: correct reclaim_interval logic 2021-08-06 15:18:36 +08:00
zhiming 082a0fbc06 feat debian package
debian clear

deb clean rules

update the shared library install dirs in deb

Update rules

Update rules

Revert "Update rules"

This reverts commit 0d32aec147.
2021-08-03 08:57:12 +08:00
YuQing 3e0f1eb1fc fast_mblock_init_ex1: unify obj name 2021-07-20 20:27:48 +08:00
117 changed files with 12442 additions and 4256 deletions

8
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Makefile.in
src/Makefile
src/tests/Makefile
# Prerequisites
*.d
@ -58,6 +59,13 @@ src/tests/test_pthread_wait
src/tests/test_mutex_lock_perf
src/tests/test_queue_perf
src/tests/test_normalize_path
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
*.swp

157
HISTORY
View File

@ -1,4 +1,161 @@
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
* sockopt.[hc]: getIpAndPort support ipv6
Version 1.62 2022-09-28
* add function fc_sleep_us
* add function fc_itoa
Version 1.61 2022-09-21
* get_base_path_from_conf_file_ex support parameter: noent_log_level
* add function common_blocked_queue_push_chain
Version 1.60 2022-08-27
* normalize_path for base_path
* struct fast_task_info add field recv_body for dynamic recv buffer
* add functions: iniGetDoubleCorrectValueEx and iniGetPercentCorrectValueEx
* fast_allocator.[hc] support object size and callbacks
Version 1.59 2022-07-21
* open file with flag O_CLOEXEC
* add global var g_set_cloexec and macro FC_SET_CLOEXEC
* add function fc_get_first_lines
Version 1.58 2022-06-04
* add function conn_pool_connect_server_ex1 to support service name
* add function conn_pool_get_connection_ex to support service name
* add function iniGetCharValueEx
* json_parser.[hc] refined for better performance
Version 1.57 2022-04-22
* add function fc_format_path
* add functions: fc_get_path_child_count and fc_copy_file
* fast_mblock.[hc] support object destroy callback
* bugfixed: fc_get_file_line_count_ex should rewind file
Version 1.56 2022-03-09
* add function fc_gettid
* function normalize_path: NULL from parameter for getcwd
* sockopt.[hc] support tcpwritev and tcpreadv
* add function fc_iov_get_bytes
* rename hash_xxx to fc_hash_xxx
* rename trim to fc_trim
* add function fc_check_rename_ex
Version 1.55 2022-01-12
* fastcommon php extension adapt to php 8
* function fast_mblock_batch_alloc changed
* add function sched_delay_free_ptr
Version 1.54 2021-12-23
* fast_allocator.[hc]: correct reclaim_interval logic
* shared_func.[hc]: add functions getFileContentEx1 and getFileContent1
* fc_queue.[hc]: add function fc_queue_timedpeek
* pthread_func.[hc]: add function init_pthread_rwlock
* add files: sorted_queue.[hc]
* add files: array_allocator.[hc]
* add files: sorted_array.[hc]
* shared_func.[hc]: add function fc_read_lines
* normalize_path removes prefix one ./ and multi ../
Version 1.53 2021-06-30
* process_action support action status
* uniq_skiplist.h: add function uniq_skiplist_iterator_at

14
INSTALL
View File

@ -6,12 +6,20 @@ Please visit the libfastcommon Home Page for more detail.
English language: https://github.com/happyfish100/libfastcommon
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,
# github address: https://github.com/happyfish100/libfastcommon.git
# gitee address: https://gitee.com/fastdfs100/libfastcommon.git
# the command lines as:
git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon; git checkout V1.0.48
./make.sh clean && ./make.sh && ./make.sh install
cd libfastcommon; git checkout V1.0.83
./make.sh clean && ./make.sh && sudo ./make.sh install

10
debian/README.source vendored
View File

@ -1,10 +0,0 @@
libfastcommon for Debian
-----------------------
<this file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file>
-- zhangchunsheng <zhangchunsheng423@gmail.com> Mon, 24 May 2021 18:54:01 +0800

193
debian/changelog vendored
View File

@ -1,5 +1,192 @@
libfastcommon (1.0.50-1) unstable; urgency=medium
libfastcommon (1.0.83-1) unstable; urgency=medium
* Initial release
* upgrade to 1.0.83-1
-- zhangchunsheng <zhangchunsheng423@gmail.com> Mon, 24 May 2021 18:54:01 +0800
-- 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
* upgrade to 1.0.62-1
-- YuQing <384681@qq.com> Sat, 08 Oct 2022 13:28:15 +0000
libfastcommon (1.0.61-1) unstable; urgency=medium
* upgrade to 1.0.61-1
-- YuQing <384681@qq.com> Thu, 22 Sep 2022 12:22:09 +0000
libfastcommon (1.0.60-1) unstable; urgency=medium
* upgrade to 1.0.60-1
-- YuQing <384681@qq.com> Wed, 07 Sep 2022 13:36:01 +0000
libfastcommon (1.0.59-1) unstable; urgency=medium
* upgrade to 1.0.59-1
-- YuQing <384681@qq.com> Mon, 25 Jul 2022 13:51:25 +0000
libfastcommon (1.0.58-1) unstable; urgency=medium
* upgrade to 1.0.58-1
-- YuQing <384681@qq.com> Wed, 15 Jun 2022 14:26:02 +0000
libfastcommon (1.0.57-1) unstable; urgency=medium
* upgrade to 1.0.57-1
-- YuQing <384681@qq.com> Thu, 28 Apr 2022 11:53:21 +0000
libfastcommon (1.0.56-1) unstable; urgency=medium
* check pthread_rwlockattr_getkind_np for porting
* correct pthread_rwlockattr getkind_np to setkind_np
* change include <sys/poll.h> to #include <poll.h>
* add function fc_gettid
* NULL from parameter for getcwd
* sockopt.[hc] support tcpwritev and tcpreadv
* add const modifier for unification
* make.sh refined
* add function fc_iov_get_bytes
* make.sh: generate macros for dirent fields
* add function log_try_init2
* rename hash_xxx to fc_hash_xxx
* rename trim to fc_trim
* php-fastcommon compile OK
* add function locked_list_destroy
* upgrade version to 1.0.56
* add function fc_check_rename_ex
* small changes for logger.[hc]
-- YuQing <384681@qq.com> Sun, 13 Mar 2022 16:43:08 +0800
libfastcommon (1.0.55-1) unstable; urgency=medium
* upgrade version to 1.0.55
-- YuQing <384681@qq.com> Sat, 15 Jan 2022 19:50:26 +0800
libfastcommon (1.0.54-1) unstable; urgency=medium
* upgrade version to 1.0.54
-- YuQing <384681@qq.com> Sun, 26 Dec 2021 20:29:05 +0800
libfastcommon (1.0.53-1) unstable; urgency=medium
* open for write MUST have the third parameter: mode
* uniq_skiplist.h: add function uniq_skiplist_iterator_at
* process_action support action status
-- YuQing <384681@qq.com> Tue, 6 Jul 2021 21:23:31 +0800

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
11

28
debian/control vendored
View File

@ -1,15 +1,25 @@
Source: libfastcommon
Section: zhangchunsheng
Section: libs
Priority: optional
Maintainer: zhangchunsheng <zhangchunsheng423@gmail.com>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.4.1
Homepage: <insert the upstream URL, if relevant>
#Vcs-Browser: https://salsa.debian.org/debian/libfastcommon
#Vcs-Git: https://salsa.debian.org/debian/libfastcommon.git
Maintainer: YuQing <384681@qq.com>
Build-Depends: debhelper (>=11~)
Standards-Version: 4.1.4
Homepage: http://github.com/happyfish100/libfastcommon/
Package: libfastcommon-dev
Architecture: any
Section: libdevel
Depends: libfastcommon (= ${binary:Version}), ${misc:Depends}
Description: libfastcommon (development files)
This package contains header files.
Package: libfastcommon
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>
Description: c common functions library
c common functions library extracted from my open source projects FastDFS and
FastDHT. this library is very simple and stable.
.
some functions are wrappered into php extension, such as fastcommon_gethostaddrs,
fastcommon_id_generator_xxx, fastcommon_get_ifconfigs, fastcommon_get_sysinfo etc.

567
debian/copyright vendored
View File

@ -1,43 +1,530 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: libfastcommon
Upstream-Contact: <preferred name and address to reach the upstream project>
Source: <url://example.com>
Files: *
Copyright: <years> <put author's name and email here>
<years> <likewise for another author>
License: <special license>
<Put the license of the package here indented by 1 space>
<This follows the format of Description: lines in control file>
.
<Including paragraphs>
# If you want to use GPL v2 or later for the /debian/* files use
# the following clauses, or change it to suit. Delete these two lines
Files: debian/*
Copyright: 2021 zhangchunsheng <zhangchunsheng423@gmail.com>
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This package 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. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
# Please avoid picking licenses with terms that are more restrictive than the
# packaged work, as it may make Debian's contributions unacceptable upstream.
Source: http://github.com/happyfish100/libfastcommon/
#
# If you need, there are some extra license texts available in two places:
# /usr/share/debhelper/dh_make/licenses/
# /usr/share/common-licenses/
# Please double check copyright with the licensecheck(1) command.
Files: php-fastcommon/fastcommon.c
php-fastcommon/fastcommon.h
src/avl_tree.c
src/avl_tree.h
src/base64.c
src/buffered_file_writer.c
src/buffered_file_writer.h
src/chain.c
src/chain.h
src/char_convert_loader.c
src/char_convert_loader.h
src/char_converter.c
src/char_converter.h
src/common_blocked_queue.c
src/common_blocked_queue.h
src/common_define.h
src/connection_pool.c
src/connection_pool.h
src/fast_allocator.c
src/fast_allocator.h
src/fast_blocked_queue.c
src/fast_blocked_queue.h
src/fast_buffer.c
src/fast_buffer.h
src/fast_mblock.c
src/fast_mblock.h
src/fast_mpool.c
src/fast_mpool.h
src/fast_task_queue.c
src/fast_task_queue.h
src/fast_timer.c
src/fast_timer.h
src/fc_atomic.h
src/fc_memory.c
src/fc_memory.h
src/fc_queue.c
src/fc_queue.h
src/flat_skiplist.c
src/flat_skiplist.h
src/hash.c
src/hash.h
src/http_func.h
src/id_generator.c
src/ini_file_reader.c
src/ini_file_reader.h
src/ioevent.c
src/ioevent.h
src/ioevent_loop.c
src/ioevent_loop.h
src/json_parser.c
src/json_parser.h
src/local_ip_func.c
src/local_ip_func.h
src/locked_timer.c
src/locked_timer.h
src/logger.c
src/multi_skiplist.c
src/multi_skiplist.h
src/multi_socket_client.c
src/multi_socket_client.h
src/process_ctrl.c
src/process_ctrl.h
src/pthread_func.c
src/pthread_func.h
src/sched_thread.c
src/sched_thread.h
src/server_id_func.c
src/server_id_func.h
src/shared_buffer.c
src/shared_buffer.h
src/shared_func.c
src/shared_func.h
src/skiplist_common.h
src/skiplist_set.c
src/system_info.c
src/system_info.h
src/tests/test_allocator.c
src/tests/test_atomic.c
src/tests/test_blocked_queue.c
src/tests/test_char_convert.c
src/tests/test_char_convert_loader.c
src/tests/test_crc32.c
src/tests/test_data_visible.c
src/tests/test_file_lock.c
src/tests/test_file_write_hole.c
src/tests/test_id_generator.c
src/tests/test_ini_parser.c
src/tests/test_json_parser.c
src/tests/test_logger.c
src/tests/test_mblock.c
src/tests/test_multi_skiplist.c
src/tests/test_mutex_lock_perf.c
src/tests/test_normalize_path.c
src/tests/test_pipe.c
src/tests/test_pthread_lock.c
src/tests/test_pthread_wait.c
src/tests/test_queue_perf.c
src/tests/test_sched_thread.c
src/tests/test_server_id_func.c
src/tests/test_skiplist.c
src/tests/test_skiplist_set.c
src/tests/test_split_string.c
src/tests/test_thourands_seperator.c
src/tests/test_thread_pool.c
src/tests/test_uniq_skiplist.c
src/thread_pool.c
src/thread_pool.h
src/uniq_skiplist.c
src/uniq_skiplist.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: .gitignore
HISTORY
INSTALL
debian/README.Debian
debian/compat
debian/control
debian/libfastcommon-dev.install
debian/libfastcommon.install
debian/rules
debian/source/format
debian/watch
doc/id_generator-Chinese.md
doc/ini_file_reader-Chinese.md
doc/php_log_file_performance-Chinese.md
libfastcommon.spec
make.sh
php-fastcommon/config.m4
php-fastcommon/fastcommon.ini
php-fastcommon/php-fastcommon.spec.in
src/Makefile.in
src/fast_link_library.sh
src/fc_list.h
src/io_opt.c
src/io_opt.h
src/locked_list.h
src/md5.c
src/md5.h
src/tests/Makefile
src/tests/servers.conf
src/tests/test.ini
Copyright: __NO_COPYRIGHT_NOR_LICENSE__
License: __NO_COPYRIGHT_NOR_LICENSE__
Files: src/skiplist.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
skiplist.h, support stable sort :)
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/skiplist_set.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
a set implemented by skiplist, the entry can occur only once
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/sockopt.c
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
socketopt.c
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/sockopt.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
socketopt.h
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/http_func.c
Copyright: 2008 Happy Fish / YuQing
2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
FastDFS may be copied only under the terms of the GNU General
Public License V3, which may be found in the FastDFS source kit.
Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/id_generator.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
64 bits id generator for multi processes, the generated id format:
32 bits timestamp + X bits machine id + Y bits of extra data + Z bits serial number
such as 12 bits machine id, 0 bits extra data and 20 bits serial number
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/php7_ext_wrapper.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
php7 extension wrapper
for compatibility, these wrapper functions are designed for old php version.
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/base64.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
base64.h
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: src/logger.h
Copyright: 2020 YuQing <384681@qq.com>
License: GPL-3.0+
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/>.
.
logger.h
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: README
Copyright: 2010 Happy Fish / YuQing
License: __UNKNOWN__
libfastcommon may be copied only under the terms of the Less GNU General
Public License(LGPL).
Please visit the libfastcommon Home Page for more detail.
English language: https://github.com/happyfish100/libfastcommon
Chinese language: http://www.fastken.com/
.
c common functions library extracted from my open source projects FastDFS and
FastDHT. this library is very simple and stable.
#----------------------------------------------------------------------------
# xml and html files (skipped):
# php-fastcommon/test_file_put_contents.php
# php-fastcommon/test.php
# php-fastcommon/test_error_log.php
#----------------------------------------------------------------------------
# Files marked as NO_LICENSE_TEXT_FOUND may be covered by the following
# license/copyright files.
#----------------------------------------------------------------------------
# License file: LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
.
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
.
.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
.
0. Additional Definitions.
.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
.
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
.
1. Exception to Section 3 of the GNU GPL.
.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
.
2. Conveying Modified Versions.
.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
.
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
.
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
.
3. Object Code Incorporating Material from Library Header Files.
.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
.
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
.
4. Combined Works.
.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
.
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
.
d) Do one of the following:
.
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
.
5. Combined Libraries.
.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
.
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
.
6. Revised Versions of the GNU Lesser General Public License.
.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

1
debian/libfastcommon-dev.install vendored Normal file
View File

@ -0,0 +1 @@
usr/include/fastcommon/*

View File

@ -1,2 +0,0 @@
README.Debian
README.source

View File

@ -1,4 +0,0 @@
#
# Regular cron jobs for the libfastcommon package
#
0 4 * * * root [ -x /usr/bin/libfastcommon_maintenance ] && /usr/bin/libfastcommon_maintenance

View File

@ -1,20 +0,0 @@
Document: libfastcommon
Title: Debian libfastcommon Manual
Author: <insert document author here>
Abstract: This manual describes what libfastcommon is
and how it can be used to
manage online manuals on Debian systems.
Section: zhangchunsheng
Format: debiandoc-sgml
Files: /usr/share/doc/libfastcommon/libfastcommon.sgml.gz
Format: postscript
Files: /usr/share/doc/libfastcommon/libfastcommon.ps.gz
Format: text
Files: /usr/share/doc/libfastcommon/libfastcommon.text.gz
Format: HTML
Index: /usr/share/doc/libfastcommon/html/index.html
Files: /usr/share/doc/libfastcommon/html/*.html

View File

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

56
debian/manpage.1.ex vendored
View File

@ -1,56 +0,0 @@
.\" Hey, EMACS: -*- nroff -*-
.\" (C) Copyright 2021 zhangchunsheng <zhangchunsheng423@gmail.com>,
.\"
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH Libfastcommon SECTION "May 24 2021"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
libfastcommon \- program to do something
.SH SYNOPSIS
.B libfastcommon
.RI [ options ] " files" ...
.br
.B bar
.RI [ options ] " files" ...
.SH DESCRIPTION
This manual page documents briefly the
.B libfastcommon
and
.B bar
commands.
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBlibfastcommon\fP is a program that...
.SH OPTIONS
These programs follow the usual GNU command line syntax, with long
options starting with two dashes (`-').
A summary of options is included below.
For a complete description, see the Info files.
.TP
.B \-h, \-\-help
Show summary of options.
.TP
.B \-v, \-\-version
Show version of program.
.SH SEE ALSO
.BR bar (1),
.BR baz (1).
.br
The programs are documented fully by
.IR "The Rise and Fall of a Fooish Bar" ,
available via the Info system.

154
debian/manpage.sgml.ex vendored
View File

@ -1,154 +0,0 @@
<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
<!-- Process this file with docbook-to-man to generate an nroff manual
page: `docbook-to-man manpage.sgml > manpage.1'. You may view
the manual page with: `docbook-to-man manpage.sgml | nroff -man |
less'. A typical entry in a Makefile or Makefile.am is:
manpage.1: manpage.sgml
docbook-to-man $< > $@
The docbook-to-man binary is found in the docbook-to-man package.
Please remember that if you create the nroff version in one of the
debian/rules file targets (such as build), you will need to include
docbook-to-man in your Build-Depends control field.
-->
<!-- Fill in your name for FIRSTNAME and SURNAME. -->
<!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
<!ENTITY dhsurname "<surname>SURNAME</surname>">
<!-- Please adjust the date whenever revising the manpage. -->
<!ENTITY dhdate "<date>May 24 2021</date>">
<!-- SECTION should be 1-8, maybe w/ subsection other parameters are
allowed: see man(7), man(1). -->
<!ENTITY dhsection "<manvolnum>SECTION</manvolnum>">
<!ENTITY dhemail "<email>zhangchunsheng423@gmail.com</email>">
<!ENTITY dhusername "zhangchunsheng">
<!ENTITY dhucpackage "<refentrytitle>Libfastcommon</refentrytitle>">
<!ENTITY dhpackage "libfastcommon">
<!ENTITY debian "<productname>Debian</productname>">
<!ENTITY gnu "<acronym>GNU</acronym>">
<!ENTITY gpl "&gnu; <acronym>GPL</acronym>">
]>
<refentry>
<refentryinfo>
<address>
&dhemail;
</address>
<author>
&dhfirstname;
&dhsurname;
</author>
<copyright>
<year>2003</year>
<holder>&dhusername;</holder>
</copyright>
&dhdate;
</refentryinfo>
<refmeta>
&dhucpackage;
&dhsection;
</refmeta>
<refnamediv>
<refname>&dhpackage;</refname>
<refpurpose>program to do something</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>&dhpackage;</command>
<arg><option>-e <replaceable>this</replaceable></option></arg>
<arg><option>--example <replaceable>that</replaceable></option></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>This manual page documents briefly the
<command>&dhpackage;</command> and <command>bar</command>
commands.</para>
<para>This manual page was written for the &debian; distribution
because the original program does not have a manual page.
Instead, it has documentation in the &gnu;
<application>Info</application> format; see below.</para>
<para><command>&dhpackage;</command> is a program that...</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<para>These programs follow the usual &gnu; command line syntax,
with long options starting with two dashes (`-'). A summary of
options is included below. For a complete description, see the
<application>Info</application> files.</para>
<variablelist>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option>
<option>--version</option>
</term>
<listitem>
<para>Show version of program.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>bar (1), baz (1).</para>
<para>The programs are documented fully by <citetitle>The Rise and
Fall of a Fooish Bar</citetitle> available via the
<application>Info</application> system.</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para>This manual page was written by &dhusername; &dhemail; for
the &debian; system (and may be used by others). Permission is
granted to copy, distribute and/or modify this document under
the terms of the &gnu; General Public License, Version 2 any
later version published by the Free Software Foundation.
</para>
<para>
On Debian systems, the complete text of the GNU General Public
License can be found in /usr/share/common-licenses/GPL.
</para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:2
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:nil
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->

291
debian/manpage.xml.ex vendored
View File

@ -1,291 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!--
`xsltproc -''-nonet \
-''-param man.charmap.use.subset "0" \
-''-param make.year.ranges "1" \
-''-param make.single.year.ranges "1" \
/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl \
manpage.xml'
A manual page <package>.<section> will be generated. You may view the
manual page with: nroff -man <package>.<section> | less'. A typical entry
in a Makefile or Makefile.am is:
DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl
XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
manpage.1: manpage.xml
$(XP) $(DB2MAN) $<
The xsltproc binary is found in the xsltproc package. The XSL files are in
docbook-xsl. A description of the parameters you can use can be found in the
docbook-xsl-doc-* packages. Please remember that if you create the nroff
version in one of the debian/rules file targets (such as build), you will need
to include xsltproc and docbook-xsl in your Build-Depends control field.
Alternatively use the xmlto command/package. That will also automatically
pull in xsltproc and docbook-xsl.
Notes for using docbook2x: docbook2x-man does not automatically create the
AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as
<refsect1> ... </refsect1>.
To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections
read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be
found in the docbook-xsl-doc-html package.
Validation can be done using: `xmllint -''-noout -''-valid manpage.xml`
General documentation about man-pages and man-page-formatting:
man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
-->
<!-- Fill in your name for FIRSTNAME and SURNAME. -->
<!ENTITY dhfirstname "FIRSTNAME">
<!ENTITY dhsurname "SURNAME">
<!-- dhusername could also be set to "&dhfirstname; &dhsurname;". -->
<!ENTITY dhusername "zhangchunsheng">
<!ENTITY dhemail "zhangchunsheng423@gmail.com">
<!-- SECTION should be 1-8, maybe w/ subsection other parameters are
allowed: see man(7), man(1) and
http://www.tldp.org/HOWTO/Man-Page/q2.html. -->
<!ENTITY dhsection "SECTION">
<!-- TITLE should be something like "User commands" or similar (see
http://www.tldp.org/HOWTO/Man-Page/q2.html). -->
<!ENTITY dhtitle "libfastcommon User Manual">
<!ENTITY dhucpackage "Libfastcommon">
<!ENTITY dhpackage "libfastcommon">
]>
<refentry>
<refentryinfo>
<title>&dhtitle;</title>
<productname>&dhpackage;</productname>
<authorgroup>
<author>
<firstname>&dhfirstname;</firstname>
<surname>&dhsurname;</surname>
<contrib>Wrote this manpage for the Debian system.</contrib>
<address>
<email>&dhemail;</email>
</address>
</author>
</authorgroup>
<copyright>
<year>2007</year>
<holder>&dhusername;</holder>
</copyright>
<legalnotice>
<para>This manual page was written for the Debian system
(and may be used by others).</para>
<para>Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU General Public License,
Version 2 or (at your option) any later version published by
the Free Software Foundation.</para>
<para>On Debian systems, the complete text of the GNU General Public
License can be found in
<filename>/usr/share/common-licenses/GPL</filename>.</para>
</legalnotice>
</refentryinfo>
<refmeta>
<refentrytitle>&dhucpackage;</refentrytitle>
<manvolnum>&dhsection;</manvolnum>
</refmeta>
<refnamediv>
<refname>&dhpackage;</refname>
<refpurpose>program to do something</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>&dhpackage;</command>
<!-- These are several examples, how syntaxes could look -->
<arg choice="plain"><option>-e <replaceable>this</replaceable></option></arg>
<arg choice="opt"><option>--example=<parameter>that</parameter></option></arg>
<arg choice="opt">
<group choice="req">
<arg choice="plain"><option>-e</option></arg>
<arg choice="plain"><option>--example</option></arg>
</group>
<replaceable class="option">this</replaceable>
</arg>
<arg choice="opt">
<group choice="req">
<arg choice="plain"><option>-e</option></arg>
<arg choice="plain"><option>--example</option></arg>
</group>
<group choice="req">
<arg choice="plain"><replaceable>this</replaceable></arg>
<arg choice="plain"><replaceable>that</replaceable></arg>
</group>
</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>&dhpackage;</command>
<!-- Normally the help and version options make the programs stop
right after outputting the requested information. -->
<group choice="opt">
<arg choice="plain">
<group choice="req">
<arg choice="plain"><option>-h</option></arg>
<arg choice="plain"><option>--help</option></arg>
</group>
</arg>
<arg choice="plain">
<group choice="req">
<arg choice="plain"><option>-v</option></arg>
<arg choice="plain"><option>--version</option></arg>
</group>
</arg>
</group>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1 id="description">
<title>DESCRIPTION</title>
<para>This manual page documents briefly the
<command>&dhpackage;</command> and <command>bar</command>
commands.</para>
<para>This manual page was written for the Debian distribution
because the original program does not have a manual page.
Instead, it has documentation in the GNU <citerefentry>
<refentrytitle>info</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry> format; see below.</para>
<para><command>&dhpackage;</command> is a program that...</para>
</refsect1>
<refsect1 id="options">
<title>OPTIONS</title>
<para>The program follows the usual GNU command line syntax,
with long options starting with two dashes (`-'). A summary of
options is included below. For a complete description, see the
<citerefentry>
<refentrytitle>info</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry> files.</para>
<variablelist>
<!-- Use the variablelist.term.separator and the
variablelist.term.break.after parameters to
control the term elements. -->
<varlistentry>
<term><option>-e <replaceable>this</replaceable></option></term>
<term><option>--example=<replaceable>that</replaceable></option></term>
<listitem>
<para>Does this and that.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option></term>
<term><option>--help</option></term>
<listitem>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<term><option>--version</option></term>
<listitem>
<para>Show version of program.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="files">
<title>FILES</title>
<variablelist>
<varlistentry>
<term><filename>/etc/foo.conf</filename></term>
<listitem>
<para>The system-wide configuration file to control the
behaviour of <application>&dhpackage;</application>. See
<citerefentry>
<refentrytitle>foo.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry> for further details.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>${HOME}/.foo.conf</filename></term>
<listitem>
<para>The per-user configuration file to control the
behaviour of <application>&dhpackage;</application>. See
<citerefentry>
<refentrytitle>foo.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry> for further details.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="environment">
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry>
<term><envar>FOO_CONF</envar></term>
<listitem>
<para>If used, the defined file is used as configuration
file (see also <xref linkend="files"/>).</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="diagnostics">
<title>DIAGNOSTICS</title>
<para>The following diagnostics may be issued
on <filename class="devicefile">stderr</filename>:</para>
<variablelist>
<varlistentry>
<term><errortext>Bad configuration file. Exiting.</errortext></term>
<listitem>
<para>The configuration file seems to contain a broken configuration
line. Use the <option>--verbose</option> option, to get more info.
</para>
</listitem>
</varlistentry>
</variablelist>
<para><command>&dhpackage;</command> provides some return codes, that can
be used in scripts:</para>
<segmentedlist>
<segtitle>Code</segtitle>
<segtitle>Diagnostic</segtitle>
<seglistitem>
<seg><errorcode>0</errorcode></seg>
<seg>Program exited successfully.</seg>
</seglistitem>
<seglistitem>
<seg><errorcode>1</errorcode></seg>
<seg>The configuration file seems to be broken.</seg>
</seglistitem>
</segmentedlist>
</refsect1>
<refsect1 id="bugs">
<!-- Or use this section to tell about upstream BTS. -->
<title>BUGS</title>
<para>The program is currently limited to only work
with the <package>foobar</package> library.</para>
<para>The upstreams <acronym>BTS</acronym> can be found
at <ulink url="http://bugzilla.foo.tld"/>.</para>
</refsect1>
<refsect1 id="see_also">
<title>SEE ALSO</title>
<!-- In alpabetical order. -->
<para><citerefentry>
<refentrytitle>bar</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>, <citerefentry>
<refentrytitle>baz</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>, <citerefentry>
<refentrytitle>foo.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry></para>
<para>The programs are documented fully by <citetitle>The Rise and
Fall of a Fooish Bar</citetitle> available via the <citerefentry>
<refentrytitle>info</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry> system.</para>
</refsect1>
</refentry>

39
debian/postinst.ex vendored
View File

@ -1,39 +0,0 @@
#!/bin/sh
# postinst script for libfastcommon
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with zhangchunsheng argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

37
debian/postrm.ex vendored
View File

@ -1,37 +0,0 @@
#!/bin/sh
# postrm script for libfastcommon
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with zhangchunsheng argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

35
debian/preinst.ex vendored
View File

@ -1,35 +0,0 @@
#!/bin/sh
# preinst script for libfastcommon
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
;;
abort-upgrade)
;;
*)
echo "preinst called with zhangchunsheng argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

38
debian/prerm.ex vendored
View File

@ -1,38 +0,0 @@
#!/bin/sh
# prerm script for libfastcommon
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
;;
failed-upgrade)
;;
*)
echo "prerm called with zhangchunsheng argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

24
debian/rules vendored
View File

@ -1,24 +1,14 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#export DH_VERBOSE = 1
# see FEATURE AREAS in dpkg-buildflags(1)
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# see ENVIRONMENT in dpkg-buildflags(1)
# package maintainers to append CFLAGS
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
# package maintainers to append LDFLAGS
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
export DESTDIR = $(CURDIR)/debian/tmp
%:
dh $@
# dh_make generated override targets
# This is example for Cmake (See https://bugs.debian.org/641051 )
#override_dh_auto_configure:
# dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
override_dh_auto_build:
./make.sh clean && ./make.sh
override_dh_auto_install:
./make.sh install
dh_auto_install

View File

@ -1,11 +0,0 @@
# For more information on what jobs are run see:
# https://salsa.debian.org/salsa-ci-team/pipeline
#
# To enable the jobs, go to your repository (at salsa.debian.org)
# and click over Settings > CI/CD > Expand (in General pipelines).
# In "Custom CI config path" write debian/salsa-ci.yml and click
# in "Save Changes". The CI tests will run after the next commit.
---
include:
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml

3
debian/watch vendored Normal file
View File

@ -0,0 +1,3 @@
version=3
opts="mode=git" https://github.com/happyfish100/libfastcommon.git \
refs/tags/v([\d\.]+) debian uupdate

38
debian/watch.ex vendored
View File

@ -1,38 +0,0 @@
# Example watch control file for uscan
# Rename this file to "watch" and then you can run the "uscan" command
# to check for upstream updates and more.
# See uscan(1) for format
# Compulsory line, this is a version 4 file
version=4
# PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig
#opts="pgpsigurlmangle=s%$%.sig%"
# HTTP site (basic)
#http://example.com/downloads.html \
# files/libfastcommon-([\d\.]+)\.tar\.gz debian uupdate
# Uncomment to examine an FTP server
#ftp://ftp.example.com/pub/libfastcommon-(.*)\.tar\.gz debian uupdate
# SourceForge hosted projects
# http://sf.net/libfastcommon/ libfastcommon-(.*)\.tar\.gz debian uupdate
# GitHub hosted projects
#opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%<project>-$1.tar.gz%" \
# https://github.com/<user>/libfastcommon/tags \
# (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate
# PyPI
# https://pypi.debian.net/libfastcommon/libfastcommon-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
# Direct Git
# opts="mode=git" http://git.example.com/libfastcommon.git \
# refs/tags/v([\d\.]+) debian uupdate
# Uncomment to find new files on GooglePages
# http://example.googlepages.com/foo.html libfastcommon-(.*)\.tar\.gz

View File

@ -1,10 +1,9 @@
%define LibFastcommonDevel libfastcommon-devel
%define LibFastcommonDebuginfo libfastcommon-debuginfo
%define CommitVersion %(echo $COMMIT_VERSION)
Name: libfastcommon
Version: 1.0.53
Version: 1.0.83
Release: 1%{?dist}
Summary: c common functions library extracted from my open source projects FastDFS
License: LGPL
@ -12,17 +11,25 @@ Group: Arch/Tech
URL: http://github.com/happyfish100/libfastcommon/
Source: http://github.com/happyfish100/libfastcommon/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: libcurl-devel
Requires: libcurl
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
c common functions library extracted from my open source projects FastDFS.
this library is very simple and stable. functions including: string, logger,
chain, hash, socket, ini file reader, base64 encode / decode,
url encode / decode, fasttimer etc.
url encode / decode, fasttimer etc.
commit version: %{CommitVersion}
%package devel

144
make.sh
View File

@ -1,3 +1,9 @@
GCC_VERSION=$(gcc -dM -E - < /dev/null | grep -w __GNUC__ | awk '{print $NF;}')
if [ -z "$GCC_VERSION" ]; then
echo -e "gcc not found, please install gcc first\n" 1>&2
exit 2
fi
tmp_src_filename=fast_check_bits.c
cat <<EOF > $tmp_src_filename
#include <stdio.h>
@ -7,56 +13,82 @@ int main()
{
printf("%d\n", (int)sizeof(void*));
printf("%d\n", (int)sizeof(off_t));
#ifdef __GLIBC_MINOR__
printf("%d\n", __GLIBC_MINOR__);
#endif
return 0;
}
EOF
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
output=`./a.out`
output=$(./a.out)
if [ $? -ne 0 ]; then
echo -e "Can't find a.out program\n" 1>&2
exit 2
fi
if [ -f /bin/expr ]; then
EXPR=/bin/expr
else
elif [ -f /usr/bin/expr ]; then
EXPR=/usr/bin/expr
else
EXPR=$(which expr)
if [ $? -ne 0 ]; then
echo -e "Can't find expr program\n" 1>&2
exit 2
fi
fi
count=0
int_bytes=4
off_bytes=8
glibc_minor=0
LIB_VERSION=lib64
for col in $output; do
if [ $count -eq 0 ]; then
int_bytes=$col
else
elif [ $count -eq 1 ]; then
off_bytes=$col
else
glibc_minor=$col
fi
count=`$EXPR $count + 1`
count=$($EXPR $count + 1)
done
/bin/rm -f a.out $tmp_src_filename
uname=$(uname)
TARGET_PREFIX=$DESTDIR/usr
if [ "$int_bytes" -eq 8 ]; then
OS_BITS=64
LIB_VERSION=lib64
OS_BITS=64
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
OS_BITS=32
LIB_VERSION=lib
OS_BITS=32
LIB_VERSION=lib
fi
if [ "$off_bytes" -eq 8 ]; then
OFF_BITS=64
OFF_BITS=64
else
OFF_BITS=32
OFF_BITS=32
fi
DEBUG_FLAG=0
export CC=gcc
CFLAGS='-Wall'
GCC_VERSION=$(gcc -dM -E - < /dev/null | grep -w __GNUC__ | awk '{print $NF;}')
if [ -n "$GCC_VERSION" ] && [ $GCC_VERSION -ge 7 ]; then
CFLAGS="$CFLAGS -Wformat-truncation=0 -Wformat-overflow=0"
fi
@ -67,6 +99,7 @@ else
CFLAGS="$CFLAGS -g -O3"
fi
INCS=''
LIBS='-lm -ldl'
if [ -f /usr/include/curl/curl.h ] || [ -f /usr/local/include/curl/curl.h ]; then
CFLAGS="$CFLAGS -DUSE_LIBCURL"
@ -79,14 +112,33 @@ HAVE_VMMETER_H=0
HAVE_USER_H=0
if [ "$uname" = "Linux" ]; then
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
OS_NAME=OS_FREEBSD
IOEVENT_USE=IOEVENT_USE_KQUEUE
if [ "$uname" = "Darwin" ]; then
CFLAGS="$CFLAGS -DDARWIN"
TARGET_PREFIX=$TARGET_PREFIX/local
LIB_VERSION=lib
else
INCS="$INCS -I/usr/local/include"
LIBS="$LIBS -L/usr/local/lib"
fi
if [ -f /usr/include/sys/vmmeter.h ]; then
@ -113,6 +165,36 @@ else
IOEVENT_USE=IOEVENT_USE_NONE
fi
check_dirent_field()
{
field_name=$1
upper_fname=$(echo $field_name | tr '[a-z]' '[A-Z]')
tmp_src_filename=fast_check_dirent.c
cat <<EOF > $tmp_src_filename
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
struct dirent dir;
dir.$field_name = 1;
printf("#define HAVE_DIRENT_$upper_fname %d\n", dir.$field_name);
return 0;
}
EOF
gcc -o a.out $tmp_src_filename 2>/dev/null && ./a.out
/bin/rm -f a.out $tmp_src_filename
}
tmp_filename=fast_dirent_macros.txt
check_dirent_field d_type > $tmp_filename
check_dirent_field d_reclen >> $tmp_filename
check_dirent_field d_namlen >> $tmp_filename
check_dirent_field d_off >> $tmp_filename
cat <<EOF > src/_os_define.h
#ifndef _OS_DEFINE_H
#define _OS_DEFINE_H
@ -135,13 +217,35 @@ cat <<EOF > src/_os_define.h
#ifndef HAVE_USER_H
#define HAVE_USER_H $HAVE_USER_H
#endif
$(cat $tmp_filename && /bin/rm -f $tmp_filename)
#endif
EOF
if [ -f /usr/lib/libpthread.so ] || [ -f /usr/local/lib/libpthread.so ] || [ -f /usr/lib64/libpthread.so ] || [ -f /usr/lib/libpthread.a ] || [ -f /usr/local/lib/libpthread.a ] || [ -f /usr/lib64/libpthread.a ]; then
pthread_path=''
for path in /lib /lib64 /usr/lib /usr/lib64 /usr/local/lib; do
if [ -d $path ]; then
pthread_path=$(find $path -name libpthread.so | head -n 1)
if [ -n "$pthread_path" ]; then
break
fi
pthread_path=$(find $path -name libpthread.a | head -n 1)
if [ -n "$pthread_path" ]; then
break
fi
fi
done
if [ -n "$pthread_path" ]; then
LIBS="$LIBS -lpthread"
line=$(nm $pthread_path 2>/dev/null | grep -F pthread_rwlockattr_setkind_np | grep -w T)
if [ -n "$line" ]; then
CFLAGS="$CFLAGS -DWITH_PTHREAD_RWLOCKATTR_SETKIND_NP=1"
fi
elif [ -f /usr/lib/libc_r.so ]; then
line=`nm -D /usr/lib/libc_r.so | 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
LIBS="$LIBS -lc_r"
fi
@ -160,7 +264,9 @@ sed_replace()
cd src
cp Makefile.in Makefile
sed_replace "s#\\\$(CC)#gcc#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#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile
sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile
@ -170,3 +276,11 @@ if [ "$1" = "clean" ]; then
/bin/rm -f Makefile _os_define.h
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

@ -12,7 +12,6 @@
* 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 "php7_ext_wrapper.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
@ -94,26 +93,111 @@ const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, N
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_version, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_gethostaddrs, 0, 0, 0)
ZEND_ARG_INFO(0, if_alias_prefix)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_time33_hash, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_simple_hash, 0, 0, 1)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_line_distance_km, 0, 0, 4)
ZEND_ARG_INFO(0, lat1)
ZEND_ARG_INFO(0, lon1)
ZEND_ARG_INFO(0, lat2)
ZEND_ARG_INFO(0, lon2)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_first_local_ip, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_next_local_ip, 0, 0, 1)
ZEND_ARG_INFO(0, previous_ip)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_is_private_ip, 0, 0, 1)
ZEND_ARG_INFO(0, ip)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_init, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, machine_id)
ZEND_ARG_INFO(0, mid_bits)
ZEND_ARG_INFO(0, extra_bits)
ZEND_ARG_INFO(0, sn_bits)
ZEND_ARG_INFO(0, mode)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_next, 0, 0, 0)
ZEND_ARG_INFO(0, extra)
ZEND_ARG_INFO(0, handle)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_get_extra, 0, 0, 1)
ZEND_ARG_INFO(0, id)
ZEND_ARG_INFO(0, handle)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_get_timestamp, 0, 0, 1)
ZEND_ARG_INFO(0, id)
ZEND_ARG_INFO(0, handle)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_destroy, 0, 0, 0)
ZEND_ARG_INFO(0, handle)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_ifconfigs, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_cpu_count, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_sysinfo, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_error_log, 0, 0, 1)
ZEND_ARG_INFO(0, message)
ZEND_ARG_INFO(0, message_type)
ZEND_ARG_INFO(0, destination)
ZEND_ARG_INFO(0, headers)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_file_put_contents, 0, 0, 2)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()
// Every user visible function must have an entry in fastcommon_functions[].
zend_function_entry fastcommon_functions[] = {
ZEND_FE(fastcommon_version, NULL)
ZEND_FE(fastcommon_gethostaddrs, NULL)
ZEND_FE(fastcommon_time33_hash, NULL)
ZEND_FE(fastcommon_simple_hash, NULL)
ZEND_FE(fastcommon_get_line_distance_km, NULL)
ZEND_FE(fastcommon_get_first_local_ip, NULL)
ZEND_FE(fastcommon_get_next_local_ip, NULL)
ZEND_FE(fastcommon_is_private_ip, NULL)
ZEND_FE(fastcommon_id_generator_init, NULL)
ZEND_FE(fastcommon_id_generator_next, NULL)
ZEND_FE(fastcommon_id_generator_get_extra, NULL)
ZEND_FE(fastcommon_id_generator_get_timestamp, NULL)
ZEND_FE(fastcommon_id_generator_destroy, NULL)
ZEND_FE(fastcommon_get_ifconfigs, NULL)
ZEND_FE(fastcommon_get_cpu_count, NULL)
ZEND_FE(fastcommon_get_sysinfo, NULL)
ZEND_FE(fastcommon_error_log, NULL)
ZEND_FE(fastcommon_file_put_contents, NULL)
ZEND_FE(fastcommon_version, arginfo_version)
ZEND_FE(fastcommon_gethostaddrs, arginfo_gethostaddrs)
ZEND_FE(fastcommon_time33_hash, arginfo_time33_hash)
ZEND_FE(fastcommon_simple_hash, arginfo_simple_hash)
ZEND_FE(fastcommon_get_line_distance_km, arginfo_get_line_distance_km)
ZEND_FE(fastcommon_get_first_local_ip, arginfo_get_first_local_ip)
ZEND_FE(fastcommon_get_next_local_ip, arginfo_get_next_local_ip)
ZEND_FE(fastcommon_is_private_ip, arginfo_is_private_ip)
ZEND_FE(fastcommon_id_generator_init, arginfo_id_generator_init)
ZEND_FE(fastcommon_id_generator_next, arginfo_id_generator_next)
ZEND_FE(fastcommon_id_generator_get_extra, arginfo_id_generator_get_extra)
ZEND_FE(fastcommon_id_generator_get_timestamp, arginfo_id_generator_get_timestamp)
ZEND_FE(fastcommon_id_generator_destroy, arginfo_id_generator_destroy)
ZEND_FE(fastcommon_get_ifconfigs, arginfo_get_ifconfigs)
ZEND_FE(fastcommon_get_cpu_count, arginfo_get_cpu_count)
ZEND_FE(fastcommon_get_sysinfo, arginfo_get_sysinfo)
ZEND_FE(fastcommon_error_log, arginfo_error_log)
ZEND_FE(fastcommon_file_put_contents, arginfo_file_put_contents)
{NULL, NULL, NULL} /* Must be the last line */
};
@ -168,7 +252,7 @@ PHP_MINIT_FUNCTION(fastcommon)
log_try_init();
le_consumer = zend_register_list_destructors_ex(id_generator_dtor, NULL,
PHP_IDG_RESOURCE_NAME, module_number);
if (hash_init(&idg_htable, simple_hash, 64, 0.75) != 0) {
if (fc_hash_init(&idg_htable, fc_simple_hash, 64, 0.75) != 0) {
return FAILURE;
}
@ -381,7 +465,7 @@ ZEND_FUNCTION(fastcommon_simple_hash)
RETURN_BOOL(false);
}
RETURN_LONG(simple_hash(str, str_len) & 0x7FFFFFFF);
RETURN_LONG(fc_simple_hash(str, str_len) & 0x7FFFFFFF);
}
/*
@ -518,7 +602,7 @@ static struct idg_context *get_idg_context(const char *filename,
key_info.extra_bits = extra_bits;
key_info.sn_bits = sn_bits;
idg_context = (struct idg_context *)hash_find(&idg_htable,
idg_context = (struct idg_context *)fc_hash_find(&idg_htable,
&key_info, sizeof(key_info));
if (idg_context == NULL) {
idg_context = (struct idg_context *)malloc(sizeof(struct idg_context));
@ -534,7 +618,7 @@ static struct idg_context *get_idg_context(const char *filename,
{
return NULL;
}
hash_insert_ex(&idg_htable, &key_info, sizeof(key_info),
fc_hash_insert_ex(&idg_htable, &key_info, sizeof(key_info),
idg_context, 0, false);
}
@ -1153,8 +1237,8 @@ static PHPFileContext *fetch_file_context(const char *filename)
static int fc_open_file(PHPFileContext *ctx)
{
if ((ctx->fd = open(ctx->filename, O_WRONLY |
O_CREAT | O_APPEND, 0644)) < 0)
if ((ctx->fd = open(ctx->filename, O_WRONLY | O_CREAT |
O_APPEND | O_CLOEXEC, 0644)) < 0)
{
logError("file: "__FILE__", line: %d, "
"open file \"%s\" to write fail, "

View File

@ -1,7 +1,7 @@
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH =
INC_PATH = $(INCS)
LIB_PATH = $(LIBS)
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
@ -14,9 +14,10 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
fast_buffer.lo multi_skiplist.lo flat_skiplist.lo \
system_info.lo fast_blocked_queue.lo id_generator.lo \
char_converter.lo char_convert_loader.lo common_blocked_queue.lo \
multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \
json_parser.lo buffered_file_writer.lo server_id_func.lo \
fc_queue.lo fc_memory.lo shared_buffer.lo thread_pool.lo
multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \
json_parser.lo buffered_file_writer.lo server_id_func.lo \
fc_queue.lo sorted_queue.lo fc_memory.lo shared_buffer.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 \
logger.o sockopt.o base64.o sched_thread.o \
@ -27,9 +28,10 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
fast_buffer.o multi_skiplist.o flat_skiplist.o \
system_info.o fast_blocked_queue.o id_generator.o \
char_converter.o char_convert_loader.o common_blocked_queue.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 \
fc_queue.o fc_memory.o shared_buffer.o thread_pool.o
fc_queue.o sorted_queue.o fc_memory.o shared_buffer.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 \
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
@ -43,8 +45,9 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
char_convert_loader.h common_blocked_queue.h \
multi_socket_client.h skiplist_set.h uniq_skiplist.h \
fc_list.h locked_list.h json_parser.h buffered_file_writer.h \
server_id_func.h fc_queue.h fc_memory.h shared_buffer.h \
thread_pool.h fc_atomic.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 \
sorted_array.h spinlock.h
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
@ -75,7 +78,7 @@ install:
install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon
@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:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)

129
src/array_allocator.c Normal file
View File

@ -0,0 +1,129 @@
/*
* 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 GNU Affero General Public License, version 3
* or later ("AGPL"), 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 GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "shared_func.h"
#include "array_allocator.h"
int array_allocator_init_ex(ArrayAllocatorContext *ctx,
const char *name_prefix, const int element_size,
const int min_bits, const int max_bits,
const bool need_lock)
{
const int obj_size = 0;
const int reclaim_interval = 0;
char name[32];
struct fast_region_info regions[32];
struct fast_region_info *region;
int bit;
int start;
int end;
int alloc_elements_once;
int step;
ctx->element_size = element_size;
ctx->min_count = (1 << min_bits);
start = 0;
alloc_elements_once = (1 << (max_bits - min_bits + 2));
for (bit=min_bits, region=regions;
bit<=max_bits; bit++, region++)
{
end = sizeof(VoidArray) + (1 << bit) * ctx->element_size;
step = end - start;
FAST_ALLOCATOR_INIT_REGION(*region, start,
end, step, alloc_elements_once);
alloc_elements_once /= 2;
start = end;
}
fc_combine_two_strings(name_prefix, "array", '-', name);
return fast_allocator_init_ex(&ctx->allocator, name,
obj_size, NULL, regions, region - regions, 0,
0.9999, reclaim_interval, need_lock);
}
VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
const int target_count)
{
int alloc;
int bytes;
VoidArray *array;
if (target_count <= ctx->min_count) {
alloc = ctx->min_count;
} else if (is_power2(target_count)) {
alloc = target_count;
} else {
alloc = ctx->min_count;
while (alloc < target_count) {
alloc *= 2;
}
}
bytes = sizeof(VoidArray) + alloc * ctx->element_size;
if ((array=fast_allocator_alloc(&ctx->allocator, bytes)) != NULL) {
array->alloc = alloc;
array->count = 0;
}
return array;
}
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,
VoidArray *old_array, const int target_count)
{
VoidArray *new_array;
if (old_array == NULL) {
return array_allocator_alloc(ctx, target_count);
}
if (old_array->alloc >= target_count) {
return old_array;
}
if ((new_array=array_allocator_alloc(ctx, target_count)) != NULL) {
if (old_array->count > 0) {
memcpy(new_array->elts, old_array->elts, ctx->
element_size * old_array->count);
}
new_array->count = old_array->count;
}
array_allocator_free(ctx, old_array);
return new_array;
}
int array_compare_element_int64(const int64_t *n1, const int64_t *n2)
{
int64_t sub;
sub = *n1 - *n2;
if (sub < 0) {
return -1;
} else if (sub > 0) {
return 1;
} else {
return 0;
}
}
int array_compare_element_int32(const int32_t *n1, const int32_t *n2)
{
return *n1 - *n2;
}
int array_compare_element_id_name(const id_name_pair_t *pair1,
const id_name_pair_t *pair2)
{
return fc_compare_int64(pair1->id, pair2->id);
}

174
src/array_allocator.h Normal file
View File

@ -0,0 +1,174 @@
/*
* 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 GNU Affero General Public License, version 3
* or later ("AGPL"), 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 GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ARRAY_ALLOCATOR_H
#define ARRAY_ALLOCATOR_H
#include "fast_allocator.h"
typedef struct
{
int alloc;
int count;
char elts[0];
} VoidArray;
typedef struct
{
int alloc;
int count;
int64_t elts[0];
} I64Array;
typedef struct
{
int alloc;
int count;
int32_t elts[0];
} I32Array;
typedef struct
{
int alloc;
int count;
id_name_pair_t elts[0];
} IdNameArray;
typedef struct
{
int alloc;
int count;
void *elts[0];
} PointerArray;
typedef struct array_allocator_context
{
struct fast_allocator_context allocator;
int element_size;
int min_count;
} ArrayAllocatorContext;
#ifdef __cplusplus
extern "C" {
#endif
int array_allocator_init_ex(ArrayAllocatorContext *ctx,
const char *name_prefix, const int element_size,
const int min_bits, const int max_bits,
const bool need_lock);
VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
const int target_count);
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,
VoidArray *old_array, const int target_count);
static inline void array_allocator_free(ArrayAllocatorContext *ctx,
VoidArray *array)
{
fast_allocator_free(&ctx->allocator, array);
}
/* comparator for 64 bits integer */
int array_compare_element_int64(const int64_t *n1, const int64_t *n2);
/* comparator for 32 bits integer */
int array_compare_element_int32(const int32_t *n1, const int32_t *n2);
/* comparator for id name pair (sorted by id) */
int array_compare_element_id_name(const id_name_pair_t *pair1,
const id_name_pair_t *pair2);
#define array_allocator_init(ctx, name_prefix, \
element_size, min_bits, max_bits) \
array_allocator_init_ex(ctx, name_prefix, \
element_size, min_bits, max_bits, true)
#define i64_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "i64", sizeof(int64_t), \
min_bits, max_bits, need_lock)
#define i64_array_allocator_init(ctx, min_bits, max_bits) \
i64_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define i64_array_allocator_alloc(ctx, target_count) \
(I64Array *)array_allocator_alloc(ctx, target_count)
#define i64_array_allocator_realloc(ctx, old_array, target_count) \
(I64Array *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define i64_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define i32_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "i32", sizeof(int32_t), \
min_bits, max_bits, need_lock)
#define i32_array_allocator_init(ctx, min_bits, max_bits) \
i32_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define i32_array_allocator_alloc(ctx, target_count) \
(I32Array *)array_allocator_alloc(ctx, target_count)
#define i32_array_allocator_realloc(ctx, old_array, target_count) \
(I32Array *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define i32_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define id_name_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "id_name", sizeof(id_name_pair_t), \
min_bits, max_bits, need_lock)
#define id_name_array_allocator_init(ctx, min_bits, max_bits) \
id_name_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define id_name_array_allocator_alloc(ctx, target_count) \
(IdNameArray *)array_allocator_alloc(ctx, target_count)
#define id_name_array_allocator_realloc(ctx, old_array, target_count) \
(IdNameArray *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define id_name_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define ptr_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "ptr", sizeof(void *), \
min_bits, max_bits, need_lock)
#define ptr_array_allocator_init(ctx, min_bits, max_bits) \
ptr_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define ptr_array_allocator_alloc(ctx, target_count) \
(PointerArray *)array_allocator_alloc(ctx, target_count)
#define ptr_array_allocator_realloc(ctx, old_array, target_count) \
(PointerArray *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define ptr_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -24,6 +24,7 @@
#include <fcntl.h>
#include <errno.h>
#include "fc_memory.h"
#include "shared_func.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.
* 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)
{
context->line_sep_len = snprintf(context->line_separator, \
sizeof(context->line_separator), "%s", pLineSeparator);
if (context->line_sep_len >= sizeof(context->line_separator))
{
context->line_sep_len = sizeof(context->line_separator) - 1;
}
context->line_sep_len = fc_safe_strcpy(context->
line_separator, pLineSeparator);
}
void base64_init_ex(struct base64_context *context, const int nLineLength, \

View File

@ -48,8 +48,9 @@ int buffered_file_writer_open_ex(BufferedFileWriter *writer,
return ENOMEM;
}
snprintf(writer->filename, sizeof(writer->filename), "%s", filename);
writer->fd = open(writer->filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
fc_safe_strcpy(writer->filename, filename);
writer->fd = open(writer->filename, O_WRONLY |
O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (writer->fd < 0)
{
result = errno != 0 ? errno : EIO;

View File

@ -34,7 +34,7 @@ int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
return result;
}
if ((result=fast_mblock_init_ex1(&queue->mblock, "queue_node",
if ((result=fast_mblock_init_ex1(&queue->mblock, "queue-node",
sizeof(struct common_blocked_node),
alloc_elements_once, alloc_elements_limit,
NULL, NULL, false)) != 0)
@ -102,6 +102,29 @@ int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
return 0;
}
void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue,
struct common_blocked_chain *chain, bool *notify)
{
if (chain->head == NULL)
{
return;
}
pthread_mutex_lock(&(queue->lc_pair.lock));
if (queue->head == NULL)
{
queue->head = chain->head;
*notify = true;
}
else
{
queue->tail->next = chain->head;
*notify = false;
}
queue->tail = chain->tail;
pthread_mutex_unlock(&(queue->lc_pair.lock));
}
void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
struct common_blocked_node *node)
{

View File

@ -31,6 +31,12 @@ struct common_blocked_node
struct common_blocked_node *next;
};
struct common_blocked_chain
{
struct common_blocked_node *head;
struct common_blocked_node *tail;
};
struct common_blocked_queue
{
struct common_blocked_node *head;
@ -88,6 +94,41 @@ static inline int common_blocked_queue_push(struct common_blocked_queue
return result;
}
static inline struct common_blocked_node *common_blocked_queue_alloc_node(
struct common_blocked_queue *queue)
{
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(
struct common_blocked_queue *queue,
struct common_blocked_node *node)
{
pthread_mutex_lock(&(queue->lc_pair.lock));
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,
struct common_blocked_chain *chain, bool *notify);
static inline void common_blocked_queue_push_chain(
struct common_blocked_queue *queue,
struct common_blocked_chain *chain)
{
bool notify;
common_blocked_queue_push_chain_ex(queue, chain, &notify);
if (notify)
{
pthread_cond_signal(&(queue->lc_pair.cond));
}
}
void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
struct common_blocked_node *node);
@ -95,6 +136,36 @@ void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
const bool blocked);
static inline bool common_blocked_queue_empty(
struct common_blocked_queue *queue)
{
bool empty;
pthread_mutex_lock(&queue->lc_pair.lock);
empty = (queue->head == NULL);
pthread_mutex_unlock(&queue->lc_pair.lock);
return empty;
}
static inline int common_blocked_queue_count(
struct common_blocked_queue *queue)
{
int count;
struct common_blocked_node *node;
count = 0;
pthread_mutex_lock(&queue->lc_pair.lock);
node = queue->head;
while (node != NULL)
{
++count;
node = node->next;
}
pthread_mutex_unlock(&queue->lc_pair.lock);
return count;
}
#define common_blocked_queue_pop(queue) \
common_blocked_queue_pop_ex(queue, true)
@ -111,7 +182,7 @@ struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
common_blocked_queue_pop_all_nodes_ex(queue, false)
#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,
struct common_blocked_node *node);

View File

@ -43,6 +43,14 @@ typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef OS_FREEBSD
//#include <sys/syscall.h>
#endif
/* Internet address (兼容IPv6长度). */
typedef uint64_t in_addr_64_t;
#define FILE_SEPERATOR "/"
typedef int SOCKET;
#define closesocket close
@ -104,7 +112,23 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
#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 FILE_RESOURCE_TAG_STR "file://"
@ -114,6 +138,11 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
(strncasecmp(filename, FILE_RESOURCE_TAG_STR, \
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
#define byte signed char
#endif
@ -132,6 +161,10 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define ECANCELED 125
#endif
#ifndef ENODATA
#define ENODATA 61 /* No data available */
#endif
#ifndef ENONET
#define ENONET 64 /* Machine is not on the network */
#endif
@ -154,6 +187,25 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define FC_TIME_UNIT_USECOND 'u' //microsecond
#define FC_TIME_UNIT_NSECOND 'n' //nanosecond
#define FC_1E01 10LL
#define FC_1E02 100LL
#define FC_1E03 1000LL
#define FC_1E04 10000LL
#define FC_1E05 100000LL
#define FC_1E06 1000000LL
#define FC_1E07 10000000LL
#define FC_1E08 100000000LL
#define FC_1E09 1000000000LL
#define FC_1E10 10000000000LL
#define FC_1E11 100000000000LL
#define FC_1E12 1000000000000LL
#define FC_1E13 10000000000000LL
#define FC_1E14 100000000000000LL
#define FC_1E15 1000000000000000LL
#define FC_1E16 10000000000000000LL
#define FC_1E17 100000000000000000LL
#define FC_1E18 1000000000000000000LL
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
#if defined(OS_LINUX)
@ -163,10 +215,12 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define st_ctimensec st_ctim.tv_nsec
#endif
#elif defined(OS_FREEBSD)
#ifndef st_atimensec
#define st_atimensec st_atimespec.tv_nsec
#define st_mtimensec st_mtimespec.tv_nsec
#define st_ctimensec st_ctimespec.tv_nsec
#endif
#endif
#ifdef __cplusplus
extern "C" {
@ -243,6 +297,30 @@ typedef struct
int count;
} key_value_array_t;
typedef struct
{
int32_t *elts;
int count;
} int32_array_t;
typedef struct
{
int64_t *elts;
int count;
} int64_array_t;
typedef struct
{
id_name_pair_t *elts;
int count;
} id_name_array_t;
typedef struct
{
void *elts;
int count;
} void_array_t;
typedef struct
{
pthread_mutex_t lock;
@ -262,17 +340,38 @@ typedef struct
string_t s;
} FilenameString;
typedef struct {
char *filename;
char *tmp_filename;
int fd;
} SafeWriteFileInfo;
typedef struct {
char filename[PATH_MAX];
int fd;
} FilenameFDPair;
typedef void (*FreeDataFunc)(void *ptr);
typedef int (*CompareFunc)(void *p1, void *p2);
typedef void* (*MallocFunc)(size_t size);
#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) \
(((x) + (align_size - 1)) & (~(align_size - 1)))
#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_IS_CHAIN_EMPTY(chain) ((chain).head == NULL)
#define FC_SET_CHAIN_TAIL_NEXT(chain, type, ptr) \
((type *)(chain).tail)->next = ptr
#ifdef WIN32
#define strcasecmp _stricmp
#endif
@ -322,6 +421,8 @@ typedef void* (*MallocFunc)(size_t size);
(dest).len = l; \
} while (0)
#define FC_SET_STRING_EMPTY(dest, s) FC_SET_STRING_EX(dest, s, 0)
#define FC_SET_STRING_NULL(dest) \
do { \
(dest).str = NULL; \
@ -354,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)
{
return (s1->len == s2->len) && (memcmp(s1->str, s2->str, s1->len) == 0);
@ -415,11 +524,40 @@ static inline int fc_compare_int64(const int64_t n1, const int64_t n2)
}
#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
#define fc_fallocate(fd, size) ftruncate(fd, size)
#define posix_fadvise(fd, offset, len, advice) 0
#ifndef POSIX_FADV_NORMAL
#define POSIX_FADV_NORMAL 0 /* No further special treatment. */
#define POSIX_FADV_RANDOM 1 /* Expect random page references. */
#define POSIX_FADV_SEQUENTIAL 2 /* Expect sequential page references. */
#define POSIX_FADV_WILLNEED 3 /* Will need these pages. */
#define POSIX_FADV_DONTNEED 4 /* Don't need these pages. */
#define POSIX_FADV_NOREUSE 5 /* Data will be accessed once. */
#endif
#ifdef OS_FREEBSD
//#define fdatasync(fd) syscall(SYS_fdatasync, fd)
#define fdatasync(fd) fsync(fd)
#endif
#endif
#define FC_MACRO_STRINGIFY(x) #x
#define FC_MACRO_TOSTRING(x) FC_MACRO_STRINGIFY(x)
#ifdef __cplusplus
}

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#include "fast_mblock.h"
#include "ini_file_reader.h"
#include "pthread_func.h"
#include "sockopt.h"
#include "hash.h"
#ifdef __cplusplus
@ -40,16 +41,105 @@ extern "C" {
(strcmp((conn1).ip_addr, (conn2).ip_addr) == 0 && \
(conn1).port == (conn2).port)
typedef struct
{
int sock;
uint16_t port;
short socket_domain; //socket domain, AF_INET, AF_INET6 or AF_UNSPEC for auto dedect
typedef enum {
fc_comm_type_sock = 0,
fc_comm_type_rdma,
fc_comm_type_both
} 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
char ip_addr[INET6_ADDRSTRLEN];
char ip_addr[IP_ADDRESS_SIZE];
void *arg1; //for RDMA
char args[0]; //for extra data
} 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);
struct tagConnectionManager;
@ -62,16 +152,32 @@ typedef struct tagConnectionNode {
} ConnectionNode;
typedef struct tagConnectionManager {
ConnectionNode *head;
int total_count; //total connections
int free_count; //free connections
pthread_mutex_t lock;
string_t key;
ConnectionNode *head;
int total_count; //total connections
int free_count; //free connections
struct tagConnectionManager *next;
} ConnectionManager;
typedef struct tagConnectionBucket {
ConnectionManager *head;
pthread_mutex_t lock;
} ConnectionBucket;
struct tagConnectionPool;
typedef struct {
ConnectionNode **buckets;
struct tagConnectionPool *cp;
} ConnectionThreadHashTable;
typedef struct tagConnectionPool {
HashArray hash_array; //key is ip:port, value is ConnectionManager
pthread_mutex_t lock;
int connect_timeout;
struct {
ConnectionBucket *buckets;
uint32_t capacity;
} hashtable;
int connect_timeout_ms;
int max_count_per_entry; //0 means no limit
/*
@ -79,7 +185,6 @@ typedef struct tagConnectionPool {
unit: second
*/
int max_idle_time;
int socket_domain; //socket domain
struct fast_mblock_man manager_allocator;
struct fast_mblock_man node_allocator;
@ -93,8 +198,29 @@ typedef struct tagConnectionPool {
fc_connection_callback_func func;
void *args;
} validate_callback;
int extra_data_size;
ConnectionExtraParams extra_params;
pthread_key_t tls_key; //for ConnectionThreadHashTable
} 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
* parameters:
@ -102,21 +228,22 @@ typedef struct tagConnectionPool {
* connect_timeout: the connect timeout in seconds
* max_count_per_entry: max connection count per host:port
* max_idle_time: reconnect the server after max idle time in seconds
* socket_domain: the socket domain
* htable_init_capacity: the init capacity of connection hash table
* af: the socket domain
* htable_capacity: the capacity of connection hash table
* connect_done_func: the connect done connection callback
* connect_done_args: the args for connect done connection callback
* validate_func: the validate connection callback
* validate_args: the args for validate connection callback
* extra_data_size: the extra data size of connection
* extra_params: for RDMA
* 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 socket_domain, const int htable_init_capacity,
fc_connection_callback_func connect_done_func, void *connect_done_args,
fc_connection_callback_func validate_func, void *validate_args,
const int extra_data_size);
const int htable_capacity, fc_connection_callback_func connect_done_func,
void *connect_done_args, fc_connection_callback_func validate_func,
void *validate_args, const int extra_data_size,
const ConnectionExtraParams *extra_params);
/**
* init ex function
@ -125,18 +252,18 @@ int conn_pool_init_ex1(ConnectionPool *cp, int connect_timeout,
* connect_timeout: the connect timeout in seconds
* max_count_per_entry: max connection count per host:port
* max_idle_time: reconnect the server after max idle time in seconds
* socket_domain: the socket domain
* return 0 for success, != 0 for error
*/
static inline int conn_pool_init_ex(ConnectionPool *cp, int connect_timeout,
const int max_count_per_entry, const int max_idle_time,
const int socket_domain)
static inline int conn_pool_init_ex(ConnectionPool *cp,
const int connect_timeout, const int max_count_per_entry,
const int max_idle_time)
{
const int htable_init_capacity = 0;
const int htable_capacity = 0;
const int extra_data_size = 0;
const ConnectionExtraParams *extra_params = NULL;
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
max_idle_time, socket_domain, htable_init_capacity,
NULL, NULL, NULL, NULL, extra_data_size);
max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
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
* 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 socket_domain = AF_INET;
const int htable_init_capacity = 0;
const int htable_capacity = 0;
const int extra_data_size = 0;
const ConnectionExtraParams *extra_params = NULL;
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
max_idle_time, socket_domain, htable_init_capacity,
NULL, NULL, NULL, NULL, extra_data_size);
max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
extra_data_size, extra_params);
}
/**
@ -172,11 +299,17 @@ void conn_pool_destroy(ConnectionPool *cp);
* parameters:
* cp: the ConnectionPool
* conn: the connection
* service_name: the service name to log
* shared: if the connection shared
* err_no: return the the errno, 0 for success
* return != NULL for success, NULL for error
*/
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
const ConnectionInfo *conn, int *err_no);
ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp,
const ConnectionInfo *conn, const char *service_name,
const bool shared, int *err_no);
#define conn_pool_get_connection(cp, conn, err_no) \
conn_pool_get_connection_ex(cp, conn, NULL, false, err_no)
#define conn_pool_close_connection(cp, conn) \
conn_pool_close_connection_ex(cp, conn, false)
@ -189,61 +322,94 @@ ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
* bForce: set true to close the socket, else only push back to connection pool
* return 0 for success, != 0 for error
*/
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
const bool bForce);
int conn_pool_close_connection_ex(ConnectionPool *cp,
ConnectionInfo *conn, const bool bForce);
/**
* disconnect from the server
* parameters:
* pConnection: the connection
* conn: the connection
* return 0 for success, != 0 for error
*/
void conn_pool_disconnect_server(ConnectionInfo *pConnection);
/**
* connect to the server
* parameters:
* pConnection: the connection
* connect_timeout: the connect timeout in seconds
* bind_ipaddr: the ip address to bind, NULL or empty for any
* log_connect_error: if log error info when connect fail
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error
*/
int conn_pool_connect_server_ex(ConnectionInfo *pConnection,
const int connect_timeout, const char *bind_ipaddr,
const bool log_connect_error);
/**
* connect to the server
* parameters:
* pConnection: the connection
* connect_timeout: the connect timeout in seconds
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error
*/
static inline int conn_pool_connect_server(ConnectionInfo *pConnection,
const int connect_timeout)
static inline void conn_pool_disconnect_server(ConnectionInfo *conn)
{
const char *bind_ipaddr = NULL;
return conn_pool_connect_server_ex(pConnection,
connect_timeout, bind_ipaddr, true);
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
* parameters:
* pConnection: the connection
* connect_timeout: the connect timeout in seconds
* service_name: the service name to log
* connect_timeout_ms: the connect timeout in milliseconds
* bind_ipaddr: the ip address to bind, NULL or empty for any
* log_connect_error: if log error info when connect fail
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error
*/
int conn_pool_connect_server_ex1(ConnectionInfo *conn,
const char *service_name, const int connect_timeout_ms,
const char *bind_ipaddr, const bool log_connect_error);
/**
* connect to the server
* parameters:
* pConnection: the connection
* connect_timeout_ms: the connect timeout in milliseconds
* bind_ipaddr: the ip address to bind, NULL or empty for any
* log_connect_error: if log error info when connect fail
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error
*/
static inline int conn_pool_connect_server_ex(ConnectionInfo *pConnection,
const int connect_timeout_ms, const char *bind_ipaddr,
const bool log_connect_error)
{
const char *service_name = NULL;
return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout_ms, bind_ipaddr, log_connect_error);
}
/**
* connect to the server
* parameters:
* pConnection: the connection
* connect_timeout_ms: the connect timeout in seconds
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 for success, != 0 for error
*/
static inline int conn_pool_connect_server(ConnectionInfo *pConnection,
const int connect_timeout_ms)
{
const char *service_name = NULL;
const char *bind_ipaddr = NULL;
return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout_ms, bind_ipaddr, true);
}
/**
* connect to the server
* parameters:
* pConnection: the connection
* connect_timeout_ms: the connect timeout in seconds
* return 0 for success, != 0 for error
*/
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 *bind_ipaddr = NULL;
pConnection->sock = -1;
return conn_pool_connect_server_ex(pConnection,
connect_timeout, bind_ipaddr, true);
return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout_ms, bind_ipaddr, true);
}
/**
@ -262,12 +428,13 @@ int conn_pool_async_connect_server_ex(ConnectionInfo *conn,
/**
* get connection count of the pool
* connection pool stat
* parameters:
* 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
@ -305,10 +472,9 @@ int conn_pool_parse_server_info(const char *pServerStr,
static inline void conn_pool_set_server_info(ConnectionInfo *pServerInfo,
const char *ip_addr, const int port)
{
snprintf(pServerInfo->ip_addr, sizeof(pServerInfo->ip_addr),
"%s", ip_addr);
fc_safe_strcpy(pServerInfo->ip_addr, ip_addr);
pServerInfo->port = port;
pServerInfo->socket_domain = AF_UNSPEC;
pServerInfo->af = is_ipv6_addr(ip_addr) ? AF_INET6 : AF_INET;
pServerInfo->sock = -1;
}
@ -322,6 +488,55 @@ static inline int conn_pool_compare_ip_and_port(const char *ip1,
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
}
#endif

View File

@ -25,14 +25,6 @@
#define BYTES_ALIGN(x, pad_mask) (((x) + pad_mask) & (~pad_mask))
struct allocator_wrapper {
int alloc_bytes;
short allocator_index;
short magic_number;
};
static struct fast_allocator_info malloc_allocator;
#define ADD_ALLOCATOR_TO_ARRAY(acontext, allocator, _pooled) \
do { \
(allocator)->index = acontext->allocator_array.count; \
@ -63,17 +55,19 @@ static int fast_allocator_malloc_trunk_check(const int alloc_bytes, void *args)
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)->
allocator_array.malloc_bytes, alloc_bytes);
allocator_array.malloc_bytes, node->trunk_size);
}
else
{
__sync_sub_and_fetch(&((struct fast_allocator_context *)args)->
allocator_array.malloc_bytes, -1 * alloc_bytes);
allocator_array.malloc_bytes, node->trunk_size);
}
}
@ -142,20 +136,22 @@ static int allocator_array_check_capacity(struct fast_allocator_context *acontex
}
static int region_init(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, struct fast_region_info *region)
const char *mblock_name_prefix, struct fast_mblock_object_callbacks
*object_callbacks, struct fast_region_info *region)
{
const int64_t alloc_elements_limit = 0;
const int prealloc_trunk_count = 0;
int result;
int bytes;
int element_size;
int allocator_count;
struct fast_mblock_trunk_callbacks trunk_callbacks;
struct fast_allocator_info *allocator;
char *name;
char name_buff[FAST_MBLOCK_NAME_SIZE];
region->pad_mask = region->step - 1;
allocator_count = (region->end - region->start) / region->step;
bytes = sizeof(struct fast_allocator_info) * allocator_count;
region->count = (region->end - region->start) / region->step;
bytes = sizeof(struct fast_allocator_info) * region->count;
region->allocators = (struct fast_allocator_info *)fc_malloc(bytes);
if (region->allocators == NULL)
{
@ -163,17 +159,29 @@ static int region_init(struct fast_allocator_context *acontext,
}
memset(region->allocators, 0, bytes);
if ((result=allocator_array_check_capacity(acontext, allocator_count)) != 0)
if ((result=allocator_array_check_capacity(acontext, region->count)) != 0)
{
return result;
}
if (region->count == 1) {
if (region->start == 0) {
region->step += acontext->extra_size;
} else {
region->start += acontext->extra_size;
}
region->end += acontext->extra_size;
}
trunk_callbacks.check_func = fast_allocator_malloc_trunk_check;
trunk_callbacks.notify_func = fast_allocator_malloc_trunk_notify_func;
name = name_buff;
result = 0;
allocator = region->allocators;
for (element_size=region->start+region->step; element_size<=region->end;
element_size+=region->step,allocator++)
{
for (element_size = region->start + region->step;
element_size <= region->end;
element_size += region->step, allocator++)
{
if (mblock_name_prefix != NULL)
{
snprintf(name, FAST_MBLOCK_NAME_SIZE, "%s-%d",
@ -183,10 +191,12 @@ static int region_init(struct fast_allocator_context *acontext,
{
name = NULL;
}
trunk_callbacks.args = acontext;
result = fast_mblock_init_ex2(&allocator->mblock, name, element_size,
region->alloc_elements_once, alloc_elements_limit, NULL, NULL,
acontext->need_lock, fast_allocator_malloc_trunk_check,
fast_allocator_malloc_trunk_notify_func, acontext);
region->alloc_elements_once, alloc_elements_limit,
prealloc_trunk_count, object_callbacks,
acontext->need_lock, &trunk_callbacks);
if (result != 0)
{
break;
@ -216,10 +226,11 @@ static void region_destroy(struct fast_allocator_context *acontext,
}
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, struct fast_region_info *regions,
const int region_count, const int64_t alloc_bytes_limit,
const double expect_usage_ratio, const int reclaim_interval,
const bool need_lock)
const char *mblock_name_prefix, const int obj_size,
struct fast_mblock_object_callbacks *object_callbacks,
struct fast_region_info *regions, const int region_count,
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
const int reclaim_interval, const bool need_lock)
{
int result;
int bytes;
@ -254,6 +265,7 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
acontext->allocator_array.malloc_bytes_limit = alloc_bytes_limit /
acontext->allocator_array.expect_usage_ratio;
acontext->allocator_array.reclaim_interval = reclaim_interval;
acontext->extra_size = sizeof(struct fast_allocator_wrapper) + obj_size;
acontext->need_lock = need_lock;
result = 0;
previous_end = 0;
@ -276,33 +288,46 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
result = EINVAL;
break;
}
if (pRegion->step <= 0 || !is_power2(pRegion->step))
if (pRegion->step <= 0)
{
logError("file: "__FILE__", line: %d, "
"invalid step: %d",
"invalid step: %d <= 0",
__LINE__, pRegion->step);
result = EINVAL;
break;
}
if (pRegion->start % pRegion->step != 0)
{
logError("file: "__FILE__", line: %d, "
"invalid start: %d, must multiple of step: %d",
__LINE__, pRegion->start, pRegion->step);
result = EINVAL;
break;
}
if (pRegion->end % pRegion->step != 0)
{
logError("file: "__FILE__", line: %d, "
"invalid end: %d, must multiple of step: %d",
__LINE__, pRegion->end, pRegion->step);
result = EINVAL;
break;
}
if ((pRegion->end - pRegion->start) / pRegion->step > 1)
{
if (!is_power2(pRegion->step))
{
logError("file: "__FILE__", line: %d, "
"invalid step: %d, expect power of 2",
__LINE__, pRegion->step);
result = EINVAL;
break;
}
if (pRegion->start % pRegion->step != 0)
{
logError("file: "__FILE__", line: %d, "
"invalid start: %d, must multiple of step: %d",
__LINE__, pRegion->start, pRegion->step);
result = EINVAL;
break;
}
if (pRegion->end % pRegion->step != 0)
{
logError("file: "__FILE__", line: %d, "
"invalid end: %d, must multiple of step: %d",
__LINE__, pRegion->end, pRegion->step);
result = EINVAL;
break;
}
}
previous_end = pRegion->end;
if ((result=region_init(acontext, mblock_name_prefix, pRegion)) != 0)
if ((result=region_init(acontext, mblock_name_prefix,
object_callbacks, pRegion)) != 0)
{
break;
}
@ -318,10 +343,12 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
return result;
}
ADD_ALLOCATOR_TO_ARRAY(acontext, &malloc_allocator, false);
ADD_ALLOCATOR_TO_ARRAY(acontext, &acontext->
allocator_array.malloc_allocator, false);
/*
logInfo("sizeof(struct allocator_wrapper): %d, allocator_array count: %d",
(int)sizeof(struct allocator_wrapper), acontext->allocator_array.count);
logInfo("sizeof(struct fast_allocator_wrapper): %d, allocator_array count: %d",
(int)sizeof(struct fast_allocator_wrapper), acontext->allocator_array.count);
*/
return result;
}
@ -333,6 +360,7 @@ int fast_allocator_init(struct fast_allocator_context *acontext,
{
#define DEFAULT_REGION_COUNT 5
const int obj_size = 0;
struct fast_region_info regions[DEFAULT_REGION_COUNT];
FAST_ALLOCATOR_INIT_REGION(regions[0], 0, 256, 8, 4096);
@ -341,9 +369,9 @@ int fast_allocator_init(struct fast_allocator_context *acontext,
FAST_ALLOCATOR_INIT_REGION(regions[3], 4096, 16384, 256, 64);
FAST_ALLOCATOR_INIT_REGION(regions[4], 16384, 65536, 1024, 16);
return fast_allocator_init_ex(acontext, mblock_name_prefix, regions,
DEFAULT_REGION_COUNT, alloc_bytes_limit, expect_usage_ratio,
reclaim_interval, need_lock);
return fast_allocator_init_ex(acontext, mblock_name_prefix, obj_size,
NULL, regions, DEFAULT_REGION_COUNT, alloc_bytes_limit,
expect_usage_ratio, reclaim_interval, need_lock);
}
void fast_allocator_destroy(struct fast_allocator_context *acontext)
@ -368,8 +396,8 @@ void fast_allocator_destroy(struct fast_allocator_context *acontext)
memset(acontext, 0, sizeof(*acontext));
}
static struct fast_allocator_info *get_allocator(struct fast_allocator_context *acontext,
int *alloc_bytes)
static struct fast_allocator_info *get_allocator(struct fast_allocator_context
*acontext, int *alloc_bytes)
{
struct fast_region_info *pRegion;
struct fast_region_info *region_end;
@ -378,14 +406,19 @@ static struct fast_allocator_info *get_allocator(struct fast_allocator_context *
for (pRegion=acontext->regions; pRegion<region_end; pRegion++)
{
if (*alloc_bytes <= pRegion->end)
{
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
return pRegion->allocators + ((*alloc_bytes -
pRegion->start) / pRegion->step) - 1;
}
{
if (pRegion->count == 1) {
*alloc_bytes = pRegion->allocators[0].mblock.info.element_size;
return pRegion->allocators + 0;
} else {
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
return pRegion->allocators + ((*alloc_bytes -
pRegion->start) / pRegion->step) - 1;
}
}
}
return &malloc_allocator;
return &acontext->allocator_array.malloc_allocator;
}
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
@ -415,7 +448,7 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
return EAGAIN;
}
for (i=0; i< acontext->allocator_array.count; i++)
for (i=0; i<acontext->allocator_array.count; i++)
{
if (fast_mblock_reclaim(&acontext->allocator_array.
allocators[i]->mblock, 0, &reclaim_count, NULL) == 0)
@ -430,6 +463,15 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
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,
const int bytes)
{
@ -437,20 +479,21 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
int64_t total_reclaim_bytes;
struct fast_allocator_info *allocator_info;
void *ptr;
void *obj;
if (bytes < 0)
{
return NULL;
}
alloc_bytes = sizeof(struct allocator_wrapper) + bytes;
alloc_bytes = acontext->extra_size + bytes;
allocator_info = get_allocator(acontext, &alloc_bytes);
if (allocator_info->pooled)
{
ptr = fast_mblock_alloc_object(&allocator_info->mblock);
if (ptr == NULL)
{
if (acontext->allocator_array.reclaim_interval <= 0)
if (acontext->allocator_array.reclaim_interval < 0)
{
return NULL;
}
@ -469,6 +512,7 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
return NULL;
}
}
obj = (char *)ptr + sizeof(struct fast_allocator_wrapper);
}
else
{
@ -481,29 +525,42 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
{
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);
if (acontext->allocator_array.allocators[0]->mblock.
object_callbacks.init_func != NULL)
{
struct fast_mblock_man *mblock;
mblock = &acontext->allocator_array.allocators[0]->mblock;
mblock->object_callbacks.init_func(obj,
mblock->object_callbacks.args);
}
}
((struct allocator_wrapper *)ptr)->allocator_index = allocator_info->index;
((struct allocator_wrapper *)ptr)->magic_number = allocator_info->magic_number;
((struct allocator_wrapper *)ptr)->alloc_bytes = alloc_bytes;
((struct fast_allocator_wrapper *)ptr)->allocator_index =
allocator_info->index;
((struct fast_allocator_wrapper *)ptr)->magic_number =
allocator_info->magic_number;
((struct fast_allocator_wrapper *)ptr)->alloc_bytes = alloc_bytes;
__sync_add_and_fetch(&acontext->alloc_bytes, alloc_bytes);
return (char *)ptr + sizeof(struct allocator_wrapper);
return obj;
}
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
{
struct allocator_wrapper *pWrapper;
struct fast_allocator_wrapper *pWrapper;
struct fast_allocator_info *allocator_info;
void *obj;
if (ptr == NULL)
void *ptr;
if (obj == NULL)
{
return;
}
obj = (char *)ptr - sizeof(struct allocator_wrapper);
pWrapper = (struct allocator_wrapper *)obj;
ptr = (char *)obj - sizeof(struct fast_allocator_wrapper);
pWrapper = (struct fast_allocator_wrapper *)ptr;
if (pWrapper->allocator_index < 0 || pWrapper->allocator_index >=
acontext->allocator_array.count)
{
@ -513,7 +570,8 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
return;
}
allocator_info = acontext->allocator_array.allocators[pWrapper->allocator_index];
allocator_info = acontext->allocator_array.
allocators[pWrapper->allocator_index];
if (pWrapper->magic_number != allocator_info->magic_number)
{
logError("file: "__FILE__", line: %d, "
@ -528,13 +586,23 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
pWrapper->magic_number = 0;
if (allocator_info->pooled)
{
fast_mblock_free_object(&allocator_info->mblock, obj);
fast_mblock_free_object(&allocator_info->mblock, ptr);
}
else
{
fast_allocator_malloc_trunk_notify_func(-1 * pWrapper->alloc_bytes, acontext);
free(obj);
}
{
malloc_trunk_notify(fast_mblock_notify_type_reclaim,
pWrapper->alloc_bytes, acontext);
if (acontext->allocator_array.allocators[0]->mblock.
object_callbacks.destroy_func != NULL)
{
struct fast_mblock_man *mblock;
mblock = &acontext->allocator_array.allocators[0]->mblock;
mblock->object_callbacks.destroy_func(obj,
mblock->object_callbacks.args);
}
free(ptr);
}
}
char *fast_allocator_memdup(struct fast_allocator_context *acontext,

View File

@ -40,39 +40,48 @@ struct fast_region_info
int step;
int alloc_elements_once;
int pad_mask; //for internal use
int count;
struct fast_allocator_info *allocators;
};
struct fast_allocator_array
{
int count;
int alloc;
int reclaim_interval; //<= 0 for never reclaim
int last_reclaim_time;
volatile int64_t malloc_bytes; //total alloc bytes
int64_t malloc_bytes_limit; //water mark bytes for malloc
double expect_usage_ratio;
struct fast_allocator_info **allocators;
int count;
int alloc;
int reclaim_interval; //< 0 for never reclaim
int last_reclaim_time;
volatile int64_t malloc_bytes; //total alloc bytes
int64_t malloc_bytes_limit; //water mark bytes for malloc
double expect_usage_ratio;
struct fast_allocator_info malloc_allocator;
struct fast_allocator_info **allocators;
};
struct fast_allocator_wrapper {
int alloc_bytes;
short allocator_index;
short magic_number;
};
struct fast_allocator_context
{
struct fast_region_info *regions;
int region_count;
int extra_size;
struct fast_allocator_array allocator_array;
int64_t alloc_bytes_limit; //mater mark bytes for alloc
int64_t alloc_bytes_limit; //water mark bytes for alloc
volatile int64_t alloc_bytes; //total alloc bytes
bool need_lock; //if need mutex lock for acontext
};
#define FAST_ALLOCATOR_INIT_REGION(region, _start, _end, _step, _alloc_once) \
do { \
region.start = _start; \
region.end = _end; \
region.step = _step; \
region.alloc_elements_once = _alloc_once; \
(region).start = _start; \
(region).end = _end; \
(region).step = _step; \
(region).alloc_elements_once = _alloc_once; \
} while(0)
#ifdef __cplusplus
@ -86,7 +95,7 @@ parameters:
mblock_name_prefix: the name prefix of mblock
alloc_bytes_limit: the alloc limit, 0 for no limit
expect_usage_ratio: the trunk usage ratio
reclaim_interval: reclaim interval in second, 0 for never reclaim
reclaim_interval: reclaim interval in second, < 0 for never reclaim
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
@ -99,19 +108,23 @@ int fast_allocator_init(struct fast_allocator_context *acontext,
allocator init
parameters:
acontext: the context pointer
mblock_name_prefix: name prefix of object alloctors
obj_size: element size of object as sizeof(obj)
object_callbacks: object init and destroy callbacks
regions: the region array
region_count: the region count
alloc_bytes_limit: the alloc limit, 0 for no limit
alloc_bytes_limit: the alloc limit, 0 for no limit
expect_usage_ratio: the trunk usage ratio
reclaim_interval: reclaim interval in second, 0 for never reclaim
reclaim_interval: reclaim interval in second, < 0 for never reclaim
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, struct fast_region_info *regions,
const int region_count, const int64_t alloc_bytes_limit,
const double expect_usage_ratio, const int reclaim_interval,
const bool need_lock);
const char *mblock_name_prefix, const int obj_size,
struct fast_mblock_object_callbacks *object_callbacks,
struct fast_region_info *regions, const int region_count,
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
const int reclaim_interval, const bool need_lock);
/**
allocator destroy
@ -134,10 +147,10 @@ void* fast_allocator_alloc(struct fast_allocator_context *acontext,
free a node (put a node to the context)
parameters:
acontext: the context pointer
ptr: the pointer to free
obj: the object ptr to free
return none
*/
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr);
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj);
/**
retry reclaim free trunks
@ -178,9 +191,19 @@ static inline int fast_allocator_alloc_string(struct fast_allocator_context
return fast_allocator_alloc_string_ex(acontext, dest, src->str, src->len);
}
static inline int64_t fast_allocator_avail_memory(
struct fast_allocator_context *acontext)
{
if (acontext->alloc_bytes_limit == 0) {
return INT64_MIN;
}
return acontext->alloc_bytes_limit - __sync_add_and_fetch(
&acontext->allocator_array.malloc_bytes, 0);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -26,23 +26,28 @@
#include "fc_memory.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->binary_mode = binary_mode;
if (init_capacity > 0)
{
buffer->alloc_size = init_capacity;
buffer->check_capacity = check_capacity;
}
else
{
buffer->alloc_size = 256;
buffer->check_capacity = true;
}
buffer->data = (char *)fc_malloc(buffer->alloc_size);
if (buffer->data == NULL)
{
return ENOMEM;
}
*(buffer->data) = '\0';
fast_buffer_set_null_terminator(buffer);
return 0;
}
@ -88,7 +93,9 @@ int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity)
if (buffer->length > 0) {
memcpy(buff, buffer->data, buffer->length);
*(buff + buffer->length) = '\0';
if (!buffer->binary_mode) {
*(buff + buffer->length) = '\0';
}
}
free(buffer->data);
@ -127,7 +134,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
}
else
{
*(buffer->data + buffer->length) = '\0'; //restore
fast_buffer_set_null_terminator(buffer); //restore
}
}
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);
buffer->length += len;
*(buffer->data + buffer->length) = '\0';
fast_buffer_set_null_terminator(buffer);
return 0;
}
@ -171,32 +178,6 @@ int fast_buffer_append_binary(FastBuffer *buffer,
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)
{
struct stat st;

View File

@ -17,12 +17,14 @@
#define __FAST_BUFFER_H__
#include <stdint.h>
#include "common_define.h"
#include "shared_func.h"
typedef struct fast_buffer {
char *data;
int alloc_size;
int length;
char *data;
int alloc_size;
int length;
bool binary_mode;
bool check_capacity;
} FastBuffer;
#ifdef __cplusplus
@ -39,26 +41,39 @@ static inline char *fast_buffer_data(FastBuffer *buffer)
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)
{
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)
static inline void fast_buffer_reset(FastBuffer *buffer)
{
buffer->length = 0;
*buffer->data = '\0';
fast_buffer_set_null_terminator(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);
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,
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);

View File

@ -35,10 +35,12 @@ struct _fast_mblock_manager
#define INIT_HEAD(head) (head)->next = (head)->prev = head
#define IS_EMPTY(head) ((head)->next == head)
static struct _fast_mblock_manager mblock_manager = {false, 0};
#define CALC_USED_RATIO(info) \
(info->element_total_count > 0 ? 100.00 * (double) \
info->element_used_count / (double) \
info->element_total_count : 0.00)
#define fast_mblock_get_trunk_size(mblock, block_size, element_count) \
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
static struct _fast_mblock_manager mblock_manager = {false, 0};
int fast_mblock_manager_init()
{
@ -59,13 +61,20 @@ int fast_mblock_manager_init()
static int cmp_mblock_info(struct fast_mblock_man *mb1, struct fast_mblock_man *mb2)
{
int result;
result = strcmp(mb1->info.name, mb2->info.name);
if (result != 0)
{
return result;
}
return mb1->info.element_size - mb2->info.element_size;
result = mb1->info.element_size - mb2->info.element_size;
if (result != 0)
{
return result;
}
return mb1->info.trunk_size - mb2->info.trunk_size;
}
static void add_to_mblock_list(struct fast_mblock_man *mblock)
@ -122,6 +131,7 @@ static void delete_from_mblock_list(struct fast_mblock_man *mblock)
if (copy_name) { \
strcpy(pStat->name, current->info.name); \
pStat->trunk_size = current->info.trunk_size; \
pStat->block_size = current->info.block_size; \
pStat->element_size = current->info.element_size; \
} \
pStat->element_total_count += current->info.element_total_count; \
@ -224,10 +234,30 @@ static int fast_mblock_info_cmp_by_element_size(const void *p1, const void *p2)
return pStat2->element_size - pStat1->element_size;
}
//desc order
static int fast_mblock_info_cmp_by_used_ratio(const void *p1, const void *p2)
{
struct fast_mblock_info *pStat1;
struct fast_mblock_info *pStat2;
double sub;
pStat1 = (struct fast_mblock_info *)p1;
pStat2 = (struct fast_mblock_info *)p2;
sub = CALC_USED_RATIO(pStat2) - CALC_USED_RATIO(pStat1);
if (sub <= -0.00005) {
return -1;
} else if (sub >= 0.00005) {
return 1;
} else {
return fast_mblock_info_cmp_by_alloc_bytes(p1, p2);
}
}
int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
{
int result;
int count;
int output_count;
int alloc_size;
struct fast_mblock_info *stats;
struct fast_mblock_info *pStat;
@ -235,7 +265,7 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
stats = NULL;
count = 0;
alloc_size = 64;
alloc_size = 256;
result = EOVERFLOW;
while (result == EOVERFLOW)
{
@ -255,26 +285,37 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
int64_t used_mem;
int64_t amem;
int64_t delay_free_mem;
int name_len;
char *size_caption;
char alloc_mem_str[32];
char used_mem_str[32];
char delay_free_mem_str[32];
if (order_by == FAST_MBLOCK_ORDER_BY_ALLOC_BYTES)
if (order_by == FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE)
{
size_caption = "el_size";
qsort(stats, count, sizeof(struct fast_mblock_info),
fast_mblock_info_cmp_by_element_size);
}
else if (order_by == FAST_MBLOCK_ORDER_BY_ALLOC_BYTES)
{
size_caption = "tr_size";
qsort(stats, count, sizeof(struct fast_mblock_info),
fast_mblock_info_cmp_by_alloc_bytes);
}
else
{
size_caption = "tr_size";
qsort(stats, count, sizeof(struct fast_mblock_info),
fast_mblock_info_cmp_by_element_size);
fast_mblock_info_cmp_by_used_ratio);
}
output_count = 0;
alloc_mem = 0;
used_mem = 0;
delay_free_mem = 0;
logInfo("%20s %8s %8s %12s %11s %10s %10s %10s %10s %12s",
"name", "el_size", "instance", "alloc_bytes",
logInfo("%20s %10s %8s %12s %11s %10s %10s %10s %10s %12s",
"name", size_caption, "instance", "alloc_bytes",
"trunc_alloc", "trunk_used", "el_alloc",
"el_used", "delay_free", "used_ratio");
stat_end = stats + count;
@ -284,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;
alloc_mem += amem;
used_mem += GET_BLOCK_SIZE(*pStat) *
pStat->element_used_count;
delay_free_mem += GET_BLOCK_SIZE(*pStat) *
pStat->delay_free_elements;
used_mem += fast_mblock_get_block_size(pStat->
element_size) * pStat->element_used_count;
delay_free_mem += fast_mblock_get_block_size(pStat->
element_size) * pStat->delay_free_elements;
}
else
{
@ -298,15 +339,19 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
}
}
logInfo("%20s %8d %8d %12"PRId64" %11"PRId64" %10"PRId64
" %10"PRId64" %10"PRId64" %10"PRId64" %11.2f%%",
pStat->name, pStat->element_size, pStat->instance_count,
amem, pStat->trunk_total_count, pStat->trunk_used_count,
pStat->element_total_count, pStat->element_used_count,
pStat->delay_free_elements,
pStat->element_total_count > 0 ? 100.00 * (double)
pStat->element_used_count / (double)
pStat->element_total_count : 0.00);
name_len = strlen(pStat->name);
if (name_len > 20) {
name_len = 20;
}
logInfo("%20.*s %10d %8d %12"PRId64" %11"PRId64" %10"PRId64
" %10"PRId64" %10"PRId64" %10"PRId64" %11.2f%%", name_len,
pStat->name, order_by == FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE ?
pStat->element_size : pStat->trunk_size,
pStat->instance_count, amem, pStat->trunk_total_count,
pStat->trunk_used_count, pStat->element_total_count,
pStat->element_used_count, pStat->delay_free_elements,
CALC_USED_RATIO(pStat));
++output_count;
}
if (alloc_mem < 1024)
@ -341,10 +386,10 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
(double)delay_free_mem / (1024 * 1024 * 1024));
}
logInfo("mblock entry count: %d, memory stat => { alloc : %s, "
"used: %s (%.2f%%), delay free: %s (%.2f%%) }",
count, alloc_mem_str, used_mem_str, alloc_mem > 0 ?
100.00 * (double)used_mem / alloc_mem : 0.00,
logInfo("mblock count: %d, output count: %d, memory stat => "
"{alloc : %s, used: %s (%.2f%%), delay free: %s (%.2f%%) }",
mblock_manager.count, output_count, alloc_mem_str, used_mem_str,
alloc_mem > 0 ? 100.00 * (double)used_mem / alloc_mem : 0.00,
delay_free_mem_str, alloc_mem > 0 ? 100.00 *
(double)delay_free_mem / alloc_mem : 0.00);
}
@ -353,97 +398,6 @@ int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by)
return 0;
}
int fast_mblock_init_ex(struct fast_mblock_man *mblock,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit,
fast_mblock_alloc_init_func init_func, void *init_args,
const bool need_lock)
{
return fast_mblock_init_ex2(mblock, NULL, element_size,
alloc_elements_once, alloc_elements_limit, init_func,
init_args, need_lock, NULL, NULL, NULL);
}
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,
fast_mblock_alloc_init_func init_func,
void *init_args, const bool need_lock,
fast_mblock_malloc_trunk_check_func malloc_trunk_check,
fast_mblock_malloc_trunk_notify_func malloc_trunk_notify,
void *malloc_trunk_args)
{
int result;
int block_size;
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;
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) / 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;
}
mblock->alloc_init_func = init_func;
mblock->init_args = init_args;
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,
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;
mblock->malloc_trunk_callback.check_func = malloc_trunk_check;
mblock->malloc_trunk_callback.notify_func = malloc_trunk_notify;
mblock->malloc_trunk_callback.args = malloc_trunk_args;
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)
{
struct fast_mblock_node *pNode;
@ -453,11 +407,9 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
char *p;
char *pLast;
int result;
int block_size;
int trunk_size;
int alloc_count;
block_size = fast_mblock_get_block_size(mblock);
if (mblock->alloc_elements.limit > 0)
{
int64_t avail_count;
@ -477,8 +429,8 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
alloc_count = avail_count > mblock->alloc_elements.once ?
mblock->alloc_elements.once : avail_count;
trunk_size = fast_mblock_get_trunk_size(mblock,
block_size, alloc_count);
trunk_size = fast_mblock_get_trunk_size(
mblock->info.block_size, alloc_count);
}
else
{
@ -486,9 +438,9 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
trunk_size = mblock->info.trunk_size;
}
if (mblock->malloc_trunk_callback.check_func != NULL &&
mblock->malloc_trunk_callback.check_func(trunk_size,
mblock->malloc_trunk_callback.args) != 0)
if (mblock->trunk_callbacks.check_func != NULL &&
mblock->trunk_callbacks.check_func(trunk_size,
mblock->trunk_callbacks.args) != 0)
{
return ENOMEM;
}
@ -501,27 +453,32 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
memset(pNew, 0, trunk_size);
pMallocNode = (struct fast_mblock_malloc *)pNew;
pTrunkStart = pNew + sizeof(struct fast_mblock_malloc);
pLast = pNew + (trunk_size - block_size);
for (p=pTrunkStart; p<=pLast; p += block_size)
pLast = pNew + (trunk_size - mblock->info.block_size);
for (p=pTrunkStart; p<=pLast; p += mblock->info.block_size)
{
pNode = (struct fast_mblock_node *)p;
if (mblock->alloc_init_func != NULL)
if (mblock->object_callbacks.init_func != NULL)
{
if ((result=mblock->alloc_init_func(pNode->data,
mblock->init_args)) != 0)
if ((result=mblock->object_callbacks.init_func(pNode->data,
mblock->object_callbacks.args)) != 0)
{
free(pNew);
return result;
}
}
pNode->offset = (int)(p - pNew);
pNode->next = (struct fast_mblock_node *)(p + block_size);
pNode->next = (struct fast_mblock_node *)(p + mblock->info.block_size);
#ifdef FAST_MBLOCK_MAGIC_CHECK
pNode->index = (p - pTrunkStart) / mblock->info.block_size;
pNode->magic = FAST_MBLOCK_MAGIC_NUMBER;
#endif
}
((struct fast_mblock_node *)pLast)->next = NULL;
mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart;
((struct fast_mblock_node *)pLast)->next = mblock->freelist.head;
mblock->freelist.head = (struct fast_mblock_node *)pTrunkStart;
pMallocNode->ref_count = 0;
pMallocNode->alloc_count = alloc_count;
@ -533,11 +490,116 @@ static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
mblock->info.trunk_total_count++;
mblock->info.element_total_count += alloc_count;
if (mblock->malloc_trunk_callback.notify_func != NULL)
if (mblock->trunk_callbacks.notify_func != NULL)
{
mblock->malloc_trunk_callback.notify_func(trunk_size,
mblock->malloc_trunk_callback.args);
mblock->trunk_callbacks.notify_func(fast_mblock_notify_type_alloc,
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;
@ -551,10 +613,10 @@ static inline void fast_mblock_remove_trunk(struct fast_mblock_man *mblock,
mblock->info.trunk_total_count--;
mblock->info.element_total_count -= pMallocNode->alloc_count;
if (mblock->malloc_trunk_callback.notify_func != NULL)
if (mblock->trunk_callbacks.notify_func != NULL)
{
mblock->malloc_trunk_callback.notify_func(-1 * pMallocNode->trunk_size,
mblock->malloc_trunk_callback.args);
mblock->trunk_callbacks.notify_func(fast_mblock_notify_type_reclaim,
pMallocNode, mblock->trunk_callbacks.args);
}
}
@ -566,6 +628,24 @@ static inline void fast_mblock_ref_counter_op(struct fast_mblock_man *mblock,
{
struct fast_mblock_malloc *pMallocNode;
#ifdef FAST_MBLOCK_MAGIC_CHECK
int calc_offset;
calc_offset = sizeof(struct fast_mblock_malloc) +
pNode->index * mblock->info.block_size;
if (pNode->magic != FAST_MBLOCK_MAGIC_NUMBER ||
pNode->offset != calc_offset)
{
logCrit("file: "__FILE__", line: %d, "
"magic check for %s %s fail, node: %p, index: %d, offset: %d, "
"offset by index: %d, magic number: %d, expect magic: %d",
__LINE__, (is_inc ? "alloc" : "free"), mblock->info.name,
pNode, pNode->index, pNode->offset, calc_offset,
pNode->magic, FAST_MBLOCK_MAGIC_NUMBER);
return;
}
#endif
pMallocNode = FAST_MBLOCK_GET_TRUNK(pNode);
if (is_inc)
{
@ -586,38 +666,59 @@ static inline void fast_mblock_ref_counter_op(struct fast_mblock_man *mblock,
}
#define fast_mblock_ref_counter_inc(mblock, pNode) \
mblock->info.element_used_count++; \
fast_mblock_ref_counter_op(mblock, pNode, true)
#define fast_mblock_ref_counter_dec(mblock, pNode) \
mblock->info.element_used_count--; \
fast_mblock_ref_counter_op(mblock, pNode, false)
static void fast_mblock_free_trunk(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *trunk)
{
char *start;
char *p;
char *last;
if (mblock->object_callbacks.destroy_func != NULL)
{
start = (char *)(trunk + 1);
last = (char *)trunk + (trunk->trunk_size - mblock->info.block_size);
for (p = start; p <= last; p += mblock->info.block_size)
{
mblock->object_callbacks.destroy_func(
((struct fast_mblock_node *)p)->data,
mblock->object_callbacks.args);
}
}
free(trunk);
}
void fast_mblock_destroy(struct fast_mblock_man *mblock)
{
struct fast_mblock_malloc *pMallocNode;
struct fast_mblock_malloc *pMallocTmp;
if (IS_EMPTY(&mblock->trunks.head))
{
delete_from_mblock_list(mblock);
return;
}
if (!IS_EMPTY(&mblock->trunks.head))
{
pMallocNode = mblock->trunks.head.next;
while (pMallocNode != &mblock->trunks.head)
{
pMallocTmp = pMallocNode;
pMallocNode = pMallocNode->next;
pMallocNode = mblock->trunks.head.next;
while (pMallocNode != &mblock->trunks.head)
{
pMallocTmp = pMallocNode;
pMallocNode = pMallocNode->next;
fast_mblock_free_trunk(mblock, pMallocTmp);
}
free(pMallocTmp);
}
INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->free_chain_head = NULL;
mblock->info.element_used_count = 0;
mblock->info.delay_free_elements = 0;
mblock->info.element_total_count = 0;
INIT_HEAD(&mblock->trunks.head);
mblock->info.trunk_total_count = 0;
mblock->info.trunk_used_count = 0;
mblock->freelist.head = NULL;
mblock->info.element_used_count = 0;
mblock->info.delay_free_elements = 0;
mblock->info.element_total_count = 0;
}
if (mblock->need_lock) destroy_pthread_lock_cond_pair(&(mblock->lcp));
delete_from_mblock_list(mblock);
@ -631,10 +732,10 @@ static inline struct fast_mblock_node *alloc_node(
while (1)
{
if (mblock->free_chain_head != NULL)
if (mblock->freelist.head != NULL)
{
pNode = mblock->free_chain_head;
mblock->free_chain_head = pNode->next;
pNode = mblock->freelist.head;
mblock->freelist.head = pNode->next;
break;
}
@ -649,14 +750,15 @@ static inline struct fast_mblock_node *alloc_node(
mblock->delay_free_chain.tail = NULL;
}
fast_mblock_ref_counter_dec(mblock, pNode);
mblock->info.delay_free_elements--;
break;
}
if ((result=fast_mblock_prealloc(mblock)) == 0)
{
pNode = mblock->free_chain_head;
mblock->free_chain_head = pNode->next;
pNode = mblock->freelist.head;
mblock->freelist.head = pNode->next;
break;
}
@ -676,7 +778,6 @@ static inline struct fast_mblock_node *alloc_node(
if (pNode != NULL)
{
mblock->info.element_used_count++;
fast_mblock_ref_counter_inc(mblock, pNode);
}
@ -728,10 +829,9 @@ int fast_mblock_free(struct fast_mblock_man *mblock,
return result;
}
notify = (mblock->free_chain_head == NULL);
pNode->next = mblock->free_chain_head;
mblock->free_chain_head = pNode;
mblock->info.element_used_count--;
notify = (mblock->freelist.head == NULL);
pNode->next = mblock->freelist.head;
mblock->freelist.head = pNode;
fast_mblock_ref_counter_dec(mblock, pNode);
if (mblock->alloc_elements.need_wait && notify)
@ -755,74 +855,79 @@ static inline void batch_free(struct fast_mblock_man *mblock,
struct fast_mblock_chain *chain)
{
bool notify;
int count;
struct fast_mblock_node *pNode;
count = 0;
pNode = chain->head;
while (pNode != NULL)
{
mblock->info.element_used_count--;
++count;
fast_mblock_ref_counter_dec(mblock, pNode);
pNode = pNode->next;
}
notify = (mblock->free_chain_head == NULL);
chain->tail->next = mblock->free_chain_head;
mblock->free_chain_head = chain->head;
notify = (mblock->freelist.head == NULL);
chain->tail->next = mblock->freelist.head;
mblock->freelist.head = chain->head;
if (mblock->alloc_elements.need_wait && notify)
{
pthread_cond_broadcast(&mblock->lcp.cond);
}
}
struct fast_mblock_node *fast_mblock_batch_alloc(
struct fast_mblock_man *mblock, const int count)
int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
const int count, struct fast_mblock_chain *chain)
{
struct fast_mblock_chain chain;
struct fast_mblock_node *pNode;
int i;
int lr;
int result;
if (mblock->need_lock && (result=pthread_mutex_lock(
if (mblock->need_lock && (lr=pthread_mutex_lock(
&mblock->lcp.lock)) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_lock fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return NULL;
__LINE__, lr, STRERROR(lr));
return lr;
}
if ((chain.head=alloc_node(mblock)) != NULL)
{
chain.tail = chain.head;
for (i=1; i<count; i++)
{
if ((pNode=alloc_node(mblock)) == NULL)
{
if ((chain->head=alloc_node(mblock)) != NULL) {
chain->tail = chain->head;
for (i=1; i<count; i++) {
if ((pNode=alloc_node(mblock)) == NULL) {
break;
}
chain.tail->next = pNode;
chain.tail = pNode;
chain->tail->next = pNode;
chain->tail = pNode;
}
chain.tail->next = NULL;
chain->tail->next = NULL;
if (i != count) { //fail
batch_free(mblock, &chain);
chain.head = NULL;
if (i == count) {
result = 0;
} else { //fail
batch_free(mblock, chain);
chain->head = chain->tail = NULL;
result = ENOMEM;
}
} else {
chain->head = chain->tail = NULL;
result = ENOMEM;
}
if (mblock->need_lock && (result=pthread_mutex_unlock(
if (mblock->need_lock && (lr=pthread_mutex_unlock(
&mblock->lcp.lock)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_unlock fail, "
"errno: %d, error info: %s",
__LINE__, lr, STRERROR(lr));
}
return chain.head;
return result;
}
int fast_mblock_batch_free(struct fast_mblock_man *mblock,
@ -858,6 +963,32 @@ int fast_mblock_batch_free(struct fast_mblock_man *mblock,
return 0;
}
void fast_mblock_free_objects(struct fast_mblock_man *mblock,
void **objs, const int count)
{
void **obj;
void **end;
struct fast_mblock_node *previous;
struct fast_mblock_node *current;
struct fast_mblock_chain chain;
if (count == 0) {
return;
}
chain.head = previous = fast_mblock_to_node_ptr(objs[0]);
end = objs + count;
for (obj=objs+1; obj<end; obj++) {
current = fast_mblock_to_node_ptr(*obj);
previous->next = current;
previous = current;
}
previous->next = NULL;
chain.tail = previous;
fast_mblock_batch_free(mblock, &chain);
}
int fast_mblock_delay_free(struct fast_mblock_man *mblock,
struct fast_mblock_node *pNode, const int deley)
{
@ -885,9 +1016,7 @@ int fast_mblock_delay_free(struct fast_mblock_man *mblock,
mblock->delay_free_chain.tail = pNode;
pNode->next = NULL;
mblock->info.element_used_count--;
mblock->info.delay_free_elements++;
fast_mblock_ref_counter_dec(mblock, pNode);
if (mblock->need_lock && (result=pthread_mutex_unlock(
&mblock->lcp.lock)) != 0)
@ -940,7 +1069,7 @@ static int fast_mblock_chain_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)
@ -952,65 +1081,65 @@ static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count,
struct fast_mblock_malloc **ppFreelist)
{
struct fast_mblock_node *pPrevious;
struct fast_mblock_node *pCurrent;
struct fast_mblock_malloc *pMallocNode;
struct fast_mblock_node *free_chain_prev;
struct fast_mblock_node *current;
struct fast_mblock_malloc *malloc_node;
struct fast_mblock_malloc *freelist;
bool lookup_done;
lookup_done = false;
*reclaim_count = 0;
freelist = NULL;
pPrevious = NULL;
pCurrent = mblock->free_chain_head;
mblock->free_chain_head = NULL;
while (pCurrent != NULL)
free_chain_prev = NULL;
current = mblock->freelist.head;
mblock->freelist.head = NULL;
while (current != NULL)
{
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
if (pMallocNode->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done))
{ //keep in free chain
malloc_node = FAST_MBLOCK_GET_TRUNK(current);
if (malloc_node->ref_count > 0 ||
(malloc_node->ref_count == 0 && lookup_done))
{ /* keep in the free chain */
if (pPrevious != NULL)
if (free_chain_prev != NULL)
{
pPrevious->next = pCurrent;
free_chain_prev->next = current;
}
else
{
mblock->free_chain_head = pCurrent;
mblock->freelist.head = current;
}
pPrevious = pCurrent;
pCurrent = pCurrent->next;
if (pCurrent == NULL)
free_chain_prev = current;
current = current->next;
if (current == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
malloc_node = FAST_MBLOCK_GET_TRUNK(current);
while (pMallocNode->ref_count > 0 ||
(pMallocNode->ref_count == 0 && lookup_done))
while (malloc_node->ref_count > 0 ||
(malloc_node->ref_count == 0 && lookup_done))
{
pPrevious = pCurrent;
pCurrent = pCurrent->next;
if (pCurrent == NULL)
free_chain_prev = current;
current = current->next;
if (current == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
malloc_node = FAST_MBLOCK_GET_TRUNK(current);
}
}
while (pMallocNode->ref_count < 0 ||
(pMallocNode->ref_count == 0 && !lookup_done))
while (malloc_node->ref_count < 0 ||
(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);
pMallocNode->ref_count = -1;
fast_mblock_remove_trunk(mblock, malloc_node);
malloc_node->ref_count = -1;
pMallocNode->next = freelist;
freelist = pMallocNode;
malloc_node->next = freelist;
freelist = malloc_node;
(*reclaim_count)++;
if (reclaim_target > 0 && *reclaim_count == reclaim_target)
{
@ -1018,23 +1147,23 @@ static int fast_mblock_do_reclaim(struct fast_mblock_man *mblock,
}
}
pCurrent = pCurrent->next;
if (pCurrent == NULL)
current = current->next;
if (current == NULL)
{
goto OUTER;
}
pMallocNode = FAST_MBLOCK_GET_TRUNK(pCurrent);
malloc_node = FAST_MBLOCK_GET_TRUNK(current);
}
}
OUTER:
if (pPrevious != NULL)
if (free_chain_prev != NULL)
{
pPrevious->next = NULL;
free_chain_prev->next = NULL;
}
/*
{
bool old_need_lock;
old_need_lock = mblock->need_lock;
@ -1045,6 +1174,7 @@ OUTER:
mblock, *reclaim_count, fast_mblock_free_count(mblock));
mblock->need_lock = old_need_lock;
}
*/
*ppFreelist = freelist;
return (freelist != NULL ? 0 : ENOENT);
@ -1060,7 +1190,8 @@ void fast_mblock_free_trunks(struct fast_mblock_man *mblock,
{
pDeleted = freelist;
freelist = freelist->next;
free(pDeleted);
fast_mblock_free_trunk(mblock, pDeleted);
count++;
}
logDebug("file: "__FILE__", line: %d, "

View File

@ -24,13 +24,25 @@
#include <pthread.h>
#include "common_define.h"
#include "fc_memory.h"
#include "chain.h"
#include "logger.h"
/* following two macros for debug only */
/*
#define FAST_MBLOCK_MAGIC_CHECK 1
#define FAST_MBLOCK_MAGIC_NUMBER 1234567890
*/
#define FAST_MBLOCK_NAME_SIZE 32
#define FAST_MBLOCK_ORDER_BY_ALLOC_BYTES 1
#define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2
#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 */
struct fast_mblock_node
@ -38,6 +50,10 @@ struct fast_mblock_node
struct fast_mblock_node *next;
int offset; //trunk offset
int recycle_timestamp;
#ifdef FAST_MBLOCK_MAGIC_CHECK
int index;
int magic; //magic number
#endif
char data[0]; //the data buffer
};
@ -56,13 +72,18 @@ struct fast_mblock_chain {
struct fast_mblock_node *tail;
};
typedef int (*fast_mblock_alloc_init_func)(void *element, void *args);
/* call by alloc trunk */
typedef int (*fast_mblock_object_init_func)(void *element, void *args);
/* call by free trunk */
typedef void (*fast_mblock_object_destroy_func)(void *element, void *args);
typedef int (*fast_mblock_malloc_trunk_check_func)(
const int alloc_bytes, void *args);
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
{
@ -70,6 +91,7 @@ struct fast_mblock_info
int element_size; //element size
int trunk_size; //trunk size
int instance_count; //instance count
int block_size;
int64_t element_total_count; //total element count
int64_t element_used_count; //used element count
int64_t delay_free_elements; //delay free element count
@ -82,7 +104,13 @@ struct fast_mblock_trunks
struct fast_mblock_malloc head; //malloc chain to be freed
};
struct fast_mblock_malloc_trunk_callback
struct fast_mblock_object_callbacks {
fast_mblock_object_init_func init_func;
fast_mblock_object_destroy_func destroy_func;
void *args;
};
struct fast_mblock_trunk_callbacks
{
fast_mblock_malloc_trunk_check_func check_func;
fast_mblock_malloc_trunk_notify_func notify_func;
@ -99,24 +127,28 @@ struct fast_mblock_man
int64_t limit; //<= 0 for no limit
bool *pcontinue_flag;
} 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_chain delay_free_chain; //delay free node chain
fast_mblock_alloc_init_func alloc_init_func;
struct fast_mblock_malloc_trunk_callback malloc_trunk_callback;
struct fast_mblock_object_callbacks object_callbacks;
struct fast_mblock_trunk_callbacks trunk_callbacks;
bool need_lock; //if need mutex lock
pthread_lock_cond_pair_t lcp; //for read / write free node chain
struct fast_mblock_man *prev; //for stat manager
struct fast_mblock_man *next; //for stat manager
void *init_args; //args for alloc_init_func
};
#define GET_BLOCK_SIZE(info) \
(MEM_ALIGN(sizeof(struct fast_mblock_node) + (info).element_size))
#define fast_mblock_get_block_size(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) \
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
@ -127,27 +159,9 @@ extern "C" {
#endif
#define fast_mblock_init(mblock, element_size, alloc_elements_once) \
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \
0, NULL, NULL, true)
/**
mblock init
parameters:
mblock: the mblock pointer
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
init_func: the init function
init_args: the args for init_func
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
int fast_mblock_init_ex(struct fast_mblock_man *mblock,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit,
fast_mblock_alloc_init_func init_func, void *init_args,
const bool need_lock);
/**
mblock init
parameters:
@ -156,22 +170,18 @@ parameters:
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
init_func: the init function
init_args: the args for init_func
prealloc_trunk_count: prealloc trunk node count
object_callbacks: the object callback functions and args
need_lock: if need lock
malloc_trunk_check: the malloc trunk check function pointor
malloc_trunk_notify: the malloc trunk notify function pointor
malloc_trunk_args: the malloc trunk args
trunk_callbacks: the trunk callback functions and args
return error no, 0 for success, != 0 fail
*/
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,
fast_mblock_alloc_init_func init_func,
void *init_args, const bool need_lock,
fast_mblock_malloc_trunk_check_func malloc_trunk_check,
fast_mblock_malloc_trunk_notify_func malloc_trunk_notify,
void *malloc_trunk_args);
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);
/**
mblock init
@ -181,23 +191,51 @@ parameters:
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
init_func: the init function
init_args: the args for init_func
init_func: the object init function
init_args: the args for object init function
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
const char *name, const int element_size,
const int alloc_elements_once,
const int64_t alloc_elements_limit,
fast_mblock_alloc_init_func init_func,
void *init_args, const bool need_lock)
const int alloc_elements_once, const int64_t alloc_elements_limit,
fast_mblock_object_init_func init_func, void *init_args,
const bool need_lock)
{
const int prealloc_trunk_count = 0;
struct fast_mblock_object_callbacks object_callbacks;
object_callbacks.init_func = init_func;
object_callbacks.destroy_func = NULL;
object_callbacks.args = init_args;
return fast_mblock_init_ex2(mblock, name, element_size,
alloc_elements_once, alloc_elements_limit, init_func,
init_args, need_lock, NULL, NULL, NULL);
alloc_elements_once, alloc_elements_limit,
prealloc_trunk_count, &object_callbacks,
need_lock, NULL);
}
/**
mblock init
parameters:
mblock: the mblock pointer
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
object_callbacks: the object callback functions and args
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, fast_mblock_object_init_func
init_func, void *init_args, const bool need_lock)
{
return fast_mblock_init_ex1(mblock, NULL, element_size,
alloc_elements_once, alloc_elements_limit,
init_func, init_args, need_lock);
}
/**
mblock destroy
parameters:
@ -225,6 +263,15 @@ static inline int fast_mblock_set_need_wait(struct fast_mblock_man *mblock,
return 0;
}
static inline void fast_mblock_set_exceed_log_level(
struct fast_mblock_man *mblock, const int log_level)
{
mblock->alloc_elements.exceed_log_level = log_level;
}
#define fast_mblock_set_exceed_silence(mblock) \
fast_mblock_set_exceed_log_level(mblock, LOG_NOTHING)
/**
alloc a node from the mblock
parameters:
@ -243,6 +290,17 @@ return 0 for success, return none zero if fail
int fast_mblock_free(struct fast_mblock_man *mblock,
struct fast_mblock_node *pNode);
/**
batch alloc nodes from the mblock
parameters:
mblock: the mblock pointer
count: alloc count
chain: return the mblock node chain
return 0 for success, return none zero if fail
*/
int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
const int count, struct fast_mblock_chain *chain);
/**
batch alloc nodes from the mblock
parameters:
@ -250,8 +308,16 @@ parameters:
count: alloc count
return the alloced node head, return NULL if fail
*/
struct fast_mblock_node *fast_mblock_batch_alloc(
struct fast_mblock_man *mblock, const int count);
static inline struct fast_mblock_node *fast_mblock_batch_alloc1(
struct fast_mblock_man *mblock, const int count)
{
struct fast_mblock_chain chain;
if (fast_mblock_batch_alloc(mblock, count, &chain) == 0) {
return chain.head;
} else {
return NULL;
}
}
/**
batch free nodes
@ -304,6 +370,17 @@ static inline int fast_mblock_free_object(struct fast_mblock_man *mblock,
return fast_mblock_free(mblock, fast_mblock_to_node_ptr(object));
}
/**
free objects (put objects to the mblock)
parameters:
mblock: the mblock pointer
objs: the object array to free
count: the count of the object array
return none
*/
void fast_mblock_free_objects(struct fast_mblock_man *mblock,
void **objs, const int count);
/**
delay free a object (put a node to the mblock)
parameters:
@ -334,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);
#define fast_mblock_total_count(mblock) (mblock)->total_count
#define fast_mblock_total_count(mblock) (mblock)->info.element_total_count
/**
init mblock manager

View File

@ -48,6 +48,10 @@ int fast_mpool_init(struct fast_mpool_man *mpool,
mpool->malloc_chain_head = NULL;
mpool->free_chain_head = NULL;
mpool->alloc_count = 0;
mpool->alloc_bytes = 0;
mpool->reset.count = 0;
mpool->reset.last_alloc_count = 0;
return 0;
}
@ -138,6 +142,8 @@ static inline void *fast_mpool_do_alloc(struct fast_mpool_man *mpool,
fast_mpool_remove_free_node(mpool, pMallocNode);
}
mpool->alloc_count++;
mpool->alloc_bytes += size;
return ptr;
}
return NULL;
@ -196,19 +202,26 @@ void *fast_mpool_memdup(struct fast_mpool_man *mpool,
void fast_mpool_reset(struct fast_mpool_man *mpool)
{
struct fast_mpool_malloc *pMallocNode;
struct fast_mpool_malloc *pMallocNode;
mpool->free_chain_head = NULL;
pMallocNode = mpool->malloc_chain_head;
while (pMallocNode != NULL)
{
mpool->reset.count++;
if (mpool->reset.last_alloc_count == mpool->alloc_count)
{
return;
}
mpool->reset.last_alloc_count = mpool->alloc_count;
mpool->free_chain_head = NULL;
pMallocNode = mpool->malloc_chain_head;
while (pMallocNode != NULL)
{
pMallocNode->free_ptr = pMallocNode->base_ptr;
pMallocNode->free_next = mpool->free_chain_head;
mpool->free_chain_head = pMallocNode;
pMallocNode = pMallocNode->malloc_next;
}
pMallocNode = pMallocNode->malloc_next;
}
}
void fast_mpool_stats(struct fast_mpool_man *mpool,
@ -243,12 +256,22 @@ void fast_mpool_stats(struct fast_mpool_man *mpool,
void fast_mpool_log_stats(struct fast_mpool_man *mpool)
{
struct fast_mpool_stats stats;
char sz_total_bytes[32];
char sz_free_bytes[32];
char sz_alloc_bytes[32];
fast_mpool_stats(mpool, &stats);
long_to_comma_str(stats.total_bytes, sz_total_bytes);
long_to_comma_str(stats.free_bytes, sz_free_bytes);
long_to_comma_str(mpool->alloc_bytes, sz_alloc_bytes);
logInfo("alloc_size_once: %d, discard_size: %d, "
"bytes: {total: %"PRId64", free: %"PRId64"}, "
"trunk_count: {total: %d, free: %d}",
mpool->alloc_size_once, mpool->discard_size,
stats.total_bytes, stats.free_bytes,
stats.total_trunk_count, stats.free_trunk_count);
"bytes: {total: %s, free: %s}, "
"trunk_count: {total: %d, free: %d}, "
"alloc_count: %"PRId64", alloc_bytes: %s, "
"reset_count: %"PRId64, mpool->alloc_size_once,
mpool->discard_size, sz_total_bytes,
sz_free_bytes, stats.total_trunk_count,
stats.free_trunk_count, mpool->alloc_count,
sz_alloc_bytes, mpool->reset.count);
}

View File

@ -37,10 +37,16 @@ struct fast_mpool_malloc
struct fast_mpool_man
{
struct fast_mpool_malloc *malloc_chain_head; //malloc chain to be freed
struct fast_mpool_malloc *free_chain_head; //free node chain
int alloc_size_once; //alloc size once, default: 1MB
int discard_size; //discard size, default: 64 bytes
struct fast_mpool_malloc *malloc_chain_head; //malloc chain to be freed
struct fast_mpool_malloc *free_chain_head; //free node chain
int alloc_size_once; //alloc size once, default: 1MB
int discard_size; //discard size, default: 64 bytes
int64_t alloc_count;
int64_t alloc_bytes;
struct {
int64_t count;
int64_t last_alloc_count;
} reset;
};
struct fast_mpool_stats

View File

@ -25,667 +25,214 @@
#include "fc_memory.h"
#include "fast_task_queue.h"
static struct fast_task_queue g_free_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)
static int task_alloc_init(struct fast_task_info *task,
struct fast_task_queue *queue)
{
int result;
if ((result=init_pthread_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
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)
{
task->arg = (char *)task + ALIGNED_TASK_INFO_SIZE + queue->padding_size;
task->send.ptr = &task->send.holder;
task->send.ptr->size = queue->min_buff_size;
if (queue->malloc_whole_block) {
task->send.ptr->data = (char *)task->arg + queue->arg_size;
} else {
task->send.ptr->data = (char *)fc_malloc(task->send.ptr->size);
if (task->send.ptr->data == NULL) {
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)
{
g_free_queue.head = head;
if (queue->double_buffers) {
task->recv.ptr = &task->recv.holder;
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)
{
g_free_queue.tail->next = head;
task->free_queue = queue;
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;
}
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;
int i;
#define MAX_DATA_SIZE (256 * 1024 * 1024)
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)
{
return pTask;
aligned_min_size = MEM_ALIGN(min_buff_size);
aligned_max_size = MEM_ALIGN(max_buff_size);
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)
{
return NULL;
}
if (aligned_max_size > aligned_min_size) {
queue->malloc_whole_block = false;
max_data_size = 0;
} else {
struct rlimit rlimit_data;
for (i=0; i<10; i++)
{
pthread_mutex_lock(&g_free_queue.lock);
if (g_free_queue.alloc_connections >= g_free_queue.max_connections)
{
if (g_free_queue.head == NULL)
{
pthread_mutex_unlock(&g_free_queue.lock);
return NULL;
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;
}
}
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,
const bool copy_data)
void free_queue_destroy(struct fast_task_queue *queue)
{
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;
new_buff = (char *)fc_malloc(new_size);
if (new_buff == NULL)
{
if (new_buff == NULL) {
return ENOMEM;
}
else
{
if (copy_data && pTask->offset > 0) {
memcpy(new_buff, pTask->data, pTask->offset);
}
free(pTask->data);
pTask->size = new_size;
pTask->data = new_buff;
return 0;
if (copy_data && buffer->offset > 0) {
memcpy(new_buff, buffer->data, buffer->offset);
}
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';
pTask->length = 0;
pTask->offset = 0;
pTask->req_count = 0;
*(task->client_ip) = '\0';
task->send.ptr->length = 0;
task->send.ptr->offset = 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
{
_realloc_buffer(pTask, g_free_queue.min_buff_size, false);
}
if (task->free_queue->double_buffers) {
task->recv.ptr->length = 0;
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)
{
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;
fast_mblock_free_object(&task->free_queue->allocator, task);
}
int free_queue_count()
{
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,
int free_queue_get_new_buffer_size(const int min_buff_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, "
"can't change buffer size because NOT supported", __LINE__);
return EOPNOTSUPP;
}
if (expect_size > max_buff_size)
{
if (expect_size > max_buff_size) {
logError("file: "__FILE__", line: %d, "
"can't change buffer size because expect buffer size: %d "
"exceeds max buffer size: %d", __LINE__, expect_size,
max_buff_size);
return EOVERFLOW;
} else if (expect_size == max_buff_size) {
*new_size = max_buff_size;
return 0;
}
*new_size = min_buff_size;
if (expect_size > min_buff_size)
{
while (*new_size < expect_size)
{
if (expect_size > min_buff_size) {
while (*new_size < expect_size) {
*new_size *= 2;
}
if (*new_size > max_buff_size)
{
if (*new_size > max_buff_size) {
*new_size = max_buff_size;
}
}
@ -693,41 +240,43 @@ int task_queue_get_new_buffer_size(const int min_buff_size,
return 0;
}
#define _get_new_buffer_size(pQueue, expect_size, new_size) \
task_queue_get_new_buffer_size(pQueue->min_buff_size, \
pQueue->max_buff_size, expect_size, new_size)
#define _get_new_buffer_size(queue, expect_size, new_size) \
free_queue_get_new_buffer_size(queue->min_buff_size, \
queue->max_buff_size, expect_size, new_size)
int task_queue_set_buffer_size(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size)
int free_queue_set_buffer_size(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size)
{
int result;
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;
}
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 _realloc_buffer(pTask, new_size, false);
return _realloc_buffer(buffer, new_size, false);
}
int task_queue_realloc_buffer(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size)
int free_queue_realloc_buffer(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size)
{
int result;
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;
}
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 _realloc_buffer(pTask, new_size, true);
return _realloc_buffer(buffer, new_size, true);
}

View File

@ -23,8 +23,10 @@
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "fc_list.h"
#include "ioevent.h"
#include "fast_timer.h"
#include "fast_mblock.h"
#define FC_NOTIFY_READ_FD(tdata) (tdata)->pipe_fds[0]
#define FC_NOTIFY_WRITE_FD(tdata) (tdata)->pipe_fds[1]
@ -35,18 +37,27 @@ struct nio_thread_data;
struct fast_task_info;
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
typedef int (*TaskFinishCallback) (struct fast_task_info *pTask);
typedef void (*TaskCleanUpCallback) (struct fast_task_info *pTask);
typedef int (*TaskInitCallback)(struct fast_task_info *pTask);
typedef void (*TaskCleanUpCallback) (struct fast_task_info *task);
typedef int (*TaskInitCallback)(struct fast_task_info *task, void *arg);
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);
struct sf_network_handler;
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
{
FastTimerEntry timer; //must first
int fd;
int res; //just for io_uring, since v1.0.81
IOEventCallback callback;
} IOEventEntry;
@ -57,6 +68,7 @@ struct nio_thread_data
int pipe_fds[2]; //for notify
struct fast_task_info *deleted_list; //tasks for cleanup
ThreadLoopCallback thread_loop_callback;
ThreadLoopCallback busy_polling_callback;
void *arg; //extra argument pointer
struct {
struct fast_task_info *head;
@ -68,6 +80,9 @@ struct nio_thread_data
bool enabled;
volatile int64_t counter;
} notify; //for thread notify
int timeout_ms; //for restore
struct fc_list_head polling_queue; //for RDMA busy polling
};
struct ioevent_notify_entry
@ -76,109 +91,225 @@ struct ioevent_notify_entry
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
{
IOEventEntry event; //must first
IOEventEntry event; //must first
union {
char server_ip[IP_ADDRESS_SIZE];
char client_ip[IP_ADDRESS_SIZE];
};
void *arg; //extra argument pointer
char *data; //buffer for write or read
void *arg; //extra argument pointer
char *recv_body; //for extra (dynamic) recv buffer
struct {
struct iovec *iovs;
int count;
} iovec_array; //for writev
int size; //alloc size
int length; //data length
int offset; //current offset
struct fast_net_buffer_wrapper send; //send buffer
struct fast_net_buffer_wrapper recv; //recv buffer
uint16_t port; //peer port
struct {
int8_t is_client;
uint8_t op_type;
} uring; //just for io_uring, since v1.0.81
struct {
uint8_t current;
volatile uint8_t notify;
} nio_stages; //stages for network IO
int (*continue_callback)(struct fast_task_info *task); //for continue stage
volatile int8_t reffer_count;
volatile int8_t canceled; //if task canceled
short connect_timeout; //for client side
short network_timeout;
int64_t req_count; //request count
TaskFinishCallback finish_callback;
struct nio_thread_data *thread_data;
void *ctx; //context pointer for libserverframe nio
struct fast_task_info *next;
volatile int8_t canceled; //if task canceled
volatile int8_t shrinked; //if task shrinked, since V1.0.81
volatile int reffer_count;
int pending_send_count;
int64_t req_count; //request count
struct {
int64_t last_req_count;
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_info *head;
struct fast_task_info *tail;
pthread_mutex_t lock;
int max_connections;
int alloc_connections;
int alloc_task_once;
int min_buff_size;
int max_buff_size;
int arg_size;
int block_size;
bool malloc_whole_block;
int min_buff_size;
int max_buff_size;
int padding_size; //for last field: conn[0]
int arg_size; //for arg pointer
int block_size;
bool malloc_whole_block;
bool double_buffers; //if send buffer and recv buffer are independent
bool need_shrink;
struct fast_mblock_man allocator;
TaskInitCallback init_callback;
void *init_arg;
TaskReleaseCallback release_callback;
};
#ifdef __cplusplus
extern "C" {
#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 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)
const int max_buff_size, const int arg_size)
{
return free_queue_init_ex2(max_connections, init_connections,
alloc_task_once, min_buff_size, max_buff_size, arg_size, NULL);
const int padding_size = 0;
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,
const int min_buff_size, const int max_buff_size, const int arg_size)
static inline int free_queue_init(struct fast_task_queue *queue,
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,
0, min_buff_size, max_buff_size, arg_size, NULL);
const char *name = "";
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);
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);
void free_queue_destroy(struct fast_task_queue *queue);
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);
int task_queue_push(struct fast_task_queue *pQueue, \
struct fast_task_info *pTask);
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue);
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);
static inline int free_queue_count(struct fast_task_queue *queue)
{
return queue->allocator.info.element_total_count -
queue->allocator.info.element_used_count;
}
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);
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
}
#endif

View File

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

View File

@ -36,6 +36,7 @@ extern "C" {
old_value = __sync_add_and_fetch(&var, 0); \
} while (new_value != old_value)
#define FC_ATOMIC_SET(var, new_value) \
do { \
typeof(var) _old_value; \
@ -48,6 +49,27 @@ extern "C" {
} while (new_value != _old_value); \
} while (0)
#define FC_ATOMIC_SET_BY_CONDITION(var, value, skip_operator) \
do { \
typeof(var) old; \
old = __sync_add_and_fetch(&var, 0); \
if (value skip_operator old) { \
break; \
} \
if (__sync_bool_compare_and_swap(&var, old, value)) { \
break; \
} \
} while (1)
#define FC_ATOMIC_SET_LARGER(var, value) \
FC_ATOMIC_SET_BY_CONDITION(var, value, <=)
#define FC_ATOMIC_SET_SMALLER(var, value) \
FC_ATOMIC_SET_BY_CONDITION(var, value, >=)
#ifdef __cplusplus
}
#endif

View File

@ -45,6 +45,16 @@ fc_list_add_before (struct fc_list_head *_new, struct fc_list_head *current)
_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
fc_list_add_internal (struct fc_list_head *_new, struct fc_list_head *prev,
struct fc_list_head *next)

View File

@ -15,22 +15,14 @@
//fc_queue.c
#include <errno.h>
#include <pthread.h>
#include <inttypes.h>
#include "logger.h"
#include "shared_func.h"
#include "pthread_func.h"
#include "fc_queue.h"
#define FC_QUEUE_NEXT_PTR(queue, data) \
*((void **)(((char *)data) + queue->next_ptr_offset))
int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
{
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;
}
@ -43,12 +35,12 @@ int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
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)
{
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
FC_QUEUE_NEXT_PTR(queue, data) = NULL;
if (queue->tail == NULL) {
queue->head = data;
@ -58,15 +50,58 @@ void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify)
*notify = false;
}
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 *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
do {
data = queue->head;
if (data == NULL) {
@ -74,7 +109,7 @@ void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
break;
}
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock);
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head;
}
@ -86,7 +121,7 @@ void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
}
} while (0);
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
@ -94,7 +129,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
{
void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
do {
data = queue->head;
if (data == NULL) {
@ -102,7 +137,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
break;
}
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock);
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head;
}
@ -111,7 +146,7 @@ void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
}
} while (0);
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
@ -123,7 +158,7 @@ void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
return;
}
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
FC_QUEUE_NEXT_PTR(queue, qinfo->tail) = queue->head;
queue->head = qinfo->head;
if (queue->tail == NULL) {
@ -132,7 +167,7 @@ void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
} else {
*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,
@ -143,7 +178,7 @@ void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
return;
}
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
if (queue->head == NULL) {
queue->head = qinfo->head;
*notify = true;
@ -152,16 +187,16 @@ void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
*notify = false;
}
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,
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 (blocked) {
pthread_cond_wait(&queue->lc_pair.cond, &queue->lc_pair.lock);
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
}
}
@ -172,7 +207,7 @@ void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
} else {
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,
@ -180,22 +215,129 @@ void *fc_queue_timedpop(struct fc_queue *queue,
{
void *data;
PTHREAD_MUTEX_LOCK(&queue->lc_pair.lock);
do {
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
data = queue->head;
if (data == NULL) {
fc_cond_timedwait(&queue->lcp, timeout, time_unit);
data = queue->head;
if (data == NULL) {
fc_cond_timedwait(&queue->lc_pair, timeout, time_unit);
data = queue->head;
}
}
if (data != NULL) {
queue->head = FC_QUEUE_NEXT_PTR(queue, data);
if (queue->head == NULL) {
queue->tail = NULL;
}
if (data != NULL) {
queue->head = FC_QUEUE_NEXT_PTR(queue, data);
if (queue->head == NULL) {
queue->tail = NULL;
}
} while (0);
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
PTHREAD_MUTEX_UNLOCK(&queue->lc_pair.lock);
return data;
}
void *fc_queue_timedpeek(struct fc_queue *queue,
const int timeout, const int time_unit)
{
void *data;
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
data = queue->head;
if (data == NULL) {
fc_cond_timedwait(&queue->lcp, timeout, time_unit);
data = queue->head;
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, const int count, struct fc_queue_info *chain)
{
struct fast_mblock_node *node;
if ((node=fast_mblock_batch_alloc1(mblock, count)) == NULL) {
chain->head = chain->tail = NULL;
return ENOMEM;
}
chain->head = chain->tail = node->data;
while ((node=node->next) != NULL) {
FC_QUEUE_NEXT_PTR(queue, chain->tail) = node->data;
chain->tail = node->data;
}
FC_QUEUE_NEXT_PTR(queue, chain->tail) = NULL;
return 0;
}
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, struct fc_queue_info *qinfo)
{
struct fast_mblock_node *previous;
struct fast_mblock_node *current;
struct fast_mblock_chain chain;
void *data;
if (qinfo->head == NULL) {
return 0;
}
chain.head = previous = fast_mblock_to_node_ptr(qinfo->head);
data = FC_QUEUE_NEXT_PTR(queue, qinfo->head);
while (data != NULL) {
current = fast_mblock_to_node_ptr(data);
previous->next = current;
previous = current;
data = FC_QUEUE_NEXT_PTR(queue, data);
}
previous->next = NULL;
chain.tail = previous;
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

@ -18,11 +18,8 @@
#ifndef _FC_QUEUE_H
#define _FC_QUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "fast_mblock.h"
struct fc_queue_info
{
@ -34,10 +31,14 @@ struct fc_queue
{
void *head;
void *tail;
pthread_lock_cond_pair_t lc_pair;
pthread_lock_cond_pair_t lcp;
int next_ptr_offset;
};
#define FC_QUEUE_NEXT_PTR(queue, data) \
*((void **)(((char *)data) + (queue)->next_ptr_offset))
#ifdef __cplusplus
extern "C" {
#endif
@ -48,7 +49,7 @@ void fc_queue_destroy(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(
@ -56,12 +57,19 @@ static inline void fc_queue_terminate_all(
{
int i;
for (i=0; i<count; i++) {
pthread_cond_signal(&(queue->lc_pair.cond));
pthread_cond_signal(&(queue->lcp.cond));
}
}
#define fc_queue_notify(queue) fc_queue_terminate(queue)
#define fc_queue_notify_all(queue, count) \
fc_queue_terminate_all(queue, count)
//notify by the caller
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)
{
@ -69,10 +77,23 @@ static inline void fc_queue_push(struct fc_queue *queue, void *data)
fc_queue_push_ex(queue, data, &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)
{
bool notify;
@ -89,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);
if (notify) {
pthread_cond_signal(&(queue->lc_pair.cond));
pthread_cond_signal(&(queue->lcp.cond));
}
}
@ -110,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);
if (notify) {
pthread_cond_signal(&(queue->lc_pair.cond));
pthread_cond_signal(&(queue->lcp.cond));
}
}
@ -142,12 +163,39 @@ static inline bool fc_queue_empty(struct fc_queue *queue)
{
bool empty;
pthread_mutex_lock(&queue->lc_pair.lock);
pthread_mutex_lock(&queue->lcp.lock);
empty = (queue->head == NULL);
pthread_mutex_unlock(&queue->lc_pair.lock);
pthread_mutex_unlock(&queue->lcp.lock);
return empty;
}
static inline int fc_queue_count(struct fc_queue *queue)
{
int count;
void *data;
count = 0;
pthread_mutex_lock(&queue->lcp.lock);
data = queue->head;
while (data != NULL)
{
++count;
data = FC_QUEUE_NEXT_PTR(queue, data);
}
pthread_mutex_unlock(&queue->lcp.lock);
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,
const int timeout, const int time_unit);
@ -160,6 +208,26 @@ void *fc_queue_timedpop(struct fc_queue *queue,
#define fc_queue_timedpop_us(queue, timeout_us) \
fc_queue_timedpop(queue, timeout_us, FC_TIME_UNIT_USECOND)
void *fc_queue_timedpeek(struct fc_queue *queue,
const int timeout, const int time_unit);
#define fc_queue_timedpeek_sec(queue, timeout) \
fc_queue_timedpeek(queue, timeout, FC_TIME_UNIT_SECOND)
#define fc_queue_timedpeek_ms(queue, timeout_ms) \
fc_queue_timedpeek(queue, timeout_ms, FC_TIME_UNIT_MSECOND)
#define fc_queue_timedpeek_us(queue, timeout_us) \
fc_queue_timedpeek(queue, timeout_us, FC_TIME_UNIT_USECOND)
int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, const int count, struct fc_queue_info *chain);
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, struct fc_queue_info *qinfo);
int fc_queue_remove(struct fc_queue *queue, void *data);
#ifdef __cplusplus
}
#endif

View File

@ -79,7 +79,7 @@ static int _hash_alloc_buckets(HashArray *pHash, const unsigned int old_capacity
return 0;
}
unsigned int *hash_get_prime_capacity(const int capacity)
unsigned int *fc_hash_get_prime_capacity(const int capacity)
{
unsigned int *pprime;
unsigned int *prime_end;
@ -95,14 +95,14 @@ unsigned int *hash_get_prime_capacity(const int capacity)
return NULL;
}
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
const unsigned int capacity, const double load_factor, \
const int64_t max_bytes, const bool bMallocValue)
{
int result;
memset(pHash, 0, sizeof(HashArray));
pHash->capacity = hash_get_prime_capacity(capacity);
pHash->capacity = fc_hash_get_prime_capacity(capacity);
if (pHash->capacity == NULL)
{
return EINVAL;
@ -129,7 +129,7 @@ int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
return 0;
}
int hash_set_locks(HashArray *pHash, const int lock_count)
int fc_hash_set_locks(HashArray *pHash, const int lock_count)
{
size_t bytes;
pthread_mutex_t *lock;
@ -168,7 +168,7 @@ int hash_set_locks(HashArray *pHash, const int lock_count)
return 0;
}
void hash_destroy(HashArray *pHash)
void fc_hash_destroy(HashArray *pHash)
{
HashData **ppBucket;
HashData **bucket_end;
@ -238,7 +238,7 @@ void hash_destroy(HashArray *pHash)
}
int hash_stat(HashArray *pHash, HashStat *pStat, \
int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
int *stat_by_lens, const int stat_size)
{
HashData **ppBucket;
@ -299,13 +299,13 @@ int hash_stat(HashArray *pHash, HashStat *pStat, \
return 0;
}
void hash_stat_print(HashArray *pHash)
void fc_hash_stat_print(HashArray *pHash)
{
#define STAT_MAX_NUM 64
HashStat hs;
int stats[STAT_MAX_NUM];
if (hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
if (fc_hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
{
printf("hash max length exceeds %d!\n", STAT_MAX_NUM);
return;
@ -381,7 +381,7 @@ static int _rehash(HashArray *pHash)
pOldCapacity = pHash->capacity;
if (pHash->is_malloc_capacity)
{
pHash->capacity = hash_get_prime_capacity(*pOldCapacity);
pHash->capacity = fc_hash_get_prime_capacity(*pOldCapacity);
}
else
{
@ -456,7 +456,7 @@ static int _hash_conflict_count(HashArray *pHash)
return conflict_count;
}
int hash_best_op(HashArray *pHash, const int suggest_capacity)
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
{
int old_capacity;
int conflict_count;
@ -513,7 +513,7 @@ int hash_best_op(HashArray *pHash, const int suggest_capacity)
pHash->is_malloc_capacity = true;
//hash_stat_print(pHash);
//fc_hash_stat_print(pHash);
return 1;
}
@ -537,7 +537,7 @@ static HashData *_chain_find_entry(HashData **ppBucket, const void *key, \
return NULL;
}
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len)
HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len)
{
unsigned int hash_code;
HashData **ppBucket;
@ -553,7 +553,7 @@ HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len)
return hash_data;
}
void *hash_find(HashArray *pHash, const void *key, const int key_len)
void *fc_hash_find(HashArray *pHash, const void *key, const int key_len)
{
unsigned int hash_code;
HashData **ppBucket;
@ -576,10 +576,10 @@ void *hash_find(HashArray *pHash, const void *key, const int key_len)
}
}
int hash_find2(HashArray *pHash, const string_t *key, string_t *value)
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value)
{
HashData *hdata;
if ((hdata=hash_find1_ex(pHash, key)) == NULL)
if ((hdata=fc_hash_find1_ex(pHash, key)) == NULL)
{
return ENOENT;
}
@ -589,12 +589,12 @@ int hash_find2(HashArray *pHash, const string_t *key, string_t *value)
return 0;
}
HashData *hash_find1_ex(HashArray *pHash, const string_t *key)
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key)
{
return hash_find_ex(pHash, key->str, key->len);
return fc_hash_find_ex(pHash, key->str, key->len);
}
int hash_get(HashArray *pHash, const void *key, const int key_len,
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
void *value, int *value_len)
{
unsigned int hash_code;
@ -628,7 +628,7 @@ int hash_get(HashArray *pHash, const void *key, const int key_len,
return result;
}
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
void *value, const int value_len, const bool needLock)
{
unsigned int hash_code;
@ -760,7 +760,7 @@ int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
return 1;
}
int64_t hash_inc_value(const HashData *old_data, const int inc,
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg)
{
int64_t n;
@ -768,27 +768,26 @@ int64_t hash_inc_value(const HashData *old_data, const int inc,
{
if (old_data->value_len < *new_value_len)
{
memcpy(new_value, old_data->value, old_data->value_len);
new_value[old_data->value_len] = '\0';
n = strtoll(new_value, NULL, 10);
n += inc;
memcpy(new_value, old_data->value, old_data->value_len);
new_value[old_data->value_len] = '\0';
n = strtoll(new_value, NULL, 10);
n += inc;
}
else
{
n = inc;
}
*new_value_len = sprintf(new_value, "%"PRId64, n);
}
else
{
n = inc;
*new_value_len = sprintf(new_value, "%"PRId64, n);
}
*new_value_len = fc_itoa(n, new_value);
return n;
}
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
const int inc, char *value, int *value_len,
ConvertValueFunc convert_func, void *arg)
{
@ -823,7 +822,7 @@ int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
}
}
}
result = hash_insert_ex(pHash, key, key_len, value, *value_len, false);
result = fc_hash_insert_ex(pHash, key, key_len, value, *value_len, false);
if (result < 0)
{
*value = '\0';
@ -839,7 +838,7 @@ int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
return result;
}
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
const char *value, const int offset, const int value_len)
{
unsigned int hash_code;
@ -881,7 +880,7 @@ int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
memcpy(pNewBuff, hash_data->value, offset);
}
memcpy(pNewBuff + offset, value, value_len);
result = hash_insert_ex(pHash, key, key_len, pNewBuff,
result = fc_hash_insert_ex(pHash, key, key_len, pNewBuff,
offset + value_len, false);
free(pNewBuff);
}
@ -892,8 +891,8 @@ int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
result = ENOENT;
break;
}
result = hash_insert_ex(pHash, key, key_len, (void *)value,
value_len, false);
result = fc_hash_insert_ex(pHash, key, key_len,
(void *)value, value_len, false);
}
if (result < 0)
@ -910,7 +909,7 @@ int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
return result;
}
int hash_delete(HashArray *pHash, const void *key, const int key_len)
int fc_hash_delete(HashArray *pHash, const void *key, const int key_len)
{
HashData **ppBucket;
HashData *hash_data;
@ -943,7 +942,7 @@ int hash_delete(HashArray *pHash, const void *key, const int key_len)
return result;
}
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
{
HashData **ppBucket;
HashData **bucket_end;
@ -972,12 +971,12 @@ int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
return 0;
}
int hash_count(HashArray *pHash)
int fc_hash_count(HashArray *pHash)
{
return pHash->item_count;
}
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
{
if (pHash->lock_count <= 0)
{
@ -988,7 +987,7 @@ int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
pHash->lock_count);
}
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
{
if (pHash->lock_count <= 0)
{
@ -1315,12 +1314,12 @@ int calc_hashnr1_ex(const void* key, const int key_len, \
\
return h; \
int simple_hash(const void* key, const int key_len)
int fc_simple_hash(const void* key, const int key_len)
{
SIMPLE_HASH_FUNC(0)
}
int simple_hash_ex(const void* key, const int key_len, \
int fc_simple_hash_ex(const void* key, const int key_len, \
const int init_value)
{
SIMPLE_HASH_FUNC(init_value)

View File

@ -93,16 +93,16 @@ typedef struct tagHashStat
* parameters:
* index: item index based 0
* data: hash data, including key and value
* args: passed by hash_walk function
* args: passed by fc_hash_walk function
* return 0 for success, != 0 for error
*/
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
#define hash_init(pHash, hash_func, capacity, load_factor) \
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
#define fc_hash_init(pHash, hash_func, capacity, load_factor) \
fc_hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
#define hash_insert(pHash, key, key_len, value) \
hash_insert_ex(pHash, key, key_len, value, 0, true)
#define fc_hash_insert(pHash, key, key_len, value) \
fc_hash_insert_ex(pHash, key, key_len, value, 0, true)
/**
* hash init function
@ -115,7 +115,7 @@ typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
* bMallocValue: if need malloc value buffer
* return 0 for success, != 0 for error
*/
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
const unsigned int capacity, const double load_factor, \
const int64_t max_bytes, const bool bMallocValue);
@ -125,7 +125,7 @@ int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
* lock_count: the lock count
* return 0 for success, != 0 for error
*/
int hash_set_locks(HashArray *pHash, const int lock_count);
int fc_hash_set_locks(HashArray *pHash, const int lock_count);
/**
* convert the value
@ -137,12 +137,12 @@ int hash_set_locks(HashArray *pHash, const int lock_count);
* arg: the user data
* return the number after increasement
*/
int64_t hash_inc_value(const HashData *old_data, const int inc,
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg);
#define hash_inc(pHash, key, key_len, inc, value, value_len) \
hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
hash_inc_value, NULL)
#define fc_hash_inc(pHash, key, key_len, inc, value, value_len) \
fc_hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
fc_hash_inc_value, NULL)
/**
* atomic increase value
@ -158,7 +158,7 @@ int64_t hash_inc_value(const HashData *old_data, const int inc,
* return 0 for success, != 0 for error (errno)
*
*/
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
const int inc, char *value, int *value_len,
ConvertValueFunc convert_func, void *arg);
@ -168,7 +168,7 @@ int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
* pHash: the hash table
* return none
*/
void hash_destroy(HashArray *pHash);
void fc_hash_destroy(HashArray *pHash);
/**
* hash insert key
@ -182,7 +182,7 @@ void hash_destroy(HashArray *pHash);
* return >= 0 for success, 0 for key already exist (update),
* 1 for new key (insert), < 0 for error
*/
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
void *value, const int value_len, const bool needLock);
/**
@ -193,7 +193,7 @@ int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
* key_len: length of th key
* return user data, return NULL when the key not exist
*/
void *hash_find(HashArray *pHash, const void *key, const int key_len);
void *fc_hash_find(HashArray *pHash, const void *key, const int key_len);
/**
* hash find key
@ -203,7 +203,7 @@ void *hash_find(HashArray *pHash, const void *key, const int key_len);
* key_len: length of th key
* return hash data, return NULL when the key not exist
*/
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len);
/**
* hash find key
@ -212,9 +212,9 @@ HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
* key: the key to find
* return user data, return NULL when the key not exist
*/
static inline void *hash_find1(HashArray *pHash, const string_t *key)
static inline void *fc_hash_find1(HashArray *pHash, const string_t *key)
{
return hash_find(pHash, key->str, key->len);
return fc_hash_find(pHash, key->str, key->len);
}
/**
@ -225,7 +225,7 @@ static inline void *hash_find1(HashArray *pHash, const string_t *key)
* value: store the value
* return 0 for success, != 0 fail (errno)
*/
int hash_find2(HashArray *pHash, const string_t *key, string_t *value);
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value);
/**
* hash find key
@ -234,7 +234,7 @@ int hash_find2(HashArray *pHash, const string_t *key, string_t *value);
* key: the key to find
* return hash data, return NULL when the key not exist
*/
HashData *hash_find1_ex(HashArray *pHash, const string_t *key);
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key);
/**
* hash get the value of the key
@ -247,7 +247,7 @@ HashData *hash_find1_ex(HashArray *pHash, const string_t *key);
* output for the length fo the value
* return 0 for success, != 0 fail (errno)
*/
int hash_get(HashArray *pHash, const void *key, const int key_len,
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
void *value, int *value_len);
@ -262,7 +262,7 @@ int hash_get(HashArray *pHash, const void *key, const int key_len,
* value_len: length of the value
* return 0 for success, != 0 fail (errno)
*/
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
const char *value, const int offset, const int value_len);
/**
@ -273,7 +273,7 @@ int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
* key_len: length of th key
* return 0 for success, != 0 fail (errno)
*/
int hash_delete(HashArray *pHash, const void *key, const int key_len);
int fc_hash_delete(HashArray *pHash, const void *key, const int key_len);
/**
* hash walk (iterator)
@ -283,7 +283,7 @@ int hash_delete(HashArray *pHash, const void *key, const int key_len);
* args: extra args which will be passed to walkFunc
* return 0 for success, != 0 fail (errno)
*/
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
/**
* get hash item count
@ -291,7 +291,7 @@ int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
* pHash: the hash table
* return item count
*/
int hash_count(HashArray *pHash);
int fc_hash_count(HashArray *pHash);
/**
* hash best optimize
@ -300,7 +300,7 @@ int hash_count(HashArray *pHash);
* suggest_capacity: suggest init capacity for speed
* return >0 for success, < 0 fail (errno)
*/
int hash_best_op(HashArray *pHash, const int suggest_capacity);
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity);
/**
* hash stat
@ -314,7 +314,7 @@ int hash_best_op(HashArray *pHash, const int suggest_capacity);
* stat_size: stats array size (contain max elments)
* return 0 for success, != 0 fail (errno)
*/
int hash_stat(HashArray *pHash, HashStat *pStat, \
int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
int *stat_by_lens, const int stat_size);
/**
@ -323,7 +323,7 @@ int hash_stat(HashArray *pHash, HashStat *pStat, \
* pHash: the hash table
* return none
*/
void hash_stat_print(HashArray *pHash);
void fc_hash_stat_print(HashArray *pHash);
/**
* lock the bucket of hash table
@ -332,7 +332,7 @@ void hash_stat_print(HashArray *pHash);
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
/**
* unlock the bucket of hash table
@ -341,7 +341,7 @@ int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
int RSHash(const void *key, const int key_len);
@ -383,8 +383,8 @@ int calc_hashnr1(const void* key, const int key_len);
int calc_hashnr1_ex(const void* key, const int key_len, \
const int init_value);
int simple_hash(const void* key, const int key_len);
int simple_hash_ex(const void* key, const int key_len, \
int fc_simple_hash(const void* key, const int key_len);
int fc_simple_hash_ex(const void* key, const int key_len, \
const int init_value);
int CRC32(const void *key, const int key_len);
@ -402,7 +402,7 @@ int64_t CRC32_ex(const void *key, const int key_len, \
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
hash_codes[2] = fc_simple_hash_ex(buff, buff_len, hash_codes[2]); \
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
@ -410,7 +410,7 @@ int64_t CRC32_ex(const void *key, const int key_len, \
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
unsigned int *hash_get_prime_capacity(const int capacity);
unsigned int *fc_hash_get_prime_capacity(const int capacity);
#ifdef __cplusplus
}

View File

@ -27,6 +27,10 @@
((strncasecmp(str, "http://", 7) == 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
extern "C" {
#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 *private_ip;
struct in_addr ip_addr;
struct in6_addr ip6_addr;
private_ip = get_first_local_private_ip();
if (private_ip != NULL)
@ -100,16 +101,28 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
context->fd = -1;
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, "
"can't get local ip address, set to %s",
__LINE__, LOCAL_LOOPBACK_IP);
"can't get local ip address, set to %s or %s",
__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, "
"invalid local ip address: %s",
__LINE__, local_ip);
@ -123,13 +136,14 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
mid = ntohl(ip_addr.s_addr) & ((1 << mid_bits) - 1);
}
if ((context->fd = open(filename, O_RDWR)) < 0)
if ((context->fd = open(filename, O_RDWR | O_CLOEXEC)) < 0)
{
if (errno == ENOENT)
{
mode_t old_mode;
old_mode = umask(0);
if ((context->fd=open(filename, O_RDWR | O_CREAT, mode)) < 0)
if ((context->fd=open(filename, O_RDWR | O_CREAT |
O_CLOEXEC, mode)) < 0)
{
result = errno != 0 ? errno : EACCES;
}

View File

@ -26,7 +26,6 @@
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <fcntl.h>
#include "common_define.h"

View File

@ -115,13 +115,6 @@ static DynamicAnnotations *iniAllocAnnotations(IniContext *pContext,
static AnnotationEntry *iniGetAnnotations(IniContext *pContext);
static SetDirectiveVars *iniGetVars(IniContext *pContext);
#define STR_TRIM(pStr) \
do { \
trim_right(pStr); \
trim_left(pStr); \
} while (0)
#define RETRY_FETCH_GLOBAL(szSectionName, bRetryGlobal) \
((szSectionName != NULL && *szSectionName != '\0') && bRetryGlobal)
@ -205,7 +198,7 @@ static int iniAnnotationFuncLocalIpGet(IniContext *context,
(int)(square_start - param), param);
index = atoi(square_start + 1);
} else {
snprintf(name_part, sizeof(name_part) - 1, "%s", param);
fc_safe_strcpy(name_part, param);
index = -2;
}
@ -329,7 +322,7 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
logWarning("file: "__FILE__", line: %d, "
"NO set directives before, set value to %s",
__LINE__, param);
snprintf(output, FAST_INI_ITEM_VALUE_SIZE, "%s", param);
fc_strlcpy(output, param, FAST_INI_ITEM_VALUE_SIZE);
return output;
}
@ -359,10 +352,10 @@ static char *doReplaceVars(IniContext *pContext, const char *param,
memcpy(name, start, name_len);
}
*(name + name_len) = '\0';
trim(name);
fc_trim(name);
name_len = strlen(name);
if (name_len > 0) {
value = (char *)hash_find(set->vars, name, name_len);
value = (char *)fc_hash_find(set->vars, name, name_len);
} else {
value = NULL;
}
@ -553,10 +546,10 @@ static int iniInitContext(IniContext *pContext, const char annotation_type,
memset(pContext, 0, sizeof(IniContext));
pContext->current_section = &pContext->global;
if ((result=hash_init(&pContext->sections, Time33Hash, 32, 0.75)) != 0)
if ((result=fc_hash_init(&pContext->sections, Time33Hash, 32, 0.75)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"hash_init fail, errno: %d, error info: %s", \
"fc_hash_init fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
@ -586,7 +579,7 @@ static void iniSortItems(IniContext *pContext)
sizeof(IniItem), iniCompareByItemName);
}
hash_walk(&pContext->sections, iniSortHashData, NULL);
fc_hash_walk(&pContext->sections, iniSortHashData, NULL);
}
int iniLoadFromFile(const char *szFilename, IniContext *pContext)
@ -659,7 +652,7 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
if (IS_URL_RESOURCE(szFilename))
{
*pContext->config_path = '\0';
snprintf(full_filename, sizeof(full_filename), "%s", szFilename);
fc_safe_strcpy(full_filename, szFilename);
}
else
{
@ -682,8 +675,7 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
memcpy(pContext->config_path, szFilename, len);
*(pContext->config_path + len) = '\0';
snprintf(full_filename, sizeof(full_filename), \
"%s", szFilename);
fc_safe_strcpy(full_filename, szFilename);
}
else
{
@ -706,9 +698,8 @@ int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
*(pContext->config_path + len) = '\0';
}
snprintf(full_filename, sizeof(full_filename), \
"%s/%s", pContext->config_path, szFilename);
fc_combine_full_filename(pContext->config_path,
szFilename, full_filename);
pLast = strrchr(szFilename, '/');
if (pLast != NULL)
{
@ -866,7 +857,7 @@ static int iniAddAnnotation(char *params)
int count;
int result;
trim(params);
fc_trim(params);
count = fc_split_string(params, " \t", cols, MAX_PARAMS);
if (count < 2)
{
@ -921,7 +912,7 @@ static int iniAddAnnotation(char *params)
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);
if (init_func == NULL)
{
@ -1015,19 +1006,17 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
isAnnotation = 0;
}
STR_TRIM(pLine);
fc_trim(pLine);
if (*pLine == '#' && \
strncasecmp(pLine+1, "include", 7) == 0 && \
(*(pLine+8) == ' ' || *(pLine+8) == '\t'))
{
snprintf(pIncludeFilename, sizeof(pIncludeFilename),
"%s", pLine + 9);
STR_TRIM(pIncludeFilename);
fc_safe_strcpy(pIncludeFilename, pLine + 9);
fc_trim(pIncludeFilename);
if (IS_URL_RESOURCE(pIncludeFilename))
{
snprintf(full_filename, sizeof(full_filename),
"%s", pIncludeFilename);
}
{
fc_safe_strcpy(full_filename, pIncludeFilename);
}
else
{
if (IS_FILE_RESOURCE(pIncludeFilename))
@ -1041,25 +1030,23 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
if (*pTrueFilename == '/')
{
snprintf(full_filename, sizeof(full_filename), \
"%s", pTrueFilename);
fc_safe_strcpy(full_filename, pTrueFilename);
}
else
{
snprintf(full_filename, sizeof(full_filename), \
"%s/%s", pContext->config_path, \
pTrueFilename);
}
{
fc_combine_full_filename(pContext->config_path,
pTrueFilename, full_filename);
}
if (!fileExists(full_filename))
{
logError("file: "__FILE__", line: %d, " \
"include file \"%s\" not exists, " \
"line: \"%s\"", __LINE__, \
pTrueFilename, pLine);
result = ENOENT;
break;
}
{
logError("file: "__FILE__", line: %d, "
"include file \"%s\" not exists, "
"line: \"%s\"", __LINE__,
pTrueFilename, pLine);
result = ENOENT;
break;
}
}
pContext->current_section = &pContext->global;
@ -1092,7 +1079,7 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
}
memcpy(pFuncName, pLine + 11, nNameLen);
pFuncName[nNameLen] = '\0';
STR_TRIM(pFuncName);
fc_trim(pFuncName);
if ((int)strlen(pFuncName) > 0)
{
isAnnotation = 1;
@ -1132,7 +1119,7 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
*(pLine + (nLineLen - 1)) = '\0';
section_name = pLine + 1; //skip [
STR_TRIM(section_name);
fc_trim(section_name);
if (*section_name == '\0') //global section
{
pContext->current_section = &pContext->global;
@ -1142,7 +1129,7 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
}
section_len = strlen(section_name);
pSection = (IniSection *)hash_find(&pContext->sections,\
pSection = (IniSection *)fc_hash_find(&pContext->sections,\
section_name, section_len);
if (pSection == NULL)
{
@ -1154,7 +1141,7 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
}
memset(pSection, 0, sizeof(IniSection));
result = hash_insert(&pContext->sections, \
result = fc_hash_insert(&pContext->sections, \
section_name, section_len, pSection);
if (result < 0)
{
@ -1225,8 +1212,8 @@ static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
memcpy(pItem->name, pLine, nNameLen);
memcpy(pItem->value, pEqualChar + 1, nValueLen);
STR_TRIM(pItem->name);
STR_TRIM(pItem->value);
fc_trim(pItem->name);
fc_trim(pItem->value);
if (isAnnotation)
{
@ -1540,7 +1527,7 @@ static SetDirectiveVars *iniAllocVars(IniContext *pContext, const bool initVars)
{
return NULL;
}
if (hash_init_ex(set->vars, simple_hash, 17, 0.75, 0, true) != 0)
if (fc_hash_init_ex(set->vars, fc_simple_hash, 17, 0.75, 0, true) != 0)
{
free(set->vars);
set->vars = NULL;
@ -2007,7 +1994,7 @@ static bool iniCalcCondition(char *condition, const int condition_len,
set = iniGetVars(pContext);
if (set != NULL && set->vars != NULL)
{
value = (char *)hash_find(set->vars, varStr, varLen);
value = (char *)fc_hash_find(set->vars, varStr, varLen);
if (value == NULL)
{
logWarning("file: "__FILE__", line: %d, "
@ -2164,7 +2151,7 @@ static int iniDoProccessSet(char *pSet, char **ppSetEnd,
}
}
result = hash_insert_ex(set->vars, key, strlen(key),
result = fc_hash_insert_ex(set->vars, key, strlen(key),
new_value, value_len + 1, false);
if (new_value != value) {
free(new_value);
@ -2636,8 +2623,7 @@ static char *iniProccessFor(char *content, const int content_len,
char *pRemain;
int remainLen;
valueLen = sprintf(value, "%d", i);
valueLen = fc_itoa(i, value);
pRemain = pForBlock;
remainLen = forBlockLen;
while (remainLen >= tagLen)
@ -2786,13 +2772,13 @@ void iniFreeContext(IniContext *pContext)
memset(&pContext->global, 0, sizeof(IniSection));
}
hash_walk(&pContext->sections, iniFreeHashData, NULL);
hash_destroy(&pContext->sections);
fc_hash_walk(&pContext->sections, iniFreeHashData, NULL);
fc_hash_destroy(&pContext->sections);
set = iniGetVars(pContext);
if (set != NULL && set->vars != NULL)
{
hash_destroy(set->vars);
fc_hash_destroy(set->vars);
free(set->vars);
set->vars = NULL;
set->offset = 0;
@ -2809,7 +2795,7 @@ do { \
} \
else \
{ \
pSection = (IniSection *)hash_find(&pContext->sections, \
pSection = (IniSection *)fc_hash_find(&pContext->sections, \
szSectionName, strlen(szSectionName)); \
if (pSection == NULL) \
{ \
@ -2824,7 +2810,7 @@ do { \
break; \
} \
\
snprintf(targetItem.name, sizeof(targetItem.name), "%s", szItemName); \
fc_safe_strcpy(targetItem.name, szItemName); \
pItem = (IniItem *)bsearch(&targetItem, pSection->items, \
pSection->count, sizeof(IniItem), iniCompareByItemName); \
} while (0)
@ -2875,6 +2861,21 @@ char *iniGetStrValueEx(const char *szSectionName, const char *szItemName,
return pFound->value;
}
char iniGetCharValueEx(const char *szSectionName, const char *szItemName,
IniContext *pContext, const char cDefaultValue,
const bool bRetryGlobal)
{
char *value;
value = iniGetStrValueEx(szSectionName, szItemName,
pContext, bRetryGlobal);
if (value == NULL) {
return cDefaultValue;
} else {
return value[0];
}
}
#define INI_FILL_SECTION_PROMPT(prompt, size, section_name) \
do { \
if (section_name != NULL && *(section_name) != '\0') { \
@ -2913,6 +2914,64 @@ int64_t iniCheckAndCorrectIntValue(IniFullContext *pIniContext,
return nValue;
}
double iniCheckAndCorrectDoubleValue(IniFullContext *pIniContext,
const char *szItemName, const double dValue,
const double dMinValue, const double dMaxValue)
{
char section_prompt[128];
if (dValue < dMinValue) {
INI_FILL_SECTION_PROMPT(section_prompt, sizeof(section_prompt),
pIniContext->section_name);
logWarning("file: "__FILE__", line: %d, "
"config file: %s, %sitem name: %s, item value: %.2f"
" < min value: %.2f, set to min value: %.2f",
__LINE__, pIniContext->filename, section_prompt,
szItemName, dValue, dMinValue, dMinValue);
return dMinValue;
} else if (dValue > dMaxValue) {
INI_FILL_SECTION_PROMPT(section_prompt, sizeof(section_prompt),
pIniContext->section_name);
logWarning("file: "__FILE__", line: %d, "
"config file: %s, %sitem name: %s, item value: %.2f"
" > max value: %.2f, set to max value: %.2f",
__LINE__, pIniContext->filename, section_prompt,
szItemName, dValue, dMaxValue, dMaxValue);
return dMaxValue;
}
return dValue;
}
double iniCheckAndCorrectPercentValue(IniFullContext *pIniContext,
const char *szItemName, const double dValue,
const double dMinValue, const double dMaxValue)
{
char section_prompt[128];
if (dValue < dMinValue) {
INI_FILL_SECTION_PROMPT(section_prompt, sizeof(section_prompt),
pIniContext->section_name);
logWarning("file: "__FILE__", line: %d, "
"config file: %s, %sitem name: %s, item value: %.2f%%"
" < min value: %.2f%%, set to min value: %.2f%%",
__LINE__, pIniContext->filename, section_prompt,
szItemName, dValue * 100, dMinValue * 100, dMinValue * 100);
return dMinValue;
} else if (dValue > dMaxValue) {
INI_FILL_SECTION_PROMPT(section_prompt, sizeof(section_prompt),
pIniContext->section_name);
logWarning("file: "__FILE__", line: %d, "
"config file: %s, %sitem name: %s, item value: %.2f%%"
" > max value: %.2f%%, set to max value: %.2f%%",
__LINE__, pIniContext->filename, section_prompt,
szItemName, dValue * 100, dMaxValue * 100, dMaxValue * 100);
return dMaxValue;
}
return dValue;
}
int64_t iniGetInt64ValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const bool bRetryGlobal)
@ -2944,6 +3003,36 @@ int64_t iniGetInt64CorrectValueEx(IniFullContext *pIniContext,
value, nMinValue, nMaxValue);
}
double iniGetDoubleCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, const double dbDefaultValue,
const double dbMinValue, const double dbMaxValue,
const bool bRetryGlobal)
{
double value;
value = iniGetDoubleValueEx(pIniContext->section_name, szItemName,
pIniContext->context, dbDefaultValue, bRetryGlobal);
return iniCheckAndCorrectDoubleValue(pIniContext, szItemName,
value, dbMinValue, dbMaxValue);
}
int iniGetPercentCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, double *dbItemValue,
const double dbDefaultValue, const double dbMinValue,
const double dbMaxValue, const bool bRetryGlobal)
{
int result;
if ((result=iniGetPercentValueEx(pIniContext, szItemName, dbItemValue,
dbDefaultValue, bRetryGlobal)) == 0)
{
*dbItemValue = iniCheckAndCorrectPercentValue(pIniContext,
szItemName, *dbItemValue, dbMinValue, dbMaxValue);
}
return result;
}
int64_t iniGetByteValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const int nDefaultUnitBytes,
@ -3182,7 +3271,7 @@ void iniPrintItems(IniContext *pContext)
}
printf("\n");
hash_walk(&pContext->sections, iniPrintHashData, NULL);
fc_hash_walk(&pContext->sections, iniPrintHashData, NULL);
}
struct section_name_walk_arg {
@ -3246,7 +3335,7 @@ int iniGetSectionNamesEx(IniContext *pContext, IniSectionNameFilterFunc
walk_arg.args = args;
walk_arg.size = max_size;
walk_arg.count = 0;
result = hash_walk(&pContext->sections, iniSectionNameWalkCallback,
result = fc_hash_walk(&pContext->sections, iniSectionNameWalkCallback,
&walk_arg);
*nCount = walk_arg.count;
return result;
@ -3317,7 +3406,7 @@ int iniGetSectionCountEx(IniContext *pContext, IniSectionNameFilterFunc
walk_arg.filter_func = filter_func;
walk_arg.args = args;
walk_arg.count = 0;
hash_walk(&pContext->sections, iniSectionCountWalkCallback, &walk_arg);
fc_hash_walk(&pContext->sections, iniSectionCountWalkCallback, &walk_arg);
return walk_arg.count;
}
@ -3340,7 +3429,7 @@ IniItem *iniGetSectionItems(const char *szSectionName, IniContext *pContext,
}
else
{
pSection = (IniSection *)hash_find(&pContext->sections,
pSection = (IniSection *)fc_hash_find(&pContext->sections,
szSectionName, strlen(szSectionName));
if (pSection == NULL)
{

View File

@ -117,28 +117,32 @@ extern "C" {
#define iniGetStrValue(szSectionName, szItemName, pContext) \
iniGetStrValueEx(szSectionName, szItemName, pContext, false)
#define iniGetCharValue(szSectionName, szItemName, pContext, cDefaultValue) \
iniGetCharValueEx(szSectionName, szItemName, \
pContext, cDefaultValue, false)
#define iniGetIntValue(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetIntValueEx(szSectionName, szItemName, pContext, \
nDefaultValue, false)
iniGetIntValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, false)
#define iniGetInt64Value(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetInt64ValueEx(szSectionName, szItemName, pContext, \
nDefaultValue, false)
iniGetInt64ValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, false)
#define iniGetDoubleValue(szSectionName, szItemName, pContext, dbDefaultValue) \
iniGetDoubleValueEx(szSectionName, szItemName, pContext, \
dbDefaultValue, false)
iniGetDoubleValueEx(szSectionName, szItemName, \
pContext, dbDefaultValue, false)
#define iniGetBoolValue(szSectionName, szItemName, pContext, bDefaultValue) \
iniGetBoolValueEx(szSectionName, szItemName, pContext, \
bDefaultValue, false)
iniGetBoolValueEx(szSectionName, szItemName, \
pContext, bDefaultValue, false)
#define iniGetPercentValue(ini_ctx, item_name, item_value, default_value) \
iniGetPercentValueEx(ini_ctx, item_name, item_value, default_value, false)
#define iniGetByteValue(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetByteValueEx(szSectionName, szItemName, pContext, \
nDefaultValue, 1, false)
iniGetByteValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, 1, false)
#define iniGetIntCorrectValue(ini_ctx, item_name, \
default_value, min_value, max_value) \
@ -155,6 +159,16 @@ extern "C" {
iniGetByteCorrectValueEx(ini_ctx, item_name, \
default_value, 1, min_value, max_value, false)
#define iniGetDoubleCorrectValue(ini_ctx, item_name, \
default_value, min_value, max_value) \
iniGetDoubleCorrectValueEx(ini_ctx, item_name, \
default_value, 1, min_value, max_value, false)
#define iniGetPercentCorrectValue(ini_ctx, item_name, \
item_value, default_value, min_value, max_value) \
iniGetPercentCorrectValueEx(ini_ctx, item_name, item_value, \
default_value, min_value, max_value, false)
int iniSetAnnotationCallBack(AnnotationEntry *annotations, int count);
void iniDestroyAnnotationCallBack();
@ -233,7 +247,7 @@ void iniFreeContext(IniContext *pContext);
/** get item string value
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -243,9 +257,23 @@ void iniFreeContext(IniContext *pContext);
char *iniGetStrValueEx(const char *szSectionName, const char *szItemName,
IniContext *pContext, const bool bRetryGlobal);
/** get the first charactor
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* cDefaultValue: the default value
* bRetryGlobal: if fetch from global section when the item not exist
* return: item value, return default value when the item not exist
*/
char iniGetCharValueEx(const char *szSectionName, const char *szItemName,
IniContext *pContext, const char cDefaultValue,
const bool bRetryGlobal);
/** get item string value
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -258,7 +286,7 @@ int iniGetValues(const char *szSectionName, const char *szItemName, \
/** get item int value (32 bits)
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -270,7 +298,7 @@ int iniGetIntValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int nDefaultValue, const bool bRetryGlobal);
/** check and correct item value
/** check and correct int value
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
@ -283,6 +311,32 @@ int64_t iniCheckAndCorrectIntValue(IniFullContext *pIniContext,
const char *szItemName, const int64_t nValue,
const int64_t nMinValue, const int64_t nMaxValue);
/** check and correct double value
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* dValue: the item value
* dMinValue: the min value to check (including)
* dMaxValue: the max value to check (including)
* return: corrected value
*/
double iniCheckAndCorrectDoubleValue(IniFullContext *pIniContext,
const char *szItemName, const double dValue,
const double dMinValue, const double dMaxValue);
/** check and correct double value (show as percentage)
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* dValue: the item value
* dMinValue: the min value to check (including)
* dMaxValue: the max value to check (including)
* return: corrected value
*/
double iniCheckAndCorrectPercentValue(IniFullContext *pIniContext,
const char *szItemName, const double dValue,
const double dMinValue, const double dMaxValue);
/** get item correct value (32 bits integer)
* parameters:
* pIniContext: the full ini context
@ -299,7 +353,7 @@ int iniGetIntCorrectValueEx(IniFullContext *pIniContext,
/** get item string value array
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -372,7 +426,7 @@ int64_t iniGetByteCorrectValueEx(IniFullContext *pIniContext,
/** get item boolean value
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -386,7 +440,7 @@ bool iniGetBoolValueEx(const char *szSectionName,
/** get item double value
* parameters:
* szSectionName: the section name, NULL or empty string for
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
@ -398,6 +452,20 @@ double iniGetDoubleValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const double dbDefaultValue, const bool bRetryGlobal);
/** get item correct double value
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* dbDefaultValue: the default value
* dbMinValue: the min value to check (including)
* dbMaxValue: the max value to check (including)
* bRetryGlobal: if fetch from global section when the item not exist
* return: double value, return dbDefaultValue when the item not exist
*/
double iniGetDoubleCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, const double dbDefaultValue,
const double dbMinValue, const double dbMaxValue,
const bool bRetryGlobal);
/** get item percent double value
* parameters:
@ -412,6 +480,22 @@ int iniGetPercentValueEx(IniFullContext *ini_ctx,
const char *item_name, double *item_value,
const double default_value, const bool retry_global);
/** get item correct double value (show as percentage)
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* dbItemValue: store the item value
* dbDefaultValue: the default value
* dbMinValue: the min value to check (including)
* dbMaxValue: the max value to check (including)
* bRetryGlobal: if fetch from global section when the item not exist
* return: error no, 0 for success, != 0 for fail
*/
int iniGetPercentCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, double *dbItemValue,
const double dbDefaultValue, const double dbMinValue,
const double dbMaxValue, const bool bRetryGlobal);
/** print all items
* parameters:
* pContext: the ini context

View File

@ -45,71 +45,119 @@ int kqueue_ev_convert(int16_t event, uint16_t flags)
}
#endif
int ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout_ms, const int extra_events)
int ioevent_init(IOEventPoller *ioevent, const char *service_name,
const bool use_io_uring, const int size, const int timeout_ms,
const int extra_events)
{
int bytes;
int bytes;
ioevent->size = size;
ioevent->extra_events = extra_events;
ioevent->iterator.index = 0;
ioevent->iterator.count = 0;
ioevent->iterator.index = 0;
ioevent->iterator.count = 0;
ioevent->service_name = service_name;
ioevent->size = size;
ioevent->extra_events = extra_events;
#if IOEVENT_USE_EPOLL
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);
#ifdef OS_LINUX
#if IOEVENT_USE_URING
ioevent->use_io_uring = use_io_uring;
if (use_io_uring) {
int result;
if ((result=io_uring_queue_init(size, &ioevent->ring, 0)) < 0) {
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
ioevent->poll_fd = kqueue();
if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM;
}
bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)fc_malloc(bytes);
ioevent->poll_fd = kqueue();
if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM;
}
bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)fc_malloc(bytes);
#elif IOEVENT_USE_PORT
ioevent->poll_fd = port_create();
if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM;
}
bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)fc_malloc(bytes);
ioevent->poll_fd = port_create();
if (ioevent->poll_fd < 0) {
return errno != 0 ? errno : ENOMEM;
}
bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)fc_malloc(bytes);
#endif
if (ioevent->events == NULL) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
return ENOMEM;
}
ioevent_set_timeout(ioevent, timeout_ms);
#if IOEVENT_USE_URING
if (!ioevent->use_io_uring) {
#endif
if (ioevent->events == NULL) {
close(ioevent->poll_fd);
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)
{
if (ioevent->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
#if IOEVENT_USE_URING
if (ioevent->use_io_uring) {
io_uring_queue_exit(&ioevent->ring);
} else {
#endif
if (ioevent->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
if (ioevent->poll_fd >= 0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
if (ioevent->poll_fd >= 0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
#if IOEVENT_USE_URING
}
#endif
}
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
void *data)
int ioevent_attach(IOEventPoller *ioevent, const int fd,
const int e, void *data)
{
#if IOEVENT_USE_EPOLL
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);
#ifdef OS_LINUX
#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_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
struct kevent ev[2];
int n = 0;
@ -128,15 +176,32 @@ int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
#endif
}
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
void *data)
int ioevent_modify(IOEventPoller *ioevent, const int fd,
const int e, void *data)
{
#if IOEVENT_USE_EPOLL
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);
#ifdef OS_LINUX
#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_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
struct kevent ev[2];
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)
{
#if IOEVENT_USE_EPOLL
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
#ifdef OS_LINUX
#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
struct kevent ev[1];
int r, w;
@ -191,15 +273,33 @@ int ioevent_detach(IOEventPoller *ioevent, const int fd)
int ioevent_poll(IOEventPoller *ioevent)
{
#if IOEVENT_USE_EPOLL
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
#ifdef OS_LINUX
#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
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
int result;
int retval;
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)
{
result = (int)nget;
@ -225,4 +325,3 @@ int ioevent_poll(IOEventPoller *ioevent)
#error port me
#endif
}

View File

@ -20,17 +20,28 @@
#include <poll.h>
#include <sys/time.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>
#define IOEVENT_EDGE_TRIGGER EPOLLET
#endif
#if IOEVENT_USE_EPOLL
#define IOEVENT_READ EPOLLIN
#define IOEVENT_WRITE EPOLLOUT
#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
#include <sys/event.h>
#include <sys/poll.h>
@ -65,18 +76,33 @@ int kqueue_ev_convert(int16_t event, uint16_t flags);
#endif
typedef struct ioevent_puller {
const char *service_name;
int size; //max events (fd)
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 {
int index;
int count;
} iterator; //for deal event loop
#if IOEVENT_USE_EPOLL
#ifdef OS_LINUX
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
struct kevent *events;
struct timespec timeout;
@ -84,9 +110,10 @@ typedef struct ioevent_puller {
port_event_t *events;
timespec_t timeout;
#endif
} IOEventPoller;
#if IOEVENT_USE_EPOLL
#if OS_LINUX
#define IOEVENT_GET_EVENTS(ioevent, index) \
(ioevent)->events[index].events
#elif IOEVENT_USE_KQUEUE
@ -99,7 +126,7 @@ typedef struct ioevent_puller {
#error port me
#endif
#if IOEVENT_USE_EPOLL
#ifdef OS_LINUX
#define IOEVENT_GET_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr
#elif IOEVENT_USE_KQUEUE
@ -112,7 +139,7 @@ typedef struct ioevent_puller {
#error port me
#endif
#if IOEVENT_USE_EPOLL
#ifdef OS_LINUX
#define IOEVENT_CLEAR_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr = NULL
#elif IOEVENT_USE_KQUEUE
@ -129,24 +156,39 @@ typedef struct ioevent_puller {
extern "C" {
#endif
int ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout_ms, const int extra_events);
int ioevent_init(IOEventPoller *ioevent, const char *service_name,
const bool use_io_uring, const int size, const int timeout_ms,
const int extra_events);
void ioevent_destroy(IOEventPoller *ioevent);
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
void *data);
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
void *data);
int ioevent_attach(IOEventPoller *ioevent, const int fd,
const int e, void *data);
int ioevent_modify(IOEventPoller *ioevent, const int fd,
const int e, void *data);
int ioevent_detach(IOEventPoller *ioevent, const int fd);
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
ioevent->timeout = timeout_ms;
ioevent->timeout_ms = timeout_ms;
#else
ioevent->timeout.tv_sec = timeout_ms / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000);
#if IOEVENT_USE_URING
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
}
@ -156,6 +198,114 @@ static inline int ioevent_poll_ex(IOEventPoller *ioevent, const int timeout_ms)
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
}
#endif

View File

@ -17,6 +17,76 @@
#include "logger.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)
{
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 index;
int result;
if (ioevent->iterator.index >= ioevent->iterator.count)
{
return ENOENT;
ioevent->iterator.count = ioevent_poll(ioevent);
if (ioevent->iterator.count > 0) {
deal_ioevents(ioevent);
}
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
ioevent->iterator.index);
if (pEntry != NULL && (void *)pEntry == data) {
return 0; //do NOT clear current entry
}
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;
else if (ioevent->iterator.count < 0) {
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;
}
}
return ENOENT;
return 0;
}
static void deal_timeouts(FastTimerEntry *head)
@ -82,16 +142,14 @@ static void deal_timeouts(FastTimerEntry *head)
current = entry;
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;
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
clean_up_callback, volatile bool *continue_flag)
{
@ -100,90 +158,133 @@ int ioevent_loop(struct nio_thread_data *pThreadData,
FastTimerEntry head;
struct fast_task_info *task;
time_t last_check_time;
int save_extra_events;
int count;
#ifdef OS_LINUX
uint32_t sched_counter;
#endif
bool sched_pull;
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.thread_data = pThreadData;
if (ioevent_attach(&pThreadData->ev_puller,
pThreadData->pipe_fds[0], IOEVENT_READ,
&ev_notify) != 0)
ev_notify.thread_data = thread_data;
save_extra_events = thread_data->ev_puller.extra_events;
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;
logCrit("file: "__FILE__", line: %d, " \
"ioevent_attach fail, " \
"errno: %d, error info: %s", \
logCrit("file: "__FILE__", line: %d, "
"ioevent_attach fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(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;
while (*continue_flag)
{
pThreadData->ev_puller.iterator.count = ioevent_poll(
&pThreadData->ev_puller);
if (pThreadData->ev_puller.iterator.count > 0)
{
deal_ioevents(&pThreadData->ev_puller);
}
else if (pThreadData->ev_puller.iterator.count < 0)
{
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;
}
}
while (*continue_flag) {
#ifdef OS_LINUX
if (thread_data->ev_puller.zero_timeout) {
sched_pull = (sched_counter++ & 8) != 0;
} else {
sched_pull = true;
}
#else
sched_pull = true;
#endif
if (pThreadData->deleted_list != NULL)
{
count = 0;
while (pThreadData->deleted_list != NULL)
{
task = pThreadData->deleted_list;
pThreadData->deleted_list = task->next;
#if IOEVENT_USE_URING
if (thread_data->ev_puller.use_io_uring) {
if (thread_data->ev_puller.submit_count > 0) {
if ((result=ioevent_uring_submit(&thread_data->
ev_puller)) != 0)
{
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);
count++;
//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;
count = fast_timer_timeouts_get(
&pThreadData->timer, g_current_time, &head);
&thread_data->timer, g_current_time, &head);
if (count > 0)
{
deal_timeouts(&head);
}
}
if (pThreadData->notify.enabled)
{
if (thread_data->notify.enabled) {
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, "
"n ==== %"PRId64", now: %"PRId64,
__LINE__, n, __sync_fetch_and_add(
&pThreadData->notify.counter, 0));
&thread_data->notify.counter, 0));
*/
}
}
if (pThreadData->thread_loop_callback != NULL)
{
pThreadData->thread_loop_callback(pThreadData);
if (thread_data->thread_loop_callback != NULL) {
thread_data->thread_loop_callback(thread_data);
}
}
@ -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 sock, short event, IOEventCallback callback, const int timeout)
int sock, short event, IOEventCallback callback,
const int timeout)
{
int result;
task->thread_data = pThread;
task->event.fd = sock;
task->event.callback = callback;
if (ioevent_attach(&pThread->ev_puller,
sock, event, task) < 0)
{
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, " \
"ioevent_attach fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
#if IOEVENT_USE_URING
if (pThread->ev_puller.use_io_uring) {
if (FC_URING_OP_TYPE(task) == IORING_OP_NOP) {
if ((result=uring_prep_first_recv(task)) != 0) {
logError("file: "__FILE__", line: %d, "
"uring_prep_recv fail, fd: %d, "
"errno: %d, error info: %s",
__LINE__, sock, result, STRERROR(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;
fast_timer_add(&pThread->timer, &task->event.timer);
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
#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
extern "C" {
#endif
int ioevent_loop(struct nio_thread_data *pThreadData,
int ioevent_loop(struct nio_thread_data *thread_data,
IOEventCallback recv_notify_callback, TaskCleanUpCallback
clean_up_callback, volatile bool *continue_flag);
//remove entry from ready list
int ioevent_remove(IOEventPoller *ioevent, void *data);
int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback,
const int timeout);
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback, const int timeout);
int ioevent_reset(struct fast_task_info *task, int new_fd, short event);
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;
}
#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
}
#endif
#endif

View File

@ -29,7 +29,7 @@
(ch >= '0' && ch <= '9') || (ch == '_' || ch == '-' || \
ch == '.'))
int detect_json_type(const string_t *input)
int fc_detect_json_type(const string_t *input)
{
if (input->len < 2) {
return FC_JSON_TYPE_STRING;
@ -45,18 +45,9 @@ int detect_json_type(const string_t *input)
return FC_JSON_TYPE_STRING;
}
typedef struct {
const char *str; //input string
const char *p; //current
const char *end;
string_t element;
char *error_info;
int error_size;
} ParseContext;
static void set_parse_error(const char *str, const char *current,
const int expect_len, const char *front,
char *error_info, const int error_size)
string_t *error_info, const int error_size)
{
const char *show_str;
int show_len;
@ -66,26 +57,18 @@ static void set_parse_error(const char *str, const char *current,
show_len = expect_len;
}
show_str = current - show_len;
snprintf(error_info, error_size, "%s, input: %.*s",
front, show_len, show_str);
error_info->len = snprintf(error_info->str, error_size,
"%s, input: %.*s", front, show_len, show_str);
}
static int json_escape_string(const string_t *input, string_t *output,
char *error_info, const int error_size)
static int json_escape_string(fc_json_context_t *context,
const string_t *input, char *output)
{
const char *src;
const char *end;
char *dest;
int size;
size = 2 * input->len + 1;
output->str = (char *)fc_malloc(size);
if (output->str == NULL) {
snprintf(error_info, error_size, "malloc %d bytes fail", size);
return ENOMEM;
}
dest = output->str;
dest = output;
end = input->str + input->len;
for (src=input->str; src<end; src++) {
switch (*src) {
@ -109,13 +92,21 @@ static int json_escape_string(const string_t *input, string_t *output,
*dest++ = '\\';
*dest++ = 'b';
break;
case '\f':
*dest++ = '\\';
*dest++ = 'f';
break;
case '\"':
*dest++ = '\\';
*dest++ = '\"';
break;
case '\'':
case '\0':
*dest++ = '\\';
*dest++ = '\'';
*dest++ = 'u';
*dest++ = '0';
*dest++ = '0';
*dest++ = '0';
*dest++ = '0';
break;
default:
*dest++ = *src;
@ -123,18 +114,19 @@ static int json_escape_string(const string_t *input, string_t *output,
}
}
*dest = '\0';
output->len = dest - output->str;
return 0;
return dest - output;
}
static int next_json_element(ParseContext *context)
static int next_json_element(fc_json_context_t *context)
{
char *dest;
const char *start;
char buff[128];
char quote_ch;
int unicode;
int i;
dest = context->element.str;
dest = context->decode.element.str;
quote_ch = *context->p;
if (quote_ch == '\"' || quote_ch == '\'') {
context->p++;
@ -143,9 +135,42 @@ static int next_json_element(ParseContext *context)
if (++context->p == context->end) {
set_parse_error(context->str, context->p,
EXPECT_STR_LEN, "expect a character after \\",
context->error_info, context->error_size);
&context->error_info, context->error_size);
return EINVAL;
}
if (*context->p == 'u') { //unicode
start = ++context->p; //skip charator 'u'
i = 0;
while (i < 4 && context->p < context->end &&
IS_HEX_CHAR(*context->p))
{
buff[i++] = *context->p;
++context->p;
}
if (i != 4) {
set_parse_error(context->str, start,
EXPECT_STR_LEN, "expect 4 hex characters "
"after \\u", &context->error_info,
context->error_size);
return EINVAL;
}
buff[i] = '\0';
unicode = strtol(buff, NULL, 16);
if (unicode < 0x80) {
*dest++ = unicode;
} else if (unicode < 0x800) {
*dest++ = 0xC0 | ((unicode >> 6) & 0x1F);
*dest++ = 0x80 | (unicode & 0x3F);
} else {
*dest++ = 0xE0 | ((unicode >> 12) & 0x0F);
*dest++ = 0x80 | ((unicode >> 6) & 0x3F);
*dest++ = 0x80 | (unicode & 0x3F);
}
continue;
}
switch (*context->p) {
case '\\':
*dest++ = '\\';
@ -162,20 +187,21 @@ static int next_json_element(ParseContext *context)
case 'n':
*dest++ = '\n';
break;
case 'b':
case 'f':
*dest++ = '\f';
break;
case 'b':
*dest++ = '\b';
break;
case '"':
*dest++ = '\"';
break;
case '\'':
*dest++ = '\'';
break;
default:
sprintf(buff, "invalid escaped character: %c(0x%x)",
*context->p, (unsigned char)*context->p);
set_parse_error(context->str, context->p + 1, EXPECT_STR_LEN,
buff, context->error_info, context->error_size);
set_parse_error(context->str, context->p + 1,
EXPECT_STR_LEN, buff, &context->error_info,
context->error_size);
return EINVAL;
}
context->p++;
@ -187,7 +213,7 @@ static int next_json_element(ParseContext *context)
if (context->p == context->end) {
sprintf(buff, "expect closed character: %c", quote_ch);
set_parse_error(context->str, context->p, EXPECT_STR_LEN,
buff, context->error_info, context->error_size);
buff, &context->error_info, context->error_size);
return EINVAL;
}
context->p++; //skip quote char
@ -198,12 +224,12 @@ static int next_json_element(ParseContext *context)
}
*dest = '\0';
context->element.len = dest - context->element.str;
context->decode.element.len = dest - context->decode.element.str;
return 0;
}
static int check_alloc_array(common_array_t *array,
char *error_info, const int error_size)
static int check_alloc_array(fc_json_context_t *context,
fc_common_array_t *array)
{
int bytes;
if (array->count < array->alloc) {
@ -219,344 +245,320 @@ static int check_alloc_array(common_array_t *array,
bytes = array->element_size * array->alloc;
array->elements = fc_realloc(array->elements, bytes);
if (array->elements == NULL) {
snprintf(error_info, error_size, "realloc %d bytes fail", bytes);
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "realloc %d bytes fail", bytes);
return ENOMEM;
}
return 0;
}
static inline int check_alloc_json_array(json_array_t *array,
char *error_info, const int error_size)
static int prepare_json_parse(fc_json_context_t *context,
const string_t *input, const char lquote,
const char rquote)
{
return check_alloc_array((common_array_t *)array, error_info, error_size);
}
static inline int check_alloc_json_map(json_map_t *array,
char *error_info, const int error_size)
{
return check_alloc_array((common_array_t *)array, error_info, error_size);
}
static int prepare_json_parse(const string_t *input, common_array_t *array,
char *error_info, const int error_size,
const char lquote, const char rquote, ParseContext *context)
{
int buff_len;
array->elements = NULL;
array->count = array->alloc = 0;
array->buff = NULL;
int expect_size;
int result;
if (input->len < 2) {
snprintf(error_info, error_size, "json string is too short");
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "json string is too short");
return EINVAL;
}
if (input->str[0] != lquote) {
snprintf(error_info, error_size,
"json array must start with \"%c\"", lquote);
context->error_info.len = snprintf(context->error_info.str, context->
error_size, "json array must start with \"%c\"", lquote);
return EINVAL;
}
if (input->str[input->len - 1] != rquote) {
snprintf(error_info, error_size,
"json array must end with \"%c\"", rquote);
context->error_info.len = snprintf(context->error_info.str, context->
error_size, "json array must end with \"%c\"", rquote);
return EINVAL;
}
buff_len = input->len - 2;
array->buff = (char *)fc_malloc(buff_len + 1);
if (array->buff == NULL) {
snprintf(error_info, error_size,
"malloc %d bytes fail", buff_len + 1);
return ENOMEM;
expect_size = input->len;
if (context->output.alloc_size < expect_size) {
if ((result=fc_realloc_buffer(&context->output, context->
init_buff_size, expect_size)) != 0)
{
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "realloc buffer fail");
return result;
}
}
context->error_info = error_info;
context->error_size = error_size;
context->element.str = array->buff;
context->element.len = 0;
context->decode.element.str = context->output.buff;
context->decode.element.len = 0;
context->str = input->str;
context->p = input->str + 1;
context->end = input->str + input->len - 1;
return 0;
}
int decode_json_array(const string_t *input, json_array_t *array,
char *error_info, const int error_size)
static inline void json_quote_string(fc_json_context_t
*context, const string_t *input, char **buff)
{
ParseContext context;
int result;
array->element_size = sizeof(string_t);
if ((result=prepare_json_parse(input, (common_array_t *)array,
error_info, error_size, '[', ']', &context)) != 0)
{
return result;
}
result = 0;
while (context.p < context.end) {
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if (context.p == context.end) {
break;
}
if (*context.p == ',') {
set_parse_error(input->str, context.p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
error_info, error_size);
result = EINVAL;
break;
}
if ((result=next_json_element(&context)) != 0) {
break;
}
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if (context.p < context.end) {
if (*context.p == ',') {
context.p++; //skip comma
} else {
set_parse_error(input->str, context.p,
EXPECT_STR_LEN, "expect comma \",\"",
error_info, error_size);
result = EINVAL;
break;
}
}
if ((result=check_alloc_json_array(array, error_info, error_size)) != 0) {
array->count = 0;
break;
}
array->elements[array->count++] = context.element;
context.element.str += context.element.len + 1;
}
if (result != 0) {
free_json_array(array);
}
return result;
}
void free_common_array(common_array_t *array)
{
if (array->elements != NULL) {
free(array->elements);
array->elements = NULL;
array->count = 0;
}
if (array->buff != NULL) {
free(array->buff);
array->buff = NULL;
}
}
static int json_quote_string(const string_t *input, char **buff,
char *error_info, const int error_size)
{
int result;
string_t escaped;
char *p;
if ((result=json_escape_string(input, &escaped,
error_info, error_size)) != 0)
{
return result;
}
p = *buff;
*p++ = '"';
memcpy(p, escaped.str, escaped.len);
p += escaped.len;
p += json_escape_string(context, input, p);
*p++ = '"';
*buff = p;
free(escaped.str);
return 0;
}
int encode_json_array(json_array_t *array, string_t *output,
char *error_info, const int error_size)
int fc_encode_json_array_ex(fc_json_context_t *context,
const string_t *elements, const int count,
BufferInfo *buffer)
{
string_t *el;
string_t *end;
const string_t *el;
const string_t *end;
char *p;
int result;
int size;
int expect_size;
end = array->elements + array->count;
size = 3;
for (el=array->elements; el<end; el++) {
size += 2 * el->len + 3;
expect_size = 3;
end = elements + count;
for (el=elements; el<end; el++) {
expect_size += 6 * el->len + 3;
}
output->str = (char *)fc_malloc(size);
if (output->str == NULL) {
snprintf(error_info, error_size, "malloc %d bytes fail", size);
return ENOMEM;
if (buffer->alloc_size < expect_size) {
if ((context->error_no=fc_realloc_buffer(buffer, context->
init_buff_size, expect_size)) != 0)
{
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "realloc buffer fail");
return context->error_no;
}
}
p = output->str;
p = buffer->buff;
*p++ = '[';
for (el=array->elements; el<end; el++) {
if (el > array->elements) {
for (el=elements; el<end; el++) {
if (el > elements) {
*p++ = ',';
}
if ((result=json_quote_string(el, &p, error_info, error_size)) != 0) {
free_json_string(output);
return result;
}
json_quote_string(context, el, &p);
}
*p++ = ']';
*p = '\0';
output->len = p - output->str;
buffer->length = p - buffer->buff;
return 0;
}
int decode_json_map(const string_t *input, json_map_t *map,
char *error_info, const int error_size)
int fc_encode_json_map_ex(fc_json_context_t *context,
const key_value_pair_t *elements, const int count,
BufferInfo *buffer)
{
ParseContext context;
key_value_pair_t kv_pair;
int result;
map->element_size = sizeof(key_value_pair_t);
if ((result=prepare_json_parse(input, (common_array_t *)map,
error_info, error_size, '{', '}', &context)) != 0)
{
return result;
}
result = 0;
while (context.p < context.end) {
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if (context.p == context.end) {
break;
}
if (*context.p == ',') {
set_parse_error(input->str, context.p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
error_info, error_size);
result = EINVAL;
break;
}
if ((result=next_json_element(&context)) != 0) {
break;
}
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if (!(context.p < context.end && *context.p == ':')) {
set_parse_error(input->str, context.p,
EXPECT_STR_LEN, "expect colon \":\"",
error_info, error_size);
result = EINVAL;
break;
}
context.p++; //skip colon
kv_pair.key = context.element;
context.element.str += context.element.len + 1;
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if ((result=next_json_element(&context)) != 0) {
break;
}
while (context.p < context.end && JSON_SPACE(*context.p)) {
context.p++;
}
if (context.p < context.end) {
if (*context.p == ',') {
context.p++; //skip comma
} else {
set_parse_error(input->str, context.p,
EXPECT_STR_LEN, "expect comma \",\"",
error_info, error_size);
result = EINVAL;
break;
}
}
kv_pair.value = context.element;
context.element.str += context.element.len + 1;
if ((result=check_alloc_json_map(map, error_info, error_size)) != 0) {
map->count = 0;
break;
}
map->elements[map->count++] = kv_pair;
}
if (result != 0) {
free_json_map(map);
}
return result;
}
int encode_json_map(json_map_t *map, string_t *output,
char *error_info, const int error_size)
{
key_value_pair_t *pair;
key_value_pair_t *end;
const key_value_pair_t *pair;
const key_value_pair_t *end;
char *p;
int result;
int size;
int expect_size;
end = map->elements + map->count;
size = 3;
for (pair=map->elements; pair<end; pair++) {
size += 2 * (pair->key.len + pair->value.len + 2) + 1;
expect_size = 3;
end = elements + count;
for (pair=elements; pair<end; pair++) {
expect_size += 6 * (pair->key.len + pair->value.len) + 5;
}
output->str = (char *)fc_malloc(size);
if (output->str == NULL) {
snprintf(error_info, error_size, "malloc %d bytes fail", size);
return ENOMEM;
if (buffer->alloc_size < expect_size) {
if ((context->error_no=fc_realloc_buffer(buffer, context->
init_buff_size, expect_size)) != 0)
{
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "realloc buffer fail");
return context->error_no;
}
}
p = output->str;
p = buffer->buff;
*p++ = '{';
for (pair=map->elements; pair<end; pair++) {
if (pair > map->elements) {
for (pair=elements; pair<end; pair++) {
if (pair > elements) {
*p++ = ',';
}
if ((result=json_quote_string(&pair->key, &p,
error_info, error_size)) != 0)
{
free_json_string(output);
return result;
}
json_quote_string(context, &pair->key, &p);
*p++ = ':';
if ((result=json_quote_string(&pair->value, &p,
error_info, error_size)) != 0)
{
free_json_string(output);
return result;
}
json_quote_string(context, &pair->value, &p);
}
*p++ = '}';
*p = '\0';
output->len = p - output->str;
buffer->length = p - buffer->buff;
return 0;
}
#define JSON_DECODE_COPY_STRING(ctx, input, dest, src) \
do { \
if ((context->error_no=fast_mpool_alloc_string_ex2( \
&ctx->decode.mpool, dest, src)) != 0) \
{ \
set_parse_error(input->str, ctx->p, EXPECT_STR_LEN, \
"out of memory", &ctx->error_info, ctx->error_size); \
return NULL; \
} \
} while (0)
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
*context, const string_t *input)
{
if ((context->error_no=prepare_json_parse(context,
input, '[', ']')) != 0)
{
return NULL;
}
context->jarray.count = 0;
while (context->p < context->end) {
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p == context->end) {
break;
}
if (*context->p == ',') {
set_parse_error(input->str, context->p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p < context->end) {
if (*context->p == ',') {
context->p++; //skip comma
} else {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
}
if ((context->error_no=check_alloc_array(context,
(fc_common_array_t *)
&context->jarray)) != 0)
{
return NULL;
}
if (context->decode.use_mpool) {
JSON_DECODE_COPY_STRING(context, input, context->jarray.elements +
context->jarray.count++, &context->decode.element);
} else {
context->jarray.elements[context->jarray.count++] =
context->decode.element;
}
context->decode.element.str += context->decode.element.len + 1;
}
return &context->jarray;
}
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
*context, const string_t *input)
{
key_value_pair_t kv_pair;
if ((context->error_no=prepare_json_parse(context,
input, '{', '}')) != 0)
{
return NULL;
}
context->jmap.count = 0;
while (context->p < context->end) {
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p == context->end) {
break;
}
if (*context->p == ',') {
set_parse_error(input->str, context->p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (!(context->p < context->end && *context->p == ':')) {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect colon \":\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
context->p++; //skip colon
kv_pair.key = context->decode.element;
context->decode.element.str += context->decode.element.len + 1;
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p < context->end) {
if (*context->p == ',') {
context->p++; //skip comma
} else {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
}
kv_pair.value = context->decode.element;
context->decode.element.str += context->decode.element.len + 1;
if ((context->error_no=check_alloc_array(context,
(fc_common_array_t *)
&context->jmap)) != 0)
{
return NULL;
}
if (context->decode.use_mpool) {
key_value_pair_t *dest;
dest = context->jmap.elements + context->jmap.count++;
JSON_DECODE_COPY_STRING(context, input,
&dest->key, &kv_pair.key);
JSON_DECODE_COPY_STRING(context, input,
&dest->value, &kv_pair.value);
} else {
context->jmap.elements[context->jmap.count++] = kv_pair;
}
}
return &context->jmap;
}

View File

@ -15,14 +15,16 @@
//json_parser.h
#ifndef _JSON_PARSER_H
#define _JSON_PARSER_H
#ifndef _FC_JSON_PARSER_H
#define _FC_JSON_PARSER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "common_define.h"
#include "shared_func.h"
#include "fast_mpool.h"
#define FC_JSON_TYPE_STRING 1
#define FC_JSON_TYPE_ARRAY 2
@ -36,55 +38,200 @@
/* for internal use */ \
int element_size; \
int alloc; \
char *buff; \
} ARRAY_TYPE
DEFINE_ARRAY_STRUCT(void, common_array_t);
DEFINE_ARRAY_STRUCT(string_t, json_array_t);
DEFINE_ARRAY_STRUCT(key_value_pair_t, json_map_t);
DEFINE_ARRAY_STRUCT(void, fc_common_array_t);
DEFINE_ARRAY_STRUCT(string_t, fc_json_array_t);
DEFINE_ARRAY_STRUCT(key_value_pair_t, fc_json_map_t);
typedef struct {
BufferInfo output; //for json encode/decode
struct {
struct fast_mpool_man mpool;
string_t element; //string allocator use output buffer
bool use_mpool;
} decode;
int init_buff_size;
int error_no;
int error_size;
char error_holder[256];
string_t error_info;
fc_json_array_t jarray;
fc_json_map_t jmap;
/* for internal use */
const char *str; //input string
const char *p; //current
const char *end;
} fc_json_context_t;
#ifdef __cplusplus
extern "C" {
#endif
void free_common_array(common_array_t *array);
static inline void free_json_array(json_array_t *array)
static inline void fc_init_common_array(fc_common_array_t *array,
const int element_size)
{
free_common_array((common_array_t *)array);
array->elements = NULL;
array->element_size = element_size;
array->count = array->alloc = 0;
}
static inline void free_json_map(json_map_t *array)
static inline void fc_init_json_array(fc_json_array_t *array)
{
free_common_array((common_array_t *)array);
fc_init_common_array((fc_common_array_t *)array, sizeof(string_t));
}
static inline void free_json_string(string_t *buffer)
static inline void fc_init_json_map(fc_json_map_t *array)
{
if (buffer->str != NULL) {
free(buffer->str);
buffer->str = NULL;
buffer->len = 0;
fc_init_common_array((fc_common_array_t *)array,
sizeof(key_value_pair_t));
}
static inline void fc_free_common_array(fc_common_array_t *array)
{
if (array->elements != NULL) {
free(array->elements);
array->elements = NULL;
array->count = array->alloc = 0;
}
}
int detect_json_type(const string_t *input);
static inline void fc_free_json_array(fc_json_array_t *array)
{
fc_free_common_array((fc_common_array_t *)array);
}
int decode_json_array(const string_t *input, json_array_t *array,
char *error_info, const int error_size);
static inline void fc_free_json_map(fc_json_map_t *array)
{
fc_free_common_array((fc_common_array_t *)array);
}
int encode_json_array(json_array_t *array, string_t *output,
char *error_info, const int error_size);
static inline void fc_set_json_error_buffer(fc_json_context_t *ctx,
char *error_info, const int error_size)
{
if (error_info != NULL && error_size > 0) {
ctx->error_info.str = error_info;
ctx->error_size = error_size;
} else {
ctx->error_info.str = ctx->error_holder;
ctx->error_size = sizeof(ctx->error_holder);
}
int decode_json_map(const string_t *input, json_map_t *map,
char *error_info, const int error_size);
ctx->error_info.len = 0;
*ctx->error_info.str = '\0';
}
int encode_json_map(json_map_t *map, string_t *output,
char *error_info, const int error_size);
static inline int fc_init_json_context_ex(fc_json_context_t *ctx,
const bool decode_use_mpool, const int alloc_size_once,
const int init_buff_size, char *error_info,
const int error_size)
{
const int discard_size = 0;
ctx->output.buff = NULL;
ctx->output.alloc_size = ctx->output.length = 0;
FC_SET_STRING_NULL(ctx->decode.element);
if (init_buff_size > 0) {
ctx->init_buff_size = init_buff_size;
} else {
ctx->init_buff_size = 1024;
}
fc_init_json_array(&ctx->jarray);
fc_init_json_map(&ctx->jmap);
ctx->error_no = 0;
fc_set_json_error_buffer(ctx, error_info, error_size);
ctx->decode.use_mpool = decode_use_mpool;
if (decode_use_mpool) {
return fast_mpool_init(&ctx->decode.mpool,
alloc_size_once, discard_size);
} else {
return 0;
}
}
static inline int fc_init_json_context(fc_json_context_t *ctx)
{
const bool decode_use_mpool = false;
const int alloc_size_once = 0;
const int init_buff_size = 0;
return fc_init_json_context_ex(ctx, decode_use_mpool,
alloc_size_once, init_buff_size, NULL, 0);
}
static inline void fc_reset_json_context(fc_json_context_t *ctx)
{
if (ctx->decode.use_mpool) {
fast_mpool_reset(&ctx->decode.mpool);
}
}
static inline void fc_destroy_json_context(fc_json_context_t *ctx)
{
fc_free_buffer(&ctx->output);
fc_free_json_array(&ctx->jarray);
fc_free_json_map(&ctx->jmap);
if (ctx->decode.use_mpool) {
fast_mpool_destroy(&ctx->decode.mpool);
}
}
static inline int fc_json_parser_get_error_no(fc_json_context_t *ctx)
{
return ctx->error_no;
}
static inline const string_t *fc_json_parser_get_error_info(
fc_json_context_t *ctx)
{
return &ctx->error_info;
}
int fc_detect_json_type(const string_t *input);
int fc_encode_json_array_ex(fc_json_context_t *context,
const string_t *elements, const int count,
BufferInfo *buffer);
int fc_encode_json_map_ex(fc_json_context_t *context,
const key_value_pair_t *elements, const int count,
BufferInfo *buffer);
static inline const BufferInfo *fc_encode_json_array(fc_json_context_t
*context, const string_t *elements, const int count)
{
if (fc_encode_json_array_ex(context, elements, count,
&context->output) == 0)
{
return &context->output;
} else {
return NULL;
}
}
static inline const BufferInfo *fc_encode_json_map(fc_json_context_t
*context, const key_value_pair_t *elements, const int count)
{
if (fc_encode_json_map_ex(context, elements, count,
&context->output) == 0)
{
return &context->output;
} else {
return NULL;
}
}
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
*context, const string_t *input);
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
*context, const string_t *input);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -31,7 +31,7 @@ bool is_local_host_ip(const char *client_ip)
char *p;
char *pEnd;
pEnd = g_local_host_ip_addrs + \
pEnd = g_local_host_ip_addrs +
IP_ADDRESS_SIZE * g_local_host_ip_count;
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;
}
strcpy(g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count, \
client_ip);
strcpy(g_local_host_ip_addrs + IP_ADDRESS_SIZE *
g_local_host_ip_count, client_ip);
g_local_host_ip_count++;
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()
{
char buff[512];
char buff[1024];
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];
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));
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 + \
IP_ADDRESS_SIZE * g_local_host_ip_count;
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)
{
@ -172,7 +171,7 @@ const char *get_next_local_ip(const char *previous_ip)
found = true;
}
}
}
}
return NULL;
}
@ -187,7 +186,10 @@ const char *get_first_local_ip()
}
else
{
return LOCAL_LOOPBACK_IP;
/* 注意当系统存在IPv6回环地址时为了简化系统的改动
IPv6IPv4
*/
return LOCAL_LOOPBACK_IPv4;
}
}
@ -212,3 +214,17 @@ const char *get_first_local_private_ip()
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"
#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
extern "C" {
#endif
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];
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
void load_local_host_ip_addrs();
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_next_local_ip(const char *previous_ip);

View File

@ -13,6 +13,9 @@ typedef struct fc_locked_list {
extern "C" {
#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)
{
int result;
@ -24,6 +27,11 @@ extern "C" {
return 0;
}
static inline void locked_list_destroy(FCLockedList *list)
{
pthread_mutex_destroy(&list->lock);
}
static inline void locked_list_add(struct fc_list_head *_new,
FCLockedList *list)
{
@ -40,6 +48,22 @@ extern "C" {
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,
FCLockedList *list)
{
@ -48,6 +72,15 @@ extern "C" {
PTHREAD_MUTEX_UNLOCK(&list->lock);
}
static inline int locked_list_empty(FCLockedList *list)
{
int empty;
PTHREAD_MUTEX_LOCK(&list->lock);
empty = fc_list_empty(&list->head);
PTHREAD_MUTEX_UNLOCK(&list->lock);
return empty;
}
static inline int locked_list_count(FCLockedList *list)
{
int count;
@ -57,6 +90,24 @@ extern "C" {
return count;
}
#define locked_list_first_entry(list, type, member, var) \
PTHREAD_MUTEX_LOCK(&(list)->lock); \
var = fc_list_first_entry(&(list)->head, type, member); \
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
#define locked_list_last_entry(list, type, member, var) \
PTHREAD_MUTEX_LOCK(&(list)->lock); \
var = fc_list_last_entry(&(list)->head, type, member); \
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
#define locked_list_pop(list, type, member, var) \
PTHREAD_MUTEX_LOCK(&(list)->lock); \
var = fc_list_first_entry(&(list)->head, type, member); \
if (var != NULL) { \
fc_list_del_init(&var->member); \
} \
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
#ifdef __cplusplus
}
#endif

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)
{
char data_path[MAX_PATH_SIZE];
char log_path[MAX_PATH_SIZE];
snprintf(data_path, sizeof(data_path), "%s/logs", base_path);
if (!fileExists(data_path))
{
if (mkdir(data_path, 0755) != 0)
{
fprintf(stderr, "mkdir \"%s\" fail, " \
"errno: %d, error info: %s\n", \
data_path, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
}
fc_combine_full_filename(base_path, "logs", log_path);
if (!fileExists(log_path))
{
if (mkdir(log_path, 0755) != 0)
{
fprintf(stderr, "mkdir \"%s\" fail, "
"errno: %d, error info: %s\n",
log_path, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
}
return 0;
return 0;
}
int log_init()
@ -112,7 +112,7 @@ int log_init_ex(LogContext *pContext)
}
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;
}
@ -136,8 +136,8 @@ static int log_print_header(LogContext *pContext)
if (pContext->current_size < 0)
{
result = errno != 0 ? errno : EACCES;
fprintf(stderr, "lseek file \"%s\" fail, " \
"errno: %d, error info: %s\n", \
fprintf(stderr, "lseek file \"%s\" fail, "
"errno: %d, error info: %s\n",
pContext->log_filename, result, STRERROR(result));
}
else {
@ -158,8 +158,8 @@ static int log_print_header(LogContext *pContext)
static int log_open(LogContext *pContext)
{
int result;
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
O_CREAT | O_APPEND | pContext->fd_flags, 0644)) < 0)
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | O_CREAT |
O_APPEND | O_CLOEXEC | pContext->fd_flags, 0644)) < 0)
{
fprintf(stderr, "open log file \"%s\" to write fail, " \
"errno: %d, error info: %s\n", \
@ -222,31 +222,44 @@ int log_reopen_ex(LogContext *pContext)
return log_open(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)
{
int result;
int result;
char log_filename[MAX_PATH_SIZE];
if ((result=check_and_mk_log_dir(base_path)) != 0)
{
return result;
}
if ((result=check_and_mk_log_dir(base_path)) != 0)
{
return result;
}
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
base_path, filename_prefix);
return log_open(pContext);
snprintf(log_filename, MAX_PATH_SIZE, "%s/logs/%s.log",
base_path, filename_prefix);
return log_set_filename_ex(pContext, log_filename);
}
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
{
if (log_filename == NULL) {
fprintf(stderr, "file: "__FILE__", line: %d, " \
"log_filename is NULL!\n", __LINE__);
if (log_filename == NULL || *log_filename == '\0')
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"log_filename is NULL or empty!\n", __LINE__);
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)
@ -283,9 +296,9 @@ void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_call
{
int64_t current_size;
pthread_mutex_lock(&(pContext->log_thread_lock));
pthread_mutex_lock(&(pContext->lock));
current_size = pContext->current_size;
pthread_mutex_unlock(&(pContext->log_thread_lock));
pthread_mutex_unlock(&(pContext->lock));
if (current_size == 0)
{
log_print_header(pContext);
@ -334,7 +347,7 @@ void log_destroy_ex(LogContext *pContext)
close(pContext->log_fd);
pContext->log_fd = STDERR_FILENO;
pthread_mutex_destroy(&pContext->log_thread_lock);
pthread_mutex_destroy(&pContext->lock);
}
if (pContext->log_buff != NULL)
@ -372,12 +385,11 @@ static int log_delete_old_file(LogContext *pContext,
char full_filename[MAX_PATH_SIZE + 128];
if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
{
snprintf(full_filename, sizeof(full_filename), "%s%s",
old_filename, GZIP_EXT_NAME_STR);
fc_concat_two_strings(old_filename, GZIP_EXT_NAME_STR, full_filename);
}
else
{
snprintf(full_filename, sizeof(full_filename), "%s", old_filename);
fc_safe_strcpy(full_filename, old_filename);
}
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;
localtime_r(&the_time, &tm);
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,
rotate_time_format_prefix, &tm);
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);
for (i=0; i<filename_array.count; i++)
{
snprintf(full_filename, sizeof(full_filename), "%s%s",
log_filepath, filename_array.filenames[i]);
fc_concat_two_strings(log_filepath, filename_array.
filenames[i], full_filename);
if (unlink(full_filename) != 0)
{
if (errno != ENOENT)
@ -690,7 +704,9 @@ int log_delete_old_files(void *args)
the_time -= 86400;
localtime_r(&the_time, &tm);
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,
pContext->rotate_time_format, &tm);
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 full_filename[MAX_PATH_SIZE + 32];
char output[512];
const char *gzip_cmd_filename;
int prefix_len;
int result;
int i;
@ -747,11 +764,10 @@ static void *log_gzip_func(void *args)
continue;
}
snprintf(full_filename, sizeof(full_filename), "%s%s",
log_filepath, filename_array.filenames[i]);
snprintf(cmd, sizeof(cmd), "%s %s",
get_gzip_command_filename(), full_filename);
gzip_cmd_filename = get_gzip_command_filename();
fc_concat_two_strings(log_filepath, filename_array.
filenames[i], full_filename);
fc_combine_two_strings(gzip_cmd_filename, full_filename, ' ', cmd);
result = getExecResult(cmd, output, sizeof(output));
if (result != 0)
{
@ -830,7 +846,9 @@ int log_rotate(LogContext *pContext)
localtime_r(&current_time, &tm);
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,
pContext->rotate_time_format, &tm);
if (access(old_filename, F_OK) == 0)
@ -900,19 +918,19 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
{
if (bNeedLock)
{
pthread_mutex_lock(&(pContext->log_thread_lock));
pthread_mutex_lock(&(pContext->lock));
}
result = log_check_rotate(pContext);
if (bNeedLock)
{
pthread_mutex_unlock(&(pContext->log_thread_lock));
pthread_mutex_unlock(&(pContext->lock));
}
return result;
}
}
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
&(pContext->log_thread_lock))) != 0))
&(pContext->lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
@ -937,10 +955,10 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
if (written != write_bytes)
{
result = errno != 0 ? errno : EIO;
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call write fail, errno: %d, error info: %s\n",\
__LINE__, result, STRERROR(result));
}
fprintf(stderr, "file: "__FILE__", line: %d, "
"pid: %d, call write fail, fd: %d, errno: %d, error info: %s\n",
__LINE__, getpid(), pContext->log_fd, result, STRERROR(result));
}
if (pContext->rotate_immediately)
{
@ -948,7 +966,7 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
}
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
&(pContext->log_thread_lock))) != 0))
&(pContext->lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
@ -959,8 +977,8 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
return result;
}
static void doLogEx(LogContext *pContext, struct timeval *tv, \
const char *caption, const char *text, const int text_len, \
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)
{
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, " \
"call pthread_mutex_lock fail, " \
@ -1000,12 +1018,12 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
__LINE__, LOG_BUFF_SIZE, text_len + 64);
if (bNeedLock)
{
pthread_mutex_unlock(&(pContext->log_thread_lock));
pthread_mutex_unlock(&(pContext->lock));
}
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_fsync(pContext, false);
@ -1032,10 +1050,14 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
}
if (caption != NULL)
{
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
pContext->pcurrent_buff += buff_len;
}
{
buff_len = strlen(caption);
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);
pContext->pcurrent_buff += text_len;
*pContext->pcurrent_buff++ = '\n';
@ -1045,7 +1067,7 @@ static void doLogEx(LogContext *pContext, struct timeval *tv, \
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, " \
"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, \
const char *text, const int text_len, \
void log_it_ex2(LogContext *pContext, const char *caption,
const char *text, const int text_len,
const bool bNeedSync, const bool bNeedLock)
{
struct timeval tv;
@ -1070,10 +1092,10 @@ void log_it_ex2(LogContext *pContext, const char *caption, \
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)
{
bool bNeedSync;
@ -1269,45 +1291,12 @@ void logAccess(LogContext *pContext, struct timeval *tvStart, \
{
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 *caption;
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;
return get_log_level_caption(pContext->log_level);
}
#ifndef LOG_FORMAT_CHECK

View File

@ -62,7 +62,7 @@ typedef struct log_context
char *pcurrent_buff;
/* mutext lock */
pthread_mutex_t log_thread_lock;
pthread_mutex_t lock;
/*
rotate the log when the log file exceeds this parameter
@ -145,6 +145,7 @@ static inline int log_try_init()
*/
int log_init2();
#define log_reopen() log_reopen_ex(&g_log_context)
#define log_set_prefix(base_path, filename_prefix) \
@ -200,7 +201,7 @@ int log_reopen_ex(LogContext *pContext);
* filename_prefix: log filename prefix
* return: 0 for success, != 0 fail
*/
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);
/** set log filename
@ -273,6 +274,24 @@ void log_take_over_stderr_ex(LogContext *pContext);
*/
void log_take_over_stdout_ex(LogContext *pContext);
/** init function using global log context
* do nothing when already inited
* return: 0 for success, != 0 fail
*/
static inline int log_try_init2()
{
int result;
if ((result=log_try_init()) != 0)
{
return result;
}
log_take_over_stderr();
log_take_over_stdout();
return 0;
}
/** set compress_log_flags to true
* parameters:
* pContext: the log context
@ -324,7 +343,7 @@ void log_it_ex(LogContext *pContext, const int priority, \
* text_len: text string length (bytes)
* 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);
/** log to file
@ -336,10 +355,13 @@ void log_it_ex1(LogContext *pContext, const int priority, \
* bNeedSync: if sync to file immediatelly
* return: none
*/
void log_it_ex2(LogContext *pContext, const char *caption, \
const char *text, const int text_len, \
void log_it_ex2(LogContext *pContext, const char *caption,
const char *text, const int text_len,
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
* parameters:

View File

@ -311,7 +311,7 @@ MD5_memset(POINTER output, int value, unsigned int len)
/*
* Digests a string
*/
int my_md5_string(char *string,unsigned char digest[16])
int my_md5_string(char *string, unsigned char digest[16])
{
MD5_CTX context;
unsigned int len = strlen(string);
@ -332,25 +332,22 @@ int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16])
return 0;
}
int my_md5_file(char *filename,unsigned char digest[16])
int my_md5_file(char *filename, unsigned char digest[16])
{
FILE *file;
MD5_CTX context;
int len;
unsigned char buffer[1024];
unsigned char buff[16 * 1024];
if ((file = fopen(filename, "rb")) == NULL)
if ((file = fopen(filename, "rb")) == NULL) {
return -1;
else {
my_md5_init(&context);
while ((len = fread(buffer, 1, 1024, file)) > 0)
{
my_md5_update(&context, buffer, len);
}
my_md5_final(digest, &context);
}
fclose(file);
}
return 0;
my_md5_init(&context);
while ((len = fread(buff, 1, sizeof(buff), file)) > 0) {
my_md5_update(&context, buff, len);
}
my_md5_final(digest, &context);
fclose(file);
return 0;
}

View File

@ -41,12 +41,12 @@ int my_md5_file(char *filename, unsigned char digest[16]);
*/
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
void my_md5_init (MD5_CTX *context);
void my_md5_init(MD5_CTX *context);
void my_md5_update (MD5_CTX *context, unsigned char *input,
void my_md5_update(MD5_CTX *context, unsigned char *input,
unsigned int inputLen);
void my_md5_final (unsigned char digest[16], MD5_CTX *context);
void my_md5_final(unsigned char digest[16], MD5_CTX *context);
#ifdef __cplusplus
}

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,
const int init_recv_buffer_size, const int timeout_ms)
{
const bool use_io_uring = false;
int result;
int new_init_recv_buffer_size;
int i;
@ -65,8 +66,8 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
return EINVAL;
}
if ((result=ioevent_init(&client->ioevent, entry_count,
timeout_ms, 0)) != 0)
if ((result=ioevent_init(&client->ioevent, "client",
use_io_uring, entry_count, timeout_ms, 0)) != 0)
{
logError("file: "__FILE__", line: %d, "
"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++) {
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)
{
return result;
@ -128,6 +129,7 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
{
int bytes;
int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0;
while (entry->remain > 0) {
@ -139,27 +141,26 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
break;
} else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal",
__LINE__, entry->conn->ip_addr,
"server: %s:%u, ignore interupt signal", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port);
continue;
} else {
result = errno != 0 ? errno : ECONNRESET;
logError("file: "__FILE__", line: %d, "
"send to server %s:%u fail, "
"errno: %d, error info: %s",
__LINE__, entry->conn->ip_addr,
entry->conn->port,
result, strerror(result));
"errno: %d, error info: %s", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, result, strerror(result));
break;
}
} else if (bytes == 0) {
logError("file: "__FILE__", line: %d, "
"send to server %s:%u, sock: %d fail, "
"connection disconnected",
__LINE__, entry->conn->ip_addr, entry->conn->port,
entry->conn->sock);
"connection disconnected", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
break;
@ -190,6 +191,7 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
{
int i;
int result;
char formatted_ip[FORMATTED_IP_SIZE];
for (i=0; i<client->entry_count; i++) {
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].done = true;
logError("file: "__FILE__", line: %d, "
"NOT connected to %s:%u",
__LINE__, client->entries[i].conn->ip_addr,
client->entries[i].conn->port);
"NOT connected to %s:%u", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
continue;
}
@ -244,6 +246,7 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
{
int bytes;
int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0;
while (entry->remain > 0) {
@ -254,27 +257,26 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
break;
} else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal",
__LINE__, entry->conn->ip_addr,
"server: %s:%u, ignore interupt signal", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port);
continue;
} else {
result = errno != 0 ? errno : ECONNRESET;
logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv failed, "
"errno: %d, error info: %s",
__LINE__, entry->conn->ip_addr,
entry->conn->port,
result, strerror(result));
"errno: %d, error info: %s", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, result, strerror(result));
break;
}
} else if (bytes == 0) {
logError("file: "__FILE__", line: %d, "
"server: %s:%u, sock: %d, recv failed, "
"connection disconnected",
__LINE__, entry->conn->ip_addr, entry->conn->port,
entry->conn->sock);
"connection disconnected", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
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);
if (body_length < 0) {
logError("file: "__FILE__", line: %d, "
"server: %s:%u, body_length: %d < 0",
__LINE__, entry->conn->ip_addr,
"server: %s:%u, body_length: %d < 0", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, body_length);
result = EPIPE;
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)
{
int result;
int event;
int count;
#if IOEVENT_USE_URING
unsigned head;
#else
int event;
int index;
#endif
int remain_timeout;
FastMultiSockEntry *entry;
char formatted_ip[FORMATTED_IP_SIZE];
while (client->pulling_count > 0) {
remain_timeout = client->deadline_time_ms -
@ -328,8 +335,39 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
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);
logInfo("poll count: %d\n", count);
//logInfo("poll count: %d\n", count);
for (index=0; index<count; index++) {
event = IOEVENT_GET_EVENTS(&client->ioevent, index);
entry = (FastMultiSockEntry *)IOEVENT_GET_DATA(
@ -337,21 +375,22 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
if (event & IOEVENT_ERROR) {
logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv error event: %d, "
"connection reset", __LINE__,
entry->conn->ip_addr, entry->conn->port, event);
"server: %s:%u, recv error event: %d, connection "
"reset", __LINE__, format_ip_address(entry->conn->
ip_addr, formatted_ip), entry->conn->port, event);
fast_multi_sock_client_finish(client, entry, ECONNRESET);
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);
if (result != 0 || entry->remain == 0) {
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,
client->entries + i, ETIMEDOUT);
logError("file: "__FILE__", line: %d, "
"recv from %s:%u timedout",
__LINE__, client->entries[i].conn->ip_addr,
client->entries[i].conn->port);
"recv from %s:%u timedout", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
}
}
}

View File

@ -21,7 +21,6 @@
#include <net/if.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include "common_define.h"
#include "connection_pool.h"

View File

@ -34,6 +34,22 @@
#include <SAPI.h>
#include <php_ini.h>
#ifndef TSRMLS_DC
#define TSRMLS_DC
#endif
#ifndef TSRMLS_C
#define TSRMLS_C
#endif
#ifndef TSRMLS_CC
#define TSRMLS_CC
#endif
#ifndef TSRMLS_FETCH
#define TSRMLS_FETCH()
#endif
#if PHP_MAJOR_VERSION < 7
typedef int zend_size_t;
#define ZEND_RETURN_STRING(s, dup) RETURN_STRING(s, dup)

View File

@ -50,14 +50,14 @@ int write_to_pid_file(const char *pidFilename)
char buff[32];
int len;
len = sprintf(buff, "%d", (int)getpid());
len = fc_itoa(getpid(), buff);
return writeToFile(pidFilename, buff, len);
}
int delete_pid_file(const char *pidFilename)
{
int result;
pid_t pid;
pid_t pid = 0;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
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
pid_t pid;
pid_t pid = 0;
int result;
int sig;
int i;
*force = false;
if ((result=do_stop(pidFilename, bShowError, &pid)) != 0) {
return result;
}
@ -131,14 +133,15 @@ int process_stop_ex(const char *pidFilename, const bool bShowError)
break;
}
usleep(100 * 1000);
fc_sleep_ms(100);
}
if (i == MAX_WAIT_COUNT) {
if (kill(pid, SIGKILL) == 0) {
fprintf(stderr, "waiting for pid [%d] exit timeout, "
"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)
{
const bool bShowError = false;
bool force;
int result;
result = process_stop_ex(pidFilename, bShowError);
result = process_stop_ex(pidFilename, bShowError, &force);
if (result == ENOENT || result == ESRCH) {
result = 0;
} else if (result == 0) {
if (force) {
sleep(1);
}
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)
{
pid_t pid;
pid_t pid = 0;
int result;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
@ -274,10 +281,11 @@ int process_exist(const char *pidFilename, pid_t *pid)
}
}
int get_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size)
int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
const int path_size, const int noent_log_level)
{
char *pBasePath;
string_t path_string;
IniContext iniContext;
int result;
@ -294,7 +302,7 @@ int get_base_path_from_conf_file(const char *filename, char *base_path,
do
{
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
if (pBasePath == NULL)
if (pBasePath == NULL || *pBasePath == '\0')
{
logError("file: "__FILE__", line: %d, " \
"conf file \"%s\" must have item " \
@ -303,16 +311,18 @@ int get_base_path_from_conf_file(const char *filename, char *base_path,
break;
}
snprintf(base_path, path_size, "%s", pBasePath);
FC_SET_STRING(path_string, pBasePath);
normalize_path(NULL, &path_string, base_path, path_size);
chopPath(base_path);
if (!fileExists(base_path))
{
logError("file: "__FILE__", line: %d, " \
"\"%s\" can't be accessed, error info: %s", \
__LINE__, base_path, STRERROR(errno));
result = errno != 0 ? errno : ENOENT;
break;
}
{
result = errno != 0 ? errno : ENOENT;
log_it_ex(&g_log_context, noent_log_level,
"file: "__FILE__", line: %d, "
"\"%s\" can't be accessed, error info: %s",
__LINE__, base_path, STRERROR(result));
break;
}
if (!isDir(base_path))
{
logError("file: "__FILE__", line: %d, " \
@ -329,7 +339,6 @@ int get_base_path_from_conf_file(const char *filename, char *base_path,
int process_action(const char *pidFilename, const char *action, bool *stop)
{
const bool bShowError = true;
int result;
pid_t pid;
@ -342,7 +351,7 @@ int process_action(const char *pidFilename, const char *action, bool *stop)
if (strcmp(action, "stop") == 0)
{
*stop = true;
return process_stop_ex(pidFilename, bShowError);
return process_stop(pidFilename);
}
else if (strcmp(action, "status") == 0)
{

View File

@ -27,8 +27,11 @@
extern "C" {
#endif
int get_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size);
int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
const int path_size, const int noent_log_level);
#define get_base_path_from_conf_file(filename, base_path, path_size) \
get_base_path_from_conf_file_ex(filename, base_path, path_size, LOG_ERR)
int get_pid_from_file(const char *pidFilename, pid_t *pid);
@ -36,9 +39,15 @@ int write_to_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);

View File

@ -71,6 +71,58 @@ int init_pthread_lock(pthread_mutex_t *pthread_lock)
return 0;
}
int init_pthread_rwlock(pthread_rwlock_t *rwlock)
{
struct {
pthread_rwlockattr_t holder;
pthread_rwlockattr_t *ptr;
} attr;
int result;
#ifdef WITH_PTHREAD_RWLOCKATTR_SETKIND_NP
attr.ptr = &attr.holder;
if ((result=pthread_rwlockattr_init(attr.ptr)) != 0) {
logError("file: "__FILE__", line: %d, "
"call pthread_rwlockattr_init fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_rwlockattr_setkind_np(attr.ptr,
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_rwlockattr_settype fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
#else
attr.ptr = NULL;
#endif
if ((result=pthread_rwlock_init(rwlock, attr.ptr)) != 0) {
logError("file: "__FILE__", line: %d, "
"call pthread_rwlock_init fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
if (attr.ptr != NULL) {
if ((result=pthread_rwlockattr_destroy(attr.ptr)) != 0) {
logError("file: "__FILE__", line: %d, "
"call thread_rwlockattr_destroy fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
}
return 0;
}
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
{
size_t old_stack_size;

View File

@ -32,6 +32,7 @@ extern "C" {
#endif
int init_pthread_lock(pthread_mutex_t *pthread_lock);
int init_pthread_rwlock(pthread_rwlock_t *rwlock);
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
int init_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp);
@ -63,6 +64,45 @@ void destroy_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp);
} while (0)
#define PTHREAD_RWLOCK_WRLOCK(rwlock) \
do { \
int rwlock_res; \
if ((rwlock_res=pthread_rwlock_wrlock(rwlock)) != 0) \
{ \
logWarning("file: "__FILE__", line: %d, " \
"call pthread_rwlock_wrlock fail, " \
"errno: %d, error info: %s", \
__LINE__, rwlock_res, STRERROR(rwlock_res)); \
} \
} while (0)
#define PTHREAD_RWLOCK_RDLOCK(rwlock) \
do { \
int rwlock_res; \
if ((rwlock_res=pthread_rwlock_rdlock(rwlock)) != 0) \
{ \
logWarning("file: "__FILE__", line: %d, " \
"call pthread_rwlock_rdlock fail, " \
"errno: %d, error info: %s", \
__LINE__, rwlock_res, STRERROR(rwlock_res)); \
} \
} while (0)
#define PTHREAD_RWLOCK_UNLOCK(rwlock) \
do { \
int unlock_res; \
if ((unlock_res=pthread_rwlock_unlock(rwlock)) != 0) \
{ \
logWarning("file: "__FILE__", line: %d, " \
"call pthread_rwlock_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, unlock_res, STRERROR(unlock_res)); \
} \
} while (0)
#define lcp_timedwait_sec(lcp, timeout) \
fc_timedwait_sec(&(lcp)->lock, &(lcp)->cond, timeout)
@ -74,9 +114,9 @@ static inline void fc_timedwait_sec(pthread_mutex_t *lock,
{
struct timespec ts;
PTHREAD_MUTEX_LOCK(lock);
ts.tv_sec = get_current_time() + timeout;
ts.tv_nsec = 0;
PTHREAD_MUTEX_LOCK(lock);
pthread_cond_timedwait(cond, lock, &ts);
PTHREAD_MUTEX_UNLOCK(lock);
}
@ -88,9 +128,9 @@ static inline void fc_timedwait_ms(pthread_mutex_t *lock,
struct timespec ts;
expires_ms = get_current_time_ms() + timeout_ms;
PTHREAD_MUTEX_LOCK(lock);
ts.tv_sec = expires_ms / 1000;
ts.tv_nsec = (expires_ms % 1000) * (1000 * 1000);
PTHREAD_MUTEX_LOCK(lock);
pthread_cond_timedwait(cond, lock, &ts);
PTHREAD_MUTEX_UNLOCK(lock);
}

View File

@ -45,16 +45,63 @@ static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
((ScheduleEntry *)p2)->next_call_time;
}
time_t sched_make_first_call_time(struct tm *tm_current,
const TimeInfo *time_base, const int interval)
{
int remain;
struct {
time_t time;
struct tm tm;
} base;
if (time_base->hour == TIME_NONE)
{
return g_current_time + interval;
}
if (tm_current->tm_hour > time_base->hour ||
(tm_current->tm_hour == time_base->hour
&& tm_current->tm_min >= time_base->minute))
{
base.tm = *tm_current;
}
else
{
base.time = g_current_time - 24 * 3600;
localtime_r(&base.time, &base.tm);
}
base.tm.tm_hour = time_base->hour;
base.tm.tm_min = time_base->minute;
if (time_base->second >= 0 && time_base->second <= 59)
{
base.tm.tm_sec = time_base->second;
}
else
{
base.tm.tm_sec = 0;
}
base.time = mktime(&base.tm);
remain = g_current_time - base.time;
if (remain > 0)
{
return g_current_time + interval - remain % interval;
}
else if (remain < 0)
{
return g_current_time + (-1 * remain) % interval;
}
else
{
return g_current_time;
}
}
static int sched_init_entries(ScheduleEntry *entries, const int count)
{
ScheduleEntry *pEntry;
ScheduleEntry *pEnd;
time_t time_base;
struct tm tm_current;
struct tm tm_base;
time_t current_time;
int remain;
int interval;
if (count < 0)
{
@ -68,8 +115,8 @@ static int sched_init_entries(ScheduleEntry *entries, const int count)
return 0;
}
current_time = time(NULL);
localtime_r((time_t *)&current_time, &tm_current);
g_current_time = time(NULL);
localtime_r((time_t *)&g_current_time, &tm_current);
pEnd = entries + count;
for (pEntry=entries; pEntry<pEnd; pEntry++)
{
@ -80,65 +127,21 @@ static int sched_init_entries(ScheduleEntry *entries, const int count)
if (pEntry->interval <= 0)
{
logError("file: "__FILE__", line: %d, " \
"shedule interval %d <= 0", \
__LINE__, pEntry->interval);
logError("file: "__FILE__", line: %d, "
"shedule id: %d, interval %d <= 0",
__LINE__, pEntry->id, pEntry->interval);
return EINVAL;
}
if (pEntry->time_base.hour == TIME_NONE)
{
pEntry->next_call_time = current_time +
pEntry->interval;
}
else
{
if (tm_current.tm_hour > pEntry->time_base.hour ||
(tm_current.tm_hour == pEntry->time_base.hour
&& tm_current.tm_min >= pEntry->time_base.minute))
{
tm_base = tm_current;
}
else
{
time_base = current_time - 24 * 3600;
localtime_r(&time_base, &tm_base);
}
tm_base.tm_hour = pEntry->time_base.hour;
tm_base.tm_min = pEntry->time_base.minute;
if (pEntry->time_base.second >= 0 && pEntry->time_base.second <= 59)
{
tm_base.tm_sec = pEntry->time_base.second;
}
else
{
tm_base.tm_sec = 0;
}
time_base = mktime(&tm_base);
remain = current_time - time_base;
if (remain > 0)
{
interval = pEntry->interval - remain % pEntry->interval;
}
else if (remain < 0)
{
interval = (-1 * remain) % pEntry->interval;
}
else
{
interval = 0;
}
pEntry->next_call_time = current_time + interval;
}
pEntry->next_call_time = sched_make_first_call_time(
&tm_current, &pEntry->time_base, pEntry->interval);
/*
{
char buff1[32];
char buff2[32];
logInfo("id=%d, current time=%s, first call time=%s",
pEntry->id, formatDatetime(current_time,
pEntry->id, formatDatetime(g_current_time,
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)),
formatDatetime(pEntry->next_call_time,
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
@ -716,7 +719,7 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
if (timer_slot_count > 0)
{
if ((result=fast_mblock_init_ex1(&pContext->delay_task_allocator,
"sched_delay_task", sizeof(FastDelayTask),
"sched-delay-task", sizeof(FastDelayTask),
mblock_alloc_once, 0, NULL, NULL, true)) != 0)
{
free(pContext);
@ -960,3 +963,16 @@ uint32_t sched_generate_next_id()
{
return ++next_id;
}
static int sched_free_ptr_func(void *ptr)
{
free(ptr);
return 0;
}
int sched_delay_free_ptr(void *ptr, const int delay_seconds)
{
const bool new_thread = false;
return sched_add_delay_task_ex(schedule_context, sched_free_ptr_func,
ptr, delay_seconds, new_thread);
}

View File

@ -168,6 +168,15 @@ int sched_add_delay_task(TaskFunc task_func, void *func_args,
const int delay_seconds, const bool new_thread);
/** delay free a pointer
* parameters:
* ptr: the ptr to free
* delay_seconds: delay seconds to free the ptr
* return: error no, 0 for success, != 0 fail
*/
int sched_delay_free_ptr(void *ptr, const int delay_seconds);
/** init the schedule context
* parameters:
* pContext: store the ScheduleContext pointer
@ -197,6 +206,9 @@ int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
*/
void sched_print_all_entries();
time_t sched_make_first_call_time(struct tm *tm_current,
const TimeInfo *time_base, const int interval);
#ifdef __cplusplus
}
#endif

View File

@ -244,6 +244,7 @@ static int fc_server_check_ip_port(FCServerConfig *ctx,
FCServerMap *previous;
FCServerMap *current;
FCServerMap *end;
char formatted_ip[FORMATTED_IP_SIZE];
int id1;
int id2;
@ -261,8 +262,8 @@ static int fc_server_check_ip_port(FCServerConfig *ctx,
logError("file: "__FILE__", line: %d, "
"config file: %s, duplicate ip:port %s:%u, "
"the server ids: %d, %d", __LINE__,
config_filename, previous->ip_addr.str,
previous->port, id1, id2);
config_filename, format_ip_address(previous->ip_addr.str,
formatted_ip), previous->port, id1, id2);
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,
const char *group_name)
{
int len;
ginfo->group_name.str = ginfo->name_buff;
ginfo->group_name.len = snprintf(ginfo->name_buff,
sizeof(ginfo->name_buff) - 1, "%s", group_name);
if (ginfo->group_name.len == 0) {
return;
len = strlen(group_name);
if (len >= sizeof(ginfo->name_buff)) {
len = sizeof(ginfo->name_buff) - 1;
}
fc_trim(ginfo->group_name.str);
ginfo->group_name.len = strlen(ginfo->group_name.str);
memcpy(ginfo->name_buff, group_name, len);
*(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,
@ -309,40 +313,111 @@ static inline void fc_server_set_ip_prefix(FCServerGroupInfo *ginfo,
{
ginfo->filter.ip_prefix.str = ginfo->filter.prefix_buff;
if (ip_prefix != NULL) {
ginfo->filter.ip_prefix.len = snprintf(ginfo->filter.prefix_buff,
sizeof(ginfo->filter.prefix_buff) - 1, "%s", ip_prefix);
ginfo->filter.ip_prefix.len = fc_safe_strcpy(
ginfo->filter.prefix_buff, ip_prefix);
}
}
static int fc_server_load_one_group(FCServerConfig *ctx,
const char *config_filename, IniContext *ini_context,
const int group_count, const char *section_name)
static inline int fc_server_set_comm_type(FCCommunicationType *comm_type,
const char *config_filename, 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;
char new_name[FAST_INI_ITEM_NAME_SIZE];
char *port_str;
char *net_type;
char *ip_prefix;
strcpy(new_name, section_name);
strcpy(new_name, ini_ctx->section_name);
group = ctx->group_array.groups + ctx->group_array.count;
fc_server_set_group_ptr_name(group, new_name + GROUP_SECTION_PREFIX_LEN);
if (group->group_name.len == 0) {
logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, no group name!",
__LINE__, config_filename, section_name);
__LINE__, ini_ctx->filename, ini_ctx->section_name);
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 (group_count == 1) {
group->port = ctx->default_port;
} else {
logError("file: "__FILE__", line: %d, "
"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);
return ENOENT;
}
@ -352,24 +427,39 @@ static int fc_server_load_one_group(FCServerConfig *ctx,
if (group->port <= 0 || (endptr != NULL && *endptr != '\0')) {
logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, item: %s, "
"invalid port: %s", __LINE__, config_filename,
section_name, SERVER_ITEM_PORT_STR, port_str);
"invalid port: %s", __LINE__, ini_ctx->filename,
ini_ctx->section_name, SERVER_ITEM_PORT_STR, port_str);
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);
if (group->filter.net_type == FC_NET_TYPE_NONE) {
logError("file: "__FILE__", line: %d, "
"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;
}
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);
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++;
return 0;
}
@ -429,7 +519,7 @@ static void fc_server_sort_groups(FCServerConfig *ctx)
}
static int fc_server_load_groups(FCServerConfig *ctx,
const char *config_filename, IniContext *ini_context)
IniFullContext *ini_ctx)
{
int result;
int count;
@ -437,30 +527,30 @@ static int fc_server_load_groups(FCServerConfig *ctx,
IniSectionInfo *section;
IniSectionInfo *end;
if ((result=iniGetSectionNamesByPrefix(ini_context,
if ((result=iniGetSectionNamesByPrefix(ini_ctx->context,
GROUP_SECTION_PREFIX_STR, sections,
FC_MAX_GROUP_COUNT, &count)) != 0)
{
logError("file: "__FILE__", line: %d, "
"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));
return result;
}
if (count == 0) {
ctx->group_array.count = 1;
memset(ctx->group_array.groups, 0, sizeof(FCServerGroupInfo));
fc_server_set_group_ptr_name(ctx->group_array.groups + 0, "");
ctx->group_array.groups[0].port = iniGetIntValue(NULL, "port",
ini_context, ctx->default_port);
ini_ctx->context, ctx->default_port);
return 0;
}
end = sections + count;
for (section=sections; section<end; section++) {
if ((result=fc_server_load_one_group(ctx, config_filename,
ini_context, count, section->section_name)) != 0)
{
ini_ctx->section_name = section->section_name;
if ((result=fc_server_load_one_group(ctx, ini_ctx, count)) != 0) {
return result;
}
}
@ -612,6 +702,7 @@ static int check_addresses_duplicate(FCServerConfig *ctx,
FCAddressInfo **ppaddr;
FCAddressInfo **ppend;
FCAddressInfo **pprevious;
char formatted_ip[FORMATTED_IP_SIZE];
if (group_addr->address_array.count <= 1) {
return 0;
@ -629,7 +720,8 @@ static int check_addresses_duplicate(FCServerConfig *ctx,
config_filename, section_name,
group_addr->server_group->group_name.len,
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;
}
pprevious = ppaddr;
@ -794,6 +886,7 @@ static int fc_server_load_group_server(FCServerConfig *ctx,
return result;
}
address.conn.comm_type = group->comm_type;
if ((result=fc_server_set_group_server_address(server,
group_addr, &address)) != 0)
{
@ -812,6 +905,7 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
FCGroupAddresses *group_addr;
const FCAddressInfo *new_addr;
FCAddressInfo addr_holder;
char formatted_ip[FORMATTED_IP_SIZE];
int result;
int count;
int group_index;
@ -835,9 +929,16 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
if (addr->conn.port == 0) {
addr_holder = *addr;
addr_holder.conn.port = FC_SERVER_GROUP_PORT(group);
addr_holder.conn.comm_type = group->comm_type;
new_addr = &addr_holder;
} 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,
@ -870,7 +971,8 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
"config filename: %s, section: %s, "
"host %s:%u belongs to %d groups",
__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;
}
@ -1167,17 +1269,71 @@ static int fc_server_load_servers(FCServerConfig *ctx,
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,
IniContext *ini_context, const char *config_filename)
{
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,
ini_context)) != 0)
FAST_INI_SET_FULL_CTX_EX(full_ini_ctx,
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;
}
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,
ini_context)) != 0)
{
@ -1340,13 +1496,31 @@ static int fc_groups_to_string(FCServerConfig *ctx, FastBuffer *buffer)
fast_buffer_append(buffer,
"[%s%.*s]\n"
"port = %d\n"
"net_type = %s\n"
"ip_prefix = %.*s\n\n",
"port = %d\n",
GROUP_SECTION_PREFIX_STR,
group->group_name.len, group->group_name.str,
group->port, net_type_caption,
group->filter.ip_prefix.len,
group->port);
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);
}
return 0;
@ -1357,6 +1531,7 @@ static void fc_group_servers_to_string(FCServerConfig *ctx,
{
FCAddressInfo **addr;
FCAddressInfo **end;
char formatted_ip[FORMATTED_IP_SIZE];
end = gaddr->address_array.addrs + gaddr->address_array.count;
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);
}
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;
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);
if ((result=fc_groups_to_string(ctx, buffer)) != 0) {
return result;
@ -1435,13 +1619,31 @@ static void fc_server_log_groups(FCServerConfig *ctx)
{
FCServerGroupInfo *group;
FCServerGroupInfo *end;
char buff[1024];
char *p;
end = ctx->group_array.groups + ctx->group_array.count;
for (group=ctx->group_array.groups; group<end; group++) {
logInfo("group_name: %.*s, port: %d, net_type: %s, ip_prefix: %.*s",
group->group_name.len, group->group_name.str, group->port,
p = buff + sprintf(buff, "group_name: %.*s, port: %d",
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),
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 **end;
char formatted_ip[FORMATTED_IP_SIZE];
end = gaddr->address_array.addrs + gaddr->address_array.count;
for (addr=gaddr->address_array.addrs; addr<end; addr++) {
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,69 +1695,24 @@ static void fc_server_log_servers(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_servers(ctx);
}
ConnectionInfo *fc_server_check_connect_ex(FCAddressPtrArray *addr_array,
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_ex(&(*current)->conn,
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_ex(&(*addr)->conn,
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,
ConnectionInfo *conn, const int connect_timeout,
const char *bind_ipaddr, const bool log_connect_error)
ConnectionInfo *conn, const char *service_name,
const int connect_timeout, const char *bind_ipaddr,
const bool log_connect_error)
{
FCAddressInfo **current;
FCAddressInfo **addr;
@ -1565,9 +1724,11 @@ int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
}
current = addr_array->addrs + addr_array->index;
*conn = (*current)->conn;
conn->sock = -1;
if ((result=conn_pool_connect_server_ex(conn, connect_timeout,
conn_pool_set_server_info(conn, (*current)->conn.ip_addr,
(*current)->conn.port);
conn->comm_type = (*current)->conn.comm_type;
if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
make_connection(conn, service_name, connect_timeout * 1000,
bind_ipaddr, log_connect_error)) == 0)
{
return 0;
@ -1583,9 +1744,11 @@ int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
continue;
}
*conn = (*addr)->conn;
conn->sock = -1;
if ((result=conn_pool_connect_server_ex(conn, connect_timeout,
conn_pool_set_server_info(conn, (*addr)->conn.ip_addr,
(*addr)->conn.port);
conn->comm_type = (*addr)->conn.comm_type;
if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
make_connection(conn, service_name, connect_timeout * 1000,
bind_ipaddr, log_connect_error)) == 0)
{
addr_array->index = addr - addr_array->addrs;
@ -1620,3 +1783,36 @@ const FCAddressInfo *fc_server_get_address_by_peer(
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;
} FCAddressPtrArray;
typedef struct
{
bool enabled;
int switch_on_iops;
int switch_on_count;
} FCSmartPollingConfig;
typedef struct
{
string_t group_name;
int port; //default port
int server_port; //port in server section
int buffer_size; //for RDMA
FCCommunicationType comm_type;
FCSmartPollingConfig smart_polling;
struct {
int net_type;
string_t ip_prefix;
@ -111,11 +121,21 @@ typedef struct
FCServerMap *maps;
} 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 min_hosts_each_group;
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;
struct {
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,
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,
const string_t *group_name)
{
@ -211,24 +241,47 @@ int fc_server_to_config_string(FCServerConfig *ctx, FastBuffer *buffer);
void fc_server_to_log(FCServerConfig *ctx);
ConnectionInfo *fc_server_check_connect_ex(FCAddressPtrArray *addr_array,
const int connect_timeout, const char *bind_ipaddr,
const bool log_connect_error, int *err_no);
#define fc_server_check_connect(addr_array, connect_timeout, err_no) \
fc_server_check_connect_ex(addr_array, connect_timeout, NULL, true, err_no)
void fc_server_disconnect(FCAddressPtrArray *addr_array);
const FCAddressInfo *fc_server_get_address_by_peer(
FCAddressPtrArray *addr_array, const char *peer_ip);
int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
ConnectionInfo *conn, const int connect_timeout,
const char *bind_ipaddr, const bool log_connect_error);
ConnectionInfo *conn, const char *service_name,
const int connect_timeout, const char *bind_ipaddr,
const bool log_connect_error);
#define fc_server_make_connection(addr_array, conn, connect_timeout) \
fc_server_make_connection_ex(addr_array, conn, connect_timeout, NULL, true)
#define fc_server_make_connection(addr_array, \
conn, service_name, connect_timeout) \
fc_server_make_connection_ex(addr_array, conn, \
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
}

View File

@ -42,7 +42,7 @@ int shared_buffer_init_ex(SharedBufferContext *context,
int result;
context->buffer_init_capacity = buffer_init_capacity;
if ((result=fast_mblock_init_ex1(&context->allocator, "shared_buffer",
if ((result=fast_mblock_init_ex1(&context->allocator, "shared-buffer",
sizeof(SharedBuffer), alloc_elements_once,
alloc_elements_limit, shared_buffer_alloc_init,
context, need_lock)) != 0)

File diff suppressed because it is too large Load Diff

View File

@ -19,11 +19,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include "common_define.h"
#ifdef OS_LINUX
#include <sys/syscall.h>
#endif
#include "fc_memory.h"
#include "ini_file_reader.h"
@ -33,14 +38,22 @@
#define NORMALIZE_FLAGS_URL_ENABLED_AND_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) \
if (g_set_cloexec) fd_set_cloexec(fd)
#ifdef __cplusplus
extern "C" {
#endif
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)
{
g_set_cloexec = cloexec;
}
/** lowercase the string
* parameters:
* src: input string, will be changed
@ -185,14 +198,24 @@ void printBuffHex(const char *s, const int len);
* buff: the buffer, at least 2 bytes space, no tail \0
* 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
* parameters:
* buff: big-endian 2 bytes buffer
* 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)
* parameters:
@ -200,14 +223,28 @@ short buff2short(const char *buff);
* buff: the buffer, at least 4 bytes space, no tail \0
* 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
* parameters:
* buff: big-endian 4 bytes buffer
* 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)
* parameters:
@ -215,15 +252,38 @@ int buff2int(const char *buff);
* buff: the buffer, at least 8 bytes space, no tail \0
* 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
* parameters:
* buff: big-endian 8 bytes buffer
* 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)
* parameters:
@ -281,6 +341,154 @@ static inline double buff2double(const char *buff)
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)
* parameters:
* pStr: the string to trim
@ -295,13 +503,6 @@ char *trim_left(char *pStr);
*/
char *trim_right(char *pStr);
/** trim leading and tail spaces ( \t\r\n)
* parameters:
* pStr: the string to trim
* return: trimed string porinter as pStr
*/
char *trim(char *pStr);
/** trim leading and tail spaces ( \t\r\n)
* parameters:
* pStr: the string to trim
@ -527,11 +728,26 @@ int load_log_level_ex(const char *conf_filename);
/** set global log level
* parameters:
* pLogLevel: log level string value
* pLogLevel: the log level string value
* return: none
*/
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
* parameters:
* pIniContext: the config context
@ -540,7 +756,7 @@ void set_log_level(char *pLogLevel);
* return: error no , 0 success, != 0 fail
*/
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
@ -592,6 +808,47 @@ int get_time_item_from_str(const char *pValue, const char *item_name,
*/
void chopPath(char *filePath);
/** remove redundant slashes
* parameters:
* src: the input path
* dest: the output path
* size: the max size of dest path
* return: error no , 0 success, != 0 fail
*/
int fc_remove_redundant_slashes(const string_t *src,
string_t *dest, const int size);
static inline int fc_remove_redundant_slashes1(const char *input,
string_t *dest, const int size)
{
string_t src;
FC_SET_STRING(src, (char *)input);
return fc_remove_redundant_slashes(&src, dest, size);
}
static inline int fc_remove_redundant_slashes2(const char *input,
char *output, const int size)
{
string_t src;
string_t dest;
FC_SET_STRING(src, (char *)input);
dest.str = output;
return fc_remove_redundant_slashes(&src, &dest, size);
}
/** get file content by fd
* parameters:
* fd: the file descriptor
* filename: the filename
* buff: return the buff, must be freed
* file_size: store the file size
* return: error no , 0 success, != 0 fail
*/
int getFileContent1(int fd, const char *filename,
char **buff, int64_t *file_size);
/** get file content
* parameters:
* filename: the filename
@ -601,6 +858,18 @@ void chopPath(char *filePath);
*/
int getFileContent(const char *filename, char **buff, int64_t *file_size);
/** get file content
* parameters:
* fd: the file descriptor
* filename: the filename
* buff: the buff to store file content
* offset: the start offset
* size: specify the size to fetch and return the fetched size
* return: error no , 0 success, != 0 fail
*/
int getFileContentEx1(int fd, const char *filename, char *buff,
int64_t offset, int64_t *size);
/** get file content
* parameters:
* filename: the filename
@ -697,7 +966,7 @@ int fd_set_cloexec(int fd);
*/
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:
* p1: the first ip address
* p2: the second ip address
@ -705,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 fc_compare_int64_ptr(const int64_t *n1, const int64_t *n2);
/** parse bytes
* parameters:
* pStr: the string to parse
@ -750,6 +1021,15 @@ double get_line_distance_km(const double lat1, const double lon1,
*/
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
* return: current time
*/
@ -767,7 +1047,10 @@ int64_t get_current_time_us();
* n: the number to test
* return: true for power 2, otherwise false
*/
bool is_power2(const int64_t n);
static inline bool is_power2(const int64_t n)
{
return ((n != 0) && (n & (n - 1)) == 0);
}
/** set file read lock
* parameters:
@ -827,7 +1110,7 @@ bool isLeadingSpacesLine(const char *content, const char *current);
*/
bool isTrailingSpacesLine(const char *tail, const char *end);
/** write to file
/** safe write wrapper
* parameters:
* fd: the fd to write
* buf: the buffer
@ -836,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);
/** 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
* parameters:
* fd: the fd to write
@ -854,6 +1146,15 @@ ssize_t fc_lock_write(int fd, const char *buf, const size_t nbyte);
*/
ssize_t fc_safe_read(int fd, char *buf, const size_t count);
/** read integral lines from file
* parameters:
* fd: the fd to read
* buf: the buffer to store the line
* size: max read bytes
* return: error no , 0 success, != 0 fail
*/
ssize_t fc_read_lines(int fd, char *buf, const size_t size);
/** ftok with hash code
* parameters:
* path: the file path
@ -890,6 +1191,8 @@ static inline const char *long_to_comma_str(const int64_t n, char *buff)
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
* parameters:
* str: the string to detect
@ -940,25 +1243,26 @@ char *format_http_date(time_t t, BufferInfo *buffer);
/** return full path for the filename (the second parameter)
* parameters:
* from: the input full path filename to get base path
* from: the input full path filename to get base path,
* NULL for current work directory
* filename: the filename to resolve path
* full_filename: store the resolved full path filename
* size: the max size of full_filename
* 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);
/** return absolute uri (the second parameter)
* parameters:
* from: the input uri to get base path
* uri: the uri to resolve
* dest: store the resolved absolute uri
* size: the max size of dest
* return: length of the resolved uri
*/
int normalize_uri(const string_t *from, const char *uri,
char *dest, const int size);
static inline int normalize_path1(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(&from_string, &filename_string, full_filename, size);
}
/** return full path for the filename (the second parameter)
* parameters:
@ -971,9 +1275,204 @@ int normalize_uri(const string_t *from, const char *uri,
* NORMALIZE_FLAGS_URL_APPEND_PARAMS: append params of from
* 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);
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
* return: the gzip command full filename
@ -1030,6 +1529,15 @@ int fc_init_buffer(BufferInfo *buffer, const int buffer_size);
*/
void fc_free_buffer(BufferInfo *buffer);
/** realloc buffer
* parameters:
* buffer: the buffer to init
* init_buff_size: the init buffer size
* expect_size: the expect buffer size
* return: error no, 0 success, != 0 fail
*/
int fc_realloc_buffer(BufferInfo *buffer, const int
init_buff_size, const int expect_size);
static inline int fc_get_umask()
{
@ -1056,9 +1564,27 @@ static inline int fc_mkdirs(const char *path, const mode_t mode)
return fc_mkdirs_ex(path, mode, &create_count);
}
int fc_check_rename_ex(const char *oldpath, const char *newpath,
const bool overwritten);
static inline int fc_check_rename(const char *oldpath, const char *newpath)
{
const bool overwritten = true;
return fc_check_rename_ex(oldpath, newpath, overwritten);
}
int fc_get_path_child_count(const char *path);
int fc_copy_file(const char *src_filename, const char *dest_filename);
int fc_copy_to_path(const char *src_filename, const char *dest_path);
int fc_get_first_line(const char *filename, char *buff,
const int buff_size, string_t *line);
int fc_get_first_lines(const char *filename, char *buff,
const int buff_size, string_t *lines, int *count);
int fc_get_last_line(const char *filename, char *buff,
const int buff_size, int64_t *file_size, string_t *line);
@ -1075,6 +1601,100 @@ int fc_get_last_lines(const char *filename, char *buff,
bool fc_path_contains(const string_t *path, const string_t *needle,
int *result);
/** itoa output as decimal number
* parameters:
* n: the integer number to convert
* buff: store the converted string, NOT null-terminated
* return: converted string length
*/
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
* parameters:
* microseconds: microseconds to sleep
* return: 0 for success, != 0 for fail
*/
static inline int fc_sleep_us(const int microseconds)
{
struct timespec ts;
ts.tv_sec = microseconds / (1000 * 1000);
ts.tv_nsec = (microseconds % (1000 * 1000)) * 1000;
if (nanosleep(&ts, NULL) == 0) {
return 0;
} else {
return errno != 0 ? errno : EINVAL;
}
}
/** sleep in milliseconds
* parameters:
@ -1105,6 +1725,45 @@ int fc_check_filename(const string_t *filename, const char *caption);
*/
bool is_digital_string(const char *str);
int fc_safe_write_file_init(SafeWriteFileInfo *fi,
const char *file_path, const char *redo_filename,
const char *tmp_filename);
static inline int fc_safe_write_file_open(SafeWriteFileInfo *fi)
{
const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
int result;
if ((fi->fd=open(fi->tmp_filename, flags, 0644)) < 0) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"open file %s fail, errno: %d, error info: %s",
__LINE__, fi->tmp_filename, result, STRERROR(result));
return result;
} else {
return 0;
}
}
static inline int fc_safe_write_file_close(SafeWriteFileInfo *fi)
{
int result;
close(fi->fd);
if (rename(fi->tmp_filename, fi->filename) != 0)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"rename file \"%s\" to \"%s\" fail, "
"errno: %d, error info: %s", __LINE__,
fi->tmp_filename, fi->filename,
result, STRERROR(result));
return result;
} else {
return 0;
}
}
static inline int fc_check_realloc_iovec_array(
iovec_array_t *array, const int target_size)
{
@ -1138,6 +1797,59 @@ static inline int fc_check_realloc_iovec_array(
return 0;
}
static inline void fc_free_iovec_array(iovec_array_t *array)
{
if (array->iovs != NULL) {
free(array->iovs);
array->iovs = NULL;
array->alloc = 0;
}
}
static inline pid_t fc_gettid()
{
#ifdef OS_LINUX
#ifdef SYS_gettid
return (pid_t)syscall(SYS_gettid);
#else
return getpid();
#endif
#else
return getpid();
#endif
}
static inline size_t fc_iov_get_bytes(const
struct iovec *iov, const int iovcnt)
{
const struct iovec *iob;
const struct iovec *end;
size_t bytes;
switch (iovcnt) {
case 0:
return 0;
case 1:
return iov[0].iov_len;
case 2:
return iov[0].iov_len + iov[1].iov_len;
case 3:
return iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
case 4:
return iov[0].iov_len + iov[1].iov_len +
iov[2].iov_len + iov[3].iov_len;
default:
bytes = 0;
end = iov + iovcnt;
for (iob=iov; iob<end; iob++) {
bytes += iob->iov_len;
}
return bytes;
}
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -18,16 +18,18 @@
#ifndef _SOCKETOPT_H_
#define _SOCKETOPT_H_
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "common_define.h"
#include "shared_func.h"
#define FC_NET_TYPE_NONE 0
#define FC_NET_TYPE_OUTER 1 //extranet IP
@ -54,14 +56,14 @@
typedef struct fast_if_config {
char name[IF_NAMESIZE]; //if name
char mac[32];
char mac[64];
char ipv4[IP_ADDRESS_SIZE];
char ipv6[48];
char ipv6[IP_ADDRESS_SIZE];
} FastIFConfig;
typedef struct ip_addr_s {
char ip_addr[INET6_ADDRSTRLEN];
int socket_domain;
char ip_addr[IP_ADDRESS_SIZE];
int af;
} ip_addr_t;
typedef struct sockaddr_convert_s {
@ -107,13 +109,13 @@ extern "C" {
extern bool g_tcp_quick_ack;
#endif
typedef int (*getnamefunc)(int socket, struct sockaddr *address, \
typedef int (*getnamefunc)(int socket, struct sockaddr *address,
socklen_t *address_len);
typedef int (*tcpsenddatafunc)(int sock, void* data, const int size, \
typedef int (*tcpsenddatafunc)(int sock, void *data, const int size,
const int timeout);
typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size, \
typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size,
const int timeout, int *count);
#define getSockIpaddr(sock, buff, bufferSize) \
@ -144,7 +146,7 @@ int tcpgets(int sock, char *s, const int size, const int timeout);
* data: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout
* count: store the bytes recveived
* count: store the bytes received
* return: error no, 0 success, != 0 fail
*/
int tcprecvdata_ex(int sock, void *data, const int size, \
@ -156,10 +158,10 @@ int tcprecvdata_ex(int sock, void *data, const int size, \
* data: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout in seconds
* count: store the bytes recveived
* count: store the bytes received
* return: error no, 0 success, != 0 fail
*/
int tcprecvdata_nb_ex(int sock, void *data, const int size, \
int tcprecvdata_nb_ex(int sock, void *data, const int size,
const int timeout, int *count);
/** recv data (non-block mode) in ms
@ -167,13 +169,45 @@ int tcprecvdata_nb_ex(int sock, void *data, const int size, \
* sock: the socket
* data: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout in milliseconds
* count: store the bytes recveived
* timeout_ms: read timeout in milliseconds
* count: store the bytes received
* return: error no, 0 success, != 0 fail
*/
int tcprecvdata_nb_ms(int sock, void *data, const int size, \
int tcprecvdata_nb_ms(int sock, void *data, const int size,
const int timeout_ms, int *count);
/** recv data by readv (non-block mode) in ms
* parameters:
* sock: the socket
* size: the expect size
* iov: the iov to send
* iovcnt: the iov count
* timeout_ms: read timeout in milliseconds
* total_bytes: store the bytes received
* return: error no, 0 success, != 0 fail
*/
int tcpreadv_nb_ms(int sock, const int size, const struct iovec *iov,
const int iovcnt, const int timeout_ms, int *total_bytes);
/** recv data by readv (non-block mode)
* parameters:
* sock: the socket
* size: the expect size
* iov: the iov to send
* iovcnt: the iov count
* timeout: read timeout in seconds
* total_bytes: store the bytes received
* return: error no, 0 success, != 0 fail
*/
static inline int tcpreadv_nb_ex(int sock, const int size,
const struct iovec *iov, const int iovcnt,
const int timeout, int *total_bytes)
{
return tcpreadv_nb_ms(sock, size, iov, iovcnt,
timeout * 1000, total_bytes);
}
/** send data (block mode)
* parameters:
* sock: the socket
@ -182,7 +216,7 @@ int tcprecvdata_nb_ms(int sock, void *data, const int size, \
* timeout: write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsenddata(int sock, void* data, const int size, const int timeout);
int tcpsenddata(int sock, void *data, const int size, const int timeout);
/** send data (non-block mode)
* parameters:
@ -192,7 +226,18 @@ int tcpsenddata(int sock, void* data, const int size, const int timeout);
* timeout: write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsenddata_nb(int sock, void* data, const int size, const int timeout);
int tcpsenddata_nb(int sock, void *data, const int size, const int timeout);
/** send data by writev (non-block mode)
* parameters:
* sock: the socket
* iov: the iov to send
* iovcnt: the iov count
* timeout: write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpwritev_nb(int sock, const struct iovec *iov,
const int iovcnt, const int timeout);
/** connect to server by block mode
* parameters:
@ -302,9 +347,9 @@ int tcpprintkeepalive(int fd);
* sock: the socket
* buff: buffer to store the ip address
* 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);
/** get ip address
@ -328,14 +373,23 @@ int getIpAndPort(getnamefunc getname, int sock,
*/
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:
* name: the hostname
* buff: buffer to store the ip address
* 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
* parameters:
@ -544,6 +598,9 @@ static inline int socketClientIPv6(const char *server_ip,
#define tcprecvdata_nb(sock, data, size, timeout) \
tcprecvdata_nb_ex(sock, data, size, timeout, NULL)
#define tcpreadv_nb(sock, size, iov, iovcnt, timeout) \
tcpreadv_nb_ex(sock, size, iov, iovcnt, timeout, NULL)
/** send a file
* parameters:
* sock: the socket
@ -641,13 +698,64 @@ int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count);
* convert: the convert struct for IPv4 and IPv6 compatibility
* 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)
{
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);
static inline void tcp_dont_try_again_when_interrupt()
@ -657,10 +765,15 @@ static inline void tcp_dont_try_again_when_interrupt()
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_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)
{
switch (err_no)

178
src/sorted_array.c Normal file
View File

@ -0,0 +1,178 @@
/*
* 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 GNU Affero General Public License, version 3
* or later ("AGPL"), 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 GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "sorted_array.h"
void sorted_array_init(SortedArrayContext *ctx,
const int element_size, const bool allow_duplication,
int (*compare_func)(const void *, const void *))
{
ctx->element_size = element_size;
ctx->allow_duplication = allow_duplication;
ctx->compare_func = compare_func;
}
static char *sorted_array_bsearch(SortedArrayContext *ctx, char *base,
const int count, const void *elt, int *insert_pos)
{
int low;
int high;
int mid;
int compr;
char *current;
*insert_pos = 0;
low = 0;
high = count - 1;
while (low <= high) {
mid = (low + high) / 2;
current = base + ctx->element_size * mid;
compr = ctx->compare_func(current, elt);
if (compr < 0) {
low = mid + 1;
*insert_pos = low;
} else if (compr == 0) {
*insert_pos = mid;
return current;
} else {
high = mid - 1;
*insert_pos = mid;
}
}
return NULL;
}
int sorted_array_insert(SortedArrayContext *ctx,
void *base, int *count, const void *elt)
{
char *current;
if (*count == 0 || ctx->compare_func((char *)base +
ctx->element_size * (*count - 1), elt) < 0)
{ //fast path
current = (char *)base + ctx->element_size * (*count);
} else {
int insert_pos;
int move_count;
char *found;
char *end;
found = sorted_array_bsearch(ctx, base, *count, elt, &insert_pos);
if (found != NULL) {
if (!ctx->allow_duplication) {
return EEXIST;
}
found += ctx->element_size;
end = (char *)base + ctx->element_size * (*count);
while (found < end && ctx->compare_func(found, elt) == 0) {
insert_pos++;
found += ctx->element_size;
}
}
current = (char *)base + ctx->element_size * insert_pos;
move_count = *count - insert_pos;
if (move_count > 0) {
memmove((char *)base + ctx->element_size * (insert_pos + 1),
current, ctx->element_size * move_count);
}
}
switch (ctx->element_size) {
case 1:
*current = *((char *)elt);
break;
case 2:
*((short *)current) = *((short *)elt);
break;
case 4:
*((int32_t *)current) = *((int32_t *)elt);
break;
case 8:
*((int64_t *)current) = *((int64_t *)elt);
break;
default:
memcpy(current, elt, ctx->element_size);
break;
}
(*count)++;
return 0;
}
void sorted_array_delete_by_index(SortedArrayContext *ctx,
void *base, int *count, const int index)
{
int move_count;
char *start;
start = (char *)base + ctx->element_size * index;
move_count = *count - (index + 1);
if (move_count > 0) {
memmove(start, start + ctx->element_size,
ctx->element_size * move_count);
}
(*count)--;
}
int sorted_array_delete(SortedArrayContext *ctx,
void *base, int *count, const void *elt)
{
int move_count;
struct {
char *current;
char *start;
char *end;
} found;
char *array_end;
if ((found.current=bsearch(elt, base, *count, ctx->element_size,
ctx->compare_func)) == NULL)
{
return ENOENT;
}
array_end = (char *)base + ctx->element_size * (*count);
if (ctx->allow_duplication) {
found.start = found.current;
while (found.start > (char *)base && ctx->compare_func(
found.start - ctx->element_size, elt) == 0)
{
found.start -= ctx->element_size;
}
found.end = found.current + ctx->element_size;
while (found.end < array_end && ctx->compare_func(
found.end, elt) == 0)
{
found.end += ctx->element_size;
}
*count -= (found.end - found.start) / ctx->element_size;
} else {
found.start = found.current;
found.end = found.start + ctx->element_size;
(*count)--;
}
move_count = (array_end - found.end) / ctx->element_size;
if (move_count > 0) {
memmove(found.start, found.end, ctx->
element_size * move_count);
}
return 0;
}

112
src/sorted_array.h Normal file
View File

@ -0,0 +1,112 @@
/*
* 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 GNU Affero General Public License, version 3
* or later ("AGPL"), 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 GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef SORTED_ARRAY_H
#define SORTED_ARRAY_H
#include "array_allocator.h"
typedef struct sorted_array_context
{
int element_size;
bool allow_duplication;
int (*compare_func)(const void *, const void *);
} SortedArrayContext;
#ifdef __cplusplus
extern "C" {
#endif
/** init the context for sorted array
* parameters:
* ctx: the context to init
* element_size: the size of one array element
* allow_duplication: if allow duplication
* compare_func: the compare function (comparator)
* return: none
*/
void sorted_array_init(SortedArrayContext *ctx,
const int element_size, const bool allow_duplication,
int (*compare_func)(const void *, const void *));
/** insert an element into the sorted array
* parameters:
* ctx: the context for sorted array
* base: the pointer of the sorted array (the first array element)
* count: the count of the sorted array (for input and output)
* elt: the element to insert
* return: 0 for success, != 0 for error
*/
int sorted_array_insert(SortedArrayContext *ctx,
void *base, int *count, const void *elt);
/** delete an element from the sorted array
* parameters:
* ctx: the context for sorted array
* base: the pointer of the sorted array (the first array element)
* count: the count of the sorted array (for input and output)
* elt: the element to delete
* return: 0 for success, != 0 for error
*/
int sorted_array_delete(SortedArrayContext *ctx,
void *base, int *count, const void *elt);
/** delete an element by index
* parameters:
* ctx: the context for sorted array
* base: the pointer of the sorted array (the first array element)
* count: the count of the sorted array (for input and output)
* index: the element index to delete
* return: 0 for success, != 0 for error
*/
void sorted_array_delete_by_index(SortedArrayContext *ctx,
void *base, int *count, const int index);
/** find element from the sorted array
* parameters:
* ctx: the context for sorted array
* base: the pointer of the sorted array (the first array element)
* count: the count of the sorted array
* key: the element to find
* return: 0 for success, != 0 for error
*/
static inline void *sorted_array_find(SortedArrayContext *ctx,
void *base, const int count, const void *key)
{
return bsearch(key, base, count, ctx->
element_size, ctx->compare_func);
}
#define sorted_i64_array_init(ctx, allow_duplication) \
sorted_array_init(ctx, sizeof(int64_t), allow_duplication, \
(int (*)(const void *, const void *))array_compare_element_int64)
#define sorted_i32_array_init(ctx, allow_duplication) \
sorted_array_init(ctx, sizeof(int32_t), allow_duplication, \
(int (*)(const void *, const void *))array_compare_element_int32)
#define sorted_id_name_array_init(ctx, allow_duplication) \
sorted_array_init(ctx, sizeof(id_name_pair_t), allow_duplication, \
(int (*)(const void *, const void *)) \
array_compare_element_id_name)
#ifdef __cplusplus
}
#endif
#endif

194
src/sorted_queue.c Normal file
View File

@ -0,0 +1,194 @@
/*
* 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/>.
*/
//sorted_queue.c
#include "pthread_func.h"
#include "sorted_queue.h"
int sorted_queue_init(struct sorted_queue *sq, const int dlink_offset,
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)
{
int result;
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)
{
destroy_pthread_lock_cond_pair(&sq->lcp);
}
void sorted_queue_push_ex(struct sorted_queue *sq, void *data, bool *notify)
{
struct fc_list_head *dlink;
struct fc_list_head *current;
dlink = FC_SORTED_QUEUE_DLINK_PTR(sq, data);
PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
if (fc_list_empty(&sq->head)) {
fc_list_add(dlink, &sq->head);
*notify = true;
} else {
if (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
sq, sq->head.prev)) >= 0)
{
fc_list_add_tail(dlink, &sq->head);
*notify = false;
} else if (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
sq, sq->head.next)) < 0)
{
fc_list_add(dlink, &sq->head);
*notify = true;
} else {
current = sq->head.prev->prev;
while (sq->push_compare_func(data, FC_SORTED_QUEUE_DATA_PTR(
sq, current)) < 0)
{
current = current->prev;
}
fc_list_add_after(dlink, current);
*notify = false;
}
}
PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
}
void *sorted_queue_pop_ex(struct sorted_queue *sq,
void *less_equal, const bool blocked)
{
void *data;
struct fc_list_head *current;
PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
do {
if (fc_list_empty(&sq->head)) {
if (!blocked) {
data = NULL;
break;
}
pthread_cond_wait(&sq->lcp.cond,
&sq->lcp.lock);
if (fc_list_empty(&sq->head)) {
data = NULL;
break;
}
}
current = sq->head.next;
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_chain_ex(struct sorted_queue *sq,
void *less_equal, struct fc_list_head *head,
const bool blocked)
{
struct fc_list_head *current;
PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
do {
if (fc_list_empty(&sq->head)) {
if (!blocked) {
FC_INIT_LIST_HEAD(head);
break;
}
pthread_cond_wait(&sq->lcp.cond,
&sq->lcp.lock);
}
if (fc_list_empty(&sq->head)) {
FC_INIT_LIST_HEAD(head);
} else {
current = sq->head.next;
if (sq->pop_compare_func(FC_SORTED_QUEUE_DATA_PTR(
sq, current), less_equal, sq->arg) <= 0)
{
head->next = current;
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)
{
current = current->next;
}
head->prev = current->prev;
current->prev->next = head;
if (current == &sq->head) {
FC_INIT_LIST_HEAD(&sq->head);
} else {
sq->head.next = current;
current->prev = &sq->head;
}
} else {
FC_INIT_LIST_HEAD(head);
}
}
} while (0);
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);
}

128
src/sorted_queue.h Normal file
View File

@ -0,0 +1,128 @@
/*
* 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/>.
*/
//sorted_queue.h
#ifndef _FC_SORTED_QUEUE_H
#define _FC_SORTED_QUEUE_H
#include "fast_mblock.h"
#include "fc_list.h"
#include "pthread_func.h"
struct sorted_queue
{
struct fc_list_head head;
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
extern "C" {
#endif
int sorted_queue_init(struct sorted_queue *sq, const int dlink_offset,
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);
static inline void sorted_queue_terminate(struct sorted_queue *sq)
{
pthread_cond_signal(&sq->lcp.cond);
}
static inline void sorted_queue_terminate_all(
struct sorted_queue *sq, const int count)
{
int i;
for (i=0; i<count; i++) {
pthread_cond_signal(&(sq->lcp.cond));
}
}
//notify by the caller
void sorted_queue_push_ex(struct sorted_queue *sq, void *data, bool *notify);
static inline void sorted_queue_push(struct sorted_queue *sq, void *data)
{
bool notify;
sorted_queue_push_ex(sq, data, &notify);
if (notify) {
pthread_cond_signal(&(sq->lcp.cond));
}
}
static inline void sorted_queue_push_silence(
struct sorted_queue *sq, void *data)
{
bool notify;
sorted_queue_push_ex(sq, data, &notify);
}
void *sorted_queue_pop_ex(struct sorted_queue *sq,
void *less_equal, const bool blocked);
#define sorted_queue_pop(sq, less_equal) \
sorted_queue_pop_ex(sq, less_equal, true)
#define sorted_queue_try_pop(sq, less_equal) \
sorted_queue_pop_ex(sq, less_equal, false)
void sorted_queue_pop_to_chain_ex(struct sorted_queue *sq,
void *less_equal, struct fc_list_head *head,
const bool blocked);
#define sorted_queue_pop_to_chain(sq, less_equal, head) \
sorted_queue_pop_to_chain_ex(sq, less_equal, head, true)
#define sorted_queue_try_pop_to_chain(sq, less_equal, head) \
sorted_queue_pop_to_chain_ex(sq, less_equal, head, false)
static inline bool sorted_queue_empty(struct sorted_queue *sq)
{
return fc_list_empty(&sq->head);
}
int sorted_queue_free_chain(struct sorted_queue *sq,
struct fast_mblock_man *mblock, struct fc_list_head *head);
static inline void sorted_queue_lock(struct sorted_queue *sq)
{
PTHREAD_MUTEX_LOCK(&sq->lcp.lock);
}
static inline void sorted_queue_unlock(struct sorted_queue *sq)
{
PTHREAD_MUTEX_UNLOCK(&sq->lcp.lock);
}
#ifdef __cplusplus
}
#endif
#endif

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;
mib[0] = CTL_HW;
#ifdef DARWIN
mib[1] = HW_MEMSIZE;
#else
mib[1] = HW_PHYSMEM;
#endif
len = sizeof(*mem_size);
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) \
do { \
snprintf(left.f_fstypename, sizeof(left.f_fstypename), "%s", fstypename); \
snprintf(left.f_mntfromname, sizeof(left.f_mntfromname), "%s", mntfromname); \
snprintf(left.f_mntonname, sizeof(left.f_mntonname), "%s", mntonname); \
fc_safe_strcpy(left.f_fstypename, fstypename); \
fc_safe_strcpy(left.f_mntfromname, mntfromname); \
fc_safe_strcpy(left.f_mntonname, mntonname); \
} 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,
const int size, int *count)
{
@ -236,15 +283,14 @@ int get_mounted_filesystems(struct fast_statfs *stats,
mntfromname = strsep(&p, " \t");
mntonname = strsep(&p, " \t");
fstypename = strsep(&p, " \t");
snprintf(stats[*count].f_mntfromname,
sizeof(stats[*count].f_mntfromname), "%s", mntfromname);
snprintf(stats[*count].f_mntonname,
sizeof(stats[*count].f_mntonname), "%s", mntonname);
snprintf(stats[*count].f_fstypename,
sizeof(stats[*count].f_fstypename), "%s", fstypename);
(*count)++;
toLowercase(fstypename);
if (get_device_type(fstypename, &stats[*count].device_type) == 0)
{
fc_safe_strcpy(stats[*count].f_mntfromname, mntfromname);
fc_safe_strcpy(stats[*count].f_mntonname, mntonname);
fc_safe_strcpy(stats[*count].f_fstypename, fstypename);
(*count)++;
}
}
fclose(fp);
@ -275,7 +321,7 @@ int get_mounted_filesystems(struct fast_statfs *stats,
int i;
mnts = NULL;
*count = getmntinfo(&mnts, 0);
*count = getmntinfo(&mnts, MNT_NOWAIT);
if (*count == 0)
{
result = errno != 0 ? errno : EPERM;
@ -302,6 +348,7 @@ int get_mounted_filesystems(struct fast_statfs *stats,
#ifdef HAVE_FILE_SYSTEM_ID
stats[i].f_fsid = mnts[i].f_fsid;
#endif
stats[i].device_type = fast_device_type_unkown;
SET_MNT_FIELDS(stats[i], mnts[i].f_fstypename,
mnts[i].f_mntfromname, mnts[i].f_mntonname);
}
@ -314,6 +361,114 @@ int get_mounted_filesystems(struct fast_statfs *stats,
#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)
typedef struct fast_process_array {
@ -613,7 +768,7 @@ int get_processes(struct fast_process_info **processes, int *count)
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ALL;
mib[3] = 0;
mib[3] = 0;
size = 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++)
{
process->field_count = 9;
snprintf(process->comm, sizeof(process->comm),
"%s", procs[i].ki_comm);
fc_safe_strcpy(process->comm, procs[i].ki_comm);
process->pid = procs[i].ki_pid;
process->ppid = procs[i].ki_ppid;
process->starttime = procs[i].ki_start;
@ -776,7 +930,6 @@ int get_sysinfo(struct fast_sysinfo *info)
page_size = sysconf(_SC_PAGESIZE);
info->freeram = vm.t_free * page_size;
info->sharedram = vm.t_rmshr * page_size;
//info->bufferram = vm. //TODO:
}
#endif
@ -844,7 +997,7 @@ int get_device_block_size(const char *device, int *block_size)
int fd;
size_t bs;
if ((fd=open(device, O_RDONLY)) < 0) {
if ((fd=open(device, O_RDONLY | O_CLOEXEC)) < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open device %s fail, errno: %d, error info: %s",
@ -884,9 +1037,10 @@ static int get_block_size_by_write(const char *path, int *block_size)
return result;
}
snprintf(tmp_filename, sizeof(tmp_filename),
"%s/.blksize-test.tmp", path);
if ((fd=open(tmp_filename, O_WRONLY | O_CREAT | O_DIRECT, 0755)) < 0) {
fc_combine_full_filename(path, ".blksize-test.tmp", tmp_filename);
if ((fd=open(tmp_filename, O_WRONLY | O_CREAT |
O_DIRECT | O_CLOEXEC, 0755)) < 0)
{
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open file %s fail, errno: %d, error info: %s",
@ -956,4 +1110,94 @@ int get_path_block_size(const char *path, int *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

View File

@ -42,6 +42,14 @@ extern "C" {
#define MNAMELEN 128
#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 {
long f_type; /* type of file system (see below) */
long f_bsize; /* optimal transfer block size */
@ -56,6 +64,7 @@ extern "C" {
char f_fstypename[MFSNAMELEN]; /* fs type name */
char f_mntfromname[MNAMELEN]; /* mounted file system */
char f_mntonname[MNAMELEN]; /* directory on which mounted */
FastDeviceType device_type;
} FastStatFS;
#if defined(OS_LINUX) || defined(OS_FREEBSD)
@ -120,24 +129,41 @@ extern "C" {
} FastProcessInfo;
#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
* parameters:
* mem_size: return the total memory size
* return: error no , 0 success, != 0 fail
* return: error no, 0 success, != 0 fail
*/
int get_sys_total_mem_size(int64_t *mem_size);
/** get system CPU count
* parameters:
* return: error no , 0 success, != 0 fail
* return: error no, 0 success, != 0 fail
*/
int get_sys_cpu_count();
/** get system boot time
* parameters:
* uptime: store the up time
* return: error no , 0 success, != 0 fail
* return: error no, 0 success, != 0 fail
*/
int get_boot_time(struct timeval *boot_time);
@ -146,17 +172,32 @@ int get_boot_time(struct timeval *boot_time);
* stats: the stat array
* size: max size of the array
* count: return the count of the array
* return: error no , 0 success, != 0 fail
* return: error no, 0 success, != 0 fail
*/
int get_mounted_filesystems(struct fast_statfs *stats,
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)
/** get processes
* parameters:
* processes: return the processes
* count: return the count of the processes
* return: error no , 0 success, != 0 fail
* return: error no, 0 success, != 0 fail
*/
int get_processes(struct fast_process_info **processes, int *count);
@ -164,6 +205,8 @@ int get_sysinfo(struct fast_sysinfo *info);
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
int get_device_block_size(const char *device, int *block_size);
int get_path_block_size(const char *path, int *block_size);

View File

@ -1,8 +1,8 @@
.SUFFIXES: .c .o
COMPILE = $(CC) -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -g -DDEBUG_FLAG
INC_PATH = -I/usr/local/include
LIB_PATH = -lfastcommon -lpthread
COMPILE = $(CC) -g -O3 -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -DDEBUG_FLAG
INC_PATH = $(INCS)
LIB_PATH = -lfastcommon $(LIBS)
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 \
@ -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_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_queue_perf test_normalize_path
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)
.c:
$(COMPILE) -o $@ $< $(LIB_PATH) $(INC_PATH)
.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 int64_t produce_count = 0;
static int64_t consume_count = 0;
static struct fast_task_queue free_queue;
static struct fast_blocked_queue blocked_queue;
#define MAX_USLEEP 10000
@ -51,7 +52,7 @@ void *producer_thread(void *arg)
printf("produce count: %"PRId64"\n", count);
}
pTask = free_queue_pop();
pTask = free_queue_pop(&free_queue);
if (pTask != NULL) {
blocked_queue_push(&blocked_queue, pTask);
}
@ -99,7 +100,7 @@ int main(int argc, char *argv[])
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);
if (result != 0) {
return result;

Some files were not shown because too many files have changed in this diff Show More