Compare commits
312 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
795b328bd6 | |
|
|
ac5f4a584f | |
|
|
c044906e63 | |
|
|
ccc84945d3 | |
|
|
c4b6f1fcb5 | |
|
|
017ca1efe7 | |
|
|
71b2229427 | |
|
|
446fa6b815 | |
|
|
98948c11bf | |
|
|
d60b141a21 | |
|
|
86bab518c6 | |
|
|
4b9ef52da2 | |
|
|
e8a9967801 | |
|
|
96c896b09a | |
|
|
8d9feff6e2 | |
|
|
cbcd38a9af | |
|
|
cd55792a89 | |
|
|
511b1066c4 | |
|
|
ddf6b5dfe9 | |
|
|
23cd03bc76 | |
|
|
065184a203 | |
|
|
de80dc19dc | |
|
|
dac653d694 | |
|
|
d5dbe3d030 | |
|
|
7973d81b69 | |
|
|
4576f22e24 | |
|
|
cb6f6f13f3 | |
|
|
012b2038ee | |
|
|
48a0ea2e30 | |
|
|
aa48e3cd9a | |
|
|
47fa7f99df | |
|
|
ec8e47f831 | |
|
|
d9d6255621 | |
|
|
2f75958a4a | |
|
|
a4cae13e07 | |
|
|
f136821c0d | |
|
|
b97f23ced2 | |
|
|
84a1f90a9a | |
|
|
3f19715e45 | |
|
|
ce4c5e23d4 | |
|
|
d59da03d60 | |
|
|
8e51f4de3e | |
|
|
0afae48142 | |
|
|
158924f259 | |
|
|
bf7c6e5144 | |
|
|
6f4b3b7cd8 | |
|
|
b1f3c7894e | |
|
|
ec2db7cd33 | |
|
|
63ef9aa8f4 | |
|
|
1d2f938a30 | |
|
|
e4898affdd | |
|
|
558670bc63 | |
|
|
cf16c41054 | |
|
|
7fbb5c620b | |
|
|
9acc202481 | |
|
|
dd0d4dbc19 | |
|
|
a1ae1cbcb0 | |
|
|
fda2679435 | |
|
|
f0484579e0 | |
|
|
6a18162a12 | |
|
|
8e834f7165 | |
|
|
a256976600 | |
|
|
62a29b55a5 | |
|
|
a6dc24e2f3 | |
|
|
70f6ad56ed | |
|
|
7f1a85b025 | |
|
|
eafb8aae74 | |
|
|
de1e9e7ec4 | |
|
|
aa144b5981 | |
|
|
a0654b83c0 | |
|
|
19dcd0c5c4 | |
|
|
d764571f6e | |
|
|
13fc696432 | |
|
|
e4a9fccddb | |
|
|
5477593ce8 | |
|
|
ce0c23358f | |
|
|
f4020e7622 | |
|
|
ed65725833 | |
|
|
13e213e3f8 | |
|
|
83f757672b | |
|
|
21366a4a2e | |
|
|
aad48cc03d | |
|
|
7a108ec5a2 | |
|
|
98e3471433 | |
|
|
8a97e84e1c | |
|
|
8ce0119aa2 | |
|
|
1b777792ab | |
|
|
2ab381d5e3 | |
|
|
a0f1ac59c8 | |
|
|
13b31434e0 | |
|
|
8aceec92ee | |
|
|
fef0a4a7f3 | |
|
|
7f699688c0 | |
|
|
e0f47116c5 | |
|
|
6cd9d6d842 | |
|
|
f4fef93061 | |
|
|
226fd0d378 | |
|
|
9a720533ce | |
|
|
55ff532f92 | |
|
|
d18ad54c2b | |
|
|
2205cae6f3 | |
|
|
5bceed4e32 | |
|
|
e0e7b9ef35 | |
|
|
05f3d62ee1 | |
|
|
01f35da9d2 | |
|
|
02f4659a32 | |
|
|
7816a28c53 | |
|
|
3f5eed3af2 | |
|
|
c9083ae0cf | |
|
|
5283a55bda | |
|
|
78caf9224b | |
|
|
dd77da144f | |
|
|
700a5bcaec | |
|
|
4eb30adb1a | |
|
|
06f0ce67fd | |
|
|
7018f4e337 | |
|
|
d68c9aff32 | |
|
|
89e70977d5 | |
|
|
5bda2dfef6 | |
|
|
8b545fcfc0 | |
|
|
6843acb456 | |
|
|
894477753c | |
|
|
6a5d4b1402 | |
|
|
1c1ea296e7 | |
|
|
961ea11c4f | |
|
|
718906e477 | |
|
|
eafe769759 | |
|
|
a1914ea249 | |
|
|
61e07a4c0f | |
|
|
6151ea721b | |
|
|
255defa788 | |
|
|
acaf94db0c | |
|
|
2e176a9d1b | |
|
|
e0b93756ab | |
|
|
7b0631e37a | |
|
|
e0bbe89d23 | |
|
|
1c1cb6d5e7 | |
|
|
70c44ea490 | |
|
|
b4e5a26ba0 | |
|
|
f49c5d134a | |
|
|
db49d54a37 | |
|
|
c9687df03a | |
|
|
d24023aee7 | |
|
|
5139ec4682 | |
|
|
bc3a65ee19 | |
|
|
44f827f291 | |
|
|
4a86162913 | |
|
|
d5f6a192a5 | |
|
|
05a694df77 | |
|
|
45e958cc1c | |
|
|
d9c14d602a | |
|
|
4480669e03 | |
|
|
fafbbb557e | |
|
|
1969fbba8d | |
|
|
896b35603f | |
|
|
15facf395b | |
|
|
3924213c9a | |
|
|
643ecdc906 | |
|
|
7726d0223f | |
|
|
4df1107fa3 | |
|
|
0c588d965e | |
|
|
8de24ad5b5 | |
|
|
8cea8632d7 | |
|
|
ccbc201636 | |
|
|
e02bb4edc3 | |
|
|
085e06aac1 | |
|
|
0806435fcc | |
|
|
c00a159fd3 | |
|
|
5247caa71a | |
|
|
2c5734ab22 | |
|
|
a19119f962 | |
|
|
428d13a07b | |
|
|
6dbc8b8937 | |
|
|
f1691b7480 | |
|
|
595a8c5664 | |
|
|
8b298570b3 | |
|
|
d81b75e4da | |
|
|
ee3631d426 | |
|
|
6d3d082c6d | |
|
|
c5138cc7cf | |
|
|
73ab695fc8 | |
|
|
be9c7c394a | |
|
|
0113263e87 | |
|
|
fd8fbfe644 | |
|
|
8ab3420bce | |
|
|
aa2fc62cbb | |
|
|
ee70efcd09 | |
|
|
86288bf99e | |
|
|
c0ea8349d3 | |
|
|
8ea9848047 | |
|
|
d07058934b | |
|
|
8e4adccb83 | |
|
|
1eb603cfd1 | |
|
|
22c7e31752 | |
|
|
c18e864220 | |
|
|
7289215470 | |
|
|
b52e516aee | |
|
|
9c967d8d4b | |
|
|
2b0796b166 | |
|
|
6ea757f492 | |
|
|
cf66174cf9 | |
|
|
117b723274 | |
|
|
5e8dc1fcb5 | |
|
|
c416c6eeb0 | |
|
|
88ad619902 | |
|
|
47fb7b2abd | |
|
|
6b70919699 | |
|
|
a9b0f20f2d | |
|
|
48ec9c64c6 | |
|
|
b0d57b325d | |
|
|
82bbc013b2 | |
|
|
7e52e7607a | |
|
|
f47f136f56 | |
|
|
e11b22ad7d | |
|
|
ed66409220 | |
|
|
51715f26aa | |
|
|
68360c1bd1 | |
|
|
138e06fd6c | |
|
|
a9e82600b7 | |
|
|
599d0f1446 | |
|
|
4a7d852409 | |
|
|
e254b8e1d3 | |
|
|
fe862d887e | |
|
|
aa5506191f | |
|
|
5a90576bdc | |
|
|
7e5acf144b | |
|
|
0b539bbba2 | |
|
|
009d33480f | |
|
|
5f34bc872b | |
|
|
793d683d2a | |
|
|
64e9499de6 | |
|
|
275279a264 | |
|
|
f24c558761 | |
|
|
1f83e66306 | |
|
|
630a6a2af6 | |
|
|
23628e85f2 | |
|
|
082902d28b | |
|
|
5802203f9f | |
|
|
f836b1a9e2 | |
|
|
26abf68ebd | |
|
|
ba011767f8 | |
|
|
7d5e94f9dd | |
|
|
80b751980b | |
|
|
776a875c84 | |
|
|
3fd3b167a8 | |
|
|
08f74db732 | |
|
|
6836337d0a | |
|
|
1cb1847b29 | |
|
|
c9cba5298a | |
|
|
7b9c257652 | |
|
|
9f1d1b6d48 | |
|
|
3331b927b3 | |
|
|
e9d186ce99 | |
|
|
29cc5af134 | |
|
|
21cd3a9798 | |
|
|
3f20211a52 | |
|
|
a19a0071db | |
|
|
787eb3a7d6 | |
|
|
4b9e2d6517 | |
|
|
505893dc4c | |
|
|
34f8c3abb9 | |
|
|
a39005253b | |
|
|
013b7888ea | |
|
|
f734710832 | |
|
|
0410c7fedd | |
|
|
0381982ac2 | |
|
|
af68bf5d6a | |
|
|
7fbdb0cece | |
|
|
c3f22aa867 | |
|
|
89e1a99129 | |
|
|
59acf16fae | |
|
|
7fe16fd1b5 | |
|
|
d9097001b5 | |
|
|
d5d317f912 | |
|
|
b4f6152776 | |
|
|
750c2c5e8a | |
|
|
fdb6bfb233 | |
|
|
f6c5256264 | |
|
|
0c437d3799 | |
|
|
64ae0757d7 | |
|
|
720c4a686d | |
|
|
87377981ec | |
|
|
740272e303 | |
|
|
4f29fd71eb | |
|
|
976872192a | |
|
|
b03963d4f6 | |
|
|
ce2ee0f482 | |
|
|
9ca9592326 | |
|
|
09e00bcf5e | |
|
|
a439b8e62d | |
|
|
8acd5e031b | |
|
|
2432e0bc79 | |
|
|
1b35cbc094 | |
|
|
8491c5d155 | |
|
|
8717f85608 | |
|
|
55f1e139a9 | |
|
|
2993b34e80 | |
|
|
81950ac246 | |
|
|
7614f789c8 | |
|
|
f5fa33611f | |
|
|
6957c19992 | |
|
|
a66370d0f8 | |
|
|
e1ef38d6a4 | |
|
|
45da326ce2 | |
|
|
ebe7d87ca4 | |
|
|
c6b2c32fe2 | |
|
|
b7ecd0d4c4 | |
|
|
2fafa215fd | |
|
|
44dcf4f821 | |
|
|
47c4eaeb13 | |
|
|
082a0fbc06 | |
|
|
3e0f1eb1fc |
|
|
@ -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
157
HISTORY
|
|
@ -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
14
INSTALL
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
11
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
usr/include/fastcommon/*
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
README.Debian
|
||||
README.source
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# Regular cron jobs for the libfastcommon package
|
||||
#
|
||||
0 4 * * * root [ -x /usr/bin/libfastcommon_maintenance ] && /usr/bin/libfastcommon_maintenance
|
||||
|
|
@ -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
|
||||
|
|
@ -1 +1 @@
|
|||
src/libfastcommon.so usr/lib64/
|
||||
usr/lib/libfastcommon.so*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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:
|
||||
-->
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version=3
|
||||
opts="mode=git" https://github.com/happyfish100/libfastcommon.git \
|
||||
refs/tags/v([\d\.]+) debian uupdate
|
||||
|
|
@ -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
|
||||
|
|
@ -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
144
make.sh
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, "
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
11
src/base64.c
11
src/base64.c
|
|
@ -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, \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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, ¬ify);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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, "
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
218
src/fc_queue.c
218
src/fc_queue.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, ¬ify);
|
||||
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, ¬ify);
|
||||
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, ¬ify);
|
||||
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, ¬ify);
|
||||
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
|
||||
|
|
|
|||
77
src/hash.c
77
src/hash.c
|
|
@ -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)
|
||||
|
|
|
|||
68
src/hash.h
68
src/hash.h
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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回环地址时,为了简化系统的改动,
|
||||
会将IPv6回环地址修改成IPv4回环地址返回
|
||||
此处错误打印时,需要带上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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
227
src/ioevent.c
227
src/ioevent.c
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
186
src/ioevent.h
186
src/ioevent.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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回环地址时,为了简化系统的改动,
|
||||
会将IPv6回环地址修改成IPv4回环地址返回
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
201
src/logger.c
201
src/logger.c
|
|
@ -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(¤t_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
|
||||
|
|
|
|||
32
src/logger.h
32
src/logger.h
|
|
@ -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:
|
||||
|
|
|
|||
27
src/md5.c
27
src/md5.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *)¤t_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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
1620
src/shared_func.c
1620
src/shared_func.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
|
|||
993
src/sockopt.c
993
src/sockopt.c
File diff suppressed because it is too large
Load Diff
159
src/sockopt.h
159
src/sockopt.h
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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, ¬ify);
|
||||
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, ¬ify);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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(¶ms, 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, ¶ms)) != 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue