Compare commits

..

No commits in common. "master" and "V1.0.35" have entirely different histories.

170 changed files with 5009 additions and 30526 deletions

98
.gitignore vendored
View File

@ -1,98 +0,0 @@
# Makefile.in
src/Makefile
src/tests/Makefile
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dSYM
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.out
src/_os_define.h
src/tests/test_allocator
src/tests/test_blocked_queue
src/tests/test_char_convert
src/tests/test_char_convert_loader
src/tests/test_crc32
src/tests/test_id_generator
src/tests/test_ini_parser
src/tests/test_json_parser
src/tests/test_logger
src/tests/test_mblock
src/tests/test_multi_skiplist
src/tests/test_sched_thread
src/tests/test_skiplist
src/tests/test_skiplist_set
src/tests/test_thourands_seperator
src/tests/test_pthread_lock
src/tests/test_split_string
src/tests/test_uniq_skiplist
src/tests/test_server_id_func
src/tests/test_pipe
src/tests/test_atomic
src/tests/test_file_write_hole
src/tests/test_file_lock
src/tests/test_thread_pool
src/tests/test_data_visible
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
*.swo
php-fastcommon/.deps
php-fastcommon/.libs/
php-fastcommon/Makefile
php-fastcommon/Makefile.fragments
php-fastcommon/Makefile.global
php-fastcommon/Makefile.objects
php-fastcommon/acinclude.m4
php-fastcommon/aclocal.m4
php-fastcommon/autom4te.cache/
php-fastcommon/build/
php-fastcommon/config.guess
php-fastcommon/config.h
php-fastcommon/config.h.in
php-fastcommon/config.log
php-fastcommon/config.nice
php-fastcommon/config.status
php-fastcommon/config.sub
php-fastcommon/configure
php-fastcommon/configure.ac
php-fastcommon/install-sh
php-fastcommon/libtool
php-fastcommon/ltmain.sh
php-fastcommon/missing
php-fastcommon/mkinstalldirs
php-fastcommon/run-tests.php

311
HISTORY
View File

@ -1,315 +1,4 @@
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
Version 1.52 2021-06-08
* process_stop more gracefully (kill -9 on timeout)
* add function fc_queue_pop_to_queue_ex
* add function get_path_block_size and get_device_block_size
* add function fc_check_realloc_iovec_array
Version 1.51 2021-05-27
* fast_mblock.[hc]: support batch alloc and batch free
* uniq_skiplist.[hc]: init function add parameter: allocator_use_lock
* add function normalize_path_ex and normalize_uri
* use libcurl to fetch URL resource
* add function get_kernel_version
Version 1.50 2021-05-11
* add function is_digital_string
* add function fc_server_load_from_ini_context
* set thread name as necessary
* add macro fc_fallocate
Version 1.49 2021-04-17
* add macros: FC_ABS and FC_NEGATIVE
* uniq_skiplist.c: add uniq_skiplist_pair struct and init function
* add functions: fc_mkdirs and str_replace
* add FilenameString type and macro
* add functions: fc_string_case_compare, fc_string_case_equal etc.
* add function: fc_check_filename_ex
* add functions: fc_queue_push_queue_to_tail etc.
* add file locked_list.h
* parse_bytes function more graceful
Version 1.48 2021-02-01
* fast_buffer.[hc]: add function fast_buffer_append_binary
* fc_check_mkdir_ex return 0 when mkdir with errno EEXIST
* add function common_blocked_queue_timedpop
* add function fc_queue_timedpop
Version 1.47 2021-01-20
* fc_atomic.h: add FC_ATOMIC_GET and FC_ATOMIC_SET etc.
* fast_mblock.[hc]: support wait with element limit
Version 1.46 2020-12-29
* add function get_time_item_from_conf_ex
* INI_FIND_ITEM just break instead of return
Version 1.45 2020-12-24
* add function uniq_skiplist_find_node_ex
* use readdir instead of readdir_r in Linux
Version 1.44 2020-12-06
* add test file src/tests/test_pthread_lock.c
* add uniq_skiplist.[hc]
* add function split_string_ex
* fast_mblock.[hc]: add init_args for init_func
* struct fast_task_info add field: nio_stage
* add function fc_memrchr
* add function is_network_error
* add function fast_mpool_log_stats
* add files: server_id_func.[hc]
* common_blocked_queue support pop all nodes
* shared_func.[hc]: add functions fc_floor_prime and fc_ceil_prime
* fast_mpool.[hc]: change function fast_mpool_strdup
* fast_allocator.[hc]: add function fast_allocator_strdup
* shared_func.[hc]: add function getFileSize
* char_converter.[hc]: add function fast_char_unescape
* struct fast_task_info add ctx pointer for libserverframe nio
* struct thread_data add waiting_queue for Linux eventfd notify
* struct fast_task_info add canceled field for complicated thread model
* nio_thread_data support thread notify
* pthread_func.[hc] add functions: create_work_threads_ex and fc_create_thread
* sched_add_entries use temp ScheduleArray for rare case
* add function common_blocked_queue_return_nodes
* add functions getIpAndPort and getPeerIpAndPort
* bugfixed: call fast_mblock_destroy in common_blocked_queue_destroy
* add function fc_get_file_line_count_ex
* uniq_skiplist add function find_ge and support bidirection
* connection_pool support validate connection on error
* fast_task_queue.[hc]: free_queue support init_callback
* ini_file_reader.c: use mutex lock when access dynamic content array
* uniq_skiplist add function uniq_skiplist_replace_ex
* add files: fc_queue.[hc]
* add files: fc_memory.[hc]
* add files: shared_buffer.[hc]
* add files: thread_pool.[hc]
* shared_func.[hc]: add function fc_path_contains
* fast_mblock.[hc]: support alloc elements limit
* sockopt.[hc]: add function asyncconnectserverbyip
* add locked_timer.[hc]: time wheel timer with lock
* tcp_quick_ack option for Linux
Version 1.43 2019-12-25
* replace function call system to getExecResult,
system is the deprecated function in iOS 11
* correct function skiplist_iterator in skiplist.h
* add buffered_file_writer.[hc]
* add function fc_delete_file_ex
Version 1.42 2019-12-03
* add function get_gzip_command_filename
* function create_work_threads changed
Version 1.41 2019-09-30
* change CIDR network_bits range from [16, 32) to [10, 32)
* ini_file_reader.c: fix empty string compare
* multi_socket_client.c: code refine
* sockopt.[hc] support IPv6
Version 1.40 2018-11-09
* add function conn_pool_parse_server_info and conn_pool_load_server_info
* support directive: #@add_annotation, for example:
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
* add function fc_split_string and fc_match_delim
* add json_parser.[hc] for parse json array and map
* add function fc_strdup
* add function fc_memmem
* add function format_http_date
* add function hash_find1 and hash_find2
* add function resolve_path and fast_buffer_append_file
* add function id_generator_next_extra_ptr, with NULL pointer to set
extra data to sn % (1 << extra_bits)
Version 1.39 2018-07-31
* add #@function REPLACE_VARS
* #@set value can embed %{VARIABLE}
* shared_func.h: add function starts_with and ends_with
* common_blocked_queue.h: add function common_blocked_queue_try_pop
* sched_thread.c: fix first schedule time
* ini_file_reader add function iniGetRequiredStrValueEx
* add file fc_list.h
* sockopt.c: add global variable try_again_when_interrupt
Version 1.38 2018-06-26
* connection_pool.c: set err_no to 0 when success
* shared_func.h: add functions float2buff / buff2float, double2buff / buff2double
* logger.h: add function log_get_level_caption
* add files: common_blocked_queue.[hc]
* add files: multi_socket_client.[hc]
* ioevent.[hc]: remove care_events in FreeBSD or MacOS
* add skiplist_set.[hc] and skiplist bug fixed
* correct CRC32
* shared_func.h: add functions int2str and long2str
* sched_thread.h: add function sched_print_all_entries
Version 1.37 2018-02-24
* ini_file_reader.c function annotations LOCAL_IP_GET support index, such as:
#@function LOCAL_IP_GET
bind_addr=private[0]
Version 1.36 2017-03-08
* correct getFileContentEx read bytes
Version 1.35 2017-03-02
* logger judge log_level in function log_it_ex and log_it_ex1
* add php extension function: fastcommon_file_put_contents

30
INSTALL
View File

@ -4,22 +4,20 @@ 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/
[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
Chinese language: http://www.csource.org/
# 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:
#step 1. download libfastcommon source package and unpack it,
tar xzf libfastcommon_v1.x.tar.gz
#for example:
tar xzf libfastcommon_v1.23.tar.gz
#step 2. enter the libfastcommon dir
cd libfastcommon
#step 3. make
./make.sh
#step 4. make install
./make.sh install
git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon; git checkout V1.0.83
./make.sh clean && ./make.sh && sudo ./make.sh install

165
LICENSE
View File

@ -1,165 +0,0 @@
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.

4
README
View File

@ -4,7 +4,7 @@ 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/
Chinese language: http://www.csource.org/
c common functions library extracted from my open source projects FastDFS and
@ -47,7 +47,7 @@ C function including:
skiplist: [skiplist.h] [flat_skiplist.h] [multi_skiplist.h] flat skiplist and multi skiplist
socket: [sockopt.h] socket wrapper for connect, recv, send etc. support IPv6
socket: [sockopt.h] socket wrapper for connect, recv, send etc.
ioevent: [ioevent.h] [ioevent_loop.h] like epoll (support Linux, FreeBSD and SunOS),

View File

@ -1,6 +0,0 @@
libfastcommon for Debian
-----------------------
<possible notes regarding this package - if none, delete this file>
-- zhangchunsheng <zhangchunsheng423@gmail.com> Mon, 24 May 2021 18:54:01 +0800

192
debian/changelog vendored
View File

@ -1,192 +0,0 @@
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:47:37 +0000
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:00:00 +0000
libfastcommon (1.0.83-1) unstable; urgency=medium
* upgrade to 1.0.83-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 09:05:57 +0000
libfastcommon (1.0.78-1) unstable; urgency=medium
* upgrade to 1.0.78-1
-- YuQing <384681@qq.com> Sat, 16 Aug 2025 16:31:05 +0000
libfastcommon (1.0.77-1) unstable; urgency=medium
* upgrade to 1.0.77-1
-- YuQing <384681@qq.com> Sun, 06 Apr 2025 16:55:50 +0000
libfastcommon (1.0.75-1) unstable; urgency=medium
* upgrade to 1.0.75-1
-- YuQing <384681@qq.com> Sun, 29 Sep 2024 15:23:57 +0000
libfastcommon (1.0.74-1) unstable; urgency=medium
* upgrade to 1.0.74-1
-- YuQing <384681@qq.com> Sat, 15 Jun 2024 14:45:01 +0000
libfastcommon (1.0.73-1) unstable; urgency=medium
* upgrade to 1.0.73-1
-- YuQing <384681@qq.com> Sun, 17 Mar 2024 15:10:21 +0000
libfastcommon (1.0.72-1) unstable; urgency=medium
* upgrade to 1.0.72-1
-- YuQing <384681@qq.com> Wed, 31 Jan 2024 11:59:25 +0000
libfastcommon (1.0.71-1) unstable; urgency=medium
* upgrade to 1.0.71-1
-- YuQing <384681@qq.com> Mon, 01 Jan 2024 11:23:54 +0000
libfastcommon (1.0.70-3) unstable; urgency=medium
* upgrade to 1.0.70-3
-- YuQing <384681@qq.com> Tue, 21 Nov 2023 14:35:29 +0000
libfastcommon (1.0.70-2) unstable; urgency=medium
* upgrade to 1.0.70-2
-- YuQing <384681@qq.com> Mon, 20 Nov 2023 13:23:17 +0000
libfastcommon (1.0.70-1) unstable; urgency=medium
* upgrade to 1.0.70-1
-- YuQing <384681@qq.com> Sun, 19 Nov 2023 14:45:34 +0000
libfastcommon (1.0.69-1) unstable; urgency=medium
* upgrade to 1.0.69-1
-- YuQing <384681@qq.com> Sun, 06 Aug 2023 07:21:50 +0000
libfastcommon (1.0.68-1) unstable; urgency=medium
* upgrade to 1.0.68-1
-- YuQing <384681@qq.com> Sun, 23 Jul 2023 14:27:27 +0000
libfastcommon (1.0.67-1) unstable; urgency=medium
* upgrade to 1.0.67-1
-- YuQing <384681@qq.com> Sun, 04 Jun 2023 10:51:06 +0000
libfastcommon (1.0.66-1) unstable; urgency=medium
* upgrade to 1.0.66-1
-- YuQing <384681@qq.com> Sat, 18 Feb 2023 05:43:58 +0000
libfastcommon (1.0.65-1) unstable; urgency=medium
* upgrade to 1.0.65-1
-- YuQing <384681@qq.com> Sun, 15 Jan 2023 13:49:19 +0000
libfastcommon (1.0.63-1) unstable; urgency=medium
* upgrade to 1.0.63-1
-- YuQing <384681@qq.com> Mon, 21 Nov 2022 14:54:56 +0000
libfastcommon (1.0.62-1) unstable; urgency=medium
* upgrade to 1.0.62-1
-- YuQing <384681@qq.com> Sat, 08 Oct 2022 13:28:15 +0000
libfastcommon (1.0.61-1) unstable; urgency=medium
* upgrade to 1.0.61-1
-- YuQing <384681@qq.com> Thu, 22 Sep 2022 12:22:09 +0000
libfastcommon (1.0.60-1) unstable; urgency=medium
* upgrade to 1.0.60-1
-- YuQing <384681@qq.com> Wed, 07 Sep 2022 13:36:01 +0000
libfastcommon (1.0.59-1) unstable; urgency=medium
* upgrade to 1.0.59-1
-- YuQing <384681@qq.com> Mon, 25 Jul 2022 13:51:25 +0000
libfastcommon (1.0.58-1) unstable; urgency=medium
* upgrade to 1.0.58-1
-- YuQing <384681@qq.com> Wed, 15 Jun 2022 14:26:02 +0000
libfastcommon (1.0.57-1) unstable; urgency=medium
* upgrade to 1.0.57-1
-- YuQing <384681@qq.com> Thu, 28 Apr 2022 11:53:21 +0000
libfastcommon (1.0.56-1) unstable; urgency=medium
* check pthread_rwlockattr_getkind_np for porting
* correct pthread_rwlockattr getkind_np to setkind_np
* change include <sys/poll.h> to #include <poll.h>
* add function fc_gettid
* NULL from parameter for getcwd
* sockopt.[hc] support tcpwritev and tcpreadv
* add const modifier for unification
* make.sh refined
* add function fc_iov_get_bytes
* make.sh: generate macros for dirent fields
* add function log_try_init2
* rename hash_xxx to fc_hash_xxx
* rename trim to fc_trim
* php-fastcommon compile OK
* add function locked_list_destroy
* upgrade version to 1.0.56
* add function fc_check_rename_ex
* small changes for logger.[hc]
-- YuQing <384681@qq.com> Sun, 13 Mar 2022 16:43:08 +0800
libfastcommon (1.0.55-1) unstable; urgency=medium
* upgrade version to 1.0.55
-- YuQing <384681@qq.com> Sat, 15 Jan 2022 19:50:26 +0800
libfastcommon (1.0.54-1) unstable; urgency=medium
* upgrade version to 1.0.54
-- YuQing <384681@qq.com> Sun, 26 Dec 2021 20:29:05 +0800
libfastcommon (1.0.53-1) unstable; urgency=medium
* open for write MUST have the third parameter: mode
* uniq_skiplist.h: add function uniq_skiplist_iterator_at
* process_action support action status
-- YuQing <384681@qq.com> Tue, 6 Jul 2021 21:23:31 +0800

1
debian/compat vendored
View File

@ -1 +0,0 @@
11

25
debian/control vendored
View File

@ -1,25 +0,0 @@
Source: libfastcommon
Section: libs
Priority: optional
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: 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.

530
debian/copyright vendored
View File

@ -1,530 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: libfastcommon
Source: http://github.com/happyfish100/libfastcommon/
#
# 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.

View File

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

View File

@ -1 +0,0 @@
usr/lib/libfastcommon.so*

14
debian/rules vendored
View File

@ -1,14 +0,0 @@
#!/usr/bin/make -f
export DESTDIR = $(CURDIR)/debian/tmp
%:
dh $@
override_dh_auto_build:
./make.sh clean && ./make.sh
override_dh_auto_install:
./make.sh install
dh_auto_install

View File

@ -1 +0,0 @@
3.0 (quilt)

3
debian/watch vendored
View File

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

View File

@ -1,48 +0,0 @@
# 64位ID⽣成器说明
```
我们在libfastcommon中实现了64位 8字节整数 ID⽣成器针对PHP这样的多进程⽅式⽣成的64位ID也可以做到全局唯⼀。
提供的PHP扩展php-fastcommon封装了64位ID⽣成器。
64位ID⽣成规则⽣成的ID可以⼩于64位
32 位Unix时间戳 + X位机器ID + Y位extra data + Z位顺序号
其中 X + Y + Z <= 32
* 机器ID machine_id缩写为mid可以在初始化时指定如果设置为0表⽰获取本地IP地址的后X位作为机器ID
* extra data⽤来存储额外信息例如订单分库的库号。如果不需要这个特性将Y设置为0即可
* 顺序号sn会保存在本地⽂件中建议顺序号的位数Z⾄少为14其对应的最⼤数值为1638316K
```
## php-fastcommon扩展提供的4个PHP函数
```
resource fastcommon_id_generator_init([string $filename = "/tmp/fastcommon_id_generator.sn",
int $machine_id = 0, int $mid_bits = 16, int $extra_bits = 0, int $sn_bits = 16])
return resource handle for success, false for fail
* 这个函数只需要在初始化的时候调⽤⼀次即可,建议不同的实例采⽤不同的⽂件来保存序列号。
* php程序运⾏⽤户对这个⽂件必须有读写权限⽂件不存在会⾃动创建。
* 返回的resoure需要保存到php变量否则该初始化⼯作会⾃动撤销
```
```
long/string fastcommon_id_generator_next([int $extra = 0, resource $handle = null])
return id for success, false for fail
return long in 64 bits OS, return string in 32 bits OS
* 如果不需要存储额外信息, extra传0即可。
* 其中$handle参数为 fastcommon_id_generator_init返回值不传递该参数表⽰使⽤最后⼀次调⽤
```
```
fastcommon_id_generator_init 返回的handle。
int fastcommon_id_generator_get_extra(long id [, resource $handle = null])
return the extra data
* 使⽤了额外信息的情况下可以使⽤这个函数获取ID中包含的extra data
```
```
bool fastcommon_id_generator_destroy([resource $handle = null])
return true for success
* 这个函数通常不需要显式调⽤
```

Binary file not shown.

View File

@ -1,122 +0,0 @@
## libfastcommon概述
```
libfastcommon是在github开源的⼀个C函数库。它提供了ini⽂件解析、logger、
64位唯⼀整数⽣成器、字符串处理、socket封装、对象池、skiplist、
定时任务调度器、时间轮等等。接下来主要介绍下ini⽂件解析ini_file_reader。
```
## ini_file_reader的主要特点
### 1、⽀持section
```
例如: [workers]
```
### 2、⼀个配置项可以出现多次
```
通过iniGetValues或者iniGetValuesEx获取。例如
tracker_server = ip1
tracker_server = ip2
```
### 3、 #include指令包含其他配置⽂件
```
可以包含本地⽂件也可以包含URL目前仅⽀持HTTP。例如
#include http.conf
```
### 4、 #@function指令⽀持标注
```
配置项的取值为扩展(外部)动态库的返回值
V1.39⽀持三个内置标注:
I. LOCAL_IP_GET [inner | private | outer | public] 获取本机IP地址
inner或private表示获取内网IPouter或public表示获取外网IP
[index]表示获取指定序号的本机IP0表示获取第一个IP-1表示获取最后一个IP
例如:[0]、inner[-1], outer[1]等等
II. SHELL_EXEC 获取命令⾏输出执行的command为配置项
III. REPLACE_VARS 替换配置项中%{VARIABLE}格式的变量,变量由#@set指令设置
```
```
配置⽰例:
#@function SHELL_EXEC
host = hostname
#@function LOCAL_IP_GET
bind_ip = inner
#@set encoder_filename=/usr/local/etc/encoder.conf
#@set encoder_port = $(grep ^inner_port %{encoder_filename} | awk -F '=' '{print $2;}')
#@function REPLACE_VARS
check_alive_command = /usr/local/lib/libdfscheckalive.so %{encoder_port} 2 30
```
### 5、 #@add_annotation 扩展#@function标签
```
格式:
#@add_annotation <function> <动态库文件名> [参数1, 参数2, ...]
参数个数0到3个。
使用libshmcache扩展标签CONFIG_GET示例
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
#@function CONFIG_GET
app.version = app1.key1
```
### 6、⽀持简单的流程控制控制标签包括
#### I. 条件判断
```
#@if %{VARIABLE} in [x,y,..]
#@else
#@endif
其中#@else指令为可选项。
#@if指令目前仅⽀持这种格式。
VARIABLE包括
1 LOCAL_IP本机IP
2 LOCAL_HOST通过hostname获得的本机主机名
3 #@set指令设置的变量 #@set指令格式
#@set VAR = value
若要获取shell命令⾏输出 value部分格式为 $(command),例如:
#@set os_name = $(uname -a | awk '{print $1;}')
注: LOCAL_IP⽀持CIDR格式的IP地址例如 172.16.12.0/22
例如:
#@if %{LOCAL_IP} in [10.0.11.89,10.0.11.99,172.16.12.0/22]
min_subprocess_number = 4
#@else
min_subprocess_number = 20
#@endif
```
#### II. 计数循环
```
#@for VARIABLE from 0 to 15 step 1
#@endfor
其中VARIABLE⻓度不超过64位字符在循环体中通过
{$VARIABLE}格式获取其值。 step可以为负数但不能为0。例如
#@for i from 0 to 15 step 1
[section{$i}]
subprocess_command = /usr/bin/php xxx {$i}
subprocess_number = 1
#@endfor
```
```
另外, libfastcommon中的部分函数提供了PHP扩展。 github地址
https://github.com/happyfish100/libfastcommon欢迎⼤家下载使⽤。
```

Binary file not shown.

View File

@ -1,35 +0,0 @@
# ⽇志⽂件优化PHP扩展函数
```
出于提升性能目的基于libfastcommon封装的php扩展提供了函数fastcommon_error_log
来替代PHP原⽣的error_log使⽤fastcommon_file_put_contents替换PHP原⽣的file_put_contents。
原理很简单就是⽇志⽂件打开后将其⽂件描述符或⽂件句柄持久化避免每次调⽤error_log
或file_put_contents时都执⾏open和close等⽂件操作。
在短字符串的场景下通过实测fastcommon_file_put_contents⽐file_put_contents性能提升2倍以上。
fastcommon_error_log⽐error_log性能提升50%以上。
两个扩展函数的⽤法和PHP原⽣函数⼀致。在可以优化的场景下由fastcommon扩展接管处理否则透传给PHP原⽣函数处理。
```
## 函数简要说明如下:
```
bool fastcommon_error_log (string $message [, int $message_type = 0, string
$destination, string $extra_headers] )
接管(优化处理)条件: $message_type为3且指定了$destination即⽇志⽂件名
在接管的情况下, $extra_headers可以为下列常量之⼀
FASTCOMMON_LOG_TIME_PRECISION_NONE⽇志⾏⾸不输出⽇期时间字符串默认值
FASTCOMMON_LOG_TIME_PRECISION_SECOND⽇志⾏⾸输出的时间精度到秒
FASTCOMMON_LOG_TIME_PRECISION_MSECOND⽇志⾏⾸输出的时间精度到毫秒
FASTCOMMON_LOG_TIME_PRECISION_USECOND⽇志⾏⾸输出的时间精度到微秒
注:如果$message最后没有换⾏符会⾃动增加。这和error_log的⾏为不⼀致。
```
```
int fastcommon_file_put_contents (string $filename , mixed $data [, int $flags = 0,
resource $context ])
接管优化处理条件需满⾜如下3个条件
* $data为字符串
* $flags 为FILE_APPEND或 (FILE_APPEND | LOCK_EX)
* $context 为null即没有指定$context
```

Binary file not shown.

View File

@ -1,45 +1,34 @@
%define LibFastcommonDevel libfastcommon-devel
%define CommitVersion %(echo $COMMIT_VERSION)
%define LibFastcommonDebuginfo libfastcommon-debuginfo
Name: libfastcommon
Version: 1.0.83
Version: 1.0.35
Release: 1%{?dist}
Summary: c common functions library extracted from my open source projects FastDFS
License: LGPL
License: GPL
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: /sbin/chkconfig
#BuildRequires: perl %{_includedir}/linux/if.h gettext
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.
commit version: %{CommitVersion}
url encode / decode, fasttimer etc.
%package devel
Summary: Development header file
Requires: libcurl-devel
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
This package provides the header files of libfastcommon
commit version: %{CommitVersion}
This pakcage provides the header files of libfastcommon
%prep
@ -64,11 +53,12 @@ rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
/usr/lib64/libfastcommon.so*
/usr/lib/libfastcommon.so*
%files devel
%defattr(-,root,root,-)
/usr/include/fastcommon/*
%changelog
* Mon Jun 23 2014 Zaixue Liao
* Mon Jun 23 2014 Zaixue Liao <liaozaixue@yongche.com>
- first RPM release (1.0)

168
make.sh
View File

@ -1,9 +1,3 @@
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>
@ -13,132 +7,71 @@ 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)
if [ $? -ne 0 ]; then
echo -e "Can't find a.out program\n" 1>&2
exit 2
fi
output=`./a.out`
if [ -f /bin/expr ]; then
EXPR=/bin/expr
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
EXPR=/usr/bin/expr
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
elif [ $count -eq 1 ]; then
off_bytes=$col
else
glibc_minor=$col
off_bytes=$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
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
OS_BITS=64
LIB_VERSION=lib64
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'
if [ -n "$GCC_VERSION" ] && [ $GCC_VERSION -ge 7 ]; then
CFLAGS="$CFLAGS -Wformat-truncation=0 -Wformat-overflow=0"
fi
CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE"
CFLAGS='-Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE'
if [ "$DEBUG_FLAG" = "1" ]; then
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
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"
LIBS="$LIBS -lcurl"
fi
LIBS='-lm'
uname=`uname`
HAVE_VMMETER_H=0
HAVE_USER_H=0
if [ "$uname" = "Linux" ]; then
OS_NAME=OS_LINUX
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
IOEVENT_USE=IOEVENT_USE_EPOLL
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
else
INCS="$INCS -I/usr/local/include"
LIBS="$LIBS -L/usr/local/lib"
fi
if [ -f /usr/include/sys/vmmeter.h ]; then
@ -153,10 +86,12 @@ elif [ "$uname" = "SunOS" ]; then
IOEVENT_USE=IOEVENT_USE_PORT
CFLAGS="$CFLAGS -D_THREAD_SAFE"
LIBS="$LIBS -lsocket -lnsl -lresolv"
export CC=gcc
elif [ "$uname" = "AIX" ]; then
OS_NAME=OS_AIX
IOEVENT_USE=IOEVENT_USE_NONE
CFLAGS="$CFLAGS -D_THREAD_SAFE"
export CC=gcc
elif [ "$uname" = "HP-UX" ]; then
OS_NAME=OS_HPUX
IOEVENT_USE=IOEVENT_USE_NONE
@ -165,36 +100,6 @@ 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
@ -217,35 +122,13 @@ 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
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
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
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 2>/dev/null | grep -F pthread_create | grep -w T)
line=`nm -D /usr/lib/libc_r.so | grep pthread_create | grep -w T`
if [ -n "$line" ]; then
LIBS="$LIBS -lc_r"
fi
@ -264,23 +147,12 @@ 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
sed_replace "s/\\\$(CFLAGS)/$CFLAGS/g" Makefile
sed_replace "s/\\\$(LIBS)/$LIBS/g" Makefile
sed_replace "s/\\\$(LIB_VERSION)/$LIB_VERSION/g" Makefile
make $1 $2 $3
if [ "$1" = "clean" ]; then
/bin/rm -f Makefile _os_define.h
fi
cd tests
cp Makefile.in Makefile
sed_replace "s#\\\$(CC)#gcc#g" Makefile
sed_replace "s#\\\$(INCS)#$INCS#g" Makefile
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
if [ "$1" = "clean" ]; then
/bin/rm -f Makefile
fi

View File

@ -1,17 +1,3 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "php7_ext_wrapper.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
@ -37,29 +23,16 @@
#define MINOR_VERSION 0
#define PATCH_VERSION 8
#define IDG_FLAGS_EXTRA_DATA_BY_MOD 1
#define PHP_IDG_RESOURCE_NAME "fastcommon_idg"
#define DEFAULT_SN_FILENAME "/tmp/fastcommon_id_generator.sn"
typedef struct {
struct idg_context *idg_context;
int flags;
struct idg_context idg_context;
} PHPIDGContext;
typedef struct {
char filename[MAX_PATH_SIZE];
int machine_id;
int mid_bits;
int extra_bits;
int sn_bits;
int flags;
} PHPIDGKeyInfo;
static int le_consumer;
static PHPIDGContext *last_idg_context = NULL;
static HashArray idg_htable;
typedef struct {
int alloc;
@ -93,111 +66,26 @@ 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, 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)
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)
{NULL, NULL, NULL} /* Must be the last line */
};
@ -220,25 +108,32 @@ zend_module_entry fastcommon_module_entry = {
ZEND_RSRC_DTOR_FUNC(id_generator_dtor)
{
PHPIDGContext *php_idg_context = NULL;
#if PHP_MAJOR_VERSION < 7
if (rsrc->ptr != NULL) {
php_idg_context = (PHPIDGContext *)rsrc->ptr;
if (rsrc->ptr != NULL)
{
PHPIDGContext *php_idg_context = (PHPIDGContext *)rsrc->ptr;
id_generator_destroy(&php_idg_context->idg_context);
if (last_idg_context == php_idg_context)
{
last_idg_context = NULL;
}
efree(php_idg_context);
rsrc->ptr = NULL;
}
#else
if (res->ptr != NULL) {
php_idg_context = (PHPIDGContext *)res->ptr;
if (res->ptr != NULL)
{
PHPIDGContext *php_idg_context = (PHPIDGContext *)res->ptr;
id_generator_destroy(&php_idg_context->idg_context);
if (last_idg_context == php_idg_context)
{
last_idg_context = NULL;
}
efree(php_idg_context);
res->ptr = NULL;
}
#endif
if (php_idg_context != NULL) {
if (last_idg_context == php_idg_context) {
last_idg_context = NULL;
}
efree(php_idg_context);
}
}
#define FASTCOMMON_REGISTER_CHAR_STR_CONSTANT(key, c, buff) \
@ -249,12 +144,9 @@ PHP_MINIT_FUNCTION(fastcommon)
{
static char buff[16];
log_try_init();
log_init();
le_consumer = zend_register_list_destructors_ex(id_generator_dtor, NULL,
PHP_IDG_RESOURCE_NAME, module_number);
if (fc_hash_init(&idg_htable, fc_simple_hash, 64, 0.75) != 0) {
return FAILURE;
}
memset(buff, 0, sizeof(buff));
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_SECOND",
@ -266,9 +158,6 @@ PHP_MINIT_FUNCTION(fastcommon)
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_NONE",
LOG_TIME_PRECISION_NONE, buff + 6);
REGISTER_LONG_CONSTANT("FASTCOMMON_IDG_FLAGS_EXTRA_DATA_BY_MOD",
IDG_FLAGS_EXTRA_DATA_BY_MOD, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
@ -465,7 +354,7 @@ ZEND_FUNCTION(fastcommon_simple_hash)
RETURN_BOOL(false);
}
RETURN_LONG(fc_simple_hash(str, str_len) & 0x7FFFFFFF);
RETURN_LONG(simple_hash(str, str_len) & 0x7FFFFFFF);
}
/*
@ -588,47 +477,9 @@ ZEND_FUNCTION(fastcommon_is_private_ip)
RETURN_BOOL(is_private_ip(ip));
}
static struct idg_context *get_idg_context(const char *filename,
const int machine_id, const int mid_bits, const int extra_bits,
const int sn_bits, const int mode)
{
PHPIDGKeyInfo key_info;
struct idg_context *idg_context;
memset(&key_info, 0, sizeof(key_info));
snprintf(key_info.filename, sizeof(key_info.filename), "%s", filename);
key_info.machine_id = machine_id;
key_info.mid_bits = mid_bits;
key_info.extra_bits = extra_bits;
key_info.sn_bits = sn_bits;
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));
if (idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail!", __LINE__,
(int)sizeof(struct idg_context));
return NULL;
}
if (id_generator_init_extra_ex(idg_context, filename,
machine_id, mid_bits, extra_bits, sn_bits, mode) != 0)
{
return NULL;
}
fc_hash_insert_ex(&idg_htable, &key_info, sizeof(key_info),
idg_context, 0, false);
}
return idg_context;
}
/*
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16,
int mode = 0644, int flags = 0])
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16, int mode = 0644])
return resource handle for success, false for fail
*/
ZEND_FUNCTION(fastcommon_id_generator_init)
@ -640,50 +491,47 @@ ZEND_FUNCTION(fastcommon_id_generator_init)
long extra_bits;
long sn_bits;
long mode;
long flags;
char *filename;
PHPIDGContext *php_idg_context;
argc = ZEND_NUM_ARGS();
if (argc > 7) {
logError("file: "__FILE__", line: %d, "
"fastcommon_id_generator_init parameters count: %d is invalid",
__LINE__, argc);
RETURN_BOOL(false);
}
argc = ZEND_NUM_ARGS();
if (argc > 6) {
logError("file: "__FILE__", line: %d, "
"fastcommon_id_generator_init parameters count: %d is invalid",
__LINE__, argc);
RETURN_BOOL(false);
}
filename = DEFAULT_SN_FILENAME;
filename = DEFAULT_SN_FILENAME;
filename_len = 0;
machine_id = 0;
mid_bits = 16;
machine_id = 0;
mid_bits = 16;
extra_bits = 0;
sn_bits = 16;
mode = ID_GENERATOR_DEFAULT_FILE_MODE;
flags = 0;
if (zend_parse_parameters(argc TSRMLS_CC, "|sllllll", &filename,
if (zend_parse_parameters(argc TSRMLS_CC, "|slllll", &filename,
&filename_len, &machine_id, &mid_bits, &extra_bits,
&sn_bits, &mode, &flags) == FAILURE)
{
logError("file: "__FILE__", line: %d, "
"zend_parse_parameters fail!", __LINE__);
RETURN_BOOL(false);
}
&sn_bits, &mode) == FAILURE)
{
logError("file: "__FILE__", line: %d, "
"zend_parse_parameters fail!", __LINE__);
RETURN_BOOL(false);
}
php_idg_context = (PHPIDGContext *)emalloc(sizeof(PHPIDGContext));
if (php_idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"emalloc %d bytes fail!", __LINE__,
(int)sizeof(PHPIDGContext));
RETURN_BOOL(false);
}
if ((php_idg_context->idg_context=get_idg_context(filename, machine_id,
mid_bits, extra_bits, sn_bits, mode)) == NULL)
if (php_idg_context == NULL)
{
RETURN_BOOL(false);
logError("file: "__FILE__", line: %d, "
"emalloc %d bytes fail!", __LINE__, (int)sizeof(PHPIDGContext));
RETURN_BOOL(false);
}
php_idg_context->flags = flags;
if (id_generator_init_extra_ex(&php_idg_context->idg_context, filename,
machine_id, mid_bits, extra_bits, sn_bits, mode) != 0)
{
RETURN_BOOL(false);
}
last_idg_context = php_idg_context;
ZEND_REGISTER_RESOURCE(return_value, php_idg_context, le_consumer);
}
@ -697,11 +545,10 @@ ZEND_FUNCTION(fastcommon_id_generator_next)
{
int argc;
long extra;
int extra_val;
int *extra_ptr;
int64_t id;
zval *zhandle;
PHPIDGContext *php_idg_context;
struct idg_context *context;
argc = ZEND_NUM_ARGS();
if (argc > 2) {
@ -719,31 +566,26 @@ ZEND_FUNCTION(fastcommon_id_generator_next)
RETURN_BOOL(false);
}
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
{
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
PHP_IDG_RESOURCE_NAME, le_consumer);
} else {
context = &php_idg_context->idg_context;
}
else
{
if (last_idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
php_idg_context = last_idg_context;
context = &last_idg_context->idg_context;
}
if ((php_idg_context->flags & IDG_FLAGS_EXTRA_DATA_BY_MOD)) {
extra_ptr = NULL;
} else {
extra_val = extra;
extra_ptr = &extra_val;
}
if (id_generator_next_extra_ptr(php_idg_context->idg_context,
extra_ptr, &id) != 0)
{
RETURN_BOOL(false);
}
if (id_generator_next_extra(context, extra, &id) != 0) {
RETURN_BOOL(false);
}
#if OS_BITS == 64
RETURN_LONG(id);
@ -767,6 +609,7 @@ ZEND_FUNCTION(fastcommon_id_generator_get_extra)
long id;
zval *zhandle;
PHPIDGContext *php_idg_context;
struct idg_context *context;
argc = ZEND_NUM_ARGS();
if (argc > 2) {
@ -784,25 +627,29 @@ ZEND_FUNCTION(fastcommon_id_generator_get_extra)
RETURN_BOOL(false);
}
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
{
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
PHP_IDG_RESOURCE_NAME, le_consumer);
} else {
context = &php_idg_context->idg_context;
}
else
{
if (last_idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
php_idg_context = last_idg_context;
context = &last_idg_context->idg_context;
}
if (php_idg_context->idg_context->fd < 0) {
if (context->fd < 0) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
RETURN_LONG(id_generator_get_extra(php_idg_context->idg_context, id));
RETURN_LONG(id_generator_get_extra(context, id));
}
/*
@ -813,7 +660,8 @@ ZEND_FUNCTION(fastcommon_id_generator_destroy)
{
int argc;
zval *zhandle;
//PHPIDGContext *php_idg_context;
PHPIDGContext *php_idg_context;
struct idg_context *context;
argc = ZEND_NUM_ARGS();
if (argc > 1) {
@ -831,20 +679,24 @@ ZEND_FUNCTION(fastcommon_id_generator_destroy)
RETURN_BOOL(false);
}
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
/*
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
{
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
PHP_IDG_RESOURCE_NAME, le_consumer);
*/
} else {
context = &php_idg_context->idg_context;
}
else
{
if (last_idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
context = &last_idg_context->idg_context;
last_idg_context = NULL;
}
id_generator_destroy(context);
RETURN_BOOL(true);
}
@ -858,6 +710,7 @@ ZEND_FUNCTION(fastcommon_id_generator_get_timestamp)
long id;
zval *zhandle;
PHPIDGContext *php_idg_context;
struct idg_context *context;
argc = ZEND_NUM_ARGS();
if (argc > 2) {
@ -875,25 +728,29 @@ ZEND_FUNCTION(fastcommon_id_generator_get_timestamp)
RETURN_BOOL(false);
}
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
{
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
PHP_IDG_RESOURCE_NAME, le_consumer);
} else {
context = &php_idg_context->idg_context;
}
else
{
if (last_idg_context == NULL) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
php_idg_context = last_idg_context;
context = &last_idg_context->idg_context;
}
if (php_idg_context->idg_context->fd < 0) {
if (context->fd < 0) {
logError("file: "__FILE__", line: %d, "
"must call fastcommon_id_generator_init first", __LINE__);
RETURN_BOOL(false);
}
RETURN_LONG(id_generator_get_timestamp(php_idg_context->idg_context, id));
RETURN_LONG(id_generator_get_timestamp(context, id));
}
/*
@ -1237,8 +1094,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 | O_CLOEXEC, 0644)) < 0)
if ((ctx->fd = open(ctx->filename, O_WRONLY |
O_CREAT | O_APPEND, 0644)) < 0)
{
logError("file: "__FILE__", line: %d, "
"open file \"%s\" to write fail, "

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
#ifndef FASTCOMMON_H
#define FASTCOMMON_H

View File

@ -26,11 +26,11 @@ unset($handle);
/*
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16, int flags = 0])
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16])
*/
$id = 6301319781687017475;
$handle1 = fastcommon_id_generator_init("/tmp/sn1.txt", 0, 8, 10, 14, 0666);
$handle1 = fastcommon_id_generator_init("/tmp/sn1.txt", 0, 8, 10, 14, 0775);
echo 'extra no: ' . fastcommon_id_generator_get_extra($id, $handle1) . "\n";
$handle2 = fastcommon_id_generator_init("/tmp/sn2.txt", 0, 8, 8, 16);
@ -58,6 +58,10 @@ for ($i=0; $i<10; $i++) {
fastcommon_id_generator_get_timestamp($id, $handle));
}
fastcommon_id_generator_destroy($handle);
fastcommon_id_generator_destroy($handle1);
fastcommon_id_generator_destroy($handle2);
fastcommon_error_log("this is a test\n", 3, "/tmp/test.log");
fastcommon_error_log("this is a test11\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
fastcommon_error_log("this is a test12\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);

View File

@ -1,53 +1,39 @@
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = $(INCS)
INC_PATH =
LIB_PATH = $(LIBS)
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
logger.lo sockopt.lo base64.lo sched_thread.lo \
http_func.lo md5.lo pthread_func.lo local_ip_func.lo \
avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \
fast_timer.lo locked_timer.lo process_ctrl.lo fast_mblock.lo \
fast_timer.lo process_ctrl.lo fast_mblock.lo \
connection_pool.lo fast_mpool.lo fast_allocator.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 sorted_queue.lo fc_memory.lo shared_buffer.lo \
thread_pool.lo array_allocator.lo sorted_array.lo spinlock.lo
char_converter.lo char_convert_loader.lo
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
logger.o sockopt.o base64.o sched_thread.o \
http_func.o md5.o pthread_func.o local_ip_func.o \
avl_tree.o ioevent.o ioevent_loop.o fast_task_queue.o \
fast_timer.o locked_timer.o process_ctrl.o fast_mblock.o \
fast_timer.o process_ctrl.o fast_mblock.o \
connection_pool.o fast_mpool.o fast_allocator.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 \
json_parser.o buffered_file_writer.o server_id_func.o \
fc_queue.o sorted_queue.o fc_memory.o shared_buffer.o \
thread_pool.o array_allocator.o sorted_array.o spinlock.o
char_converter.o char_convert_loader.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 \
sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h \
avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \
fast_timer.h locked_timer.h process_ctrl.h fast_mblock.h \
fast_timer.h process_ctrl.h fast_mblock.h \
connection_pool.h fast_mpool.h fast_allocator.h \
fast_buffer.h skiplist.h multi_skiplist.h flat_skiplist.h \
skiplist_common.h system_info.h fast_blocked_queue.h \
php7_ext_wrapper.h id_generator.h char_converter.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 sorted_queue.h fc_memory.h \
shared_buffer.h thread_pool.h fc_atomic.h array_allocator.h \
sorted_array.h spinlock.h
char_convert_loader.h
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
@ -57,8 +43,8 @@ STATIC_LIBS = libfastcommon.a
ALL_LIBS = $(SHARED_LIBS) $(STATIC_LIBS)
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
libfastcommon.so: $(FAST_SHARED_OBJS)
$(COMPILE) -o $@ -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
libfastcommon.so:
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
libfastcommon.a: $(FAST_STATIC_OBJS)
ar rcs $@ $(FAST_STATIC_OBJS)
.o:
@ -70,15 +56,12 @@ libfastcommon.a: $(FAST_STATIC_OBJS)
.c.lo:
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_LIB)
mkdir -p $(TARGET_PREFIX)/lib
mkdir -p $(TARGET_PREFIX)/include/fastcommon
install -m 755 $(SHARED_LIBS) $(TARGET_LIB)
install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon
@BUILDROOT=$$(echo "$(TARGET_PREFIX)" | grep BUILDROOT); \
if [ -z "$$BUILDROOT" ] && [ "$(TARGET_LIB)" != "$(TARGET_PREFIX)/lib" ]; then ln -sf $(TARGET_LIB)/libfastcommon.so $(TARGET_PREFIX)/lib/libfastcommon.so; fi
mkdir -p $(DESTDIR)/usr/$(LIB_VERSION)
mkdir -p $(DESTDIR)/usr/lib
install -m 755 $(SHARED_LIBS) $(DESTDIR)/usr/$(LIB_VERSION)
install -m 755 $(SHARED_LIBS) $(DESTDIR)/usr/lib
mkdir -p $(DESTDIR)/usr/include/fastcommon
install -m 644 $(HEADER_FILES) $(DESTDIR)/usr/include/fastcommon
clean:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)

View File

@ -1,129 +0,0 @@
/*
* 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);
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ARRAY_ALLOCATOR_H
#define ARRAY_ALLOCATOR_H
#include "fast_allocator.h"
typedef struct
{
int alloc;
int count;
char elts[0];
} VoidArray;
typedef struct
{
int alloc;
int count;
int64_t elts[0];
} I64Array;
typedef struct
{
int alloc;
int count;
int32_t elts[0];
} I32Array;
typedef struct
{
int alloc;
int count;
id_name_pair_t elts[0];
} IdNameArray;
typedef struct
{
int alloc;
int count;
void *elts[0];
} PointerArray;
typedef struct array_allocator_context
{
struct fast_allocator_context allocator;
int element_size;
int min_count;
} ArrayAllocatorContext;
#ifdef __cplusplus
extern "C" {
#endif
int array_allocator_init_ex(ArrayAllocatorContext *ctx,
const char *name_prefix, const int element_size,
const int min_bits, const int max_bits,
const bool need_lock);
VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
const int target_count);
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,
VoidArray *old_array, const int target_count);
static inline void array_allocator_free(ArrayAllocatorContext *ctx,
VoidArray *array)
{
fast_allocator_free(&ctx->allocator, array);
}
/* comparator for 64 bits integer */
int array_compare_element_int64(const int64_t *n1, const int64_t *n2);
/* comparator for 32 bits integer */
int array_compare_element_int32(const int32_t *n1, const int32_t *n2);
/* comparator for id name pair (sorted by id) */
int array_compare_element_id_name(const id_name_pair_t *pair1,
const id_name_pair_t *pair2);
#define array_allocator_init(ctx, name_prefix, \
element_size, min_bits, max_bits) \
array_allocator_init_ex(ctx, name_prefix, \
element_size, min_bits, max_bits, true)
#define i64_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "i64", sizeof(int64_t), \
min_bits, max_bits, need_lock)
#define i64_array_allocator_init(ctx, min_bits, max_bits) \
i64_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define i64_array_allocator_alloc(ctx, target_count) \
(I64Array *)array_allocator_alloc(ctx, target_count)
#define i64_array_allocator_realloc(ctx, old_array, target_count) \
(I64Array *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define i64_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define i32_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "i32", sizeof(int32_t), \
min_bits, max_bits, need_lock)
#define i32_array_allocator_init(ctx, min_bits, max_bits) \
i32_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define i32_array_allocator_alloc(ctx, target_count) \
(I32Array *)array_allocator_alloc(ctx, target_count)
#define i32_array_allocator_realloc(ctx, old_array, target_count) \
(I32Array *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define i32_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define id_name_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "id_name", sizeof(id_name_pair_t), \
min_bits, max_bits, need_lock)
#define id_name_array_allocator_init(ctx, min_bits, max_bits) \
id_name_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define id_name_array_allocator_alloc(ctx, target_count) \
(IdNameArray *)array_allocator_alloc(ctx, target_count)
#define id_name_array_allocator_realloc(ctx, old_array, target_count) \
(IdNameArray *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define id_name_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#define ptr_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
array_allocator_init_ex(ctx, "ptr", sizeof(void *), \
min_bits, max_bits, need_lock)
#define ptr_array_allocator_init(ctx, min_bits, max_bits) \
ptr_array_allocator_init_ex(ctx, min_bits, max_bits, true)
#define ptr_array_allocator_alloc(ctx, target_count) \
(PointerArray *)array_allocator_alloc(ctx, target_count)
#define ptr_array_allocator_realloc(ctx, old_array, target_count) \
(PointerArray *)array_allocator_realloc(ctx, \
(VoidArray *)old_array, target_count)
#define ptr_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,19 +1,3 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "fc_memory.h"
#include "avl_tree.h"
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
@ -61,9 +45,14 @@ void avl_tree_destroy(AVLTreeInfo *tree)
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
{
AVLTreeNode *pNewNode;
pNewNode = (AVLTreeNode *)fc_malloc(sizeof(AVLTreeNode));
pNewNode = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
if (pNewNode == NULL)
{
/*
fprintf(stderr, "file: "__FILE__", line: %d, " \
"malloc %d bytes fail!\n", __LINE__, \
(int)sizeof(AVLTreeNode));
*/
return NULL;
}

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
#ifndef AVL_TREE_H
#define AVL_TREE_H

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <time.h>
#include <stdio.h>
@ -23,8 +16,6 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "fc_memory.h"
#include "shared_func.h"
#include "base64.h"
/**
@ -54,11 +45,15 @@ 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 = fc_safe_strcpy(context->
line_separator, 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;
}
}
void base64_init_ex(struct base64_context *context, const int nLineLength, \
@ -286,9 +281,11 @@ char *base64_decode_auto(struct base64_context *context, const char *src, \
}
else
{
pBuff = (char *)fc_malloc(nNewLen);
pBuff = (char *)malloc(nNewLen);
if (pBuff == NULL)
{
fprintf(stderr, "Can't malloc %d bytes\n", \
nSrcLen + nPadLen + 1);
*dest_len = 0;
*dest = '\0';
return dest;

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//base64.h

View File

@ -1,214 +0,0 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include "shared_func.h"
#include "logger.h"
#include "fc_memory.h"
#include "buffered_file_writer.h"
int buffered_file_writer_open_ex(BufferedFileWriter *writer,
const char *filename, const int buffer_size,
const int max_written_once, const int mode)
{
int result;
int written_once;
writer->buffer_size = (buffer_size > 0) ? buffer_size : 64 * 1024;
written_once = (max_written_once > 0) ? max_written_once : 256;
if (written_once > writer->buffer_size)
{
logError("file: "__FILE__", line: %d, "
"max_written_once: %d > buffer_size: %d",
__LINE__, written_once, writer->buffer_size);
return EINVAL;
}
writer->buff = (char *)fc_malloc(writer->buffer_size);
if (writer->buff == NULL)
{
return ENOMEM;
}
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;
logError("file: "__FILE__", line: %d, "
"open file %s fail, "
"errno: %d, error info: %s",
__LINE__, writer->filename,
result, STRERROR(result));
free(writer->buff);
writer->buff = NULL;
return result;
}
writer->current = writer->buff;
writer->buff_end = writer->buff + writer->buffer_size;
writer->water_mark = writer->buff_end - written_once;
return 0;
}
int buffered_file_writer_close(BufferedFileWriter *writer)
{
int result;
if (writer->buff == NULL)
{
return EINVAL;
}
result = buffered_file_writer_flush(writer);
if (result == 0 && fsync(writer->fd) != 0)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"fsync file %s fail, "
"errno: %d, error info: %s",
__LINE__, writer->filename,
result, STRERROR(result));
}
if (close(writer->fd) != 0)
{
if (result == 0)
{
result = errno != 0 ? errno : EIO;
}
logError("file: "__FILE__", line: %d, "
"close file %s fail, "
"errno: %d, error info: %s",
__LINE__, writer->filename,
errno, STRERROR(errno));
}
free(writer->buff);
writer->buff = NULL;
return result;
}
int buffered_file_writer_flush(BufferedFileWriter *writer)
{
int result;
int len;
len = writer->current - writer->buff;
if (len == 0)
{
return 0;
}
if (fc_safe_write(writer->fd, writer->buff, len) != len)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s", __LINE__,
writer->filename, result, STRERROR(result));
return result;
}
writer->current = writer->buff;
return 0;
}
int buffered_file_writer_append(BufferedFileWriter *writer,
const char *format, ...)
{
va_list ap;
int result;
int remain_size;
int len;
int i;
result = 0;
for (i=0; i<2; i++)
{
remain_size = writer->buff_end - writer->current;
va_start(ap, format);
len = vsnprintf(writer->current, remain_size, format, ap);
va_end(ap);
if (len < remain_size)
{
writer->current += len;
if (writer->current > writer->water_mark)
{
result = buffered_file_writer_flush(writer);
}
break;
}
if (len > writer->buffer_size)
{
result = ENOSPC;
logError("file: "__FILE__", line: %d, "
"too large output buffer, %d > %d!",
__LINE__, len, writer->buffer_size);
break;
}
//maybe full, try again
if ((result=buffered_file_writer_flush(writer)) != 0)
{
break;
}
}
return result;
}
int buffered_file_writer_append_buff(BufferedFileWriter *writer,
const char *buff, const int len)
{
int result;
if (len >= writer->water_mark - writer->current)
{
if ((result=buffered_file_writer_flush(writer)) != 0)
{
return result;
}
if (fc_safe_write(writer->fd, buff, len) != len)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s", __LINE__,
writer->filename, result, STRERROR(result));
return result;
}
return 0;
}
memcpy(writer->current, buff, len);
writer->current += len;
return 0;
}

View File

@ -1,79 +0,0 @@
/*
* 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/>.
*/
#ifndef BUFFERED_FILE_WRITER_H
#define BUFFERED_FILE_WRITER_H
#include "common_define.h"
typedef struct
{
int fd;
int buffer_size;
char filename[MAX_PATH_SIZE];
char *buff;
char *current;
char *buff_end;
char *water_mark;
} BufferedFileWriter;
#ifdef __cplusplus
extern "C" {
#endif
/** open buffered file writer
* parameters:
* writer: the writer
* filename: the filename to write
* buffer_size: the buffer size, <= 0 for recommend 64KB
* max_written_once: max written bytes per call, <= 0 for 256
* mode: the file privilege such as 0644
* return: error code, 0 for success, != 0 for errno
*/
int buffered_file_writer_open_ex(BufferedFileWriter *writer,
const char *filename, const int buffer_size,
const int max_written_once, const int mode);
static inline int buffered_file_writer_open(BufferedFileWriter *writer,
const char *filename)
{
const int buffer_size = 0;
const int max_written_once = 0;
const int mode = 0644;
return buffered_file_writer_open_ex(writer, filename,
buffer_size, max_written_once, mode);
}
/** close buffered file writer
* parameters:
* writer: the writer
* return: error code, 0 for success, != 0 for errno
*/
int buffered_file_writer_close(BufferedFileWriter *writer);
int buffered_file_writer_append(BufferedFileWriter *writer,
const char *format, ...);
int buffered_file_writer_append_buff(BufferedFileWriter *writer,
const char *buff, const int len);
int buffered_file_writer_flush(BufferedFileWriter *writer);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,24 +1,16 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "chain.h"
#include "fc_memory.h"
//#include "use_mmalloc.h"
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
@ -77,7 +69,7 @@ int insertNodePrior(ChainList *pList, void *data)
return EINVAL;
}
pNode = (ChainNode *)fc_malloc(sizeof(ChainNode));
pNode = (ChainNode *)malloc(sizeof(ChainNode));
if (pNode == NULL)
{
return ENOMEM;
@ -103,7 +95,7 @@ int appendNode(ChainList *pList, void *data)
return EINVAL;
}
pNode = (ChainNode *)fc_malloc(sizeof(ChainNode));
pNode = (ChainNode *)malloc(sizeof(ChainNode));
if (pNode == NULL)
{
return ENOMEM;
@ -136,7 +128,7 @@ int insertNodeAsc(ChainList *pList, void *data)
return EINVAL;
}
pNew = (ChainNode *)fc_malloc(sizeof(ChainNode));
pNew = (ChainNode *)malloc(sizeof(ChainNode));
if (pNew == NULL)
{
return ENOMEM;

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#ifndef CHAIN_H
#define CHAIN_H

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//char_convert_loader.h
#ifndef CHAR_CONVERT_LOADER_H

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
@ -27,8 +20,7 @@ int char_converter_init_ex(FastCharConverter *pCharConverter,
const unsigned op)
{
int i;
unsigned char from;
unsigned char to;
unsigned char src;
if (count > FAST_MAX_CHAR_COUNT)
{
logError("file: "__FILE__", line: %d, "
@ -41,15 +33,10 @@ int char_converter_init_ex(FastCharConverter *pCharConverter,
pCharConverter->count = count;
for (i=0; i<count; i++)
{
from = charPairs[i].src;
to = charPairs[i].dest;
pCharConverter->char_table[from].op = op;
pCharConverter->char_table[from].dest = to;
pCharConverter->unescape_chars[to].op = op;
pCharConverter->unescape_chars[to].dest = from;
src = charPairs[i].src;
pCharConverter->char_table[src].op = op;
pCharConverter->char_table[src].dest = charPairs[i].dest;
}
return 0;
}
@ -80,14 +67,14 @@ int std_spaces_add_backslash_converter_init(FastCharConverter *pCharConverter)
#define SPACE_CHAR_PAIR_COUNT2 8
FastCharPair pairs[SPACE_CHAR_PAIR_COUNT2];
FAST_CHAR_MAKE_PAIR(pairs[0], '\0', '0');
FAST_CHAR_MAKE_PAIR(pairs[1], '\t', 't');
FAST_CHAR_MAKE_PAIR(pairs[2], '\n', 'n');
FAST_CHAR_MAKE_PAIR(pairs[3], '\v', 'v');
FAST_CHAR_MAKE_PAIR(pairs[4], '\f', 'f');
FAST_CHAR_MAKE_PAIR(pairs[5], '\r', 'r');
FAST_CHAR_MAKE_PAIR(pairs[6], ' ', 's');
FAST_CHAR_MAKE_PAIR(pairs[7], '\\', '\\');
pairs[0].src = '\0'; pairs[0].dest = '0';
pairs[1].src = '\t'; pairs[1].dest = 't';
pairs[2].src = '\n'; pairs[2].dest = 'n';
pairs[3].src = '\v'; pairs[3].dest = 'v';
pairs[4].src = '\f'; pairs[4].dest = 'f';
pairs[5].src = '\r'; pairs[5].dest = 'r';
pairs[6].src = ' '; pairs[6].dest = '-';
pairs[7].src = '\\'; pairs[7].dest = '\\';
return char_converter_init_ex(pCharConverter, pairs,
SPACE_CHAR_PAIR_COUNT2, FAST_CHAR_OP_ADD_BACKSLASH);
@ -155,7 +142,7 @@ int fast_char_convert(FastCharConverter *pCharConverter,
out_size_sub1 = out_size - 1;
for (; pi<end; pi++) {
if (po - (unsigned char *)output >= out_size_sub1) {
logWarning("file: "__FILE__", line: %d, "
logDebug("file: "__FILE__", line: %d, "
"exceeds max size: %d", __LINE__, out_size);
break;
}
@ -175,47 +162,3 @@ int fast_char_convert(FastCharConverter *pCharConverter,
return count;
}
int fast_char_unescape(FastCharConverter *pCharConverter, char *str, int *len)
{
int count;
unsigned char *backslash;
unsigned char *p;
unsigned char *end;
unsigned char *dest;
backslash = (unsigned char *)memchr(str, '\\', *len);
if (backslash == NULL) {
return 0;
}
count = 0;
end = (unsigned char *)str + *len;
p = dest = backslash;
while (p < end) {
if (*p == '\\') {
if (p + 1 < end) {
if (pCharConverter->unescape_chars[p[1]].op ==
FAST_CHAR_OP_ADD_BACKSLASH)
{
*dest++ = pCharConverter->unescape_chars[p[1]].dest;
p += 2;
++count;
} else {
*dest++ = *p++;
}
} else {
*dest++ = *p++;
}
} else if (pCharConverter->unescape_chars[*p].op ==
FAST_CHAR_OP_NO_BACKSLASH)
{
*dest++ = pCharConverter->unescape_chars[*p++].dest;
++count;
} else {
*dest++ = *p++;
}
}
*len = dest - (unsigned char *)str;
return count;
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//char_converter.h
#ifndef CHAR_CONVERTER_H
@ -31,9 +24,6 @@ extern "C" {
#define FAST_CHAR_OP_ADD_BACKSLASH 1
#define FAST_CHAR_OP_NO_BACKSLASH 2
#define FAST_CHAR_MAKE_PAIR(pair, from, to) \
pair.src = from; pair.dest = to
typedef struct fast_char_pair
{
unsigned char src;
@ -57,11 +47,6 @@ typedef struct fast_char_converter
* char table to convert
* */
FastCharTarget char_table[FAST_MAX_CHAR_COUNT];
/*
* char table to unescape
* */
FastCharTarget unescape_chars[FAST_MAX_CHAR_COUNT];
} FastCharConverter;
/**
@ -148,21 +133,6 @@ int fast_char_convert(FastCharConverter *pCharConverter,
const char *input, const int input_len,
char *output, int *out_len, const int out_size);
#define fast_char_escape(pCharConverter, input, input_len, \
output, out_len, out_size) \
fast_char_convert(pCharConverter, input, input_len, \
output, out_len, out_size)
/**
* char unescape function
* parameters:
* pCharConverter: the char converter
* str: the string to unescape
* len: the input string length and store the unscaped string length
* return: converted char count
*/
int fast_char_unescape(FastCharConverter *pCharConverter, char *str, int *len);
#ifdef __cplusplus
}
#endif

View File

@ -1,311 +0,0 @@
/*
* 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/>.
*/
//common_blocked_queue.c
#include <errno.h>
#include <pthread.h>
#include <inttypes.h>
#include "logger.h"
#include "shared_func.h"
#include "pthread_func.h"
#include "common_blocked_queue.h"
int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
const int alloc_elements_once)
{
const int64_t alloc_elements_limit = 0;
int result;
if ((result=init_pthread_lock_cond_pair(&queue->lc_pair)) != 0)
{
return result;
}
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)
{
return result;
}
queue->head = NULL;
queue->tail = NULL;
return 0;
}
void common_blocked_queue_destroy(struct common_blocked_queue *queue)
{
destroy_pthread_lock_cond_pair(&queue->lc_pair);
fast_mblock_destroy(&queue->mblock);
}
int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
void *data, bool *notify)
{
int result;
struct common_blocked_node *node;
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
node = (struct common_blocked_node *)fast_mblock_alloc_object(
&queue->mblock);
if (node == NULL)
{
pthread_mutex_unlock(&(queue->lc_pair.lock));
return ENOMEM;
}
node->data = data;
node->next = NULL;
if (queue->tail == NULL)
{
queue->head = node;
*notify = true;
}
else
{
queue->tail->next = node;
*notify = false;
}
queue->tail = node;
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
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)
{
struct common_blocked_node *last;
if (node == NULL)
{
return;
}
last = node;
while (last->next != NULL) {
last = last->next;
}
pthread_mutex_lock(&(queue->lc_pair.lock));
last->next = queue->head;
queue->head = node;
if (queue->tail == NULL)
{
queue->tail = last;
}
pthread_mutex_unlock(&(queue->lc_pair.lock));
}
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
const bool blocked)
{
struct common_blocked_node *node;
void *data;
int result;
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return NULL;
}
do {
node = queue->head;
if (node == NULL)
{
if (!blocked)
{
data = NULL;
break;
}
pthread_cond_wait(&(queue->lc_pair.cond), &(queue->lc_pair.lock));
node = queue->head;
}
if (node != NULL)
{
queue->head = node->next;
if (queue->head == NULL)
{
queue->tail = NULL;
}
data = node->data;
fast_mblock_free_object(&queue->mblock, node);
}
else
{
data = NULL;
}
} while (0);
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return data;
}
void *common_blocked_queue_timedpop(struct common_blocked_queue *queue,
const int timeout, const int time_unit)
{
struct common_blocked_node *node;
void *data;
int result;
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_lock fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return NULL;
}
do {
node = queue->head;
if (node == NULL)
{
fc_cond_timedwait(&queue->lc_pair, timeout, time_unit);
node = queue->head;
}
if (node != NULL)
{
queue->head = node->next;
if (queue->head == NULL)
{
queue->tail = NULL;
}
data = node->data;
fast_mblock_free_object(&queue->mblock, node);
}
else
{
data = NULL;
}
} while (0);
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_unlock fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
}
return data;
}
struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
struct common_blocked_queue *queue, const bool blocked)
{
struct common_blocked_node *node;
int result;
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_lock fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return NULL;
}
if (queue->head == NULL)
{
if (blocked)
{
pthread_cond_wait(&(queue->lc_pair.cond), &(queue->lc_pair.lock));
}
}
node = queue->head;
queue->head = queue->tail = NULL;
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
{
logError("file: "__FILE__", line: %d, "
"call pthread_mutex_unlock fail, "
"errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
}
return node;
}
void common_blocked_queue_free_all_nodes(struct common_blocked_queue *queue,
struct common_blocked_node *node)
{
struct common_blocked_node *deleted;
pthread_mutex_lock(&(queue->lc_pair.lock));
while (node != NULL) {
deleted = node;
node = node->next;
fast_mblock_free_object(&queue->mblock, deleted);
}
pthread_mutex_unlock(&(queue->lc_pair.lock));
}

View File

@ -1,206 +0,0 @@
/*
* 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/>.
*/
//common_blocked_queue.h
#ifndef _COMMON_BLOCKED_QUEUE_H
#define _COMMON_BLOCKED_QUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "fast_mblock.h"
struct common_blocked_node
{
void *data;
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;
struct common_blocked_node *tail;
struct fast_mblock_man mblock;
pthread_lock_cond_pair_t lc_pair;
};
#ifdef __cplusplus
extern "C" {
#endif
int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
const int alloc_elements_once);
#define common_blocked_queue_init(queue) \
common_blocked_queue_init_ex(queue, 1024)
void common_blocked_queue_destroy(struct common_blocked_queue *queue);
static inline void common_blocked_queue_terminate(
struct common_blocked_queue *queue)
{
pthread_cond_signal(&(queue->lc_pair.cond));
}
static inline void common_blocked_queue_terminate_all(
struct common_blocked_queue *queue, const int count)
{
int i;
for (i=0; i<count; i++)
{
pthread_cond_signal(&(queue->lc_pair.cond));
}
}
//notify by the caller
int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
void *data, bool *notify);
static inline int common_blocked_queue_push(struct common_blocked_queue
*queue, void *data)
{
bool notify;
int result;
if ((result=common_blocked_queue_push_ex(queue, data, &notify)) == 0)
{
if (notify)
{
pthread_cond_signal(&(queue->lc_pair.cond));
}
}
return result;
}
static inline struct common_blocked_node *common_blocked_queue_alloc_node(
struct common_blocked_queue *queue)
{
struct common_blocked_node *node;
pthread_mutex_lock(&(queue->lc_pair.lock));
node = (struct common_blocked_node *)fast_mblock_alloc_object(&queue->mblock);
pthread_mutex_unlock(&(queue->lc_pair.lock));
return node;
}
static inline void common_blocked_queue_free_node(
struct common_blocked_queue *queue,
struct common_blocked_node *node)
{
pthread_mutex_lock(&(queue->lc_pair.lock));
fast_mblock_free_object(&queue->mblock, node);
pthread_mutex_unlock(&(queue->lc_pair.lock));
}
void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue,
struct common_blocked_chain *chain, bool *notify);
static inline void common_blocked_queue_push_chain(
struct common_blocked_queue *queue,
struct common_blocked_chain *chain)
{
bool notify;
common_blocked_queue_push_chain_ex(queue, chain, &notify);
if (notify)
{
pthread_cond_signal(&(queue->lc_pair.cond));
}
}
void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
struct common_blocked_node *node);
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)
#define common_blocked_queue_try_pop(queue) \
common_blocked_queue_pop_ex(queue, false)
struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
struct common_blocked_queue *queue, const bool blocked);
#define common_blocked_queue_pop_all_nodes(queue) \
common_blocked_queue_pop_all_nodes_ex(queue, true)
#define common_blocked_queue_try_pop_all_nodes(queue) \
common_blocked_queue_pop_all_nodes_ex(queue, false)
#define common_blocked_queue_free_one_node(queue, 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);
void *common_blocked_queue_timedpop(struct common_blocked_queue *queue,
const int timeout, const int time_unit);
#define common_blocked_queue_timedpop_sec(queue, timeout) \
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_SECOND)
#define common_blocked_queue_timedpop_ms(queue, timeout) \
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_MSECOND)
#define common_blocked_queue_timedpop_us(queue, timeout) \
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_USECOND)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//common_define.h
@ -19,9 +12,7 @@
#define _COMMON_DEFINE_H_
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#ifdef WIN32
@ -35,7 +26,6 @@ typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
#else
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <inttypes.h>
@ -43,14 +33,6 @@ 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
@ -68,10 +50,6 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#include "_os_define.h"
#ifdef OS_LINUX
#include <sys/prctl.h>
#endif
#ifdef OS_LINUX
#ifndef PTHREAD_MUTEX_ERRORCHECK
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
@ -102,47 +80,19 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#define USE_SENDFILE
#endif
#define MAX_PATH_SIZE 256
#define MAX_PATH_SIZE 256
#define LOG_FILE_DIR "logs"
#define CONF_FILE_DIR "conf"
#define DEFAULT_CONNECT_TIMEOUT 10
#define DEFAULT_CONNECT_TIMEOUT 30
#define DEFAULT_NETWORK_TIMEOUT 30
#define DEFAULT_MAX_CONNECTONS 256
#define DEFAULT_WORK_THREADS 4
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
#define TIME_NONE -1
#define DEFAULT_MAX_CONNECTONS 256
#define DEFAULT_WORK_THREADS 4
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
#define TIME_NONE -1
#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 IP_ADDRESS_SIZE 16
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
#define FILE_RESOURCE_TAG_STR "file://"
#define FILE_RESOURCE_TAG_LEN (sizeof(FILE_RESOURCE_TAG_STR) - 1)
#define IS_FILE_RESOURCE(filename) \
(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
@ -161,51 +111,11 @@ 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
#define compile_barrier() __asm__ __volatile__("" : : : "memory")
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
#define IS_HEX_CHAR(ch) (IS_UPPER_HEX(ch) || (ch >= 'a' && ch <= 'f'))
#define FC_IS_DIGITAL(ch) (ch >= '0' && ch <= '9')
#define FC_IS_LETTER(ch) ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
#define FC_IS_UPPER_LETTER(ch) (ch >= 'A' && ch <= 'Z')
#define FC_IS_LOWER_LETTER(ch) (ch >= 'a' && ch <= 'z')
#define FC_MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2))
#define FC_MAX(v1, v2) ((v1) > (v2) ? (v1) : (v2))
#define FC_ABS(n) ((n) >= 0 ? (n) : -1 * (n))
#define FC_NEGATIVE(n) ((n) <= 0 ? (n) : -1 * (n))
#define FC_TIME_UNIT_SECOND 's' //second
#define FC_TIME_UNIT_MSECOND 'm' //millisecond
#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)
@ -215,12 +125,10 @@ 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" {
@ -240,12 +148,6 @@ typedef struct
char patch;
} Version;
typedef struct
{
char **strs;
int count;
} str_ptr_array_t;
typedef struct
{
char *key;
@ -267,298 +169,17 @@ typedef struct
int length;
} BufferInfo;
typedef struct
{
char *str;
int len;
} string_t;
typedef struct
{
string_t *strings;
int count;
} string_array_t;
typedef struct
{
int64_t id;
string_t name;
} id_name_pair_t;
typedef struct
{
string_t key;
string_t value;
} key_value_pair_t;
typedef struct
{
key_value_pair_t *kv_pairs;
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;
pthread_cond_t cond;
} pthread_lock_cond_pair_t;
typedef struct
{
int alloc;
int count;
struct iovec *iovs;
} iovec_array_t;
typedef struct
{
char buff[PATH_MAX];
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_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
#define MEM_ALIGN(x) (((x) + 7) & (~7))
#ifdef WIN32
#define strcasecmp _stricmp
#endif
#ifndef likely
#if defined(__GNUC__) && __GNUC__ >= 3
#define likely(cond) __builtin_expect ((cond), 1)
#define unlikely(cond) __builtin_expect ((cond), 0)
#else
#define likely(cond) (cond)
#define unlikely(cond) (cond)
#endif
#endif
#ifdef __GNUC__
#define __gcc_attribute__ __attribute__
#else
#define __gcc_attribute__(x)
#endif
#define FC_IS_CHINESE_UTF8_CHAR(p, end) \
((p + 2 < end) && \
((((unsigned char)*p) & 0xF0) == 0xE0) && \
((((unsigned char)*(p + 1)) & 0xC0) == 0x80) && \
((((unsigned char)*(p + 2)) & 0xC0) == 0x80))
//for printf format %.*s
#define FC_PRINTF_STAR_STRING_PARAMS(s) (s).len, (s).str
#define FC_SET_IOVEC(iovec, buff, len) \
do { \
(iovec).iov_base = buff; \
(iovec).iov_len = len; \
} while (0)
#define FC_SET_STRING(dest, src) \
do { \
(dest).str = src; \
(dest).len = strlen(src); \
} while (0)
#define FC_SET_STRING_EX(dest, s, l) \
do { \
(dest).str = s; \
(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; \
(dest).len = 0; \
} while (0)
#define FC_IS_NULL_STRING(s) ((s)->str == NULL)
#define FC_IS_EMPTY_STRING(s) ((s)->len == 0)
#define FC_INIT_FILENAME_STRING(filename) \
FC_SET_STRING_EX((filename).s, (filename).buff, 0)
#define FC_FILENAME_STRING_OBJ(filename) ((filename).s)
#define FC_FILENAME_STRING_PTR(filename) ((filename).buff)
#define FC_FILENAME_BUFFER_SIZE(filename) sizeof((filename).buff)
#define fc_compare_string(s1, s2) fc_string_compare(s1, s2)
static inline int fc_string_compare(const string_t *s1, const string_t *s2)
{
int result;
if (s1->len == s2->len) {
return memcmp(s1->str, s2->str, s1->len);
} else if (s1->len < s2->len) {
result = memcmp(s1->str, s2->str, s1->len);
return result == 0 ? -1 : result;
} else {
result = memcmp(s1->str, s2->str, s2->len);
return result == 0 ? 1 : result;
}
}
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);
}
static inline bool fc_string_equal2(const string_t *s1,
const char *str2, const int len2)
{
return (s1->len == len2) && (memcmp(s1->str, str2, s1->len) == 0);
}
#define fc_string_equals(s1, s2) fc_string_equal(s1, s2)
#define fc_string_equals2(s1, str2, len2) fc_string_equal2(s1, str2, len2)
#define fc_case_compare_string(s1, s2) fc_string_case_compare(s1, s2)
static inline int fc_string_case_compare(const string_t *s1, const string_t *s2)
{
int result;
if (s1->len == s2->len) {
return strncasecmp(s1->str, s2->str, s1->len);
} else if (s1->len < s2->len) {
result = strncasecmp(s1->str, s2->str, s1->len);
return result == 0 ? -1 : result;
} else {
result = strncasecmp(s1->str, s2->str, s2->len);
return result == 0 ? 1 : result;
}
}
static inline bool fc_string_case_equal(const string_t *s1, const string_t *s2)
{
return (s1->len == s2->len) && (strncasecmp(s1->str, s2->str, s1->len) == 0);
}
static inline bool fc_string_case_equal2(const string_t *s1,
const char *str2, const int len2)
{
return (s1->len == len2) && (strncasecmp(s1->str, str2, s1->len) == 0);
}
#define fc_string_case_equals(s1, s2) fc_string_case_equal(s1, s2)
#define fc_string_case_equals2(s1, str2, len2) \
fc_string_case_equal2(s1, str2, len2)
static inline int fc_compare_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;
}
}
#ifdef OS_LINUX
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
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//connection_pool.h
@ -23,125 +16,21 @@
#include <string.h>
#include <time.h>
#include "common_define.h"
#include "fast_mblock.h"
#include "ini_file_reader.h"
#include "pthread_func.h"
#include "sockopt.h"
#include "hash.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FC_CONNECTION_SERVER_EQUAL(conn, target_ip, target_port) \
(strcmp((conn).ip_addr, target_ip) == 0 && \
(conn).port == target_port)
#define FC_CONNECTION_SERVER_EQUAL1(conn1, conn2) \
(strcmp((conn1).ip_addr, (conn2).ip_addr) == 0 && \
(conn1).port == (conn2).port)
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[IP_ADDRESS_SIZE];
void *arg1; //for RDMA
char args[0]; //for extra data
typedef struct
{
int sock;
int port;
char ip_addr[INET6_ADDRSTRLEN];
int socket_domain; //socket domain, AF_INET, AF_INET6 or PF_UNSPEC for auto dedect
} 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;
typedef struct tagConnectionNode {
@ -152,75 +41,26 @@ typedef struct tagConnectionNode {
} ConnectionNode;
typedef struct tagConnectionManager {
string_t key;
ConnectionNode *head;
int total_count; //total connections
int free_count; //free connections
struct tagConnectionManager *next;
ConnectionNode *head;
int total_count; //total connections
int free_count; //free connections
pthread_mutex_t lock;
} ConnectionManager;
typedef struct tagConnectionBucket {
ConnectionManager *head;
pthread_mutex_t lock;
} ConnectionBucket;
struct tagConnectionPool;
typedef struct {
ConnectionNode **buckets;
struct tagConnectionPool *cp;
} ConnectionThreadHashTable;
typedef struct tagConnectionPool {
struct {
ConnectionBucket *buckets;
uint32_t capacity;
} hashtable;
int connect_timeout_ms;
HashArray hash_array; //key is ip:port, value is ConnectionManager
pthread_mutex_t lock;
int connect_timeout;
int max_count_per_entry; //0 means no limit
/*
connections whose idle time exceeds this time will be closed
connections whose the idle time exceeds this time will be closed
unit: second
*/
int max_idle_time;
struct fast_mblock_man manager_allocator;
struct fast_mblock_man node_allocator;
struct {
fc_connection_callback_func func;
void *args;
} connect_done_callback;
struct {
fc_connection_callback_func func;
void *args;
} validate_callback;
int extra_data_size;
ConnectionExtraParams extra_params;
pthread_key_t tls_key; //for ConnectionThreadHashTable
int socket_domain; //socket domain
} 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:
@ -228,43 +68,12 @@ int conn_pool_global_init_for_rdma();
* 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
* 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
* socket_domain: the socket domain
* return 0 for success, != 0 for error
*/
int conn_pool_init_ex1(ConnectionPool *cp, const int connect_timeout,
int conn_pool_init_ex(ConnectionPool *cp, int connect_timeout,
const int max_count_per_entry, const int max_idle_time,
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
* parameters:
* cp: the ConnectionPool
* 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
* return 0 for success, != 0 for error
*/
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_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, htable_capacity, NULL, NULL, NULL, NULL,
extra_data_size, extra_params);
}
const int socket_domain);
/**
* init function
@ -275,16 +84,8 @@ static inline int conn_pool_init_ex(ConnectionPool *cp,
* 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, const int connect_timeout,
const int max_count_per_entry, const int max_idle_time)
{
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, htable_capacity, NULL, NULL, NULL, NULL,
extra_data_size, extra_params);
}
int conn_pool_init(ConnectionPool *cp, int connect_timeout,
const int max_count_per_entry, const int max_idle_time);
/**
* destroy function
@ -299,17 +100,11 @@ 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_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)
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
const ConnectionInfo *conn, int *err_no);
#define conn_pool_close_connection(cp, conn) \
conn_pool_close_connection_ex(cp, conn, false)
@ -322,220 +117,35 @@ ConnectionInfo *conn_pool_get_connection_ex(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:
* conn: the connection
* pConnection: the connection
* return 0 for success, != 0 for error
*/
static inline void conn_pool_disconnect_server(ConnectionInfo *conn)
{
if (conn->sock >= 0)
{
close(conn->sock);
conn->sock = -1;
}
}
static inline bool conn_pool_is_connected(ConnectionInfo *conn)
{
return (conn->sock >= 0);
}
void conn_pool_disconnect_server(ConnectionInfo *pConnection);
/**
* connect to the server
* parameters:
* pConnection: the connection
* 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
* 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
*/
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);
}
int conn_pool_connect_server(ConnectionInfo *pConnection, \
const int connect_timeout);
/**
* 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_ms)
{
const char *service_name = NULL;
const char *bind_ipaddr = NULL;
pConnection->sock = -1;
return conn_pool_connect_server_ex1(pConnection, service_name,
connect_timeout_ms, bind_ipaddr, true);
}
/**
* async connect to the server
* parameters:
* pConnection: the connection
* bind_ipaddr: the ip address to bind, NULL or empty for any
* NOTE: pConnection->sock will be closed when it >= 0 before connect
* return 0 or EINPROGRESS for success, others for error
*/
int conn_pool_async_connect_server_ex(ConnectionInfo *conn,
const char *bind_ipaddr);
#define conn_pool_async_connect_server(conn) \
conn_pool_async_connect_server_ex(conn, NULL)
/**
* connection pool stat
* get connection count of the pool
* parameters:
* cp: the ConnectionPool
* stat: the output stat
* return none
* return current connection count
*/
void conn_pool_stat(ConnectionPool *cp, ConnectionPoolStat *stat);
/**
* load server info from config file
* parameters:
* pIniContext: the ini context
* filename: the config filename
* item_name: the item name in config file, format item_name=server:port
* pServerInfo: store server info
* default_port: the default port
* return 0 for success, != 0 for error
*/
int conn_pool_load_server_info(IniContext *pIniContext, const char *filename,
const char *item_name, ConnectionInfo *pServerInfo,
const int default_port);
/**
* parse server info from string
* parameters:
* pServerStr: server and port string as server:port
* pServerInfo: store server info
* default_port: the default port
* return 0 for success, != 0 for error
*/
int conn_pool_parse_server_info(const char *pServerStr,
ConnectionInfo *pServerInfo, const int default_port);
/**
* set server info with ip address and port
* parameters:
* pServerInfo: store server info
* ip_addr: the ip address
* port: the port
* return none
*/
static inline void conn_pool_set_server_info(ConnectionInfo *pServerInfo,
const char *ip_addr, const int port)
{
fc_safe_strcpy(pServerInfo->ip_addr, ip_addr);
pServerInfo->port = port;
pServerInfo->af = is_ipv6_addr(ip_addr) ? AF_INET6 : AF_INET;
pServerInfo->sock = -1;
}
static inline int conn_pool_compare_ip_and_port(const char *ip1,
const int port1, const char *ip2, const int port2)
{
int result;
if ((result=strcmp(ip1, ip2)) != 0) {
return result;
}
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";
}
}
int conn_pool_get_connection_count(ConnectionPool *cp);
#ifdef __cplusplus
}

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
//fast_allocator.c
#include <errno.h>
@ -25,6 +10,14 @@
#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; \
@ -32,8 +25,7 @@
(allocator)->pooled = _pooled; \
acontext->allocator_array.allocators[ \
acontext->allocator_array.count++] = allocator; \
/* logInfo("count: %d, magic_number: %d", acontext->allocator_array.count, \
(allocator)->magic_number); */ \
/* logInfo("count: %d, magic_number: %d", acontext->allocator_array.count, (allocator)->magic_number); */\
} while (0)
@ -55,72 +47,53 @@ 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 enum fast_mblock_notify_type type,
const struct fast_mblock_malloc *node, void *args)
static void fast_allocator_malloc_trunk_notify_func(const int alloc_bytes, void *args)
{
if (type == fast_mblock_notify_type_alloc)
if (alloc_bytes > 0)
{
__sync_add_and_fetch(&((struct fast_allocator_context *)args)->
allocator_array.malloc_bytes, node->trunk_size);
allocator_array.malloc_bytes, alloc_bytes);
}
else
{
__sync_sub_and_fetch(&((struct fast_allocator_context *)args)->
allocator_array.malloc_bytes, node->trunk_size);
allocator_array.malloc_bytes, -1 * alloc_bytes);
}
}
static int allocator_array_check_capacity(struct fast_allocator_context *acontext,
const int allocator_count)
{
int result;
int bytes;
int target_count;
int alloc_count;
struct fast_allocator_info **new_allocators;
target_count = acontext->allocator_array.count + allocator_count;
if (acontext->allocator_array.alloc >= target_count)
if (acontext->allocator_array.alloc >= acontext->allocator_array.count +
allocator_count)
{
return 0;
}
if (acontext->allocator_array.alloc == 0)
{
if (target_count < 128)
{
alloc_count = 128;
}
else if (target_count < 256)
{
alloc_count = 256;
}
else if (target_count < 512)
{
alloc_count = 512;
}
else if (target_count < 1024)
{
alloc_count = 1024;
}
else
{
alloc_count = 2 * target_count;
}
acontext->allocator_array.alloc = 2 * allocator_count;
}
else
{
alloc_count = acontext->allocator_array.alloc;
do
{
alloc_count *= 2;
} while (alloc_count < target_count);
acontext->allocator_array.alloc *= 2;
} while (acontext->allocator_array.alloc < allocator_count);
}
bytes = sizeof(struct fast_allocator_info *) * alloc_count;
new_allocators = (struct fast_allocator_info **)fc_malloc(bytes);
bytes = sizeof(struct fast_allocator_info*) * acontext->allocator_array.alloc;
new_allocators = (struct fast_allocator_info **)malloc(bytes);
if (new_allocators == NULL)
{
return ENOMEM;
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, errno: %d, error info: %s",
__LINE__, bytes, result, STRERROR(result));
return result;
}
if (acontext->allocator_array.allocators != NULL)
@ -130,73 +103,48 @@ static int allocator_array_check_capacity(struct fast_allocator_context *acontex
acontext->allocator_array.count);
free(acontext->allocator_array.allocators);
}
acontext->allocator_array.alloc = alloc_count;
acontext->allocator_array.allocators = new_allocators;
return 0;
}
static int region_init(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, struct fast_mblock_object_callbacks
*object_callbacks, struct fast_region_info *region)
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;
struct fast_mblock_trunk_callbacks trunk_callbacks;
int allocator_count;
struct fast_allocator_info *allocator;
char *name;
char name_buff[FAST_MBLOCK_NAME_SIZE];
region->pad_mask = region->step - 1;
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);
allocator_count = (region->end - region->start) / region->step;
bytes = sizeof(struct fast_allocator_info) * allocator_count;
region->allocators = (struct fast_allocator_info *)malloc(bytes);
if (region->allocators == NULL)
{
return ENOMEM;
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, errno: %d, error info: %s",
__LINE__, bytes, result, STRERROR(result));
return result;
}
memset(region->allocators, 0, bytes);
if ((result=allocator_array_check_capacity(acontext, region->count)) != 0)
if ((result=allocator_array_check_capacity(acontext, allocator_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++)
{
if (mblock_name_prefix != NULL)
{
snprintf(name, FAST_MBLOCK_NAME_SIZE, "%s-%d",
mblock_name_prefix, element_size);
}
else
{
name = NULL;
}
trunk_callbacks.args = acontext;
result = fast_mblock_init_ex2(&allocator->mblock, name, element_size,
region->alloc_elements_once, alloc_elements_limit,
prealloc_trunk_count, object_callbacks,
acontext->need_lock, &trunk_callbacks);
for (element_size=region->start+region->step; element_size<=region->end;
element_size+=region->step,allocator++)
{
result = fast_mblock_init_ex2(&allocator->mblock, NULL, element_size,
region->alloc_elements_once, NULL, acontext->need_lock,
fast_allocator_malloc_trunk_check,
fast_allocator_malloc_trunk_notify_func, acontext);
if (result != 0)
{
break;
@ -226,11 +174,9 @@ static void region_destroy(struct fast_allocator_context *acontext,
}
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
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)
const int reclaim_interval, const bool need_lock)
{
int result;
int bytes;
@ -246,10 +192,14 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
}
bytes = sizeof(struct fast_region_info) * region_count;
acontext->regions = (struct fast_region_info *)fc_malloc(bytes);
acontext->regions = (struct fast_region_info *)malloc(bytes);
if (acontext->regions == NULL)
{
return ENOMEM;
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, errno: %d, error info: %s",
__LINE__, bytes, result, STRERROR(result));
return result;
}
memcpy(acontext->regions, regions, bytes);
acontext->region_count = region_count;
@ -265,7 +215,6 @@ 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;
@ -288,46 +237,33 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
result = EINVAL;
break;
}
if (pRegion->step <= 0)
if (pRegion->step <= 0 || !is_power2(pRegion->step))
{
logError("file: "__FILE__", line: %d, "
"invalid step: %d <= 0",
"invalid step: %d",
__LINE__, 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;
}
}
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,
object_callbacks, pRegion)) != 0)
if ((result=region_init(acontext, pRegion)) != 0)
{
break;
}
@ -343,35 +279,39 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
return result;
}
ADD_ALLOCATOR_TO_ARRAY(acontext, &acontext->
allocator_array.malloc_allocator, false);
ADD_ALLOCATOR_TO_ARRAY(acontext, &malloc_allocator, false);
/*
logInfo("sizeof(struct fast_allocator_wrapper): %d, allocator_array count: %d",
(int)sizeof(struct fast_allocator_wrapper), acontext->allocator_array.count);
logInfo("sizeof(struct allocator_wrapper): %d, allocator_array count: %d",
(int)sizeof(struct allocator_wrapper), acontext->allocator_array.count);
*/
return result;
}
#define INIT_REGION(region, _start, _end, _step, _alloc_once) \
do { \
region.start = _start; \
region.end = _end; \
region.step = _step; \
region.alloc_elements_once = _alloc_once; \
} while(0)
int fast_allocator_init(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, const int64_t alloc_bytes_limit,
const double expect_usage_ratio, const int reclaim_interval,
const bool need_lock)
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
const int reclaim_interval, const bool need_lock)
{
#define DEFAULT_REGION_COUNT 5
const int obj_size = 0;
struct fast_region_info regions[DEFAULT_REGION_COUNT];
struct fast_region_info regions[DEFAULT_REGION_COUNT];
FAST_ALLOCATOR_INIT_REGION(regions[0], 0, 256, 8, 4096);
FAST_ALLOCATOR_INIT_REGION(regions[1], 256, 1024, 16, 1024);
FAST_ALLOCATOR_INIT_REGION(regions[2], 1024, 4096, 64, 256);
FAST_ALLOCATOR_INIT_REGION(regions[3], 4096, 16384, 256, 64);
FAST_ALLOCATOR_INIT_REGION(regions[4], 16384, 65536, 1024, 16);
INIT_REGION(regions[0], 0, 256, 8, 4096);
INIT_REGION(regions[1], 256, 1024, 16, 1024);
INIT_REGION(regions[2], 1024, 4096, 64, 256);
INIT_REGION(regions[3], 4096, 16384, 256, 64);
INIT_REGION(regions[4], 16384, 65536, 1024, 16);
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);
return fast_allocator_init_ex(acontext, regions,
DEFAULT_REGION_COUNT, alloc_bytes_limit,
expect_usage_ratio, reclaim_interval, need_lock);
}
void fast_allocator_destroy(struct fast_allocator_context *acontext)
@ -396,8 +336,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;
@ -406,19 +346,14 @@ static struct fast_allocator_info *get_allocator(struct fast_allocator_context
for (pRegion=acontext->regions; pRegion<region_end; pRegion++)
{
if (*alloc_bytes <= pRegion->end)
{
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;
}
}
{
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
return pRegion->allocators + ((*alloc_bytes -
pRegion->start) / pRegion->step) - 1;
}
}
return &acontext->allocator_array.malloc_allocator;
return &malloc_allocator;
}
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
@ -437,10 +372,8 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
acontext->allocator_array.last_reclaim_time = get_current_time();
malloc_bytes = acontext->allocator_array.malloc_bytes;
/*
logInfo("malloc_bytes: %"PRId64", ratio: %f", malloc_bytes,
(double)acontext->alloc_bytes / (double)malloc_bytes);
*/
logInfo("malloc_bytes: %"PRId64", ratio: %f", malloc_bytes, (double)acontext->alloc_bytes /
(double)malloc_bytes);
if (malloc_bytes == 0 || (double)acontext->alloc_bytes /
(double)malloc_bytes >= acontext->allocator_array.expect_usage_ratio)
@ -448,12 +381,12 @@ 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)
{
//logInfo("reclaim_count: %d", reclaim_count);
logInfo("reclaim_count: %d", reclaim_count);
*total_reclaim_bytes += reclaim_count *
acontext->allocator_array.allocators[i]->
mblock.info.trunk_size;
@ -463,15 +396,6 @@ 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)
{
@ -479,21 +403,20 @@ 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 = acontext->extra_size + bytes;
alloc_bytes = sizeof(struct allocator_wrapper) + 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;
}
@ -501,7 +424,7 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
{
return NULL;
}
//logInfo("reclaimed bytes: %"PRId64, total_reclaim_bytes);
logInfo("reclaimed bytes: %"PRId64, total_reclaim_bytes);
if (total_reclaim_bytes < allocator_info->mblock.info.trunk_size)
{
return NULL;
@ -512,7 +435,6 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
return NULL;
}
}
obj = (char *)ptr + sizeof(struct fast_allocator_wrapper);
}
else
{
@ -520,47 +442,34 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
{
return NULL;
}
ptr = fc_malloc(alloc_bytes);
ptr = malloc(alloc_bytes);
if (ptr == NULL)
{
return NULL;
}
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);
}
fast_allocator_malloc_trunk_notify_func(alloc_bytes, acontext);
}
((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;
((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;
__sync_add_and_fetch(&acontext->alloc_bytes, alloc_bytes);
return obj;
return (char *)ptr + sizeof(struct allocator_wrapper);
}
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
{
struct fast_allocator_wrapper *pWrapper;
struct allocator_wrapper *pWrapper;
struct fast_allocator_info *allocator_info;
void *ptr;
if (obj == NULL)
void *obj;
if (ptr == NULL)
{
return;
}
ptr = (char *)obj - sizeof(struct fast_allocator_wrapper);
pWrapper = (struct fast_allocator_wrapper *)ptr;
obj = (char *)ptr - sizeof(struct allocator_wrapper);
pWrapper = (struct allocator_wrapper *)obj;
if (pWrapper->allocator_index < 0 || pWrapper->allocator_index >=
acontext->allocator_array.count)
{
@ -570,8 +479,7 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
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, "
@ -586,36 +494,12 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
pWrapper->magic_number = 0;
if (allocator_info->pooled)
{
fast_mblock_free_object(&allocator_info->mblock, ptr);
fast_mblock_free_object(&allocator_info->mblock, obj);
}
else
{
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);
}
{
fast_allocator_malloc_trunk_notify_func(-1 * pWrapper->alloc_bytes, acontext);
free(obj);
}
}
char *fast_allocator_memdup(struct fast_allocator_context *acontext,
const char *src, const int len)
{
char *dest;
dest = (char *)fast_allocator_alloc(acontext, len);
if (dest == NULL) {
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, len);
return NULL;
}
memcpy(dest, src, len);
return dest;
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//fast_allocator.h
@ -35,55 +28,38 @@ struct fast_allocator_info
struct fast_region_info
{
int start; //exclude
int end; //include
int start;
int end;
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 malloc_allocator;
struct fast_allocator_info **allocators;
};
struct fast_allocator_wrapper {
int alloc_bytes;
short allocator_index;
short magic_number;
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;
};
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; //water mark bytes for alloc
int64_t alloc_bytes_limit; //mater 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; \
} while(0)
#ifdef __cplusplus
extern "C" {
#endif
@ -92,39 +68,32 @@ extern "C" {
allocator init by default region allocators
parameters:
acontext: the context pointer
mblock_name_prefix: the name prefix of mblock
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(struct fast_allocator_context *acontext,
const char *mblock_name_prefix, const int64_t alloc_bytes_limit,
const double expect_usage_ratio, const int reclaim_interval,
const bool need_lock);
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
const int reclaim_interval, const bool need_lock);
/**
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, 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);
const int reclaim_interval, const bool need_lock);
/**
allocator destroy
@ -147,10 +116,10 @@ void* fast_allocator_alloc(struct fast_allocator_context *acontext,
free a node (put a node to the context)
parameters:
acontext: the context pointer
obj: the object ptr to free
ptr: the pointer to free
return none
*/
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj);
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr);
/**
retry reclaim free trunks
@ -162,48 +131,9 @@ return error no, 0 for success, != 0 fail
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
int64_t *total_reclaim_bytes);
char *fast_allocator_memdup(struct fast_allocator_context *acontext,
const char *src, const int len);
static inline char *fast_allocator_strdup_ex(struct fast_allocator_context *
acontext, const char *src, const int len)
{
return fast_allocator_memdup(acontext, src, len + 1);
}
static inline char *fast_allocator_strdup(struct fast_allocator_context *
acontext, const char *src)
{
return fast_allocator_memdup(acontext, src, strlen(src) + 1);
}
static inline int fast_allocator_alloc_string_ex(struct fast_allocator_context
*acontext, string_t *dest, const char *src, const int len)
{
dest->str = fast_allocator_memdup(acontext, src, len);
dest->len = len;
return dest->str != NULL ? 0 : ENOMEM;
}
static inline int fast_allocator_alloc_string(struct fast_allocator_context
*acontext, string_t *dest, const string_t *src)
{
return fast_allocator_alloc_string_ex(acontext, dest, src->str, src->len);
}
static inline int64_t fast_allocator_avail_memory(
struct fast_allocator_context *acontext)
{
if (acontext->alloc_bytes_limit == 0) {
return INT64_MIN;
}
return acontext->alloc_bytes_limit - __sync_add_and_fetch(
&acontext->allocator_array.malloc_bytes, 0);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
//fast_blocked_queue.c
#include <errno.h>

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//fast_blocked_queue.h
@ -45,19 +38,8 @@ static inline void blocked_queue_terminate(struct fast_blocked_queue *pQueue)
pthread_cond_signal(&(pQueue->cond));
}
static inline void blocked_queue_terminate_all(struct fast_blocked_queue *pQueue,
const int count)
{
int i;
for (i=0; i<count; i++)
{
pthread_cond_signal(&(pQueue->cond));
}
}
int blocked_queue_push(struct fast_blocked_queue *pQueue,
struct fast_task_info *pTask);
struct fast_task_info *blocked_queue_pop(struct fast_blocked_queue *pQueue);
#ifdef __cplusplus

View File

@ -1,18 +1,3 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -20,34 +5,28 @@
#include <unistd.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/stat.h>
#include "logger.h"
#include "shared_func.h"
#include "fc_memory.h"
#include "fast_buffer.h"
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity,
const bool binary_mode, const bool check_capacity)
int fast_buffer_init_ex(FastBuffer *buffer, const int init_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);
buffer->data = (char *)malloc(buffer->alloc_size);
if (buffer->data == NULL)
{
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, buffer->alloc_size);
return ENOMEM;
}
fast_buffer_set_null_terminator(buffer);
*(buffer->data) = '\0';
return 0;
}
@ -61,41 +40,32 @@ void fast_buffer_destroy(FastBuffer *buffer)
}
}
int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity)
static int fast_buffer_check(FastBuffer *buffer, const int inc_len)
{
int alloc_size;
int new_capacity;
char *buff;
new_capacity = FC_MAX(capacity, buffer->length + 1);
if (buffer->alloc_size >= new_capacity) {
if (new_capacity > 1024) {
alloc_size = 2048;
} else if (new_capacity > 512) {
alloc_size = 1024;
} else if (new_capacity > 256) {
alloc_size = 512;
} else {
alloc_size = 256;
}
} else {
alloc_size = buffer->alloc_size * 2;
if (buffer->alloc_size > buffer->length + inc_len)
{
return 0;
}
while (alloc_size < new_capacity) {
alloc_size = buffer->alloc_size * 2;
while (alloc_size <= buffer->length + inc_len)
{
alloc_size *= 2;
}
buff = (char *)fc_malloc(alloc_size);
if (buff == NULL) {
buff = (char *)malloc(alloc_size);
if (buff == NULL)
{
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, alloc_size);
return ENOMEM;
}
if (buffer->length > 0) {
if (buffer->length > 0)
{
memcpy(buff, buffer->data, buffer->length);
if (!buffer->binary_mode) {
*(buff + buffer->length) = '\0';
}
}
free(buffer->data);
@ -125,7 +95,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
}
else //maybe full, realloc and try again
{
if ((result=fast_buffer_check(buffer, len + 1)) == 0)
if ((result=fast_buffer_check(buffer, len)) == 0)
{
va_start(ap, format);
buffer->length += vsnprintf(buffer->data + buffer->length,
@ -134,7 +104,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
}
else
{
fast_buffer_set_null_terminator(buffer); //restore
*(buffer->data + buffer->length) = '\0'; //restore
}
}
return result;
@ -144,26 +114,6 @@ int fast_buffer_append_buff(FastBuffer *buffer, const char *data, const int len)
{
int result;
if (len <= 0)
{
return 0;
}
if ((result=fast_buffer_check(buffer, len + 1)) != 0)
{
return result;
}
memcpy(buffer->data + buffer->length, data, len);
buffer->length += len;
fast_buffer_set_null_terminator(buffer);
return 0;
}
int fast_buffer_append_binary(FastBuffer *buffer,
const void *data, const int len)
{
int result;
if (len <= 0)
{
return 0;
@ -175,49 +125,33 @@ int fast_buffer_append_binary(FastBuffer *buffer,
memcpy(buffer->data + buffer->length, data, len);
buffer->length += len;
*(buffer->data + buffer->length) = '\0';
return 0;
}
int fast_buffer_append_file(FastBuffer *buffer, const char *filename)
int fast_buffer_append_int(FastBuffer *buffer, const int n)
{
struct stat st;
int result;
int64_t file_size;
if (stat(filename, &st) != 0) {
result = errno != 0 ? errno : ENOENT;
if (result == ENOENT) {
logError("file: "__FILE__", line: %d, "
"file %s not exist!", __LINE__,
filename);
} else {
logError("file: "__FILE__", line: %d, "
"stat file %s fail, "
"result: %d, error info: %s", __LINE__,
filename, result, strerror(result));
}
return result;
}
if (!S_ISREG(st.st_mode)) {
logError("file: "__FILE__", line: %d, "
"file %s is NOT a regular file!",
__LINE__, filename);
return EINVAL;
}
file_size = st.st_size + 1;
if ((result=fast_buffer_check(buffer, file_size)) != 0) {
return result;
}
if ((result=getFileContentEx(filename, buffer->data + buffer->length,
0, &file_size)) != 0)
if ((result=fast_buffer_check(buffer, 16)) != 0)
{
return result;
}
buffer->length += file_size;
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;
}

View File

@ -1,30 +1,12 @@
/*
* 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/>.
*/
#ifndef __FAST_BUFFER_H__
#define __FAST_BUFFER_H__
#include <stdint.h>
#include "shared_func.h"
typedef struct fast_buffer {
char *data;
int alloc_size;
int length;
bool binary_mode;
bool check_capacity;
} FastBuffer;
#ifdef __cplusplus
@ -41,123 +23,36 @@ static inline char *fast_buffer_data(FastBuffer *buffer)
return buffer->data;
}
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);
}
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity);
static inline int fast_buffer_init(FastBuffer *buffer)
{
const int init_capacity = 0;
return fast_buffer_init1(buffer, init_capacity);
return fast_buffer_init_ex(buffer, 0);
}
#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;
fast_buffer_set_null_terminator(buffer);
*buffer->data = '\0';
}
void fast_buffer_destroy(FastBuffer *buffer);
int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity);
static inline int fast_buffer_check_capacity(FastBuffer *buffer,
const int capacity)
{
if (buffer->alloc_size >= capacity)
{
return 0;
}
return fast_buffer_set_capacity(buffer, capacity);
}
static inline int fast_buffer_check_inc_size(FastBuffer *buffer,
const int inc_size)
{
return fast_buffer_check_capacity(buffer, buffer->length + inc_size);
}
int fast_buffer_append(FastBuffer *buffer, const char *format, ...);
int fast_buffer_append_buff(FastBuffer *buffer,
const char *data, const int len);
int fast_buffer_append_buff(FastBuffer *buffer, const char *data, const int len);
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;
if ((result=fast_buffer_check(buffer, 1)) != 0)
{
return result;
}
*(buffer->data + buffer->length++) = ch;
fast_buffer_set_null_terminator(buffer);
return 0;
}
static inline int fast_buffer_append_int32(FastBuffer *buffer, const int n)
{
int result;
if ((result=fast_buffer_check(buffer, 16)) != 0)
{
return result;
}
buffer->length += fc_itoa(n, buffer->data + buffer->length);
fast_buffer_set_null_terminator(buffer);
return 0;
}
static inline int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n)
{
int result;
if ((result=fast_buffer_check(buffer, 32)) != 0)
{
return result;
}
buffer->length += fc_itoa(n, buffer->data + buffer->length);
fast_buffer_set_null_terminator(buffer);
return 0;
}
#define fast_buffer_append_int(buffer, n) \
fast_buffer_append_int64(buffer, n)
int fast_buffer_append_file(FastBuffer *buffer, const char *filename);
int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n);
static inline int fast_buffer_append_string(FastBuffer *buffer, const char *str)
{
return fast_buffer_append_buff(buffer, str, strlen(str));
}
static inline int fast_buffer_append_string2(FastBuffer *buffer, const string_t *add)
{
return fast_buffer_append_buff(buffer, add->str, add->len);
}
static inline int fast_buffer_append_buffer(FastBuffer *buffer, FastBuffer *src)
{
return fast_buffer_append_buff(buffer, src->data, src->length);
@ -168,3 +63,4 @@ static inline int fast_buffer_append_buffer(FastBuffer *buffer, FastBuffer *src)
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//fast_mblock.h
@ -23,46 +16,23 @@
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "fc_memory.h"
#include "logger.h"
/* following two macros for debug only */
/*
#define FAST_MBLOCK_MAGIC_CHECK 1
#define FAST_MBLOCK_MAGIC_NUMBER 1234567890
*/
#include "chain.h"
#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
{
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
};
/* malloc chain */
struct fast_mblock_malloc
{
int64_t ref_count; //refference count
int alloc_count; //allocated element count
int trunk_size; //trunk bytes
int64_t ref_count; //refference count
struct fast_mblock_malloc *prev;
struct fast_mblock_malloc *next;
};
@ -72,31 +42,24 @@ struct fast_mblock_chain {
struct fast_mblock_node *tail;
};
/* 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_alloc_init_func)(void *element);
typedef int (*fast_mblock_malloc_trunk_check_func)(
const int alloc_bytes, void *args);
typedef void (*fast_mblock_malloc_trunk_notify_func)(
const enum fast_mblock_notify_type type,
const struct fast_mblock_malloc *node, void *args);
const int alloc_bytes, void *args);
struct fast_mblock_info
{
char name[FAST_MBLOCK_NAME_SIZE];
int element_size; //element size
int element_total_count; //total element count
int element_used_count; //used element count
int trunk_size; //trunk size
int trunk_total_count; //total trunk count
int trunk_used_count; //used trunk count
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
int64_t trunk_total_count; //total trunk count
int64_t trunk_used_count; //used trunk count
};
struct fast_mblock_trunks
@ -104,13 +67,7 @@ struct fast_mblock_trunks
struct fast_mblock_malloc head; //malloc chain to be freed
};
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
struct fast_mblock_malloc_trunk_callback
{
fast_mblock_malloc_trunk_check_func check_func;
fast_mblock_malloc_trunk_notify_func notify_func;
@ -120,35 +77,24 @@ struct fast_mblock_trunk_callbacks
struct fast_mblock_man
{
struct fast_mblock_info info;
struct {
bool need_wait;
int exceed_log_level; //for exceed limit
int once; //alloc elements once
int64_t limit; //<= 0 for no limit
bool *pcontinue_flag;
} alloc_elements;
struct {
struct fast_mblock_node *head;
} freelist; //free node chain
int alloc_elements_once; //alloc elements once
struct fast_mblock_node *free_chain_head; //free node chain
struct fast_mblock_trunks trunks;
struct fast_mblock_chain delay_free_chain; //delay free node chain
struct fast_mblock_object_callbacks object_callbacks;
struct fast_mblock_trunk_callbacks trunk_callbacks;
fast_mblock_alloc_init_func alloc_init_func;
struct fast_mblock_malloc_trunk_callback malloc_trunk_callback;
bool need_lock; //if need mutex lock
pthread_lock_cond_pair_t lcp; //for read / write free node chain
bool need_lock; //if need mutex lock
pthread_mutex_t lock; //the lock for read / write free node chain
struct fast_mblock_man *prev; //for stat manager
struct fast_mblock_man *next; //for stat manager
};
#define fast_mblock_get_block_size(element_size) \
(MEM_ALIGN(sizeof(struct fast_mblock_node) + element_size))
#define GET_BLOCK_SIZE(info) \
(MEM_ALIGN(sizeof(struct fast_mblock_node) + (info).element_size))
#define fast_mblock_get_trunk_size(block_size, element_count) \
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
#define fast_mblock_get_block_size(mblock) GET_BLOCK_SIZE(mblock->info)
#define fast_mblock_to_node_ptr(data_ptr) \
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
@ -159,8 +105,21 @@ extern "C" {
#endif
#define fast_mblock_init(mblock, element_size, alloc_elements_once) \
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \
0, NULL, NULL, true)
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, 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
init_func: the init function
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,
fast_mblock_alloc_init_func init_func, const bool need_lock);
/**
mblock init
@ -169,19 +128,19 @@ 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
prealloc_trunk_count: prealloc trunk node count
object_callbacks: the object callback functions and args
init_func: the init function
need_lock: if need lock
trunk_callbacks: the trunk callback functions and args
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
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, const int prealloc_trunk_count,
struct fast_mblock_object_callbacks *object_callbacks,
const bool need_lock, struct fast_mblock_trunk_callbacks
*trunk_callbacks);
fast_mblock_alloc_init_func init_func, 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);
/**
mblock init
@ -190,52 +149,18 @@ 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 object init function
init_args: the args for object init function
init_func: the 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_object_init_func init_func, void *init_args,
const bool need_lock)
const char *name, const int element_size, const int alloc_elements_once,
fast_mblock_alloc_init_func init_func, 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,
prealloc_trunk_count, &object_callbacks,
need_lock, NULL);
alloc_elements_once, init_func, need_lock, NULL, NULL, 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:
@ -243,35 +168,6 @@ parameters:
*/
void fast_mblock_destroy(struct fast_mblock_man *mblock);
static inline int fast_mblock_set_need_wait(struct fast_mblock_man *mblock,
const bool need_wait, bool * volatile pcontinue_flag)
{
if (!mblock->need_lock || mblock->alloc_elements.limit <= 0)
{
logError("file: "__FILE__", line: %d, "
"need_lock: %d != 1 or alloc_elements.limit: %"PRId64" <= 0",
__LINE__, mblock->need_lock, mblock->alloc_elements.limit);
return EINVAL;
}
mblock->alloc_elements.need_wait = need_wait;
mblock->alloc_elements.pcontinue_flag = pcontinue_flag;
if (need_wait)
{
mblock->alloc_elements.exceed_log_level = LOG_NOTHING;
}
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:
@ -290,45 +186,6 @@ 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:
mblock: the mblock pointer
count: alloc count
return the alloced node head, return NULL if fail
*/
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
parameters:
mblock: the mblock pointer
chain: the node chain to free
return 0 for success, return none zero if fail
*/
int fast_mblock_batch_free(struct fast_mblock_man *mblock,
struct fast_mblock_chain *chain);
/**
delay free a node (put a node to the mblock)
parameters:
@ -370,17 +227,6 @@ 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:
@ -411,7 +257,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)->info.element_total_count
#define fast_mblock_total_count(mblock) (mblock)->total_count
/**
init mblock manager
@ -436,13 +282,9 @@ int fast_mblock_manager_stat(struct fast_mblock_info *stats,
print mblock manager stat
parameters:
hide_empty: if hide empty
order_by: order by which field
return error no, 0 for success, != 0 fail
*/
int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by);
#define fast_mblock_manager_stat_print(hide_empty) \
fast_mblock_manager_stat_print_ex(hide_empty, FAST_MBLOCK_ORDER_BY_ALLOC_BYTES)
int fast_mblock_manager_stat_print(const bool hide_empty);
typedef void (*fast_mblock_free_trunks_func)(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist);

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
//fast_mpool.c
#include <errno.h>
@ -48,10 +33,6 @@ 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;
}
@ -63,10 +44,14 @@ static int fast_mpool_prealloc(struct fast_mpool_man *mpool,
int bytes;
bytes = sizeof(struct fast_mpool_malloc) + alloc_size;
pMallocNode = (struct fast_mpool_malloc *)fc_malloc(bytes);
pMallocNode = (struct fast_mpool_malloc *)malloc(bytes);
if (pMallocNode == NULL)
{
return ENOMEM;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, bytes, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
pMallocNode->alloc_size = alloc_size;
@ -142,8 +127,6 @@ 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;
@ -182,50 +165,24 @@ void *fast_mpool_alloc(struct fast_mpool_man *mpool, const int size)
return NULL;
}
void *fast_mpool_memdup(struct fast_mpool_man *mpool,
const void *src, const int len)
{
void *dest;
dest = (char *)fast_mpool_alloc(mpool, len);
if (dest == NULL)
{
logError("file: "__FILE__", line: %d, "
"alloc %d bytes from mpool fail", __LINE__, len);
return NULL;
}
if (len > 0) {
memcpy(dest, src, len);
}
return dest;
}
void fast_mpool_reset(struct fast_mpool_man *mpool)
{
struct fast_mpool_malloc *pMallocNode;
struct fast_mpool_malloc *pMallocNode;
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)
{
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,
struct fast_mpool_stats *stats)
void fast_mpool_stats(struct fast_mpool_man *mpool, struct fast_mpool_stats *stats)
{
struct fast_mpool_malloc *pMallocNode;
@ -238,8 +195,7 @@ void fast_mpool_stats(struct fast_mpool_man *mpool,
while (pMallocNode != NULL)
{
stats->total_bytes += pMallocNode->alloc_size;
stats->free_bytes += (int)(pMallocNode->end_ptr -
pMallocNode->free_ptr);
stats->free_bytes += (int)(pMallocNode->end_ptr - pMallocNode->free_ptr);
stats->total_trunk_count++;
pMallocNode = pMallocNode->malloc_next;
@ -253,25 +209,3 @@ 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: %s, free: %s}, "
"trunk_count: {total: %d, free: %d}, "
"alloc_count: %"PRId64", alloc_bytes: %s, "
"reset_count: %"PRId64, mpool->alloc_size_once,
mpool->discard_size, sz_total_bytes,
sz_free_bytes, stats.total_trunk_count,
stats.free_trunk_count, mpool->alloc_count,
sz_alloc_bytes, mpool->reset.count);
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//fast_mpool.h
@ -37,16 +30,10 @@ 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
int64_t alloc_count;
int64_t alloc_bytes;
struct {
int64_t count;
int64_t last_alloc_count;
} reset;
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_stats
@ -95,111 +82,13 @@ return the alloced ptr, return NULL if fail
*/
void *fast_mpool_alloc(struct fast_mpool_man *mpool, const int size);
/**
alloc and copy memory from the mpool
parameters:
mpool: the mpool pointer
src: the source memory pointer
len: the length of the source memory
return alloc and duplicate memory pointer, NULL for fail
*/
void *fast_mpool_memdup(struct fast_mpool_man *mpool,
const void *src, const int len);
/**
alloc and copy string from the mpool
parameters:
mpool: the mpool pointer
src: the source '\0' terminated string
len: the length of the source string
return alloc and duplicate string pointer, NULL for fail
*/
static inline char *fast_mpool_strdup_ex(struct fast_mpool_man *mpool,
const char *src, const int len)
{
return (char *)fast_mpool_memdup(mpool, src, len + 1);
}
/**
alloc and copy string from the mpool
parameters:
mpool: the mpool pointer
src: the source '\0' terminated string
len: the length of the source string
return alloc and duplicate string pointer, NULL for fail
*/
static inline char *fast_mpool_strdup(struct fast_mpool_man *mpool,
const char *src)
{
return (char *)fast_mpool_memdup(mpool, src, strlen(src) + 1);
}
/**
alloc and copy string from the mpool
parameters:
mpool: the mpool pointer
dest: the dest string (return the alloced memory in dest->str)
src: the source string
len: the length of the source string
return error no, 0 for success, != 0 fail
*/
static inline int fast_mpool_alloc_string_ex(struct fast_mpool_man *mpool,
string_t *dest, const char *src, const int len)
{
dest->str = (char *)fast_mpool_memdup(mpool, src, len);
dest->len = len;
return dest->str != NULL ? 0 : ENOMEM;
}
/**
alloc and copy string from the mpool
parameters:
mpool: the mpool pointer
dest: the dest string (return the alloced memory in dest->str)
src: the source string
return error no, 0 for success, != 0 fail
*/
static inline int fast_mpool_alloc_string(struct fast_mpool_man *mpool,
string_t *dest, const char *src)
{
int len;
len = (src != NULL) ? strlen(src) : 0;
return fast_mpool_alloc_string_ex(mpool, dest, src, len);
}
/**
alloc and copy string from the mpool
parameters:
mpool: the mpool pointer
dest: the dest string (return the alloced memory in dest->str)
src: the source string
return error no, 0 for success, != 0 fail
*/
static inline int fast_mpool_alloc_string_ex2(struct fast_mpool_man *mpool,
string_t *dest, const string_t *src)
{
return fast_mpool_alloc_string_ex(mpool, dest, src->str, src->len);
}
/**
get stats
parameters:
mpool: the mpool pointer
stats: return the stats
return none
*/
void fast_mpool_stats(struct fast_mpool_man *mpool,
struct fast_mpool_stats *stats);
/**
log stats info
parameters:
mpool: the mpool pointer
return none
*/
void fast_mpool_log_stats(struct fast_mpool_man *mpool);
void fast_mpool_stats(struct fast_mpool_man *mpool, struct fast_mpool_stats *stats);
#ifdef __cplusplus
}

View File

@ -1,238 +1,678 @@
/*
* 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/>.
*/
//fast_task_queue.c
#include <errno.h>
#include <sys/resource.h>
#include <pthread.h>
#include <inttypes.h>
#include "fast_task_queue.h"
#include "logger.h"
#include "shared_func.h"
#include "pthread_func.h"
#include "fc_memory.h"
#include "fast_task_queue.h"
static int task_alloc_init(struct fast_task_info *task,
struct fast_task_queue *queue)
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};
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
int task_queue_init(struct fast_task_queue *pQueue)
{
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;
}
}
int result;
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 ((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;
}
task->free_queue = queue;
if (queue->init_callback != NULL) {
return queue->init_callback(task, queue->init_arg);
}
return 0;
pQueue->head = NULL;
pQueue->tail = NULL;
return 0;
}
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 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 *)malloc(sizeof(struct mpool_node));
if (mpool == NULL)
{
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, (int)sizeof(struct mpool_node), \
errno, STRERROR(errno));
return NULL;
}
mpool->next = NULL;
mpool->blocks = (struct fast_task_info *)malloc(total_alloc_size);
if (mpool->blocks == NULL)
{
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, total_alloc_size, \
errno, STRERROR(errno));
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 *)malloc(pTask->size);
if (pTask->data == NULL)
{
char *pt;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, pTask->size, \
errno, STRERROR(errno));
for (pt=(char *)mpool->blocks; pt < p; \
pt += g_free_queue.block_size)
{
free(((struct fast_task_info *)pt)->data);
}
free(mpool->blocks);
free(mpool);
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_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)
{
#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_padding_size;
int aligned_arg_size;
rlim_t max_data_size;
char aname[64];
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_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 (aligned_max_size > aligned_min_size) {
queue->malloc_whole_block = false;
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;
}
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 (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)(queue->block_size +
aligned_min_size) * (int64_t)alloc_once)
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)
{
queue->malloc_whole_block = true;
queue->block_size += aligned_min_size;
} else {
queue->malloc_whole_block = false;
max_data_size = 0;
g_free_queue.alloc_task_once = alloc_once;
}
}
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;
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, "
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, "
"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);
*/
"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);
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);
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 fast_task_queue *queue)
int free_queue_init(const int max_connections, const int min_buff_size,
const int max_buff_size, const int arg_size)
{
fast_mblock_destroy(&queue->allocator);
return free_queue_init_ex(max_connections, max_connections,
0, min_buff_size, max_buff_size, arg_size);
}
static int _realloc_buffer(struct fast_net_buffer *buffer,
const int new_size, const bool copy_data)
void free_queue_destroy()
{
char *new_buff;
struct mpool_node *mpool;
struct mpool_node *mp;
new_buff = (char *)fc_malloc(new_size);
if (new_buff == NULL) {
return ENOMEM;
if (g_mpool.head == NULL)
{
return;
}
if (!g_free_queue.malloc_whole_block)
{
char *p;
char *pCharEnd;
struct fast_task_info *pTask;
mpool = g_mpool.head;
while (mpool != NULL)
{
pCharEnd = (char *)mpool->last_block + g_free_queue.block_size;
for (p=(char *)mpool->blocks; p<pCharEnd; p += g_free_queue.block_size)
{
pTask = (struct fast_task_info *)p;
if (pTask->data != NULL)
{
free(pTask->data);
pTask->data = NULL;
}
}
mpool = mpool->next;
}
}
mpool = g_mpool.head;
while (mpool != NULL)
{
mp = mpool;
mpool = mpool->next;
free(mp->blocks);
free(mp);
}
g_mpool.head = g_mpool.tail = NULL;
pthread_mutex_destroy(&(g_free_queue.lock));
}
static int free_queue_realloc()
{
struct mpool_node *mpool;
struct fast_task_info *head;
struct fast_task_info *tail;
int remain_count;
int alloc_count;
int current_alloc_size;
head = tail = NULL;
remain_count = g_free_queue.max_connections -
g_free_queue.alloc_connections;
alloc_count = (remain_count > g_free_queue.alloc_task_once) ?
g_free_queue.alloc_task_once : remain_count;
if (alloc_count > 0)
{
current_alloc_size = g_free_queue.block_size * alloc_count;
mpool = malloc_mpool(current_alloc_size);
if (mpool == NULL)
{
return ENOMEM;
}
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 (copy_data && buffer->offset > 0) {
memcpy(new_buff, buffer->data, buffer->offset);
if (g_free_queue.head == NULL)
{
g_free_queue.head = head;
}
free(buffer->data);
buffer->size = new_size;
buffer->data = new_buff;
if (g_free_queue.tail != NULL)
{
g_free_queue.tail->next = head;
}
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;
}
void free_queue_push(struct fast_task_info *task)
struct fast_task_info *free_queue_pop()
{
if (task->free_queue->release_callback != NULL) {
task->free_queue->release_callback(task);
struct fast_task_info *pTask;
int i;
if ((pTask=task_queue_pop(&g_free_queue)) != NULL)
{
return pTask;
}
*(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 (g_free_queue.alloc_connections >= g_free_queue.max_connections)
{
return NULL;
}
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)
for (i=0; i<10; i++)
{
pthread_mutex_lock(&g_free_queue.lock);
if (g_free_queue.alloc_connections >= g_free_queue.max_connections)
{
_realloc_buffer(task->recv.ptr, task->free_queue->
min_buff_size, false);
task->shrinked = true;
if (g_free_queue.head == NULL)
{
pthread_mutex_unlock(&g_free_queue.lock);
return NULL;
}
}
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)
{
return pTask;
}
}
fast_mblock_free_object(&task->free_queue->allocator, task);
return NULL;
}
int free_queue_get_new_buffer_size(const int min_buff_size,
static int _realloc_buffer(struct fast_task_info *pTask, const int new_size,
const bool copy_data)
{
char *new_buff;
new_buff = (char *)malloc(new_size);
if (new_buff == NULL)
{
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, "
"errno: %d, error info: %s",
__LINE__, new_size,
errno, STRERROR(errno));
return errno != 0 ? errno : 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;
}
}
int free_queue_push(struct fast_task_info *pTask)
{
int result;
*(pTask->client_ip) = '\0';
pTask->length = 0;
pTask->offset = 0;
pTask->req_count = 0;
if (pTask->size > g_free_queue.min_buff_size) //need thrink
{
_realloc_buffer(pTask, g_free_queue.min_buff_size, false);
}
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;
}
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 task_queue_push(struct fast_task_queue *pQueue, \
struct fast_task_info *pTask)
{
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
pTask->next = NULL;
if (pQueue->tail == NULL)
{
pQueue->head = pTask;
}
else
{
pQueue->tail->next = pTask;
}
pQueue->tail = pTask;
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return 0;
}
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return NULL;
}
pTask = pQueue->head;
if (pTask != NULL)
{
pQueue->head = pTask->next;
if (pQueue->head == NULL)
{
pQueue->tail = NULL;
}
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return pTask;
}
int task_queue_count(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int count;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return 0;
}
count = 0;
pTask = pQueue->head;
while (pTask != NULL)
{
pTask = pTask->next;
count++;
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return count;
}
int task_queue_get_new_buffer_size(const int min_buff_size,
const int max_buff_size, const int expect_size, int *new_size)
{
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;
}
}
@ -240,43 +680,42 @@ int free_queue_get_new_buffer_size(const int min_buff_size,
return 0;
}
#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)
#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)
int free_queue_set_buffer_size(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size)
int task_queue_set_buffer_size(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size)
{
int result;
int new_size;
if ((result=_get_new_buffer_size(task->free_queue,
expect_size, &new_size)) != 0)
{
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) {
return result;
}
if (buffer->size == new_size) { //do NOT need change buffer size
if (pTask->size == new_size) //do NOT need change buffer size
{
return 0;
}
return _realloc_buffer(buffer, new_size, false);
return _realloc_buffer(pTask, new_size, false);
}
int free_queue_realloc_buffer(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size)
int task_queue_realloc_buffer(struct fast_task_queue *pQueue,
struct fast_task_info *pTask, const int expect_size)
{
int result;
int new_size;
if (buffer->size >= expect_size) { //do NOT need change buffer size
if (pTask->size >= expect_size) //do NOT need change buffer size
{
return 0;
}
if ((result=_get_new_buffer_size(task->free_queue,
expect_size, &new_size)) != 0)
{
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) {
return result;
}
return _realloc_buffer(buffer, new_size, true);
return _realloc_buffer(pTask, new_size, true);
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//fast_task_queue.h
@ -23,293 +16,99 @@
#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]
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
struct nio_thread_data;
struct fast_task_info;
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
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 int (*TaskFinishCallback) (struct fast_task_info *pTask);
typedef void (*TaskCleanUpCallback) (struct fast_task_info *pTask);
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 void (*IOEventCallback) (int sock, short event, void *arg);
typedef struct ioevent_entry
{
FastTimerEntry timer; //must first
int fd;
int res; //just for io_uring, since v1.0.81
IOEventCallback callback;
int fd;
FastTimerEntry timer;
IOEventCallback callback;
} IOEventEntry;
struct nio_thread_data
{
struct ioevent_puller ev_puller;
struct fast_timer timer;
int pipe_fds[2]; //for notify
struct fast_task_info *deleted_list; //tasks for cleanup
int pipe_fds[2];
struct fast_task_info *deleted_list;
ThreadLoopCallback thread_loop_callback;
ThreadLoopCallback busy_polling_callback;
void *arg; //extra argument pointer
struct {
struct fast_task_info *head;
struct fast_task_info *tail;
pthread_mutex_t lock;
} waiting_queue; //task queue
struct {
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
{
IOEventEntry event; //must first
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
union {
char server_ip[IP_ADDRESS_SIZE];
char client_ip[IP_ADDRESS_SIZE];
};
void *arg; //extra argument pointer
char *recv_body; //for extra (dynamic) recv buffer
struct {
struct iovec *iovs;
int count;
} iovec_array; //for writev
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
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
IOEventEntry event; //must first
char client_ip[IP_ADDRESS_SIZE];
void *arg; //extra argument pointer
char *data; //buffer for write or recv
int size; //alloc size
int length; //data length
int offset; //current offset
int64_t req_count; //request count
TaskFinishCallback finish_callback;
struct nio_thread_data *thread_data;
struct fast_task_info *next;
};
struct fast_task_queue
{
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;
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;
};
#ifdef __cplusplus
extern "C" {
#endif
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,
int free_queue_init(const int max_connections, const int min_buff_size, \
const int max_buff_size, const int arg_size);
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 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);
}
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)
{
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 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 struct fast_task_info *free_queue_pop(
struct fast_task_queue *queue)
{
return (struct fast_task_info *)fast_mblock_alloc_object(&queue->allocator);
}
void free_queue_push(struct fast_task_info *task);
static inline int free_queue_count(struct fast_task_queue *queue)
{
return queue->allocator.info.element_total_count -
queue->allocator.info.element_used_count;
}
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,
int task_queue_get_new_buffer_size(const int min_buff_size,
const int max_buff_size, const int expect_size, int *new_size);
int free_queue_set_buffer_size(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size);
static inline int free_queue_set_max_buffer_size(
struct fast_task_info *task,
struct fast_net_buffer *buffer)
{
return free_queue_set_buffer_size(task, buffer,
task->free_queue->max_buff_size);
}
int free_queue_realloc_buffer(struct fast_task_info *task,
struct fast_net_buffer *buffer, const int expect_size);
static inline int free_queue_realloc_max_buffer(
struct fast_task_info *task,
struct fast_net_buffer *buffer)
{
return free_queue_realloc_buffer(task, buffer,
task->free_queue->max_buff_size);
}
/* send and recv buffer operations */
static inline int free_queue_set_send_buffer_size(
struct fast_task_info *task, const int expect_size)
{
return free_queue_set_buffer_size(task, task->send.ptr, expect_size);
}
static inline int free_queue_set_recv_buffer_size(
struct fast_task_info *task, const int expect_size)
{
return free_queue_set_buffer_size(task, task->recv.ptr, expect_size);
}
static inline int free_queue_set_send_max_buffer_size(
struct fast_task_info *task)
{
return free_queue_set_max_buffer_size(task, task->send.ptr);
}
static inline int free_queue_set_recv_max_buffer_size(
struct fast_task_info *task)
{
return free_queue_set_max_buffer_size(task, task->recv.ptr);
}
static inline int free_queue_realloc_send_buffer(
struct fast_task_info *task, const int expect_size)
{
return free_queue_realloc_buffer(task, task->send.ptr, expect_size);
}
static inline int free_queue_realloc_recv_buffer(
struct fast_task_info *task, const int expect_size)
{
return free_queue_realloc_buffer(task, task->recv.ptr, expect_size);
}
static inline int free_queue_realloc_send_max_buffer(
struct fast_task_info *task)
{
return free_queue_realloc_max_buffer(task, task->send.ptr);
}
static inline int free_queue_realloc_recv_max_buffer(
struct fast_task_info *task)
{
return free_queue_realloc_max_buffer(task, task->recv.ptr);
}
#ifdef __cplusplus
}
#endif

View File

@ -1,56 +1,37 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "logger.h"
#include "fc_memory.h"
#include "pthread_func.h"
#include "fast_timer.h"
int fast_timer_init(FastTimer *timer, const int slot_count,
const int64_t current_time)
{
int bytes;
int bytes;
if (slot_count <= 0 || current_time <= 0) {
return EINVAL;
}
if (slot_count <= 0 || current_time <= 0) {
return EINVAL;
}
timer->slot_count = slot_count;
timer->base_time = current_time; //base time for slot 0
timer->current_time = current_time;
bytes = sizeof(FastTimerSlot) * slot_count;
timer->slots = (FastTimerSlot *)fc_malloc(bytes);
if (timer->slots == NULL) {
return ENOMEM;
}
memset(timer->slots, 0, bytes);
return 0;
timer->slot_count = slot_count;
timer->base_time = current_time; //base time for slot 0
timer->current_time = current_time;
bytes = sizeof(FastTimerSlot) * slot_count;
timer->slots = (FastTimerSlot *)malloc(bytes);
if (timer->slots == NULL) {
return errno != 0 ? errno : ENOMEM;
}
memset(timer->slots, 0, bytes);
return 0;
}
void fast_timer_destroy(FastTimer *timer)
{
if (timer->slots != NULL) {
free(timer->slots);
timer->slots = NULL;
}
if (timer->slots != NULL) {
free(timer->slots);
timer->slots = NULL;
}
}
#define TIMER_GET_SLOT_INDEX(timer, expires) \
@ -59,160 +40,138 @@ void fast_timer_destroy(FastTimer *timer)
#define TIMER_GET_SLOT_POINTER(timer, expires) \
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
static inline void add_entry(FastTimer *timer, FastTimerSlot *slot,
FastTimerEntry *entry, const int64_t expires, const bool set_expires)
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
{
if (set_expires) {
entry->expires = expires;
}
entry->next = slot->head.next;
if (slot->head.next != NULL) {
slot->head.next->prev = entry;
}
entry->prev = &slot->head;
slot->head.next = entry;
entry->rehash = false;
}
FastTimerSlot *slot;
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
const int64_t expires, const bool set_expires)
{
FastTimerSlot *slot;
int64_t new_expires;
bool new_set_expires;
if (expires > timer->current_time) {
new_expires = expires;
new_set_expires = set_expires;
} else {
new_expires = timer->current_time + 1; //plus 1 for rare case
new_set_expires = true;
}
slot = TIMER_GET_SLOT_POINTER(timer, new_expires);
add_entry(timer, slot, entry, new_expires, new_set_expires);
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
timer->current_time ? entry->expires : timer->current_time);
entry->next = slot->head.next;
if (slot->head.next != NULL) {
slot->head.next->prev = entry;
}
entry->prev = &slot->head;
slot->head.next = entry;
entry->rehash = false;
return 0;
}
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
const int64_t new_expires)
{
int result;
if (new_expires > entry->expires) {
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
TIMER_GET_SLOT_INDEX(timer, entry->expires);
entry->expires = new_expires; //lazy move
} else if (new_expires < entry->expires) {
if ((result=fast_timer_remove(timer, entry)) == 0) {
fast_timer_add_ex(timer, entry, new_expires, true);
}
return result;
}
if (new_expires == entry->expires) {
return 0;
}
if (new_expires < entry->expires) {
fast_timer_remove(timer, entry);
entry->expires = new_expires;
return fast_timer_add(timer, entry);
}
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
TIMER_GET_SLOT_INDEX(timer, entry->expires);
entry->expires = new_expires; //lazy move
return 0;
}
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
{
if (entry->prev == NULL) {
return ENOENT; //already removed
}
if (entry->prev == NULL) {
return ENOENT; //already removed
}
if (entry->next != NULL) {
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
entry->next = NULL;
} else {
entry->prev->next = NULL;
}
if (entry->next != NULL) {
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
entry->next = NULL;
}
else {
entry->prev->next = NULL;
}
entry->prev = NULL;
return 0;
entry->prev = NULL;
return 0;
}
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
{
if (timer->current_time >= current_time) {
return NULL;
}
if (timer->current_time >= current_time) {
return NULL;
}
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
}
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
FastTimerEntry *head)
FastTimerEntry *head)
{
FastTimerSlot *slot;
FastTimerSlot *new_slot;
FastTimerEntry *entry;
FastTimerEntry *first;
FastTimerEntry *last;
FastTimerEntry *tail;
int count;
FastTimerSlot *slot;
FastTimerEntry *entry;
FastTimerEntry *first;
FastTimerEntry *last;
FastTimerEntry *tail;
int count;
head->prev = NULL;
head->next = NULL;
if (timer->current_time >= current_time) {
return 0;
}
head->prev = NULL;
head->next = NULL;
if (timer->current_time >= current_time) {
return 0;
}
first = NULL;
last = NULL;
tail = head;
count = 0;
while (timer->current_time < current_time) {
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
entry = slot->head.next;
while (entry != NULL) {
if (entry->expires >= current_time) { //not expired
if (first != NULL) {
first->prev->next = entry;
entry->prev = first->prev;
tail->next = first;
first->prev = tail;
tail = last;
first = NULL;
}
if (entry->rehash) {
last = entry;
entry = entry->next;
new_slot = TIMER_GET_SLOT_POINTER(timer, last->expires);
if (new_slot != slot) { //check to avoid deadlock
if (fast_timer_remove(timer, last) == 0) {
add_entry(timer, new_slot, last,
last->expires, false);
}
} else {
last->rehash = false;
}
continue;
}
} else { //expired
count++;
if (first == NULL) {
first = entry;
}
}
last = entry;
entry = entry->next;
}
if (first != NULL) {
first->prev->next = NULL;
first = NULL;
last = NULL;
tail = head;
count = 0;
while (timer->current_time < current_time) {
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
entry = slot->head.next;
while (entry != NULL) {
if (entry->expires >= current_time) { //not expired
if (first != NULL) {
first->prev->next = entry;
entry->prev = first->prev;
tail->next = first;
first->prev = tail;
tail = last;
first = NULL;
}
}
if (entry->rehash) {
last = entry;
entry = entry->next;
last->rehash = false;
fast_timer_remove(timer, last);
fast_timer_add(timer, last);
continue;
}
}
else { //expired
count++;
if (first == NULL) {
first = entry;
}
}
last = entry;
entry = entry->next;
}
if (count > 0) {
tail->next = NULL;
}
if (first != NULL) {
first->prev->next = NULL;
return count;
tail->next = first;
first->prev = tail;
tail = last;
first = NULL;
}
}
if (count > 0) {
tail->next = NULL;
}
return count;
}

View File

@ -1,58 +1,37 @@
/*
* 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/>.
*/
#ifndef __FAST_TIMER_H__
#define __FAST_TIMER_H__
#include <stdint.h>
#include <pthread.h>
#include "common_define.h"
struct fast_timer_slot;
typedef struct fast_timer_entry {
int64_t expires;
struct fast_timer_entry *prev;
struct fast_timer_entry *next;
int slot_index;
bool rehash;
int64_t expires;
void *data;
struct fast_timer_entry *prev;
struct fast_timer_entry *next;
bool rehash;
} FastTimerEntry;
typedef struct fast_timer_slot {
struct fast_timer_entry head;
struct fast_timer_entry head;
} FastTimerSlot;
typedef struct fast_timer {
int slot_count; //time wheel slot count
int64_t base_time; //base time for slot 0
volatile int64_t current_time;
FastTimerSlot *slots;
int slot_count; //time wheel slot count
int64_t base_time; //base time for slot 0
int64_t current_time;
FastTimerSlot *slots;
} FastTimer;
#ifdef __cplusplus
extern "C" {
#endif
#define fast_timer_add(timer, entry) \
fast_timer_add_ex(timer, entry, (entry)->expires, false)
int fast_timer_init(FastTimer *timer, const int slot_count,
const int64_t current_time);
void fast_timer_destroy(FastTimer *timer);
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
const int64_t expires, const bool set_expires);
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
const int64_t new_expires);

View File

@ -1,77 +0,0 @@
/*
* 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/>.
*/
#ifndef _FC_ATOMIC_H
#define _FC_ATOMIC_H
#ifdef __cplusplus
extern "C" {
#endif
#define FC_ATOMIC_GET(var) __sync_add_and_fetch(&var, 0)
#define FC_ATOMIC_INC(var) __sync_add_and_fetch(&var, 1)
#define FC_ATOMIC_DEC(var) __sync_sub_and_fetch(&var, 1)
#define FC_ATOMIC_INC_EX(var, n) __sync_add_and_fetch(&var, n)
#define FC_ATOMIC_DEC_EX(var, n) __sync_sub_and_fetch(&var, n)
#define FC_ATOMIC_CAS(var, old_value, new_value) \
do { \
if (__sync_bool_compare_and_swap(&var, old_value, new_value)) { \
break; \
} \
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; \
_old_value = var; \
do { \
if (__sync_bool_compare_and_swap(&var, _old_value, new_value)) { \
break; \
} \
_old_value = __sync_add_and_fetch(&var, 0); \
} 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
#endif

View File

@ -1,201 +0,0 @@
#ifndef _FC_LIST_H
#define _FC_LIST_H
struct fc_list_head {
struct fc_list_head *next;
struct fc_list_head *prev;
};
#define FC_INIT_LIST_HEAD(head) \
do { \
(head)->next = (head)->prev = head; \
} while (0)
#ifdef __cplusplus
extern "C" {
#endif
static inline void
fc_list_add (struct fc_list_head *_new, struct fc_list_head *head)
{
_new->prev = head;
_new->next = head->next;
_new->prev->next = _new;
_new->next->prev = _new;
}
static inline void
fc_list_add_tail (struct fc_list_head *_new, struct fc_list_head *head)
{
_new->next = head;
_new->prev = head->prev;
_new->prev->next = _new;
_new->next->prev = _new;
}
static inline void
fc_list_add_before (struct fc_list_head *_new, struct fc_list_head *current)
{
_new->prev = current->prev;
_new->next = current;
_new->prev->next = _new;
_new->next->prev = _new;
}
static inline void
fc_list_add_after (struct fc_list_head *_new, struct fc_list_head *current)
{
_new->prev = current;
_new->next = current->next;
current->next->prev = _new;
current->next = _new;
}
static inline void
fc_list_add_internal (struct fc_list_head *_new, struct fc_list_head *prev,
struct fc_list_head *next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
static inline void
fc_list_del (struct fc_list_head *old)
{
old->prev->next = old->next;
old->next->prev = old->prev;
old->next = (struct fc_list_head *)0xbabebabe;
old->prev = (struct fc_list_head *)0xcafecafe;
}
static inline void
fc_list_del_init (struct fc_list_head *old)
{
old->prev->next = old->next;
old->next->prev = old->prev;
old->next = old;
old->prev = old;
}
static inline void
fc_list_move (struct fc_list_head *list, struct fc_list_head *head)
{
list->prev->next = list->next;
list->next->prev = list->prev;
fc_list_add (list, head);
}
static inline void
fc_list_move_tail (struct fc_list_head *list, struct fc_list_head *head)
{
list->prev->next = list->next;
list->next->prev = list->prev;
fc_list_add_tail (list, head);
}
static inline int
fc_list_empty (struct fc_list_head *head)
{
return (head->next == head);
}
static inline void
__fc_list_splice (struct fc_list_head *list, struct fc_list_head *head)
{
(list->prev)->next = (head->next);
(head->next)->prev = (list->prev);
(head)->next = (list->next);
(list->next)->prev = (head);
}
static inline void
fc_list_splice (struct fc_list_head *list, struct fc_list_head *head)
{
if (fc_list_empty (list))
return;
__fc_list_splice (list, head);
}
static inline void
fc_list_splice_init (struct fc_list_head *list, struct fc_list_head *head)
{
if (fc_list_empty (list))
return;
__fc_list_splice (list, head);
FC_INIT_LIST_HEAD (list);
}
static inline int fc_list_is_last(const struct fc_list_head *list,
const struct fc_list_head *head)
{
return list->next == head;
}
static inline int fc_list_count(struct fc_list_head *head)
{
struct fc_list_head *pos;
int count;
count = 0;
for (pos = head->next; pos != head; pos = pos->next) {
++count;
}
return count;
}
#define fc_list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define fc_list_first_entry(head, type, member) \
((head)->next == head ? NULL : \
fc_list_entry((head)->next, type, member))
#define fc_list_last_entry(head, type, member) \
((head)->prev == head ? NULL : \
fc_list_entry((head)->prev, type, member))
#define fc_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define fc_list_for_each_entry(pos, head, member) \
for (pos = fc_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = fc_list_entry(pos->member.next, typeof(*pos), member))
#define fc_list_for_each_entry_safe(pos, n, head, member) \
for (pos = fc_list_entry((head)->next, typeof(*pos), member), \
n = fc_list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = fc_list_entry(n->member.next, typeof(*n), member))
#define fc_list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,20 +0,0 @@
/*
* 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/>.
*/
//fc_memory.c
#include "fc_memory.h"
fc_memory_oom_notify_func g_oom_notify = NULL;

View File

@ -1,112 +0,0 @@
/*
* 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/>.
*/
//fc_memory.h
#ifndef _FC_MEMORY_H
#define _FC_MEMORY_H
#include <stdlib.h>
#include "common_define.h"
#include "logger.h"
typedef void (*fc_memory_oom_notify_func)(const size_t curr_size);
#ifdef __cplusplus
extern "C" {
#endif
extern fc_memory_oom_notify_func g_oom_notify;
static inline void *fc_malloc_ex(const char *file,
const int line, size_t size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL) {
logError("file: %s, line: %d, malloc %"PRId64" bytes fail, "
"errno: %d, error info: %s", file, line,
(int64_t)size, errno, STRERROR(errno));
if (g_oom_notify != NULL) {
g_oom_notify(size);
}
}
return ptr;
}
static inline void *fc_realloc_ex(const char *file,
const int line, void *ptr, size_t size)
{
void *new_ptr;
new_ptr = realloc(ptr, size);
if (new_ptr == NULL) {
logError("file: %s, line: %d, realloc %"PRId64" bytes fail, "
"errno: %d, error info: %s", file, line,
(int64_t)size, errno, STRERROR(errno));
if (g_oom_notify != NULL) {
g_oom_notify(size);
}
}
return new_ptr;
}
static inline char *fc_strdup_ex(const char *file,
const int line, const char *str)
{
char *output;
int len;
len = strlen(str);
output = (char *)fc_malloc_ex(file, line, len + 1);
if (output == NULL) {
return NULL;
}
if (len > 0) {
memcpy(output, str, len);
}
*(output + len) = '\0';
return output;
}
static inline void *fc_calloc_ex(const char *file,
const int line, size_t count, size_t size)
{
void *ptr;
ptr = calloc(count, size);
if (ptr == NULL) {
logError("file: %s, line: %d, malloc %"PRId64" bytes fail, "
"errno: %d, error info: %s", file, line,
(int64_t)(count * size), errno, STRERROR(errno));
if (g_oom_notify != NULL) {
g_oom_notify(count * size);
}
}
return ptr;
}
#define fc_malloc(size) fc_malloc_ex(__FILE__, __LINE__, size)
#define fc_realloc(ptr, size) fc_realloc_ex(__FILE__, __LINE__, ptr, size)
#define fc_calloc(count, size) fc_calloc_ex(__FILE__, __LINE__, count, size)
#define fc_strdup(str) fc_strdup_ex(__FILE__, __LINE__, str)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,343 +0,0 @@
/*
* 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/>.
*/
//fc_queue.c
#include "pthread_func.h"
#include "fc_queue.h"
int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
{
int result;
if ((result=init_pthread_lock_cond_pair(&queue->lcp)) != 0)
{
return result;
}
queue->head = NULL;
queue->tail = NULL;
queue->next_ptr_offset = next_ptr_offset;
return 0;
}
void fc_queue_destroy(struct fc_queue *queue)
{
destroy_pthread_lock_cond_pair(&queue->lcp);
}
void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify)
{
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
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);
}
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->lcp.lock);
do {
data = queue->head;
if (data == NULL) {
if (!blocked) {
break;
}
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head;
}
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);
return data;
}
void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
{
void *data;
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
do {
data = queue->head;
if (data == NULL) {
if (!blocked) {
break;
}
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
data = queue->head;
}
if (data != NULL) {
queue->head = queue->tail = NULL;
}
} while (0);
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, bool *notify)
{
if (qinfo->head == NULL) {
*notify = false;
return;
}
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
FC_QUEUE_NEXT_PTR(queue, qinfo->tail) = queue->head;
queue->head = qinfo->head;
if (queue->tail == NULL) {
queue->tail = qinfo->tail;
*notify = true;
} else {
*notify = false;
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
}
void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, bool *notify)
{
if (qinfo->head == NULL) {
*notify = false;
return;
}
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
if (queue->head == NULL) {
queue->head = qinfo->head;
*notify = true;
} else {
FC_QUEUE_NEXT_PTR(queue, queue->tail) = qinfo->head;
*notify = false;
}
queue->tail = qinfo->tail;
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->lcp.lock);
if (queue->head == NULL) {
if (blocked) {
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
}
}
if (queue->head != NULL) {
qinfo->head = queue->head;
qinfo->tail = queue->tail;
queue->head = queue->tail = NULL;
} else {
qinfo->head = qinfo->tail = NULL;
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
}
void *fc_queue_timedpop(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;
}
if (data != NULL) {
queue->head = FC_QUEUE_NEXT_PTR(queue, data);
if (queue->head == NULL) {
queue->tail = NULL;
}
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
void *fc_queue_timedpeek(struct fc_queue *queue,
const int timeout, const int time_unit)
{
void *data;
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
data = queue->head;
if (data == NULL) {
fc_cond_timedwait(&queue->lcp, timeout, time_unit);
data = queue->head;
}
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
return data;
}
int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, const int count, struct fc_queue_info *chain)
{
struct fast_mblock_node *node;
if ((node=fast_mblock_batch_alloc1(mblock, count)) == NULL) {
chain->head = chain->tail = NULL;
return ENOMEM;
}
chain->head = chain->tail = node->data;
while ((node=node->next) != NULL) {
FC_QUEUE_NEXT_PTR(queue, chain->tail) = node->data;
chain->tail = node->data;
}
FC_QUEUE_NEXT_PTR(queue, chain->tail) = NULL;
return 0;
}
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
*mblock, struct fc_queue_info *qinfo)
{
struct fast_mblock_node *previous;
struct fast_mblock_node *current;
struct fast_mblock_chain chain;
void *data;
if (qinfo->head == NULL) {
return 0;
}
chain.head = previous = fast_mblock_to_node_ptr(qinfo->head);
data = FC_QUEUE_NEXT_PTR(queue, qinfo->head);
while (data != NULL) {
current = fast_mblock_to_node_ptr(data);
previous->next = current;
previous = current;
data = FC_QUEUE_NEXT_PTR(queue, data);
}
previous->next = NULL;
chain.tail = previous;
return fast_mblock_batch_free(mblock, &chain);
}
int fc_queue_remove(struct fc_queue *queue, void *data)
{
void *previous;
void *current;
int result;
pthread_mutex_lock(&queue->lcp.lock);
if (queue->head == NULL)
{
result = ENOENT;
}
else if (queue->head == data)
{
queue->head = FC_QUEUE_NEXT_PTR(queue, queue->head);
if (queue->head == NULL)
{
queue->tail = NULL;
}
result = 0;
}
else
{
result = ENOENT;
previous = queue->head;
while ((current=FC_QUEUE_NEXT_PTR(queue, previous)) != NULL)
{
if (current == data)
{
FC_QUEUE_NEXT_PTR(queue, previous) =
FC_QUEUE_NEXT_PTR(queue, current);
if (queue->tail == current)
{
queue->tail = previous;
}
result = 0;
break;
}
previous = current;
}
}
pthread_mutex_unlock(&queue->lcp.lock);
return result;
}

View File

@ -1,235 +0,0 @@
/*
* 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/>.
*/
//fc_queue.h
#ifndef _FC_QUEUE_H
#define _FC_QUEUE_H
#include "common_define.h"
#include "fast_mblock.h"
struct fc_queue_info
{
void *head;
void *tail;
};
struct fc_queue
{
void *head;
void *tail;
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
int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset);
void fc_queue_destroy(struct fc_queue *queue);
static inline void fc_queue_terminate(struct fc_queue *queue)
{
pthread_cond_signal(&queue->lcp.cond);
}
static inline void fc_queue_terminate_all(
struct fc_queue *queue, const int count)
{
int i;
for (i=0; i<count; i++) {
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)
{
bool notify;
fc_queue_push_ex(queue, data, &notify);
if (notify) {
pthread_cond_signal(&(queue->lcp.cond));
}
}
static inline int fc_queue_push_with_check(struct fc_queue *queue, void *data)
{
int result;
bool notify;
result = fc_queue_push_with_check_ex(queue, data, &notify);
if (notify) {
pthread_cond_signal(&(queue->lcp.cond));
}
return result;
}
static inline void fc_queue_push_silence(struct fc_queue *queue, void *data)
{
bool notify;
fc_queue_push_ex(queue, data, &notify);
}
void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, bool *notify);
static inline void fc_queue_push_queue_to_head(struct fc_queue *queue,
struct fc_queue_info *qinfo)
{
bool notify;
fc_queue_push_queue_to_head_ex(queue, qinfo, &notify);
if (notify) {
pthread_cond_signal(&(queue->lcp.cond));
}
}
static inline void fc_queue_push_queue_to_head_silence(
struct fc_queue *queue, struct fc_queue_info *qinfo)
{
bool notify;
fc_queue_push_queue_to_head_ex(queue, qinfo, &notify);
}
void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, bool *notify);
static inline void fc_queue_push_queue_to_tail(struct fc_queue *queue,
struct fc_queue_info *qinfo)
{
bool notify;
fc_queue_push_queue_to_tail_ex(queue, qinfo, &notify);
if (notify) {
pthread_cond_signal(&(queue->lcp.cond));
}
}
static inline void fc_queue_push_queue_to_tail_silence(
struct fc_queue *queue, struct fc_queue_info *qinfo)
{
bool notify;
fc_queue_push_queue_to_tail_ex(queue, qinfo, &notify);
}
void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked);
#define fc_queue_pop(queue) fc_queue_pop_ex(queue, true)
#define fc_queue_try_pop(queue) fc_queue_pop_ex(queue, false)
void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked);
#define fc_queue_pop_all(queue) fc_queue_pop_all_ex(queue, true)
#define fc_queue_try_pop_all(queue) fc_queue_pop_all_ex(queue, false)
void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
struct fc_queue_info *qinfo, const bool blocked);
#define fc_queue_pop_to_queue(queue, qinfo) \
fc_queue_pop_to_queue_ex(queue, qinfo, true)
#define fc_queue_try_pop_to_queue(queue, qinfo) \
fc_queue_pop_to_queue_ex(queue, qinfo, false)
static inline bool fc_queue_empty(struct fc_queue *queue)
{
bool empty;
pthread_mutex_lock(&queue->lcp.lock);
empty = (queue->head == NULL);
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);
#define fc_queue_timedpop_sec(queue, timeout) \
fc_queue_timedpop(queue, timeout, FC_TIME_UNIT_SECOND)
#define fc_queue_timedpop_ms(queue, timeout_ms) \
fc_queue_timedpop(queue, timeout_ms, FC_TIME_UNIT_MSECOND)
#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
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2015 Happy Fish / YuQing
*
* libfastcommon 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.csource.org/ for more detail.
**/
//flat_skiplist.c
@ -22,15 +15,12 @@
#include <errno.h>
#include <assert.h>
#include "logger.h"
#include "fc_memory.h"
#include "flat_skiplist.h"
int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
skiplist_compare_func compare_func, skiplist_free_func free_func,
const int min_alloc_elements_once)
{
const int64_t alloc_elements_limit = 0;
char name[64];
int bytes;
int element_size;
int i;
@ -45,23 +35,20 @@ int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
return EINVAL;
}
if (level_count > 30) {
if (level_count > 20) {
logError("file: "__FILE__", line: %d, "
"level count: %d is too large",
__LINE__, level_count);
return E2BIG;
}
bytes = sizeof(FlatSkiplistNode *) * level_count;
sl->tmp_previous = (FlatSkiplistNode **)fc_malloc(bytes);
if (sl->tmp_previous == NULL) {
return ENOMEM;
}
bytes = sizeof(struct fast_mblock_man) * level_count;
sl->mblocks = (struct fast_mblock_man *)fc_malloc(bytes);
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
if (sl->mblocks == NULL) {
return ENOMEM;
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, errno: %d, error info: %s",
__LINE__, bytes, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
memset(sl->mblocks, 0, bytes);
@ -74,16 +61,13 @@ int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
}
for (i=level_count-1; i>=0; i--) {
sprintf(name, "flat-sl-level%02d", i);
element_size = sizeof(FlatSkiplistNode) +
sizeof(FlatSkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex1(sl->mblocks + i, name,
element_size, alloc_elements_once, alloc_elements_limit,
NULL, NULL, false)) != 0)
element_size = sizeof(FlatSkiplistNode) + sizeof(FlatSkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex(sl->mblocks + i,
element_size, alloc_elements_once, NULL, false)) != 0)
{
return result;
}
if (i % 2 == 0 && alloc_elements_once < 64 * 1024) {
if (alloc_elements_once < 1024 * 1024) {
alloc_elements_once *= 2;
}
}
@ -161,13 +145,13 @@ int flat_skiplist_insert(FlatSkiplist *sl, void *data)
int level_index;
FlatSkiplistNode *node;
FlatSkiplistNode *previous;
FlatSkiplistNode *current = NULL;
level_index = flat_skiplist_get_level_index(sl);
node = (FlatSkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index);
if (node == NULL) {
return ENOMEM;
}
node->data = data;
previous = sl->top;
for (i=sl->top_level_index; i>level_index; i--) {
@ -185,20 +169,16 @@ int flat_skiplist_insert(FlatSkiplist *sl, void *data)
previous = previous->links[i];
}
sl->tmp_previous[i] = previous;
current = previous->links[i];
previous->links[i] = node;
node->links[i] = current;
i--;
}
//set previous links of level 0
node->prev = previous;
previous->links[0]->prev = node;
//thread safe for one write with many read model
for (i=0; i<=level_index; i++) {
node->links[i] = sl->tmp_previous[i]->links[i];
sl->tmp_previous[i]->links[i] = node;
}
current->prev = node;
node->data = data;
return 0;
}
@ -208,7 +188,9 @@ static FlatSkiplistNode *flat_skiplist_get_previous(FlatSkiplist *sl, void *data
int i;
int cmp;
FlatSkiplistNode *previous;
FlatSkiplistNode *found;
found = NULL;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
@ -217,79 +199,17 @@ static FlatSkiplistNode *flat_skiplist_get_previous(FlatSkiplist *sl, void *data
break;
}
else if (cmp == 0) {
found = previous;
*level_index = i;
return previous;
goto DONE;
}
previous = previous->links[i];
}
}
return NULL;
}
static FlatSkiplistNode *flat_skiplist_get_first_larger_or_equal(
FlatSkiplist *sl, void *data)
{
int i;
int cmp;
FlatSkiplistNode *previous;
FlatSkiplistNode *current;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->data);
if (cmp > 0) {
break;
}
else if (cmp == 0) {
current = previous->links[i]->links[0];
while ((current != sl->tail) && (sl->compare_func(
data, current->data) == 0))
{
current = current->links[0];
}
return current->prev;
}
previous = previous->links[i];
}
}
return previous;
}
static FlatSkiplistNode *flat_skiplist_get_first_larger(
FlatSkiplist *sl, void *data)
{
int i;
int cmp;
FlatSkiplistNode *previous;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->data);
if (cmp > 0) {
break;
}
else if (cmp == 0) {
previous = previous->links[i]->prev;
while ((previous != sl->top) && (sl->compare_func(
data, previous->data) == 0))
{
previous = previous->prev;
}
return previous;
}
previous = previous->links[i];
}
}
return previous;
DONE:
return found;
}
int flat_skiplist_delete(FlatSkiplist *sl, void *data)
@ -306,11 +226,13 @@ int flat_skiplist_delete(FlatSkiplist *sl, void *data)
deleted = previous->links[level_index];
for (i=level_index; i>=0; i--) {
while (previous->links[i] != sl->tail && previous->links[i] != deleted) {
while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) < 0)
{
previous = previous->links[i];
}
assert(previous->links[i] == deleted);
assert(sl->compare_func(data, previous->links[i]->data) == 0);
previous->links[i] = previous->links[i]->links[i];
}
@ -355,46 +277,13 @@ int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *i
return ENOENT;
}
previous = previous->links[level_index];
last = previous->links[0];
last = previous->links[0]->links[0];
while (last != sl->tail && sl->compare_func(data, last->data) == 0) {
last = last->links[0];
}
do {
previous = previous->prev;
} while (previous != sl->top && sl->compare_func(data, previous->data) == 0);
iterator->top = previous;
iterator->current = last->prev;
return 0;
}
void *flat_skiplist_find_ge(FlatSkiplist *sl, void *data)
{
FlatSkiplistNode *node;
node = flat_skiplist_get_first_larger_or_equal(sl, data);
if (node == sl->top) {
return NULL;
}
return node->data;
}
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
FlatSkiplistIterator *iterator)
{
if (sl->compare_func(start_data, end_data) > 0) {
iterator->current = sl->top;
iterator->top = sl->top;
return EINVAL;
}
iterator->current = flat_skiplist_get_first_larger_or_equal(sl, start_data);
if (iterator->current == sl->top) {
iterator->top = sl->top;
return ENOENT;
}
iterator->top = flat_skiplist_get_first_larger(sl, end_data);
return iterator->current != iterator->top ? 0 : ENOENT;
}

View File

@ -1,21 +1,12 @@
/*
* 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/>.
*/
//flat_skiplist.h, support duplicated entries, and support stable sort :)
//you should use multi_skiplist with too many duplicated entries
/**
* Copyright (C) 2015 Happy Fish / YuQing
*
* libfastcommon 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.csource.org/ for more detail.
**/
//flat_skiplist.h, support stable sort :)
#ifndef _FLAT_SKIPLIST_H
#define _FLAT_SKIPLIST_H
@ -42,7 +33,6 @@ typedef struct flat_skiplist
struct fast_mblock_man *mblocks; //node allocators
FlatSkiplistNode *top; //the top node
FlatSkiplistNode *tail; //the tail node for interator
FlatSkiplistNode **tmp_previous; //thread safe for insert
} FlatSkiplist;
typedef struct flat_skiplist_iterator {
@ -69,9 +59,6 @@ int flat_skiplist_delete(FlatSkiplist *sl, void *data);
int flat_skiplist_delete_all(FlatSkiplist *sl, void *data, int *delete_count);
void *flat_skiplist_find(FlatSkiplist *sl, void *data);
int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *iterator);
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
FlatSkiplistIterator *iterator);
void *flat_skiplist_find_ge(FlatSkiplist *sl, void *data);
static inline void flat_skiplist_iterator(FlatSkiplist *sl, FlatSkiplistIterator *iterator)
{
@ -92,42 +79,6 @@ static inline void *flat_skiplist_next(FlatSkiplistIterator *iterator)
return data;
}
static inline void *flat_skiplist_get_first(FlatSkiplist *sl)
{
if (sl->top->links[0] != sl->tail) {
return sl->top->links[0]->data;
} else {
return NULL;
}
}
static inline bool flat_skiplist_empty(FlatSkiplist *sl)
{
return sl->top->links[0] == sl->tail;
}
typedef const char * (*flat_skiplist_tostring_func)(void *data, char *buff, const int size);
static inline void flat_skiplist_print(FlatSkiplist *sl, flat_skiplist_tostring_func tostring_func)
{
int i;
FlatSkiplistNode *current;
char buff[1024];
printf("###################\n");
for (i=sl->top_level_index; i>=0; i--) {
printf("level %d: ", i);
current = sl->top->links[i];
while (current != sl->tail) {
printf("%s ", tostring_func(current->data, buff, sizeof(buff)));
current = current->links[i];
}
printf("\n");
}
printf("###################\n");
printf("\n");
}
#ifdef __cplusplus
}
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <stdlib.h>
#include <stdio.h>
@ -19,7 +12,6 @@
#include <errno.h>
#include <inttypes.h>
#include "pthread_func.h"
#include "fc_memory.h"
#include "hash.h"
static unsigned int prime_array[] = {
@ -67,7 +59,7 @@ static int _hash_alloc_buckets(HashArray *pHash, const unsigned int old_capacity
return ENOSPC;
}
pHash->buckets = (HashData **)fc_malloc(bytes);
pHash->buckets = (HashData **)malloc(bytes);
if (pHash->buckets == NULL)
{
return ENOMEM;
@ -79,7 +71,7 @@ static int _hash_alloc_buckets(HashArray *pHash, const unsigned int old_capacity
return 0;
}
unsigned int *fc_hash_get_prime_capacity(const int capacity)
unsigned int *hash_get_prime_capacity(const int capacity)
{
unsigned int *pprime;
unsigned int *prime_end;
@ -95,14 +87,14 @@ unsigned int *fc_hash_get_prime_capacity(const int capacity)
return NULL;
}
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
int 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 = fc_hash_get_prime_capacity(capacity);
pHash->capacity = hash_get_prime_capacity(capacity);
if (pHash->capacity == NULL)
{
return EINVAL;
@ -129,7 +121,7 @@ int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
return 0;
}
int fc_hash_set_locks(HashArray *pHash, const int lock_count)
int hash_set_locks(HashArray *pHash, const int lock_count)
{
size_t bytes;
pthread_mutex_t *lock;
@ -145,14 +137,13 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count)
return EINVAL;
}
//do NOT support rehash
if (pHash->load_factor >= 0.10)
{
return EINVAL;
}
bytes = sizeof(pthread_mutex_t) * lock_count;
pHash->locks = (pthread_mutex_t *)fc_malloc(bytes);
pHash->locks = (pthread_mutex_t *)malloc(bytes);
if (pHash->locks == NULL)
{
return ENOMEM;
@ -168,7 +159,7 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count)
return 0;
}
void fc_hash_destroy(HashArray *pHash)
void hash_destroy(HashArray *pHash)
{
HashData **ppBucket;
HashData **bucket_end;
@ -238,7 +229,7 @@ void fc_hash_destroy(HashArray *pHash)
}
int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
int hash_stat(HashArray *pHash, HashStat *pStat, \
int *stat_by_lens, const int stat_size)
{
HashData **ppBucket;
@ -299,13 +290,13 @@ int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
return 0;
}
void fc_hash_stat_print(HashArray *pHash)
void hash_stat_print(HashArray *pHash)
{
#define STAT_MAX_NUM 64
HashStat hs;
int stats[STAT_MAX_NUM];
if (fc_hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
if (hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
{
printf("hash max length exceeds %d!\n", STAT_MAX_NUM);
return;
@ -381,7 +372,7 @@ static int _rehash(HashArray *pHash)
pOldCapacity = pHash->capacity;
if (pHash->is_malloc_capacity)
{
pHash->capacity = fc_hash_get_prime_capacity(*pOldCapacity);
pHash->capacity = hash_get_prime_capacity(*pOldCapacity);
}
else
{
@ -456,7 +447,7 @@ static int _hash_conflict_count(HashArray *pHash)
return conflict_count;
}
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
int hash_best_op(HashArray *pHash, const int suggest_capacity)
{
int old_capacity;
int conflict_count;
@ -469,7 +460,7 @@ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
}
old_capacity = *pHash->capacity;
new_capacity = (unsigned int *)fc_malloc(sizeof(unsigned int));
new_capacity = (unsigned int *)malloc(sizeof(unsigned int));
if (new_capacity == NULL)
{
return -ENOMEM;
@ -513,7 +504,7 @@ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
pHash->is_malloc_capacity = true;
//fc_hash_stat_print(pHash);
//hash_stat_print(pHash);
return 1;
}
@ -537,7 +528,7 @@ static HashData *_chain_find_entry(HashData **ppBucket, const void *key, \
return NULL;
}
HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len)
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len)
{
unsigned int hash_code;
HashData **ppBucket;
@ -553,7 +544,7 @@ HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len)
return hash_data;
}
void *fc_hash_find(HashArray *pHash, const void *key, const int key_len)
void *hash_find(HashArray *pHash, const void *key, const int key_len)
{
unsigned int hash_code;
HashData **ppBucket;
@ -576,25 +567,7 @@ void *fc_hash_find(HashArray *pHash, const void *key, const int key_len)
}
}
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value)
{
HashData *hdata;
if ((hdata=fc_hash_find1_ex(pHash, key)) == NULL)
{
return ENOENT;
}
value->str = hdata->value;
value->len = hdata->value_len;
return 0;
}
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key)
{
return fc_hash_find_ex(pHash, key->str, key->len);
}
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
int hash_get(HashArray *pHash, const void *key, const int key_len,
void *value, int *value_len)
{
unsigned int hash_code;
@ -628,7 +601,7 @@ int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
return result;
}
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
int 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;
@ -712,7 +685,7 @@ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
return -ENOSPC;
}
pBuff = (char *)fc_malloc(bytes);
pBuff = (char *)malloc(bytes);
if (pBuff == NULL)
{
return -ENOMEM;
@ -760,7 +733,7 @@ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
return 1;
}
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
int64_t hash_inc_value(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg)
{
int64_t n;
@ -768,26 +741,27 @@ int64_t fc_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 fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
int 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)
{
@ -822,7 +796,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
}
}
}
result = fc_hash_insert_ex(pHash, key, key_len, value, *value_len, false);
result = hash_insert_ex(pHash, key, key_len, value, *value_len, false);
if (result < 0)
{
*value = '\0';
@ -838,7 +812,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
return result;
}
int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
int 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;
@ -868,7 +842,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
break;
}
pNewBuff = (char *)fc_malloc(offset + value_len);
pNewBuff = (char *)malloc(offset + value_len);
if (pNewBuff == NULL)
{
result = errno != 0 ? errno : ENOMEM;
@ -880,7 +854,7 @@ int fc_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 = fc_hash_insert_ex(pHash, key, key_len, pNewBuff,
result = hash_insert_ex(pHash, key, key_len, pNewBuff,
offset + value_len, false);
free(pNewBuff);
}
@ -891,8 +865,8 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
result = ENOENT;
break;
}
result = fc_hash_insert_ex(pHash, key, key_len,
(void *)value, value_len, false);
result = hash_insert_ex(pHash, key, key_len, (void *)value,
value_len, false);
}
if (result < 0)
@ -909,7 +883,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
return result;
}
int fc_hash_delete(HashArray *pHash, const void *key, const int key_len)
int hash_delete(HashArray *pHash, const void *key, const int key_len)
{
HashData **ppBucket;
HashData *hash_data;
@ -942,7 +916,7 @@ int fc_hash_delete(HashArray *pHash, const void *key, const int key_len)
return result;
}
int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
{
HashData **ppBucket;
HashData **bucket_end;
@ -971,12 +945,12 @@ int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
return 0;
}
int fc_hash_count(HashArray *pHash)
int hash_count(HashArray *pHash)
{
return pHash->item_count;
}
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
{
if (pHash->lock_count <= 0)
{
@ -987,7 +961,7 @@ int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
pHash->lock_count);
}
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
{
if (pHash->lock_count <= 0)
{
@ -1307,19 +1281,19 @@ int calc_hashnr1_ex(const void* key, const int key_len, \
\
h = init_value; \
pEnd = (unsigned char *)key + key_len; \
for (p = (unsigned char *)key; p != pEnd; p++) \
for (p = (unsigned char *)key; p!= pEnd; p++) \
{ \
h = 31 * h + *p; \
} \
\
return h; \
int fc_simple_hash(const void* key, const int key_len)
int simple_hash(const void* key, const int key_len)
{
SIMPLE_HASH_FUNC(0)
}
int fc_simple_hash_ex(const void* key, const int key_len, \
int simple_hash_ex(const void* key, const int key_len, \
const int init_value)
{
SIMPLE_HASH_FUNC(init_value)
@ -1395,7 +1369,7 @@ static unsigned int crc_table[256] = {
#define CRC32_BODY(init_value) \
unsigned char *pKey; \
unsigned char *pEnd; \
int64_t crc; \
int crc; \
\
crc = init_value; \
pEnd = (unsigned char *)key + key_len; \
@ -1404,17 +1378,18 @@ static unsigned int crc_table[256] = {
crc = crc_table[(crc ^ *pKey) & 0xFF] ^ (crc >> 8); \
} \
int CRC32(const void *key, const int key_len)
int CRC32(void *key, const int key_len)
{
CRC32_BODY(CRC32_XINIT)
return (int)(crc ^ CRC32_XOROT);
return crc ^ CRC32_XOROT;
}
int64_t CRC32_ex(const void *key, const int key_len, \
const int64_t init_value)
int CRC32_ex(void *key, const int key_len, \
const int init_value)
{
CRC32_BODY(init_value)
return crc;
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#ifndef _HASH_H_
#define _HASH_H_
@ -24,7 +17,7 @@
extern "C" {
#endif
#define CRC32_XINIT 0xFFFFFFFF /* initial value */
#define CRC32_XINIT 0xFFFFFFFF /* initial value */
#define CRC32_XOROT 0xFFFFFFFF /* final xor value */
typedef int (*HashFunc) (const void *key, const int key_len);
@ -93,16 +86,16 @@ typedef struct tagHashStat
* parameters:
* index: item index based 0
* data: hash data, including key and value
* args: passed by fc_hash_walk function
* args: passed by hash_walk function
* return 0 for success, != 0 for error
*/
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
#define fc_hash_init(pHash, hash_func, capacity, load_factor) \
fc_hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
#define hash_init(pHash, hash_func, capacity, load_factor) \
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
#define fc_hash_insert(pHash, key, key_len, value) \
fc_hash_insert_ex(pHash, key, key_len, value, 0, true)
#define hash_insert(pHash, key, key_len, value) \
hash_insert_ex(pHash, key, key_len, value, 0, true)
/**
* hash init function
@ -110,12 +103,12 @@ typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
* pHash: the hash table
* hash_func: hash function
* capacity: init capacity
* load_factor: hash load factor (or watermark), >= 0.10 for auto rehash. eg. 0.75
* load_factor: hash load factor, such as 0.75
* max_bytes: max memory can be used (bytes)
* bMallocValue: if need malloc value buffer
* return 0 for success, != 0 for error
*/
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
int 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 +118,7 @@ int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
* lock_count: the lock count
* return 0 for success, != 0 for error
*/
int fc_hash_set_locks(HashArray *pHash, const int lock_count);
int hash_set_locks(HashArray *pHash, const int lock_count);
/**
* convert the value
@ -137,12 +130,12 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count);
* arg: the user data
* return the number after increasement
*/
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
int64_t hash_inc_value(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg);
#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)
#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)
/**
* atomic increase value
@ -158,7 +151,7 @@ int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
* return 0 for success, != 0 for error (errno)
*
*/
int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
int 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 +161,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
* pHash: the hash table
* return none
*/
void fc_hash_destroy(HashArray *pHash);
void hash_destroy(HashArray *pHash);
/**
* hash insert key
@ -182,7 +175,7 @@ void fc_hash_destroy(HashArray *pHash);
* return >= 0 for success, 0 for key already exist (update),
* 1 for new key (insert), < 0 for error
*/
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
void *value, const int value_len, const bool needLock);
/**
@ -193,7 +186,7 @@ int fc_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 *fc_hash_find(HashArray *pHash, const void *key, const int key_len);
void *hash_find(HashArray *pHash, const void *key, const int key_len);
/**
* hash find key
@ -203,38 +196,8 @@ void *fc_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 *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len);
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
/**
* hash find key
* parameters:
* pHash: the hash table
* key: the key to find
* return user data, return NULL when the key not exist
*/
static inline void *fc_hash_find1(HashArray *pHash, const string_t *key)
{
return fc_hash_find(pHash, key->str, key->len);
}
/**
* hash get the value of the key
* parameters:
* pHash: the hash table
* key: the key to find
* value: store the value
* return 0 for success, != 0 fail (errno)
*/
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value);
/**
* hash find key
* parameters:
* pHash: the hash table
* key: the key to find
* return hash data, return NULL when the key not exist
*/
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key);
/**
* hash get the value of the key
@ -247,7 +210,7 @@ HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key);
* output for the length fo the value
* return 0 for success, != 0 fail (errno)
*/
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
int hash_get(HashArray *pHash, const void *key, const int key_len,
void *value, int *value_len);
@ -262,7 +225,7 @@ int fc_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 fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
const char *value, const int offset, const int value_len);
/**
@ -273,7 +236,7 @@ int fc_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 fc_hash_delete(HashArray *pHash, const void *key, const int key_len);
int hash_delete(HashArray *pHash, const void *key, const int key_len);
/**
* hash walk (iterator)
@ -283,7 +246,7 @@ int fc_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 fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
/**
* get hash item count
@ -291,7 +254,7 @@ int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
* pHash: the hash table
* return item count
*/
int fc_hash_count(HashArray *pHash);
int hash_count(HashArray *pHash);
/**
* hash best optimize
@ -300,7 +263,7 @@ int fc_hash_count(HashArray *pHash);
* suggest_capacity: suggest init capacity for speed
* return >0 for success, < 0 fail (errno)
*/
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity);
int hash_best_op(HashArray *pHash, const int suggest_capacity);
/**
* hash stat
@ -314,7 +277,7 @@ int fc_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 fc_hash_stat(HashArray *pHash, HashStat *pStat, \
int hash_stat(HashArray *pHash, HashStat *pStat, \
int *stat_by_lens, const int stat_size);
/**
@ -323,7 +286,7 @@ int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
* pHash: the hash table
* return none
*/
void fc_hash_stat_print(HashArray *pHash);
void hash_stat_print(HashArray *pHash);
/**
* lock the bucket of hash table
@ -332,7 +295,7 @@ void fc_hash_stat_print(HashArray *pHash);
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
/**
* unlock the bucket of hash table
@ -341,7 +304,7 @@ int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
int RSHash(const void *key, const int key_len);
@ -383,13 +346,13 @@ 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 fc_simple_hash(const void* key, const int key_len);
int fc_simple_hash_ex(const void* key, const int key_len, \
int simple_hash(const void* key, const int key_len);
int simple_hash_ex(const void* key, const int key_len, \
const int init_value);
int CRC32(const void *key, const int key_len);
int64_t CRC32_ex(const void *key, const int key_len, \
const int64_t init_value);
int CRC32(void *key, const int key_len);
int CRC32_ex(void *key, const int key_len, \
const int init_value);
#define CRC32_FINAL(crc) (crc ^ CRC32_XOROT)
@ -402,7 +365,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] = fc_simple_hash_ex(buff, buff_len, hash_codes[2]); \
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
@ -410,7 +373,7 @@ int64_t CRC32_ex(const void *key, const int key_len, \
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
unsigned int *fc_hash_get_prime_capacity(const int capacity);
unsigned int *hash_get_prime_capacity(const int capacity);
#ifdef __cplusplus
}

View File

@ -1,25 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <time.h>
@ -36,133 +21,6 @@
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
#include "fc_memory.h"
#include "http_func.h"
#ifdef USE_LIBCURL
#include <curl/curl.h>
static bool curl_inited = false;
typedef struct {
char *buff;
int length;
int alloc_size;
bool dynamic_alloc;
} CurlCallbackArg;
static size_t curl_write_data(void *ptr, size_t size,
size_t nmemb, void *userdata)
{
size_t len;
int alloc_size;
char *new_buff;
CurlCallbackArg *cbarg;
cbarg = (CurlCallbackArg *)userdata;
len = size * nmemb;
if ((cbarg->alloc_size - cbarg->length) < len) {
if (!cbarg->dynamic_alloc) {
return 0;
}
alloc_size = 2 * cbarg->alloc_size;
while ((alloc_size - cbarg->length) < len) {
alloc_size *= 2;
}
new_buff = (char *)fc_malloc(alloc_size);
if (new_buff == NULL) {
return 0;
}
if (cbarg->length > 0) {
memcpy(new_buff, cbarg->buff, cbarg->length);
}
free(cbarg->buff);
cbarg->buff = new_buff;
cbarg->alloc_size = alloc_size;
}
memcpy(cbarg->buff + cbarg->length, ptr, len);
cbarg->length += len;
return len;
}
int get_url_content_ex(const char *url, const int url_len,
const int connect_timeout, const int network_timeout,
int *http_status, char **content, int *content_len,
char *error_info)
{
CURLcode result;
long response_code;
CURL *curl;
CurlCallbackArg cbarg;
*error_info = '\0';
*http_status = 0;
if (!curl_inited) {
if ((result=curl_global_init(CURL_GLOBAL_ALL)) != 0) {
sprintf(error_info, "curl_global_init fail "
"with code: %d", result);
return errno != 0 ? errno : EBUSY;
}
curl_inited = true;
}
if ((curl=curl_easy_init()) == NULL) {
sprintf(error_info, "curl_easy_init fail");
return errno != 0 ? errno : EBUSY;
}
if (*content == NULL) {
cbarg.dynamic_alloc = true;
cbarg.alloc_size = 16 * 1024;
cbarg.buff = (char *)fc_malloc(cbarg.alloc_size);
if (cbarg.buff == NULL) {
return ENOMEM;
}
} else {
cbarg.dynamic_alloc = false;
cbarg.alloc_size = *content_len;
cbarg.buff = *content;
}
cbarg.length = 0;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, connect_timeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, connect_timeout + network_timeout);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cbarg);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
result = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
curl_easy_cleanup(curl);
*http_status = response_code;
if (result == CURLE_OK) {
if (cbarg.dynamic_alloc) {
*content = cbarg.buff;
}
*content_len = cbarg.length;
*(*content + *content_len) = '\0';
return 0;
} else {
sprintf(error_info, "curl_easy_perform fail with code: %d, %s",
result, curl_easy_strerror(result));
if (cbarg.dynamic_alloc && cbarg.buff != NULL) {
free(cbarg.buff);
}
*content_len = 0;
return EACCES;
}
}
#else
int get_url_content_ex(const char *url, const int url_len,
const int connect_timeout, const int network_timeout,
@ -185,7 +43,6 @@ int get_url_content_ex(const char *url, const int url_len,
char *pPort;
char *pSpace;
*error_info = '\0';
*http_status = 0;
if (*content == NULL)
{
@ -272,7 +129,7 @@ int get_url_content_ex(const char *url, const int url_len,
close(sock);
sprintf(error_info, "file: "__FILE__", line: %d, " \
"connect to %s:%u fail, errno: %d, " \
"connect to %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
@ -281,7 +138,7 @@ int get_url_content_ex(const char *url, const int url_len,
out_len = snprintf(out_buff, sizeof(out_buff), \
"GET %s HTTP/1.0\r\n" \
"Host: %s:%u\r\n" \
"Host: %s:%d\r\n" \
"Connection: close\r\n" \
"\r\n", pURI, domain_name, port);
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
@ -289,7 +146,7 @@ int get_url_content_ex(const char *url, const int url_len,
close(sock);
sprintf(error_info, "file: "__FILE__", line: %d, " \
"send data to %s:%u fail, errno: %d, " \
"send data to %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
@ -298,11 +155,18 @@ int get_url_content_ex(const char *url, const int url_len,
if (bNeedAlloc)
{
*content = (char *)fc_malloc(alloc_size + 1);
*content = (char *)malloc(alloc_size + 1);
if (*content == NULL)
{
close(sock);
return ENOMEM;
result = errno != 0 ? errno : ENOMEM;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"malloc %d bytes fail, errno: %d, " \
"error info: %s", __LINE__, alloc_size + 1, \
result, STRERROR(result));
return result;
}
}
@ -314,12 +178,20 @@ int get_url_content_ex(const char *url, const int url_len,
if (bNeedAlloc)
{
alloc_size *= 2;
*content = (char *)fc_realloc(*content, alloc_size + 1);
*content = (char *)realloc(*content, alloc_size + 1);
if (*content == NULL)
{
*content_len = 0;
close(sock);
return ENOMEM;
result = errno != 0 ? errno : ENOMEM;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"realloc %d bytes fail, errno: %d, " \
"error info: %s", __LINE__, \
alloc_size + 1, \
result, STRERROR(result));
return result;
}
recv_bytes = alloc_size - *content_len;
@ -347,7 +219,7 @@ int get_url_content_ex(const char *url, const int url_len,
}
else {
sprintf(error_info, "file: "__FILE__", line: %d, " \
"recv data from %s:%u fail, errno: %d, " \
"recv data from %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
@ -359,7 +231,7 @@ int get_url_content_ex(const char *url, const int url_len,
if (pContent == NULL)
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"response data from %s:%u is invalid", \
"response data from %s:%d is invalid", \
__LINE__, domain_name, port);
result = EINVAL;
@ -371,7 +243,7 @@ int get_url_content_ex(const char *url, const int url_len,
if (pSpace == NULL || pSpace >= pContent)
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"response data from %s:%u is invalid", \
"response data from %s:%d is invalid", \
__LINE__, domain_name, port);
result = EINVAL;
@ -380,8 +252,9 @@ int get_url_content_ex(const char *url, const int url_len,
*http_status = atoi(pSpace + 1);
*content_len -= pContent - *content;
memmove(*content, pContent, *content_len);
memcpy(*content, pContent, *content_len);
*(*content + *content_len) = '\0';
*error_info = '\0';
} while (0);
close(sock);
@ -395,8 +268,6 @@ int get_url_content_ex(const char *url, const int url_len,
return result;
}
#endif
int get_url_content(const char *url, const int connect_timeout, \
const int network_timeout, int *http_status, \
char **content, int *content_len, char *error_info)

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#ifndef _HTTP_FUNC_H
#define _HTTP_FUNC_H
@ -23,14 +16,6 @@
#include <ctype.h>
#include "common_define.h"
#define IS_URL_RESOURCE(str) \
((strncasecmp(str, "http://", 7) == 0) || \
(strncasecmp(str, "https://", 8) == 0))
#define IS_URL_RESOURCE_EX(s) \
((s)->len >= 8 && ((memcmp((s)->str, "http://", 7) == 0) || \
(memcmp((s)->str, "https://", 8) == 0)))
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <time.h>
#include <stdio.h>
@ -84,7 +77,6 @@ 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)
@ -101,28 +93,16 @@ 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_IPv4) == 0)
else if (strcmp(local_ip, LOCAL_LOOPBACK_IP) == 0)
{
/* 注意当系统存在IPv6回环地址时为了简化系统的改动
IPv6IPv4
IPv6
*/
logWarning("file: "__FILE__", line: %d, "
"can't get local ip address, set to %s or %s",
__LINE__, LOCAL_LOOPBACK_IPv4, LOCAL_LOOPBACK_IPv6);
"can't get local ip address, set to %s",
__LINE__, LOCAL_LOOPBACK_IP);
}
}
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
{
if (inet_pton(AF_INET, local_ip, &ip_addr) != 1)
{
logError("file: "__FILE__", line: %d, "
"invalid local ip address: %s",
__LINE__, local_ip);
@ -136,14 +116,13 @@ 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 | O_CLOEXEC)) < 0)
if ((context->fd = open(filename, O_RDWR)) < 0)
{
if (errno == ENOENT)
{
mode_t old_mode;
old_mode = umask(0);
if ((context->fd=open(filename, O_RDWR | O_CREAT |
O_CLOEXEC, mode)) < 0)
if ((context->fd=open(filename, O_RDWR | O_CREAT, mode)) < 0)
{
result = errno != 0 ? errno : EACCES;
}
@ -203,13 +182,12 @@ void id_generator_destroy(struct idg_context *context)
}
}
int id_generator_next_extra_ptr(struct idg_context *context,
const int *extra, int64_t *id)
int id_generator_next_extra(struct idg_context *context, const int extra,
int64_t *id)
{
int result;
int len;
int bytes;
int new_extra;
int64_t sn;
char buff[32];
char *endptr;
@ -272,18 +250,9 @@ int id_generator_next_extra_ptr(struct idg_context *context,
file_unlock(context->fd);
if (extra == NULL)
{
new_extra = sn % (1 << context->extra_bits);
}
else
{
new_extra = *extra;
}
*id = (((int64_t)time(NULL)) << context->mes_bits_sum) |
context->masked_mid |
((new_extra << context->sn_bits) & context->extra_mask) |
context->masked_mid | ((extra << context->sn_bits) & context->extra_mask) |
(sn & context->sn_mask);
return result;
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2016 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
/**
64 bits id generator for multi processes, the generated id format:
@ -26,6 +19,7 @@
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <fcntl.h>
#include "common_define.h"
@ -128,42 +122,15 @@ static inline int id_generator_init(struct idg_context *context, const char *fil
void id_generator_destroy(struct idg_context *context);
/**
* generate next id with extra pointer
* parameter:
* context: the id generator context
* extra: the extra data pointer, NULL for set extra data to sn % (1 << extra_bits)
* id: store the id
* return error no, 0 for success, none zero for fail
*/
int id_generator_next_extra_ptr(struct idg_context *context,
const int *extra, int64_t *id);
/**
* generate next id with extra data
* generate next id ex
* parameter:
* context: the id generator context
* extra: the extra data
* id: store the id
* return error no, 0 for success, none zero for fail
*/
static inline int id_generator_next_extra(struct idg_context *context,
const int extra, int64_t *id)
{
return id_generator_next_extra_ptr(context, &extra, id);
}
/**
* generate next id, set extra data to sn % (1 << extra_bits)
* parameter:
* context: the id generator context
* id: store the id
* return error no, 0 for success, none zero for fail
*/
static inline int id_generator_next_extra_by_mod(struct idg_context *context,
int64_t *id)
{
return id_generator_next_extra_ptr(context, NULL, id);
}
int id_generator_next_extra(struct idg_context *context, const int extra,
int64_t *id);
/**
* generate next id
@ -174,8 +141,7 @@ static inline int id_generator_next_extra_by_mod(struct idg_context *context,
*/
static inline int id_generator_next(struct idg_context *context, int64_t *id)
{
const int extra = 0;
return id_generator_next_extra_ptr(context, &extra, id);
return id_generator_next_extra(context, 0, id);
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//ini_file_reader.h
#ifndef INI_FILE_READER_H
@ -23,53 +16,44 @@
#include "common_define.h"
#include "hash.h"
#define FAST_INI_ITEM_NAME_LEN 63
#define FAST_INI_ITEM_VALUE_LEN 255
#define FAST_INI_ITEM_NAME_SIZE (FAST_INI_ITEM_NAME_LEN + 1)
#define FAST_INI_ITEM_VALUE_SIZE (FAST_INI_ITEM_VALUE_LEN + 1)
#define FAST_INI_ITEM_NAME_LEN 64
#define FAST_INI_ITEM_VALUE_LEN 256
#define FAST_INI_ANNOTATION_WITHOUT_BUILTIN 0
#define FAST_INI_ANNOTATION_DISABLE 1
#define FAST_INI_ANNOTATION_WITH_BUILTIN 2
#define FAST_INI_ANNOTATION_NONE FAST_INI_ANNOTATION_DISABLE
#define FAST_INI_FLAGS_NONE 0
#define FAST_INI_FLAGS_SHELL_EXECUTE 1
#define FAST_INI_FLAGS_DISABLE_SAME_SECTION_MERGE 2
#define FAST_INI_FLAGS_NONE 0
#define FAST_INI_FLAGS_SHELL_EXECUTE 1
typedef bool (*IniSectionNameFilterFunc)(const char *section_name,
const int name_len, void *args);
typedef struct {
char *func_name;
int (*func_init) ();
void (*func_destroy) ();
int (*func_get) (char *key, char **pOutValue, int max_values);
} AnnotationMap;
#define FAST_INI_SET_FULL_CTX_EX(ctx, config_file, sname, ini_context) \
do { \
ctx.filename = config_file; \
ctx.section_name = sname; \
ctx.context = ini_context; \
} while (0)
#define FAST_INI_SET_FULL_CTX(ctx, config_file, sname) \
FAST_INI_SET_FULL_CTX_EX(ctx, config_file, sname, NULL)
typedef struct ini_item
typedef struct
{
char name[FAST_INI_ITEM_NAME_SIZE];
char value[FAST_INI_ITEM_VALUE_SIZE];
char name[FAST_INI_ITEM_NAME_LEN + 1];
char value[FAST_INI_ITEM_VALUE_LEN + 1];
} IniItem;
typedef struct ini_section
typedef struct
{
IniItem *items;
int count; //item count
int alloc;
int alloc_count;
} IniSection;
typedef struct ini_section_info
typedef struct
{
char section_name[FAST_INI_ITEM_NAME_SIZE];
char section_name[FAST_INI_ITEM_NAME_LEN + 1];
IniSection *pSection;
} IniSectionInfo;
typedef struct ini_context
typedef struct
{
IniSection global;
HashArray sections; //key is session name, and value is IniSection
@ -79,31 +63,6 @@ typedef struct ini_context
char flags;
} IniContext;
typedef struct ini_full_context
{
const char *filename;
const char *section_name;
IniContext *context;
} IniFullContext;
typedef struct ini_annotation_entry {
char *func_name;
void *arg;
void *dlhandle;
int (*func_init) (struct ini_annotation_entry *annotation);
void (*func_destroy) (struct ini_annotation_entry *annotation);
int (*func_get) (IniContext *context,
struct ini_annotation_entry *annotation,
const IniItem *item,
char **pOutValue, int max_values);
void (*func_free) (struct ini_annotation_entry *annotation,
char **values, const int count);
bool inited;
} AnnotationEntry;
#ifdef __cplusplus
extern "C" {
#endif
@ -114,67 +73,9 @@ extern "C" {
strcasecmp(pValue, "on") == 0 || \
strcmp(pValue, "1") == 0)
#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)
#define iniGetInt64Value(szSectionName, szItemName, pContext, nDefaultValue) \
iniGetInt64ValueEx(szSectionName, szItemName, \
pContext, nDefaultValue, false)
#define iniGetDoubleValue(szSectionName, szItemName, pContext, dbDefaultValue) \
iniGetDoubleValueEx(szSectionName, szItemName, \
pContext, dbDefaultValue, false)
#define iniGetBoolValue(szSectionName, szItemName, pContext, bDefaultValue) \
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)
#define iniGetIntCorrectValue(ini_ctx, item_name, \
default_value, min_value, max_value) \
iniGetIntCorrectValueEx(ini_ctx, item_name, \
default_value, min_value, max_value, false)
#define iniGetInt64CorrectValue(ini_ctx, item_name, \
default_value, min_value, max_value) \
iniGetInt64CorrectValueEx(ini_ctx, item_name, \
default_value, min_value, max_value, false)
#define iniGetByteCorrectValue(ini_ctx, item_name, \
default_value, min_value, max_value) \
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);
int iniSetAnnotationCallBack(AnnotationMap *map, int count);
void iniDestroyAnnotationCallBack();
void iniAnnotationFreeValues(struct ini_annotation_entry *annotation,
char **values, const int count);
/** load ini items from file
* parameters:
* szFilename: the filename, can be an URL
@ -183,16 +84,6 @@ void iniAnnotationFreeValues(struct ini_annotation_entry *annotation,
*/
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
/** load ini items from file with flags
* parameters:
* szFilename: the filename, can be an URL
* pContext: the ini context
* flags: the flags
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromFile1(const char *szFilename,
IniContext *pContext, const char flags);
/** load ini items from file
* parameters:
* szFilename: the filename, can be an URL
@ -204,7 +95,7 @@ int iniLoadFromFile1(const char *szFilename,
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
const char annotation_type, AnnotationEntry *annotations, const int count,
const char annotation_type, AnnotationMap *annotations, const int count,
const char flags);
/** load ini items from string buffer
@ -226,18 +117,9 @@ int iniLoadFromBuffer(char *content, IniContext *pContext);
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromBufferEx(char *content, IniContext *pContext,
const char annotation_type, AnnotationEntry *annotations, const int count,
const char annotation_type, AnnotationMap *annotations, const int count,
const char flags);
/** load ini items from string buffer with flags
* parameters:
* content: the string buffer to parse
* pContext: the ini context
* flags: the flags
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromBuffer1(char *content, IniContext *pContext, const char flags);
/** free ini context
* parameters:
* pContext: the ini context
@ -247,33 +129,18 @@ 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
* bRetryGlobal: if fetch from global section when the item not exist
* return: item value, return NULL when the item not exist
*/
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);
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
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
@ -286,215 +153,63 @@ 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
* nDefaultValue: the default value
* bRetryGlobal: if fetch from global section when the item not exist
* return: item value, return nDefaultValue when the item not exist
*/
int iniGetIntValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int nDefaultValue, const bool bRetryGlobal);
/** check and correct int value
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* nValue: the item value
* nMinValue: the min value to check (including)
* nMaxValue: the max value to check (including)
* return: corrected value
*/
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
* szItemName: the item name
* nDefaultValue: the default value
* nMinValue: the min value to check (including)
* nMaxValue: the max value to check (including)
* bRetryGlobal: if fetch from global section when the item not exist
* return: item value, return nDefaultValue when the item not exist
*/
int iniGetIntCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, const int nDefaultValue,
const int nMinValue, const int nMaxValue, const bool bRetryGlobal);
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int nDefaultValue);
/** 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
* nTargetCount: store the item value count
* return: item value array, return NULL when the item not exist
*/
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName,
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
IniContext *pContext, int *nTargetCount);
/** get item value (64 bits integer)
/** get item int64 value (64 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
* nDefaultValue: the default value
* bRetryGlobal: if fetch from global section when the item not exist
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetInt64ValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const bool bRetryGlobal);
/** get item correct value (64 bits integer)
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* nDefaultValue: the default value
* nMinValue: the min value to check (including)
* nMaxValue: the max value to check (including)
* bRetryGlobal: if fetch from global section when the item not exist
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetInt64CorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, const int64_t nDefaultValue,
const int64_t nMinValue, const int64_t nMaxValue,
const bool bRetryGlobal);
/** get item byte value (64 bits integer)
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nDefaultValue: the default value
* nDefaultUnitBytes: the default byte unit, such as 1 for byte, 1024 for KB
* bRetryGlobal: if fetch from global section when the item not exist
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetByteValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const int64_t nDefaultValue, const int nDefaultUnitBytes,
const bool bRetryGlobal);
/** get item correct byte value (64 bits integer)
* parameters:
* pIniContext: the full ini context
* szItemName: the item name
* nDefaultValue: the default value
* nDefaultUnitBytes: the default byte unit, such as 1 for byte, 1024 for KB
* nMinValue: the min value to check (including)
* nMaxValue: the max value to check (including)
* bRetryGlobal: if fetch from global section when the item not exist
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetByteCorrectValueEx(IniFullContext *pIniContext,
const char *szItemName, const int64_t nDefaultValue,
const int nDefaultUnitBytes, const int64_t nMinValue,
const int64_t nMaxValue, const bool bRetryGlobal);
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int64_t nDefaultValue);
/** 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
* bDefaultValue: the default value
* bRetryGlobal: if fetch from global section when the item not exist
* return: item boolean value, return bDefaultValue when the item not exist
*/
bool iniGetBoolValueEx(const char *szSectionName,
const char *szItemName, IniContext *pContext,
const bool bDefaultValue, const bool bRetryGlobal);
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const bool bDefaultValue);
/** 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
* dbDefaultValue: the default value
* bRetryGlobal: if fetch from global section when the item not exist
* return: item value, return dbDefaultValue when the item not exist
*/
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:
* ini_ctx: the full context
* item_name: the item name
* item_value: store the item value
* default_value: the default value
* retry_global: if fetch from global section when the item not exist
* return: error no, 0 for success, != 0 for fail
*/
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);
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const double dbDefaultValue);
/** print all items
* parameters:
@ -513,7 +228,7 @@ static inline const char *iniGetConfigPath(IniContext *pContext)
return pContext->config_path;
}
/** return the section names
/** return the items of global section
* parameters:
* pContext: the ini context
* sections: the section array
@ -524,60 +239,6 @@ static inline const char *iniGetConfigPath(IniContext *pContext)
int iniGetSectionNames(IniContext *pContext, IniSectionInfo *sections,
const int max_size, int *nCount);
/** return the section names
* parameters:
* pContext: the ini context
* prefix: the prefix of section name
* sections: the section array
* max_size: the max size of sections
* nCount: return the section count
* return: errno, 0 for success, != 0 for fail
*/
int iniGetSectionNamesByPrefix(IniContext *pContext, const char *szPrefix,
IniSectionInfo *sections, const int max_size, int *nCount);
/** return the section names
* parameters:
* pContext: the ini context
* filter_func: the section name filter function
* args: the extra data pointer
* sections: the section array
* max_size: the max size of sections
* nCount: return the section count
* return: errno, 0 for success, != 0 for fail
*/
int iniGetSectionNamesEx(IniContext *pContext, IniSectionNameFilterFunc
filter_func, void *args, IniSectionInfo *sections,
const int max_size, int *nCount);
/** get matched section count
* parameters:
* pContext: the ini context
* filter_func: the section name filter function
* args: the extra data pointer
* return: matched section count
*/
int iniGetSectionCountEx(IniContext *pContext, IniSectionNameFilterFunc
filter_func, void *args);
/** get matched section count
* parameters:
* pContext: the ini context
* prefix: the prefix of section name
* return: matched section count
*/
int iniGetSectionCountByPrefix(IniContext *pContext, const char *szPrefix);
/** get section count
* parameters:
* pContext: the ini context
* return: section count
*/
static inline int iniGetSectionCount(IniContext *pContext)
{
return pContext->sections.item_count;
}
/** return the items of global section
* parameters:
* pContext: the ini context
@ -601,25 +262,6 @@ static inline IniItem *iniGetGlobalItems(IniContext *pContext, int *nCount)
IniItem *iniGetSectionItems(const char *szSectionName, IniContext *pContext,
int *nCount);
/** get item string value
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nMinLength: the min value length
* return: item value, return NULL when the item not exist
*/
char *iniGetRequiredStrValueEx(const char *szSectionName, const char *szItemName,
IniContext *pContext, const int nMinLength);
static inline char *iniGetRequiredStrValue(const char *szSectionName,
const char *szItemName, IniContext *pContext)
{
const int nMinLength = 1;
return iniGetRequiredStrValueEx(szSectionName, szItemName, pContext, nMinLength);
}
#ifdef __cplusplus
}
#endif

View File

@ -1,3 +1,11 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

View File

@ -1,3 +1,11 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#ifndef IO_OPT_H_
#define IO_OPT_H_

View File

@ -1,24 +1,8 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "fc_memory.h"
#include "ioevent.h"
#if IOEVENT_USE_KQUEUE
@ -45,119 +29,61 @@ int kqueue_ev_convert(int16_t event, uint16_t flags)
}
#endif
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 ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout_ms, const int extra_events)
{
int bytes;
int bytes;
ioevent->iterator.index = 0;
ioevent->iterator.count = 0;
ioevent->service_name = service_name;
ioevent->size = size;
ioevent->extra_events = extra_events;
ioevent->size = size;
ioevent->extra_events = extra_events;
ioevent->iterator.index = 0;
ioevent->iterator.count = 0;
#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
#if IOEVENT_USE_EPOLL
ioevent->poll_fd = epoll_create(ioevent->size);
bytes = sizeof(struct epoll_event) * size;
ioevent->events = (struct epoll_event *)malloc(bytes);
#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();
bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)malloc(bytes);
ioevent->care_events = 0;
#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();
bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)malloc(bytes);
#endif
#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
if (ioevent->events == NULL) {
return errno != 0 ? errno : ENOMEM;
}
ioevent_set_timeout(ioevent, timeout_ms);
ioevent_set_timeout(ioevent, timeout_ms);
return 0;
return 0;
}
void ioevent_destroy(IOEventPoller *ioevent)
{
#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->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
if (ioevent->poll_fd >= 0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
#if IOEVENT_USE_URING
}
#endif
if (ioevent->poll_fd >= 0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
}
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)
{
#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
#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);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int n = 0;
@ -167,68 +93,46 @@ int ioevent_attach(IOEventPoller *ioevent, const int fd,
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
if (n == 0) {
return ENOENT;
}
ioevent->care_events = e;
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#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)
{
#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
#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);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int result;
int n = 0;
if (e & IOEVENT_READ) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
else if ((ioevent->care_events & IOEVENT_READ)) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
}
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
else if ((ioevent->care_events & IOEVENT_WRITE)) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
}
result = kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
if (result == -1) {
result = ioevent_detach(ioevent, fd);
if (e & (IOEVENT_READ | IOEVENT_WRITE)) {
result = ioevent_attach(ioevent, fd, e, data);
}
ioevent->care_events = e;
if (n > 0) {
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
}
else {
return 0;
}
return result;
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#endif
@ -236,36 +140,25 @@ int ioevent_modify(IOEventPoller *ioevent, const int fd,
int ioevent_detach(IOEventPoller *ioevent, const int fd)
{
#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
#if IOEVENT_USE_EPOLL
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[1];
int r, w;
struct kevent ev[2];
int n = 0;
if ((ioevent->care_events & IOEVENT_READ)) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
}
if ((ioevent->care_events & IOEVENT_WRITE)) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
}
EV_SET(&ev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
r = kevent(ioevent->poll_fd, ev, 1, NULL, 0, NULL);
EV_SET(&ev[0], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
w = kevent(ioevent->poll_fd, ev, 1, NULL, 0, NULL);
return (r == 0 || w == 0) ? 0 : r;
ioevent->care_events = 0;
if (n > 0) {
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
}
else {
return 0;
}
#elif IOEVENT_USE_PORT
return port_dissociate(ioevent->poll_fd, PORT_SOURCE_FD, fd);
#endif
@ -273,33 +166,15 @@ int ioevent_detach(IOEventPoller *ioevent, const int fd)
int ioevent_poll(IOEventPoller *ioevent)
{
#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
#if IOEVENT_USE_EPOLL
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
#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;
@ -325,3 +200,4 @@ int ioevent_poll(IOEventPoller *ioevent)
#error port me
#endif
}

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
#ifndef __IOEVENT_H__
#define __IOEVENT_H__
@ -20,28 +5,17 @@
#include <poll.h>
#include <sys/time.h>
#include "_os_define.h"
#include "logger.h"
#define IOEVENT_TIMEOUT (1 << 20)
#define IOEVENT_NOTIFY (1 << 21) //for io_uring send_zc done callback
#ifdef OS_LINUX
#include <sys/epoll.h>
#define IOEVENT_EDGE_TRIGGER EPOLLET
#endif
#define IOEVENT_TIMEOUT 0x8000
#if IOEVENT_USE_EPOLL
#include <sys/epoll.h>
#define IOEVENT_EDGE_TRIGGER EPOLLET
#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>
@ -76,78 +50,63 @@ 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;
#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
#ifdef OS_LINUX
#if IOEVENT_USE_EPOLL
struct epoll_event *events;
int timeout_ms; //for epoll
#if IOEVENT_USE_URING
struct io_uring_cqe *cqe;
struct __kernel_timespec timeout;
#endif
bool zero_timeout;
int timeout;
#elif IOEVENT_USE_KQUEUE
struct kevent *events;
struct timespec timeout;
int care_events;
#elif IOEVENT_USE_PORT
port_event_t *events;
timespec_t timeout;
#endif
} IOEventPoller;
#if OS_LINUX
#if IOEVENT_USE_EPOLL
#define IOEVENT_GET_EVENTS(ioevent, index) \
(ioevent)->events[index].events
ioevent->events[index].events
#elif IOEVENT_USE_KQUEUE
#define IOEVENT_GET_EVENTS(ioevent, index) kqueue_ev_convert( \
(ioevent)->events[index].filter, (ioevent)->events[index].flags)
ioevent->events[index].filter, ioevent->events[index].flags)
#elif IOEVENT_USE_PORT
#define IOEVENT_GET_EVENTS(ioevent, index) \
(ioevent)->events[index].portev_events
ioevent->events[index].portev_events
#else
#error port me
#endif
#ifdef OS_LINUX
#if IOEVENT_USE_EPOLL
#define IOEVENT_GET_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr
ioevent->events[index].data.ptr
#elif IOEVENT_USE_KQUEUE
#define IOEVENT_GET_DATA(ioevent, index) \
(ioevent)->events[index].udata
ioevent->events[index].udata
#elif IOEVENT_USE_PORT
#define IOEVENT_GET_DATA(ioevent, index) \
(ioevent)->events[index].portev_user
ioevent->events[index].portev_user
#else
#error port me
#endif
#ifdef OS_LINUX
#if IOEVENT_USE_EPOLL
#define IOEVENT_CLEAR_DATA(ioevent, index) \
(ioevent)->events[index].data.ptr = NULL
ioevent->events[index].data.ptr = NULL
#elif IOEVENT_USE_KQUEUE
#define IOEVENT_CLEAR_DATA(ioevent, index) \
(ioevent)->events[index].udata = NULL
ioevent->events[index].udata = NULL
#elif IOEVENT_USE_PORT
#define IOEVENT_CLEAR_DATA(ioevent, index) \
(ioevent)->events[index].portev_user = NULL
ioevent->events[index].portev_user = NULL
#else
#error port me
#endif
@ -156,39 +115,24 @@ typedef struct ioevent_puller {
extern "C" {
#endif
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 ioevent_init(IOEventPoller *ioevent, 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_ms = timeout_ms;
ioevent->timeout = timeout_ms;
#else
#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);
ioevent->timeout.tv_sec = timeout_ms / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000);
#endif
}
@ -198,114 +142,6 @@ static inline int ioevent_poll_ex(IOEventPoller *ioevent, const int timeout_ms)
return ioevent_poll(ioevent);
}
#if IOEVENT_USE_URING
static inline void ioevent_set_send_zc_done_notify(
IOEventPoller *ioevent, const bool need_notify)
{
ioevent->send_zc_done_notify = need_notify;
}
static inline int ioevent_uring_submit(IOEventPoller *ioevent)
{
int result;
ioevent->submit_count = 0;
while (1) {
result = io_uring_submit(&ioevent->ring);
if (result < 0) {
if (result != -EINTR) {
return -result;
}
} else {
return 0;
}
}
}
static inline struct io_uring_sqe *ioevent_uring_get_sqe(IOEventPoller *ioevent)
{
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
if (sqe == NULL) {
logError("file: "__FILE__", line: %d, "
"io_uring_get_sqe fail", __LINE__);
}
return sqe;
}
static inline void ioevent_uring_prep_recv(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t size, void *user_data)
{
io_uring_prep_recv(sqe, sockfd, buf, size, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_send(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t len, void *user_data)
{
io_uring_prep_send(sqe, sockfd, buf, len, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_writev(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd, const struct iovec *iovecs,
unsigned nr_vecs, void *user_data)
{
io_uring_prep_writev(sqe, sockfd, iovecs, nr_vecs, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_send_zc(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int sockfd,
void *buf, size_t len, void *user_data)
{
io_uring_prep_send_zc(sqe, sockfd, buf, len, 0,
#ifdef IORING_SEND_ZC_REPORT_USAGE
IORING_SEND_ZC_REPORT_USAGE
#else
0
#endif
);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_close(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int fd, void *user_data)
{
io_uring_prep_close(sqe, fd);
if (user_data == NULL) {
/* set sqe->flags MUST after io_uring_prep_xxx */
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
} else {
sqe->user_data = (long)user_data;
}
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_cancel(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, void *user_data)
{
io_uring_prep_cancel(sqe, user_data, 0);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
static inline void ioevent_uring_prep_connect(IOEventPoller *ioevent,
struct io_uring_sqe *sqe, int fd, const struct sockaddr *addr,
socklen_t addrlen, void *user_data)
{
io_uring_prep_connect(sqe, fd, addr, addrlen);
sqe->user_data = (long)user_data;
ioevent->submit_count++;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,133 +1,57 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "sched_thread.h"
#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;
IOEventEntry *pEntry;
for (ioevent->iterator.index=0; ioevent->iterator.index < ioevent->
iterator.count; ioevent->iterator.index++)
for (ioevent->iterator.index=0; ioevent->iterator.index < ioevent->iterator.
count; ioevent->iterator.index++)
{
event = IOEVENT_GET_EVENTS(ioevent, ioevent->iterator.index);
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
ioevent->iterator.index);
if (pEntry != NULL) {
pEntry->callback(pEntry->fd, event, pEntry);
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
}
else {
logDebug("file: "__FILE__", line: %d, "
"ignore ioevent : %d, index: %d",
__LINE__, event, ioevent->iterator.index);
"ignore iovent : %d, index: %d", __LINE__, event, ioevent->iterator.index);
}
}
}
static int ioevent_process_by_poll(IOEventPoller *ioevent)
int ioevent_remove(IOEventPoller *ioevent, void *data)
{
int result;
IOEventEntry *pEntry;
int index;
ioevent->iterator.count = ioevent_poll(ioevent);
if (ioevent->iterator.count > 0) {
deal_ioevents(ioevent);
if (ioevent->iterator.index >= ioevent->iterator.count)
{
return ENOENT;
}
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;
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
ioevent->iterator.index);
if (pEntry != NULL && pEntry->timer.data == 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 && pEntry->timer.data == data) {
logDebug("file: "__FILE__", line: %d, "
"clear iovent data: %p", __LINE__, data);
IOEVENT_CLEAR_DATA(ioevent, index);
return 0;
}
}
return 0;
return ENOENT;
}
static void deal_timeouts(FastTimerEntry *head)
@ -142,214 +66,138 @@ static void deal_timeouts(FastTimerEntry *head)
current = entry;
entry = entry->next;
/* must set NULL because NOT in time wheel */
current->prev = current->next = NULL;
pEventEntry = (IOEventEntry *)current;
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT, current);
current->prev = current->next = NULL; //must set NULL because NOT in time wheel
pEventEntry = (IOEventEntry *)current->data;
if (pEventEntry != NULL)
{
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
current->data);
}
}
}
int ioevent_loop(struct nio_thread_data *thread_data,
void iovent_add_to_deleted_list(struct fast_task_info *pTask)
{
if (pTask->thread_data == NULL) {
return;
}
pTask->next = pTask->thread_data->deleted_list;
pTask->thread_data->deleted_list = pTask;
}
int ioevent_loop(struct nio_thread_data *pThreadData,
IOEventCallback recv_notify_callback, TaskCleanUpCallback
clean_up_callback, volatile bool *continue_flag)
{
int result;
struct ioevent_notify_entry ev_notify;
IOEventEntry ev_notify;
FastTimerEntry head;
struct fast_task_info *task;
struct fast_task_info *pTask;
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(thread_data);
ev_notify.event.callback = recv_notify_callback;
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)
ev_notify.fd = pThreadData->pipe_fds[0];
ev_notify.callback = recv_notify_callback;
if (ioevent_attach(&pThreadData->ev_puller,
pThreadData->pipe_fds[0], 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
#ifdef OS_LINUX
sched_counter = 0;
#endif
thread_data->deleted_list = NULL;
pThreadData->deleted_list = NULL;
last_check_time = g_current_time;
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 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++;
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;
}
//logInfo("cleanup task count: %d", count);
}
if (g_current_time - last_check_time > 0) {
if (pThreadData->deleted_list != NULL)
{
count = 0;
while (pThreadData->deleted_list != NULL)
{
pTask = pThreadData->deleted_list;
pThreadData->deleted_list = pTask->next;
clean_up_callback(pTask);
count++;
}
logDebug("cleanup task count: %d", count);
}
if (g_current_time - last_check_time > 0)
{
last_check_time = g_current_time;
count = fast_timer_timeouts_get(
&thread_data->timer, g_current_time, &head);
&pThreadData->timer, g_current_time, &head);
if (count > 0)
{
deal_timeouts(&head);
}
}
if (thread_data->notify.enabled) {
int64_t n;
if ((n=__sync_fetch_and_add(&thread_data->notify.counter, 0)) != 0)
{
__sync_fetch_and_sub(&thread_data->notify.counter, n);
/*
logInfo("file: "__FILE__", line: %d, "
"n ==== %"PRId64", now: %"PRId64,
__LINE__, n, __sync_fetch_and_add(
&thread_data->notify.counter, 0));
*/
}
}
if (thread_data->thread_loop_callback != NULL) {
thread_data->thread_loop_callback(thread_data);
if (pThreadData->thread_loop_callback != NULL) {
pThreadData->thread_loop_callback(pThreadData);
}
}
return 0;
}
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 result;
task->thread_data = pThread;
task->event.fd = sock;
task->event.callback = callback;
#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
pTask->thread_data = pThread;
pTask->event.fd = sock;
pTask->event.callback = callback;
if (ioevent_attach(&pThread->ev_puller,
sock, event, pTask) < 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;
}
pTask->event.timer.data = pTask;
pTask->event.timer.expires = g_current_time + timeout;
result = fast_timer_add(&pThread->timer, &pTask->event.timer);
if (result != 0)
{
logError("file: "__FILE__", line: %d, " \
"fast_timer_add fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
task->event.timer.expires = g_current_time + timeout;
fast_timer_add(&pThread->timer, &task->event.timer);
return 0;
}
int ioevent_reset(struct fast_task_info *task, int new_fd, short event)
{
if (task->event.fd == new_fd)
{
return 0;
}
if (task->event.fd >= 0)
{
ioevent_detach(&task->thread_data->ev_puller, task->event.fd);
}
task->event.fd = new_fd;
return ioevent_attach(&task->thread_data->ev_puller, new_fd, event, task);
}

View File

@ -1,250 +1,27 @@
/*
* 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/>.
*/
#ifndef _IOEVENT_LOOP_H
#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 *thread_data,
int ioevent_loop(struct nio_thread_data *pThreadData,
IOEventCallback recv_notify_callback, TaskCleanUpCallback
clean_up_callback, volatile bool *continue_flag);
int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback,
const int timeout);
//remove entry from ready list
int ioevent_remove(IOEventPoller *ioevent, void *data);
int ioevent_reset(struct fast_task_info *task, int new_fd, short event);
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback, const int timeout);
static inline bool ioevent_is_canceled(struct fast_task_info *task)
{
return __sync_fetch_and_add(&task->canceled, 0) != 0;
}
//only called by the nio thread
static inline void ioevent_add_to_deleted_list(struct fast_task_info *task)
{
if (!__sync_bool_compare_and_swap(&task->canceled, 0, 1))
{
logWarning("file: "__FILE__", line: %d, "
"task %p already canceled", __LINE__, task);
return;
}
task->next = task->thread_data->deleted_list;
task->thread_data->deleted_list = task;
}
static inline int ioevent_notify_thread(struct nio_thread_data *thread_data)
{
int64_t n;
int result;
if (__sync_fetch_and_add(&thread_data->notify.counter, 1) == 0)
{
n = 1;
if (write(FC_NOTIFY_WRITE_FD(thread_data), &n, sizeof(n)) != sizeof(n))
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to fd %d fail, errno: %d, error info: %s",
__LINE__, FC_NOTIFY_WRITE_FD(thread_data),
result, STRERROR(result));
return result;
}
}
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
void iovent_add_to_deleted_list(struct fast_task_info *pTask);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,564 +0,0 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <errno.h>
#include "shared_func.h"
#include "fc_memory.h"
#include "json_parser.h"
#define EXPECT_STR_LEN 80
#define JSON_SPACE(ch) \
(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
#define JSON_TOKEN(ch) \
((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || \
(ch >= '0' && ch <= '9') || (ch == '_' || ch == '-' || \
ch == '.'))
int fc_detect_json_type(const string_t *input)
{
if (input->len < 2) {
return FC_JSON_TYPE_STRING;
}
if (input->str[0] == '[' && input->str[input->len - 1] == ']') {
return FC_JSON_TYPE_ARRAY;
}
if (input->str[0] == '{' && input->str[input->len - 1] == '}') {
return FC_JSON_TYPE_MAP;
}
return FC_JSON_TYPE_STRING;
}
static void set_parse_error(const char *str, const char *current,
const int expect_len, const char *front,
string_t *error_info, const int error_size)
{
const char *show_str;
int show_len;
show_len = current - str;
if (show_len > expect_len) {
show_len = expect_len;
}
show_str = current - show_len;
error_info->len = snprintf(error_info->str, error_size,
"%s, input: %.*s", front, show_len, show_str);
}
static int json_escape_string(fc_json_context_t *context,
const string_t *input, char *output)
{
const char *src;
const char *end;
char *dest;
dest = output;
end = input->str + input->len;
for (src=input->str; src<end; src++) {
switch (*src) {
case '\\':
*dest++ = '\\';
*dest++ = '\\';
break;
case '\t':
*dest++ = '\\';
*dest++ = 't';
break;
case '\r':
*dest++ = '\\';
*dest++ = 'r';
break;
case '\n':
*dest++ = '\\';
*dest++ = 'n';
break;
case '\b':
*dest++ = '\\';
*dest++ = 'b';
break;
case '\f':
*dest++ = '\\';
*dest++ = 'f';
break;
case '\"':
*dest++ = '\\';
*dest++ = '\"';
break;
case '\0':
*dest++ = '\\';
*dest++ = 'u';
*dest++ = '0';
*dest++ = '0';
*dest++ = '0';
*dest++ = '0';
break;
default:
*dest++ = *src;
break;
}
}
return dest - output;
}
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->decode.element.str;
quote_ch = *context->p;
if (quote_ch == '\"' || quote_ch == '\'') {
context->p++;
while (context->p < context->end && *context->p != quote_ch) {
if (*context->p == '\\') {
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);
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++ = '\\';
break;
case '/':
*dest++ = '/';
break;
case 't':
*dest++ = '\t';
break;
case 'r':
*dest++ = '\r';
break;
case 'n':
*dest++ = '\n';
break;
case 'f':
*dest++ = '\f';
break;
case 'b':
*dest++ = '\b';
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);
return EINVAL;
}
context->p++;
} else {
*dest++ = *context->p++;
}
}
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);
return EINVAL;
}
context->p++; //skip quote char
} else {
while (context->p < context->end && JSON_TOKEN(*context->p)) {
*dest++ = *context->p++;
}
}
*dest = '\0';
context->decode.element.len = dest - context->decode.element.str;
return 0;
}
static int check_alloc_array(fc_json_context_t *context,
fc_common_array_t *array)
{
int bytes;
if (array->count < array->alloc) {
return 0;
}
if (array->alloc == 0) {
array->alloc = 32;
} else {
array->alloc *= 2;
}
bytes = array->element_size * array->alloc;
array->elements = fc_realloc(array->elements, bytes);
if (array->elements == NULL) {
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "realloc %d bytes fail", bytes);
return ENOMEM;
}
return 0;
}
static int prepare_json_parse(fc_json_context_t *context,
const string_t *input, const char lquote,
const char rquote)
{
int expect_size;
int result;
if (input->len < 2) {
context->error_info.len = snprintf(context->error_info.str,
context->error_size, "json string is too short");
return EINVAL;
}
if (input->str[0] != 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) {
context->error_info.len = snprintf(context->error_info.str, context->
error_size, "json array must end with \"%c\"", rquote);
return EINVAL;
}
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->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;
}
static inline void json_quote_string(fc_json_context_t
*context, const string_t *input, char **buff)
{
char *p;
p = *buff;
*p++ = '"';
p += json_escape_string(context, input, p);
*p++ = '"';
*buff = p;
}
int fc_encode_json_array_ex(fc_json_context_t *context,
const string_t *elements, const int count,
BufferInfo *buffer)
{
const string_t *el;
const string_t *end;
char *p;
int expect_size;
expect_size = 3;
end = elements + count;
for (el=elements; el<end; el++) {
expect_size += 6 * el->len + 3;
}
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 = buffer->buff;
*p++ = '[';
for (el=elements; el<end; el++) {
if (el > elements) {
*p++ = ',';
}
json_quote_string(context, el, &p);
}
*p++ = ']';
*p = '\0';
buffer->length = p - buffer->buff;
return 0;
}
int fc_encode_json_map_ex(fc_json_context_t *context,
const key_value_pair_t *elements, const int count,
BufferInfo *buffer)
{
const key_value_pair_t *pair;
const key_value_pair_t *end;
char *p;
int expect_size;
expect_size = 3;
end = elements + count;
for (pair=elements; pair<end; pair++) {
expect_size += 6 * (pair->key.len + pair->value.len) + 5;
}
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 = buffer->buff;
*p++ = '{';
for (pair=elements; pair<end; pair++) {
if (pair > elements) {
*p++ = ',';
}
json_quote_string(context, &pair->key, &p);
*p++ = ':';
json_quote_string(context, &pair->value, &p);
}
*p++ = '}';
*p = '\0';
buffer->length = p - buffer->buff;
return 0;
}
#define JSON_DECODE_COPY_STRING(ctx, input, dest, src) \
do { \
if ((context->error_no=fast_mpool_alloc_string_ex2( \
&ctx->decode.mpool, dest, src)) != 0) \
{ \
set_parse_error(input->str, ctx->p, EXPECT_STR_LEN, \
"out of memory", &ctx->error_info, ctx->error_size); \
return NULL; \
} \
} while (0)
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
*context, const string_t *input)
{
if ((context->error_no=prepare_json_parse(context,
input, '[', ']')) != 0)
{
return NULL;
}
context->jarray.count = 0;
while (context->p < context->end) {
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p == context->end) {
break;
}
if (*context->p == ',') {
set_parse_error(input->str, context->p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p < context->end) {
if (*context->p == ',') {
context->p++; //skip comma
} else {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
}
if ((context->error_no=check_alloc_array(context,
(fc_common_array_t *)
&context->jarray)) != 0)
{
return NULL;
}
if (context->decode.use_mpool) {
JSON_DECODE_COPY_STRING(context, input, context->jarray.elements +
context->jarray.count++, &context->decode.element);
} else {
context->jarray.elements[context->jarray.count++] =
context->decode.element;
}
context->decode.element.str += context->decode.element.len + 1;
}
return &context->jarray;
}
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
*context, const string_t *input)
{
key_value_pair_t kv_pair;
if ((context->error_no=prepare_json_parse(context,
input, '{', '}')) != 0)
{
return NULL;
}
context->jmap.count = 0;
while (context->p < context->end) {
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p == context->end) {
break;
}
if (*context->p == ',') {
set_parse_error(input->str, context->p + 1,
EXPECT_STR_LEN, "unexpect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (!(context->p < context->end && *context->p == ':')) {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect colon \":\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
context->p++; //skip colon
kv_pair.key = context->decode.element;
context->decode.element.str += context->decode.element.len + 1;
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if ((context->error_no=next_json_element(context)) != 0) {
return NULL;
}
while (context->p < context->end && JSON_SPACE(*context->p)) {
context->p++;
}
if (context->p < context->end) {
if (*context->p == ',') {
context->p++; //skip comma
} else {
set_parse_error(input->str, context->p,
EXPECT_STR_LEN, "expect comma \",\"",
&context->error_info, context->error_size);
context->error_no = EINVAL;
return NULL;
}
}
kv_pair.value = context->decode.element;
context->decode.element.str += context->decode.element.len + 1;
if ((context->error_no=check_alloc_array(context,
(fc_common_array_t *)
&context->jmap)) != 0)
{
return NULL;
}
if (context->decode.use_mpool) {
key_value_pair_t *dest;
dest = context->jmap.elements + context->jmap.count++;
JSON_DECODE_COPY_STRING(context, input,
&dest->key, &kv_pair.key);
JSON_DECODE_COPY_STRING(context, input,
&dest->value, &kv_pair.value);
} else {
context->jmap.elements[context->jmap.count++] = kv_pair;
}
}
return &context->jmap;
}

View File

@ -1,237 +0,0 @@
/*
* 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/>.
*/
//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
#define FC_JSON_TYPE_MAP 3
#define DEFINE_ARRAY_STRUCT(ELEMENT_TYPE, ARRAY_TYPE) \
typedef struct { \
ELEMENT_TYPE *elements; \
int count; \
\
/* for internal use */ \
int element_size; \
int alloc; \
} ARRAY_TYPE
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
static inline void fc_init_common_array(fc_common_array_t *array,
const int element_size)
{
array->elements = NULL;
array->element_size = element_size;
array->count = array->alloc = 0;
}
static inline void fc_init_json_array(fc_json_array_t *array)
{
fc_init_common_array((fc_common_array_t *)array, sizeof(string_t));
}
static inline void fc_init_json_map(fc_json_map_t *array)
{
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;
}
}
static inline void fc_free_json_array(fc_json_array_t *array)
{
fc_free_common_array((fc_common_array_t *)array);
}
static inline void fc_free_json_map(fc_json_map_t *array)
{
fc_free_common_array((fc_common_array_t *)array);
}
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);
}
ctx->error_info.len = 0;
*ctx->error_info.str = '\0';
}
static inline int fc_init_json_context_ex(fc_json_context_t *ctx,
const bool decode_use_mpool, const int alloc_size_once,
const int init_buff_size, char *error_info,
const int error_size)
{
const int discard_size = 0;
ctx->output.buff = NULL;
ctx->output.alloc_size = ctx->output.length = 0;
FC_SET_STRING_NULL(ctx->decode.element);
if (init_buff_size > 0) {
ctx->init_buff_size = init_buff_size;
} else {
ctx->init_buff_size = 1024;
}
fc_init_json_array(&ctx->jarray);
fc_init_json_map(&ctx->jmap);
ctx->error_no = 0;
fc_set_json_error_buffer(ctx, error_info, error_size);
ctx->decode.use_mpool = decode_use_mpool;
if (decode_use_mpool) {
return fast_mpool_init(&ctx->decode.mpool,
alloc_size_once, discard_size);
} else {
return 0;
}
}
static inline int fc_init_json_context(fc_json_context_t *ctx)
{
const bool decode_use_mpool = false;
const int alloc_size_once = 0;
const int init_buff_size = 0;
return fc_init_json_context_ex(ctx, decode_use_mpool,
alloc_size_once, init_buff_size, NULL, 0);
}
static inline void fc_reset_json_context(fc_json_context_t *ctx)
{
if (ctx->decode.use_mpool) {
fast_mpool_reset(&ctx->decode.mpool);
}
}
static inline void fc_destroy_json_context(fc_json_context_t *ctx)
{
fc_free_buffer(&ctx->output);
fc_free_json_array(&ctx->jarray);
fc_free_json_map(&ctx->jmap);
if (ctx->decode.use_mpool) {
fast_mpool_destroy(&ctx->decode.mpool);
}
}
static inline int fc_json_parser_get_error_no(fc_json_context_t *ctx)
{
return ctx->error_no;
}
static inline const string_t *fc_json_parser_get_error_info(
fc_json_context_t *ctx)
{
return &ctx->error_info;
}
int fc_detect_json_type(const string_t *input);
int fc_encode_json_array_ex(fc_json_context_t *context,
const string_t *elements, const int count,
BufferInfo *buffer);
int fc_encode_json_map_ex(fc_json_context_t *context,
const key_value_pair_t *elements, const int count,
BufferInfo *buffer);
static inline const BufferInfo *fc_encode_json_array(fc_json_context_t
*context, const string_t *elements, const int count)
{
if (fc_encode_json_array_ex(context, elements, count,
&context->output) == 0)
{
return &context->output;
} else {
return NULL;
}
}
static inline const BufferInfo *fc_encode_json_map(fc_json_context_t
*context, const key_value_pair_t *elements, const int count)
{
if (fc_encode_json_map_ex(context, elements, count,
&context->output) == 0)
{
return &context->output;
} else {
return NULL;
}
}
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
*context, const string_t *input);
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
*context, const string_t *input);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <netdb.h>
#include <unistd.h>
@ -31,7 +24,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,34 +49,29 @@ 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;
}
const char *local_host_ip_addrs_to_string(char *buff, const int size)
void log_local_host_ip_addrs()
{
char *p;
char *pEnd;
char buff[512];
int len;
len = snprintf(buff, size, "local_host_ip_count: %d,",
g_local_host_ip_count);
pEnd = g_local_host_ip_addrs +
len = sprintf(buff, "local_host_ip_count: %d,", g_local_host_ip_count);
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)
{
len += snprintf(buff + len, size - len, " %s", p);
len += sprintf(buff + len, " %s", p);
}
return buff;
}
void log_local_host_ip_addrs()
{
char buff[1024];
logInfo("%s", local_host_ip_addrs_to_string(buff, sizeof(buff)));
logInfo("%s", buff);
}
void load_local_host_ip_addrs()
@ -95,7 +83,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_IPv4);
insert_into_local_host_ip(LOCAL_LOOPBACK_IP);
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
if (*g_if_alias_prefix == '\0')
@ -159,8 +147,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 (!is_loopback_ip(p))
{
if (strcmp(p, LOCAL_LOOPBACK_IP) != 0)
{
if (found)
{
@ -171,7 +159,7 @@ const char *get_next_local_ip(const char *previous_ip)
found = true;
}
}
}
}
return NULL;
}
@ -186,10 +174,7 @@ const char *get_first_local_ip()
}
else
{
/* 注意当系统存在IPv6回环地址时为了简化系统的改动
IPv6IPv4
*/
return LOCAL_LOOPBACK_IPv4;
return LOCAL_LOOPBACK_IP;
}
}
@ -214,17 +199,3 @@ const char *get_first_local_private_ip()
return NULL;
}
void stat_local_host_ip(int *ipv4_count, int *ipv6_count)
{
const char *ip_addr;
*ipv4_count = *ipv6_count = 0;
ip_addr = NULL;
while ((ip_addr=get_next_local_ip(ip_addr)) != NULL) {
if (is_ipv6_addr(ip_addr)) {
++(*ipv6_count);
} else {
++(*ipv4_count);
}
}
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//local_ip_func.h
@ -25,32 +18,22 @@
#include "common_define.h"
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
#define FAST_MAX_LOCAL_IP_ADDRS 32
#define FAST_MAX_LOCAL_IP_ADDRS 16
#define LOCAL_LOOPBACK_IPv4 "127.0.0.1"
#define LOCAL_LOOPBACK_IPv6 "::1"
#define LOCAL_LOOPBACK_IP "127.0.0.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);
@ -59,7 +42,6 @@ const char *get_first_local_private_ip();
int insert_into_local_host_ip(const char *client_ip);
void log_local_host_ip_addrs();
void print_local_host_ip_addrs();
const char *local_host_ip_addrs_to_string(char *buff, const int size);
#ifdef __cplusplus
}

View File

@ -1,115 +0,0 @@
#ifndef _LOCKED_LIST_H
#define _LOCKED_LIST_H
#include "fc_list.h"
#include "pthread_func.h"
typedef struct fc_locked_list {
struct fc_list_head head;
pthread_mutex_t lock;
} FCLockedList;
#ifdef __cplusplus
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;
if ((result=init_pthread_lock(&list->lock)) != 0) {
return result;
}
FC_INIT_LIST_HEAD(&list->head);
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)
{
PTHREAD_MUTEX_LOCK(&list->lock);
fc_list_add(_new, &list->head);
PTHREAD_MUTEX_UNLOCK(&list->lock);
}
static inline void locked_list_add_tail(struct fc_list_head *_new,
FCLockedList *list)
{
PTHREAD_MUTEX_LOCK(&list->lock);
fc_list_add_tail(_new, &list->head);
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)
{
PTHREAD_MUTEX_LOCK(&list->lock);
fc_list_del_init(old);
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;
PTHREAD_MUTEX_LOCK(&list->lock);
count = fc_list_count(&list->head);
PTHREAD_MUTEX_UNLOCK(&list->lock);
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
#endif

View File

@ -1,353 +0,0 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "logger.h"
#include "fc_memory.h"
#include "shared_func.h"
#include "pthread_func.h"
#include "locked_timer.h"
static int locked_timer_init_slots(LockedTimer *timer)
{
int bytes;
int result;
LockedTimerSlot *slot;
LockedTimerSlot *send;
pthread_mutex_t *lock;
pthread_mutex_t *lend;
bytes = sizeof(LockedTimerSlot) * timer->slot_count;
timer->slots = (LockedTimerSlot *)fc_malloc(bytes);
if (timer->slots == NULL) {
return ENOMEM;
}
memset(timer->slots, 0, bytes);
send = timer->slots + timer->slot_count;
for (slot=timer->slots; slot<send; slot++) {
if ((result=init_pthread_lock(&slot->lock)) != 0) {
return result;
}
FC_INIT_LIST_HEAD(&slot->head);
}
timer->entry_shares.locks = (pthread_mutex_t *)fc_malloc(
sizeof(pthread_mutex_t) * timer->entry_shares.count);
if (timer->entry_shares.locks == NULL) {
return ENOMEM;
}
lend = timer->entry_shares.locks + timer->entry_shares.count;
for (lock=timer->entry_shares.locks; lock<lend; lock++) {
if ((result=init_pthread_lock(lock)) != 0) {
return result;
}
}
return 0;
}
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
const int64_t current_time, const int shared_lock_count,
const bool set_lock_index)
{
if (slot_count <= 0 || current_time <= 0) {
return EINVAL;
}
timer->slot_count = slot_count;
timer->entry_shares.count = shared_lock_count;
timer->entry_shares.set_lock_index = set_lock_index;
timer->base_time = current_time; //base time for slot 0
timer->current_time = current_time;
return locked_timer_init_slots(timer);
}
void locked_timer_destroy(LockedTimer *timer)
{
LockedTimerSlot *slot;
LockedTimerSlot *send;
pthread_mutex_t *lock;
pthread_mutex_t *lend;
if (timer->slots == NULL) {
return;
}
send = timer->slots + timer->slot_count;
for (slot=timer->slots; slot<send; slot++) {
pthread_mutex_destroy(&slot->lock);
}
lend = timer->entry_shares.locks + timer->entry_shares.count;
for (lock=timer->entry_shares.locks; lock<lend; lock++) {
pthread_mutex_destroy(lock);
}
free(timer->entry_shares.locks);
timer->entry_shares.locks = NULL;
timer->entry_shares.count = 0;
free(timer->slots);
timer->slots = NULL;
}
#define TIMER_GET_SLOT_INDEX(timer, expires) \
(((expires) - timer->base_time) % timer->slot_count)
#define TIMER_GET_SLOT_POINTER(timer, expires) \
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
#define TIMER_ENTRY_LOCK(timer, lock_index) \
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index)
#define TIMER_ENTRY_UNLOCK(timer, lock_index) \
PTHREAD_MUTEX_UNLOCK(timer->entry_shares.locks + lock_index)
#define TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry) \
(timer->entry_shares.set_lock_index ? \
__sync_add_and_fetch(&entry->lock_index, 0) : entry->lock_index)
#define TIMER_ENTRY_FETCH_AND_LOCK(timer, entry) \
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry); \
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index)
#define TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index) \
do { \
TIMER_ENTRY_LOCK(timer, lock_index); \
entry->status = FAST_TIMER_STATUS_NORMAL; \
entry->slot_index = slot - timer->slots; \
TIMER_ENTRY_UNLOCK(timer, lock_index); \
} while (0)
static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot,
LockedTimerEntry *entry, const int64_t expires, const int flags)
{
int lock_index;
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) != 0) {
if (timer->entry_shares.set_lock_index) {
int old_index;
/* init the entry on the first call */
lock_index = ((unsigned long)entry) % timer->entry_shares.count;
old_index = entry->lock_index;
while (!__sync_bool_compare_and_swap(&entry->lock_index,
old_index, lock_index))
{
old_index = __sync_add_and_fetch(&entry->lock_index, 0);
}
} else {
lock_index = entry->lock_index;
}
TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index);
} else {
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry);
}
PTHREAD_MUTEX_LOCK(&slot->lock);
if ((flags & FAST_TIMER_FLAGS_SET_EXPIRES) != 0) {
entry->expires = expires;
}
fc_list_add_tail(&entry->dlink, &slot->head);
entry->rehash = false;
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) == 0) {
/* MUST set entry status and slot index in the end when entry move */
TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index);
}
PTHREAD_MUTEX_UNLOCK(&slot->lock);
}
#define check_entry_status(timer, entry, slot_index) \
check_set_entry_status(timer, entry, slot_index, \
FAST_TIMER_STATUS_NONE)
static inline int check_set_entry_status(LockedTimer *timer,
LockedTimerEntry *entry, int *slot_index, const int new_status)
{
int result;
int lock_index;
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry);
while (1) {
TIMER_ENTRY_LOCK(timer, lock_index);
switch (entry->status) {
case FAST_TIMER_STATUS_CLEARED:
result = ECANCELED;
break;
case FAST_TIMER_STATUS_TIMEOUT:
result = ETIMEDOUT;
break;
case FAST_TIMER_STATUS_MOVING:
result = EAGAIN;
break;
case FAST_TIMER_STATUS_NORMAL:
result = 0;
if (new_status != FAST_TIMER_STATUS_NONE) {
entry->status = new_status;
}
break;
default:
result = EINVAL;
break;
}
*slot_index = entry->slot_index;
TIMER_ENTRY_UNLOCK(timer, lock_index);
if (result != EAGAIN) {
return result;
}
fc_sleep_ms(1);
}
}
void locked_timer_add_ex(LockedTimer *timer, LockedTimerEntry *entry,
const int64_t expires, const int flags)
{
LockedTimerSlot *slot;
int64_t new_expires;
bool new_flags;
if (expires > timer->current_time) {
new_expires = expires;
new_flags = flags;
} else {
new_expires = timer->current_time + 1; //plus 1 for rare case
new_flags = flags | FAST_TIMER_FLAGS_SET_EXPIRES;
}
slot = TIMER_GET_SLOT_POINTER(timer, new_expires);
add_entry(timer, slot, entry, new_expires, new_flags);
}
int locked_timer_modify(LockedTimer *timer, LockedTimerEntry *entry,
const int64_t new_expires)
{
int result;
int slot_index;
if (new_expires > entry->expires) {
if ((result=check_entry_status(timer, entry, &slot_index)) != 0) {
return result;
}
PTHREAD_MUTEX_LOCK(&(timer->slots + slot_index)->lock);
entry->rehash = TIMER_GET_SLOT_INDEX(timer,
new_expires) != slot_index;
entry->expires = new_expires; //lazy move
PTHREAD_MUTEX_UNLOCK(&(timer->slots + slot_index)->lock);
} else if (new_expires < entry->expires) {
if ((result=locked_timer_remove_ex(timer, entry,
FAST_TIMER_STATUS_MOVING)) == 0)
{
locked_timer_add_ex(timer, entry, new_expires,
FAST_TIMER_FLAGS_SET_EXPIRES);
}
return result;
}
return 0;
}
int locked_timer_remove_ex(LockedTimer *timer, LockedTimerEntry *entry,
const int new_status)
{
int result;
int slot_index;
if ((result=check_set_entry_status(timer, entry,
&slot_index, new_status)) != 0)
{
return result;
}
PTHREAD_MUTEX_LOCK(&(timer->slots + slot_index)->lock);
fc_list_del_init(&entry->dlink);
PTHREAD_MUTEX_UNLOCK(&(timer->slots + slot_index)->lock);
return 0;
}
int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
LockedTimerEntry *head)
{
LockedTimerSlot *slot;
LockedTimerSlot *new_slot;
LockedTimerEntry *entry;
LockedTimerEntry *tmp;
LockedTimerEntry *tail;
bool is_valid;
int lock_index;
int count;
if (timer->current_time >= current_time) {
head->next = NULL;
return 0;
}
tail = head;
count = 0;
while (timer->current_time < current_time) {
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
PTHREAD_MUTEX_LOCK(&slot->lock);
fc_list_for_each_entry_safe(entry, tmp, &slot->head, dlink) {
if (entry->expires >= current_time) { //not expired
if (entry->rehash) {
new_slot = TIMER_GET_SLOT_POINTER(timer, entry->expires);
if (new_slot != slot) { //check to avoid deadlock
TIMER_ENTRY_FETCH_AND_LOCK(timer, entry);
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
entry->status = FAST_TIMER_STATUS_MOVING;
is_valid = true;
} else {
is_valid = false;
}
TIMER_ENTRY_UNLOCK(timer, lock_index);
if (is_valid) {
fc_list_del_init(&entry->dlink);
add_entry(timer, new_slot, entry, entry->expires,
FAST_TIMER_FLAGS_SET_NOTHING);
}
} else {
entry->rehash = false;
}
}
} else { //expired
TIMER_ENTRY_FETCH_AND_LOCK(timer, entry);
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
entry->status = FAST_TIMER_STATUS_TIMEOUT;
is_valid = true;
} else {
is_valid = false;
}
TIMER_ENTRY_UNLOCK(timer, lock_index);
if (is_valid) {
fc_list_del_init(&entry->dlink);
tail->next = entry;
tail = entry;
count++;
}
}
}
PTHREAD_MUTEX_UNLOCK(&slot->lock);
}
tail->next = NULL;
return count;
}

View File

@ -1,102 +0,0 @@
/*
* 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/>.
*/
#ifndef __LOCKED_TIMER_H__
#define __LOCKED_TIMER_H__
#include <stdint.h>
#include <pthread.h>
#include "common_define.h"
#include "fc_list.h"
#define FAST_TIMER_STATUS_NONE 0
#define FAST_TIMER_STATUS_NORMAL 1
#define FAST_TIMER_STATUS_MOVING 2
#define FAST_TIMER_STATUS_TIMEOUT 3
#define FAST_TIMER_STATUS_CLEARED 4
#define FAST_TIMER_FLAGS_SET_NOTHING 0
#define FAST_TIMER_FLAGS_SET_EXPIRES 1
#define FAST_TIMER_FLAGS_SET_ENTRY_LOCK 2
#define FAST_TIMER_FLAGS_SET_ALL (FAST_TIMER_FLAGS_SET_EXPIRES | \
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
typedef struct locked_timer_entry {
int64_t expires;
struct fc_list_head dlink; //for timer slot
struct locked_timer_entry *next; //for timeout chain
uint32_t slot_index; //for slot lock
volatile uint16_t lock_index; //for entry lock
uint8_t status;
bool rehash;
} LockedTimerEntry;
typedef struct locked_timer_slot {
struct fc_list_head head;
pthread_mutex_t lock;
} LockedTimerSlot;
typedef struct locked_timer_shared_locks {
bool set_lock_index;
uint16_t count;
pthread_mutex_t *locks;
} LockedTimerSharedLocks;
typedef struct locked_timer {
int slot_count; //time wheel slot count
LockedTimerSharedLocks entry_shares; //shared locks for entry
int64_t base_time; //base time for slot 0
volatile int64_t current_time;
LockedTimerSlot *slots;
} LockedTimer;
#ifdef __cplusplus
extern "C" {
#endif
#define locked_timer_init(timer, slot_count, current_time, shared_lock_count) \
locked_timer_init_ex(timer, slot_count, current_time, shared_lock_count, \
true)
#define locked_timer_add(timer, entry) \
locked_timer_add_ex(timer, entry, (entry)->expires, \
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
#define locked_timer_remove(timer, entry) \
locked_timer_remove_ex(timer, entry, FAST_TIMER_STATUS_CLEARED)
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
const int64_t current_time, const int shared_lock_count,
const bool set_lock_index);
void locked_timer_destroy(LockedTimer *timer);
void locked_timer_add_ex(LockedTimer *timer, LockedTimerEntry *entry,
const int64_t expires, const int flags);
int locked_timer_remove_ex(LockedTimer *timer, LockedTimerEntry *entry,
const int new_status);
int locked_timer_modify(LockedTimer *timer, LockedTimerEntry *entry,
const int64_t new_expires);
int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
LockedTimerEntry *head);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
#include <limits.h>
#include <stdarg.h>
@ -50,29 +43,27 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock);
static int check_and_mk_log_dir(const char *base_path)
{
char log_path[MAX_PATH_SIZE];
char data_path[MAX_PATH_SIZE];
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;
}
}
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", \
data_path, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
}
return 0;
return 0;
}
int log_init()
{
if (g_log_context.log_buff != NULL)
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"g_log_context already inited\n", __LINE__);
return 0;
}
@ -99,20 +90,19 @@ int log_init_ex(LogContext *pContext)
pContext->log_level = LOG_INFO;
pContext->log_fd = STDERR_FILENO;
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
pContext->compress_log_days_before = 1;
strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S");
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
if (pContext->log_buff == NULL)
{
fprintf(stderr, "malloc %d bytes fail, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
LOG_BUFF_SIZE, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
pContext->pcurrent_buff = pContext->log_buff;
if ((result=init_pthread_lock(&(pContext->lock))) != 0)
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0)
{
return result;
}
@ -136,8 +126,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 +148,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 | O_CLOEXEC | pContext->fd_flags, 0644)) < 0)
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
O_CREAT | O_APPEND | pContext->fd_flags, 0644)) < 0)
{
fprintf(stderr, "open log file \"%s\" to write fail, " \
"errno: %d, error info: %s\n", \
@ -222,44 +212,31 @@ 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;
char log_filename[MAX_PATH_SIZE];
int result;
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(log_filename, MAX_PATH_SIZE, "%s/logs/%s.log",
base_path, filename_prefix);
return log_set_filename_ex(pContext, log_filename);
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
base_path, filename_prefix);
return log_open(pContext);
}
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
{
if (log_filename == NULL || *log_filename == '\0')
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"log_filename is NULL or empty!\n", __LINE__);
if (log_filename == NULL) {
fprintf(stderr, "file: "__FILE__", line: %d, " \
"log_filename is NULL!\n", __LINE__);
return EINVAL;
}
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);
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
return log_open(pContext);
}
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
@ -296,9 +273,9 @@ void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_call
{
int64_t current_size;
pthread_mutex_lock(&(pContext->lock));
pthread_mutex_lock(&(pContext->log_thread_lock));
current_size = pContext->current_size;
pthread_mutex_unlock(&(pContext->lock));
pthread_mutex_unlock(&(pContext->log_thread_lock));
if (current_size == 0)
{
log_print_header(pContext);
@ -323,14 +300,7 @@ void log_set_compress_log_flags_ex(LogContext *pContext, const short flags)
void log_set_compress_log_days_before_ex(LogContext *pContext, const int days_before)
{
if (days_before > 0)
{
pContext->compress_log_days_before = days_before;
}
else
{
pContext->compress_log_days_before = 1;
}
pContext->compress_log_days_before = days_before;
}
void log_set_fd_flags(LogContext *pContext, const int flags)
@ -347,7 +317,7 @@ void log_destroy_ex(LogContext *pContext)
close(pContext->log_fd);
pContext->log_fd = STDERR_FILENO;
pthread_mutex_destroy(&pContext->lock);
pthread_mutex_destroy(&pContext->log_thread_lock);
}
if (pContext->log_buff != NULL)
@ -385,11 +355,12 @@ static int log_delete_old_file(LogContext *pContext,
char full_filename[MAX_PATH_SIZE + 128];
if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
{
fc_concat_two_strings(old_filename, GZIP_EXT_NAME_STR, full_filename);
snprintf(full_filename, sizeof(full_filename), "%s%s",
old_filename, GZIP_EXT_NAME_STR);
}
else
{
fc_safe_strcpy(full_filename, old_filename);
snprintf(full_filename, sizeof(full_filename), "%s", old_filename);
}
if (unlink(full_filename) != 0)
@ -400,10 +371,6 @@ static int log_delete_old_file(LogContext *pContext,
"unlink %s fail, errno: %d, error info: %s\n", \
__LINE__, full_filename, errno, STRERROR(errno));
}
else if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
{
unlink(old_filename);
}
return errno != 0 ? errno : EPERM;
}
@ -545,9 +512,7 @@ static int log_get_matched_files(LogContext *pContext,
char *log_filename;
char *filename;
DIR *dir;
#ifndef OS_LINUX
struct dirent ent;
#endif
struct dirent *pEntry;
time_t the_time;
struct tm tm;
@ -589,18 +554,11 @@ 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 = strlen(log_filename);
memcpy(filename_prefix, log_filename, len);
*(filename_prefix + len++) = '.';
len = sprintf(filename_prefix, "%s.", log_filename);
strftime(filename_prefix + len, sizeof(filename_prefix) - len,
rotate_time_format_prefix, &tm);
prefix_filename_len = strlen(filename_prefix);
#ifndef OS_LINUX
while (readdir_r(dir, &ent, &pEntry) == 0)
#else
while ((pEntry=readdir(dir)) != NULL)
#endif
{
if (pEntry == NULL)
{
@ -652,8 +610,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++)
{
fc_concat_two_strings(log_filepath, filename_array.
filenames[i], full_filename);
snprintf(full_filename, sizeof(full_filename), "%s%s",
log_filepath, filename_array.filenames[i]);
if (unlink(full_filename) != 0)
{
if (errno != ENOENT)
@ -704,9 +662,7 @@ int log_delete_old_files(void *args)
the_time -= 86400;
localtime_r(&the_time, &tm);
memset(old_filename, 0, sizeof(old_filename));
len = strlen(pContext->log_filename);
memcpy(old_filename, pContext->log_filename, len);
*(old_filename + len++) = '.';
len = sprintf(old_filename, "%s.", pContext->log_filename);
strftime(old_filename + len, sizeof(old_filename) - len,
pContext->rotate_time_format, &tm);
if ((result=log_delete_old_file(pContext, old_filename)) != 0)
@ -728,20 +684,31 @@ int log_delete_old_files(void *args)
}
}
static void *log_gzip_func(void *args)
static void* log_gzip_func(void *args)
{
LogContext *pContext;
char *gzip;
char cmd[MAX_PATH_SIZE + 128];
struct log_filename_array filename_array;
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;
pContext = (LogContext *)args;
if (access("/bin/gzip", F_OK) == 0)
{
gzip = "/bin/gzip";
}
else if (access("/usr/bin/gzip", F_OK) == 0)
{
gzip = "/usr/bin/gzip";
}
else
{
gzip = "gzip";
}
if (log_get_prefix_len(pContext, &prefix_len) != 0)
{
return NULL;
@ -764,25 +731,13 @@ static void *log_gzip_func(void *args)
continue;
}
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)
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"exec command \"%s\" fail, "
"errno: %d, error info: %s",
__LINE__, cmd, result, STRERROR(result));
break;
}
if (*output != '\0')
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"exec command \"%s\", output: %s",
__LINE__, cmd, output);
}
snprintf(full_filename, sizeof(full_filename), "%s%s",
log_filepath, filename_array.filenames[i]);
snprintf(cmd, sizeof(cmd), "%s %s", gzip, full_filename);
if (system(cmd) == -1)
{
fprintf(stderr, "execute %s fail\n", cmd);
}
}
log_free_filename_array(&filename_array);
@ -806,7 +761,7 @@ static void log_gzip(LogContext *pContext)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"create thread failed, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
pthread_attr_destroy(&thread_attr);
@ -833,7 +788,8 @@ int log_rotate(LogContext *pContext)
close(pContext->log_fd);
current_time = get_current_time();
current_time = get_current_time();
localtime_r(&current_time, &tm);
if (tm.tm_hour == 0 && tm.tm_min <= 1)
{
if (strstr(pContext->rotate_time_format, "%H") == NULL
@ -841,14 +797,12 @@ int log_rotate(LogContext *pContext)
&& strstr(pContext->rotate_time_format, "%S") == NULL)
{
current_time -= 120;
localtime_r(&current_time, &tm);
}
}
localtime_r(&current_time, &tm);
memset(old_filename, 0, sizeof(old_filename));
len = strlen(pContext->log_filename);
memcpy(old_filename, pContext->log_filename, len);
*(old_filename + len++) = '.';
len = sprintf(old_filename, "%s.", pContext->log_filename);
strftime(old_filename + len, sizeof(old_filename) - len,
pContext->rotate_time_format, &tm);
if (access(old_filename, F_OK) == 0)
@ -918,23 +872,23 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
{
if (bNeedLock)
{
pthread_mutex_lock(&(pContext->lock));
pthread_mutex_lock(&(pContext->log_thread_lock));
}
result = log_check_rotate(pContext);
if (bNeedLock)
{
pthread_mutex_unlock(&(pContext->lock));
pthread_mutex_unlock(&(pContext->log_thread_lock));
}
return result;
}
}
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
&(pContext->lock))) != 0))
&(pContext->log_thread_lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
__LINE__, lock_res, STRERROR(lock_res));
}
@ -955,10 +909,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, "
"pid: %d, call write fail, fd: %d, errno: %d, error info: %s\n",
__LINE__, getpid(), pContext->log_fd, result, STRERROR(result));
}
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call write fail, errno: %d, error info: %s\n",\
__LINE__, result, STRERROR(result));
}
if (pContext->rotate_immediately)
{
@ -966,19 +920,19 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
}
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
&(pContext->lock))) != 0))
&(pContext->log_thread_lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
__LINE__, lock_res, STRERROR(lock_res));
}
return result;
}
void log_it_ex3(LogContext *pContext, struct timeval *tv,
const char *caption, const char *text, const int text_len,
static void doLogEx(LogContext *pContext, struct timeval *tv, \
const char *caption, const char *text, const int text_len, \
const bool bNeedSync, const bool bNeedLock)
{
struct tm tm;
@ -1003,27 +957,27 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
}
}
if (bNeedLock && (result=pthread_mutex_lock(&pContext->lock)) != 0)
if (bNeedLock && (result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
if (text_len + 64 > LOG_BUFF_SIZE)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"log buff size: %d < log text length: %d\n", \
"log buff size: %d < log text length: %d ", \
__LINE__, LOG_BUFF_SIZE, text_len + 64);
if (bNeedLock)
{
pthread_mutex_unlock(&(pContext->lock));
pthread_mutex_unlock(&(pContext->log_thread_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);
@ -1050,14 +1004,10 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
}
if (caption != NULL)
{
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++ = ' ';
}
{
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
pContext->pcurrent_buff += buff_len;
}
memcpy(pContext->pcurrent_buff, text, text_len);
pContext->pcurrent_buff += text_len;
*pContext->pcurrent_buff++ = '\n';
@ -1067,17 +1017,17 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
log_fsync(pContext, false);
}
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->lock))) != 0)
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s\n", \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
}
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;
@ -1092,10 +1042,10 @@ void log_it_ex2(LogContext *pContext, const char *caption,
gettimeofday(&tv, NULL);
}
log_it_ex3(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock);
doLogEx(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;
@ -1291,12 +1241,7 @@ void logAccess(LogContext *pContext, struct timeval *tvStart, \
{
len = sizeof(text) - 1;
}
log_it_ex3(pContext, tvStart, NULL, text, len, false, true);
}
const char *log_get_level_caption_ex(LogContext *pContext)
{
return get_log_level_caption(pContext->log_level);
doLogEx(pContext, tvStart, NULL, text, len, false, true);
}
#ifndef LOG_FORMAT_CHECK

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* 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.csource.org/ for more detail.
**/
//logger.h
#ifndef LOGGER_H
@ -36,16 +29,11 @@ extern "C" {
#define LOG_COMPRESS_FLAGS_ENABLED 1
#define LOG_COMPRESS_FLAGS_NEW_THREAD 2
#define LOG_NOTHING (LOG_DEBUG + 10)
struct log_context;
//log header line callback
typedef void (*LogHeaderCallback)(struct log_context *pContext);
#define FC_LOG_BY_LEVEL(level) \
(level <= g_log_context.log_level)
typedef struct log_context
{
/* log level value please see: sys/syslog.h
@ -62,7 +50,7 @@ typedef struct log_context
char *pcurrent_buff;
/* mutext lock */
pthread_mutex_t lock;
pthread_mutex_t log_thread_lock;
/*
rotate the log when the log file exceeds this parameter
@ -127,25 +115,11 @@ extern LogContext g_log_context;
*/
int log_init();
/** init function using global log context
* do nothing when already inited
* return: 0 for success, != 0 fail
*/
static inline int log_try_init()
{
if (g_log_context.log_buff != NULL)
{
return 0;
}
return log_init();
}
/** init function using global log context, take over stderr and stdout
* return: 0 for success, != 0 fail
*/
int log_init2();
#define log_reopen() log_reopen_ex(&g_log_context)
#define log_set_prefix(base_path, filename_prefix) \
@ -172,13 +146,6 @@ int log_init2();
#define log_destroy() log_destroy_ex(&g_log_context)
#define log_it1(priority, text, text_len) \
log_it_ex1(&g_log_context, priority, text, text_len)
#define log_it2(caption, text, text_len, bNeedSync, bNeedLock) \
log_it_ex2(&g_log_context, caption, text, text_len, bNeedSync, bNeedLock)
/** init function, use stderr for output by default
* parameters:
* pContext: the log context
@ -201,7 +168,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
@ -274,24 +241,6 @@ 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
@ -333,7 +282,7 @@ void log_destroy_ex(LogContext *pContext);
* return: none
*/
void log_it_ex(LogContext *pContext, const int priority, \
const char *format, ...) __gcc_attribute__ ((format (printf, 3, 4)));
const char *format, ...);
/** log to file
* parameters:
@ -343,7 +292,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
@ -355,13 +304,10 @@ 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:
@ -392,41 +338,16 @@ int log_rotate(LogContext *pContext);
*/
int log_delete_old_files(void *args);
/** get log level caption
* parameters:
* pContext: the log context
* return: log level caption
*/
const char *log_get_level_caption_ex(LogContext *pContext);
#define log_get_level_caption() log_get_level_caption_ex(&g_log_context)
void logEmergEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logCritEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logAlertEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logErrorEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logWarningEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logNoticeEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logInfoEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logDebugEx(LogContext *pContext, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
void logAccess(LogContext *pContext, struct timeval *tvStart,
const char *format, ...) __gcc_attribute__ ((format (printf, 3, 4)));
void logEmergEx(LogContext *pContext, const char *format, ...);
void logCritEx(LogContext *pContext, const char *format, ...);
void logAlertEx(LogContext *pContext, const char *format, ...);
void logErrorEx(LogContext *pContext, const char *format, ...);
void logWarningEx(LogContext *pContext, const char *format, ...);
void logNoticeEx(LogContext *pContext, const char *format, ...);
void logInfoEx(LogContext *pContext, const char *format, ...);
void logDebugEx(LogContext *pContext, const char *format, ...);
void logAccess(LogContext *pContext, struct timeval *tvStart, \
const char *format, ...);
//#define LOG_FORMAT_CHECK
@ -444,29 +365,14 @@ void logAccess(LogContext *pContext, struct timeval *tvStart,
#else
/* following functions use global log context: g_log_context */
void logEmerg(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logCrit(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logAlert(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logError(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logWarning(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logNotice(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logInfo(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logDebug(const char *format, ...)
__gcc_attribute__ ((format (printf, 1, 2)));
void logEmerg(const char *format, ...);
void logCrit(const char *format, ...);
void logAlert(const char *format, ...);
void logError(const char *format, ...);
void logWarning(const char *format, ...);
void logNotice(const char *format, ...);
void logInfo(const char *format, ...);
void logDebug(const char *format, ...);
#endif
@ -475,3 +381,4 @@ void logDebug(const char *format, ...)
#endif
#endif

View File

@ -311,7 +311,7 @@ MD5_memset(POINTER output, int value, unsigned int len)
/*
* Digests a string
*/
int my_md5_string(char *string, unsigned char digest[16])
int my_md5_string(char *string,unsigned char digest[16])
{
MD5_CTX context;
unsigned int len = strlen(string);
@ -332,22 +332,25 @@ 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 buff[16 * 1024];
unsigned char buffer[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);
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;
fclose(file);
}
return 0;
}

View File

@ -41,12 +41,11 @@ 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 *);
void my_md5_update(MD5_CTX *context, unsigned char *input,
unsigned int inputLen);
void my_md5_update (MD5_CTX *, unsigned char *, unsigned int);
void my_md5_final(unsigned char digest[16], MD5_CTX *context);
void my_md5_final (unsigned char [16], MD5_CTX *);
#ifdef __cplusplus
}

View File

@ -1,17 +1,10 @@
/*
* 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/>.
*/
/**
* Copyright (C) 2015 Happy Fish / YuQing
*
* libfastcommon 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.csource.org/ for more detail.
**/
//multi_skiplist.c
@ -22,7 +15,6 @@
#include <errno.h>
#include <assert.h>
#include "logger.h"
#include "fc_memory.h"
#include "multi_skiplist.h"
int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
@ -30,8 +22,6 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
skiplist_free_func free_func,
const int min_alloc_elements_once)
{
const int64_t alloc_elements_limit = 0;
char name[64];
int bytes;
int element_size;
int i;
@ -46,23 +36,20 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
return EINVAL;
}
if (level_count > 30) {
if (level_count > 20) {
logError("file: "__FILE__", line: %d, "
"level count: %d is too large",
__LINE__, level_count);
return E2BIG;
}
bytes = sizeof(MultiSkiplistNode *) * level_count;
sl->tmp_previous = (MultiSkiplistNode **)fc_malloc(bytes);
if (sl->tmp_previous == NULL) {
return ENOMEM;
}
bytes = sizeof(struct fast_mblock_man) * level_count;
sl->mblocks = (struct fast_mblock_man *)fc_malloc(bytes);
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
if (sl->mblocks == NULL) {
return ENOMEM;
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail, errno: %d, error info: %s",
__LINE__, bytes, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
memset(sl->mblocks, 0, bytes);
@ -75,16 +62,13 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
}
for (i=level_count-1; i>=0; i--) {
sprintf(name, "multi-sl-level%02d", i);
element_size = sizeof(MultiSkiplistNode) +
sizeof(MultiSkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex1(sl->mblocks + i, name,
element_size, alloc_elements_once, alloc_elements_limit,
NULL, NULL, false)) != 0)
element_size = sizeof(MultiSkiplistNode) + sizeof(MultiSkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex(sl->mblocks + i,
element_size, alloc_elements_once, NULL, false)) != 0)
{
return result;
}
if (i % 2 == 0 && alloc_elements_once < 64 * 1024) {
if (alloc_elements_once < 1024 * 1024) {
alloc_elements_once *= 2;
}
}
@ -103,9 +87,9 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
}
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
if ((result=fast_mblock_init_ex1(&sl->data_mblock, "multi-sl-data",
if ((result=fast_mblock_init_ex(&sl->data_mblock,
sizeof(MultiSkiplistData), alloc_elements_once,
alloc_elements_limit, NULL, NULL, false)) != 0)
NULL, false)) != 0)
{
return result;
}
@ -165,7 +149,9 @@ static MultiSkiplistNode *multi_skiplist_get_previous(MultiSkiplist *sl, void *d
int i;
int cmp;
MultiSkiplistNode *previous;
MultiSkiplistNode *found;
found = NULL;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
@ -174,65 +160,17 @@ static MultiSkiplistNode *multi_skiplist_get_previous(MultiSkiplist *sl, void *d
break;
}
else if (cmp == 0) {
found = previous;
*level_index = i;
return previous;
goto DONE;
}
previous = previous->links[i];
}
}
return NULL;
}
static MultiSkiplistNode *multi_skiplist_get_first_larger_or_equal(
MultiSkiplist *sl, void *data)
{
int i;
int cmp;
MultiSkiplistNode *previous;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->head->data);
if (cmp < 0) {
break;
}
else if (cmp == 0) {
return previous->links[i];
}
previous = previous->links[i];
}
}
return previous->links[0];
}
static MultiSkiplistNode *multi_skiplist_get_first_larger(
MultiSkiplist *sl, void *data)
{
int i;
int cmp;
MultiSkiplistNode *previous;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->head->data);
if (cmp < 0) {
break;
}
else if (cmp == 0) {
return previous->links[i]->links[0];
}
previous = previous->links[i];
}
}
return previous->links[0];
DONE:
return found;
}
static inline void multi_skiplist_free_data_node(MultiSkiplist *sl,
@ -264,6 +202,7 @@ int multi_skiplist_insert(MultiSkiplist *sl, void *data)
MultiSkiplistData *dataNode;
MultiSkiplistNode *node;
MultiSkiplistNode *previous;
MultiSkiplistNode *current = NULL;
dataNode = (MultiSkiplistData *)fast_mblock_alloc_object(&sl->data_mblock);
if (dataNode == NULL) {
@ -303,19 +242,15 @@ int multi_skiplist_insert(MultiSkiplist *sl, void *data)
previous = previous->links[i];
}
sl->tmp_previous[i] = previous;
current = previous->links[i];
previous->links[i] = node;
node->links[i] = current;
i--;
}
node->head = dataNode;
node->tail = dataNode;
//thread safe for one write with many read model
for (i=0; i<=level_index; i++) {
node->links[i] = sl->tmp_previous[i]->links[i];
sl->tmp_previous[i]->links[i] = node;
}
return 0;
}
@ -348,13 +283,12 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data,
}
for (i=level_index; i>=0; i--) {
while (previous->links[i] != sl->tail &&
previous->links[i] != deleted)
while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->head->data) > 0)
{
previous = previous->links[i];
}
assert(previous->links[i] == deleted);
previous->links[i] = previous->links[i]->links[i];
}
@ -405,46 +339,9 @@ int multi_skiplist_find_all(MultiSkiplist *sl, void *data,
return ENOENT;
}
else {
iterator->current.node = previous->links[level_index];
iterator->tail = iterator->current.node->links[0];
iterator->current.data = iterator->current.node->head;
iterator->current.node = previous;
iterator->tail = previous->links[0]->links[0];
return 0;
}
}
void *multi_skiplist_find_ge(MultiSkiplist *sl, void *data)
{
MultiSkiplistNode *node;
node = multi_skiplist_get_first_larger_or_equal(sl, data);
if (node == sl->tail) {
return NULL;
}
return node->head->data;
}
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
MultiSkiplistIterator *iterator)
{
if (sl->compare_func(start_data, end_data) > 0) {
iterator->current.node = sl->tail;
iterator->current.data = NULL;
iterator->tail = sl->tail;
return EINVAL;
}
iterator->current.node = multi_skiplist_get_first_larger_or_equal(sl, start_data);
if (iterator->current.node == sl->tail) {
iterator->current.data = NULL;
iterator->tail = sl->tail;
return ENOENT;
}
iterator->tail = multi_skiplist_get_first_larger(sl, end_data);
if (iterator->current.node != iterator->tail) {
iterator->current.data = iterator->current.node->head;
return 0;
} else {
iterator->current.data = NULL;
return ENOENT;
}
}

View File

@ -1,20 +1,12 @@
/*
* 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/>.
*/
//multi_skiplist.h, support duplicated entries, and support stable sort :)
/**
* Copyright (C) 2015 Happy Fish / YuQing
*
* libfastcommon 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.csource.org/ for more detail.
**/
//multi_skiplist.h, support stable sort :)
#ifndef _MULTI_SKIPLIST_H
#define _MULTI_SKIPLIST_H
@ -48,7 +40,6 @@ typedef struct multi_skiplist
struct fast_mblock_man *mblocks; //node allocators
MultiSkiplistNode *top; //the top node
MultiSkiplistNode *tail; //the tail node for terminate
MultiSkiplistNode **tmp_previous; //thread safe for insert
} MultiSkiplist;
typedef struct multi_skiplist_iterator {
@ -80,21 +71,13 @@ int multi_skiplist_delete_all(MultiSkiplist *sl, void *data, int *delete_count);
void *multi_skiplist_find(MultiSkiplist *sl, void *data);
int multi_skiplist_find_all(MultiSkiplist *sl, void *data,
MultiSkiplistIterator *iterator);
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
MultiSkiplistIterator *iterator);
void *multi_skiplist_find_ge(MultiSkiplist *sl, void *data);
static inline void multi_skiplist_iterator(MultiSkiplist *sl,
MultiSkiplistIterator *iterator)
{
iterator->tail = sl->tail;
iterator->current.node = sl->top->links[0];
if (iterator->current.node != sl->tail) {
iterator->current.data = iterator->current.node->head;
}
else {
iterator->current.data = NULL;
}
iterator->current.node = sl->top;
iterator->current.data = NULL;
}
static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator)
@ -117,44 +100,9 @@ static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator)
return data;
}
static inline void *multi_skiplist_get_first(MultiSkiplist *sl)
{
if (sl->top->links[0] != sl->tail) {
return sl->top->links[0]->head->data;
} else {
return NULL;
}
}
static inline bool multi_skiplist_empty(MultiSkiplist *sl)
{
return sl->top->links[0] == sl->tail;
}
typedef const char * (*multi_skiplist_tostring_func)(void *data, char *buff, const int size);
static inline void multi_skiplist_print(MultiSkiplist *sl, multi_skiplist_tostring_func tostring_func)
{
int i;
MultiSkiplistNode *current;
char buff[1024];
printf("###################\n");
for (i=sl->top_level_index; i>=0; i--) {
printf("level %d: ", i);
current = sl->top->links[i];
while (current != sl->tail) {
printf("%s ", tostring_func(current->head->data, buff, sizeof(buff)));
current = current->links[i];
}
printf("\n");
}
printf("###################\n");
printf("\n");
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,436 +0,0 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "common_define.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "logger.h"
#include "sockopt.h"
#include "sched_thread.h"
#include "fast_buffer.h"
#include "multi_socket_client.h"
static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
FastMultiSockEntry *entry);
static int64_t fms_get_current_time_ms()
{
return (int64_t)get_current_time() * 1000LL;
}
int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
FastMultiSockEntry *entries, const int entry_count,
const int header_length,
fms_client_get_body_length_func get_body_length_func,
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;
memset(client, 0, sizeof(FastMultiSockClient));
if (entry_count <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid entry_count: %d <= 0",
__LINE__, entry_count);
return EINVAL;
}
if (header_length <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid header_length: %d <= 0",
__LINE__, header_length);
return EINVAL;
}
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",
__LINE__, result, STRERROR(result));
return result;
}
if (init_recv_buffer_size <= 0) {
new_init_recv_buffer_size = 4 * 1024;
} else {
new_init_recv_buffer_size = init_recv_buffer_size;
}
if (new_init_recv_buffer_size < header_length) {
new_init_recv_buffer_size = header_length;
}
for (i=0; i<entry_count; i++) {
if ((result=fast_buffer_init1(&entries[i].recv_buffer,
new_init_recv_buffer_size)) != 0)
{
return result;
}
}
client->entry_count = entry_count;
client->header_length = header_length;
client->get_body_length_func = get_body_length_func;
client->get_current_time_ms_func = get_current_time_ms_func;
client->entries = entries;
client->timeout_ms = timeout_ms;
return 0;
}
int fast_multi_sock_client_init(FastMultiSockClient *client,
FastMultiSockEntry *entries, const int entry_count,
const int header_length,
fms_client_get_body_length_func get_body_length_func,
const int init_recv_buffer_size, const int timeout)
{
return fast_multi_sock_client_init_ex(client, entries, entry_count,
header_length, get_body_length_func, fms_get_current_time_ms,
init_recv_buffer_size, timeout * 1000);
}
void fast_multi_sock_client_destroy(FastMultiSockClient *client)
{
int i;
ioevent_destroy(&client->ioevent);
for (i=0; i<client->entry_count; i++) {
fast_buffer_destroy(&client->entries[i].recv_buffer);
}
}
static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
FastMultiSockEntry *entry)
{
int bytes;
int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0;
while (entry->remain > 0) {
bytes = write(entry->conn->sock, entry->send_buffer->data +
(entry->send_buffer->length - entry->remain), entry->remain);
if (bytes < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, "
"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__,
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__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
break;
}
entry->remain -= bytes;
if (entry->remain == 0) {
entry->remain = client->header_length; //to recv pkg header
entry->recv_stage = fms_stage_recv_header;
entry->io_callback = fast_multi_sock_client_do_recv;
if (ioevent_modify(&client->ioevent, entry->conn->sock,
IOEVENT_READ, entry) != 0)
{
result = errno != 0 ? errno : EACCES;
logError("file: "__FILE__", line: %d, "
"ioevent_modify fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
}
break;
}
}
return result;
}
static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
FastBuffer *send_buffer)
{
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;
client->entries[i].done = false;
client->entries[i].recv_buffer.length = 0;
client->entries[i].send_buffer = send_buffer;
client->entries[i].io_callback = fast_multi_sock_client_do_send;
if (client->entries[i].conn->sock < 0) {
client->entries[i].error_no = ENOTCONN;
client->entries[i].done = true;
logError("file: "__FILE__", line: %d, "
"NOT connected to %s:%u", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
continue;
}
if (ioevent_attach(&client->ioevent,
client->entries[i].conn->sock, IOEVENT_WRITE,
client->entries + i) != 0)
{
client->entries[i].error_no = errno != 0 ? errno : EACCES;
client->entries[i].done = true;
result = client->entries[i].error_no;
logError("file: "__FILE__", line: %d, "
"ioevent_attach fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
continue;
}
client->pulling_count++;
}
return client->pulling_count > 0 ? 0 : ENOENT;
}
static inline void fast_multi_sock_client_finish(FastMultiSockClient *client,
FastMultiSockEntry *entry, const int error_no)
{
entry->error_no = error_no;
entry->done = true;
client->pulling_count--;
ioevent_detach(&client->ioevent, entry->conn->sock);
if (error_no == 0) {
client->success_count++;
}
}
static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
FastMultiSockEntry *entry)
{
int bytes;
int result;
char formatted_ip[FORMATTED_IP_SIZE];
result = 0;
while (entry->remain > 0) {
bytes = read(entry->conn->sock, entry->recv_buffer.data +
entry->recv_buffer.length, entry->remain);
if (bytes < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else if (errno == EINTR) { //should retry
logDebug("file: "__FILE__", line: %d, "
"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__,
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__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
break;
}
entry->recv_buffer.length += bytes;
entry->remain -= bytes;
if (entry->remain == 0 && entry->recv_stage == fms_stage_recv_header) {
int body_length;
entry->recv_stage = fms_stage_recv_body;
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__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, body_length);
result = EPIPE;
break;
} else if (body_length == 0) {
break;
}
if ((result=fast_buffer_check(&entry->recv_buffer,
body_length)) != 0)
{
break;
}
entry->remain = body_length; //to recv body
}
}
logInfo("file: "__FILE__", line: %d, "
"recv remain: %d", __LINE__, entry->remain);
return result;
}
static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
{
int result;
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 -
client->get_current_time_ms_func();
if (remain_timeout < 0) { //timeout
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);
for (index=0; index<count; index++) {
event = IOEVENT_GET_EVENTS(&client->ioevent, index);
entry = (FastMultiSockEntry *)IOEVENT_GET_DATA(
&client->ioevent, index);
if (event & IOEVENT_ERROR) {
logError("file: "__FILE__", line: %d, "
"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);
result = entry->io_callback(client, entry);
if (result != 0 || entry->remain == 0) {
fast_multi_sock_client_finish(client, entry, result);
}
}
#endif
}
/*
logInfo("file: "__FILE__", line: %d, pulling_count: %d, "
"success_count: %d\n", __LINE__,
client->pulling_count, client->success_count);
*/
if (client->pulling_count > 0) {
int i;
for (i=0; i<client->entry_count; i++) {
if (!client->entries[i].done) {
fast_multi_sock_client_finish(client,
client->entries + i, ETIMEDOUT);
logError("file: "__FILE__", line: %d, "
"recv from %s:%u timedout", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
}
}
}
logInfo("file: "__FILE__", line: %d, pulling_count: %d, "
"success_count: %d\n", __LINE__,
client->pulling_count, client->success_count);
return client->success_count > 0 ? 0 :
(remain_timeout > 0 ? ENOENT : ETIMEDOUT);
}
int fast_multi_sock_client_request(FastMultiSockClient *client,
FastBuffer *send_buffer)
{
int result;
client->deadline_time_ms = client->get_current_time_ms_func() +
client->timeout_ms;
client->pulling_count = 0;
client->success_count = 0;
if ((result=fast_multi_sock_client_send_data(client, send_buffer)) != 0) {
return result;
}
return fast_multi_sock_client_deal_io(client);
}

View File

@ -1,132 +0,0 @@
/*
* 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/>.
*/
//multi_socket_client.h
#ifndef _MULTI_SOCKET_CLIENT_H_
#define _MULTI_SOCKET_CLIENT_H_
#include <net/if.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "common_define.h"
#include "connection_pool.h"
#include "fast_buffer.h"
#include "ioevent.h"
typedef enum {
fms_stage_recv_header = 'H',
fms_stage_recv_body = 'B'
} FastMultiSockRecvStage;
struct fast_multi_sock_client;
struct fast_multi_sock_entry;
typedef int64_t (*fms_client_get_current_time_ms_func)();
//return the body length
typedef int (*fms_client_get_body_length_func)(const FastBuffer *recv_buffer);
//IO deal fucntion
typedef int (*fast_multi_sock_client_io_func)(struct fast_multi_sock_client *
client, struct fast_multi_sock_entry *entry);
typedef struct fast_multi_sock_entry {
ConnectionInfo *conn; //the connected socket must be non-block socket
FastBuffer *send_buffer; //send buffer for internal use
fast_multi_sock_client_io_func io_callback; //for internal use
FastBuffer recv_buffer; //recv buffer for response package
int error_no; //0 for success, != 0 fail
int remain; //remain bytes, for internal use
FastMultiSockRecvStage recv_stage; //for internal use
bool done; //for internal use
} FastMultiSockEntry;
typedef struct fast_multi_sock_client {
int entry_count;
int header_length; //package header size
int pulling_count;
int success_count;
int timeout_ms;
int64_t deadline_time_ms;
FastMultiSockEntry *entries;
fms_client_get_current_time_ms_func get_current_time_ms_func;
fms_client_get_body_length_func get_body_length_func;
IOEventPoller ioevent;
} FastMultiSockClient;
#ifdef __cplusplus
extern "C" {
#endif
/**
init function
@param client the client context
@param entries the socket entries
@param entry_count the count of socket entries
@param header_length the header length of a package
@param get_body_length_func the get body length function
@param get_current_time_ms_func the get current time in ms function
@param init_recv_buffer_size the initial size of response buffer
@param timeout_ms the timeout in milliseconds
@return error no, 0 for success, != 0 fail
*/
int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
FastMultiSockEntry *entries, const int entry_count,
const int header_length,
fms_client_get_body_length_func get_body_length_func,
fms_client_get_current_time_ms_func get_current_time_ms_func,
const int init_recv_buffer_size, const int timeout_ms);
/**
init function
@param client the client context
@param entries the socket entries
@param entry_count the count of socket entries
@param header_length the header length of a package
@param get_body_length_func the get body length function
@param init_recv_buffer_size the initial size of response buffer
@param timeout the timeout in seconds
@return error no, 0 for success, != 0 fail
*/
int fast_multi_sock_client_init(FastMultiSockClient *client,
FastMultiSockEntry *entries, const int entry_count,
const int header_length,
fms_client_get_body_length_func get_body_length_func,
const int init_recv_buffer_size, const int timeout);
/**
destroy function
@param client the client context
@return none
*/
void fast_multi_sock_client_destroy(FastMultiSockClient *client);
/**
request function
@param client the client context
@param send_buffer the buffer to send
@return error no, 0 for success, != 0 fail
*/
int fast_multi_sock_client_request(FastMultiSockClient *client,
FastBuffer *send_buffer);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
/* php7 extension wrapper
* for compatibility, these wrapper functions are designed for old php version.
*/
@ -34,22 +19,6 @@
#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)
@ -63,8 +32,7 @@ typedef int zend_size_t;
#define ZEND_TYPE_OF(z) (z)->type
#define ZEND_IS_BOOL(z) (ZEND_TYPE_OF(z) == IS_BOOL)
#define ZEND_IS_TRUE(z) (ZEND_IS_BOOL(z) && (z)->value.lval != 0)
#define ZEND_IS_FALSE(z) (ZEND_IS_BOOL(z) && (z)->value.lval == 0)
#define ZEND_IS_TRUE(z) ((z)->value.lval != 0)
#define Z_CE_P(z) ((zend_class_entry *)(z))
#define ZEND_ZVAL_STRINGL ZVAL_STRINGL
//#define zend_get_object_wrapper(obj) zend_object_store_get_object(obj)
@ -157,7 +125,6 @@ typedef size_t zend_size_t;
#define ZEND_TYPE_OF(z) Z_TYPE_P(z)
#define ZEND_IS_BOOL(z) (Z_TYPE_P(z) == IS_TRUE || Z_TYPE_P(z) == IS_FALSE)
#define ZEND_IS_TRUE(z) (Z_TYPE_P(z) == IS_TRUE)
#define ZEND_IS_FALSE(z) (Z_TYPE_P(z) == IS_FALSE)
#define Z_STRVAL_PP(s) Z_STRVAL_P(*s)
#define Z_STRLEN_PP(s) Z_STRLEN_P(*s)
#define ZEND_ZVAL_STRINGL(z, s, l, dup) ZVAL_STRINGL(z, s, l)

View File

@ -1,18 +1,3 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -32,11 +17,12 @@ int get_pid_from_file(const char *pidFilename, pid_t *pid)
return errno != 0 ? errno : EPERM;
}
file_size = sizeof(buff);
file_size = sizeof(buff) - 1;
if ((result=getFileContentEx(pidFilename, buff, 0, &file_size)) != 0) {
return result;
}
*(buff + file_size) = '\0';
*pid = strtol(buff, NULL, 10);
if (*pid == 0) {
return EINVAL;
@ -50,14 +36,14 @@ int write_to_pid_file(const char *pidFilename)
char buff[32];
int len;
len = fc_itoa(getpid(), buff);
len = sprintf(buff, "%d", (int)getpid());
return writeToFile(pidFilename, buff, len);
}
int delete_pid_file(const char *pidFilename)
{
int result;
pid_t pid = 0;
pid_t pid;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
return result;
@ -112,59 +98,43 @@ static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
}
}
int process_stop_ex(const char *pidFilename,
const bool bShowError, bool *force)
int process_stop(const char *pidFilename)
{
#define MAX_WAIT_COUNT 300
pid_t pid = 0;
pid_t pid;
int result;
int sig;
int i;
*force = false;
if ((result=do_stop(pidFilename, bShowError, &pid)) != 0) {
result = do_stop(pidFilename, true, &pid);
if (result != 0) {
return result;
}
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
for (i=0; i<MAX_WAIT_COUNT; i++) {
sig = (i % 10 == 0) ? SIGTERM : 0;
if (kill(pid, sig) != 0) {
break;
}
do {
sleep(1);
} while (kill(pid, SIGTERM) == 0);
fprintf(stderr, "pid [%d] exit.\n", (int)pid);
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);
*force = true;
fc_sleep_ms(100);
}
}
fprintf(stderr, "pid [%d] exit.\n\n", (int)pid);
return 0;
}
int process_restart(const char *pidFilename)
{
const bool bShowError = false;
bool force;
int result;
pid_t pid;
result = process_stop_ex(pidFilename, bShowError, &force);
if (result == ENOENT || result == ESRCH) {
result = 0;
} else if (result == 0) {
if (force) {
result = do_stop(pidFilename, false, &pid);
if (result == 0) {
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
do {
sleep(1);
}
} while (kill(pid, SIGTERM) == 0);
fprintf(stderr, "starting ...\n");
}
if (result == ENOENT || result == ESRCH) {
return 0;
}
return result;
}
@ -180,27 +150,14 @@ static const char *process_get_exename(const char* program)
}
}
static const char *get_exename_by_pid(const pid_t pid, char *buff,
const int buff_size, int *result)
{
char cmdfile[MAX_PATH_SIZE];
int64_t cmdsz;
cmdsz = buff_size;
sprintf(cmdfile, "/proc/%d/cmdline", pid);
if ((*result=getFileContentEx(cmdfile, buff, 0, &cmdsz)) != 0) {
fprintf(stderr, "read file %s fail, errno: %d, error info: %s\n",
cmdfile, *result, strerror(*result));
return NULL;
}
return process_get_exename(buff);
}
int process_start(const char* pidFilename)
{
pid_t pid = 0;
pid_t pid;
int result;
char cmdline[MAX_PATH_SIZE];
char cmdfile[MAX_PATH_SIZE];
char argv0[MAX_PATH_SIZE];
int64_t cmdsz;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
if (result == ENOENT) {
@ -215,30 +172,30 @@ int process_start(const char* pidFilename)
}
if (kill(pid, 0) == 0) {
if (access("/proc", F_OK) == 0) {
char cmdline[MAX_PATH_SIZE];
char argv0[MAX_PATH_SIZE];
const char *exename1, *exename2;
exename1 = get_exename_by_pid(pid, cmdline, sizeof(cmdline), &result);
if (exename1 == NULL) {
return result;
}
exename2 = get_exename_by_pid(getpid(), argv0, sizeof(argv0), &result);
if (exename2 == NULL) {
return result;
}
if (strcmp(exename1, exename2) == 0) {
fprintf(stderr, "process %s already running, pid: %d\n",
argv0, (int)pid);
return EEXIST;
}
return 0;
const char *exename1, *exename2;
cmdsz = sizeof(cmdline);
cmdline[cmdsz-1] = argv0[cmdsz-1] = '\0';
sprintf(cmdfile, "/proc/%d/cmdline", pid);
if ((result=getFileContentEx(cmdfile, cmdline, 0, &cmdsz)) != 0) {
fprintf(stderr, "read file %s failed. %d %s\n",
cmdfile, errno, strerror(errno));
return result;
}
else {
fprintf(stderr, "process already running, pid: %d\n", (int)pid);
cmdsz = sizeof(argv0);
sprintf(cmdfile, "/proc/%d/cmdline", getpid());
if ((result=getFileContentEx(cmdfile, argv0, 0, &cmdsz)) != 0) {
fprintf(stderr, "read file %s failed. %d %s\n",
cmdfile, errno, strerror(errno));
return result;
}
exename1 = process_get_exename(cmdline);
exename2 = process_get_exename(argv0);
if (strcmp(exename1, exename2) == 0) {
fprintf(stderr, "process %s already running, pid: %d\n",
argv0, (int)pid);
return EEXIST;
}
return 0;
}
else if (errno == ENOENT || errno == ESRCH) {
return 0;
@ -251,41 +208,40 @@ int process_start(const char* pidFilename)
}
}
int process_exist(const char *pidFilename, pid_t *pid)
int process_exist(const char *pidFilename)
{
pid_t pid;
int result;
if ((result=get_pid_from_file(pidFilename, pid)) != 0) {
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
if (result == ENOENT) {
return result;
return false;
}
else {
fprintf(stderr, "get pid from file: %s fail, " \
"errno: %d, error info: %s\n",
pidFilename, result, strerror(result));
return result;
return true;
}
}
if (kill(*pid, 0) == 0) {
return 0;
if (kill(pid, 0) == 0) {
return true;
}
else if (errno == ENOENT || errno == ESRCH) {
return ENOENT;
return false;
}
else {
result = errno != 0 ? errno : EPERM;
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
(int)*pid, result, strerror(result));
return result;
(int)pid, errno, strerror(errno));
return true;
}
}
int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
const int path_size, const int noent_log_level)
int get_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size)
{
char *pBasePath;
string_t path_string;
IniContext iniContext;
int result;
@ -302,7 +258,7 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
do
{
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
if (pBasePath == NULL || *pBasePath == '\0')
if (pBasePath == NULL)
{
logError("file: "__FILE__", line: %d, " \
"conf file \"%s\" must have item " \
@ -311,18 +267,16 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
break;
}
FC_SET_STRING(path_string, pBasePath);
normalize_path(NULL, &path_string, base_path, path_size);
snprintf(base_path, path_size, "%s", pBasePath);
chopPath(base_path);
if (!fileExists(base_path))
{
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;
}
{
logError("file: "__FILE__", line: %d, " \
"\"%s\" can't be accessed, error info: %s", \
__LINE__, base_path, STRERROR(errno));
result = errno != 0 ? errno : ENOENT;
break;
}
if (!isDir(base_path))
{
logError("file: "__FILE__", line: %d, " \
@ -339,9 +293,6 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
int process_action(const char *pidFilename, const char *action, bool *stop)
{
int result;
pid_t pid;
*stop = false;
if (action == NULL)
{
@ -353,23 +304,6 @@ int process_action(const char *pidFilename, const char *action, bool *stop)
*stop = true;
return process_stop(pidFilename);
}
else if (strcmp(action, "status") == 0)
{
*stop = true;
result = process_exist(pidFilename, &pid);
switch (result) {
case 0:
printf("Running, pid: %d\n", (int)pid);
break;
case ENOENT:
printf("NOT running\n");
break;
default:
printf("Unkown status\n");
break;
}
return result;
}
else if (strcmp(action, "restart") == 0)
{
return process_restart(pidFilename);

View File

@ -1,18 +1,3 @@
/*
* 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/>.
*/
#ifndef PROCESS_CTRL_H
#define PROCESS_CTRL_H
@ -27,11 +12,8 @@
extern "C" {
#endif
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_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size);
int get_pid_from_file(const char *pidFilename, pid_t *pid);
@ -39,19 +21,11 @@ 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, bool *force);
static inline int process_stop(const char *pidFilename)
{
const bool bShowError = true;
bool force;
return process_stop_ex(pidFilename, bShowError, &force);
}
int process_stop(const char *pidFilename);
int process_restart(const char *pidFilename);
int process_exist(const char *pidFilename, pid_t *pid);
int process_exist(const char *pidFilename);
int process_action(const char *pidFilename, const char *action, bool *stop);

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