Compare commits

..
892 Commits
Author SHA1 Message Date
John Sully bf5b2d78d9 Fix issue #300 2021-03-30 23:30:17 +00:00
benschermel f660cd9357 bump version 2021-03-27 18:30:52 +00:00
benschermel 4272a7de24 bump version 2021-03-26 22:57:19 +00:00
benschermel f52815d309 update rpm script for centos8 2021-03-26 22:55:12 +00:00
John Sully 0b7b5332f2 Merge branch 'unstable' into RELEASE_6 2021-02-07 23:55:58 +00:00
John Sully 165333b0fc Fix memory leak in mvccRestore 2021-02-07 23:38:49 +00:00
John Sully cc827e157a Module test reliability 2021-02-01 22:21:49 +00:00
John Sully 7b4e25008a Simplify the handling of CreateTimer 2021-02-01 15:51:22 -05:00
VivekSainiEQ f66e5a9c3d Modified RM_CreateTimer to prevent more that one function being posted at a time 2021-02-01 15:51:22 -05:00
VivekSainiEQ 9954f5b4a4 Changed RM_CreateTimer to only call aePostFunction is existing aePostFunction isn't in flight 2021-02-01 15:51:22 -05:00
VivekSainiEQ 53936661c8 Now post entire timer installation process as one function to make atomic with respect to global locks 2021-02-01 15:51:22 -05:00
VivekSainiEQ e2552ff8a9 Updated header file to remove fSynchronous flag 2021-02-01 15:51:22 -05:00
VivekSainiEQ 6ab08cc3e1 Removed more uses of fSynchronous and the use of condition variable and mutex on the control struct. 2021-02-01 15:51:22 -05:00
VivekSainiEQ 3205373bb3 Added fix for scenario where module thread waiting for s_mutexModule in acquireGIL can deadlock with module thread waiting for s_mutex in releaseGIL 2021-02-01 15:51:22 -05:00
VivekSainiEQ 3b8d1f7076 removed synchronous calls to aePostFunction and changed scope of g_fModuleThread in order to prevent module related deadlocks, issue #214 2021-02-01 15:51:22 -05:00
John Sully d30fcfbe8a Bump version 2021-01-31 21:24:49 +00:00
John Sully 32b11ab809 Merge branch 'unstable' into RELEASE_6 2021-01-31 21:24:07 +00:00
John Sully 5832c25ad1 ARM build fix 2021-01-31 21:22:23 +00:00
John Sully 569a3d9ff8 Fix test failure caused by allowing pings during load 2021-01-31 07:15:55 +00:00
John Sully 69bc7108bd Reduce intermittent failures by giving tests more time 2021-01-31 06:33:13 +00:00
christianEQ 8a557e9d71 added exception to allow pings during loading 2021-01-31 00:12:49 -05:00
christianEQ fe0f071993 added severity levels for afterErrorReply 2021-01-31 00:12:49 -05:00
John Sully effa53339c Improve multithreaded test reliability 2021-01-31 04:33:27 +00:00
John Sully f6fb0e4620 Fix test failure due to bad merge 2021-01-31 03:40:57 +00:00
John Sully cf46a014c1 Fix CI failure due to missing package 2021-01-31 02:36:30 +00:00
John Sully d72b5fa16d Fix crash on shutdown command 2021-01-31 02:30:28 +00:00
christianEQ 0151507cef Merge pull request #284 from christianEQ/redismerge_2021-01-20
Merge Redis 6.0.10 into KeyDB
2021-01-29 10:59:36 -05:00
christianEQ 0fea781f8f killMainThread -> killServerThreads 2021-01-28 23:57:19 +00:00
christianEQ 3c4cadc020 compare_exchange in connSocketRead, explicitly enforce memory order (even if redundant) 2021-01-28 23:17:48 +00:00
christianEQ e2615ccf88 fixed replicaof no one config, added test case 2021-01-28 19:49:22 +00:00
christianEQ 595deb0e13 updated version num to 255.255.255 2021-01-28 16:54:22 +00:00
christianEQ 5372d1aab2 Merge remote-tracking branch 'john/unstable' into redismerge_2021-01-20 2021-01-27 22:25:14 +00:00
christianEQ 52eca14ca6 arm locker before checking zmalloc_used_memory 2021-01-27 22:24:06 +00:00
Daniel Dai 1155f5ac63 Fix Swapdb crash 2021-01-27 15:24:10 -05:00
christianEQ 7319953ae3 fixed uninitialized variables in ACLSetUserCommandBit 2021-01-26 23:29:15 +00:00
christianEQ b8e106a72e fixed strncpy off-by-one errors 2021-01-26 23:27:28 +00:00
christianEQ f30f8eba2f removed unimplemented killIOThreads function declaration 2021-01-26 22:27:22 +00:00
christianEQ 7ed2296fc5 fixed server.cpp mentions 2021-01-26 22:22:19 +00:00
christianEQ 0691a46669 added note about io-threads to keydb.conf 2021-01-26 22:10:53 +00:00
christianEQ d7f01c1f7d fixed race condition in connSocketWrite 2021-01-26 22:08:07 +00:00
christianEQ 4d71929c60 Removed Redis-specific things from conf file 2021-01-26 21:50:45 +00:00
christianEQ dadce055f8 Merge tag 'tags/6.0.10' into redismerge_2021-01-20 2021-01-26 21:43:09 +00:00
christianEQ d2867580ab changed loading process config types to be consistent across environments 2021-01-14 21:12:36 -05:00
christianEQ 8dc238efae renamed loaded key counter to be more clear 2021-01-14 13:06:57 -05:00
christianEQ 7cd4b5e11c removed 'comment arguments' from config options (doesn't ignore inline comments) 2021-01-14 13:06:57 -05:00
christianEQ 00043f9509 fixed signedness warning 2021-01-14 13:06:57 -05:00
christianEQ 9b81f3f263 added section to keydb.conf for new options, tweaked default 2021-01-14 13:06:57 -05:00
christianEQ 2747d1a1a9 ping replicas during key load 2021-01-14 13:06:57 -05:00
christianEQ 9f7ed0b232 added config option for loading callback interval keys 2021-01-14 13:06:57 -05:00
christianEQ c176ea7366 configurized loading_process_events_interval_bytes 2021-01-14 13:06:57 -05:00
John Sully d50e4bb819 Fix intermittent module test failure, resizing the repl backlog is not good enough to clear the backlog 2021-01-12 00:29:07 +00:00
benschermel 4485ca74f6 update perf chart, build info, job post link 2021-01-11 11:40:00 -05:00
benschermel 7f72b214e5 created ascii logo image 2021-01-11 11:40:00 -05:00
John Sully bc8cc1adb3 Merge branch 'repl_perf' into unstable 2020-12-24 02:22:57 +00:00
John Sully d03c2de901 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-12-11 03:59:50 +00:00
John Sully 7d3c5f1e64 don't try and free a client that can't be freed 2020-12-11 03:59:39 +00:00
John Sully 81573de393 Prevent use after free 2020-12-11 03:59:26 +00:00
John Sully a80dd5d001 Remove AE_ASSERT and use the proper assert infra 2020-12-11 00:24:27 +00:00
John Sully 7e0077f293 Prevent test crash due to unimplemented save for nested hash 2020-12-11 00:23:44 +00:00
John Sully 1eb035e6ad Fix crash freeing nested hash with list 2020-12-11 00:23:14 +00:00
Kajaruban Surendran bdd14ac517 Addressing PR comments 2020-12-04 14:54:06 -05:00
Kajaruban Surendran 63e5d00bdf Addressing PR comments 2020-12-04 14:54:06 -05:00
Kajaruban Surendran c25fb3d74f Handling of aeResizeSetSize's return code for current thread 2020-12-04 14:54:06 -05:00
Kajaruban Surendran 572d41325b check the aeResizeSetSize return code 2020-12-04 14:54:06 -05:00
Kajaruban Surendran e02120cdf7 Adding thread index to the error message 2020-12-04 14:54:06 -05:00
Kajaruban Surendran 7b1221a74d Call aePostFunction to change the setsize of each threads by that thread 2020-12-04 14:54:06 -05:00
Kajaruban Surendran d6b4f994ad Calling initServerThread function cserver.cthreads(server-threads) times than MAX_EVENT_LOOPS(constant) 2020-12-04 14:52:28 -05:00
christianEQ 66a41dafc4 Issue: #204 Allocate 8 MB to thread stack 2020-12-01 14:50:03 -05:00
John Sully f19b9c155e Issue: #260 Don't use C++ static_assert in C files 2020-11-30 23:01:20 +00:00
John Sully 5d016fdb6b code coverage reports should test multithreaded 2020-11-30 22:59:00 +00:00
VivekSainiEQ cae9924fd9 Added module data type load/save tests 2020-11-30 17:47:04 -05:00
VivekSainiEQ 089f28e8ba Removed use of module datatypes, now should work if tests/modules is not built 2020-11-30 17:47:04 -05:00
VivekSainiEQ dcb44d3a09 Added tests for saving various data types to disk and loading them back, and for loading data types from redis to maintain compatibility 2020-11-30 17:47:04 -05:00
VivekSainiEQ f99cba0b92 Added remainder of runtest scripts to make lcov command. Code coverage goes from 57.9% to 72.1% 2020-11-30 17:47:04 -05:00
VivekSainiEQ e10dc0dace Added KeyDB.info to .gitignore file 2020-11-30 17:47:04 -05:00
Kajaruban Surendran 49a89d636b Configurable option for MOTD 2020-11-30 10:42:48 -05:00
VivekSainiEQ b94f91b9b2 Added references to KeyDB.info instead of redis.info 2020-11-25 18:49:20 -05:00
VivekSainiEQ 06a17c8511 Properly escaped $ in lcov command 2020-11-25 18:49:20 -05:00
VivekSainiEQ eebd70aaa6 Updated 'make lcov' command to exclude external dependancies and generate final code coverage percentage 2020-11-25 18:49:20 -05:00
VivekSainiEQ 779c775df9 Added test for issue #257 2020-11-25 17:21:37 -05:00
VivekSainiEQ 1d4d2925c2 Made NULL pointer check explicit, issue #257 2020-11-25 17:21:37 -05:00
VivekSainiEQ b67db7c2d5 Added NULL check to function objFromAllocPtr, now NULL input will map to NULL output even if active replica is enabled 2020-11-25 17:21:37 -05:00
John Sully 18953b2998 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-11-23 02:01:54 +00:00
John Sully 527b7eb074 Fix issue where active replication doesn't replicate RDB data 2020-11-23 02:01:40 +00:00
Kajaruban Surendran 34a97c447f fix for the server crash when the maxclients increased via config set 2020-11-20 15:20:46 -05:00
John Sully 1c525e20b1 Blocking clients should not crash if an active replica loads a remote RDB with a key in the blocklist 2020-11-19 23:28:01 +00:00
John Sully 0bcce50285 Ensure multithreaded tests pass 2020-11-13 21:08:10 +00:00
John Sully 96e0b2a2b1 Improve replication performance in multithreaded scenarios 2020-11-13 21:08:10 +00:00
John Sully f3794d2c42 Add ability to compile KeyDB without MOTD and curl 2020-11-13 20:51:30 +00:00
John Sully 97fd736923 Add missing file 2020-11-11 03:29:38 +00:00
John Sully ba950a3d1f Second implementation of nested hashes 2020-11-06 19:24:48 +00:00
John Sully dad5a902d3 Additional test reliability fixes 2020-10-27 07:25:43 +00:00
John Sully 3e33fbcd35 Disarm not release D'oh 2020-10-27 06:41:33 +00:00
John Sully 444555d3e4 Active replica test reliability enhancements 2020-10-27 06:23:14 +00:00
John Sully 6a74f524e5 Prevent crashes on shutdown due to lock being held 2020-10-27 04:53:19 +00:00
John Sully 9c5b59ac01 Ensure MVCC timestamp is incremented after the real time is updated 2020-10-27 04:52:35 +00:00
John Sully 1840601f8e Fix multithreaded test failure 2020-10-27 01:54:13 +00:00
John Sully 88962af8b2 Avoid unnecessary memory fences 2020-10-26 02:28:38 +00:00
John Sully df22cdf6e9 Remove addReply*Async methods since we already know if its async or not. This is just a source of bugs 2020-10-24 02:18:03 +00:00
John Sully 041446005b Allow the locker to be used even without a client 2020-10-23 20:21:49 +00:00
John Sully 7c39a9b0e1 Fix multithread test failures 2020-10-23 15:57:39 +00:00
John Sully 05cd92f766 Remove leak warning with ASAN in the CLI 2020-10-21 21:16:08 +00:00
John Sully d724e7226c run when necessary 2020-10-16 07:00:03 +00:00
John Sully 738c782f02 Fix replica buffer overflows 2020-10-16 06:47:40 +00:00
John Sully 33b05c859a Avoid locking if we won't run a time event 2020-10-16 06:19:52 +00:00
John Sully ed369d7223 Reduce async write copies 2020-10-15 23:10:17 +00:00
John Sully fb32bb12b1 Fix branding 2020-10-15 20:15:35 +00:00
John Sully 3e996035ea Relax memory order where possible 2020-10-13 06:35:16 +00:00
John Sully ae8a94d615 Significantly improve perf in replication scenarios 2020-10-12 15:27:03 +00:00
John Sully 69a74a567b Avoid excess locking, seeing up to 8% performance improvements 2020-10-12 05:50:58 +00:00
John Sully 1b46d4f09a Perf: remove unnecessary vector operations 2020-10-12 04:28:39 +00:00
John Sully c6f13892e0 Remove dead code 2020-10-09 21:02:09 +00:00
Hanif Bin Ariffin 05e0f32345 Fixed non-empty check in src/Makefile
Per [GNU Make Manual](https://www.gnu.org/software/make/manual/html_node/Conditional-Syntax.html).
To properly check for non-empty variable, one must strip whitespaces.

Signed-off-by: Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
2020-10-05 10:58:49 -04:00
Hanif Bin Ariffin 8171e6de13 Removed dead code from a macro in zmalloc.cpp
I think the compiler would have removed this no-op anyways but it
definitely wasted me some 30 minutes on this :(

I was hoping I could remove the branch through some bit-hacking but
apparently its dead code :). Oh well, its 30 minutes of refreshing
bit hacking.

Signed-off-by: Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
2020-10-03 20:41:26 -04:00
John Sully b042495f37 Delete CONTRIBUTING 2020-10-01 11:17:56 -04:00
John Sully 420ccdfbae Fix module test failures due to locking 2020-10-01 00:08:54 +00:00
John Sully 41466a4147 Fix TLS test failure due to bad merge 2020-09-30 20:21:40 +00:00
John Sully 9798f2d711 Keep redis-cli.c C89 compatible 2020-09-30 20:17:51 +00:00
John Sully 5f3543921b Mac build break fix 2020-09-30 20:17:02 +00:00
John Sully a41366cc3a Fix stream replication failure with active replication, issue #238 2020-09-30 20:12:54 +00:00
John Sully 4c7e4b91a6 Merge tag '6.0.8' into unstable 2020-09-30 19:47:55 +00:00
John Sully 28183f4b66 Test RDB merge on load with active replication 2020-09-29 03:26:06 +00:00
Ben Schermel 63c47a09e9 update deb changelog 2020-09-28 23:42:54 +00:00
Ben Schermel 087af94c22 update deb changelog 2020-09-28 20:51:31 +00:00
John Sully bf3a3225fc Drop min-clients-per-thread to a more reasonable number 2020-09-28 19:19:47 +00:00
John Sully a0abc1eddd Drop min-clients-per-thread to a more reasonable number 2020-09-28 19:17:36 +00:00
John Sully dab9296d7c bump version 6.0.16 2020-09-28 19:14:17 +00:00
John Sully a6f5a391a1 Merge branch 'unstable' into RELEASE_6 2020-09-28 18:55:24 +00:00
John Sully 676644f2db Support read only replicas attaching to active replicas (Bug #229) 2020-09-23 04:16:08 +00:00
John Sully 22ac56d62d Active replicas memory leak 2020-09-22 21:38:35 +00:00
John Sully 143f7f634d Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-09-21 04:42:46 +00:00
Dmitry Dorofeev 955faef23a Fix to support FreeBSD pthread_getthreadid_np call 2020-09-21 00:41:41 -04:00
John Sully 2e159e6ea3 Fix TSAN errors in fastlock 2020-09-21 03:26:50 +00:00
John Sully 02b533fec3 Fix issue #222 2020-09-21 01:09:58 +00:00
John Sully de3099e6d8 Make multimaster replication info statelessly paresable 2020-09-20 23:57:06 +00:00
John Sully 368f67f422 Dramatically improve the performance of subkey expires 2020-09-20 23:30:21 +00:00
John Sully 13c9a094d1 Reduce test noise 2020-09-19 22:00:17 +00:00
John Sully 0f8b7a19ef Fix CI failure due to apt host changes 2020-09-19 21:49:59 +00:00
John Sully 8f7d977f90 Avoid memory overhead in situations it won't be used (active rep only) 2020-09-19 21:44:59 +00:00
John Sully 064440ee84 Update endurance test for ubuntu 20 2020-09-17 02:10:18 +00:00
John Sully 50641d0569 Fix build break 2020-09-17 00:53:56 +00:00
John Sully f5ecc77e29 master_global_link_status should respect the quorum 2020-09-17 00:31:10 +00:00
John Sully 655bb6e21c Allow reads during an active replica load, optionally allow writes as an experimental feature 2020-09-17 00:13:03 +00:00
John Sully ab4cdd2ed4 Implement replica-quorum config 2020-09-16 03:26:31 +00:00
Yossi Gottlieb d3834c5069 TLS: Session caching configuration support. (#7420)
* TLS: Session caching configuration support.
* TLS: Remove redundant config initialization.
2020-09-16 02:10:29 +00:00
John Sully 7a1b2c58c3 Protocol error in client command 2020-09-11 20:48:18 +00:00
John Sully 7fc6d6c6b1 Fix more protocol errors 2020-09-11 20:47:27 +00:00
John Sully dec5db4e71 Fix protocol difference with Redis 2020-09-11 20:08:26 +00:00
John Sully d47aeb1fc8 Fix whitespace 2020-09-07 03:35:46 +00:00
John Sully e47584b286 Dramatically improve perf by blocking commands 2020-09-07 00:49:53 +00:00
John Sully f17d178d03 Add build flag to disable MVCC tstamps 2020-08-10 06:10:24 +00:00
John Sully d88fd1588d Fix lock after free in module API 2020-08-10 06:10:24 +00:00
John Sully 119797014c Remove gitter, we don't check it often enough 2020-07-13 21:14:03 -04:00
benschermel a6782a3c0d update deb changelog 2020-07-13 01:35:25 -04:00
John Sully f7d7baccc9 Bump version 2020-07-13 03:59:16 +00:00
John Sully eff294e374 Merge branch 'unstable' into RELEASE_6 2020-07-13 01:05:36 +00:00
John Sully e8f568644b Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-07-13 01:05:17 +00:00
John Sully f7c2006bf6 Merge branch 'unstable' into RELEASE_6 2020-07-13 01:04:49 +00:00
John Sully b736a95b0d Merge tag '6.0.5' into unstable
Redis 6.0.5
2020-07-13 00:55:23 +00:00
benschermel d909d12cb3 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-07-12 18:04:40 -04:00
benschermel 201ffa9d62 update rpm permissions 2020-07-12 18:03:21 -04:00
John Sully 5619f51528 Add the KEYDB.MEXISTS command, see issue #203 2020-07-12 21:42:11 +00:00
John Sully d99d06b125 Add multi-master-no-forward command to reduce bus traffic with multi-master 2020-07-12 19:25:19 +00:00
John Sully 1b9ade7f65 Document min-clients-per-thread 2020-07-12 18:49:02 +00:00
John Sully e01312642b Prevent deadlock in RM_ThreadSafeContextLock() when triggered as part of a module callback in a server thread 2020-07-12 18:17:53 +00:00
John Sully cd9514f4c8 Fix failure to merge databases on active replica sync, due to bad merge with Redis 6 2020-07-12 01:13:22 +00:00
John Sully f111c23415 Support missing Redis 6 config options 2020-07-11 21:39:20 +00:00
John Sully 6857c4c208 Latency fixes 2020-07-01 21:59:38 -04:00
Muhammad Zahalqa 52897f8f9a replace memcpy with cctor on objects 2020-06-24 23:20:59 -04:00
Muhammad Zahalqa 8bc70e9840 unique lock used with cv.wait already owns mutex 2020-06-24 23:18:53 -04:00
Muhammad Zahalqa 5b81303f04 Fix bug in condition_variabe.wait usage
consition variable wait should always be called with a locked mutex.
This code break the pre-conditions of using wait.
2020-06-24 23:18:53 -04:00
Muhammad Zahalqa ede524c064 fixes for robj_sharedptr
1. fix cases where null pointer might be accessed
2. make assignmnet op safe
3. make operator bool explicit (safe bool idiom)
4. make comparison operators symetric

fix robj_sharedptr use in rdb.cpp
2020-06-24 23:18:27 -04:00
Muhammad Zahalqa aeed09c346 aeCommand objects no need for memset and missing init of some memebers. 2020-06-24 23:15:29 -04:00
John Sully 42c4d85d72 Merge PKG files from unstable
No code change
2020-06-24 00:16:21 -04:00
John Sully 70b80aa5fa Implement replicaof remove as requested in issue #192 2020-06-09 12:43:58 -04:00
John Sully e8d4d095cc Update gcov for C++ 2020-06-08 16:48:44 -04:00
Ben Schermel c50a3568a5 update Dockerfile 2020-06-08 15:34:22 -04:00
Ben Schermel 17e96b91b5 updating changelog 2020-06-08 15:34:22 -04:00
Ben Schermel c5e7a8517b dh9 for stretch deb pkg 2020-06-08 15:34:22 -04:00
Ben Schermel c36773777d fix missing sentinel 2020-06-08 15:34:22 -04:00
Ben Schermel d69e0b8561 update changelog 2020-06-08 15:34:22 -04:00
Ben Schermel 19ccc22a43 update changelog 2020-06-08 15:34:22 -04:00
Ben Schermel 6968a0cfcb update changelog 2020-06-08 15:34:22 -04:00
Ben Schermel df618fbd9f include support for dists < dh11 2020-06-08 15:34:22 -04:00
Ben Schermel 94acd43340 fix rpmbuild dirs 2020-06-08 15:34:22 -04:00
Ben Schermel 14bdd745d1 fix rpmbuild dirs 2020-06-08 15:34:22 -04:00
Ben Schermel aa3f5de16f adding dh_installsystemd 2020-06-08 15:34:22 -04:00
Ben Schermel 9f7890cb1a strip unused from deb source 2020-06-08 15:34:22 -04:00
benschermel 1dc34c16b5 add deb/rpm/docker support 2020-06-08 15:34:22 -04:00
benschermel b0e7be7ce2 add deb/rpm/docker support 2020-06-08 15:34:22 -04:00
benschermel 026ab4c922 update github CI for deb 2020-06-08 15:34:22 -04:00
Ben Schermel 07ba64c200 update rpm versioning 2020-06-08 15:34:22 -04:00
benschermel b4b35cf904 add package utilities 2020-06-08 15:34:22 -04:00
John Sully ba974c9810 Some valgrind fixes 2020-06-07 23:20:10 -04:00
John Sully 9817db7edd fix valgrind false error 2020-06-07 20:17:47 -04:00
John Sully 515bb0e6bd Endurance mode for tests ignore flaky ones 2020-06-07 16:59:59 -04:00
John Sully 4a3e1f3b9b Bump version 2020-06-07 16:43:07 -04:00
John Sully 575fc98010 Solo tests should work with loopn 2020-06-07 16:43:07 -04:00
John Sully eb18345a61 Stream tests rely on deferring clients, mitigate races caused by them 2020-06-07 16:43:07 -04:00
John Sully d528c5c2c2 replication test race 2020-06-07 16:43:07 -04:00
John Sully fa03a539f3 fix race in test 2020-06-07 16:43:07 -04:00
John Sully 9646b1d944 Make lazyfree more reliable 2020-06-07 16:43:07 -04:00
John Sully cc5e906ebd Detect issues like #189 2020-06-07 16:43:07 -04:00
John Sully b0e14683b2 Ensure CRON jobs run in a clean environment 2020-06-07 16:43:07 -04:00
John Sully 8d5cc4cf0c Undecorated new is OK to use 2020-06-07 16:43:07 -04:00
John Sully bc7ea8fb20 Solo tests should work with loopn 2020-06-07 15:06:50 -04:00
John Sully 2caf8e4c80 Stream tests rely on deferring clients, mitigate races caused by them 2020-06-07 13:59:41 -04:00
John Sully e1f3cd6ec3 replication test race 2020-06-07 01:14:57 -04:00
John Sully 02e821530a fix race in test 2020-06-07 00:44:11 -04:00
John Sully b6c3d80edb Make lazyfree more reliable 2020-06-07 00:40:58 -04:00
John Sully 0042586190 Detect issues like #189 2020-06-05 22:18:28 -04:00
John Sully c6dce838b7 Ensure CRON jobs run in a clean environment 2020-06-05 21:35:47 -04:00
John Sully 5b885bb164 Undecorated new is OK to use 2020-06-01 23:36:01 -04:00
John Sully b608acb349 RELEASE endurance tests should run offset from unstable 2020-06-01 17:02:16 -04:00
John Sully 8dbea2a050 Bump version 2020-06-01 17:01:50 -04:00
John Sully 95f46e6077 maxmem tests should be run solo for higher reliability 2020-06-01 16:50:30 -04:00
John Sully 31f58311e3 Remove debug logs that shouldn't have been checked in 2020-06-01 16:34:05 -04:00
John Sully 130613e166 PSYNC test shouldn't wait forever 2020-06-01 16:13:58 -04:00
John Sully 50fd4fa7e6 PSYNC test reliability improvements (test only issue) 2020-06-01 16:01:26 -04:00
John Sully e6a9a6b428 Fix for issue #187 we need to properly handle the case where a key with a subkey expirey itself expires during load 2020-06-01 15:33:19 -04:00
John Sully d6be93537e Update endurance.yml 2020-06-01 00:25:31 -04:00
John Sully 1ef35cf466 Fix module multithreaded test failures 2020-05-31 23:46:12 -04:00
John Sully 1eb0e3c1c6 sendfile has high latency in some scenarios, don't use it 2020-05-31 23:22:25 -04:00
John Sully e50313b207 we must always respect the output of sdscat, also change the string so its not a substring of other config params 2020-05-31 23:22:10 -04:00
John Sully ac3f8d1ac7 Do another iteration for endurance 2020-05-31 22:51:02 -04:00
John Sully 202b97eff7 Don't start multimaster tests until all nodes are connected 2020-05-31 22:50:30 -04:00
John Sully f25aebf269 Fix client race in test (test only issue) 2020-05-31 21:39:50 -04:00
John Sully 9b1e636a66 --loop should run forever 2020-05-31 21:27:15 -04:00
John Sully 5147f0153a PUBSUB test reliability: A client race was erroneously failing tests (test only issue) 2020-05-31 21:27:15 -04:00
John Sully 88f7739ae0 Update endurance.yml 2020-05-31 17:50:02 -04:00
John Sully c0c033a0c1 Active replicas referencing eachother should connect one at a time 2020-05-31 16:03:50 -04:00
John Sully 73300c5700 Fix race in futex_sleep 2020-05-31 16:03:50 -04:00
John Sully 37033179fe Update endurance.yml 2020-05-31 14:18:12 -04:00
John Sully 3e6a5ac9cf Update endurance.yml 2020-05-31 03:43:06 -04:00
John Sully dcd297eb5b Endurance tests need more cores 2020-05-30 22:16:56 -04:00
John Sully 4a9742e696 Update endurance.yml 2020-05-30 20:03:04 -04:00
John Sully 8edbae2e04 Auto tune lock for high CPU tension scenarios 2020-05-30 18:22:27 -04:00
John Sully 63c6735ffc Ensure endurance run can complete in an hour 2020-05-30 15:31:54 -04:00
John Sully 8a0441c144 We only want one master connection in progress at a time, ensure that if the connection fails we try a different master 2020-05-30 15:13:28 -04:00
John Sully 460c5ed2b3 daily CI config fix 2020-05-30 03:27:37 -04:00
John Sully 8f44f0937b More clients for endurance 2020-05-30 03:13:04 -04:00
John Sully 1803b1587b Endurance tests need to be faster, reduce loops 2020-05-30 02:40:44 -04:00
John Sully a5325061f2 Only CI ARM daily 2020-05-30 02:34:37 -04:00
John Sully a10a0df09f Also test with multiple threads 2020-05-30 02:10:00 -04:00
John Sully 031044c7ea Reduce clients for endurance test 2020-05-30 02:07:30 -04:00
John Sully ca755e4905 Fix cron syntax 2020-05-30 01:53:21 -04:00
John Sully 3063a028b3 Add endurance CI tests 2020-05-30 01:47:26 -04:00
John Sully 2c659acc7d Update daily CI job 2020-05-30 01:21:50 -04:00
John Sully 341a8caef9 TLS requires we explicitly marshal connected sockets when using them on a different thread 2020-05-30 01:14:53 -04:00
John Sully 366f8c2dc6 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-05-30 00:06:23 -04:00
John Sully 5803540422 Fix memory test failures with multithreading enabled 2020-05-30 00:06:15 -04:00
Ben Schermel f17c492a63 centos build fix 2020-05-29 22:23:48 -04:00
John Sully aad6a7ce15 sendFile blocks too long for use with active replication 2020-05-29 20:27:45 -04:00
John Sully 1cb48c7bf6 Unify beforeSleep handling 2020-05-29 17:44:55 -04:00
John Sully f25c405ad2 Cluster crash 2020-05-29 03:40:52 -04:00
John Sully c9920849dd active replica tests on slow computers 2020-05-29 01:58:15 -04:00
John Sully 81b240f81d Fix test issue with TLS 2020-05-29 01:44:52 -04:00
John Sully 6a902b29e1 Fix CI 2020-05-29 01:01:41 -04:00
John Sully 9c31ac7925 Merge tag '6.0.4' into unstable
Redis 6.0.4.
2020-05-29 00:57:07 -04:00
John Sully f0d8d1680f Fix TLS tests 2020-05-29 00:16:06 -04:00
John Sully 6dcbcacb10 gencert its own step 2020-05-28 23:49:13 -04:00
John Sully 3196717cee CI yml syntax error 2020-05-28 23:18:02 -04:00
John Sully f95578ac02 Fix TLS tests in CI 2020-05-28 23:16:42 -04:00
John Sully 57ca6facc3 fix TLS test failure 2020-05-28 23:16:27 -04:00
John Sully 561a1f8d8a Test TLS as part of CI 2020-05-26 01:39:54 -04:00
John Sully 1449c8b9fe Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-05-26 01:29:08 -04:00
John Sully 1938af27f5 Fix client tracking, also ensure tracking tests are enabled 2020-05-26 01:28:52 -04:00
Maxime de Roucy 123bc125cf acl: @replication command group
containing mandatory commands for replication (used by masteruser user)
2020-05-25 02:35:22 -04:00
John Sully ecbe168b54 Fix issue #170. Intermittent crash destroying fastlock due to implicit type conversion in assert 2020-05-25 02:13:57 -04:00
John Sully 00cef78858 Fix infinite logs of Error in rreplay 2020-05-24 20:05:22 -04:00
John Sully d05da0fabd Enable TLS connections 2020-05-24 19:57:16 -04:00
John Sully 4db3f2a443 don't keep feeding data to clients pending close 2020-05-24 12:46:11 -04:00
John Sully fd710d590a Quiet TSAN during exit 2020-05-24 12:45:10 -04:00
John Sully 9b98c9edd3 Install deps for daily workflow 2020-05-24 11:19:53 -04:00
John Sully 4893eedacb Hold the AE lock until we process the repl backlog after a command 2020-05-24 11:19:23 -04:00
John Sully fb50163b47 Add standardized way to post client dependent functions 2020-05-24 02:46:39 -04:00
John Sully 3b8463f9d2 remove unnecessary cplusplus guard 2020-05-24 02:45:55 -04:00
John Sully 42c7677690 race in connection state when setting a handler on a different thread 2020-05-24 02:45:11 -04:00
John Sully 8665f25031 Fix ASAN races 2020-05-24 01:58:33 -04:00
John Sully 1c6b573147 Incorrect locking in replication error paths 2020-05-24 01:57:49 -04:00
John Sully 90162da1a6 Incorrect memory order on weak ordered architectures 2020-05-24 01:57:18 -04:00
John Sully 1ca6c1dd56 If we request shutdown from a client on a different thread than a blocking lua script we fail to actually shutdown until the script completes 2020-05-24 01:56:23 -04:00
John Sully 2d27c8ecdb race calculating client overhead 2020-05-24 01:53:43 -04:00
John Sully 59cda9cfb9 During RDB load we can only handle clients on the main thread as our workers are not yet created. This change also unifies the accept logic across the socket types 2020-05-23 16:03:24 -04:00
John Sully 091af64003 Diskless replication handler needs to run on the main thread 2020-05-23 15:15:42 -04:00
ShooterIT a12210c875 Fix reply bytes calculation error
Fix #7275.
2020-05-23 13:02:55 -04:00
John Sully 43649fc5b4 Merge tag '6.0.3' into unstable
Redis 6.0.3
2020-05-22 16:53:10 -04:00
John Sully 01cc25653a Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-05-22 16:45:27 -04:00
John Sully a010e4a4b2 Merge tag '6.0.2' into unstable
Redis 6.0.2
2020-05-22 16:45:18 -04:00
John Sully 817a11ff11 Merge commit 'cb683a84f7a9d530bec629f2b656e7d0842a0f75' into unstable 2020-05-22 15:56:35 -04:00
John Sully c52e1fc78c Merge commit '3a441c7d95c8757d2ab12ff730cc7ca8899538c9' into unstable 2020-05-22 15:42:50 -04:00
John Sully d74871da40 Merge commit 'c57d9146f41f4b661d9d2cb48b83b3abc757ba0e' into unstable 2020-05-22 15:36:44 -04:00
John Sully a25cf15ecd Update README.md 2020-05-22 14:03:29 -04:00
John Sully c505df8830 Merge tag '6.0.1' into unstable
Redis 6.0.1.
2020-05-21 23:41:36 -04:00
John Sully f214ada545 Missing noexcept 2020-05-21 23:25:50 -04:00
John Sully c10aa3b8b0 build failure on macos 2020-05-21 23:24:34 -04:00
John Sully 6311d709c3 Fix bad merge in CI.yml 2020-05-21 22:09:06 -04:00
John Sully 8ab77465db Merge commit 'bec68bff2978de88b23140f41b6a943162333b11' into unstable 2020-05-21 19:37:42 -04:00
John Sully 201bf73ef7 Merge commit '414debfd04d21c0b19d5f6bb5249398d83670f3d' into unstable 2020-05-21 18:57:28 -04:00
John Sully 49784c8122 Merge commit 'cbcd07777dc569618a34f59e5fd0de53178f4f1d' into unstable 2020-05-21 18:48:49 -04:00
John Sully 3e03f308b5 Merge commit '5719b3054a534e62c25ae97680ecd4f7238ba484' into unstable 2020-05-21 17:55:09 -04:00
John Sully 95cecb0229 Merge commit '026cc11b056f063631d990f1a9db45b4e583974e' into unstable 2020-05-21 17:45:15 -04:00
John Sully 7676f5b15f Merge commit '024c380b9da02bc4112822c0f5f9ac1388b4205b' into unstable 2020-05-21 17:36:53 -04:00
John Sully d5b057534a Merge commit 'eba28e2cea0b2632cf751426ada02adf24f273db' into unstable 2020-05-21 17:32:53 -04:00
John Sully 7a15f6dfc7 Merge commit 'c35a53169ffdbdf73f91224b6e62f6129fb9a838' into unstable 2020-05-21 17:30:56 -04:00
John Sully 712d825c23 Override missing new, fix new/delete mismatch 2020-05-20 15:57:08 -04:00
John Sully 4073758874 Remove debugging logs 2020-05-14 22:18:29 -04:00
John 3543a3c763 more reliability fixes for multimaster 2020-05-11 05:38:21 -04:00
John 3122912920 Make multimaster tests more reliable 2020-05-11 05:23:47 -04:00
John Sully f11fdf6717 Update access LFU/LRU access times when overwriting key 2020-05-11 00:42:46 -04:00
John Sully 572bcca9c2 We should still send replies even if an async close is pending 2020-05-10 23:56:29 -04:00
John Sully 10fa064109 Fix race on clients_to_close 2020-05-10 23:14:15 -04:00
John Sully 7cd779d304 Fix crash in client unblock command 2020-05-10 22:08:50 -04:00
John Sully 628d168049 Fix crash during hook module test 2020-05-10 21:57:16 -04:00
John Sully 37423757b5 Fix crash in module tests 2020-05-10 21:06:38 -04:00
John Sully 58752bb8fe Run sentinel and module tests under CI 2020-05-10 18:05:05 -04:00
John Sully 7e7f70ff3e add help for hrename 2020-05-10 17:41:01 -04:00
John Sully f77c227b2d hrename tests 2020-05-10 17:14:44 -04:00
John Sully 21d842b0b0 Implement keydb.hrename command 2020-05-10 17:04:22 -04:00
John Sully 86f9ed6248 Disable cluster tests
They are unreliable on slow hardware.
2020-05-07 01:49:04 -04:00
Diab Neiroukh dcd7b684bb Clang requires libatomic to be linked via LDFLAGS
Clang requires the libatomic to be linked via LDFLAGS or else the linker
will fail to recognise __atomic macros.

An error as a result of not passing -latomic to the linker can be seen
below:

ld.lld: error: undefined symbol: __atomic_fetch_add_2
>>> referenced by sds.c:185
>>>               lto.tmp:(sdsdupshared)
clang-10: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [Makefile:276: keydb-server] Error 1
2020-04-30 15:06:10 -04:00
John Sully f715d0b860 cluster tests should be a named task 2020-04-29 18:43:55 -04:00
John Sully 98d690b849 Run cluster tests as part of CI 2020-04-29 18:41:51 -04:00
John Sully 45535e8a63 use serverAssert() instead of assert() to get callstacks in fastlock 2020-04-28 22:41:07 -04:00
John Sully c78895aaea Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-04-28 22:24:45 -04:00
John Sully d5ede50b04 shared pointer comparisons with other pointers 2020-04-24 22:20:26 -04:00
John Sully fab6132cb3 EMBSTR size is lower than it needs to be 2020-04-24 22:19:55 -04:00
John Sully e0a8709c09 Default yes in apt install 2020-04-22 02:17:28 -04:00
John Sully 17795fd5ce Run arm CI builds 2020-04-22 02:13:02 -04:00
John Sully d6738ffa5d MacOS Build Break Fix 2020-04-22 01:21:35 -04:00
John Sully e72642667f Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-04-16 20:12:14 -04:00
John Sully 3785b1efd4 Fix some clang warnings 2020-04-16 20:12:05 -04:00
John Sully 7aeae62f84 Always link libatomic 2020-04-16 20:01:24 -04:00
John Sully e5e33f8cb7 Fix warning in cluster.cpp 2020-04-16 20:01:13 -04:00
John Sully a836d5947d quiet TSAN in serverLog 2020-04-16 17:06:25 -04:00
John Sully 7cdd5d9e41 Update Readme to use github CI badge 2020-04-15 23:21:10 -04:00
John Sully 3f5d3fec36 update TLS readme for KeyDB 2020-04-15 23:19:05 -04:00
John Sully 90094a2dca Deprecate travis and finish setting up github CI 2020-04-15 23:04:04 -04:00
John Sully cc9924ffa6 Merge branch 'unstable' into redis_6_merge 2020-04-15 23:00:13 -04:00
John Sully 5e6b4ab99e OS X build break 2020-04-15 22:43:40 -04:00
John Sully 2d6d374162 more dependencies for CI 2020-04-15 22:39:47 -04:00
John Sully 3137d4f35c Add CI dependency 2020-04-15 22:36:16 -04:00
John Sully 6ff9d23fd4 During AOF reload we can erroneously read incorrect aof_state values, so this variable must be read with the global lock acquired 2020-04-15 22:30:19 -04:00
John Sully d4939c838b Quiet test only ASAN fd race 2020-04-15 22:27:45 -04:00
John Sully cd306f1d23 Run all KeyDB instances in testmode during tests 2020-04-15 22:27:04 -04:00
John Sully 5fd07e0889 Fix race in sendBulk 2020-04-15 22:26:00 -04:00
John Sully b0796ff5fd Convert variables accessed outside lock to atomics 2020-04-15 22:25:17 -04:00
John Sully 9dfa074cd6 ASAN races in leak checker 2020-04-15 22:24:12 -04:00
John Sully 033761c5f9 Multithreading reliability, force single thread for test relying on internal behavior 2020-04-15 20:52:25 -04:00
John Sully 2926ac494e rename to KeyDB (merge) 2020-04-15 16:44:06 -04:00
John Sully 06143c2e8c Log stdout and stderr for cluster tests 2020-04-15 16:35:24 -04:00
John Sully f00d28fdab Fix TSAN race 2020-04-15 16:34:38 -04:00
John Sully 4705f29e2f Fix incorrect cluster slot tracking (regression from merge) 2020-04-15 16:34:07 -04:00
John Sully b2cb10de5f Merge tag '6.0-rc3' into redis_6_merge
Redis 6.0 RC3.
2020-04-14 22:56:19 -04:00
John Sully 1005a725d4 Fix merge issues and move timeout to C++ 2020-04-14 22:37:26 -04:00
John Sully 50768cd242 Merge commit 'c3b268a0bcded2d730790a772176483efb7c31fb' into redis_6_merge 2020-04-14 22:25:44 -04:00
John Sully cc3ebbe519 Merge commit '0f7dfc378ce5ab0524ac28b6142545bc41435386' into redis_6_merge 2020-04-14 22:19:29 -04:00
John Sully 8056e349e0 Merge commit '7c07841632500dfdff31f5a69e5bd140abea646c' into redis_6_merge 2020-04-14 21:26:51 -04:00
John Sully 0001f59c8d Merge commit 'b3e0305448422239ba3cb8d125681bccdb809cd3' into redis_6_merge 2020-04-14 21:16:38 -04:00
John Sully 2941792a85 Merge commit 'e628f94436f2ffb38dd6305f18956f309838a8d6' into redis_6_merge 2020-04-14 21:13:42 -04:00
John Sully 320bc3c032 Merge commit '76d57161d960f27ac92765118e3b80fef8847b8f' into redis_6_merge 2020-04-14 21:04:42 -04:00
John Sully 2825e51550 Merge commit 'e74e68c84f5eba8013769087c9a46cab811b8417' into redis_6_merge 2020-04-14 20:55:29 -04:00
John Sully cbdd47d056 Merge commit 'baaf869fc3e138cfcb4cfda09f09fd3c87c8f924' into redis_6_merge 2020-04-14 20:44:27 -04:00
John Sully 516c8c6e23 Merge commit 'be4bc1a5be26a7fde2fd05acd8187f5f0ed59f25' into redis_6_merge 2020-04-14 20:42:48 -04:00
John Sully ef1236b600 Merge commit '973297336fc05a601e17be70aba88e5dca6480ae' into redis_6_merge 2020-04-14 20:19:48 -04:00
John Sully 28cbed1d13 Merge commit '349aa24511253b3e323064b95cefb4414f31726c' into redis_6_merge 2020-04-14 20:09:53 -04:00
John Sully cde199a797 Merge commit 'df83892760d19b1b7e92d76e72daf4834ad2df6c' into redis_6_merge 2020-04-14 19:43:04 -04:00
John Sully 5589a0a69c Merge commit 'f42ce57d0f7eee6705fb0a81714cabe97a4f2c0a' into redis_6_merge 2020-04-14 19:22:44 -04:00
John Sully 09e8fb17cd Merge commit '51c1a9f8fbc12a9276489178242e498bb6ccbdba' into redis_6_merge 2020-04-14 18:44:42 -04:00
John Sully d71c4c2215 Merge commit '6fe55c2f299bbb306533af39cb28346bf5d473d3' into redis_6_merge 2020-04-14 18:30:26 -04:00
John Sully 6f621e6480 Merge commit '721a39ddff0eb9be822d27dba80267f6da149aff' into redis_6_merge 2020-04-14 18:29:03 -04:00
John Sully 8e33c2d301 Merge commit 'cbabf779c24fd107ca8e4fe6369e4677ad0eda10' into redis_6_merge 2020-04-14 18:05:10 -04:00
John Sully 52aca124c3 Merge commit 'ecd17e819cbb05110a49d81c6fda10e6770a7838' into redis_6_merge 2020-04-14 18:04:51 -04:00
antirez c7159d58f1 Jump to right label on AOF parsing error.
Related to #6054.
2020-04-14 18:03:22 -04:00
antirez 5d6e8fe3e3 PSYNC2: meaningful offset implemented.
A very commonly signaled operational problem with Redis master-replicas
sets is that, once the master becomes unavailable for some reason,
especially because of network problems, many times it wont be able to
perform a partial resynchronization with the new master, once it rejoins
the partition, for the following reason:

1. The master becomes isolated, however it keeps sending PINGs to the
replicas. Such PINGs will never be received since the link connection is
actually already severed.
2. On the other side, one of the replicas will turn into the new master,
setting its secondary replication ID offset to the one of the last
command received from the old master: this offset will not include the
PINGs sent by the master once the link was already disconnected.
3. When the master rejoins the partion and is turned into a replica, its
offset will be too advanced because of the PINGs, so a PSYNC will fail,
and a full synchronization will be required.

Related to issue #7002 and other discussion we had in the past around
this problem.
2020-04-14 17:56:09 -04:00
Oran Agra 99762dac23 reduce repeated calls to use_diskless_load
this function possibly iterates on the module list
2020-04-14 17:34:36 -04:00
John Sully 57956b3fd2 Fix merge conflicts from cherry-pick 2020-04-14 17:33:54 -04:00
antirez b323645227 Remove RDB files used for replication in persistence-less instances. 2020-04-14 17:27:05 -04:00
Johannes Truschnigg dd9502f373 Signal systemd readiness atfer Partial Resync
"Partial Resynchronization" is a special variant of replication success
that we have to tell systemd about if it is managing redis-server via a
Type=Notify service unit.
2020-04-14 17:22:30 -04:00
Guy Benoish aa8a3077a2 Diskless-load emptyDb-related fixes
1. Call emptyDb even in case of diskless-load: We want modules
   to get the same FLUSHDB event as disk-based replication.
2. Do not fire any module events when flushing the backups array.
3. Delete redundant call to signalFlushedDb (Called from emptyDb).
2020-04-14 17:21:10 -04:00
John Sully 8e81e5f29e Cache fake client in replicaFeedSlaves 2020-04-13 22:45:15 -04:00
John Sully 63dd1fb599 Don't do active replica work if we're not an active replica 2020-04-13 22:35:06 -04:00
John Sully 32561a9912 Optimize replicaFeedSlaves by removing use of snprintf 2020-04-13 22:11:34 -04:00
John Sully 3fdc8608f3 Fix failure to AUTH with master when masterauth is set last 2020-04-06 01:24:59 -04:00
John Sully 9e2e2067c6 Add the ability to set a starting core # when setting thread affinity 2020-04-04 22:58:17 -04:00
John Sully f112c77fcc Fix issue #164 2020-04-04 22:45:12 -04:00
John Sully 888d69a87a Role command protocol corruption with multiple masters 2020-04-04 22:32:15 -04:00
John Sully bd183cdee1 Fix subkey expires not replicating correctly, and AOF issues 2020-04-04 21:52:27 -04:00
John Sully 95b4f899c5 Merge branch 'redis_6_merge' of https://github.com/JohnSully/KeyDB into redis_6_merge 2020-03-30 00:52:43 -04:00
John Sully 2946155313 Merge branch 'unstable' into redis_6_merge 2020-03-30 00:52:12 -04:00
John Sully f2ca2aa1f7 Allow active replicas to connect to each other when replica-serve-stale-data is set 2020-03-30 00:51:40 -04:00
John Sully b20bf10fda Don't send build log to stderr 2020-03-28 23:36:57 -04:00
John Sully 208c15bc16 Merge branch 'unstable' into redis_6_merge 2020-03-27 14:50:37 -04:00
John Sully c3d3c82f3a Raspberry Pi fixes (compile and replication) 2020-03-27 12:46:25 -04:00
John Sully b22d9cc27d Fix merge issues 2020-03-25 22:26:27 -04:00
John Sully 908cf5042e Merge branch 'unstable' into redis_6_merge 2020-03-25 22:12:22 -04:00
John Sully 6ec1641294 Fix issue #143 2020-03-25 21:55:31 -04:00
John Sully 7b79ec360b Give a better error when handling std::terminate 2020-03-25 16:27:24 -04:00
John Sully 718aee242d Merge branch 'unstable' into redis_6_merge 2020-03-25 15:47:12 -04:00
John Sully 56fc6b7deb Add roundtrip test for subkey expires 2020-03-25 15:34:30 -04:00
John Sully 528a43bd6c Fix failure to load subkey expires 2020-03-25 01:38:58 -04:00
John Sully b357803362 Expire entry needs to be resorted after a subkey expires 2020-03-25 01:06:40 -04:00
John Sully 448808529a Unstable branch should always be version 0.0.0 2020-03-19 15:52:24 -04:00
John Sully a0bc208412 Merge branch 'RELEASE_5' into unstable 2020-03-19 15:38:16 -04:00
John Sully 6b0172b9bf Print stack traces of other threads in the deadlock detector 2020-03-19 15:37:49 -04:00
John Sully bc1eccb66d Log which thread a message came from 2020-03-19 15:37:24 -04:00
John Sully a9249d4a82 Fix lock inversion in processEventsWhileBlocked 2020-03-19 15:28:39 -04:00
John Sully 3c373494d6 Prevent dangling lock when we can't free the client 2020-03-19 14:34:23 -04:00
John Sully 40761e4031 Merge branch 'unstable' into redis_6_merge 2020-03-17 00:09:48 -04:00
John Sully 5aef606d3b Fix issue #153: Config get replicaof returns a corrupt response 2020-03-16 20:43:46 -04:00
John Sully 4671cd6002 Merge branch 'unstable' into redis_6_merge 2020-03-15 18:47:27 -04:00
John Sully 2ec0b2cd20 Handle HTTP error codes with MOTD 2020-03-15 18:47:01 -04:00
John Sully 07effa3925 Merge branch 'unstable' into redis_6_merge 2020-03-15 18:33:24 -04:00
John Sully cd76a71de3 Update MOTD URL 2020-03-15 18:32:05 -04:00
John Sully 5e63c0955d Fix CLANG build break 2020-03-04 17:24:17 -05:00
John Sully e523afa741 Fix CLANG build break 2020-03-04 17:24:00 -05:00
John Sully c2a98a60f9 Fix CLANG build break 2020-03-04 17:23:40 -05:00
John Sully 6bc92d6d31 Merge branch 'unstable' into redis_6_merge 2020-03-04 17:13:50 -05:00
John Sully 13cf8bbeb7 Merge branch 'unstable' into RELEASE_5 2020-03-04 17:13:32 -05:00
John Sully 60c0d4104d Add missing files from last checkin 2020-03-04 17:13:18 -05:00
John Sully 52fd4445a4 Merge branch 'unstable' into redis_6_merge 2020-03-04 17:13:01 -05:00
John Sully 693ba4ed4a Merge branch 'unstable' into RELEASE_5 2020-03-04 17:09:29 -05:00
John Sully 5397f0b033 Add extra logging when reporting errors from masters - especially in rreplay 2020-03-04 17:09:12 -05:00
John Sully 6c78ec7c41 MOTD refactor 2020-03-04 16:22:55 -05:00
John Sully fed4bd5269 min-clients-per-thread needs to use the new config code 2020-03-04 15:14:41 -05:00
John Sully c0882864f2 Update README.md 2020-03-03 13:58:48 -08:00
John Sully 1a7e2e663e Merge branch 'unstable' into redis_6_merge 2020-03-01 21:48:51 -05:00
John Sully faa87ed839 Merge branch 'unstable' into RELEASE_5 2020-03-01 21:43:21 -05:00
John Sully 83f585e30a Update tests to reflect new CRON name (keydb.cron) 2020-03-01 21:42:01 -05:00
benschermel 7a244bb847 Merge branch 'unstable' into RELEASE_5 2020-03-01 19:53:32 -05:00
John Sully 1b925119b5 Rename cron command to KEYDB.CRON and add help 2020-03-01 19:18:21 -05:00
John Sully 3eb847e28f Rename cron command to KEYDB.CRON and add help 2020-03-01 19:17:58 -05:00
John Sully 9dc8f30e47 Merge branch 'unstable' into redis_6_merge 2020-02-28 23:56:26 -05:00
John Sully 3ce6441a0c Bump version 2020-02-28 23:53:54 -05:00
John Sully 6d00a1a5cf Merge branch 'unstable' into RELEASE_5 2020-02-28 23:53:00 -05:00
John Sully aaca32a5cd Fix compile failure on raspberry pi machines, issue #141 2020-02-28 23:49:17 -05:00
John Sully 54c96d1995 Fix not respecting max clients config, issue #147 2020-02-28 22:04:42 -05:00
John Sully e5a2d59446 Fix issue #146 2020-02-28 21:21:05 -05:00
John Sully d95bead383 Fix crash propogating stale keys 2020-02-26 21:49:40 -05:00
John Sully 51ea3cf30c Change Redis to KeyDB 2020-02-17 23:46:01 -05:00
John Sully 6ad6c1d780 Change Redis to KeyDB 2020-02-17 23:45:40 -05:00
John Sully 32f34f63fd Merge branch 'unstable' into redis_6_merge 2020-02-17 19:55:29 -05:00
John Sully 98aefac09b Add double unlock detection and improve fastlock_unlock assmebly 2020-02-17 19:54:05 -05:00
John Sully 5dc84850ad Incorrect use of std::atomic 2020-02-17 19:07:13 -05:00
John Sully 45b711f9d1 processEventsWhileBlocked not exception safe 2020-02-17 19:04:11 -05:00
John Sully 1ef187533c processEventsWhileBlocked not exception safe 2020-02-17 19:03:49 -05:00
John Sully 6a71de7835 Merge branch 'unstable' into redis_6_merge 2020-02-16 19:14:51 -05:00
John Sully 18496b6285 Support C++14 and remove dependency on future standard 2a 2020-02-16 19:04:56 -05:00
John Sully b9db899f6c Graceful shutdown of server threads when quit is requested 2020-02-16 18:53:46 -05:00
John Sully 4e9d2f08b1 Fix memory leak in RDB load 2020-02-16 18:42:14 -05:00
John Sully 06ad1c15d7 Fix memory leak in RDB load 2020-02-16 18:41:50 -05:00
John Sully 30a603ce05 Merge branch 'unstable' into redis_6_merge 2020-02-16 18:18:24 -05:00
John Sully 63ae679fe1 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-02-16 18:12:11 -05:00
John Sully b92bbf4de8 Memory leak fix on config, and redisDb dtor 2020-02-16 17:08:00 -05:00
John Sully 4781eda722 Fix memory leak of ReplicaNestState on shutdown 2020-02-16 03:43:29 -05:00
John Sully 2fd93c5789 aeDeleteEventLoop use after free and leak fixes 2020-02-16 03:34:25 -05:00
John Sully 329519d4aa Merge branch 'unstable' into redis_6_merge 2020-02-11 03:48:08 -05:00
John Sully 52434a583a Fix race condition in allocating connections to threads 2020-02-11 03:44:28 -05:00
John Sully 18a5f46b61 Merge branch 'unstable' into redis_6_merge 2020-02-11 02:39:08 -05:00
John Sully 16a019dba0 Implement an error handler so bug #125 can't happen 2020-02-11 01:41:00 -05:00
John Sully 1a4c3224c9 Fix higher latency at low load by grouping clients to threads. This fixes slow perf in cluster benchmarks mentioned in issue #102 2020-02-11 01:00:21 -05:00
John Sully c3317686f8 Fix cases where duplicate RREPLAY is applied 2020-02-11 00:59:07 -05:00
John Sully 4622472123 Fix issue #119 2020-02-10 19:52:57 -05:00
John Sully f1748f8c76 Fix memory leak in cron 2020-02-10 18:26:04 -05:00
John Sully 0c101dccc8 Add missing test file 2020-02-10 18:15:29 -05:00
John Sully dc78bf1ccb CLANG build fix 2020-02-10 00:29:26 -05:00
John Sully a7cc3aac28 Ensure multi-master works for ring topologies 2020-02-10 00:25:03 -05:00
John Sully 339631530a Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-02-09 02:25:20 -05:00
John Sully fb2bdf7d05 Addmissing test file 2020-02-08 16:49:41 -05:00
John Sully c45f1328ac merge 5.0 unstable 2020-02-07 16:45:59 -05:00
John Sully 050d58007f Fix issue #137 and #132 2020-02-06 23:31:31 -05:00
John Sully 49d86746ed Add test to detect issue #137 and #132 2020-02-06 23:31:12 -05:00
John Sully ef4e11ecb8 module fixes 2020-02-04 01:22:25 -05:00
John Sully fd702e43f1 Fix cluster test failures from Redis 6 merge 2020-02-03 20:00:09 -05:00
John Sully 249e0fdd36 addRef memory model too restrictive 2020-02-01 21:52:17 -05:00
John Sully 6208118b13 RDB memory leaks 2020-01-30 17:57:10 -05:00
John Sully 73020b6a93 replication memory leaks 2020-01-30 17:56:24 -05:00
John Sully a9667e84ad Fix memory leak in cron 2020-01-30 17:55:48 -05:00
John Sully ab1524ff1a Merge branch 'redis_merge' into unstable 2020-01-30 16:05:40 -05:00
John Sully 1069d0b4bf CRON jobs were running half as often as required 2020-01-28 21:40:40 -05:00
John Sully 4a980f4ddb More threading fixes from merge 2020-01-28 17:54:00 -05:00
John Sully 9fbb9a551e reenable multithreading after merge 2020-01-27 19:59:04 -05:00
John Sully c24a7c03c2 cron reliability 2020-01-27 18:31:02 -05:00
John Sully 5a8280d577 fix expire test failures during overwrite 2020-01-27 18:26:23 -05:00
John Sully da83e84125 Fix most tests (still some failures) 2020-01-27 18:16:19 -05:00
John Sully ef9a3cadcf Merge remote-tracking branch 'redis/6.0' into redis_merge 2020-01-27 02:55:48 -05:00
John Sully c983d57f73 Missing cron files 2020-01-21 19:51:16 -05:00
John Sully 3204a39ada Initial implementation of the CRON command 2020-01-21 19:50:28 -05:00
John Sully f4319c1280 Bump version 2020-01-20 19:20:50 -05:00
John Sully 762396d997 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-01-11 16:35:06 -05:00
John Sully c575e7df94 Avoid crash due to excessive posted functions for AOF rewrite 2020-01-11 16:34:30 -05:00
John Sully aa6409f2e8 Avoid crash due to excessive posted functions for AOF rewrite 2020-01-11 16:34:09 -05:00
John Sully e603e57588 Merge branch 'unstable' into RELEASE_5 2020-01-10 17:46:23 -05:00
John Sully 049b48ef79 Ignore other flags after pro is enabled since we won't understand them 2020-01-10 17:46:02 -05:00
John Sully 0ba0a6ab0a Update README.md 2020-01-10 14:21:11 -05:00
John Sully 7475ea1b0b Update graphs 2020-01-10 14:19:44 -05:00
John Sully d0654af74f Merge branch 'unstable' into RELEASE_5 2020-01-06 14:24:49 -05:00
John Sully d5f8df5997 pro launch should respect KEYDB_PRO_DIRECTORY 2020-01-06 14:24:37 -05:00
John Sully 39acb312ef Bump version 2020-01-06 12:07:57 -05:00
John Sully b643c38204 Merge branch 'unstable' into RELEASE_5 2020-01-06 12:07:11 -05:00
John Sully dd70f5efd7 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2020-01-06 12:04:00 -05:00
John Sully bb38628f0e Add new flags to example configuration file 2020-01-05 20:19:28 -05:00
John Sully 0cf3af6857 subkey expire testes 2020-01-03 16:50:13 -05:00
John Sully edb993d52b Drop severity of master disconnect log when multimaster is enabled 2020-01-02 15:36:02 -05:00
John Sully aea333bb78 Fix issue where expire is lost when performing a defrag 2020-01-01 20:41:17 -05:00
John Sully 45817db8c3 C++ wrapper classes for SDS 2020-01-01 19:13:48 -05:00
John Sully dbef17c2e1 Fix issue #130 due to fastlock timeout reduction 2020-01-01 11:52:00 -05:00
John Sully 42a8f22c21 Fix some static analysis warnings 2019-12-27 18:17:22 -05:00
John Sully 6e06e0dfc7 Ignore dependency files 2019-12-27 17:45:56 -05:00
John Sully bf500ab44b Make incremental building work with header files 2019-12-27 17:34:41 -05:00
John Sully 4d4eca5433 Multimaster requires Active Replication 2019-12-21 18:24:02 -05:00
Petr Vaněk 4b01ad1e30 Rename redis.conf to keydb.conf 2019-12-21 15:00:24 -05:00
Petr Vaněk 3b60929bdc Rename default pid file 2019-12-21 15:00:24 -05:00
John Sully a45d141597 Implement subkey expires for sorted sets 2019-12-18 00:10:05 -05:00
John Sully 8cbe254491 Implement subkey expire for hashes 2019-12-18 00:04:48 -05:00
John Sully ab365ce3da Launch the pro binary with --enable-pro 2019-12-17 23:52:19 -05:00
John Sully aa3e70f9a0 Fix type in makefile 2019-12-17 18:23:19 -05:00
John Sully cda8d42a76 Enusre CXXFLAGS has the same settings as CFLAGS 2019-12-17 17:49:51 -05:00
Petr Vaněk 67f32bf1b1 Correct C++ related makefile variables
FINAL_CXXFLAGS should not inherit CFLAGS because they can contain C
specific options unsupported by C++.

REDIS_CXX should point to the C++ compiler rather than C.
2019-12-17 17:43:15 -05:00
Petr Vaněk 7a3f363f34 readme: fix typo 2019-12-16 15:40:09 -05:00
Tais P. Hansen 91eac2cdb3 Fix keydb-cli crashing on read-only filesystem 2019-12-09 14:23:10 -05:00
John Sully 98a928147f Fix Issue #107 2019-12-01 18:17:33 -05:00
John Sully 8a9045c028 Fix deadlock in spinlock (mfence) also spin for less time before sleeping 2019-11-30 00:51:58 -05:00
John Sully 6c65a11b8d Fastlock should yield in ARM 2019-11-28 14:26:43 -05:00
John Sully 7dd53182e0 Bump version 2019-11-21 20:16:42 -05:00
John Sully 53b95d830a Merge branch 'unstable' into RELEASE_5 2019-11-21 20:16:23 -05:00
John Sully 3028a890ef Fix issue #83 2019-11-21 20:05:16 -05:00
John Sully 39c6fbddb1 Add missing dependency to dockerfile 2019-11-20 20:35:14 -05:00
John Sully 704cb4e929 Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2019-11-20 19:44:43 -05:00
John Sully 8e4f323439 Fix issue #107, active replicas do their own expires 2019-11-20 19:44:31 -05:00
John Sully 937702ea1d Additional asserts ensuring the client is creating on the correct thread 2019-11-20 17:00:40 -05:00
John Sully 3ea56ffb38 Update issue templates 2019-11-20 16:25:33 -05:00
John Sully becd3fc5a3 Update issue templates 2019-11-20 16:24:23 -05:00
John Sully 4c8603815c Fix failure to wakeup from futex sleep due to fastlock_unlock reading the wrong offset in the asm version. Also fix false sharing in spinlock 2019-11-17 16:06:49 -05:00
John Sully 3ae75c2d2b Revert "Debug sleep should apply to all threads"
This reverts commit 41b678814b.
2019-11-17 15:39:47 -05:00
John Sully 9371c005aa Improve perf of reading cluster bitfield 2019-11-17 14:52:12 -05:00
John Sully 16bd6b3f5d Merge branch 'unstable' of https://github.com/JohnSully/KeyDB into unstable 2019-11-14 21:21:46 -05:00
John Sully 3dd78a6101 Cluster multithreading fixes 2019-11-14 20:14:24 -05:00
John Sully 41b678814b Debug sleep should apply to all threads 2019-11-14 19:57:29 -05:00
John Sully d0ccb074d5 killing clients should take effect ASAP 2019-11-14 19:49:32 -05:00
John Sully cb0fc7cca2 Improve AE Assert message 2019-11-14 19:34:13 -05:00
John Sully 5e40ea6ee7 Fix test failure with tcl8.5 (test only issue) 2019-11-04 17:31:29 -08:00
John Sully 427c5999f1 Fix potential race in pubsub 2019-10-25 02:50:30 -04:00
John Sully a91f58b8fd Fix potential race in pubsub 2019-10-25 02:44:14 -04:00
John Sully 3013799664 bump version 2019-10-25 01:00:28 -04:00
John Sully f8220a658e Merge branch 'unstable' into RELEASE_5 2019-10-24 23:39:18 -04:00
John Sully f1d2b29450 Signals can happen on any thread, so look for the signal handler not the command on the callstack 2019-10-24 23:30:08 -04:00
John Sully cb93752aff Two fixes: 1) Remove race conditions by not locking clients when async writing. 2) Don't derefence dangling pointers in lambda 2019-10-24 23:07:02 -04:00
John Sully 549cad378d Sanitizers work with GCC too 2019-10-24 23:05:39 -04:00
John Sully 631f863dd8 Remove the DB lock, its unnecessary 2019-10-24 20:18:48 -04:00
John Sully 4396682c07 Remove unlocked KEYS command support, we will do this with snapshotting 2019-10-24 20:18:11 -04:00
John Sully ca4ee4e3e4 Build break, ensure C99 compatibility 2019-10-23 13:38:07 -04:00
John Sully 2da09e0732 Fix build break in TravisCI 2019-10-23 13:31:39 -04:00
John Sully 4986dc6da9 If a replica is about to be closed, don't wait on its lock (potential deadlock) 2019-10-23 13:20:23 -04:00
John Sully 1a70af2ae1 processEventsWhileBlocked needs to release the lock in a safe way 2019-10-23 13:19:57 -04:00
John Sully 5a8cb77d0d Remove race conditions 2019-10-22 23:26:37 -04:00
John Sully 600fc241cf Optimize deadlock detection, fix callstack for ASM, and annotate locks
Note: This change moves our assembly code to use the GNU Assembler because NASM seems to be incapable of emitting the necessary debug information for callstack unwinding to work.
2019-10-22 21:34:51 -04:00
John Sully fa797408d9 Implement deadlock detection 2019-10-22 00:43:32 -04:00
John Sully 3fac516950 Disable multithreaded KEYS due to bugs 2019-10-21 12:21:46 -04:00
John Sully 2f65aa2337 Merge branch 'unstable' into RELEASE_5 2019-10-16 12:47:06 -04:00
john@csquare.ca f5210a8fb0 Fix: ExpireMember does not update MVCC timestamp 2019-10-16 12:38:15 -04:00
John Sully 8f1295c00f expiremember should return the same results as expire 2019-10-16 12:27:04 -04:00
John Sully 18a3768e07 Fix crash adding expire to key with a subkey expire already set 2019-10-16 12:26:48 -04:00
eric-weaver 95e3dbc104 add missing dependency 2019-10-13 21:30:06 +02:00
Segmond 40355eac3e Update README.md
Typo, focuses spelled as focusses
2019-10-13 21:29:15 +02:00
John Sully 3a3b59a054 Implement the lastmodified query for the OBJECT command 2019-10-13 14:12:09 -04:00
John Sully 12e17cfd6e You are not allowed to set a subkey expire if the subkey does not exist 2019-10-13 14:11:43 -04:00
John Sully 203e341bf4 Implement the EXPIREMEMBERAT command 2019-10-13 13:15:13 -04:00
John Sully 6e6cd84ad7 Add millisecond support for EXPIREMEMBER command 2019-10-13 12:57:50 -04:00
John Sully 252725d50f Update more slave instances to use replica (Issue #75) 2019-10-13 12:29:20 -04:00
John Sully c15633ea9e Update a few uses of slave to use the new replica terminology (Issue #75) 2019-10-13 12:12:05 -04:00
John Sully 27c9ae667e Fix an intermittent crash when replicationCron happens before slavesdb is update 2019-10-13 12:04:54 -04:00
John Sully 16f96efbe7 Implement TTL and PERSIST commands for subkeys. Also ensure expiremember replaces any old subkey expiries 2019-10-13 12:03:25 -04:00
John Sully 5787e7adc7 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-10-13 10:03:01 -04:00
John Sully 4631119179 Fix issue #88 - don't let seperate KeyDB processes listen on the same port 2019-10-13 10:02:21 -04:00
John Sully 0a0c2146c8 Bump version 2019-10-01 17:53:48 -04:00
Edgard Lorraine Messias cedea7e400 Fixed "Provides" name in chkconfig info 2019-10-01 13:44:58 -04:00
John Sully 66cef6646c Merge branch 'unstable' into RELEASE_5 2019-09-30 00:28:12 -04:00
John Sully 64aa4b80e6 Expire DEL command place holder 2019-09-30 00:01:23 -04:00
John Sully 551a3cb1aa Fuzz mode is now an argument not based on the exe name 2019-09-30 00:00:29 -04:00
John Sully 0942188b0a finish up the RDB fuzz 2019-09-28 17:38:46 -04:00
John Sully 070c481871 Fix double free in RDB load 2019-09-28 17:38:26 -04:00
John Sully 6df4d29422 RDB fuzz test cases 2019-09-28 17:04:08 -04:00
John Sully 6e1e5bd08b RREPLAY command now takes a DB argument 2019-09-28 14:59:44 -04:00
John Sully ba365298ed Implement left and right shift BITOP operators 2019-09-28 00:10:46 -04:00
John Sully e1c9620951 Fix leaking stale RDBs during multimaster sync 2019-09-27 13:17:29 -04:00
John Sully e776474f68 Fix multi master bugs: 1. we fail to create the temp file. 2. We use a master RDB as our backup even though we merged databases (and therefore it is not representitive) 2019-09-26 20:35:51 -04:00
John Sully 4589e861ab Fix issue where AOF events are posted to the wrong event loop and not properly cleaned up 2019-09-19 15:40:09 -04:00
John Sully 55324aa56a Fix issue where AOF events are posted to the wrong event loop and not properly cleaned up 2019-09-19 15:39:52 -04:00
John Sully 18d42a5c35 KEYS now only blocks one database 2019-09-12 18:51:10 -04:00
John Sully 71d5a10621 bump version 2019-09-06 13:31:40 -04:00
John Sully ac595ebe37 Fix issue where Active Replicas were commiting data to the wrong database under load 2019-09-06 13:30:28 -04:00
John Sully 50a6a3ca38 Fix issue where Active Replicas were commiting data to the wrong database under load 2019-09-06 13:30:15 -04:00
John Sully f83a89f82a Acquire the lock for modules that don't acquire it before calling like they are supposed to 2019-08-29 15:41:03 -04:00
John Sully bf905a78f0 Bump version 2019-08-27 15:32:24 -04:00
John Sully fad9483fc9 Fix race condition in PUB/SUB and other async reply commands where the client can be freed before our handler is executed on the client thread. When this occurs the client pointer is dangling 2019-08-27 15:31:47 -04:00
John Sully 46a78c69e7 Fix race condition in PUB/SUB and other async reply commands where the client can be freed before our handler is executed on the client thread. When this occurs the client pointer is dangling 2019-08-26 20:18:52 -04:00
John Sully 33e0b3e1c0 Fix warnings on newer compilers 2019-08-14 01:03:24 -04:00
benschermel 4e9bfcf84b update readme (#71)
* update readme

* KeyDB must acknowledge its Redis origin and that while we have different opinions we are greatful to Antirez and Redis for the work they've done in this space.

* Update README.md
2019-08-06 19:25:13 -04:00
John Sully 75c6b4c64a Optimize the new expire code 2019-08-02 21:31:05 -04:00
John Sully 8536854266 Fix test failures: Non active replicas are allowed to use shared int values 2019-07-30 17:11:15 -04:00
John Sully 6016dd0f8b Acquire the lock for modules that don't acquire it before calling like they are supposed to 2019-07-30 16:54:25 -04:00
John Sully 47ef9e5cbd Fix HLL corruption 2019-07-29 18:08:45 -04:00
John Sully 4858fd893c Fix crash setting expire on a key with an existing subkey expiration 2019-07-29 17:09:51 -04:00
John Sully 6b6e6f6c1e Fix crash in RediSearch 2019-07-29 15:08:57 -04:00
John Sully cbe5c04a0f Fix crash in RediSearch 2019-07-29 15:08:41 -04:00
John Sully b0a0f03b96 RREPLAY failures should be logged 2019-07-24 22:49:55 -04:00
John Sully 08b6a04055 RREPLAY failures should be logged 2019-07-24 22:49:30 -04:00
John Sully f1982ca63d Issue #64 RREPLAY isn't binary safe. Add fix and test. 2019-07-24 22:31:44 -04:00
John Sully afe66288fe Issue #64 RREPLAY isn't binary safe. Add fix and test. 2019-07-24 22:31:02 -04:00
John Sully 2794cfced4 We can't set FExpire() on shared objects, issue #66 2019-07-23 23:39:47 -04:00
John Sully d6b45a56e7 Merge pull request #65 from JohnSully/subexpire
EXPIREMEMBER Command Implementation
2019-07-23 19:06:57 -04:00
John Sully a55d980436 Subexpire entries should load/save 2019-07-23 18:53:59 -04:00
John Sully 6037d1f326 Fix buggy rebase 2019-07-23 18:53:59 -04:00
John Sully 0b43b51a2e Fix merge conflict 2019-07-23 18:53:59 -04:00
John Sully 184abac694 Plumb support for sub expires to all expire related code 2019-07-23 18:53:59 -04:00
John Sully 0ba5b2c3d6 Fix crash with traditional expiration 2019-07-23 18:53:58 -04:00
John Sully 0b3d74ea67 Initial prototype of EXPIREMEMBER command 2019-07-23 18:53:58 -04:00
John Sully ea3bd614b8 New expire datastructure and algorithm. Allows us to expire in sublinear time 2019-07-23 18:49:31 -04:00
John Sully d45edc493d Merge pull request #50 from JohnSully/expire
New Expire Datastructure which is faster and more memory efficient.  This allows us to process expiries in sublinear time.
2019-07-23 18:40:48 -04:00
John Sully 271df3dad4 Support TTL stats with the new expire datastructure 2019-07-23 18:30:10 -04:00
John Sully 5a193872f8 Implement hash table stats and fixup the hash function based on the results 2019-07-23 18:30:10 -04:00
John Sully b5512d77a1 Add back missing file lost in rebase 2019-07-23 18:30:10 -04:00
John Sully 42bda8eaba Add back file erroniously deleted in rebase 2019-07-23 18:30:10 -04:00
John Sully 7e5d3f4f16 never make last minute changes before commiting 2019-07-23 18:30:10 -04:00
John Sully 5f3920e491 Fix a few potential assert crashes 2019-07-23 18:30:10 -04:00
John Sully 3880d2616c New expire datastructure and algorithm. Allows us to expire in sublinear time 2019-07-23 18:30:10 -04:00
John Sully 156e596f9c Any +x bit is acceptable 2019-07-19 15:26:17 -04:00
John Sully fc58516cca Any +x bit is acceptable 2019-07-19 01:42:05 -04:00
John Sully a4efcd35af Modules must have execute permissions to load 2019-07-19 01:31:10 -04:00
antirez 27fe1658a2 RDB: make sure to abort on LZF encoding error. 2019-07-19 01:03:16 -04:00
antirez 47feb2719c RDB: handle encoding errors with rdbExitReportCorruptRDB().
Without such change, the diskless replicas, when loading RDB files from
the socket will not abort when a broken RDB file gets loaded. This is
potentially unsafe, because right now Redis is not able to guarantee
that encoding errors are safe from the POV of memory corruptions (for
instance the LZF library may not be safe against untrusted data?) so
better to abort when the RDB file we are going to load is corrupted.

Instead I/O errors are still returned to the caller without aborting,
so that in case of short read the diskless replica can try again.
2019-07-19 01:02:49 -04:00
John Sully c21af6b351 Fix bad merge in SCAN KEYS command 2019-07-19 00:43:23 -04:00
John Sully 821c12c482 Merge commit '722446510faf0debf0d309708b2ed4fe4d939319' into unstable 2019-07-19 00:32:43 -04:00
John Sully 4602f8c391 Merge commit '677e95e2f5ee903682ce44a7bfd9558a22577926' into unstable 2019-07-19 00:01:56 -04:00
John Sully 27a927fe00 Fix compile errors from merges 2019-07-18 23:35:51 -04:00
Angus Pearson 3cdc6e8d84 Add char* typeNameCanonicalize(robj*) to remove duplicate code between SCAN and TYPE commands,
and to keep OBJ_* enum to string canonicalization in one place.
2019-07-18 23:31:31 -04:00
John Sully 89b52da387 Merge commit '0cabe0cfa7290d9b14596ec38e0d0a22df65d1df' into unstable 2019-07-18 23:28:56 -04:00
Madelyn Olson 50ad880ad5 Fixed some spelling issues in ACL codepath including user facing error 2019-07-18 23:28:36 -04:00
John Sully 15bed4bbcc Merge commit 'de035c94816722dd923e4aedd852869de79a5185' into unstable 2019-07-18 23:26:46 -04:00
John Sully 10986ae3a8 Merge commit 'bf963253ecfd367b49081a26c1b5c410558aecfc' into unstable 2019-07-18 23:22:36 -04:00
John Sully 2baa76b2ee Merge commit '7fababd44e8b8b2df53cad0906ec5ab7c678dd44' into unstable 2019-07-18 23:21:13 -04:00
John Sully ee460301fd Merge commit '074d24df1e82b5c794a5da9fb6cda5b77b60b27b' into unstable 2019-07-18 23:20:46 -04:00
John Sully 8ebe2fce3d Merge commit 'caf74e507e6535dab58ce6f3db19f8b594b5f7ca' into unstable 2019-07-18 23:18:42 -04:00
antirez 8198a697fd Test: fix slowlog test false positive.
In fast systems "SLOWLOG RESET" is fast enough to don't be logged even
when the time limit is "1" sometimes. Leading to false positives such
as:

[err]: SLOWLOG - can be disabled in tests/unit/slowlog.tcl
Expected '1' to be equal to '0'
2019-07-18 23:12:52 -04:00
antirez 35acae360a Make comment in getClientOutputBufferMemoryUsage() describing the present. 2019-07-18 23:12:39 -04:00
antirez 8aaa8b0b11 Fix test false positive introduced by threaded I/O.
Now clients that are ready to be terminated asynchronously are processed
more often in beforeSleep() instead of being processed in serverCron().
This means that the test will not be able to catch the moment the client
was terminated, also note that the 'omem' figure now changes in big
steps, because of the new client output buffers layout.

So we have to change the test range in order to accomodate for that.
Yet the test is useful enough to be worth taking, even if its precision
is reduced by this commit. Probably if we get more problems, a thing
that makes sense is just to check that the limit is < 200k. That's more
than enough actually.
2019-07-18 23:12:05 -04:00
John Sully 25e18a7de9 Release version 5 2019-07-18 20:50:40 -04:00
John Sully bb090b6d20 Active Replicas should always use their own slaveseldb variable when sending/saving rdbs - never those of their masters. This is because the Active Replica is also simultaneously a master 2019-07-18 20:50:20 -04:00
John Sully a9c4e3970f remove unnecessary variables 2019-07-18 19:37:49 -04:00
John Sully d5ecc2347a Fix issue #59 - Test replicaof config variable 2019-07-18 19:22:49 -04:00
John Sully 58971a430d Add support for sanitizers and fix issues they have found 2019-07-18 18:39:42 -04:00
John Sully 1512274f4c Resolve race on neterr variable 2019-07-18 17:11:28 -04:00
John Sully e310d33c12 Make object refcounts atomic, technically it doesn't need to be currently but the semantics are complicated and error prone. This is much safer with little performance impact 2019-07-18 15:49:12 -04:00
John Sully ad32ba0343 Suppress initialized data sanitizer warnings 2019-07-18 15:49:03 -04:00
John Sully 4e30a5b4e5 Another RESP3 regression 2019-07-17 22:57:52 -04:00
John Sully c8516f3dc4 Fix Issue #58 2019-07-17 02:34:02 -04:00
John Sully aae0fdc114 Shared objects should be marked as such 2019-07-16 18:32:01 -04:00
John Sully a19d0f67b9 Crash when aborting SYNC with a master on a thread other than main 2019-07-15 14:55:41 -04:00
John Sully 971f69fe1f Implement test mode to make finding bugs easier 2019-07-15 14:55:18 -04:00
John Sully 7468c691ad Blocked clients can stall when under low load 2019-07-13 16:44:11 -04:00
John Sully 620c2ec141 Give the active-rep more time to sync for test reliability 2019-07-12 23:52:07 -04:00
John Sully 3081b6f98b Fix more locking deadlocks 2019-07-12 23:51:45 -04:00
John Sully 8630339e43 Fix deadlock with client and ae locks 2019-07-12 20:46:50 -04:00
John Sully 528d10091f Add Active Replication tests 2019-07-12 03:54:41 -04:00
John Sully 149c3cf3dd FIX: The dabase count configuration is not respected 2019-07-12 02:13:37 -04:00
John Sully f12c3cf9dd Update README.md 2019-07-11 20:29:47 -04:00
John Sully 1f08a0efb3 Fix compile errors on GCC v5 2019-07-11 20:20:01 -04:00
John Sully 6cf85d1d01 Fix more accounting errors with active replication and the replication offset. Specifically we don't update repl_ack_off as frequently as we do reploff_skipped 2019-07-11 19:20:12 -04:00
John Sully b5101a460d Active Replicas are not slaves 2019-07-11 18:51:20 -04:00
John Sully a5784ef09e Fix active replication offset synchronization accounting, and enable the wait command 2019-07-11 17:00:23 -04:00
John Sully 122ec25bf0 lazyfree needs to consume more memory to be detectable 2019-07-06 00:53:40 -04:00
John Sully d013ad9eba Redis only does this in beforeSleep function - doing extra calls like we do causes test issues 2019-07-06 00:53:20 -04:00
John Sully d918ca6fa5 Add back user space buffering of RDB save 2019-07-06 00:36:23 -04:00
John Sully 852819180f We can use less memory in the client output buffers. Its OK 2019-07-05 23:43:01 -04:00
John Sully 218111eb72 Fix additional warning related to new() overloads 2019-07-05 23:42:39 -04:00
John Sully 1531cfb7ee Fix additional warnings 2019-06-27 16:29:36 -04:00
John Sully 16a89f21dc Fix mac build breaks 2019-06-27 15:04:09 -04:00
John Sully 79e5160e37 Fix libcxxabi clang compile failure in travis, as well as bool issue due to old clang 2019-06-18 00:42:01 -04:00
John Sully 510e966dc0 Bump travis compiler version 2019-06-18 00:42:01 -04:00
John Sully 8238d3207e Fix Travis CI issue 2019-06-17 23:56:23 -04:00
John Sully e37bc4ad40 Fix issues with relaxed memory model architectures 2019-06-17 23:00:12 -04:00
John Sully 0f78b8b917 Remove unnecessary recursive lock 2019-06-17 23:00:12 -04:00
John Sully 19061fe04f missing file :) 2019-06-17 23:00:12 -04:00
John Sully 9c901eb65f Fix test failures due to assert 2019-06-17 23:00:12 -04:00
John Sully ae33ff3a6e convert the pending write list to a vector for better performance and less cache thrashing 2019-06-17 23:00:12 -04:00
John Sully 59dbd625c1 Move more code out of the GIL 2019-06-17 23:00:12 -04:00
John Sully 8eb4e355b9 Remove an unnecessary lock that eats performance 2019-06-17 23:00:12 -04:00
John Sully 8b76b01bfe Even the next up thread should sleep in the futex 2019-06-17 23:00:12 -04:00
John Sully ec57b4b024 Fallback to a futex if we spin for a long time 2019-06-17 23:00:12 -04:00
John Sully 46d6caa47c Enable load balancing of UNIX sockets across threads 2019-06-11 01:34:36 -04:00
John Sully 97b65ce19c Fix crash adding duplicate replica. Just send an error instead 2019-06-02 15:50:50 -04:00
John Sully 55d0ef40b0 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-06-01 03:23:21 -04:00
John Sully a6c56416fc Implement MOTD feature in keydb-cli 2019-05-21 15:12:12 -04:00
John Sully cd3c482d5e Update README.md 2019-05-21 00:04:12 -04:00
John Sully c5cbb77fc7 Fix regressions from RESP3 changes in commit 317f8b9d38 2019-05-20 23:39:44 -04:00
John Sully d7f21f02b3 The unstable branch doesn't have a version # 2019-05-20 16:12:26 -04:00
John Sully 87dc8ce9b3 Fix double unlock 2019-05-20 15:52:04 -04:00
John Sully 2e22aa1a9c Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-05-20 10:57:59 -04:00
John Sully 8c56dbf971 Protocol regression from RESP3 work 2019-05-20 10:57:37 -04:00
Qix a78169e9e0 cast void data pointer to const char * to fix gcc 2019-05-19 16:24:39 -04:00
John Sully 39a60c8120 Fix build breaks on some older compilers 2019-05-18 20:58:48 -04:00
John Sully c57d8760bd Fix build break on some compilers 2019-05-18 20:41:05 -04:00
John Sully 3eed2a8780 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-05-18 20:25:23 -04:00
John Sully 23b0268a7f Print nicer error messages for uncaught exceptions 2019-05-18 20:24:29 -04:00
John Sully 3d0de946bb Fix: Active replication falls behind under high load 2019-05-18 20:23:20 -04:00
John Sully 866b8ead91 Update Active Replication wiki links 2019-05-11 21:53:30 -04:00
John Sully aa274960ff Fix a few issues from the merge 2019-05-11 19:26:59 -04:00
John Sully 54d6eb851b Make lazy free test more reliable 2019-05-11 17:57:35 -04:00
John Sully 86d7276f24 Merge branch 'unstable' of https://github.com/antirez/redis into MergeRedis
Note: some tests failing
2019-05-11 02:20:34 -04:00
John Sully 0918651438 Add byline to logo 2019-05-10 23:48:14 -04:00
John Sully 272d9297b6 Fix CentOS build failure 2019-05-09 19:54:34 -04:00
John Sully f5bfc71899 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-05-09 19:16:50 -04:00
John Sully 42e1ded55f build break fix 2019-05-09 19:16:31 -04:00
John Sully 6c410af5a8 Fix issue #11 2019-05-09 19:14:10 -04:00
John Sully 57ae676181 Fix typo 2019-05-09 19:06:58 -04:00
John Sully 7896ca6e52 Add missing file 2019-05-09 19:05:09 -04:00
John Sully c4a315dd5e Change debug messages to reference KeyDB 2019-05-09 19:03:50 -04:00
John Sully bf26959b72 Fix module locking issues 2019-05-09 19:00:27 -04:00
John Sully 37b2d046be refactor server global into a pointer (so that threadsafe commands can set this to NULL to prove they don't rely on it 2019-04-21 14:01:10 -04:00
John Sully fa2e407873 Factor out some normally const globals 2019-04-21 13:20:45 -04:00
John Sully c61cf57db5 additional fix to rreplay forward compat 2019-04-20 01:36:23 -04:00
John Sully ef3690f2db Make rreplay forward compatible with extra future args 2019-04-20 01:15:01 -04:00
John Sully 14d01ec7bd Tweak mvcc time format so rollovers are not an issue 2019-04-20 01:03:08 -04:00
John Sully 5dc9f70386 Timestamp writes to objects so we can be smarter about merging databases 2019-04-20 00:52:07 -04:00
John Sully 88e593bf96 Fix use uninitialized 2019-04-19 23:41:40 -04:00
John Sully efde2e6be6 Additional MVCC work and fix memory leak loading objects from rdb 2019-04-19 22:54:42 -04:00
John Sully 5a78a3bc46 Add version override command for users that need compatibility with Redis 2019-04-19 19:57:11 -04:00
John Sully b276d803d4 RREPLAY PERF: The UUID stack is unnecessary, RREPLAY itself can detect the cycle and call cancel() 2019-04-19 19:36:47 -04:00
John Sully da51ac430b Detect cycles in mesh networks with multi master 2019-04-19 19:31:11 -04:00
John Sully 01eb0a3c7f Fix crash near boot when adding replicas and dumping database 2019-04-19 17:08:54 -04:00
John Sully dc2b3cf4f8 Replication fake connection should inhereit the user and permission of the real connection 2019-04-18 22:07:35 -04:00
John Sully c4621a5ed2 Start of MVCC support (and more C++) 2019-04-16 23:16:03 -04:00
John Sully 1c953a4d5b Fix module linking and crashing issues 2019-04-16 13:34:22 -04:00
John Sully c64ce7aa9c Fix replica authentication failure when masterauth is below replicaof in the config file 2019-04-15 22:31:02 -04:00
John Sully acdc4fdfec Fix memory leak unsetting master 2019-04-11 19:55:44 -04:00
John Sully 7ef9c18b72 Fix compile errors when MALLOC=memkind 2019-04-11 19:40:45 -04:00
John Sully a69b4e79db Fix failure to respect masterauth issue #26 2019-04-11 19:08:12 -04:00
John Sully 740fc6c2b8 Fix addition RESP3 regressions (return empty set) 2019-04-08 16:52:57 -04:00
John Sully 42202c868d Fix protocol break with hgetall and family 2019-04-08 13:52:02 -04:00
John Sully 8c133b605c Move remaning files dependent on server.h over to C++ 2019-04-08 01:00:48 -04:00
John Sully b50acd7238 Move dict to C++ 2019-04-07 17:23:59 -04:00
John Sully 54db278695 Port db to C++ 2019-04-07 17:13:14 -04:00
John Sully 011948bcef Move a bunch of files to C++ 2019-04-07 16:54:56 -04:00
John Sully 9f95d8b38f Make t_string C++ 2019-04-07 15:24:23 -04:00
John Sully 3d394a6fa2 Fix clang compile error 2019-04-06 00:20:17 -04:00
John Sully 68d2b648e0 Add RREPLAY command and put the issue of packet storms to rest. Fixes issue #24 2019-04-06 00:14:27 -04:00
John Sully 283998404f Fix regression in active replication caused by multimaster PR 2019-04-04 16:50:40 -04:00
John Sully a7b4d0fea6 Merge pull request #23 from JohnSully/wip-multimaster
Wip multimaster
2019-04-04 11:40:58 -07:00
John Sully 59051dd59d All tests runs pass! YAYgit add src/cluster.c src/config.c ! 2019-04-04 01:02:19 -04:00
John Sully cd836a37e7 Fix some more failing tests 2019-04-04 00:25:30 -04:00
John Sully 4326d22380 Merge branch 'unstable' into wip-multimaster 2019-04-03 00:12:13 -04:00
John Sully 161d3a35ff Fix cluster test failure (not real issue) 2019-04-03 00:11:34 -04:00
John Sully 20a9d21dfb Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-04-03 00:09:51 -04:00
John Sully e902789aa7 Fix failing tests due to build issue inhereted from Redis 2019-04-03 00:09:26 -04:00
John Sully 3745bbd95b Merge branch 'unstable' of https://github.com/antirez/redis into unstable 2019-04-03 00:00:38 -04:00
John Sully e63b2880b0 Cluster tests shouldn't crash (note: still not passing either) 2019-04-02 22:32:10 -04:00
John Sully a9b70e1ef7 Multiple masters is no good if we keep dropping the database 2019-04-02 21:47:21 -04:00
John Sully e300f753c5 Tests are passing! YAY! 2019-04-02 21:36:04 -04:00
John Sully efaeca5887 It compiles and doesn't crash immediately! 2019-04-02 16:47:05 -04:00
John Sully 4d67305661 Link to GUI 2019-03-31 14:37:54 -04:00
John Sully 853bb6ca3e Commit missing file 2019-03-28 17:56:14 -04:00
John Sully b16f23ae8e Travis needs to install uuid-dev 2019-03-28 16:18:26 -04:00
John Sully 91e6368de0 Implement database merging for Active Replicas 2019-03-28 15:12:43 -04:00
John Sully e4451b9628 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-27 22:59:38 -04:00
John Sully 770bb8ef5f If no rdb file is specified and no s3 file is specified use the default RDB filename. If only S3 is specified use diskless sync 2019-03-27 22:59:12 -04:00
John Sully 87b958a210 Update README.md 2019-03-27 21:52:08 -04:00
John Sully 314ac90ba9 Update README.md 2019-03-27 15:39:25 -04:00
John Sully 9f33822083 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-26 20:39:56 -04:00
John Sully 10a4b35bc5 SIGALRM should happen on a worker thread to make our tests happy 2019-03-26 20:39:30 -04:00
John Sully 7b1dd0b60d Make PSYNC2 tests more reliable on slower hardware 2019-03-26 18:59:31 -04:00
John Sully 7a650741f7 Merge pull request #18 from DevopsDood/unstable
Update Readme for missing docker flag
2019-03-26 09:49:53 -04:00
Richard Silver 2ce5f1b944 Update Readme for missing docker flag 2019-03-25 15:55:23 -07:00
John Sully 063a14372d Give information on dependencies that need installation. 2019-03-25 16:22:10 -04:00
John Sully dd70e1b571 Add depenednecy on uuid-dev to dockerfile 2019-03-25 02:09:53 -04:00
John Sully 1840b893c2 Talk about active replica 2019-03-25 00:12:04 -04:00
John Sully 8bcde757ce We don't corretly terminate our varargs 2019-03-24 18:57:25 -04:00
John Sully 1dff223c71 OS X build fixes 2019-03-24 18:06:57 -04:00
John Sully a7aa2b0740 Active Replica Support 2019-03-24 15:39:10 -04:00
John Sully fb45fefbca Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-21 23:11:55 -04:00
John Sully 7b914c2531 Fix kqueue build error 2019-03-21 23:11:19 -04:00
John Sully 75d517a27f Merge pull request #16 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2019-03-21 21:57:25 -04:00
John Sully 4c98bc690e Update README.md 2019-03-21 21:26:00 -04:00
John Sully 550b3a3a99 Update README.md 2019-03-21 21:25:49 -04:00
The Gitter Badger ef7e89352d Add Gitter badge 2019-03-22 01:24:32 +00:00
John Sully 9322d604ee Merge branch 'unstable' of https://github.com/antirez/redis into unstable 2019-03-21 20:15:59 -04:00
John Sully 5d92110630 Merge pull request #15 from DevopsDood/unstable
Added docker builder for those that want it
2019-03-21 19:54:00 -04:00
Richard Silver 4056037cc2 Merge branch 'unstable' of github.com:JohnSully/KeyDB into unstable 2019-03-21 16:19:45 -07:00
Richard Silver 677ae5487f updated readme and Dockerfile to allow for tests to be run in container 2019-03-21 16:18:37 -07:00
John Sully 19956b3807 comment issue 2019-03-21 22:18:48 +00:00
John Sully ab9122f2cb Polarity of the weak flag was wrong. We want to use the strong variant of atomic_compare_exchange always 2019-03-21 22:17:04 +00:00
Richard Silver e62c6b0ed0 Added build Dockerfile 2019-03-21 15:15:11 -07:00
John Sully 27a420fbc2 Compile issues at O0 optimization 2019-03-21 21:57:18 +00:00
John Sully b775ebb382 ARM build fix: Don't use X64 asm here 2019-03-20 04:14:33 +00:00
John Sully ac80a5c6a6 Add debugging stats to the INFO command 2019-03-19 22:04:33 -04:00
John Sully c74100a552 Add release badge 2019-03-19 20:54:36 -04:00
John Sully 03379106d6 Add CI badge 2019-03-19 20:46:25 -04:00
John Sully 9ad229f663 Getting close! Maybe there was a better way to do this than checking in travis.yml files repeatedly but alas it works and doesn't affect people building locally 2019-03-19 20:40:17 -04:00
John Sully 0900edf776 Clang build with libc malloc 2019-03-19 20:34:09 -04:00
John Sully ea520027b9 more clang travis fixes 2019-03-19 20:26:35 -04:00
John Sully 04679b3b3b Fix race condition building dependencies with multithreaded builds 2019-03-19 20:25:30 -04:00
John Sully 2bf5c1324a Will clang build now with travis? 2019-03-19 20:00:52 -04:00
John Sully 3d93ca1bf6 clang build failure 2019-03-19 19:55:03 -04:00
John Sully c548431611 Travis clang dependencies 2019-03-19 19:50:28 -04:00
John Sully 0ab29f7394 Makefile ignores env CXXFLAGS 2019-03-19 19:29:14 -04:00
John Sully 30dab7ad14 No underscore 2019-03-19 19:22:27 -04:00
John Sully 0c5fa59221 Maybe this will make travis-ci stop using GCC headers when compiling with clang 2019-03-19 19:12:15 -04:00
John Sully 267e84f97d Feature gate SO_INCOMING_CPU so we compile on older kernels 2019-03-19 18:55:42 -04:00
John Sully 344cca75c6 typo 2019-03-19 18:40:50 -04:00
John Sully 0dd8e682f4 It would be nice if our CI actually called make... 2019-03-19 18:37:53 -04:00
John Sully da7e54819a Fix issues with travis config 2019-03-19 18:31:45 -04:00
John Sully 4e70215307 Let's try travis-ci 2019-03-19 18:27:54 -04:00
John 6aa162f6ff Fix linker errors on some compilers due to sdslen() 2019-03-19 22:08:20 +00:00
John Sully d380074569 KeyDB has different aims than the Redis project.
We believe software is for the user.  If a feature requires complicating the codebase
but simplifies our user's lives we will do it any time.  This should not be taken
as an outright rejection of the manifesto, as we agree on many points.
2019-03-19 01:36:03 -04:00
John Sully c406e7ff51 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-19 01:26:22 -04:00
John Sully 31ff6cffee Merge branch 'unstable' of https://github.com/antirez/redis into unstable 2019-03-19 01:26:10 -04:00
John Sully a9e525c81e Hack to prevent build errors on some machines due to missing throw() 2019-03-15 05:28:20 +00:00
John Sully 6157a5fc1b Merge /home/john/repos/redis_clean into unstable 2019-03-14 14:22:41 -04:00
John Sully be3cb1ad33 Merge branch 'unstable' of https://github.com/antirez/redis into unstable 2019-03-14 14:22:27 -04:00
John Sully 966f4a8144 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-13 18:08:59 -04:00
John Sully 261cf24efc Merge branch 'unstable' of https://github.com/antirez/redis into unstable
Lots of fixes and improvements from upstream.
2019-03-13 18:08:22 -04:00
JohnSully a3da10f4eb Update README.md 2019-03-13 16:57:40 -04:00
John Sully 6cb8063497 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-13 16:53:55 -04:00
John Sully a45f212693 Implement load database dumps from S3. We already save. 2019-03-13 16:53:37 -04:00
JohnSully 7c72cd5471 Merge pull request #9 from 0xflotus/patch-1
fixed guarantees
2019-03-13 12:22:29 -04:00
0xflotus 66f2032708 fixed guarantees 2019-03-13 15:14:34 +01:00
JohnSully 7546c7d8b4 Update README.md 2019-03-12 14:38:03 -04:00
JohnSully 703e4ad2fe formatting fixes 2019-03-12 00:59:28 -04:00
JohnSully 0b98280a1f Add charts to readme
Hotlink from medium, hope they don't mind.
2019-03-12 00:55:03 -04:00
John Sully 4609bed6a4 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into RELEASE_0_9 2019-03-11 20:54:14 -04:00
John Sully 99ccb11d89 Werror is good for me, but not for people compiling on other compilers 2019-03-11 20:53:57 -04:00
JohnSully 8a5a513662 Explain how multithreading works 2019-03-11 20:37:57 -04:00
JohnSully bf0fd22309 Update README.md 2019-03-11 19:38:20 -04:00
John Sully cc98d10fc6 Make storage.h C++ safe 2019-03-09 13:42:08 -05:00
John Sully a6a022faa2 sizeof is too big 2019-03-09 13:41:49 -05:00
John Sully a864ad1c9c bump version 2019-03-07 19:13:59 -05:00
John Sully 0bc586933f Merge branch 'unstable' into RELEASE_0_9 2019-03-07 19:13:33 -05:00
John Sully 2785a8b4d4 Module threading fixes 2019-03-07 19:13:01 -05:00
John Sully d5d5f6ae06 Merge branch 'unstable' into RELEASE_0_9 2019-03-06 16:39:15 -05:00
John Sully be3ba1d53e Limit server-threads to cores in the machine 2019-03-06 16:39:02 -05:00
John Sully 09e6a4fee0 port server.c to server.cpp 2019-03-06 16:29:30 -05:00
John Sully efc60dd8c5 Set version 2019-03-06 15:25:28 -05:00
John Sully a52cd974b9 Don't send replies to slaves after we've queued them to be closed 2019-03-06 15:21:05 -05:00
John Sully de4217489c defer free 2019-03-05 15:46:19 -05:00
John Sully 3c658b5012 Fix crash with paused clients (accessed when global lock is not acquired) 2019-03-03 22:24:12 -05:00
John Sully f6814aa825 Crash in Memory Doctor when all clients are slaves 2019-03-03 13:56:47 -05:00
John Sully 01a529cbda Fix issue #2, check posix return values 2019-03-02 20:43:03 -05:00
John Sully a1475af1e4 sds copies uninitialized data wasting time for everyone 2019-03-02 19:27:52 -05:00
John Sully 07594d4f95 Merge branch 'unstable' of https://github.com/antirez/redis into unstable
We want that awesome multithreaded benchmark
2019-03-02 18:07:18 -05:00
John Sully bad73faf28 write fastlock_unlock in ASM... because its faster 2019-03-02 16:47:27 -05:00
John Sully 8d3704d93b Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-01 16:40:20 -05:00
John Sully 8bd56fadd6 tighten up the spinlock loop, and some other bikeshedding 2019-03-01 13:29:21 -05:00
John Sully 23f9b584a8 remove unnecessary logs 2019-02-28 13:57:58 -05:00
JohnSully 141557963e Update README.md 2019-02-26 15:16:46 -05:00
John Sully ffabf3c5b7 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-02-26 15:14:50 -05:00
John Sully 9b1e95809c Thread affinity feature (default disabled) 2019-02-26 15:14:35 -05:00
JohnSully b8776bb001 Link to detailed benchmarking results and methodology. 2019-02-26 15:11:25 -05:00
JohnSully 84c20e8337 More fine tuning help. Hopefully we can automate this. 2019-02-26 03:30:37 -05:00
JohnSully bae2409cce Update benchmarking notes. 2019-02-26 02:30:03 -05:00
John Sully 8f7c44257b test code shouldn't be commited 2019-02-26 00:21:37 -05:00
John Sully 2772ce249c Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-02-26 00:20:11 -05:00
John Sully bcfd9327cb writes shouldn't be under the global lock 2019-02-26 00:19:38 -05:00
John Sully 01ff36fc28 Option to disable ASM spinlock 2019-02-26 00:00:04 -05:00
John Sully 6466b09fdc Fix build break 2019-02-26 01:10:07 +00:00
John Sully 40d7a701fe Rewrite our spinlock in assembly, pretty big performance improvement 2019-02-25 18:21:27 -05:00
JohnSully 78b9d303d3 Formatting (more) 2019-02-23 03:08:24 -05:00
John Sully d912013d1b Update copyright to include additional authorship 2019-02-23 02:27:19 -05:00
John Sully 898e6519d1 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-02-23 02:25:00 -05:00
John Sully 8c074a7d01 Merge branch 'Multithread' into unstable 2019-02-23 02:24:23 -05:00
JohnSully 6e69b4a795 More edits 2019-02-23 01:48:05 -05:00
JohnSully 1c36b46cb4 type 2019-02-23 01:33:27 -05:00
JohnSully 73abd04b95 Formatting 2019-02-23 01:32:50 -05:00
JohnSully 29d6845d1f Initial rewrite of Readme 2019-02-23 01:28:44 -05:00
John Sully da84b26785 Fastlock fixes 2019-02-10 22:00:19 -05:00
John Sully eb9070c833 move ae to C++ 2019-02-10 20:24:11 -05:00
John Sully b7b503d3ce Keep pool allocator up to date (even though we aren't enabling it) 2019-02-10 19:33:07 -05:00
John Sully 327bbec981 Prevent so many copies of sdslen getting added 2019-02-10 19:31:46 -05:00
John Sully 7175a8e4eb Performance enhancements! 2019-02-09 13:05:06 -05:00
John Sully 9aefc183c6 Reduce memory usage for in place strings by 8 bytes 2019-02-09 13:04:18 -05:00
John Sully 3e9b867709 complete rebranding with tests passing 2019-02-09 10:11:46 -05:00
John Sully e8b5bbf7a1 Fix bug where we try to load a database with no name 2019-02-09 07:56:45 -05:00
John Sully 79ef18e885 remove Redis branding 2019-02-08 17:56:32 -05:00
John Sully 23a91df9f6 Support AWS S3 saving via the s3 cli tools 2019-02-06 01:06:48 -05:00
John Sully d8741595ae Merge branch 'unstable' of https://github.com/antirez/redis into unstable 2019-02-06 00:09:39 -05:00
John Sully 3c9dd6ffc2 Make main headers C++ safe, and change rdb to use file descriptor instead of FILE pointer 2019-02-05 23:36:40 -05:00
John Sully 42d28c9ff6 complete malloc memory class work, and pass tests 2019-02-04 16:56:13 -05:00
John Sully 82372cbce8 Properly integrate memkind 2019-02-01 15:21:00 -05:00
John Sully 69b07c5cc2 Merge commit '09a263e6076b3fd0fe3b094a2bfad7f93fc997d6' as 'deps/memkind/src' 2019-02-01 14:45:39 -05:00
John Sully a6d27dc02c template config 2019-02-01 14:01:35 -05:00
John Sully bbcaf48cb0 Support configurable file backed scratch 2019-02-01 13:54:59 -05:00
John Sully 85194d99da crash fixes 2019-01-30 01:15:10 -05:00
John Sully 5c86d2faa2 Custom flash heap 2019-01-29 18:10:46 -05:00
588 changed files with 17264 additions and 67631 deletions

No files matched your search

+9 -13
View File
@@ -1,24 +1,20 @@
---
name: Bug report
about: Help us improve KeyDB by reporting a bug
title: '[BUG]'
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
A short description of the bug.
** Log Files **
These should be KeyDB logs, not syslogs or logs from your container manager. If you are reporting a crash there will be a line in your log stating:
"=== KEYDB BUG REPORT START: Cut & paste starting from here ==="
**To reproduce**
Please copy everything after this line.
Steps to reproduce the behavior and/or a minimal code sample.
**Expected behavior**
A description of what you expected to happen.
**Additional information**
Any additional information that is relevant to the problem.
**To Reproduce**
Do you know how to reproduce this? If so please provide repro steps.
-20
View File
@@ -1,20 +0,0 @@
---
name: Crash report
about: Submit a crash report
title: '[CRASH]'
labels: ''
assignees: ''
---
**Crash report**
Paste the complete crash log between the quotes below. Please include a few lines from the log preceding the crash report to provide some context.
```
```
**Aditional information**
1. OS distribution and version
2. Steps to reproduce (if any)
+10 -14
View File
@@ -1,24 +1,20 @@
---
name: Feature request
about: Suggest a feature for KeyDB
title: '[NEW]'
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**The problem/use-case that the feature addresses**
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A description of the problem that the feature will solve, or the use-case with which the feature will be used.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Description of the feature**
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
A description of what you want to happen.
**Alternatives you've considered**
Any alternative solutions or features you've considered, including references to existing open and closed feature requests in this repository.
**Additional information**
Any additional information that is relevant to the feature request.
**Additional context**
Add any other context or screenshots about the feature request here.
-8
View File
@@ -1,8 +0,0 @@
---
name: Other
about: Can't find the right issue type? Use this one!
title: ''
labels: ''
assignees: ''
---
+11 -24
View File
@@ -8,64 +8,51 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: make
run: |
sudo apt-get update
sudo apt-get -y remove libzstd || true
sudo apt-get -y install uuid-dev libcurl4-openssl-dev libbz2-dev zlib1g-dev libsnappy-dev liblz4-dev libzstd-dev libgflags-dev
make BUILD_TLS=yes -j2 KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror'
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make BUILD_TLS=yes -j2
- name: gen-cert
run: ./utils/gen-test-certs.sh
- name: test-tls
run: |
sudo apt-get -y install tcl tcl-tls
./runtest --clients 1 --verbose --tls
./runtest --clients 2 --verbose --tls
- name: cluster-test
run: |
./runtest-cluster --tls --config server-threads 1
./runtest-cluster --tls
- name: sentinel test
run: |
./runtest-sentinel
- name: module tests
run: |
./runtest-moduleapi
- name: rotation test
run: |
./runtest-rotation
build-ubuntu-old:
runs-on: ubuntu-20.04
runs-on: ubuntu-16.04
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/checkout@v1
- name: make -j2
run: |
sudo apt-get update
sudo apt-get -y remove libzstd || true
sudo apt-get -y install uuid-dev libcurl4-openssl-dev libbz2-dev zlib1g-dev libsnappy-dev liblz4-dev libzstd-dev libgflags-dev
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make -j2
build-macos-latest:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: make
run: make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' -j2
run: make -j2
build-libc-malloc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: make
run: |
sudo apt-get update
sudo apt-get -y remove libzstd || true
sudo apt-get -y install uuid-dev libcurl4-openssl-dev libbz2-dev zlib1g-dev libsnappy-dev liblz4-dev libzstd-dev libgflags-dev
make KEYDB_CFLAGS='-Werror' KEYDB_CXXFLAGS='-Werror' MALLOC=libc -j2
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make MALLOC=libc -j2
+180
View File
@@ -0,0 +1,180 @@
name: Daily
on:
pull_request:
branches:
# any PR to a release branch.
- '[0-9].[0-9]'
schedule:
- cron: '0 0 * * *'
jobs:
test-ubuntu-jemalloc:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make
- name: test
run: |
sudo apt-get install tcl8.5
./runtest --accurate --verbose
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
test-ubuntu-libc-malloc:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make MALLOC=libc
- name: test
run: |
sudo apt-get install tcl8.5
./runtest --accurate --verbose
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
test:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make BUILD_TLS=yes -j2
- name: "test (tls)"
run: |
sudo apt-get install tcl8.5 tcl-tls
./utils/gen-test-certs.sh
./runtest --accurate --verbose --tls
- name: test
run: ./runtest --accurate --verbose
- name: module api test (tls)
run: ./runtest-moduleapi --verbose --tls
test-ubuntu-arm:
runs-on: [self-hosted, linux, arm]
steps:
- uses: actions/checkout@v2
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make -j4
- name: test
run: |
sudo apt-get -y install tcl8.5
./runtest --clients 2 --verbose
- name: module tests
run: |
./runtest-moduleapi
test-valgrind:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make valgrind
- name: test
run: |
sudo apt-get update
sudo apt-get install tcl8.5 valgrind -y
./runtest --valgrind --verbose --clients 1
- name: module api test
run: ./runtest-moduleapi --valgrind --verbose --clients 1
test-centos7-jemalloc:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
container: centos:7
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
yum -y install centos-release-scl
yum -y install devtoolset-7
scl enable devtoolset-7 "make"
- name: test
run: |
yum -y install tcl
./runtest --accurate --verbose
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
test-centos7-tls:
runs-on: ubuntu-latest
if: github.repository == 'redis/redis'
container: centos:7
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: |
yum -y install centos-release-scl epel-release
yum -y install devtoolset-7 openssl-devel openssl
scl enable devtoolset-7 "make BUILD_TLS=yes"
- name: test
run: |
yum -y install tcl tcltls
./utils/gen-test-certs.sh
./runtest --accurate --verbose --tls
./runtest --accurate --verbose
- name: module api test
run: |
./runtest-moduleapi --verbose --tls
./runtest-moduleapi --verbose
- name: sentinel tests
run: |
./runtest-sentinel --tls
./runtest-sentinel
- name: cluster tests
run: |
./runtest-cluster --tls
./runtest-cluster
test-macos-latest:
runs-on: macos-latest
if: github.repository == 'redis/redis'
timeout-minutes: 14400
steps:
- uses: actions/checkout@v2
- name: make
run: make
- name: test
run: |
./runtest --accurate --verbose --no-latency
- name: module api test
run: ./runtest-moduleapi --verbose
- name: sentinel tests
run: ./runtest-sentinel
- name: cluster tests
run: ./runtest-cluster
+22
View File
@@ -0,0 +1,22 @@
name: Endurance
on:
schedule:
- cron: '0 * * * *'
jobs:
test-endurance:
runs-on: octocore
timeout-minutes: 60
steps:
- uses: actions/checkout@v1
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make -j8
- name: test-multithread (5X)
run: |
sudo apt-get install -y tcl tcl-tls
./runtest --loopn 5 --config server-threads 3 --clients 5 --endurance
+2 -3
View File
@@ -15,6 +15,7 @@ src/keydb-server
**/app/keydb-server
*.deb
*.rpm
keydb-pro-server
src/keydb-cli
**/bin/keydb-cli
**/app/keydb-cli
@@ -29,7 +30,6 @@ redis-check-rdb
keydb-check-rdb
redis-check-dump
keydb-check-dump
keydb-diagnostic-tool
redis-cli
redis-sentinel
redis-server
@@ -48,7 +48,7 @@ src/nodes.conf
deps/lua/src/lua
deps/lua/src/luac
deps/lua/src/liblua.a
tests/tls*/*
tests/tls/*
.make-*
.prerequisites
*.dSYM
@@ -58,4 +58,3 @@ Makefile.dep
.ccls
.ccls-cache/*
compile_commands.json
keydb.code-workspace
-3
View File
@@ -1,6 +1,3 @@
[submodule "deps/rocksdb"]
path = deps/rocksdb
url = https://github.com/facebook/rocksdb.git
[submodule "deps/depot_tools"]
path = deps/depot_tools
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
+3204 -616
View File
File diff suppressed because it is too large. Load diff
-96
View File
@@ -1,96 +0,0 @@
Contributor Covenant Code of Conduct
Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others’ private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
this email address: redis@redis.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
1. Correction
Community Impact: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
Consequence: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
2. Warning
Community Impact: A violation through a single incident or series
of actions.
Consequence: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
3. Temporary Ban
Community Impact: A serious violation of community standards, including
sustained inappropriate behavior.
Consequence: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
4. Permanent Ban
Community Impact: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
Consequence: A permanent ban from any sort of public interaction within
the community.
Attribution
This Code of Conduct is adapted from the Contributor Covenant,
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by Mozilla’s code of conduct
enforcement ladder.
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+1 -3
View File
@@ -1,7 +1,5 @@
Copyright (c) 2006-2020, Salvatore Sanfilippo
Copyright (C) 2019-2021, John Sully
Copyright (C) 2020-2021, EQ Alpha Technology Ltd.
Copyright (C) 2022 Snap Inc.
Copyright (C) 2019-2020, John Sully
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+1 -1
View File
@@ -1,4 +1,4 @@
# Top level makefile, this just calls into src/Makefile where the real work is done. Changes should be made there.
# Top level makefile, the real shit is at src/Makefile
default: all
+52 -84
View File
@@ -2,20 +2,18 @@
![CI](https://github.com/JohnSully/KeyDB/workflows/CI/badge.svg?branch=unstable)
[![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/eq-alpha-technology-inc/eq-alpha-technology-inc)
##### KeyDB is now a part of Snap Inc! Check out the announcement [here](https://docs.keydb.dev/news/2022/05/12/keydb-joins-snap)
##### [Release v6.3.0](https://github.com/EQ-Alpha/KeyDB/releases/tag/v6.3.0) is here with major improvements as we consolodate our Open Source and Enterprise offerings into a single BSD-3 licensed project. See our [roadmap](https://docs.keydb.dev/docs/coming-soon) for details.
##### Want to extend KeyDB with Javascript? Try [ModJS](https://github.com/JohnSully/ModJS)
##### New! Want to extend KeyDB with Javascript? Try [ModJS](https://github.com/JohnSully/ModJS)
##### Need Help? Check out our extensive [documentation](https://docs.keydb.dev).
##### KeyDB is on Slack. Click [here](https://docs.keydb.dev/slack/) to learn more and join the KeyDB Community Slack workspace.
##### Have feedback? Take our quick survey: https://www.surveymonkey.com/r/Y9XNS93
##### KeyDB is Hiring! We are currently building out our dev team. If you are interested please see the posting here: https://keydb.dev/careers.html
What is KeyDB?
--------------
KeyDB is a high performance fork of Redis with a focus on multithreading, memory efficiency, and high throughput. In addition to performance improvements, KeyDB offers features such as Active Replication, FLASH Storage and Subkey Expires. KeyDB has a MVCC architecture that allows you to execute queries such as KEYS and SCAN without blocking the database and degrading performance.
KeyDB is a high performance fork of Redis with a focus on multithreading, memory efficiency, and high throughput. In addition to multithreading, KeyDB also has features only available in Redis Enterprise such as [Active Replication](https://github.com/JohnSully/KeyDB/wiki/Active-Replication), [FLASH storage](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) support, and some not available at all such as direct backup to AWS S3.
KeyDB maintains full compatibility with the Redis protocol, modules, and scripts. This includes the atomicity guarantees for scripts and transactions. Because KeyDB keeps in sync with Redis development KeyDB is a superset of Redis functionality, making KeyDB a drop in replacement for existing Redis deployments.
@@ -34,81 +32,54 @@ KeyDB has a different philosophy on how the codebase should evolve. We feel tha
Because of this difference of opinion features which are right for KeyDB may not be appropriate for Redis. A fork allows us to explore this new development path and implement features which may never be a part of Redis. KeyDB keeps in sync with upstream Redis changes, and where applicable we upstream bug fixes and changes. It is our hope that the two projects can continue to grow and learn from each other.
Project Support
-------------------
The KeyDB team maintains this project as part of Snap Inc. KeyDB is used by Snap as part of its caching infrastructure and is fully open sourced. There is no separate commercial product and no paid support options available. We really value collaborating with the open source community and welcome PRs, bug reports, and open discussion. For community support or to get involved further with the project check out our community support options [here](https://docs.keydb.dev/docs/support) (slack, forum, meetup, github issues). Our team monitors these channlels regularly.
Additional Resources
--------------------
Try the KeyDB [Docker Image](https://hub.docker.com/r/eqalpha/keydb)
Try our docker container: https://hub.docker.com/r/eqalpha/keydb
Join us on [Slack](https://docs.keydb.dev/slack/)
Talk on Gitter: https://gitter.im/KeyDB
Learn more using KeyDB's extensive [documentation](https://docs.keydb.dev)
Visit our Website: https://keydb.dev
Post to our [Community Forum](https://community.keydb.dev)
See options for channel partners and support contracts: https://keydb.dev/support.html
See the [KeyDB Roadmap](https://docs.keydb.dev/docs/coming-soon) to see what's in store
Learn with KeyDB’s official documentation site: https://docs.keydb.dev
[Subscribe to the KeyDB mailing list](https://eqalpha.us20.list-manage.com/subscribe/post?u=978f486c2f95589b24591a9cc&id=4ab9220500)
Management GUI: We recommend [FastoNoSQL](https://fastonosql.com/) which has official KeyDB support.
Benchmarking KeyDB
------------------
Please note keydb-benchmark and redis-benchmark are currently single threaded and too slow to properly benchmark KeyDB. We recommend using a redis cluster benchmark tool such as [memtier](https://github.com/RedisLabs/memtier_benchmark). Please ensure your machine has enough cores for both KeyDB and memtier if testing locally. KeyDB expects exclusive use of any cores assigned to it.
Please note keydb-benchmark and redis-benchmark are currently single threaded and too slow to properly benchmark KeyDB. We recommend using a redis cluster benchmark tool such as [memtier](https://github.com/RedisLabs/memtier_benchmark). Please ensure your machine has enough cores for both KeyDB and memteir if testing locally. KeyDB expects exclusive use of any cores assigned to it.
For more details on how we benchmarked KeyDB along with performance numbers check out our blog post: [Redis Should Be Multithreaded](https://medium.com/@john_63123/redis-should-be-multi-threaded-e28319cab744?source=friends_link&sk=7ce8e9fe3ec8224a4d27ef075d085457)
New Configuration Options
-------------------------
With new features comes new options. All other configuration options behave as you'd expect. Your existing configuration files should continue to work unchanged.
With new features comes new options:
```
server-threads N
server-thread-affinity [true/false]
```
The number of threads used to serve requests. This should be related to the number of queues available in your network hardware, *not* the number of cores on your
machine. Because KeyDB uses spinlocks to reduce latency; making this too high will reduce performance. We recommend using 4 here. By default this is set to two.
```
min-clients-per-thread 50
```
The minimum number of clients on a thread before KeyDB assigns new connections to a different thread. Tuning this parameter is a tradeoff between locking overhead and distributing the workload over multiple cores
The number of threads used to serve requests. This should be related to the number of queues available in your network hardware, *not* the number of cores on your machine. Because KeyDB uses spinlocks to reduce latency; making this too high will reduce performance. We recommend using 4 here. By default this is set to one.
```
replica-weighting-factor 2
```
KeyDB will attempt to balance clients across threads evenly; However, replica clients are usually much more expensive than a normal client, and so KeyDB will try to assign fewer clients to threads with a replica. The weighting factor below is intented to help tune this behavior. A replica weighting factor of 2 means we treat a replica as the equivalent of two normal clients. Adjusting this value may improve performance when replication is used. The best weighting is workload specific - e.g. read heavy workloads should set this to 1. Very write heavy workloads may benefit from higher numbers.
scratch-file-path /path
```
active-client-balancing yes
```
Should KeyDB make active attempts at balancing clients across threads? This can impact performance accepting new clients. By default this is enabled. If disabled there is still a best effort from the kernel to distribute across threads with SO_REUSEPORT but it will not be as fair. By default this is enabled
```
active-replica yes
```
If you are using active-active replication set `active-replica` option to “yes”. This will enable both instances to accept reads and writes while remaining synced. [Click here](https://docs.keydb.dev/docs/active-rep/) to see more on active-rep in our docs section. There are also [docker examples]( https://docs.keydb.dev/docs/docker-active-rep/) on docs.
```
multi-master-no-forward no
```
Avoid forwarding RREPLAY messages to other masters? WARNING: This setting is dangerous! You must be certain all masters are connected to eachother in a true mesh topology or data loss will occur! This command can be used to reduce multimaster bus traffic
```
If you would like to use the [FLASH backed](https://github.com/JohnSully/KeyDB/wiki/FLASH-Storage) storage this option configures the directory for KeyDB's temporary files. This feature relies on snapshotting to work so must be used on a BTRFS filesystem. ZFS may also work but is untested. With this feature KeyDB will use RAM as a cache and page to disk as necessary. NOTE: This requires special compilation options, see Building KeyDB below.
db-s3-object /path/to/bucket
```
If you would like KeyDB to dump and load directly to AWS S3 this option specifies the bucket. Using this option with the traditional RDB options will result in KeyDB backing up twice to both locations. If both are specified KeyDB will first attempt to load from the local dump file and if that fails load from S3. This requires the AWS CLI tools to be installed and configured which are used under the hood to transfer the data.
active-replica yes
```
storage-provider flash /path/to/flash
```
If you would like to use KeyDB FLASH storage, specify the storage medium followed by the directory path on your local SSD volume. Note that this feature is still considered experimental and should be used with discretion. See [FLASH Documentation](https://docs.keydb.dev/docs/flash) for more details on configuration and setting up your FLASH volume.
If you are using active-active replication set `active-replica` option to “yes”. This will enable both instances to accept reads and writes while remaining synced. [Click here](https://docs.keydb.dev/docs/active-rep/) to see more on active-rep in our docs section. There are also [docker examples]( https://docs.keydb.dev/docs/docker-active-rep/) on docs.
All other configuration options behave as you'd expect. Your existing configuration files should continue to work unchanged.
Building KeyDB
--------------
@@ -117,18 +88,19 @@ KeyDB can be compiled and is tested for use on Linux. KeyDB currently relies on
More on CentOS/Archlinux/Alpine/Debian/Ubuntu dependencies and builds can be found here: https://docs.keydb.dev/docs/build/
Init and clone submodule dependencies:
% git submodule init && git submodule update
Install dependencies:
% sudo apt install build-essential nasm autotools-dev autoconf libjemalloc-dev tcl tcl-dev uuid-dev libcurl4-openssl-dev libbz2-dev libzstd-dev liblz4-dev libsnappy-dev libssl-dev
% sudo apt install build-essential nasm autotools-dev autoconf libjemalloc-dev tcl tcl-dev uuid-dev libcurl4-openssl-dev
Compiling is as simple as:
% make
To build with TLS support, you'll need OpenSSL development libraries (e.g.
libssl-dev on Debian/Ubuntu) and run:
% make BUILD_TLS=yes
To build with systemd support, you'll need systemd development libraries (such
as libsystemd-dev on Debian/Ubuntu or systemd-devel on CentOS) and run:
@@ -141,22 +113,12 @@ To append a suffix to KeyDB program names, use:
***Note that the following dependencies may be needed:
% sudo apt-get install autoconf autotools-dev libnuma-dev libtool
To buik=ld with TLS support, use:
% make BUILD_TLS=yes
Running the tests with TLS enabled (you will need `tcl-tls`
If TLS is built, running the tests with TLS enabled (you will need `tcl-tls`
installed):
% ./utils/gen-test-certs.sh
% ./runtest --tls
To build with KeyDB FLASH support, use:
% make ENABLE_FLASH=yes
***Note that the KeyDB FLASH feature is considered experimental (beta) and should used with discretion
Fixing build problems with dependencies or cached build options
---------
@@ -209,18 +171,6 @@ To compile against jemalloc on Mac OS X systems, use:
% make MALLOC=jemalloc
Monotonic clock
---------------
By default, KeyDB will build using the POSIX clock_gettime function as the
monotonic clock source. On most modern systems, the internal processor clock
can be used to improve performance. Cautions can be found here:
http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/
To build with support for the processor's internal instruction clock, use:
% make CFLAGS="-DUSE_PROCESSOR_CLOCK"
Verbose build
-------------
@@ -253,11 +203,11 @@ All the options in keydb.conf are also supported as options using the command
line, with exactly the same name.
Running KeyDB with TLS:
Running Redis with TLS:
------------------
Please consult the [TLS.md](TLS.md) file for more information on
how to use KeyDB with TLS.
how to use Redis with TLS.
Playing with KeyDB
@@ -317,6 +267,24 @@ KeyDB works by running the normal Redis event loop on multiple threads. Network
Unlike most databases the core data structure is the fastest part of the system. Most of the query time comes from parsing the REPL protocol and copying data to/from the network.
Future work:
- Allow rebalancing of connections to different threads after the connection
- Allow multiple readers access to the hashtable concurrently
Docker Build
------------
Build the latest binaries from the github unstable branch within a docker container. Note this is built for Ubuntu 18.04.
Simply make a directory you would like to have the latest binaries dumped in, then run the following commmand with your updated path:
```
$ docker run -it --rm -v /path-to-dump-binaries:/keydb_bin eqalpha/keydb-build-bin
```
You should receive the following files: keydb-benchmark, keydb-check-aof, keydb-check-rdb, keydb-cli, keydb-sentinel, keydb-server
If you are looking to enable flash support with the build (make MALLOC=memkind) then use the following command:
```
$ docker run -it --rm -v /path-to-dump-binaries:/keydb_bin eqalpha/keydb-build-bin:flash
```
Please note that you will need libcurl4-openssl-dev in order to run keydb. With flash version you may need libnuma-dev and libtool installed in order to run the binaries. Keep this in mind especially when running in a container. For a copy of all our Dockerfiles, please see them on [docs]( https://docs.keydb.dev/docs/dockerfiles/).
Code contributions
-----------------
+17 -14
View File
@@ -6,17 +6,20 @@ Getting Started
### Building
TLS support is enabled in the default build. To build without TLS, run `make BUILD_TLS=no`.
To build with TLS support you'll need OpenSSL development libraries (e.g.
libssl-dev on Debian/Ubuntu).
Run `make BUILD_TLS=yes`.
### Tests
To run KeyDB test suite with TLS, you'll need TLS support for TCL (i.e.
To run Redis test suite with TLS, you'll need TLS support for TCL (i.e.
`tcl-tls` package on Debian/Ubuntu).
1. Run `./utils/gen-test-certs.sh` to generate a root CA and a server
certificate.
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run KeyDB and KeyDB
2. Run `./runtest --tls` or `./runtest-cluster --tls` to run Redis and Redis
Cluster tests in TLS mode.
### Running manually
@@ -24,23 +27,23 @@ To run KeyDB test suite with TLS, you'll need TLS support for TCL (i.e.
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
invoked so sample certificates/keys are available):
./src/keydb-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/client.crt \
--tls-key-file ./tests/tls/client.key \
./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt
To connect to this Redis server with `keydb-cli`:
To connect to this Redis server with `redis-cli`:
./src/keydb-cli --tls \
--cert ./tests/tls/keydb.crt \
--key ./tests/tls/keydb.key \
./src/redis-cli --tls \
--cert ./tests/tls/redis.crt \
--key ./tests/tls/redis.key \
--cacert ./tests/tls/ca.crt
This will disable TCP and enable TLS on port 6379. It's also possible to have
both TCP and TLS available, but you'll need to assign different ports.
To make a Replica connect to the master using TLS, use `--tls-replication yes`,
and to make KeyDB Cluster use TLS across nodes use `--tls-cluster yes`.
and to make Redis Cluster use TLS across nodes use `--tls-cluster yes`.
Connections
-----------
@@ -53,18 +56,18 @@ Note that unlike Redis, KeyDB fully supports multithreading of TLS connections.
To-Do List
----------
- [ ] keydb-benchmark support. The current implementation is a mix of using
- [ ] redis-benchmark support. The current implementation is a mix of using
hiredis for parsing and basic networking (establishing connections), but
directly manipulating sockets for most actions. This will need to be cleaned
up for proper TLS support. The best approach is probably to migrate to hiredis
async mode.
- [ ] keydb-cli `--slave` and `--rdb` support.
- [ ] redis-cli `--slave` and `--rdb` support.
Multi-port
----------
Consider the implications of allowing TLS to be configured on a separate port,
making KeyDB listening on multiple ports:
making Redis listening on multiple ports:
1. Startup banner port notification
2. Proctitle
+3 -22
View File
@@ -1,7 +1,6 @@
# Redis dependency Makefile
uname_S:= $(shell sh -c 'uname -s 2>/dev/null || echo not')
uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
CCCOLOR="\033[34m"
LINKCOLOR="\033[34;1m"
@@ -38,8 +37,6 @@ distclean:
-(cd linenoise && $(MAKE) clean) > /dev/null || true
-(cd lua && $(MAKE) clean) > /dev/null || true
-(cd jemalloc && [ -f Makefile ] && $(MAKE) distclean) > /dev/null || true
-(cd rocksdb && $(MAKE) clean) > /dev/null || true
-(cd hdr_histogram && $(MAKE) clean) > /dev/null || true
-(rm -f .make-*)
.PHONY: distclean
@@ -65,24 +62,18 @@ memkind:
cd memkind && $(MAKE)
hdr_histogram: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd hdr_histogram && $(MAKE)
.PHONY: hdr_histogram
ifeq ($(uname_S),SunOS)
# Make isinf() available
LUA_CFLAGS= -D__C99FEATURES__=1
endif
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -DLUA_USE_MKSTEMP $(CFLAGS)
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' $(CFLAGS)
LUA_LDFLAGS+= $(LDFLAGS)
# lua's Makefile defines AR="ar rcu", which is unusual, and makes it more
# challenging to cross-compile lua (and redis). These defines make it easier
# to fit redis into cross-compilation environments, which typically set AR.
AR=ar
ARFLAGS=rc
ARFLAGS=rcu
lua: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
@@ -95,17 +86,7 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
jemalloc: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd jemalloc && ./configure --with-version=5.2.1-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ --disable-cxx CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
cd jemalloc && ./configure --with-version=5.1.0-0-g0 --with-lg-quantum=3 --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
.PHONY: jemalloc
rocksdb: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
ifeq ($(uname_M),x86_64)
cd rocksdb && CFLAGS=-Wno-error PORTABLE=1 USE_SSE=1 FORCE_SSE42=1 $(MAKE) static_lib
else
cd rocksdb && PORTABLE=1 $(MAKE) static_lib
endif
.PHONY: rocksdb
+1 -1
View File
@@ -17,7 +17,7 @@ active defragmentation logic. However this feature of Redis is not mandatory
and Redis is able to understand if the Jemalloc version it is compiled
against supports such Redis-specific modifications. So in theory, if you
are not interested in the active defragmentation, you can replace Jemalloc
just following these steps:
just following tose steps:
1. Remove the jemalloc directory.
2. Substitute it with the new jemalloc source tree.
-583
View File
@@ -1,583 +0,0 @@
// Provides an efficient blocking version of moodycamel::ConcurrentQueue.
// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified
// BSD license, available at the top of concurrentqueue.h.
// Also dual-licensed under the Boost Software License (see LICENSE.md)
// Uses Jeff Preshing's semaphore implementation (under the terms of its
// separate zlib license, see lightweightsemaphore.h).
#pragma once
#include "concurrentqueue.h"
#include "lightweightsemaphore.h"
#include <type_traits>
#include <cerrno>
#include <memory>
#include <chrono>
#include <ctime>
namespace moodycamel
{
// This is a blocking version of the queue. It has an almost identical interface to
// the normal non-blocking version, with the addition of various wait_dequeue() methods
// and the removal of producer-specific dequeue methods.
template<typename T, typename Traits = ConcurrentQueueDefaultTraits>
class BlockingConcurrentQueue
{
private:
typedef ::moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue;
typedef ::moodycamel::LightweightSemaphore LightweightSemaphore;
public:
typedef typename ConcurrentQueue::producer_token_t producer_token_t;
typedef typename ConcurrentQueue::consumer_token_t consumer_token_t;
typedef typename ConcurrentQueue::index_t index_t;
typedef typename ConcurrentQueue::size_t size_t;
typedef typename std::make_signed<size_t>::type ssize_t;
static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE;
static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD;
static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE;
static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE;
static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE;
static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE;
static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE;
public:
// Creates a queue with at least `capacity` element slots; note that the
// actual number of elements that can be inserted without additional memory
// allocation depends on the number of producers and the block size (e.g. if
// the block size is equal to `capacity`, only a single block will be allocated
// up-front, which means only a single producer will be able to enqueue elements
// without an extra allocation -- blocks aren't shared between producers).
// This method is not thread safe -- it is up to the user to ensure that the
// queue is fully constructed before it starts being used by other threads (this
// includes making the memory effects of construction visible, possibly with a
// memory barrier).
explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)
: inner(capacity), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member");
if (!sema) {
MOODYCAMEL_THROW(std::bad_alloc());
}
}
BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)
: inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member");
if (!sema) {
MOODYCAMEL_THROW(std::bad_alloc());
}
}
// Disable copying and copy assignment
BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
// Moving is supported, but note that it is *not* a thread-safe operation.
// Nobody can use the queue while it's being moved, and the memory effects
// of that move must be propagated to other threads before they can use it.
// Note: When a queue is moved, its tokens are still valid but can only be
// used with the destination queue (i.e. semantically they are moved along
// with the queue itself).
BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
: inner(std::move(other.inner)), sema(std::move(other.sema))
{ }
inline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
{
return swap_internal(other);
}
// Swaps this queue's state with the other's. Not thread-safe.
// Swapping two queues does not invalidate their tokens, however
// the tokens that were created for one queue must be used with
// only the swapped queue (i.e. the tokens are tied to the
// queue's movable state, not the object itself).
inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT
{
swap_internal(other);
}
private:
BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other)
{
if (this == &other) {
return *this;
}
inner.swap(other.inner);
sema.swap(other.sema);
return *this;
}
public:
// Enqueues a single item (by copying it).
// Allocates memory if required. Only fails if memory allocation fails (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(T const& item)
{
if ((details::likely)(inner.enqueue(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible).
// Allocates memory if required. Only fails if memory allocation fails (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(T&& item)
{
if ((details::likely)(inner.enqueue(std::move(item)))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by copying it) using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails (or
// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(producer_token_t const& token, T const& item)
{
if ((details::likely)(inner.enqueue(token, item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible) using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails (or
// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(producer_token_t const& token, T&& item)
{
if ((details::likely)(inner.enqueue(token, std::move(item)))) {
sema->signal();
return true;
}
return false;
}
// Enqueues several items.
// Allocates memory if required. Only fails if memory allocation fails (or
// implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
// is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Note: Use std::make_move_iterator if the elements should be moved instead of copied.
// Thread-safe.
template<typename It>
inline bool enqueue_bulk(It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(std::forward<It>(itemFirst), count))) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues several items using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails
// (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(token, std::forward<It>(itemFirst), count))) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues a single item (by copying it).
// Does not allocate memory. Fails if not enough room to enqueue (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
// is 0).
// Thread-safe.
inline bool try_enqueue(T const& item)
{
if (inner.try_enqueue(item)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible).
// Does not allocate memory (except for one-time implicit producer).
// Fails if not enough room to enqueue (or implicit production is
// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
// Thread-safe.
inline bool try_enqueue(T&& item)
{
if (inner.try_enqueue(std::move(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by copying it) using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Thread-safe.
inline bool try_enqueue(producer_token_t const& token, T const& item)
{
if (inner.try_enqueue(token, item)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible) using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Thread-safe.
inline bool try_enqueue(producer_token_t const& token, T&& item)
{
if (inner.try_enqueue(token, std::move(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues several items.
// Does not allocate memory (except for one-time implicit producer).
// Fails if not enough room to enqueue (or implicit production is
// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool try_enqueue_bulk(It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(std::forward<It>(itemFirst), count)) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues several items using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(token, std::forward<It>(itemFirst), count)) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Attempts to dequeue from the queue.
// Returns false if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename U>
inline bool try_dequeue(U& item)
{
if (sema->tryWait()) {
while (!inner.try_dequeue(item)) {
continue;
}
return true;
}
return false;
}
// Attempts to dequeue from the queue using an explicit consumer token.
// Returns false if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename U>
inline bool try_dequeue(consumer_token_t& token, U& item)
{
if (sema->tryWait()) {
while (!inner.try_dequeue(token, item)) {
continue;
}
return true;
}
return false;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued.
// Returns 0 if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename It>
inline size_t try_dequeue_bulk(It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued.
// Returns 0 if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename It>
inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Blocks the current thread until there's something to dequeue, then
// dequeues it.
// Never allocates. Thread-safe.
template<typename U>
inline void wait_dequeue(U& item)
{
while (!sema->wait()) {
continue;
}
while (!inner.try_dequeue(item)) {
continue;
}
}
// Blocks the current thread until either there's something to dequeue
// or the timeout (specified in microseconds) expires. Returns false
// without setting `item` if the timeout expires, otherwise assigns
// to `item` and returns true.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
// Never allocates. Thread-safe.
template<typename U>
inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs)
{
if (!sema->wait(timeout_usecs)) {
return false;
}
while (!inner.try_dequeue(item)) {
continue;
}
return true;
}
// Blocks the current thread until either there's something to dequeue
// or the timeout expires. Returns false without setting `item` if the
// timeout expires, otherwise assigns to `item` and returns true.
// Never allocates. Thread-safe.
template<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Blocks the current thread until there's something to dequeue, then
// dequeues it using an explicit consumer token.
// Never allocates. Thread-safe.
template<typename U>
inline void wait_dequeue(consumer_token_t& token, U& item)
{
while (!sema->wait()) {
continue;
}
while (!inner.try_dequeue(token, item)) {
continue;
}
}
// Blocks the current thread until either there's something to dequeue
// or the timeout (specified in microseconds) expires. Returns false
// without setting `item` if the timeout expires, otherwise assigns
// to `item` and returns true.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
// Never allocates. Thread-safe.
template<typename U>
inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs)
{
if (!sema->wait(timeout_usecs)) {
return false;
}
while (!inner.try_dequeue(token, item)) {
continue;
}
return true;
}
// Blocks the current thread until either there's something to dequeue
// or the timeout expires. Returns false without setting `item` if the
// timeout expires, otherwise assigns to `item` and returns true.
// Never allocates. Thread-safe.
template<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(token, item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which will
// always be at least one (this method blocks until the queue
// is non-empty) and at most max.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk(It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue_bulk.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Never allocates. Thread-safe.
template<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which will
// always be at least one (this method blocks until the queue
// is non-empty) and at most max.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue_bulk.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Never allocates. Thread-safe.
template<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(token, itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Returns an estimate of the total number of elements currently in the queue. This
// estimate is only accurate if the queue has completely stabilized before it is called
// (i.e. all enqueue and dequeue operations have completed and their memory effects are
// visible on the calling thread, and no further operations start while this method is
// being called).
// Thread-safe.
inline size_t size_approx() const
{
return (size_t)sema->availableApprox();
}
// Returns true if the underlying atomic variables used by
// the queue are lock-free (they should be on most platforms).
// Thread-safe.
static bool is_lock_free()
{
return ConcurrentQueue::is_lock_free();
}
private:
template<typename U, typename A1, typename A2>
static inline U* create(A1&& a1, A2&& a2)
{
void* p = (Traits::malloc)(sizeof(U));
return p != nullptr ? new (p) U(std::forward<A1>(a1), std::forward<A2>(a2)) : nullptr;
}
template<typename U>
static inline void destroy(U* p)
{
if (p != nullptr) {
p->~U();
}
(Traits::free)(p);
}
private:
ConcurrentQueue inner;
std::unique_ptr<LightweightSemaphore, void (*)(LightweightSemaphore*)> sema;
};
template<typename T, typename Traits>
inline void swap(BlockingConcurrentQueue<T, Traits>& a, BlockingConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT
{
a.swap(b);
}
} // end namespace moodycamel
File diff suppressed because it is too large. Load diff
-412
View File
@@ -1,412 +0,0 @@
// Provides an efficient implementation of a semaphore (LightweightSemaphore).
// This is an extension of Jeff Preshing's sempahore implementation (licensed
// under the terms of its separate zlib license) that has been adapted and
// extended by Cameron Desrochers.
#pragma once
#include <cstddef> // For std::size_t
#include <atomic>
#include <type_traits> // For std::make_signed<T>
#if defined(_WIN32)
// Avoid including windows.h in a header; we only need a handful of
// items, so we'll redeclare them here (this is relatively safe since
// the API generally has to remain stable between Windows versions).
// I know this is an ugly hack but it still beats polluting the global
// namespace with thousands of generic names or adding a .cpp for nothing.
extern "C" {
struct _SECURITY_ATTRIBUTES;
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName);
__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount);
}
#elif defined(__MACH__)
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#endif
namespace moodycamel
{
namespace details
{
// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's
// portable + lightweight semaphore implementations, originally from
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
// LICENSE:
// Copyright (c) 2015 Jeff Preshing
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#if defined(_WIN32)
class Semaphore
{
private:
void* m_hSema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
const long maxLong = 0x7fffffff;
m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
assert(m_hSema);
}
~Semaphore()
{
CloseHandle(m_hSema);
}
bool wait()
{
const unsigned long infinite = 0xffffffff;
return WaitForSingleObject(m_hSema, infinite) == 0;
}
bool try_wait()
{
return WaitForSingleObject(m_hSema, 0) == 0;
}
bool timed_wait(std::uint64_t usecs)
{
return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;
}
void signal(int count = 1)
{
while (!ReleaseSemaphore(m_hSema, count, nullptr));
}
};
#elif defined(__MACH__)
//---------------------------------------------------------
// Semaphore (Apple iOS and OSX)
// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
//---------------------------------------------------------
class Semaphore
{
private:
semaphore_t m_sema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
assert(rc == KERN_SUCCESS);
(void)rc;
}
~Semaphore()
{
semaphore_destroy(mach_task_self(), m_sema);
}
bool wait()
{
return semaphore_wait(m_sema) == KERN_SUCCESS;
}
bool try_wait()
{
return timed_wait(0);
}
bool timed_wait(std::uint64_t timeout_usecs)
{
mach_timespec_t ts;
ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
ts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000);
// added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
kern_return_t rc = semaphore_timedwait(m_sema, ts);
return rc == KERN_SUCCESS;
}
void signal()
{
while (semaphore_signal(m_sema) != KERN_SUCCESS);
}
void signal(int count)
{
while (count-- > 0)
{
while (semaphore_signal(m_sema) != KERN_SUCCESS);
}
}
};
#elif defined(__unix__)
//---------------------------------------------------------
// Semaphore (POSIX, Linux)
//---------------------------------------------------------
class Semaphore
{
private:
sem_t m_sema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
int rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount));
assert(rc == 0);
(void)rc;
}
~Semaphore()
{
sem_destroy(&m_sema);
}
bool wait()
{
// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
int rc;
do {
rc = sem_wait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool try_wait()
{
int rc;
do {
rc = sem_trywait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool timed_wait(std::uint64_t usecs)
{
struct timespec ts;
const int usecs_in_1_sec = 1000000;
const int nsecs_in_1_sec = 1000000000;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += (time_t)(usecs / usecs_in_1_sec);
ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000;
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
// so we have to clean things up before passing it in
if (ts.tv_nsec >= nsecs_in_1_sec) {
ts.tv_nsec -= nsecs_in_1_sec;
++ts.tv_sec;
}
int rc;
do {
rc = sem_timedwait(&m_sema, &ts);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
void signal()
{
while (sem_post(&m_sema) == -1);
}
void signal(int count)
{
while (count-- > 0)
{
while (sem_post(&m_sema) == -1);
}
}
};
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif
} // end namespace details
//---------------------------------------------------------
// LightweightSemaphore
//---------------------------------------------------------
class LightweightSemaphore
{
public:
typedef std::make_signed<std::size_t>::type ssize_t;
private:
std::atomic<ssize_t> m_count;
details::Semaphore m_sema;
int m_maxSpins;
bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1)
{
ssize_t oldCount;
int spin = m_maxSpins;
while (--spin >= 0)
{
oldCount = m_count.load(std::memory_order_relaxed);
if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
return true;
std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop.
}
oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
if (oldCount > 0)
return true;
if (timeout_usecs < 0)
{
if (m_sema.wait())
return true;
}
if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs))
return true;
// At this point, we've timed out waiting for the semaphore, but the
// count is still decremented indicating we may still be waiting on
// it. So we have to re-adjust the count, but only if the semaphore
// wasn't signaled enough times for us too since then. If it was, we
// need to release the semaphore too.
while (true)
{
oldCount = m_count.load(std::memory_order_acquire);
if (oldCount >= 0 && m_sema.try_wait())
return true;
if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
return false;
}
}
ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1)
{
assert(max > 0);
ssize_t oldCount;
int spin = m_maxSpins;
while (--spin >= 0)
{
oldCount = m_count.load(std::memory_order_relaxed);
if (oldCount > 0)
{
ssize_t newCount = oldCount > max ? oldCount - max : 0;
if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
return oldCount - newCount;
}
std::atomic_signal_fence(std::memory_order_acquire);
}
oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
if (oldCount <= 0)
{
if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs)))
{
while (true)
{
oldCount = m_count.load(std::memory_order_acquire);
if (oldCount >= 0 && m_sema.try_wait())
break;
if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
return 0;
}
}
}
if (max > 1)
return 1 + tryWaitMany(max - 1);
return 1;
}
public:
LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins)
{
assert(initialCount >= 0);
assert(maxSpins >= 0);
}
bool tryWait()
{
ssize_t oldCount = m_count.load(std::memory_order_relaxed);
while (oldCount > 0)
{
if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
return true;
}
return false;
}
bool wait()
{
return tryWait() || waitWithPartialSpinning();
}
bool wait(std::int64_t timeout_usecs)
{
return tryWait() || waitWithPartialSpinning(timeout_usecs);
}
// Acquires between 0 and (greedily) max, inclusive
ssize_t tryWaitMany(ssize_t max)
{
assert(max >= 0);
ssize_t oldCount = m_count.load(std::memory_order_relaxed);
while (oldCount > 0)
{
ssize_t newCount = oldCount > max ? oldCount - max : 0;
if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
return oldCount - newCount;
}
return 0;
}
// Acquires at least one, and (greedily) at most max
ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs)
{
assert(max >= 0);
ssize_t result = tryWaitMany(max);
if (result == 0 && max > 0)
result = waitManyWithPartialSpinning(max, timeout_usecs);
return result;
}
ssize_t waitMany(ssize_t max)
{
ssize_t result = waitMany(max, -1);
assert(result > 0);
return result;
}
void signal(ssize_t count = 1)
{
assert(count >= 0);
ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release);
ssize_t toRelease = -oldCount < count ? -oldCount : count;
if (toRelease > 0)
{
m_sema.signal((int)toRelease);
}
}
std::size_t availableApprox() const
{
ssize_t count = m_count.load(std::memory_order_relaxed);
return count > 0 ? static_cast<std::size_t>(count) : 0;
}
};
} // end namespace moodycamel
-121
View File
@@ -1,121 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
-41
View File
@@ -1,41 +0,0 @@
The code in this repository code was Written by Gil Tene, Michael Barker,
and Matt Warren, and released to the public domain, as explained at
http://creativecommons.org/publicdomain/zero/1.0/
For users of this code who wish to consume it under the "BSD" license
rather than under the public domain or CC0 contribution text mentioned
above, the code found under this directory is *also* provided under the
following license (commonly referred to as the BSD 2-Clause License). This
license does not detract from the above stated release of the code into
the public domain, and simply represents an additional license granted by
the Author.
-----------------------------------------------------------------------------
** Beginning of "BSD 2-Clause License" text. **
Copyright (c) 2012, 2013, 2014 Gil Tene
Copyright (c) 2014 Michael Barker
Copyright (c) 2014 Matt Warren
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-20
View File
@@ -1,20 +0,0 @@
STD=
WARN= -Wall
OPT= -Os
R_CFLAGS= $(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS)
R_LDFLAGS= $(LDFLAGS)
DEBUG= -g
R_CC=$(CC) $(R_CFLAGS)
R_LD=$(CC) $(R_LDFLAGS)
hdr_histogram.o: hdr_histogram.h hdr_histogram.c
.c.o:
$(R_CC) -c $<
clean:
rm -f *.o
-10
View File
@@ -1,10 +0,0 @@
HdrHistogram_c v0.11.0
----------------------------------------------
This port contains a subset of the 'C' version of High Dynamic Range (HDR) Histogram available at [github.com/HdrHistogram/HdrHistogram_c](https://github.com/HdrHistogram/HdrHistogram_c).
The code present on `hdr_histogram.c`, `hdr_histogram.h`, and `hdr_atomic.c` was Written by Gil Tene, Michael Barker,
and Matt Warren, and released to the public domain, as explained at
http://creativecommons.org/publicdomain/zero/1.0/.
-146
View File
@@ -1,146 +0,0 @@
/**
* hdr_atomic.h
* Written by Philip Orwig and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
#ifndef HDR_ATOMIC_H__
#define HDR_ATOMIC_H__
#if defined(_MSC_VER)
#include <stdint.h>
#include <intrin.h>
#include <stdbool.h>
static void __inline * hdr_atomic_load_pointer(void** pointer)
{
_ReadBarrier();
return *pointer;
}
static void hdr_atomic_store_pointer(void** pointer, void* value)
{
_WriteBarrier();
*pointer = value;
}
static int64_t __inline hdr_atomic_load_64(int64_t* field)
{
_ReadBarrier();
return *field;
}
static void __inline hdr_atomic_store_64(int64_t* field, int64_t value)
{
_WriteBarrier();
*field = value;
}
static int64_t __inline hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
{
#if defined(_WIN64)
return _InterlockedExchange64(field, value);
#else
int64_t comparand;
int64_t initial_value = *field;
do
{
comparand = initial_value;
initial_value = _InterlockedCompareExchange64(field, value, comparand);
}
while (comparand != initial_value);
return initial_value;
#endif
}
static int64_t __inline hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
{
#if defined(_WIN64)
return _InterlockedExchangeAdd64(field, value) + value;
#else
int64_t comparand;
int64_t initial_value = *field;
do
{
comparand = initial_value;
initial_value = _InterlockedCompareExchange64(field, comparand + value, comparand);
}
while (comparand != initial_value);
return initial_value + value;
#endif
}
static bool __inline hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
{
return *expected == _InterlockedCompareExchange64(field, desired, *expected);
}
#elif defined(__ATOMIC_SEQ_CST)
#define hdr_atomic_load_pointer(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
#define hdr_atomic_store_pointer(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
#define hdr_atomic_load_64(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
#define hdr_atomic_store_64(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
#define hdr_atomic_exchange_64(f,i) __atomic_exchange_n(f,i, __ATOMIC_SEQ_CST)
#define hdr_atomic_add_fetch_64(field, value) __atomic_add_fetch(field, value, __ATOMIC_SEQ_CST)
#define hdr_atomic_compare_exchange_64(field, expected, desired) __atomic_compare_exchange_n(field, expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#elif defined(__x86_64__)
#include <stdint.h>
#include <stdbool.h>
static inline void* hdr_atomic_load_pointer(void** pointer)
{
void* p = *pointer;
asm volatile ("" ::: "memory");
return p;
}
static inline void hdr_atomic_store_pointer(void** pointer, void* value)
{
asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*pointer));
}
static inline int64_t hdr_atomic_load_64(int64_t* field)
{
int64_t i = *field;
asm volatile ("" ::: "memory");
return i;
}
static inline void hdr_atomic_store_64(int64_t* field, int64_t value)
{
asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*field));
}
static inline int64_t hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
{
int64_t result = 0;
asm volatile ("lock; xchgq %1, %2" : "=r" (result), "+q" (value), "+m" (*field));
return result;
}
static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
{
return __sync_add_and_fetch(field, value);
}
static inline bool hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
{
int64_t original;
asm volatile( "lock; cmpxchgq %2, %1" : "=a"(original), "+m"(*field) : "q"(desired), "0"(*expected));
return original == *expected;
}
#else
#error "Unable to determine atomic operations for your platform"
#endif
#endif /* HDR_ATOMIC_H__ */
-1155
View File
File diff suppressed because it is too large. Load diff
-509
View File
@@ -1,509 +0,0 @@
/**
* hdr_histogram.h
* Written by Michael Barker and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*
* The source for the hdr_histogram utilises a few C99 constructs, specifically
* the use of stdint/stdbool and inline variable declaration.
*/
#ifndef HDR_HISTOGRAM_H
#define HDR_HISTOGRAM_H 1
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
struct hdr_histogram
{
int64_t lowest_trackable_value;
int64_t highest_trackable_value;
int32_t unit_magnitude;
int32_t significant_figures;
int32_t sub_bucket_half_count_magnitude;
int32_t sub_bucket_half_count;
int64_t sub_bucket_mask;
int32_t sub_bucket_count;
int32_t bucket_count;
int64_t min_value;
int64_t max_value;
int32_t normalizing_index_offset;
double conversion_ratio;
int32_t counts_len;
int64_t total_count;
int64_t* counts;
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* Allocate the memory and initialise the hdr_histogram.
*
* Due to the size of the histogram being the result of some reasonably
* involved math on the input parameters this function it is tricky to stack allocate.
* The histogram should be released with hdr_close
*
* @param lowest_trackable_value The smallest possible value to be put into the
* histogram.
* @param highest_trackable_value The largest possible value to be put into the
* histogram.
* @param significant_figures The level of precision for this histogram, i.e. the number
* of figures in a decimal number that will be maintained. E.g. a value of 3 will mean
* the results from the histogram will be accurate up to the first three digits. Must
* be a value between 1 and 5 (inclusive).
* @param result Output parameter to capture allocated histogram.
* @return 0 on success, EINVAL if lowest_trackable_value is < 1 or the
* significant_figure value is outside of the allowed range, ENOMEM if malloc
* failed.
*/
int hdr_init(
int64_t lowest_trackable_value,
int64_t highest_trackable_value,
int significant_figures,
struct hdr_histogram** result);
/**
* Free the memory and close the hdr_histogram.
*
* @param h The histogram you want to close.
*/
void hdr_close(struct hdr_histogram* h);
/**
* Allocate the memory and initialise the hdr_histogram. This is the equivalent of calling
* hdr_init(1, highest_trackable_value, significant_figures, result);
*
* @deprecated use hdr_init.
*/
int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result);
/**
* Reset a histogram to zero - empty out a histogram and re-initialise it
*
* If you want to re-use an existing histogram, but reset everything back to zero, this
* is the routine to use.
*
* @param h The histogram you want to reset to empty.
*
*/
void hdr_reset(struct hdr_histogram* h);
/**
* Get the memory size of the hdr_histogram.
*
* @param h "This" pointer
* @return The amount of memory used by the hdr_histogram in bytes
*/
size_t hdr_get_memory_size(struct hdr_histogram* h);
/**
* Records a value in the histogram, will round this value of to a precision at or better
* than the significant_figure specified at construction time.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_value(struct hdr_histogram* h, int64_t value);
/**
* Records a value in the histogram, will round this value of to a precision at or better
* than the significant_figure specified at construction time.
*
* Will record this value atomically, however the whole structure may appear inconsistent
* when read concurrently with this update. Do NOT mix calls to this method with calls
* to non-atomic updates.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value);
/**
* Records count values in the histogram, will round this value of to a
* precision at or better than the significant_figure specified at construction
* time.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @param count Number of 'value's to add to the histogram
* @return false if any value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count);
/**
* Records count values in the histogram, will round this value of to a
* precision at or better than the significant_figure specified at construction
* time.
*
* Will record this value atomically, however the whole structure may appear inconsistent
* when read concurrently with this update. Do NOT mix calls to this method with calls
* to non-atomic updates.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @param count Number of 'value's to add to the histogram
* @return false if any value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count);
/**
* Record a value in the histogram and backfill based on an expected interval.
*
* Records a value in the histogram, will round this value of to a precision at or better
* than the significant_figure specified at contruction time. This is specifically used
* for recording latency. If the value is larger than the expected_interval then the
* latency recording system has experienced co-ordinated omission. This method fills in the
* values that would have occured had the client providing the load not been blocked.
* @param h "This" pointer
* @param value Value to add to the histogram
* @param expected_interval The delay between recording values.
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval);
/**
* Record a value in the histogram and backfill based on an expected interval.
*
* Records a value in the histogram, will round this value of to a precision at or better
* than the significant_figure specified at contruction time. This is specifically used
* for recording latency. If the value is larger than the expected_interval then the
* latency recording system has experienced co-ordinated omission. This method fills in the
* values that would have occured had the client providing the load not been blocked.
*
* Will record this value atomically, however the whole structure may appear inconsistent
* when read concurrently with this update. Do NOT mix calls to this method with calls
* to non-atomic updates.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @param expected_interval The delay between recording values.
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expexcted_interval);
/**
* Record a value in the histogram 'count' times. Applies the same correcting logic
* as 'hdr_record_corrected_value'.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @param count Number of 'value's to add to the histogram
* @param expected_interval The delay between recording values.
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval);
/**
* Record a value in the histogram 'count' times. Applies the same correcting logic
* as 'hdr_record_corrected_value'.
*
* Will record this value atomically, however the whole structure may appear inconsistent
* when read concurrently with this update. Do NOT mix calls to this method with calls
* to non-atomic updates.
*
* @param h "This" pointer
* @param value Value to add to the histogram
* @param count Number of 'value's to add to the histogram
* @param expected_interval The delay between recording values.
* @return false if the value is larger than the highest_trackable_value and can't be recorded,
* true otherwise.
*/
bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval);
/**
* Adds all of the values from 'from' to 'this' histogram. Will return the
* number of values that are dropped when copying. Values will be dropped
* if they around outside of h.lowest_trackable_value and
* h.highest_trackable_value.
*
* @param h "This" pointer
* @param from Histogram to copy values from.
* @return The number of values dropped when copying.
*/
int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from);
/**
* Adds all of the values from 'from' to 'this' histogram. Will return the
* number of values that are dropped when copying. Values will be dropped
* if they around outside of h.lowest_trackable_value and
* h.highest_trackable_value.
*
* @param h "This" pointer
* @param from Histogram to copy values from.
* @return The number of values dropped when copying.
*/
int64_t hdr_add_while_correcting_for_coordinated_omission(
struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval);
/**
* Get minimum value from the histogram. Will return 2^63-1 if the histogram
* is empty.
*
* @param h "This" pointer
*/
int64_t hdr_min(const struct hdr_histogram* h);
/**
* Get maximum value from the histogram. Will return 0 if the histogram
* is empty.
*
* @param h "This" pointer
*/
int64_t hdr_max(const struct hdr_histogram* h);
/**
* Get the value at a specific percentile.
*
* @param h "This" pointer.
* @param percentile The percentile to get the value for
*/
int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile);
/**
* Gets the standard deviation for the values in the histogram.
*
* @param h "This" pointer
* @return The standard deviation
*/
double hdr_stddev(const struct hdr_histogram* h);
/**
* Gets the mean for the values in the histogram.
*
* @param h "This" pointer
* @return The mean
*/
double hdr_mean(const struct hdr_histogram* h);
/**
* Determine if two values are equivalent with the histogram's resolution.
* Where "equivalent" means that value samples recorded for any two
* equivalent values are counted in a common total count.
*
* @param h "This" pointer
* @param a first value to compare
* @param b second value to compare
* @return 'true' if values are equivalent with the histogram's resolution.
*/
bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b);
/**
* Get the lowest value that is equivalent to the given value within the histogram's resolution.
* Where "equivalent" means that value samples recorded for any two
* equivalent values are counted in a common total count.
*
* @param h "This" pointer
* @param value The given value
* @return The lowest value that is equivalent to the given value within the histogram's resolution.
*/
int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value);
/**
* Get the count of recorded values at a specific value
* (to within the histogram resolution at the value level).
*
* @param h "This" pointer
* @param value The value for which to provide the recorded count
* @return The total count of values recorded in the histogram within the value range that is
* {@literal >=} lowestEquivalentValue(<i>value</i>) and {@literal <=} highestEquivalentValue(<i>value</i>)
*/
int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value);
int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index);
int64_t hdr_value_at_index(const struct hdr_histogram* h, int32_t index);
struct hdr_iter_percentiles
{
bool seen_last_value;
int32_t ticks_per_half_distance;
double percentile_to_iterate_to;
double percentile;
};
struct hdr_iter_recorded
{
int64_t count_added_in_this_iteration_step;
};
struct hdr_iter_linear
{
int64_t value_units_per_bucket;
int64_t count_added_in_this_iteration_step;
int64_t next_value_reporting_level;
int64_t next_value_reporting_level_lowest_equivalent;
};
struct hdr_iter_log
{
double log_base;
int64_t count_added_in_this_iteration_step;
int64_t next_value_reporting_level;
int64_t next_value_reporting_level_lowest_equivalent;
};
/**
* The basic iterator. This is a generic structure
* that supports all of the types of iteration. Use
* the appropriate initialiser to get the desired
* iteration.
*
* @
*/
struct hdr_iter
{
const struct hdr_histogram* h;
/** raw index into the counts array */
int32_t counts_index;
/** snapshot of the length at the time the iterator is created */
int64_t total_count;
/** value directly from array for the current counts_index */
int64_t count;
/** sum of all of the counts up to and including the count at this index */
int64_t cumulative_count;
/** The current value based on counts_index */
int64_t value;
int64_t highest_equivalent_value;
int64_t lowest_equivalent_value;
int64_t median_equivalent_value;
int64_t value_iterated_from;
int64_t value_iterated_to;
union
{
struct hdr_iter_percentiles percentiles;
struct hdr_iter_recorded recorded;
struct hdr_iter_linear linear;
struct hdr_iter_log log;
} specifics;
bool (* _next_fp)(struct hdr_iter* iter);
};
/**
* Initalises the basic iterator.
*
* @param itr 'This' pointer
* @param h The histogram to iterate over
*/
void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h);
/**
* Initialise the iterator for use with percentiles.
*/
void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance);
/**
* Initialise the iterator for use with recorded values.
*/
void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h);
/**
* Initialise the iterator for use with linear values.
*/
void hdr_iter_linear_init(
struct hdr_iter* iter,
const struct hdr_histogram* h,
int64_t value_units_per_bucket);
/**
* Update the iterator value units per bucket
*/
void hdr_iter_linear_set_value_units_per_bucket(struct hdr_iter* iter, int64_t value_units_per_bucket);
/**
* Initialise the iterator for use with logarithmic values
*/
void hdr_iter_log_init(
struct hdr_iter* iter,
const struct hdr_histogram* h,
int64_t value_units_first_bucket,
double log_base);
/**
* Iterate to the next value for the iterator. If there are no more values
* available return faluse.
*
* @param itr 'This' pointer
* @return 'false' if there are no values remaining for this iterator.
*/
bool hdr_iter_next(struct hdr_iter* iter);
typedef enum
{
CLASSIC,
CSV
} format_type;
/**
* Print out a percentile based histogram to the supplied stream. Note that
* this call will not flush the FILE, this is left up to the user.
*
* @param h 'This' pointer
* @param stream The FILE to write the output to
* @param ticks_per_half_distance The number of iteration steps per half-distance to 100%
* @param value_scale Scale the output values by this amount
* @param format_type Format to use, e.g. CSV.
* @return 0 on success, error code on failure. EIO if an error occurs writing
* the output.
*/
int hdr_percentiles_print(
struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance,
double value_scale, format_type format);
/**
* Internal allocation methods, used by hdr_dbl_histogram.
*/
struct hdr_histogram_bucket_config
{
int64_t lowest_trackable_value;
int64_t highest_trackable_value;
int64_t unit_magnitude;
int64_t significant_figures;
int32_t sub_bucket_half_count_magnitude;
int32_t sub_bucket_half_count;
int64_t sub_bucket_mask;
int32_t sub_bucket_count;
int32_t bucket_count;
int32_t counts_len;
};
int hdr_calculate_bucket_config(
int64_t lowest_trackable_value,
int64_t highest_trackable_value,
int significant_figures,
struct hdr_histogram_bucket_config* cfg);
void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg);
int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value);
int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t value);
int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value);
/**
* Used to reset counters after importing data manuallying into the histogram, used by the logging code
* and other custom serialisation tools.
*/
void hdr_reset_internal_counters(struct hdr_histogram* h);
#ifdef __cplusplus
}
#endif
#endif
-1
View File
@@ -6,4 +6,3 @@
/*.a
/*.pc
*.dSYM
tags
+9 -43
View File
@@ -1,4 +1,5 @@
language: c
sudo: false
compiler:
- gcc
- clang
@@ -7,34 +8,17 @@ os:
- linux
- osx
dist: bionic
branches:
only:
- staging
- trying
- master
- /^release\/.*$/
install:
- if [ "$BITS" == "64" ]; then
wget https://github.com/redis/redis/archive/6.0.6.tar.gz;
tar -xzvf 6.0.6.tar.gz;
pushd redis-6.0.6 && BUILD_TLS=yes make && export PATH=$PWD/src:$PATH && popd;
fi
before_script:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.6.2-10.13-HighSierra.pkg;
sudo installer -pkg MacPorts-2.6.2-10.13-HighSierra.pkg -target /;
export PATH=$PATH:/opt/local/bin && sudo port -v selfupdate;
sudo port -N install openssl redis;
fi;
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi
addons:
apt:
sources:
- sourceline: 'ppa:chris-lea/redis-server'
packages:
- libc6-dbg
- libc6-dev
@@ -43,20 +27,14 @@ addons:
- libc6-dbg:i386
- gcc-multilib
- g++-multilib
- libssl-dev
- libssl-dev:i386
- valgrind
- redis
env:
- BITS="32"
- BITS="64"
script:
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON";
if [ "$BITS" == "64" ]; then
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_SSL_TESTS:BOOL=ON";
fi;
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON";
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
@@ -80,24 +58,12 @@ script:
fi;
fi;
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
- make && make clean;
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
if [ "$BITS" == "64" ]; then
OPENSSL_PREFIX="$(ls -d /usr/local/Cellar/openssl@1.1/*)" USE_SSL=1 make;
fi;
else
USE_SSL=1 make;
fi;
- mkdir build/ && cd build/
- cmake .. ${EXTRA_CMAKE_OPTS}
- make VERBOSE=1
- if [ "$BITS" == "64" ]; then
TEST_SSL=1 SKIPS_AS_FAILS=1 ctest -V;
else
SKIPS_AS_FAILS=1 ctest -V;
fi;
- ctest -V
jobs:
matrix:
include:
# Windows MinGW cross compile on Linux
- os: linux
@@ -123,9 +89,9 @@ jobs:
- eval "${MATRIX_EVAL}"
install:
- choco install ninja
- choco install -y memurai-developer
script:
- mkdir build && cd build
- cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' amd64 '&&'
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=ON '&&' ninja -v
- ./hiredis-test.exe
- cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 &&
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release &&
ninja -v'
- ctest -V
+16 -162
View File
@@ -1,175 +1,28 @@
## [1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) - (2020-08-03)
Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada:
_A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed._ :sparkling_heart:
[Michael Grunder](https://github.com/michael-grunder), [Yossi Gottlieb](https://github.com/yossigo),
[Mark Nunberg](https://github.com/mnunberg), [Marcus Geelnard](https://github.com/mbitsnbites),
[Justin Brewer](https://github.com/justinbrewer), [Valentino Geron](https://github.com/valentinogeron),
[Minun Dragonation](https://github.com/dragonation), [Omri Steiner](https://github.com/OmriSteiner),
[Sangmoon Yi](https://github.com/jman-krafton), [Jinjiazh](https://github.com/jinjiazhang),
[Odin Hultgren Van Der Horst](https://github.com/Miniwoffer), [Muhammad Zahalqa](https://github.com/tryfinally),
[Nick Rivera](https://github.com/heronr), [Qi Yang](https://github.com/movebean),
[kevin1018](https://github.com/kevin1018)
[Full Changelog](https://github.com/redis/hiredis/compare/v0.14.1...v1.0.0)
### 1.0.0 (unreleased)
**BREAKING CHANGES**:
* `redisOptions` now has two timeout fields. One for connecting, and one for commands. If you're presently using `options->timeout` you will need to change it to use `options->connect_timeout`. (See [example](https://github.com/redis/hiredis/commit/38b5ae543f5c99eb4ccabbe277770fc6bc81226f#diff-86ba39d37aa829c8c82624cce4f049fbL36))
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
protocol errors. This is consistent with the RESP specification. On 32-bit
platforms, the upper bound is lowered to `SIZE_MAX`.
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now protocol errors. This is consistent
with the RESP specification. On 32-bit platforms, the upper bound is lowered to `SIZE_MAX`.
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
User code should compare this to `size_t` values as well. If it was used to
compare to other values, casting might be necessary or can be removed, if
casting was applied before.
**New features:**
- Support for RESP3
[\#697](https://github.com/redis/hiredis/pull/697),
[\#805](https://github.com/redis/hiredis/pull/805),
[\#819](https://github.com/redis/hiredis/pull/819),
[\#841](https://github.com/redis/hiredis/pull/841)
([Yossi Gottlieb](https://github.com/yossigo), [Michael Grunder](https://github.com/michael-grunder))
- Support for SSL connections
[\#645](https://github.com/redis/hiredis/pull/645),
[\#699](https://github.com/redis/hiredis/pull/699),
[\#702](https://github.com/redis/hiredis/pull/702),
[\#708](https://github.com/redis/hiredis/pull/708),
[\#711](https://github.com/redis/hiredis/pull/711),
[\#821](https://github.com/redis/hiredis/pull/821),
[more](https://github.com/redis/hiredis/pulls?q=is%3Apr+is%3Amerged+SSL)
([Mark Nunberg](https://github.com/mnunberg), [Yossi Gottlieb](https://github.com/yossigo))
- Run-time allocator injection
[\#800](https://github.com/redis/hiredis/pull/800)
([Michael Grunder](https://github.com/michael-grunder))
- Improved Windows support (including MinGW and Windows CI)
[\#652](https://github.com/redis/hiredis/pull/652),
[\#663](https://github.com/redis/hiredis/pull/663)
([Marcus Geelnard](https://www.bitsnbites.eu/author/m/))
- Adds support for distinct connect and command timeouts
[\#839](https://github.com/redis/hiredis/pull/839),
[\#829](https://github.com/redis/hiredis/pull/829)
([Valentino Geron](https://github.com/valentinogeron))
- Add generic pointer and destructor to `redisContext` that users can use for context.
[\#855](https://github.com/redis/hiredis/pull/855)
([Michael Grunder](https://github.com/michael-grunder))
**Closed issues (that involved code changes):**
- Makefile does not install TLS libraries [\#809](https://github.com/redis/hiredis/issues/809)
- redisConnectWithOptions should not set command timeout [\#722](https://github.com/redis/hiredis/issues/722), [\#829](https://github.com/redis/hiredis/pull/829) ([valentinogeron](https://github.com/valentinogeron))
- Fix integer overflow in `sdsrange` [\#827](https://github.com/redis/hiredis/issues/827)
- INFO & CLUSTER commands failed when using RESP3 [\#802](https://github.com/redis/hiredis/issues/802)
- Windows compatibility patches [\#687](https://github.com/redis/hiredis/issues/687), [\#838](https://github.com/redis/hiredis/issues/838), [\#842](https://github.com/redis/hiredis/issues/842)
- RESP3 PUSH messages incorrectly use pending callback [\#825](https://github.com/redis/hiredis/issues/825)
- Asynchronous PSUBSCRIBE command fails when using RESP3 [\#815](https://github.com/redis/hiredis/issues/815)
- New SSL API [\#804](https://github.com/redis/hiredis/issues/804), [\#813](https://github.com/redis/hiredis/issues/813)
- Hard-coded limit of nested reply depth [\#794](https://github.com/redis/hiredis/issues/794)
- Fix TCP_NODELAY in Windows/OSX [\#679](https://github.com/redis/hiredis/issues/679), [\#690](https://github.com/redis/hiredis/issues/690), [\#779](https://github.com/redis/hiredis/issues/779), [\#785](https://github.com/redis/hiredis/issues/785),
- Added timers to libev adapter. [\#778](https://github.com/redis/hiredis/issues/778), [\#795](https://github.com/redis/hiredis/pull/795)
- Initialization discards const qualifier [\#777](https://github.com/redis/hiredis/issues/777)
- \[BUG\]\[MinGW64\] Error setting socket timeout [\#775](https://github.com/redis/hiredis/issues/775)
- undefined reference to hi_malloc [\#769](https://github.com/redis/hiredis/issues/769)
- hiredis pkg-config file incorrectly ignores multiarch libdir spec'n [\#767](https://github.com/redis/hiredis/issues/767)
- Don't use -G to build shared object on Solaris [\#757](https://github.com/redis/hiredis/issues/757)
- error when make USE\_SSL=1 [\#748](https://github.com/redis/hiredis/issues/748)
- Allow to change SSL Mode [\#646](https://github.com/redis/hiredis/issues/646)
- hiredis/adapters/libevent.h memleak [\#618](https://github.com/redis/hiredis/issues/618)
- redisLibuvPoll crash when server closes the connetion [\#545](https://github.com/redis/hiredis/issues/545)
- about redisAsyncDisconnect question [\#518](https://github.com/redis/hiredis/issues/518)
- hiredis adapters libuv error for help [\#508](https://github.com/redis/hiredis/issues/508)
- API/ABI changes analysis [\#506](https://github.com/redis/hiredis/issues/506)
- Memory leak patch in Redis [\#502](https://github.com/redis/hiredis/issues/502)
- Remove the depth limitation [\#421](https://github.com/redis/hiredis/issues/421)
**Merged pull requests:**
- Move SSL management to a distinct private pointer [\#855](https://github.com/redis/hiredis/pull/855) ([michael-grunder](https://github.com/michael-grunder))
- Move include to sockcompat.h to maintain style [\#850](https://github.com/redis/hiredis/pull/850) ([michael-grunder](https://github.com/michael-grunder))
- Remove erroneous tag and add license to push example [\#849](https://github.com/redis/hiredis/pull/849) ([michael-grunder](https://github.com/michael-grunder))
- fix windows compiling with mingw [\#848](https://github.com/redis/hiredis/pull/848) ([rmalizia44](https://github.com/rmalizia44))
- Some Windows quality of life improvements. [\#846](https://github.com/redis/hiredis/pull/846) ([michael-grunder](https://github.com/michael-grunder))
- Use \_WIN32 define instead of WIN32 [\#845](https://github.com/redis/hiredis/pull/845) ([michael-grunder](https://github.com/michael-grunder))
- Non Linux CI fixes [\#844](https://github.com/redis/hiredis/pull/844) ([michael-grunder](https://github.com/michael-grunder))
- Resp3 oob push support [\#841](https://github.com/redis/hiredis/pull/841) ([michael-grunder](https://github.com/michael-grunder))
- fix \#785: defer TCP\_NODELAY in async tcp connections [\#836](https://github.com/redis/hiredis/pull/836) ([OmriSteiner](https://github.com/OmriSteiner))
- sdsrange overflow fix [\#830](https://github.com/redis/hiredis/pull/830) ([michael-grunder](https://github.com/michael-grunder))
- Use explicit pointer casting for c++ compatibility [\#826](https://github.com/redis/hiredis/pull/826) ([aureus1](https://github.com/aureus1))
- Document allocator injection and completeness fix in test.c [\#824](https://github.com/redis/hiredis/pull/824) ([michael-grunder](https://github.com/michael-grunder))
- Use unique names for allocator struct members [\#823](https://github.com/redis/hiredis/pull/823) ([michael-grunder](https://github.com/michael-grunder))
- New SSL API to replace redisSecureConnection\(\). [\#821](https://github.com/redis/hiredis/pull/821) ([yossigo](https://github.com/yossigo))
- Add logic to handle RESP3 push messages [\#819](https://github.com/redis/hiredis/pull/819) ([michael-grunder](https://github.com/michael-grunder))
- Use standrad isxdigit instead of custom helper function. [\#814](https://github.com/redis/hiredis/pull/814) ([tryfinally](https://github.com/tryfinally))
- Fix missing SSL build/install options. [\#812](https://github.com/redis/hiredis/pull/812) ([yossigo](https://github.com/yossigo))
- Add link to ABI tracker [\#808](https://github.com/redis/hiredis/pull/808) ([michael-grunder](https://github.com/michael-grunder))
- Resp3 verbatim string support [\#805](https://github.com/redis/hiredis/pull/805) ([michael-grunder](https://github.com/michael-grunder))
- Allow users to replace allocator and handle OOM everywhere. [\#800](https://github.com/redis/hiredis/pull/800) ([michael-grunder](https://github.com/michael-grunder))
- Remove nested depth limitation. [\#797](https://github.com/redis/hiredis/pull/797) ([michael-grunder](https://github.com/michael-grunder))
- Attempt to fix compilation on Solaris [\#796](https://github.com/redis/hiredis/pull/796) ([michael-grunder](https://github.com/michael-grunder))
- Support timeouts in libev adapater [\#795](https://github.com/redis/hiredis/pull/795) ([michael-grunder](https://github.com/michael-grunder))
- Fix pkgconfig when installing to a custom lib dir [\#793](https://github.com/redis/hiredis/pull/793) ([michael-grunder](https://github.com/michael-grunder))
- Fix USE\_SSL=1 make/cmake on OSX and CMake tests [\#789](https://github.com/redis/hiredis/pull/789) ([michael-grunder](https://github.com/michael-grunder))
- Use correct libuv call on Windows [\#784](https://github.com/redis/hiredis/pull/784) ([michael-grunder](https://github.com/michael-grunder))
- Added CMake package config and fixed hiredis\_ssl on Windows [\#783](https://github.com/redis/hiredis/pull/783) ([michael-grunder](https://github.com/michael-grunder))
- CMake: Set hiredis\_ssl shared object version. [\#780](https://github.com/redis/hiredis/pull/780) ([yossigo](https://github.com/yossigo))
- Win32 tests and timeout fix [\#776](https://github.com/redis/hiredis/pull/776) ([michael-grunder](https://github.com/michael-grunder))
- Provides an optional cleanup callback for async data. [\#768](https://github.com/redis/hiredis/pull/768) ([heronr](https://github.com/heronr))
- Housekeeping fixes [\#764](https://github.com/redis/hiredis/pull/764) ([michael-grunder](https://github.com/michael-grunder))
- install alloc.h [\#756](https://github.com/redis/hiredis/pull/756) ([ch1aki](https://github.com/ch1aki))
- fix spelling mistakes [\#746](https://github.com/redis/hiredis/pull/746) ([ShooterIT](https://github.com/ShooterIT))
- Free the reply in redisGetReply when passed NULL [\#741](https://github.com/redis/hiredis/pull/741) ([michael-grunder](https://github.com/michael-grunder))
- Fix dead code in sslLogCallback relating to should\_log variable. [\#737](https://github.com/redis/hiredis/pull/737) ([natoscott](https://github.com/natoscott))
- Fix typo in dict.c. [\#731](https://github.com/redis/hiredis/pull/731) ([Kevin-Xi](https://github.com/Kevin-Xi))
- Adding an option to DISABLE\_TESTS [\#727](https://github.com/redis/hiredis/pull/727) ([pbotros](https://github.com/pbotros))
- Update README with SSL support. [\#720](https://github.com/redis/hiredis/pull/720) ([yossigo](https://github.com/yossigo))
- Fixes leaks in unit tests [\#715](https://github.com/redis/hiredis/pull/715) ([michael-grunder](https://github.com/michael-grunder))
- SSL Tests [\#711](https://github.com/redis/hiredis/pull/711) ([yossigo](https://github.com/yossigo))
- SSL Reorganization [\#708](https://github.com/redis/hiredis/pull/708) ([yossigo](https://github.com/yossigo))
- Fix MSVC build. [\#706](https://github.com/redis/hiredis/pull/706) ([yossigo](https://github.com/yossigo))
- SSL: Properly report SSL\_connect\(\) errors. [\#702](https://github.com/redis/hiredis/pull/702) ([yossigo](https://github.com/yossigo))
- Silent SSL trace to stdout by default. [\#699](https://github.com/redis/hiredis/pull/699) ([yossigo](https://github.com/yossigo))
- Port RESP3 support from Redis. [\#697](https://github.com/redis/hiredis/pull/697) ([yossigo](https://github.com/yossigo))
- Removed whitespace before newline [\#691](https://github.com/redis/hiredis/pull/691) ([Miniwoffer](https://github.com/Miniwoffer))
- Add install adapters header files [\#688](https://github.com/redis/hiredis/pull/688) ([kevin1018](https://github.com/kevin1018))
- Remove unnecessary null check before free [\#684](https://github.com/redis/hiredis/pull/684) ([qlyoung](https://github.com/qlyoung))
- redisReaderGetReply leak memory [\#671](https://github.com/redis/hiredis/pull/671) ([movebean](https://github.com/movebean))
- fix timeout code in windows [\#670](https://github.com/redis/hiredis/pull/670) ([jman-krafton](https://github.com/jman-krafton))
- test: fix errstr matching for musl libc [\#665](https://github.com/redis/hiredis/pull/665) ([ghost](https://github.com/ghost))
- Windows: MinGW fixes and Windows Travis builders [\#663](https://github.com/redis/hiredis/pull/663) ([mbitsnbites](https://github.com/mbitsnbites))
- The setsockopt and getsockopt API diffs from BSD socket and WSA one [\#662](https://github.com/redis/hiredis/pull/662) ([dragonation](https://github.com/dragonation))
- Fix Compile Error On Windows \(Visual Studio\) [\#658](https://github.com/redis/hiredis/pull/658) ([jinjiazhang](https://github.com/jinjiazhang))
- Fix NXDOMAIN test case [\#653](https://github.com/redis/hiredis/pull/653) ([michael-grunder](https://github.com/michael-grunder))
- Add MinGW support [\#652](https://github.com/redis/hiredis/pull/652) ([mbitsnbites](https://github.com/mbitsnbites))
- SSL Support [\#645](https://github.com/redis/hiredis/pull/645) ([mnunberg](https://github.com/mnunberg))
- Fix Invalid argument after redisAsyncConnectUnix [\#644](https://github.com/redis/hiredis/pull/644) ([codehz](https://github.com/codehz))
- Makefile: use predefined AR [\#632](https://github.com/redis/hiredis/pull/632) ([Mic92](https://github.com/Mic92))
- FreeBSD build fix [\#628](https://github.com/redis/hiredis/pull/628) ([devnexen](https://github.com/devnexen))
- Fix errors not propagating properly with libuv.h. [\#624](https://github.com/redis/hiredis/pull/624) ([yossigo](https://github.com/yossigo))
- Update README.md [\#621](https://github.com/redis/hiredis/pull/621) ([Crunsher](https://github.com/Crunsher))
- Fix redisBufferRead documentation [\#620](https://github.com/redis/hiredis/pull/620) ([hacst](https://github.com/hacst))
- Add CPPFLAGS to REAL\_CFLAGS [\#614](https://github.com/redis/hiredis/pull/614) ([thomaslee](https://github.com/thomaslee))
- Update createArray to take size\_t [\#597](https://github.com/redis/hiredis/pull/597) ([justinbrewer](https://github.com/justinbrewer))
- fix common realloc mistake and add null check more [\#580](https://github.com/redis/hiredis/pull/580) ([charsyam](https://github.com/charsyam))
- Proper error reporting for connect failures [\#578](https://github.com/redis/hiredis/pull/578) ([mnunberg](https://github.com/mnunberg))
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
## [1.0.0-rc1](https://github.com/redis/hiredis/tree/v1.0.0-rc1) - (2020-07-29)
_Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog_
### 0.14.1 (2020-03-13)
* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder)
### 0.14.0 (2018-09-25)
### 0.x.x (unreleased)
**BREAKING CHANGES**:
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
User code should compare this to `size_t` values as well.
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
User code should compare this to `size_t` values as well.
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
### 0.14.0 (2018-09-25)
* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
@@ -343,3 +196,4 @@ The parser, standalone since v0.12.0, can now be compiled on Windows
### 0.10.0
* See commit log.
+9 -84
View File
@@ -3,8 +3,6 @@ INCLUDE(GNUInstallDirs)
PROJECT(hiredis)
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF)
MACRO(getVersionBit name)
SET(VERSION_REGEX "^#define ${name} (.+)$")
@@ -24,8 +22,7 @@ PROJECT(hiredis VERSION "${VERSION}")
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
SET(hiredis_sources
alloc.c
ADD_LIBRARY(hiredis SHARED
async.c
dict.c
hiredis.c
@@ -34,32 +31,20 @@ SET(hiredis_sources
sds.c
sockcompat.c)
SET(hiredis_sources ${hiredis_sources})
IF(WIN32)
ADD_COMPILE_DEFINITIONS(_CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN)
ENDIF()
ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
SET_TARGET_PROPERTIES(hiredis
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
PROPERTIES
VERSION "${HIREDIS_SONAME}")
IF(WIN32 OR MINGW)
TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
ENDIF()
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:.> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC .)
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
INSTALL(TARGETS hiredis
EXPORT hiredis-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h
INSTALL(FILES hiredis.h read.h sds.h async.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
INSTALL(DIRECTORY adapters
@@ -68,26 +53,6 @@ INSTALL(DIRECTORY adapters
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
export(EXPORT hiredis-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake"
NAMESPACE hiredis::)
SET(CMAKE_CONF_INSTALL_DIR share/hiredis)
SET(INCLUDE_INSTALL_DIR include)
include(CMakePackageConfigHelpers)
configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
PATH_VARS INCLUDE_INSTALL_DIR)
INSTALL(EXPORT hiredis-targets
FILE hiredis-targets.cmake
NAMESPACE hiredis::
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
IF(ENABLE_SSL)
IF (NOT OPENSSL_ROOT_DIR)
IF (APPLE)
@@ -95,66 +60,26 @@ IF(ENABLE_SSL)
ENDIF()
ENDIF()
FIND_PACKAGE(OpenSSL REQUIRED)
SET(hiredis_ssl_sources
ssl.c)
ADD_LIBRARY(hiredis_ssl SHARED
${hiredis_ssl_sources})
IF (APPLE)
SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
ENDIF()
SET_TARGET_PROPERTIES(hiredis_ssl
PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
VERSION "${HIREDIS_SONAME}")
ssl.c)
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
IF (WIN32 OR MINGW)
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
ENDIF()
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
INSTALL(TARGETS hiredis_ssl
EXPORT hiredis_ssl-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
INSTALL(FILES hiredis_ssl.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
export(EXPORT hiredis_ssl-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake"
NAMESPACE hiredis::)
SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl)
configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
PATH_VARS INCLUDE_INSTALL_DIR)
INSTALL(EXPORT hiredis_ssl-targets
FILE hiredis_ssl-targets.cmake
NAMESPACE hiredis::
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
ENDIF()
IF(NOT DISABLE_TESTS)
IF(NOT (WIN32 OR MINGW))
ENABLE_TESTING()
ADD_EXECUTABLE(hiredis-test test.c)
IF(ENABLE_SSL_TESTS)
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl)
ELSE()
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
ENDIF()
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
ENDIF()
+19 -59
View File
@@ -3,16 +3,16 @@
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
# This file is released under the BSD license, see the COPYING file
OBJ=alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o
OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o
SSL_OBJ=ssl.o
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
ifeq ($(USE_SSL),1)
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
endif
TESTS=hiredis-test
LIBNAME=libhiredis
PKGCONFNAME=hiredis.pc
SSL_LIBNAME=libhiredis_ssl
PKGCONFNAME=hiredis.pc
SSL_PKGCONFNAME=hiredis_ssl.pc
HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
@@ -55,16 +55,11 @@ STLIBSUFFIX=a
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=$(AR) rcs
SSL_DYLIB_MINOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
SSL_DYLIB_MAJOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
SSL_DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(SSL_DYLIB_MINOR_NAME)
STLIB_MAKE_CMD=$(AR) rcs
# Platform-specific overrides
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
@@ -77,12 +72,7 @@ ifeq ($(USE_SSL),1)
endif
ifeq ($(uname_S),Linux)
ifdef OPENSSL_PREFIX
CFLAGS+=-I$(OPENSSL_PREFIX)/include
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
else
SSL_LDFLAGS=-lssl -lcrypto
endif
SSL_LDFLAGS=-lssl -lcrypto
else
OPENSSL_PREFIX?=/usr/local/opt/openssl
CFLAGS+=-I$(OPENSSL_PREFIX)/include
@@ -90,22 +80,13 @@ else
endif
ifeq ($(uname_S),SunOS)
IS_SUN_CC=$(shell sh -c '$(CC) -V 2>&1 |egrep -i -c "sun|studio"')
ifeq ($(IS_SUN_CC),1)
SUN_SHARED_FLAG=-G
else
SUN_SHARED_FLAG=-shared
endif
REAL_LDFLAGS+= -ldl -lnsl -lsocket
DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
SSL_DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(SSL_DYLIBNAME) -h $(SSL_DYLIB_MINOR_NAME) $(LDFLAGS) $(SSL_LDFLAGS)
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
endif
ifeq ($(uname_S),Darwin)
DYLIBSUFFIX=dylib
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
SSL_DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) -o $(SSL_DYLIBNAME) $(LDFLAGS) $(SSL_LDFLAGS)
DYLIB_PLUGIN=-Wl,-undefined -Wl,dynamic_lookup
endif
all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
@@ -114,16 +95,15 @@ all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
endif
# Deps (use make dep to generate this)
alloc.o: alloc.c fmacros.h alloc.h
async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h
dict.o: dict.c fmacros.h alloc.h dict.h
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h
read.o: read.c fmacros.h alloc.h read.h sds.h win32.h
sds.o: sds.c sds.h sdsalloc.h alloc.h
async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h
dict.o: dict.c fmacros.h dict.h
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h win32.h
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h sockcompat.h win32.h
read.o: read.c fmacros.h read.h sds.h
sds.o: sds.c sds.h
sockcompat.o: sockcompat.c sockcompat.h
ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h
test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h sockcompat.h win32.h
ssl.o: ssl.c hiredis.h
test.o: test.c fmacros.h hiredis.h read.h sds.h
$(DYLIBNAME): $(OBJ)
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)
@@ -132,7 +112,7 @@ $(STLIBNAME): $(OBJ)
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
$(SSL_DYLIBNAME): $(SSL_OBJ)
$(SSL_DYLIB_MAKE_CMD) $(DYLIB_PLUGIN) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(LDFLAGS) $(SSL_LDFLAGS)
$(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
$(SSL_STLIBNAME): $(SSL_OBJ)
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)
@@ -166,7 +146,6 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
ifndef AE_DIR
hiredis-example-ae:
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
@@ -201,19 +180,13 @@ endif
hiredis-example: examples/example.c $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
hiredis-example-push: examples/example-push.c $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
examples: $(EXAMPLES)
TEST_LIBS = $(STLIBNAME)
ifeq ($(USE_SSL),1)
TEST_LIBS += $(SSL_STLIBNAME)
TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread
TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread
endif
hiredis-test: test.o $(TEST_LIBS)
$(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS)
hiredis-%: %.o $(STLIBNAME)
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)
@@ -248,7 +221,7 @@ $(PKGCONFNAME): hiredis.h
@echo Libs: -L\$${libdir} -lhiredis >> $@
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
$(SSL_PKGCONFNAME): hiredis_ssl.h
$(SSL_PKGCONFNAME): hiredis.h
@echo "Generating $@ for pkgconfig..."
@echo prefix=$(PREFIX) > $@
@echo exec_prefix=\$${prefix} >> $@
@@ -264,7 +237,7 @@ $(SSL_PKGCONFNAME): hiredis_ssl.h
install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
$(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH)
$(INSTALL) hiredis.h async.h read.h sds.h $(INSTALL_INCLUDE_PATH)
$(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
@@ -272,19 +245,6 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
mkdir -p $(INSTALL_PKGCONF_PATH)
$(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
ifeq ($(USE_SSL),1)
install: install-ssl
install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
$(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH)
$(INSTALL) $(SSL_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME)
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME)
$(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH)
mkdir -p $(INSTALL_PKGCONF_PATH)
$(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
endif
32bit:
@echo ""
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
+13 -259
View File
@@ -1,6 +1,6 @@
[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
**This Readme reflects the latest changed in the master branch. See [v0.13.3](https://github.com/redis/hiredis/tree/v0.13.3) for the Readme and documentation for the latest release.**
# HIREDIS
@@ -24,31 +24,12 @@ The library comes with multiple APIs. There is the
## Upgrading to `1.0.0`
Version 1.0.0 marks the first stable release of Hiredis.
Version 1.0.0 marks a stable release of hiredis.
It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
It also bundles the updated `sds` library, to sync up with upstream and Redis.
For most applications a recompile against the new hiredis should be enough.
For code changes see the [Changelog](CHANGELOG.md).
_Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._
## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0`
* `redisContext` has two additional members (`free_privdata`, and `privctx`).
* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.
* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.
## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x
Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
protocol errors. This is consistent with the RESP specification. On 32-bit
platforms, the upper bound is lowered to `SIZE_MAX`.
Change `redisReply.len` to `size_t`, as it denotes the the size of a string
User code should compare this to `size_t` values as well. If it was used to
compare to other values, casting might be necessary or can be removed, if
casting was applied before.
## Upgrading from `<0.9.0`
Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
@@ -129,8 +110,6 @@ The standard replies that `redisCommand` are of the type `redisReply`. The
`type` field in the `redisReply` should be used to test what kind of reply
was received:
### RESP2
* **`REDIS_REPLY_STATUS`**:
* The command replied with a status reply. The status string can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.
@@ -155,51 +134,16 @@ was received:
and can be accessed via `reply->element[..index..]`.
Redis may reply with nested arrays but this is fully supported.
### RESP3
Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)
* **`REDIS_REPLY_DOUBLE`**:
* The command replied with a double-precision floating point number.
The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.
* **`REDIS_REPLY_BOOL`**:
* A boolean true/false reply.
The value is stored in the `integer` member and will be either `0` or `1`.
* **`REDIS_REPLY_MAP`**:
* An array with the added invariant that there will always be an even number of elements.
The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
* **`REDIS_REPLY_SET`**:
* An array response where each entry is unique.
Like the MAP type, the data is identical to an array response except there are no duplicate values.
* **`REDIS_REPLY_PUSH`**:
* An array that can be generated spontaneously by Redis.
This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.
* **`REDIS_REPLY_ATTR`**:
* An array structurally identical to a `MAP` but intended as meta-data about a reply.
_As of Redis 6.0.6 this reply type is not used in Redis_
* **`REDIS_REPLY_BIGNUM`**:
* A string representing an arbitrarily large signed or unsigned integer value.
The number will be encoded as a string in the `str` member of `redisReply`.
* **`REDIS_REPLY_VERB`**:
* A verbatim string, intended to be presented to the user without modification.
The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).
Replies should be freed using the `freeReplyObject()` function.
Note that this function will take care of freeing sub-reply objects
contained in arrays and nested arrays, so there is no need for the user to
free the sub replies (it is actually harmful and will corrupt the memory).
**Important:** the current version of hiredis (1.0.0) frees replies when the
**Important:** the current version of hiredis (0.10.0) frees replies when the
asynchronous API is used. This means you should not call `freeReplyObject` when
you use this API. The reply is cleaned up by hiredis _after_ the callback
returns. We may introduce a flag to make this configurable in future versions of the library.
returns. This behavior will probably change in future releases, so make sure to
keep an eye on the changelog when upgrading (see issue #39).
### Cleaning up
@@ -261,16 +205,16 @@ a single call to `read(2)`):
redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,(void *)&reply); // reply for SET
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,(void *)&reply); // reply for GET
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);
```
This API can also be used to implement a blocking subscriber:
```c
reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
while(redisGetReply(context,&reply) == REDIS_OK) {
// consume message
freeReplyObject(reply);
}
@@ -460,199 +404,9 @@ This should be done only in order to maximize performances when working with
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
as soon as possible in order to prevent allocation of useless memory.
### Reader max array elements
By default the hiredis reply parser sets the maximum number of multi-bulk elements
to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies
with more than this many elements you can set the value higher or to zero, meaning
unlimited with:
```c
context->reader->maxelements = 0;
```
## SSL/TLS Support
### Building
SSL/TLS support is not built by default and requires an explicit flag:
make USE_SSL=1
This requires OpenSSL development package (e.g. including header files to be
available.
When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and
`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries
unaffected so no additional dependencies are introduced.
### Using it
First, you'll need to make sure you include the SSL header file:
```c
#include "hiredis.h"
#include "hiredis_ssl.h"
```
You will also need to link against `libhiredis_ssl`, **in addition** to
`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.
Hiredis implements SSL/TLS on top of its normal `redisContext` or
`redisAsyncContext`, so you will need to establish a connection first and then
initiate an SSL/TLS handshake.
#### Hiredis OpenSSL Wrappers
Before Hiredis can negotiate an SSL/TLS connection, it is necessary to
initialize OpenSSL and create a context. You can do that in two ways:
1. Work directly with the OpenSSL API to initialize the library's global context
and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can
call `redisInitiateSSL()`.
2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a
`redisSSLContext` object to hold configuration and use
`redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake.
```c
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
* many contexts.
*/
redisSSLContext *ssl;
/* An error variable to indicate what went wrong, if the context fails to
* initialize.
*/
redisSSLContextError ssl_error;
/* Initialize global OpenSSL state.
*
* You should call this only once when your app initializes, and only if
* you don't explicitly or implicitly initialize OpenSSL it elsewhere.
*/
redisInitOpenSSL();
/* Create SSL context */
ssl = redisCreateSSLContext(
"cacertbundle.crt", /* File name of trusted CA/ca bundle file, optional */
"/path/to/certs", /* Path of trusted certificates, optional */
"client_cert.pem", /* File name of client certificate file, optional */
"client_key.pem", /* File name of client private key, optional */
"redis.mydomain.com", /* Server name to request (SNI), optional */
&ssl_error
) != REDIS_OK) {
printf("SSL error: %s\n", redisSSLContextGetError(ssl_error);
/* Abort... */
}
/* Create Redis context and establish connection */
c = redisConnect("localhost", 6443);
if (c == NULL || c->err) {
/* Handle error and abort... */
}
/* Negotiate SSL/TLS */
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
/* Handle error, in c->err / c->errstr */
}
```
## RESP3 PUSH replies
Redis 6.0 introduced PUSH replies with the reply-type `>`. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.
### Default behavior
Hiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`.
### Custom PUSH handler prototypes
The callback prototypes differ between `redisContext` and `redisAsyncContext`.
#### redisContext
```c
void my_push_handler(void *privdata, void *reply) {
/* Handle the reply */
/* Note: We need to free the reply in our custom handler for
blocking contexts. This lets us keep the reply if
we want. */
freeReplyObject(reply);
}
```
#### redisAsyncContext
```c
void my_async_push_handler(redisAsyncContext *ac, void *reply) {
/* Handle the reply */
/* Note: Because async hiredis always frees replies, you should
not call freeReplyObject in an async push callback. */
}
```
### Installing a custom handler
There are two ways to set your own PUSH handlers.
1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`.
```c
redisOptions = {0};
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
options->push_cb = my_push_handler;
redisContext *context = redisConnectWithOptions(&options);
```
2. Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context.
```c
redisContext *context = redisConnect("127.0.0.1", 6379);
redisSetPushCallback(context, my_push_handler);
```
_Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler, making it easy to override and then return to the old value._
### Specifying no handler
If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.
1. Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`.
```c
redisOptions = {0};
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
redisContext *context = redisConnectWithOptions(&options);
```
3. Call `redisSetPushCallback` with `NULL` once connected.
```c
redisContext *context = redisConnect("127.0.0.1", 6379);
redisSetPushCallback(context, NULL);
```
_Note: With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking`redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._
## Allocator injection
Hiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions. By default they just point to libc (`malloc`, `calloc`, `realloc`, etc).
### Overriding
One can override the allocators like so:
```c
hiredisAllocFuncs myfuncs = {
.mallocFn = my_malloc,
.callocFn = my_calloc,
.reallocFn = my_realloc,
.strdupFn = my_strdup,
.freeFn = my_free,
};
// Override allocators (function returns current allocators if needed)
hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);
```
To reset the allocators to their default libc function simply call:
```c
hiredisResetAllocators();
```
## AUTHORS
Salvatore Sanfilippo (antirez at gmail),\
Pieter Noordhuis (pcnoordhuis at gmail)\
Michael Grunder (michael dot grunder at gmail)
_Hiredis is released under the BSD license._
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and
Jan-Erik Rediger (janerik at fnordig dot com)
+2 -5
View File
@@ -96,7 +96,7 @@ static void redisAeCleanup(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
redisAeDelRead(privdata);
redisAeDelWrite(privdata);
hi_free(e);
free(e);
}
static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
@@ -108,10 +108,7 @@ static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisAeEvents*)hi_malloc(sizeof(*e));
if (e == NULL)
return REDIS_ERR;
e = (redisAeEvents*)malloc(sizeof(*e));
e->context = ac;
e->loop = loop;
e->fd = c->fd;
-3
View File
@@ -134,9 +134,6 @@ redis_source_new (redisAsyncContext *ac)
g_return_val_if_fail(ac != NULL, NULL);
source = (RedisSource *)g_source_new(&source_funcs, sizeof *source);
if (source == NULL)
return NULL;
source->ac = ac;
source->poll_fd.fd = c->fd;
source->poll_fd.events = 0;
+2 -5
View File
@@ -43,7 +43,7 @@ static void redisIvykisCleanup(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
iv_fd_unregister(&e->fd);
hi_free(e);
free(e);
}
static int redisIvykisAttach(redisAsyncContext *ac) {
@@ -55,10 +55,7 @@ static int redisIvykisAttach(redisAsyncContext *ac) {
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisIvykisEvents*)hi_malloc(sizeof(*e));
if (e == NULL)
return REDIS_ERR;
e = (redisIvykisEvents*)malloc(sizeof(*e));
e->context = ac;
/* Register functions to start/stop listening for events */
+3 -35
View File
@@ -41,7 +41,6 @@ typedef struct redisLibevEvents {
struct ev_loop *loop;
int reading, writing;
ev_io rev, wev;
ev_timer timer;
} redisLibevEvents;
static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
@@ -104,39 +103,11 @@ static void redisLibevDelWrite(void *privdata) {
}
}
static void redisLibevStopTimer(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
ev_timer_stop(EV_A_ &e->timer);
}
static void redisLibevCleanup(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
redisLibevDelRead(privdata);
redisLibevDelWrite(privdata);
redisLibevStopTimer(privdata);
hi_free(e);
}
static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
((void)revents);
redisLibevEvents *e = (redisLibevEvents*)timer->data;
redisAsyncHandleTimeout(e->context);
}
static void redisLibevSetTimeout(void *privdata, struct timeval tv) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (!ev_is_active(&e->timer)) {
ev_init(&e->timer, redisLibevTimeout);
e->timer.data = e;
}
e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00;
ev_timer_again(EV_A_ &e->timer);
free(e);
}
static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
@@ -148,16 +119,14 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisLibevEvents*)hi_calloc(1, sizeof(*e));
if (e == NULL)
return REDIS_ERR;
e = (redisLibevEvents*)malloc(sizeof(*e));
e->context = ac;
#if EV_MULTIPLICITY
e->loop = loop;
#else
e->loop = NULL;
#endif
e->reading = e->writing = 0;
e->rev.data = e;
e->wev.data = e;
@@ -167,7 +136,6 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
ac->ev.addWrite = redisLibevAddWrite;
ac->ev.delWrite = redisLibevDelWrite;
ac->ev.cleanup = redisLibevCleanup;
ac->ev.scheduleTimer = redisLibevSetTimeout;
ac->ev.data = e;
/* Initialize read/write events */
+2 -5
View File
@@ -47,7 +47,7 @@ typedef struct redisLibeventEvents {
} redisLibeventEvents;
static void redisLibeventDestroy(redisLibeventEvents *e) {
hi_free(e);
free(e);
}
static void redisLibeventHandler(int fd, short event, void *arg) {
@@ -152,10 +152,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
if (e == NULL)
return REDIS_ERR;
e = (redisLibeventEvents*)calloc(1, sizeof(*e));
e->context = ac;
/* Register functions to start/stop listening for events */
+7 -5
View File
@@ -73,7 +73,7 @@ static void redisLibuvDelWrite(void *privdata) {
static void on_close(uv_handle_t* handle) {
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
hi_free(p);
free(p);
}
@@ -98,13 +98,15 @@ static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
ac->ev.delWrite = redisLibuvDelWrite;
ac->ev.cleanup = redisLibuvCleanup;
redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p));
if (p == NULL)
return REDIS_ERR;
redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p));
if (!p) {
return REDIS_ERR;
}
memset(p, 0, sizeof(*p));
if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) {
if (uv_poll_init(loop, &p->handle, c->fd) != 0) {
return REDIS_ERR;
}
+3 -4
View File
@@ -27,7 +27,7 @@ static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) {
CFSocketInvalidate(redisRunLoop->socketRef);
CFRelease(redisRunLoop->socketRef);
}
hi_free(redisRunLoop);
free(redisRunLoop);
}
return REDIS_ERR;
}
@@ -80,9 +80,8 @@ static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLo
/* Nothing should be attached when something is already attached */
if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR;
RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop));
if (redisRunLoop == NULL)
return REDIS_ERR;
RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop));
if( !redisRunLoop ) return REDIS_ERR;
/* Setup redis stuff */
redisRunLoop->context = redisAsyncCtx;
-86
View File
@@ -1,86 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmacros.h"
#include "alloc.h"
#include <string.h>
#include <stdlib.h>
hiredisAllocFuncs hiredisAllocFns = {
.mallocFn = malloc,
.callocFn = calloc,
.reallocFn = realloc,
.strdupFn = strdup,
.freeFn = free,
};
/* Override hiredis' allocators with ones supplied by the user */
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *override) {
hiredisAllocFuncs orig = hiredisAllocFns;
hiredisAllocFns = *override;
return orig;
}
/* Reset allocators to use libc defaults */
void hiredisResetAllocators(void) {
hiredisAllocFns = (hiredisAllocFuncs) {
.mallocFn = malloc,
.callocFn = calloc,
.reallocFn = realloc,
.strdupFn = strdup,
.freeFn = free,
};
}
#ifdef _WIN32
void *hi_malloc(size_t size) {
return hiredisAllocFns.mallocFn(size);
}
void *hi_calloc(size_t nmemb, size_t size) {
return hiredisAllocFns.callocFn(nmemb, size);
}
void *hi_realloc(void *ptr, size_t size) {
return hiredisAllocFns.reallocFn(ptr, size);
}
char *hi_strdup(const char *str) {
return hiredisAllocFns.strdupFn(str);
}
void hi_free(void *ptr) {
hiredisAllocFns.freeFn(ptr);
}
#endif
-91
View File
@@ -1,91 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HIREDIS_ALLOC_H
#define HIREDIS_ALLOC_H
#include <stddef.h> /* for size_t */
#ifdef __cplusplus
extern "C" {
#endif
/* Structure pointing to our actually configured allocators */
typedef struct hiredisAllocFuncs {
void *(*mallocFn)(size_t);
void *(*callocFn)(size_t,size_t);
void *(*reallocFn)(void*,size_t);
char *(*strdupFn)(const char*);
void (*freeFn)(void*);
} hiredisAllocFuncs;
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha);
void hiredisResetAllocators(void);
#ifndef _WIN32
/* Hiredis' configured allocator function pointer struct */
extern hiredisAllocFuncs hiredisAllocFns;
static inline void *hi_malloc(size_t size) {
return hiredisAllocFns.mallocFn(size);
}
static inline void *hi_calloc(size_t nmemb, size_t size) {
return hiredisAllocFns.callocFn(nmemb, size);
}
static inline void *hi_realloc(void *ptr, size_t size) {
return hiredisAllocFns.reallocFn(ptr, size);
}
static inline char *hi_strdup(const char *str) {
return hiredisAllocFns.strdupFn(str);
}
static inline void hi_free(void *ptr) {
hiredisAllocFns.freeFn(ptr);
}
#else
void *hi_malloc(size_t size);
void *hi_calloc(size_t nmemb, size_t size);
void *hi_realloc(void *ptr, size_t size);
char *hi_strdup(const char *str);
void hi_free(void *ptr);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HIREDIS_ALLOC_H */
+48 -169
View File
@@ -30,7 +30,6 @@
*/
#include "fmacros.h"
#include "alloc.h"
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
@@ -47,24 +46,18 @@
#include "async_private.h"
/* Forward declarations of hiredis.c functions */
/* Forward declaration of function in hiredis.c */
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);
void __redisSetError(redisContext *c, int type, const char *str);
/* Functions managing dictionary of callbacks for pub/sub. */
static unsigned int callbackHash(const void *key) {
return dictGenHashFunction((const unsigned char *)key,
hi_sdslen((const hisds)key));
sdslen((const sds)key));
}
static void *callbackValDup(void *privdata, const void *src) {
((void) privdata);
redisCallback *dup;
dup = hi_malloc(sizeof(*dup));
if (dup == NULL)
return NULL;
redisCallback *dup = malloc(sizeof(*dup));
memcpy(dup,src,sizeof(*dup));
return dup;
}
@@ -73,20 +66,20 @@ static int callbackKeyCompare(void *privdata, const void *key1, const void *key2
int l1, l2;
((void) privdata);
l1 = hi_sdslen((const hisds)key1);
l2 = hi_sdslen((const hisds)key2);
l1 = sdslen((const sds)key1);
l2 = sdslen((const sds)key2);
if (l1 != l2) return 0;
return memcmp(key1,key2,l1) == 0;
}
static void callbackKeyDestructor(void *privdata, void *key) {
((void) privdata);
hi_sdsfree((hisds)key);
sdsfree((sds)key);
}
static void callbackValDestructor(void *privdata, void *val) {
((void) privdata);
hi_free(val);
free(val);
}
static dictType callbackDict = {
@@ -100,19 +93,10 @@ static dictType callbackDict = {
static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
redisAsyncContext *ac;
dict *channels = NULL, *patterns = NULL;
channels = dictCreate(&callbackDict,NULL);
if (channels == NULL)
goto oom;
patterns = dictCreate(&callbackDict,NULL);
if (patterns == NULL)
goto oom;
ac = hi_realloc(c,sizeof(redisAsyncContext));
ac = realloc(c,sizeof(redisAsyncContext));
if (ac == NULL)
goto oom;
return NULL;
c = &(ac->c);
@@ -124,7 +108,6 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
ac->err = 0;
ac->errstr = NULL;
ac->data = NULL;
ac->dataCleanup = NULL;
ac->ev.data = NULL;
ac->ev.addRead = NULL;
@@ -141,14 +124,9 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
ac->replies.tail = NULL;
ac->sub.invalid.head = NULL;
ac->sub.invalid.tail = NULL;
ac->sub.channels = channels;
ac->sub.patterns = patterns;
ac->sub.channels = dictCreate(&callbackDict,NULL);
ac->sub.patterns = dictCreate(&callbackDict,NULL);
return ac;
oom:
if (channels) dictRelease(channels);
if (patterns) dictRelease(patterns);
return NULL;
}
/* We want the error field to be accessible directly instead of requiring
@@ -167,26 +145,16 @@ redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
redisContext *c;
redisAsyncContext *ac;
/* Clear any erroneously set sync callback and flag that we don't want to
* use freeReplyObject by default. */
myOptions.push_cb = NULL;
myOptions.options |= REDIS_OPT_NO_PUSH_AUTOFREE;
myOptions.options |= REDIS_OPT_NONBLOCK;
c = redisConnectWithOptions(&myOptions);
if (c == NULL) {
return NULL;
}
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
/* Set any configured async push handler */
redisAsyncSetPushCallback(ac, myOptions.async_push_cb);
__redisAsyncCopyError(ac);
return ac;
}
@@ -246,7 +214,7 @@ static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
redisCallback *cb;
/* Copy callback from stack to heap */
cb = hi_malloc(sizeof(*cb));
cb = malloc(sizeof(*cb));
if (cb == NULL)
return REDIS_ERR_OOM;
@@ -274,7 +242,7 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
/* Copy callback from heap to stack */
if (target != NULL)
memcpy(target,cb,sizeof(*cb));
hi_free(cb);
free(cb);
return REDIS_OK;
}
return REDIS_ERR;
@@ -289,14 +257,6 @@ static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisRe
}
}
static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) {
if (ac->push_cb != NULL) {
ac->c.flags |= REDIS_IN_CALLBACK;
ac->push_cb(ac, reply);
ac->c.flags &= ~REDIS_IN_CALLBACK;
}
}
/* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
@@ -312,28 +272,18 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
__redisRunCallback(ac,&cb,NULL);
/* Run subscription callbacks with NULL reply */
if (ac->sub.channels) {
it = dictGetIterator(ac->sub.channels);
if (it != NULL) {
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
}
/* Run subscription callbacks callbacks with NULL reply */
it = dictGetIterator(ac->sub.channels);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.channels);
dictRelease(ac->sub.channels);
}
if (ac->sub.patterns) {
it = dictGetIterator(ac->sub.patterns);
if (it != NULL) {
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
}
dictRelease(ac->sub.patterns);
}
it = dictGetIterator(ac->sub.patterns);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.patterns);
/* Signal event lib to clean up */
_EL_CLEANUP(ac);
@@ -348,10 +298,6 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
}
}
if (ac->dataCleanup) {
ac->dataCleanup(ac->data);
}
/* Cleanup self */
redisFree(c);
}
@@ -418,11 +364,11 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
dictEntry *de;
int pvariant;
char *stype;
hisds sname;
sds sname;
/* Custom reply functions are not supported for pub/sub. This will fail
* very hard when they are used... */
if (reply->type == REDIS_REPLY_ARRAY || reply->type == REDIS_REPLY_PUSH) {
if (reply->type == REDIS_REPLY_ARRAY) {
assert(reply->elements >= 2);
assert(reply->element[0]->type == REDIS_REPLY_STRING);
stype = reply->element[0]->str;
@@ -435,10 +381,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
/* Locate the right callback */
assert(reply->element[1]->type == REDIS_REPLY_STRING);
sname = hi_sdsnewlen(reply->element[1]->str,reply->element[1]->len);
if (sname == NULL)
goto oom;
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
de = dictFind(callbacks,sname);
if (de != NULL) {
cb = dictGetEntryVal(de);
@@ -466,39 +409,12 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
c->flags &= ~REDIS_SUBSCRIBED;
}
}
hi_sdsfree(sname);
sdsfree(sname);
} else {
/* Shift callback for invalid commands. */
__redisShiftCallback(&ac->sub.invalid,dstcb);
}
return REDIS_OK;
oom:
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
#define redisIsSpontaneousPushReply(r) \
(redisIsPushReply(r) && !redisIsSubscribeReply(r))
static int redisIsSubscribeReply(redisReply *reply) {
char *str;
size_t len, off;
/* We will always have at least one string with the subscribe/message type */
if (reply->elements < 1 || reply->element[0]->type != REDIS_REPLY_STRING ||
reply->element[0]->len < sizeof("message") - 1)
{
return 0;
}
/* Get the string/len moving past 'p' if needed */
off = tolower(reply->element[0]->str[0]) == 'p';
str = reply->element[0]->str + off;
len = reply->element[0]->len - off;
return !strncasecmp(str, "subscribe", len) ||
!strncasecmp(str, "message", len);
}
void redisProcessCallbacks(redisAsyncContext *ac) {
@@ -511,7 +427,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
if (reply == NULL) {
/* When the connection is being disconnected and there are
* no more replies, this is the cue to really disconnect. */
if (c->flags & REDIS_DISCONNECTING && hi_sdslen(c->obuf) == 0
if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0
&& ac->replies.head == NULL) {
__redisAsyncDisconnect(ac);
return;
@@ -527,18 +443,8 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
break;
}
/* Send any non-subscribe related PUSH messages to our PUSH handler
* while allowing subscribe related PUSH messages to pass through.
* This allows existing code to be backward compatible and work in
* either RESP2 or RESP3 mode. */
if (redisIsSpontaneousPushReply(reply)) {
__redisRunPushCallback(ac, reply);
c->reader->fn->freeObject(reply);
continue;
}
/* Even if the context is subscribed, pending regular
* callbacks will get a reply before pub/sub messages arrive. */
/* Even if the context is subscribed, pending regular callbacks will
* get a reply before pub/sub messages arrive. */
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
/*
* A spontaneous reply in a not-subscribed context can be the error
@@ -591,31 +497,20 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
__redisAsyncDisconnect(ac);
}
static void __redisAsyncHandleConnectFailure(redisAsyncContext *ac) {
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
__redisAsyncDisconnect(ac);
}
/* Internal helper function to detect socket status the first time a read or
* write event fires. When connecting was not successful, the connect callback
* is called with a REDIS_ERR status and the context is free'd. */
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
int completed = 0;
redisContext *c = &(ac->c);
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
/* Error! */
redisCheckSocketError(c);
__redisAsyncHandleConnectFailure(ac);
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
__redisAsyncDisconnect(ac);
return REDIS_ERR;
} else if (completed == 1) {
/* connected! */
if (c->connection_type == REDIS_CONN_TCP &&
redisSetTcpNoDelay(c) == REDIS_ERR) {
__redisAsyncHandleConnectFailure(ac);
return REDIS_ERR;
}
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
@@ -687,6 +582,8 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
c->funcs->async_write(ac);
}
void __redisSetError(redisContext *c, int type, const char *str);
void redisAsyncHandleTimeout(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;
@@ -744,7 +641,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
const char *cstr, *astr;
size_t clen, alen;
const char *p;
hisds sname;
sds sname;
int ret;
/* Don't accept new commands when the connection is about to be closed. */
@@ -768,10 +665,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
/* Add every channel/pattern to the list of subscription callbacks. */
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
sname = hi_sdsnewlen(astr,alen);
if (sname == NULL)
goto oom;
sname = sdsnewlen(astr,alen);
if (pvariant)
cbdict = ac->sub.patterns;
else
@@ -786,7 +680,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
ret = dictReplace(cbdict,sname,&cb);
if (ret == 0) hi_sdsfree(sname);
if (ret == 0) sdsfree(sname);
}
} else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
/* It is only useful to call (P)UNSUBSCRIBE when the context is
@@ -815,9 +709,6 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
_EL_ADD_WRITE(ac);
return REDIS_OK;
oom:
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
@@ -831,7 +722,7 @@ int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdat
return REDIS_ERR;
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
hi_free(cmd);
free(cmd);
return status;
}
@@ -845,14 +736,14 @@ int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata
}
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
hisds cmd;
sds cmd;
int len;
int status;
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
if (len < 0)
return REDIS_ERR;
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
hi_sdsfree(cmd);
sdsfree(cmd);
return status;
}
@@ -861,27 +752,15 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
return status;
}
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn) {
redisAsyncPushFn *old = ac->push_cb;
ac->push_cb = fn;
return old;
}
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
if (!ac->c.command_timeout) {
ac->c.command_timeout = hi_calloc(1, sizeof(tv));
if (ac->c.command_timeout == NULL) {
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
__redisAsyncCopyError(ac);
return REDIS_ERR;
}
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
if (!ac->c.timeout) {
ac->c.timeout = calloc(1, sizeof(tv));
}
if (tv.tv_sec != ac->c.command_timeout->tv_sec ||
tv.tv_usec != ac->c.command_timeout->tv_usec)
{
*ac->c.command_timeout = tv;
if (tv.tv_sec == ac->c.timeout->tv_sec &&
tv.tv_usec == ac->c.timeout->tv_usec) {
return;
}
return REDIS_OK;
*ac->c.timeout = tv;
}
+1 -6
View File
@@ -70,7 +70,6 @@ typedef struct redisAsyncContext {
/* Not used by hiredis */
void *data;
void (*dataCleanup)(void *privdata);
/* Event library data and hooks */
struct {
@@ -106,9 +105,6 @@ typedef struct redisAsyncContext {
struct dict *channels;
struct dict *patterns;
} sub;
/* Any configured RESP3 PUSH handler */
redisAsyncPushFn *push_cb;
} redisAsyncContext;
/* Functions that proxy to hiredis */
@@ -121,8 +117,7 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path);
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
void redisAsyncDisconnect(redisAsyncContext *ac);
void redisAsyncFree(redisAsyncContext *ac);
+10 -13
View File
@@ -51,21 +51,18 @@
#define _EL_CLEANUP(ctx) do { \
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
ctx->ev.cleanup = NULL; \
} while(0)
} while(0);
static inline void refreshTimeout(redisAsyncContext *ctx) {
#define REDIS_TIMER_ISSET(tvp) \
(tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
#define REDIS_EL_TIMER(ac, tvp) \
if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
(ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
}
if (ctx->c.flags & REDIS_CONNECTED) {
REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
} else {
REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
if (ctx->c.timeout && ctx->ev.scheduleTimer &&
(ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
// } else {
// printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
// if (ctx->c.timeout){
// printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
// ctx->c.timeout->tv_usec);
// }
}
}
+11 -25
View File
@@ -34,7 +34,6 @@
*/
#include "fmacros.h"
#include "alloc.h"
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
@@ -72,10 +71,7 @@ static void _dictReset(dict *ht) {
/* Create a new hash table */
static dict *dictCreate(dictType *type, void *privDataPtr) {
dict *ht = hi_malloc(sizeof(*ht));
if (ht == NULL)
return NULL;
dict *ht = malloc(sizeof(*ht));
_dictInit(ht,type,privDataPtr);
return ht;
}
@@ -101,9 +97,7 @@ static int dictExpand(dict *ht, unsigned long size) {
_dictInit(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize-1;
n.table = hi_calloc(realsize,sizeof(dictEntry*));
if (n.table == NULL)
return DICT_ERR;
n.table = calloc(realsize,sizeof(dictEntry*));
/* Copy all the elements from the old to the new table:
* note that if the old hash table is empty ht->size is zero,
@@ -130,7 +124,7 @@ static int dictExpand(dict *ht, unsigned long size) {
}
}
assert(ht->used == 0);
hi_free(ht->table);
free(ht->table);
/* Remap the new hashtable in the old */
*ht = n;
@@ -148,10 +142,7 @@ static int dictAdd(dict *ht, void *key, void *val) {
return DICT_ERR;
/* Allocates the memory and stores key */
entry = hi_malloc(sizeof(*entry));
if (entry == NULL)
return DICT_ERR;
entry = malloc(sizeof(*entry));
entry->next = ht->table[index];
ht->table[index] = entry;
@@ -175,9 +166,6 @@ static int dictReplace(dict *ht, void *key, void *val) {
return 1;
/* It already exists, get the entry */
entry = dictFind(ht, key);
if (entry == NULL)
return 0;
/* Free the old value and set the new one */
/* Set the new value and free the old one. Note that it is important
* to do that in this order, as the value may just be exactly the same
@@ -211,7 +199,7 @@ static int dictDelete(dict *ht, const void *key) {
dictFreeEntryKey(ht,de);
dictFreeEntryVal(ht,de);
hi_free(de);
free(de);
ht->used--;
return DICT_OK;
}
@@ -234,13 +222,13 @@ static int _dictClear(dict *ht) {
nextHe = he->next;
dictFreeEntryKey(ht, he);
dictFreeEntryVal(ht, he);
hi_free(he);
free(he);
ht->used--;
he = nextHe;
}
}
/* Free the table and the allocated cache structure */
hi_free(ht->table);
free(ht->table);
/* Re-initialize the table */
_dictReset(ht);
return DICT_OK; /* never fails */
@@ -249,7 +237,7 @@ static int _dictClear(dict *ht) {
/* Clear & Release the hash table */
static void dictRelease(dict *ht) {
_dictClear(ht);
hi_free(ht);
free(ht);
}
static dictEntry *dictFind(dict *ht, const void *key) {
@@ -268,9 +256,7 @@ static dictEntry *dictFind(dict *ht, const void *key) {
}
static dictIterator *dictGetIterator(dict *ht) {
dictIterator *iter = hi_malloc(sizeof(*iter));
if (iter == NULL)
return NULL;
dictIterator *iter = malloc(sizeof(*iter));
iter->ht = ht;
iter->index = -1;
@@ -300,7 +286,7 @@ static dictEntry *dictNext(dictIterator *iter) {
}
static void dictReleaseIterator(dictIterator *iter) {
hi_free(iter);
free(iter);
}
/* ------------------------- private functions ------------------------------ */
@@ -308,7 +294,7 @@ static void dictReleaseIterator(dictIterator *iter) {
/* Expand the hash table if needed */
static int _dictExpandIfNeeded(dict *ht) {
/* If the hash table is empty expand it to the initial size,
* if the table is "full" double its size. */
* if the table is "full" dobule its size. */
if (ht->size == 0)
return dictExpand(ht, DICT_HT_INITIAL_SIZE);
if (ht->used == ht->size)
-3
View File
@@ -44,6 +44,3 @@ ENDIF()
ADD_EXECUTABLE(example example.c)
TARGET_LINK_LIBRARIES(example hiredis)
ADD_EXECUTABLE(example-push example-push.c)
TARGET_LINK_LIBRARIES(example-push hiredis)
-2
View File
@@ -33,9 +33,7 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
}
int main (int argc, char **argv) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
iv_init();
-2
View File
@@ -33,9 +33,7 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
}
int main (int argc, char **argv) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
+1 -18
View File
@@ -34,10 +34,7 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
}
int main (int argc, char **argv) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
struct event_base *base = event_base_new();
if (argc < 5) {
fprintf(stderr,
@@ -55,25 +52,13 @@ int main (int argc, char **argv) {
const char *certKey = argv[5];
const char *caCert = argc > 5 ? argv[6] : NULL;
redisSSLContext *ssl;
redisSSLContextError ssl_error;
redisInitOpenSSL();
ssl = redisCreateSSLContext(caCert, NULL,
cert, certKey, NULL, &ssl_error);
if (!ssl) {
printf("Error: %s\n", redisSSLContextGetError(ssl_error));
return 1;
}
redisAsyncContext *c = redisAsyncConnect(hostname, port);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
if (redisInitiateSSLWithContext(&c->c, ssl) != REDIS_OK) {
if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) {
printf("SSL Error!\n");
exit(1);
}
@@ -84,7 +69,5 @@ int main (int argc, char **argv) {
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
event_base_dispatch(base);
redisFreeSSLContext(ssl);
return 0;
}
+1 -4
View File
@@ -38,16 +38,13 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
}
int main (int argc, char **argv) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
struct event_base *base = event_base_new();
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
struct timeval tv = {0};
tv.tv_sec = 1;
options.connect_timeout = &tv;
options.timeout = &tv;
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
-3
View File
@@ -33,10 +33,7 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
}
int main (int argc, char **argv) {
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
uv_loop_t* loop = uv_default_loop();
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
-160
View File
@@ -1,160 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
#include <win32.h>
#define KEY_COUNT 5
#define panicAbort(fmt, ...) \
do { \
fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \
exit(-1); \
} while (0)
static void assertReplyAndFree(redisContext *context, redisReply *reply, int type) {
if (reply == NULL)
panicAbort("NULL reply from server (error: %s)", context->errstr);
if (reply->type != type) {
if (reply->type == REDIS_REPLY_ERROR)
fprintf(stderr, "Redis Error: %s\n", reply->str);
panicAbort("Expected reply type %d but got type %d", type, reply->type);
}
freeReplyObject(reply);
}
/* Switch to the RESP3 protocol and enable client tracking */
static void enableClientTracking(redisContext *c) {
redisReply *reply = redisCommand(c, "HELLO 3");
if (reply == NULL || c->err) {
panicAbort("NULL reply or server error (error: %s)", c->errstr);
}
if (reply->type != REDIS_REPLY_MAP) {
fprintf(stderr, "Error: Can't send HELLO 3 command. Are you sure you're ");
fprintf(stderr, "connected to redis-server >= 6.0.0?\nRedis error: %s\n",
reply->type == REDIS_REPLY_ERROR ? reply->str : "(unknown)");
exit(-1);
}
freeReplyObject(reply);
/* Enable client tracking */
reply = redisCommand(c, "CLIENT TRACKING ON");
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
}
void pushReplyHandler(void *privdata, void *r) {
redisReply *reply = r;
int *invalidations = privdata;
/* Sanity check on the invalidation reply */
if (reply->type != REDIS_REPLY_PUSH || reply->elements != 2 ||
reply->element[1]->type != REDIS_REPLY_ARRAY ||
reply->element[1]->element[0]->type != REDIS_REPLY_STRING)
{
panicAbort("%s", "Can't parse PUSH message!");
}
/* Increment our invalidation count */
*invalidations += 1;
printf("pushReplyHandler(): INVALIDATE '%s' (invalidation count: %d)\n",
reply->element[1]->element[0]->str, *invalidations);
freeReplyObject(reply);
}
/* We aren't actually freeing anything here, but it is included to show that we can
* have hiredis call our data destructor when freeing the context */
void privdata_dtor(void *privdata) {
unsigned int *icount = privdata;
printf("privdata_dtor(): In context privdata dtor (invalidations: %u)\n", *icount);
}
int main(int argc, char **argv) {
unsigned int j, invalidations = 0;
redisContext *c;
redisReply *reply;
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
int port = (argc > 2) ? atoi(argv[2]) : 6379;
redisOptions o = {0};
REDIS_OPTIONS_SET_TCP(&o, hostname, port);
/* Set our context privdata to the address of our invalidation counter. Each
* time our PUSH handler is called, hiredis will pass the privdata for context.
*
* This could also be done after we create the context like so:
*
* c->privdata = &invalidations;
* c->free_privdata = privdata_dtor;
*/
REDIS_OPTIONS_SET_PRIVDATA(&o, &invalidations, privdata_dtor);
/* Set our custom PUSH message handler */
o.push_cb = pushReplyHandler;
c = redisConnectWithOptions(&o);
if (c == NULL || c->err)
panicAbort("Connection error: %s", c ? c->errstr : "OOM");
/* Enable RESP3 and turn on client tracking */
enableClientTracking(c);
/* Set some keys and then read them back. Once we do that, Redis will deliver
* invalidation push messages whenever the key is modified */
for (j = 0; j < KEY_COUNT; j++) {
reply = redisCommand(c, "SET key:%d initial:%d", j, j);
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
reply = redisCommand(c, "GET key:%d", j);
assertReplyAndFree(c, reply, REDIS_REPLY_STRING);
}
/* Trigger invalidation messages by updating keys we just read */
for (j = 0; j < KEY_COUNT; j++) {
printf(" main(): SET key:%d update:%d\n", j, j);
reply = redisCommand(c, "SET key:%d update:%d", j, j);
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
printf(" main(): SET REPLY OK\n");
}
printf("\nTotal detected invalidations: %d, expected: %d\n", invalidations, KEY_COUNT);
/* PING server */
redisFree(c);
}
+2 -15
View File
@@ -4,12 +4,9 @@
#include <hiredis.h>
#include <hiredis_ssl.h>
#include <win32.h>
int main(int argc, char **argv) {
unsigned int j;
redisSSLContext *ssl;
redisSSLContextError ssl_error;
redisContext *c;
redisReply *reply;
if (argc < 4) {
@@ -22,18 +19,10 @@ int main(int argc, char **argv) {
const char *key = argv[4];
const char *ca = argc > 4 ? argv[5] : NULL;
redisInitOpenSSL();
ssl = redisCreateSSLContext(ca, NULL, cert, key, NULL, &ssl_error);
if (!ssl) {
printf("SSL Context error: %s\n",
redisSSLContextGetError(ssl_error));
exit(1);
}
struct timeval tv = { 1, 500000 }; // 1.5 seconds
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
options.connect_timeout = &tv;
options.timeout = &tv;
c = redisConnectWithOptions(&options);
if (c == NULL || c->err) {
@@ -46,7 +35,7 @@ int main(int argc, char **argv) {
exit(1);
}
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) {
printf("Couldn't initialize SSL!\n");
printf("Error: %s\n", c->errstr);
redisFree(c);
@@ -104,7 +93,5 @@ int main(int argc, char **argv) {
/* Disconnects and frees the context */
redisFree(c);
redisFreeSSLContext(ssl);
return 0;
}
+1 -1
View File
@@ -1,8 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
#include <win32.h>
int main(int argc, char **argv) {
unsigned int j, isunix = 0;
-13
View File
@@ -1,13 +0,0 @@
@PACKAGE_INIT@
set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
IF (NOT TARGET hiredis::hiredis)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake)
ENDIF()
SET(hiredis_LIBRARIES hiredis::hiredis)
SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR})
check_required_components(hiredis)
+110 -199
View File
@@ -44,11 +44,8 @@
#include "async.h"
#include "win32.h"
extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout);
extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
static redisContextFuncs redisContextDefaultFuncs = {
.free_privctx = NULL,
.free_privdata = NULL,
.async_read = redisAsyncRead,
.async_write = redisAsyncWrite,
.read = redisNetRead,
@@ -77,7 +74,7 @@ static redisReplyObjectFunctions defaultFunctions = {
/* Create a reply object */
static redisReply *createReplyObject(int type) {
redisReply *r = hi_calloc(1,sizeof(*r));
redisReply *r = calloc(1,sizeof(*r));
if (r == NULL)
return NULL;
@@ -100,22 +97,20 @@ void freeReplyObject(void *reply) {
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
case REDIS_REPLY_SET:
case REDIS_REPLY_PUSH:
if (r->element != NULL) {
for (j = 0; j < r->elements; j++)
freeReplyObject(r->element[j]);
hi_free(r->element);
free(r->element);
}
break;
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
case REDIS_REPLY_STRING:
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_VERB:
hi_free(r->str);
free(r->str);
break;
}
hi_free(r);
free(r);
}
static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
@@ -133,18 +128,22 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
/* Copy string value */
if (task->type == REDIS_REPLY_VERB) {
buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
if (buf == NULL) goto oom;
buf = malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
memcpy(r->vtype,str,3);
r->vtype[3] = '\0';
memcpy(buf,str+4,len-4);
buf[len-4] = '\0';
r->len = len - 4;
r->len = len-4;
} else {
buf = hi_malloc(len+1);
if (buf == NULL) goto oom;
buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
memcpy(buf,str,len);
buf[len] = '\0';
r->len = len;
@@ -155,15 +154,10 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->type == REDIS_REPLY_SET);
parent->element[task->idx] = r;
}
return r;
oom:
freeReplyObject(r);
return NULL;
}
static void *createArrayObject(const redisReadTask *task, size_t elements) {
@@ -174,8 +168,7 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
return NULL;
if (elements > 0) {
if (SIZE_MAX / sizeof(redisReply*) < elements) return NULL; /* Don't overflow */
r->element = hi_calloc(elements,sizeof(redisReply*));
r->element = calloc(elements,sizeof(redisReply*));
if (r->element == NULL) {
freeReplyObject(r);
return NULL;
@@ -188,8 +181,7 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->type == REDIS_REPLY_SET);
parent->element[task->idx] = r;
}
return r;
@@ -208,8 +200,7 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->type == REDIS_REPLY_SET);
parent->element[task->idx] = r;
}
return r;
@@ -223,7 +214,7 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
return NULL;
r->dval = value;
r->str = hi_malloc(len+1);
r->str = malloc(len+1);
if (r->str == NULL) {
freeReplyObject(r);
return NULL;
@@ -258,8 +249,7 @@ static void *createNilObject(const redisReadTask *task) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->type == REDIS_REPLY_SET);
parent->element[task->idx] = r;
}
return r;
@@ -307,7 +297,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
const char *c = format;
char *cmd = NULL; /* final command */
int pos; /* position in final command */
hisds curarg, newarg; /* current argument */
sds curarg, newarg; /* current argument */
int touched = 0; /* was the current argument touched? */
char **curargv = NULL, **newargv = NULL;
int argc = 0;
@@ -320,7 +310,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
return -1;
/* Build the command string accordingly to protocol */
curarg = hi_sdsempty();
curarg = sdsempty();
if (curarg == NULL)
return -1;
@@ -328,19 +318,19 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if (*c != '%' || c[1] == '\0') {
if (*c == ' ') {
if (touched) {
newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto memory_err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += bulklen(hi_sdslen(curarg));
totlen += bulklen(sdslen(curarg));
/* curarg is put in argv so it can be overwritten. */
curarg = hi_sdsempty();
curarg = sdsempty();
if (curarg == NULL) goto memory_err;
touched = 0;
}
} else {
newarg = hi_sdscatlen(curarg,c,1);
newarg = sdscatlen(curarg,c,1);
if (newarg == NULL) goto memory_err;
curarg = newarg;
touched = 1;
@@ -357,16 +347,16 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
arg = va_arg(ap,char*);
size = strlen(arg);
if (size > 0)
newarg = hi_sdscatlen(curarg,arg,size);
newarg = sdscatlen(curarg,arg,size);
break;
case 'b':
arg = va_arg(ap,char*);
size = va_arg(ap,size_t);
if (size > 0)
newarg = hi_sdscatlen(curarg,arg,size);
newarg = sdscatlen(curarg,arg,size);
break;
case '%':
newarg = hi_sdscat(curarg,"%");
newarg = sdscat(curarg,"%");
break;
default:
/* Try to detect printf format */
@@ -454,7 +444,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if (_l < sizeof(_format)-2) {
memcpy(_format,c,_l);
_format[_l] = '\0';
newarg = hi_sdscatvprintf(curarg,_format,_cpy);
newarg = sdscatvprintf(curarg,_format,_cpy);
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
@@ -477,13 +467,13 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
/* Add the last argument if needed */
if (touched) {
newargv = hi_realloc(curargv,sizeof(char*)*(argc+1));
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto memory_err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += bulklen(hi_sdslen(curarg));
totlen += bulklen(sdslen(curarg));
} else {
hi_sdsfree(curarg);
sdsfree(curarg);
}
/* Clear curarg because it was put in curargv or was free'd. */
@@ -493,22 +483,22 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
totlen += 1+countDigits(argc)+2;
/* Build the command at protocol level */
cmd = hi_malloc(totlen+1);
cmd = malloc(totlen+1);
if (cmd == NULL) goto memory_err;
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
pos += sprintf(cmd+pos,"$%zu\r\n",hi_sdslen(curargv[j]));
memcpy(cmd+pos,curargv[j],hi_sdslen(curargv[j]));
pos += hi_sdslen(curargv[j]);
hi_sdsfree(curargv[j]);
pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
pos += sdslen(curargv[j]);
sdsfree(curargv[j]);
cmd[pos++] = '\r';
cmd[pos++] = '\n';
}
assert(pos == totlen);
cmd[pos] = '\0';
hi_free(curargv);
free(curargv);
*target = cmd;
return totlen;
@@ -523,12 +513,12 @@ memory_err:
cleanup:
if (curargv) {
while(argc--)
hi_sdsfree(curargv[argc]);
hi_free(curargv);
sdsfree(curargv[argc]);
free(curargv);
}
hi_sdsfree(curarg);
hi_free(cmd);
sdsfree(curarg);
free(cmd);
return error_type;
}
@@ -560,16 +550,16 @@ int redisFormatCommand(char **target, const char *format, ...) {
return len;
}
/* Format a command according to the Redis protocol using an hisds string and
* hi_sdscatfmt for the processing of arguments. This function takes the
/* Format a command according to the Redis protocol using an sds string and
* sdscatfmt for the processing of arguments. This function takes the
* number of arguments, an array with arguments and an array with their
* lengths. If the latter is set to NULL, strlen will be used to compute the
* argument lengths.
*/
int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
const size_t *argvlen)
{
hisds cmd, aux;
sds cmd;
unsigned long long totlen;
int j;
size_t len;
@@ -586,36 +576,32 @@ int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
}
/* Use an SDS string for command construction */
cmd = hi_sdsempty();
cmd = sdsempty();
if (cmd == NULL)
return -1;
/* We already know how much storage we need */
aux = hi_sdsMakeRoomFor(cmd, totlen);
if (aux == NULL) {
hi_sdsfree(cmd);
cmd = sdsMakeRoomFor(cmd, totlen);
if (cmd == NULL)
return -1;
}
cmd = aux;
/* Construct command */
cmd = hi_sdscatfmt(cmd, "*%i\r\n", argc);
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
for (j=0; j < argc; j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]);
cmd = hi_sdscatfmt(cmd, "$%u\r\n", len);
cmd = hi_sdscatlen(cmd, argv[j], len);
cmd = hi_sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
cmd = sdscatfmt(cmd, "$%u\r\n", len);
cmd = sdscatlen(cmd, argv[j], len);
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
}
assert(hi_sdslen(cmd)==totlen);
assert(sdslen(cmd)==totlen);
*target = cmd;
return totlen;
}
void redisFreeSdsCommand(hisds cmd) {
hi_sdsfree(cmd);
void redisFreeSdsCommand(sds cmd) {
sdsfree(cmd);
}
/* Format a command according to the Redis protocol. This function takes the
@@ -641,7 +627,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
}
/* Build the command at protocol level */
cmd = hi_malloc(totlen+1);
cmd = malloc(totlen+1);
if (cmd == NULL)
return -1;
@@ -662,7 +648,7 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
}
void redisFreeCommand(char *cmd) {
hi_free(cmd);
free(cmd);
}
void __redisSetError(redisContext *c, int type, const char *str) {
@@ -685,21 +671,15 @@ redisReader *redisReaderCreate(void) {
return redisReaderCreateWithFunctions(&defaultFunctions);
}
static void redisPushAutoFree(void *privdata, void *reply) {
(void)privdata;
freeReplyObject(reply);
}
static redisContext *redisContextInit(void) {
static redisContext *redisContextInit(const redisOptions *options) {
redisContext *c;
c = hi_calloc(1, sizeof(*c));
c = calloc(1, sizeof(*c));
if (c == NULL)
return NULL;
c->funcs = &redisContextDefaultFuncs;
c->obuf = hi_sdsempty();
c->obuf = sdsempty();
c->reader = redisReaderCreate();
c->fd = REDIS_INVALID_FD;
@@ -707,7 +687,7 @@ static redisContext *redisContextInit(void) {
redisFree(c);
return NULL;
}
(void)options; /* options are used in other functions */
return c;
}
@@ -716,23 +696,18 @@ void redisFree(redisContext *c) {
return;
redisNetClose(c);
hi_sdsfree(c->obuf);
sdsfree(c->obuf);
redisReaderFree(c->reader);
hi_free(c->tcp.host);
hi_free(c->tcp.source_addr);
hi_free(c->unix_sock.path);
hi_free(c->connect_timeout);
hi_free(c->command_timeout);
hi_free(c->saddr);
if (c->privdata && c->free_privdata)
c->free_privdata(c->privdata);
if (c->funcs->free_privctx)
c->funcs->free_privctx(c->privctx);
free(c->tcp.host);
free(c->tcp.source_addr);
free(c->unix_sock.path);
free(c->timeout);
free(c->saddr);
if (c->funcs->free_privdata) {
c->funcs->free_privdata(c->privdata);
}
memset(c, 0xff, sizeof(*c));
hi_free(c);
free(c);
}
redisFD redisFreeKeepFd(redisContext *c) {
@@ -746,46 +721,35 @@ int redisReconnect(redisContext *c) {
c->err = 0;
memset(c->errstr, '\0', strlen(c->errstr));
if (c->privctx && c->funcs->free_privctx) {
c->funcs->free_privctx(c->privctx);
c->privctx = NULL;
if (c->privdata && c->funcs->free_privdata) {
c->funcs->free_privdata(c->privdata);
c->privdata = NULL;
}
redisNetClose(c);
hi_sdsfree(c->obuf);
sdsfree(c->obuf);
redisReaderFree(c->reader);
c->obuf = hi_sdsempty();
c->obuf = sdsempty();
c->reader = redisReaderCreate();
if (c->obuf == NULL || c->reader == NULL) {
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
int ret = REDIS_ERR;
if (c->connection_type == REDIS_CONN_TCP) {
ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
c->connect_timeout, c->tcp.source_addr);
return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
c->timeout, c->tcp.source_addr);
} else if (c->connection_type == REDIS_CONN_UNIX) {
ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_timeout);
return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
} else {
/* Something bad happened here and shouldn't have. There isn't
enough information in the context to reconnect. */
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
ret = REDIS_ERR;
}
if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
redisContextSetTimeout(c, *c->command_timeout);
}
return ret;
return REDIS_ERR;
}
redisContext *redisConnectWithOptions(const redisOptions *options) {
redisContext *c = redisContextInit();
redisContext *c = redisContextInit(options);
if (c == NULL) {
return NULL;
}
@@ -796,32 +760,16 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
c->flags |= REDIS_REUSEADDR;
}
if (options->options & REDIS_OPT_NOAUTOFREE) {
c->flags |= REDIS_NO_AUTO_FREE;
}
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
* as a default unless specifically flagged that we don't want one. */
if (options->push_cb != NULL)
redisSetPushCallback(c, options->push_cb);
else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE))
redisSetPushCallback(c, redisPushAutoFree);
c->privdata = options->privdata;
c->free_privdata = options->free_privdata;
if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK ||
redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) {
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
return c;
c->flags |= REDIS_NO_AUTO_FREE;
}
if (options->type == REDIS_CONN_TCP) {
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
options->endpoint.tcp.port, options->connect_timeout,
options->endpoint.tcp.port, options->timeout,
options->endpoint.tcp.source_addr);
} else if (options->type == REDIS_CONN_UNIX) {
redisContextConnectUnix(c, options->endpoint.unix_socket,
options->connect_timeout);
options->timeout);
} else if (options->type == REDIS_CONN_USERFD) {
c->fd = options->endpoint.fd;
c->flags |= REDIS_CONNECTED;
@@ -829,11 +777,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
// Unknown type - FIXME - FREE
return NULL;
}
if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
redisContextSetTimeout(c, *options->command_timeout);
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
redisContextSetTimeout(c, *options->timeout);
}
return c;
}
@@ -849,7 +795,7 @@ redisContext *redisConnect(const char *ip, int port) {
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.connect_timeout = &tv;
options.timeout = &tv;
return redisConnectWithOptions(&options);
}
@@ -887,7 +833,7 @@ redisContext *redisConnectUnix(const char *path) {
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
options.connect_timeout = &tv;
options.timeout = &tv;
return redisConnectWithOptions(&options);
}
@@ -919,13 +865,6 @@ int redisEnableKeepAlive(redisContext *c) {
return REDIS_OK;
}
/* Set a user provided RESP3 PUSH handler and return any old one set. */
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) {
redisPushFn *old = c->push_cb;
c->push_cb = fn;
return old;
}
/* Use this function to handle a read event on the descriptor. It will try
* and read some bytes from the socket and feed them to the reply parser.
*
@@ -967,27 +906,21 @@ int redisBufferWrite(redisContext *c, int *done) {
if (c->err)
return REDIS_ERR;
if (hi_sdslen(c->obuf) > 0) {
ssize_t nwritten = c->funcs->write(c);
if (sdslen(c->obuf) > 0) {
int nwritten = c->funcs->write(c);
if (nwritten < 0) {
return REDIS_ERR;
} else if (nwritten > 0) {
if (nwritten == (ssize_t)hi_sdslen(c->obuf)) {
hi_sdsfree(c->obuf);
c->obuf = hi_sdsempty();
if (c->obuf == NULL)
goto oom;
if (nwritten == (signed)sdslen(c->obuf)) {
sdsfree(c->obuf);
c->obuf = sdsempty();
} else {
if (hi_sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
sdsrange(c->obuf,nwritten,-1);
}
}
}
if (done != NULL) *done = (hi_sdslen(c->obuf) == 0);
if (done != NULL) *done = (sdslen(c->obuf) == 0);
return REDIS_OK;
oom:
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
/* Internal helper function to try and get a reply from the reader,
@@ -997,21 +930,9 @@ int redisGetReplyFromReader(redisContext *c, void **reply) {
__redisSetError(c,c->reader->err,c->reader->errstr);
return REDIS_ERR;
}
return REDIS_OK;
}
/* Internal helper that returns 1 if the reply was a RESP3 PUSH
* message and we handled it with a user-provided callback. */
static int redisHandledPushReply(redisContext *c, void *reply) {
if (reply && c->push_cb && redisIsPushReply(reply)) {
c->push_cb(c->privdata, reply);
return 1;
}
return 0;
}
int redisGetReply(redisContext *c, void **reply) {
int wdone = 0;
void *aux = NULL;
@@ -1032,23 +953,13 @@ int redisGetReply(redisContext *c, void **reply) {
do {
if (redisBufferRead(c) == REDIS_ERR)
return REDIS_ERR;
/* We loop here in case the user has specified a RESP3
* PUSH handler (e.g. for client tracking). */
do {
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
return REDIS_ERR;
} while (redisHandledPushReply(c, aux));
if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
return REDIS_ERR;
} while (aux == NULL);
}
/* Set reply or free it if we were passed NULL */
if (reply != NULL) {
*reply = aux;
} else {
freeReplyObject(aux);
}
/* Set reply object */
if (reply != NULL) *reply = aux;
return REDIS_OK;
}
@@ -1060,9 +971,9 @@ int redisGetReply(redisContext *c, void **reply) {
* the reply (or replies in pub/sub).
*/
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
hisds newbuf;
sds newbuf;
newbuf = hi_sdscatlen(c->obuf,cmd,len);
newbuf = sdscatlen(c->obuf,cmd,len);
if (newbuf == NULL) {
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
return REDIS_ERR;
@@ -1095,11 +1006,11 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
}
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
hi_free(cmd);
free(cmd);
return REDIS_ERR;
}
hi_free(cmd);
free(cmd);
return REDIS_OK;
}
@@ -1114,7 +1025,7 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
}
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
hisds cmd;
sds cmd;
int len;
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
@@ -1124,11 +1035,11 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
}
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
hi_sdsfree(cmd);
sdsfree(cmd);
return REDIS_ERR;
}
hi_sdsfree(cmd);
sdsfree(cmd);
return REDIS_OK;
}
+16 -53
View File
@@ -39,16 +39,14 @@
#include <sys/time.h> /* for struct timeval */
#else
struct timeval; /* forward declaration */
typedef long long ssize_t;
#endif
#include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for hisds */
#include "alloc.h" /* for allocation wrappers */
#include "sds.h" /* for sds */
#define HIREDIS_MAJOR 1
#define HIREDIS_MINOR 0
#define HIREDIS_MAJOR 0
#define HIREDIS_MINOR 14
#define HIREDIS_PATCH 0
#define HIREDIS_SONAME 1.0.0
#define HIREDIS_SONAME 0.14
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
@@ -92,15 +90,6 @@ typedef long long ssize_t;
* SO_REUSEADDR is being used. */
#define REDIS_CONNECT_RETRIES 10
/* Forward declarations for structs defined elsewhere */
struct redisAsyncContext;
struct redisContext;
/* RESP3 push helpers and callback prototypes */
#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH)
typedef void (redisPushFn)(void *, void *);
typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *);
#ifdef __cplusplus
extern "C" {
#endif
@@ -112,7 +101,7 @@ typedef struct redisReply {
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
size_t len; /* Length of string */
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
and REDIS_REPLY_DOUBLE (in additionl to dval). */
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
terminated 3 character content type, such as "txt". */
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
@@ -128,9 +117,9 @@ void freeReplyObject(void *reply);
int redisvFormatCommand(char **target, const char *format, va_list ap);
int redisFormatCommand(char **target, const char *format, ...);
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
int redisFormatSdsCommandArgv(hisds *target, int argc, const char ** argv, const size_t *argvlen);
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
void redisFreeCommand(char *cmd);
void redisFreeSdsCommand(hisds cmd);
void redisFreeSdsCommand(sds cmd);
enum redisConnectionType {
REDIS_CONN_TCP,
@@ -149,9 +138,6 @@ struct redisSsl;
*/
#define REDIS_OPT_NOAUTOFREE 0x04
/* Don't automatically intercept and free RESP3 PUSH replies. */
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
/* In Unix systems a file descriptor is a regular signed int, with -1
* representing an invalid descriptor. In Windows it is a SOCKET
* (32- or 64-bit unsigned integer depending on the architecture), where
@@ -176,11 +162,8 @@ typedef struct {
int type;
/* bit field of REDIS_OPT_xxx */
int options;
/* timeout value for connect operation. If NULL, no timeout is used */
const struct timeval *connect_timeout;
/* timeout value for commands. If NULL, no timeout is used. This can be
* updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */
const struct timeval *command_timeout;
/* timeout value. if NULL, no timeout is used */
const struct timeval *timeout;
union {
/** use this field for tcp/ip connections */
struct {
@@ -195,14 +178,6 @@ typedef struct {
* file descriptor */
redisFD fd;
} endpoint;
/* Optional user defined data/destructor */
void *privdata;
void (*free_privdata)(void *);
/* A user defined PUSH message callback */
redisPushFn *push_cb;
redisAsyncPushFn *async_push_cb;
} redisOptions;
/**
@@ -217,16 +192,15 @@ typedef struct {
(opts)->type = REDIS_CONN_UNIX; \
(opts)->endpoint.unix_socket = path;
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
(opts)->privdata = data; \
(opts)->free_privdata = dtor; \
struct redisAsyncContext;
struct redisContext;
typedef struct redisContextFuncs {
void (*free_privctx)(void *);
void (*free_privdata)(void *);
void (*async_read)(struct redisAsyncContext *);
void (*async_write)(struct redisAsyncContext *);
ssize_t (*read)(struct redisContext *, char *, size_t);
ssize_t (*write)(struct redisContext *);
int (*read)(struct redisContext *, char *, size_t);
int (*write)(struct redisContext *);
} redisContextFuncs;
/* Context for a connection to Redis */
@@ -241,8 +215,7 @@ typedef struct redisContext {
redisReader *reader; /* Protocol reader */
enum redisConnectionType connection_type;
struct timeval *connect_timeout;
struct timeval *command_timeout;
struct timeval *timeout;
struct {
char *host;
@@ -258,17 +231,8 @@ typedef struct redisContext {
struct sockadr *saddr;
size_t addrlen;
/* Optional data and corresponding destructor users can use to provide
* context to a given redisContext. Not used by hiredis. */
/* Additional private data for hiredis addons such as SSL */
void *privdata;
void (*free_privdata)(void *);
/* Internal context pointer presently used by hiredis to manage
* SSL connections. */
void *privctx;
/* An optional RESP3 PUSH handler */
redisPushFn *push_cb;
} redisContext;
redisContext *redisConnectWithOptions(const redisOptions *options);
@@ -295,7 +259,6 @@ redisContext *redisConnectFd(redisFD fd);
*/
int redisReconnect(redisContext *c);
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn);
int redisSetTimeout(redisContext *c, const struct timeval tv);
int redisEnableKeepAlive(redisContext *c);
void redisFree(redisContext *c);
+1 -2
View File
@@ -1,7 +1,6 @@
prefix=@CMAKE_INSTALL_PREFIX@
install_libdir=@CMAKE_INSTALL_LIBDIR@
exec_prefix=${prefix}
libdir=${exec_prefix}/${install_libdir}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis
-13
View File
@@ -1,13 +0,0 @@
@PACKAGE_INIT@
set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
IF (NOT TARGET hiredis::hiredis_ssl)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake)
ENDIF()
SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl)
SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR})
check_required_components(hiredis_ssl)
+6 -80
View File
@@ -32,96 +32,22 @@
#ifndef __HIREDIS_SSL_H
#define __HIREDIS_SSL_H
#ifdef __cplusplus
extern "C" {
#endif
/* This is the underlying struct for SSL in ssl.h, which is not included to
* keep build dependencies short here.
*/
struct ssl_st;
/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly
* calling OpenSSL.
/**
* Secure the connection using SSL. This should be done before any command is
* executed on the connection.
*/
typedef struct redisSSLContext redisSSLContext;
int redisSecureConnection(redisContext *c, const char *capath, const char *certpath,
const char *keypath, const char *servername);
/**
* Initialization errors that redisCreateSSLContext() may return.
*/
typedef enum {
REDIS_SSL_CTX_NONE = 0, /* No Error */
REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */
REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */
} redisSSLContextError;
/**
* Return the error message corresponding with the specified error code.
*/
const char *redisSSLContextGetError(redisSSLContextError error);
/**
* Helper function to initialize the OpenSSL library.
*
* OpenSSL requires one-time initialization before it can be used. Callers should
* call this function only once, and only if OpenSSL is not directly initialized
* elsewhere.
*/
int redisInitOpenSSL(void);
/**
* Helper function to initialize an OpenSSL context that can be used
* to initiate SSL connections.
*
* cacert_filename is an optional name of a CA certificate/bundle file to load
* and use for validation.
*
* capath is an optional directory path where trusted CA certificate files are
* stored in an OpenSSL-compatible structure.
*
* cert_filename and private_key_filename are optional names of a client side
* certificate and private key files to use for authentication. They need to
* be both specified or omitted.
*
* server_name is an optional and will be used as a server name indication
* (SNI) TLS extension.
*
* If error is non-null, it will be populated in case the context creation fails
* (returning a NULL).
*/
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
const char *cert_filename, const char *private_key_filename,
const char *server_name, redisSSLContextError *error);
/**
* Free a previously created OpenSSL context.
*/
void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx);
/**
* Initiate SSL on an existing redisContext.
*
* This is similar to redisInitiateSSL() but does not require the caller
* to directly interact with OpenSSL, and instead uses a redisSSLContext
* previously created using redisCreateSSLContext().
*/
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx);
/**
* Initiate SSL/TLS negotiation on a provided OpenSSL SSL object.
* Initiate SSL/TLS negotiation on a provided context.
*/
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
#ifdef __cplusplus
}
#endif
#endif /* __HIREDIS_SSL_H */
+39 -80
View File
@@ -57,8 +57,8 @@ void redisNetClose(redisContext *c) {
}
}
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
ssize_t nread = recv(c->fd, buf, bufcap, 0);
int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
int nread = recv(c->fd, buf, bufcap, 0);
if (nread == -1) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
@@ -79,8 +79,8 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
}
}
ssize_t redisNetWrite(redisContext *c) {
ssize_t nwritten = send(c->fd, c->obuf, hi_sdslen(c->obuf), 0);
int redisNetWrite(redisContext *c) {
int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
if (nwritten < 0) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
@@ -203,7 +203,7 @@ int redisKeepAlive(redisContext *c, int interval) {
return REDIS_OK;
}
int redisSetTcpNoDelay(redisContext *c) {
static int redisSetTcpNoDelay(redisContext *c) {
int yes = 1;
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
@@ -217,7 +217,7 @@ int redisSetTcpNoDelay(redisContext *c) {
static int redisContextTimeoutMsec(redisContext *c, long *result)
{
const struct timeval *timeout = c->connect_timeout;
const struct timeval *timeout = c->timeout;
long msec = -1;
/* Only use timeout when not NULL. */
@@ -316,7 +316,11 @@ int redisCheckSocketError(redisContext *c) {
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
const void *to_ptr = &tv;
size_t to_sz = sizeof(tv);
#ifdef _WIN32
DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
to_ptr = &timeout_msec;
to_sz = sizeof(timeout_msec);
#endif
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
return REDIS_ERR;
@@ -328,38 +332,6 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
return REDIS_OK;
}
int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
/* Same timeval struct, short circuit */
if (c->connect_timeout == timeout)
return REDIS_OK;
/* Allocate context timeval if we need to */
if (c->connect_timeout == NULL) {
c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
if (c->connect_timeout == NULL)
return REDIS_ERR;
}
memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
return REDIS_OK;
}
int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
/* Same timeval struct, short circuit */
if (c->command_timeout == timeout)
return REDIS_OK;
/* Allocate context timeval if we need to */
if (c->command_timeout == NULL) {
c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
if (c->command_timeout == NULL)
return REDIS_ERR;
}
memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
return REDIS_OK;
}
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout,
const char *source_addr) {
@@ -384,19 +356,21 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
* This is a bit ugly, but atleast it works and doesn't leak memory.
**/
if (c->tcp.host != addr) {
hi_free(c->tcp.host);
free(c->tcp.host);
c->tcp.host = hi_strdup(addr);
if (c->tcp.host == NULL)
goto oom;
c->tcp.host = strdup(addr);
}
if (timeout) {
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
goto oom;
if (c->timeout != timeout) {
if (c->timeout == NULL)
c->timeout = malloc(sizeof(struct timeval));
memcpy(c->timeout, timeout, sizeof(struct timeval));
}
} else {
hi_free(c->connect_timeout);
c->connect_timeout = NULL;
free(c->timeout);
c->timeout = NULL;
}
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
@@ -405,11 +379,11 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
}
if (source_addr == NULL) {
hi_free(c->tcp.source_addr);
free(c->tcp.source_addr);
c->tcp.source_addr = NULL;
} else if (c->tcp.source_addr != source_addr) {
hi_free(c->tcp.source_addr);
c->tcp.source_addr = hi_strdup(source_addr);
free(c->tcp.source_addr);
c->tcp.source_addr = strdup(source_addr);
}
snprintf(_port, 6, "%d", port);
@@ -472,11 +446,8 @@ addrretry:
}
/* For repeat connection */
hi_free(c->saddr);
c->saddr = hi_malloc(p->ai_addrlen);
if (c->saddr == NULL)
goto oom;
free(c->saddr);
c->saddr = malloc(p->ai_addrlen);
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
c->addrlen = p->ai_addrlen;
@@ -503,12 +474,12 @@ addrretry:
wait_for_ready:
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
goto error;
if (redisSetTcpNoDelay(c) != REDIS_OK)
goto error;
}
}
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
goto error;
if (redisSetTcpNoDelay(c) != REDIS_OK)
goto error;
c->flags |= REDIS_CONNECTED;
rv = REDIS_OK;
@@ -521,8 +492,6 @@ addrretry:
goto error;
}
oom:
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
error:
rv = REDIS_ERR;
end:
@@ -556,32 +525,25 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
return REDIS_ERR;
c->connection_type = REDIS_CONN_UNIX;
if (c->unix_sock.path != path) {
hi_free(c->unix_sock.path);
c->unix_sock.path = hi_strdup(path);
if (c->unix_sock.path == NULL)
goto oom;
}
if (c->unix_sock.path != path)
c->unix_sock.path = strdup(path);
if (timeout) {
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
goto oom;
if (c->timeout != timeout) {
if (c->timeout == NULL)
c->timeout = malloc(sizeof(struct timeval));
memcpy(c->timeout, timeout, sizeof(struct timeval));
}
} else {
hi_free(c->connect_timeout);
c->connect_timeout = NULL;
free(c->timeout);
c->timeout = NULL;
}
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
return REDIS_ERR;
/* Don't leak sockaddr if we're reconnecting */
if (c->saddr) hi_free(c->saddr);
sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un)));
if (sa == NULL)
goto oom;
sa = (struct sockaddr_un*)(c->saddr = malloc(sizeof(struct sockaddr_un)));
c->addrlen = sizeof(struct sockaddr_un);
sa->sun_family = AF_UNIX;
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
@@ -606,7 +568,4 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
errno = EPROTONOSUPPORT;
return REDIS_ERR;
#endif /* _WIN32 */
oom:
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
+2 -4
View File
@@ -38,8 +38,8 @@
#include "hiredis.h"
void redisNetClose(redisContext *c);
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
ssize_t redisNetWrite(redisContext *c);
int redisNetRead(redisContext *c, char *buf, size_t bufcap);
int redisNetWrite(redisContext *c);
int redisCheckSocketError(redisContext *c);
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
@@ -51,6 +51,4 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
int redisKeepAlive(redisContext *c, int interval);
int redisCheckConnectDone(redisContext *c, int *completed);
int redisSetTcpNoDelay(redisContext *c);
#endif
+50 -108
View File
@@ -42,14 +42,10 @@
#include <limits.h>
#include <math.h>
#include "alloc.h"
#include "read.h"
#include "sds.h"
#include "win32.h"
/* Initial size of our nested reply stack and how much we grow it when needd */
#define REDIS_READER_STACK_SIZE 9
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
size_t len;
@@ -59,7 +55,7 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
}
/* Clear input buffer on errors. */
hi_sdsfree(r->buf);
sdsfree(r->buf);
r->buf = NULL;
r->pos = r->len = 0;
@@ -247,12 +243,11 @@ static void moveToNextTask(redisReader *r) {
return;
}
cur = r->task[r->ridx];
prv = r->task[r->ridx-1];
cur = &(r->rstack[r->ridx]);
prv = &(r->rstack[r->ridx-1]);
assert(prv->type == REDIS_REPLY_ARRAY ||
prv->type == REDIS_REPLY_MAP ||
prv->type == REDIS_REPLY_SET ||
prv->type == REDIS_REPLY_PUSH);
prv->type == REDIS_REPLY_SET);
if (cur->idx == prv->elements-1) {
r->ridx--;
} else {
@@ -267,7 +262,7 @@ static void moveToNextTask(redisReader *r) {
}
static int processLineItem(redisReader *r) {
redisReadTask *cur = r->task[r->ridx];
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
int len;
@@ -302,7 +297,7 @@ static int processLineItem(redisReader *r) {
if (strcasecmp(buf,",inf") == 0) {
d = INFINITY; /* Positive infinite. */
} else if (strcasecmp(buf,",-inf") == 0) {
d = -INFINITY; /* Negative infinite. */
d = -INFINITY; /* Nevative infinite. */
} else {
d = strtod((char*)buf,&eptr);
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
@@ -349,7 +344,7 @@ static int processLineItem(redisReader *r) {
}
static int processBulkItem(redisReader *r) {
redisReadTask *cur = r->task[r->ridx];
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj = NULL;
char *p, *s;
long long len;
@@ -420,43 +415,19 @@ static int processBulkItem(redisReader *r) {
return REDIS_ERR;
}
static int redisReaderGrow(redisReader *r) {
redisReadTask **aux;
int newlen;
/* Grow our stack size */
newlen = r->tasks + REDIS_READER_STACK_SIZE;
aux = hi_realloc(r->task, sizeof(*r->task) * newlen);
if (aux == NULL)
goto oom;
r->task = aux;
/* Allocate new tasks */
for (; r->tasks < newlen; r->tasks++) {
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
if (r->task[r->tasks] == NULL)
goto oom;
}
return REDIS_OK;
oom:
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
/* Process the array, map and set types. */
static int processAggregateItem(redisReader *r) {
redisReadTask *cur = r->task[r->ridx];
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
long long elements;
int root = 0, len;
/* Set error for nested multi bulks with depth > 7 */
if (r->ridx == r->tasks - 1) {
if (redisReaderGrow(r) == REDIS_ERR)
return REDIS_ERR;
if (r->ridx == 8) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"No support for nested multi bulk replies with depth > 7");
return REDIS_ERR;
}
if ((p = readLine(r,&len)) != NULL) {
@@ -468,9 +439,7 @@ static int processAggregateItem(redisReader *r) {
root = (r->ridx == 0);
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) ||
(r->maxelements > 0 && elements > r->maxelements))
{
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Multi-bulk length out of range");
return REDIS_ERR;
@@ -506,12 +475,12 @@ static int processAggregateItem(redisReader *r) {
cur->elements = elements;
cur->obj = obj;
r->ridx++;
r->task[r->ridx]->type = -1;
r->task[r->ridx]->elements = -1;
r->task[r->ridx]->idx = 0;
r->task[r->ridx]->obj = NULL;
r->task[r->ridx]->parent = cur;
r->task[r->ridx]->privdata = r->privdata;
r->rstack[r->ridx].type = -1;
r->rstack[r->ridx].elements = -1;
r->rstack[r->ridx].idx = 0;
r->rstack[r->ridx].obj = NULL;
r->rstack[r->ridx].parent = cur;
r->rstack[r->ridx].privdata = r->privdata;
} else {
moveToNextTask(r);
}
@@ -526,7 +495,7 @@ static int processAggregateItem(redisReader *r) {
}
static int processItem(redisReader *r) {
redisReadTask *cur = r->task[r->ridx];
redisReadTask *cur = &(r->rstack[r->ridx]);
char *p;
/* check if we need to read type */
@@ -566,9 +535,6 @@ static int processItem(redisReader *r) {
case '=':
cur->type = REDIS_REPLY_VERB;
break;
case '>':
cur->type = REDIS_REPLY_PUSH;
break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
@@ -594,7 +560,6 @@ static int processItem(redisReader *r) {
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
case REDIS_REPLY_SET:
case REDIS_REPLY_PUSH:
return processAggregateItem(r);
default:
assert(NULL);
@@ -605,57 +570,33 @@ static int processItem(redisReader *r) {
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
redisReader *r;
r = hi_calloc(1,sizeof(redisReader));
r = calloc(1,sizeof(redisReader));
if (r == NULL)
return NULL;
r->buf = hi_sdsempty();
if (r->buf == NULL)
goto oom;
r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task));
if (r->task == NULL)
goto oom;
for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) {
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
if (r->task[r->tasks] == NULL)
goto oom;
r->fn = fn;
r->buf = sdsempty();
r->maxbuf = REDIS_READER_MAX_BUF;
if (r->buf == NULL) {
free(r);
return NULL;
}
r->fn = fn;
r->maxbuf = REDIS_READER_MAX_BUF;
r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS;
r->ridx = -1;
return r;
oom:
redisReaderFree(r);
return NULL;
}
void redisReaderFree(redisReader *r) {
if (r == NULL)
return;
if (r->reply != NULL && r->fn && r->fn->freeObject)
r->fn->freeObject(r->reply);
if (r->task) {
/* We know r->task[i] is allocated if i < r->tasks */
for (int i = 0; i < r->tasks; i++) {
hi_free(r->task[i]);
}
hi_free(r->task);
}
hi_sdsfree(r->buf);
hi_free(r);
sdsfree(r->buf);
free(r);
}
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
hisds newbuf;
sds newbuf;
/* Return early when this reader is in an erroneous state. */
if (r->err)
@@ -664,25 +605,26 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
/* Copy the provided buffer. */
if (buf != NULL && len >= 1) {
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && r->maxbuf != 0 && hi_sdsavail(r->buf) > r->maxbuf) {
hi_sdsfree(r->buf);
r->buf = hi_sdsempty();
if (r->buf == 0) goto oom;
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
sdsfree(r->buf);
r->buf = sdsempty();
r->pos = 0;
/* r->buf should not be NULL since we just free'd a larger one. */
assert(r->buf != NULL);
}
newbuf = hi_sdscatlen(r->buf,buf,len);
if (newbuf == NULL) goto oom;
newbuf = sdscatlen(r->buf,buf,len);
if (newbuf == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
r->buf = newbuf;
r->len = hi_sdslen(r->buf);
r->len = sdslen(r->buf);
}
return REDIS_OK;
oom:
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
int redisReaderGetReply(redisReader *r, void **reply) {
@@ -700,12 +642,12 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Set first item to process when the stack is empty. */
if (r->ridx == -1) {
r->task[0]->type = -1;
r->task[0]->elements = -1;
r->task[0]->idx = -1;
r->task[0]->obj = NULL;
r->task[0]->parent = NULL;
r->task[0]->privdata = r->privdata;
r->rstack[0].type = -1;
r->rstack[0].elements = -1;
r->rstack[0].idx = -1;
r->rstack[0].obj = NULL;
r->rstack[0].parent = NULL;
r->rstack[0].privdata = r->privdata;
r->ridx = 0;
}
@@ -721,9 +663,9 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Discard part of the buffer when we've consumed at least 1k, to avoid
* doing unnecessary calls to memmove() in sds.c. */
if (r->pos >= 1024) {
if (hi_sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
sdsrange(r->buf,r->pos,-1);
r->pos = 0;
r->len = hi_sdslen(r->buf);
r->len = sdslen(r->buf);
}
/* Emit a reply when there is one. */
+3 -10
View File
@@ -63,11 +63,7 @@
#define REDIS_REPLY_BIGNUM 13
#define REDIS_REPLY_VERB 14
/* Default max unused reader buffer. */
#define REDIS_READER_MAX_BUF (1024*16)
/* Default multi-bulk element limit */
#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1)
#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
#ifdef __cplusplus
extern "C" {
@@ -75,7 +71,7 @@ extern "C" {
typedef struct redisReadTask {
int type;
long long elements; /* number of elements in multibulk container */
int elements; /* number of elements in multibulk container */
int idx; /* index in parent (array) object */
void *obj; /* holds user-generated value for a read task */
struct redisReadTask *parent; /* parent task */
@@ -100,11 +96,8 @@ typedef struct redisReader {
size_t pos; /* Buffer cursor */
size_t len; /* Buffer length */
size_t maxbuf; /* Max length of unused buffer */
long long maxelements; /* Max multi-bulk elements */
redisReadTask **task;
int tasks;
redisReadTask rstack[9];
int ridx; /* Index of current read task */
void *reply; /* Temporary reply pointer */
+415 -413
View File
File diff suppressed because it is too large. Load diff
+131 -133
View File
@@ -30,31 +30,29 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HIREDIS_SDS_H
#define HIREDIS_SDS_H
#ifndef __SDS_H
#define __SDS_H
#define HI_SDS_MAX_PREALLOC (1024*1024)
#define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#define __attribute__(x)
typedef long long ssize_t;
#define SSIZE_MAX (LLONG_MAX >> 1)
#endif
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
typedef char *hisds;
typedef char *sds;
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) hisdshdr5 {
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
#ifndef __cplusplus
char buf[];
#endif
};
struct __attribute__ ((__packed__)) hisdshdr8 {
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
@@ -62,7 +60,7 @@ struct __attribute__ ((__packed__)) hisdshdr8 {
char buf[];
#endif
};
struct __attribute__ ((__packed__)) hisdshdr16 {
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
@@ -70,7 +68,7 @@ struct __attribute__ ((__packed__)) hisdshdr16 {
char buf[];
#endif
};
struct __attribute__ ((__packed__)) hisdshdr32 {
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
@@ -78,7 +76,7 @@ struct __attribute__ ((__packed__)) hisdshdr32 {
char buf[];
#endif
};
struct __attribute__ ((__packed__)) hisdshdr64 {
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
@@ -87,203 +85,203 @@ struct __attribute__ ((__packed__)) hisdshdr64 {
#endif
};
#define HI_SDS_TYPE_5 0
#define HI_SDS_TYPE_8 1
#define HI_SDS_TYPE_16 2
#define HI_SDS_TYPE_32 3
#define HI_SDS_TYPE_64 4
#define HI_SDS_TYPE_MASK 7
#define HI_SDS_TYPE_BITS 3
#define HI_SDS_HDR_VAR(T,s) struct hisdshdr##T *sh = (struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T)));
#define HI_SDS_HDR(T,s) ((struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T))))
#define HI_SDS_TYPE_5_LEN(f) ((f)>>HI_SDS_TYPE_BITS)
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
static inline size_t hi_sdslen(const hisds s) {
static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
switch(__builtin_expect((flags&HI_SDS_TYPE_MASK), HI_SDS_TYPE_5)) {
case HI_SDS_TYPE_5:
return HI_SDS_TYPE_5_LEN(flags);
case HI_SDS_TYPE_8:
return HI_SDS_HDR(8,s)->len;
case HI_SDS_TYPE_16:
return HI_SDS_HDR(16,s)->len;
case HI_SDS_TYPE_32:
return HI_SDS_HDR(32,s)->len;
case HI_SDS_TYPE_64:
return HI_SDS_HDR(64,s)->len;
switch(__builtin_expect((flags&SDS_TYPE_MASK), SDS_TYPE_5)) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->len;
case SDS_TYPE_16:
return SDS_HDR(16,s)->len;
case SDS_TYPE_32:
return SDS_HDR(32,s)->len;
case SDS_TYPE_64:
return SDS_HDR(64,s)->len;
}
return 0;
}
static inline size_t hi_sdsavail(const hisds s) {
static inline size_t sdsavail(const sds s) {
unsigned char flags = s[-1];
switch(flags&HI_SDS_TYPE_MASK) {
case HI_SDS_TYPE_5: {
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5: {
return 0;
}
case HI_SDS_TYPE_8: {
HI_SDS_HDR_VAR(8,s);
case SDS_TYPE_8: {
SDS_HDR_VAR(8,s);
return sh->alloc - sh->len;
}
case HI_SDS_TYPE_16: {
HI_SDS_HDR_VAR(16,s);
case SDS_TYPE_16: {
SDS_HDR_VAR(16,s);
return sh->alloc - sh->len;
}
case HI_SDS_TYPE_32: {
HI_SDS_HDR_VAR(32,s);
case SDS_TYPE_32: {
SDS_HDR_VAR(32,s);
return sh->alloc - sh->len;
}
case HI_SDS_TYPE_64: {
HI_SDS_HDR_VAR(64,s);
case SDS_TYPE_64: {
SDS_HDR_VAR(64,s);
return sh->alloc - sh->len;
}
}
return 0;
}
static inline void hi_sdssetlen(hisds s, size_t newlen) {
static inline void sdssetlen(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&HI_SDS_TYPE_MASK) {
case HI_SDS_TYPE_5:
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
*fp = (unsigned char)(HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS));
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
}
break;
case HI_SDS_TYPE_8:
HI_SDS_HDR(8,s)->len = (uint8_t)newlen;
case SDS_TYPE_8:
SDS_HDR(8,s)->len = (uint8_t)newlen;
break;
case HI_SDS_TYPE_16:
HI_SDS_HDR(16,s)->len = (uint16_t)newlen;
case SDS_TYPE_16:
SDS_HDR(16,s)->len = (uint16_t)newlen;
break;
case HI_SDS_TYPE_32:
HI_SDS_HDR(32,s)->len = (uint32_t)newlen;
case SDS_TYPE_32:
SDS_HDR(32,s)->len = (uint32_t)newlen;
break;
case HI_SDS_TYPE_64:
HI_SDS_HDR(64,s)->len = (uint64_t)newlen;
case SDS_TYPE_64:
SDS_HDR(64,s)->len = (uint64_t)newlen;
break;
}
}
static inline void hi_sdsinclen(hisds s, size_t inc) {
static inline void sdsinclen(sds s, size_t inc) {
unsigned char flags = s[-1];
switch(flags&HI_SDS_TYPE_MASK) {
case HI_SDS_TYPE_5:
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
unsigned char newlen = HI_SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
*fp = HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS);
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
case HI_SDS_TYPE_8:
HI_SDS_HDR(8,s)->len += (uint8_t)inc;
case SDS_TYPE_8:
SDS_HDR(8,s)->len += (uint8_t)inc;
break;
case HI_SDS_TYPE_16:
HI_SDS_HDR(16,s)->len += (uint16_t)inc;
case SDS_TYPE_16:
SDS_HDR(16,s)->len += (uint16_t)inc;
break;
case HI_SDS_TYPE_32:
HI_SDS_HDR(32,s)->len += (uint32_t)inc;
case SDS_TYPE_32:
SDS_HDR(32,s)->len += (uint32_t)inc;
break;
case HI_SDS_TYPE_64:
HI_SDS_HDR(64,s)->len += (uint64_t)inc;
case SDS_TYPE_64:
SDS_HDR(64,s)->len += (uint64_t)inc;
break;
}
}
/* hi_sdsalloc() = hi_sdsavail() + hi_sdslen() */
static inline size_t hi_sdsalloc(const hisds s) {
/* sdsalloc() = sdsavail() + sdslen() */
static inline size_t sdsalloc(const sds s) {
unsigned char flags = s[-1];
switch(flags & HI_SDS_TYPE_MASK) {
case HI_SDS_TYPE_5:
return HI_SDS_TYPE_5_LEN(flags);
case HI_SDS_TYPE_8:
return HI_SDS_HDR(8,s)->alloc;
case HI_SDS_TYPE_16:
return HI_SDS_HDR(16,s)->alloc;
case HI_SDS_TYPE_32:
return HI_SDS_HDR(32,s)->alloc;
case HI_SDS_TYPE_64:
return HI_SDS_HDR(64,s)->alloc;
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->alloc;
case SDS_TYPE_16:
return SDS_HDR(16,s)->alloc;
case SDS_TYPE_32:
return SDS_HDR(32,s)->alloc;
case SDS_TYPE_64:
return SDS_HDR(64,s)->alloc;
}
return 0;
}
static inline void hi_sdssetalloc(hisds s, size_t newlen) {
static inline void sdssetalloc(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&HI_SDS_TYPE_MASK) {
case HI_SDS_TYPE_5:
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
/* Nothing to do, this type has no total allocation info. */
break;
case HI_SDS_TYPE_8:
HI_SDS_HDR(8,s)->alloc = (uint8_t)newlen;
case SDS_TYPE_8:
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
break;
case HI_SDS_TYPE_16:
HI_SDS_HDR(16,s)->alloc = (uint16_t)newlen;
case SDS_TYPE_16:
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
break;
case HI_SDS_TYPE_32:
HI_SDS_HDR(32,s)->alloc = (uint32_t)newlen;
case SDS_TYPE_32:
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
break;
case HI_SDS_TYPE_64:
HI_SDS_HDR(64,s)->alloc = (uint64_t)newlen;
case SDS_TYPE_64:
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
break;
}
}
hisds hi_sdsnewlen(const void *init, size_t initlen);
hisds hi_sdsnew(const char *init);
hisds hi_sdsempty(void);
hisds hi_sdsdup(const hisds s);
void hi_sdsfree(hisds s);
hisds hi_sdsgrowzero(hisds s, size_t len);
hisds hi_sdscatlen(hisds s, const void *t, size_t len);
hisds hi_sdscat(hisds s, const char *t);
hisds hi_sdscatsds(hisds s, const hisds t);
hisds hi_sdscpylen(hisds s, const char *t, size_t len);
hisds hi_sdscpy(hisds s, const char *t);
sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init);
sds sdsempty(void);
sds sdsdup(const sds s);
void sdsfree(sds s);
sds sdsgrowzero(sds s, size_t len);
sds sdscatlen(sds s, const void *t, size_t len);
sds sdscat(sds s, const char *t);
sds sdscatsds(sds s, const sds t);
sds sdscpylen(sds s, const char *t, size_t len);
sds sdscpy(sds s, const char *t);
hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap);
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
#ifdef __GNUC__
hisds hi_sdscatprintf(hisds s, const char *fmt, ...)
sds sdscatprintf(sds s, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
hisds hi_sdscatprintf(hisds s, const char *fmt, ...);
sds sdscatprintf(sds s, const char *fmt, ...);
#endif
hisds hi_sdscatfmt(hisds s, char const *fmt, ...);
hisds hi_sdstrim(hisds s, const char *cset);
int hi_sdsrange(hisds s, ssize_t start, ssize_t end);
void hi_sdsupdatelen(hisds s);
void hi_sdsclear(hisds s);
int hi_sdscmp(const hisds s1, const hisds s2);
hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
void hi_sdsfreesplitres(hisds *tokens, int count);
void hi_sdstolower(hisds s);
void hi_sdstoupper(hisds s);
hisds hi_sdsfromlonglong(long long value);
hisds hi_sdscatrepr(hisds s, const char *p, size_t len);
hisds *hi_sdssplitargs(const char *line, int *argc);
hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen);
hisds hi_sdsjoin(char **argv, int argc, char *sep);
hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen);
sds sdscatfmt(sds s, char const *fmt, ...);
sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, int start, int end);
void sdsupdatelen(sds s);
void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2);
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count);
void sdstolower(sds s);
void sdstoupper(sds s);
sds sdsfromlonglong(long long value);
sds sdscatrepr(sds s, const char *p, size_t len);
sds *sdssplitargs(const char *line, int *argc);
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
sds sdsjoin(char **argv, int argc, char *sep);
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
/* Low level functions exposed to the user API */
hisds hi_sdsMakeRoomFor(hisds s, size_t addlen);
void hi_sdsIncrLen(hisds s, int incr);
hisds hi_sdsRemoveFreeSpace(hisds s);
size_t hi_sdsAllocSize(hisds s);
void *hi_sdsAllocPtr(hisds s);
sds sdsMakeRoomFor(sds s, size_t addlen);
void sdsIncrLen(sds s, int incr);
sds sdsRemoveFreeSpace(sds s);
size_t sdsAllocSize(sds s);
void *sdsAllocPtr(sds s);
/* Export the allocator used by SDS to the program using SDS.
* Sometimes the program SDS is linked to, may use a different set of
* allocators, but may want to allocate or free things that SDS will
* respectively free or allocate. */
void *hi_sds_malloc(size_t size);
void *hi_sds_realloc(void *ptr, size_t size);
void hi_sds_free(void *ptr);
void *sds_malloc(size_t size);
void *sds_realloc(void *ptr, size_t size);
void sds_free(void *ptr);
#ifdef REDIS_TEST
int hi_sdsTest(int argc, char *argv[]);
int sdsTest(int argc, char *argv[]);
#endif
#endif /* HIREDIS_SDS_H */
#endif
+3 -5
View File
@@ -37,8 +37,6 @@
* the include of your alternate allocator if needed (not needed in order
* to use the default libc allocator). */
#include "alloc.h"
#define hi_s_malloc hi_malloc
#define hi_s_realloc hi_realloc
#define hi_s_free hi_free
#define s_malloc malloc
#define s_realloc realloc
#define s_free free
-94
View File
@@ -1,94 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* SDS compatibility header.
*
* This simple file maps sds types and calls to their unique hiredis symbol names.
* It's useful when we build Hiredis as a dependency of Redis and want to call
* Hiredis' sds symbols rather than the ones built into Redis, as the libraries
* have slightly diverged and could cause hard to track down ABI incompatibility
* bugs.
*
*/
#ifndef HIREDIS_SDS_COMPAT
#define HIREDIS_SDS_COMPAT
#define sds hisds
#define sdslen hi_sdslen
#define sdsavail hi_sdsavail
#define sdssetlen hi_sdssetlen
#define sdsinclen hi_sdsinclen
#define sdsalloc hi_sdsalloc
#define sdssetalloc hi_sdssetalloc
#define sdsAllocPtr hi_sdsAllocPtr
#define sdsAllocSize hi_sdsAllocSize
#define sdscat hi_sdscat
#define sdscatfmt hi_sdscatfmt
#define sdscatlen hi_sdscatlen
#define sdscatprintf hi_sdscatprintf
#define sdscatrepr hi_sdscatrepr
#define sdscatsds hi_sdscatsds
#define sdscatvprintf hi_sdscatvprintf
#define sdsclear hi_sdsclear
#define sdscmp hi_sdscmp
#define sdscpy hi_sdscpy
#define sdscpylen hi_sdscpylen
#define sdsdup hi_sdsdup
#define sdsempty hi_sdsempty
#define sds_free hi_sds_free
#define sdsfree hi_sdsfree
#define sdsfreesplitres hi_sdsfreesplitres
#define sdsfromlonglong hi_sdsfromlonglong
#define sdsgrowzero hi_sdsgrowzero
#define sdsIncrLen hi_sdsIncrLen
#define sdsjoin hi_sdsjoin
#define sdsjoinsds hi_sdsjoinsds
#define sdsll2str hi_sdsll2str
#define sdsMakeRoomFor hi_sdsMakeRoomFor
#define sds_malloc hi_sds_malloc
#define sdsmapchars hi_sdsmapchars
#define sdsnew hi_sdsnew
#define sdsnewlen hi_sdsnewlen
#define sdsrange hi_sdsrange
#define sds_realloc hi_sds_realloc
#define sdsRemoveFreeSpace hi_sdsRemoveFreeSpace
#define sdssplitargs hi_sdssplitargs
#define sdssplitlen hi_sdssplitlen
#define sdstolower hi_sdstolower
#define sdstoupper hi_sdstoupper
#define sdstrim hi_sdstrim
#define sdsull2str hi_sdsull2str
#define sdsupdatelen hi_sdsupdatelen
#endif /* HIREDIS_SDS_COMPAT */
+1 -1
View File
@@ -212,7 +212,7 @@ int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, sockle
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) {
int ret = 0;
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
const struct timeval *tv = optval;
struct timeval *tv = optval;
DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
} else {
+1 -2
View File
@@ -49,10 +49,9 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stddef.h>
#include <errno.h>
#ifdef _MSC_VER
typedef long long ssize_t;
typedef signed long ssize_t;
#endif
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
+121 -199
View File
@@ -34,33 +34,25 @@
#include "async.h"
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "win32.h"
#include "async_private.h"
#include "hiredis_ssl.h"
void __redisSetError(redisContext *c, int type, const char *str);
struct redisSSLContext {
/* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */
/* The SSL context is attached to SSL/TLS connections as a privdata. */
typedef struct redisSSLContext {
/**
* OpenSSL SSL_CTX; It is optional and will not be set when using
* user-supplied SSL.
*/
SSL_CTX *ssl_ctx;
/* Requested SNI, or NULL */
char *server_name;
};
/* The SSL connection context is attached to SSL/TLS connections as a privdata. */
typedef struct redisSSL {
/**
* OpenSSL SSL object.
*/
@@ -80,11 +72,43 @@ typedef struct redisSSL {
* should resume whenever a read takes place, if possible
*/
int pendingWrite;
} redisSSL;
} redisSSLContext;
/* Forward declaration */
redisContextFuncs redisContextSSLFuncs;
#ifdef HIREDIS_SSL_TRACE
/**
* Callback used for debugging
*/
static void sslLogCallback(const SSL *ssl, int where, int ret) {
const char *retstr = "";
int should_log = 1;
/* Ignore low-level SSL stuff */
if (where & SSL_CB_ALERT) {
should_log = 1;
}
if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) {
should_log = 1;
}
if ((where & SSL_CB_EXIT) && ret == 0) {
should_log = 1;
}
if (!should_log) {
return;
}
retstr = SSL_alert_type_string(ret);
printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr);
if (where == SSL_CB_HANDSHAKE_DONE) {
printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl));
}
}
#endif
/**
* OpenSSL global initialization and locking handling callbacks.
* Note that this is only required for OpenSSL < 1.1.0.
@@ -95,18 +119,6 @@ redisContextFuncs redisContextSSLFuncs;
#endif
#ifdef HIREDIS_USE_CRYPTO_LOCKS
#ifdef _WIN32
typedef CRITICAL_SECTION sslLockType;
static void sslLockInit(sslLockType* l) {
InitializeCriticalSection(l);
}
static void sslLockAcquire(sslLockType* l) {
EnterCriticalSection(l);
}
static void sslLockRelease(sslLockType* l) {
LeaveCriticalSection(l);
}
#else
typedef pthread_mutex_t sslLockType;
static void sslLockInit(sslLockType *l) {
pthread_mutex_init(l, NULL);
@@ -117,9 +129,7 @@ static void sslLockAcquire(sslLockType *l) {
static void sslLockRelease(sslLockType *l) {
pthread_mutex_unlock(l);
}
#endif
static sslLockType* ossl_locks;
static pthread_mutex_t *ossl_locks;
static void opensslDoLock(int mode, int lkid, const char *f, int line) {
sslLockType *l = ossl_locks + lkid;
@@ -134,151 +144,36 @@ static void opensslDoLock(int mode, int lkid, const char *f, int line) {
(void)line;
}
static int initOpensslLocks(void) {
static void initOpensslLocks(void) {
unsigned ii, nlocks;
if (CRYPTO_get_locking_callback() != NULL) {
/* Someone already set the callback before us. Don't destroy it! */
return REDIS_OK;
return;
}
nlocks = CRYPTO_num_locks();
ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks);
if (ossl_locks == NULL)
return REDIS_ERR;
ossl_locks = malloc(sizeof(*ossl_locks) * nlocks);
for (ii = 0; ii < nlocks; ii++) {
sslLockInit(ossl_locks + ii);
}
CRYPTO_set_locking_callback(opensslDoLock);
return REDIS_OK;
}
#endif /* HIREDIS_USE_CRYPTO_LOCKS */
int redisInitOpenSSL(void)
{
SSL_library_init();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks();
#endif
return REDIS_OK;
}
/**
* redisSSLContext helper context destruction.
*/
const char *redisSSLContextGetError(redisSSLContextError error)
{
switch (error) {
case REDIS_SSL_CTX_NONE:
return "No Error";
case REDIS_SSL_CTX_CREATE_FAILED:
return "Failed to create OpenSSL SSL_CTX";
case REDIS_SSL_CTX_CERT_KEY_REQUIRED:
return "Client cert and key must both be specified or skipped";
case REDIS_SSL_CTX_CA_CERT_LOAD_FAILED:
return "Failed to load CA Certificate or CA Path";
case REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED:
return "Failed to load client certificate";
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
return "Failed to load private key";
default:
return "Unknown error code";
}
}
void redisFreeSSLContext(redisSSLContext *ctx)
{
if (!ctx)
return;
if (ctx->server_name) {
hi_free(ctx->server_name);
ctx->server_name = NULL;
}
if (ctx->ssl_ctx) {
SSL_CTX_free(ctx->ssl_ctx);
ctx->ssl_ctx = NULL;
}
hi_free(ctx);
}
/**
* redisSSLContext helper context initialization.
*/
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
const char *cert_filename, const char *private_key_filename,
const char *server_name, redisSSLContextError *error)
{
redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext));
if (ctx == NULL)
goto error;
ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ctx->ssl_ctx) {
if (error) *error = REDIS_SSL_CTX_CREATE_FAILED;
goto error;
}
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
if ((cert_filename != NULL && private_key_filename == NULL) ||
(private_key_filename != NULL && cert_filename == NULL)) {
if (error) *error = REDIS_SSL_CTX_CERT_KEY_REQUIRED;
goto error;
}
if (capath || cacert_filename) {
if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) {
if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED;
goto error;
}
}
if (cert_filename) {
if (!SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, cert_filename)) {
if (error) *error = REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED;
goto error;
}
if (!SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, private_key_filename, SSL_FILETYPE_PEM)) {
if (error) *error = REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED;
goto error;
}
}
if (server_name)
ctx->server_name = hi_strdup(server_name);
return ctx;
error:
redisFreeSSLContext(ctx);
return NULL;
}
/**
* SSL Connection initialization.
*/
static int redisSSLConnect(redisContext *c, SSL *ssl) {
if (c->privctx) {
static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
if (c->privdata) {
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
return REDIS_ERR;
}
redisSSL *rssl = hi_calloc(1, sizeof(redisSSL));
if (rssl == NULL) {
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
return REDIS_ERR;
}
c->privdata = calloc(1, sizeof(redisSSLContext));
c->funcs = &redisContextSSLFuncs;
redisSSLContext *rssl = c->privdata;
rssl->ssl_ctx = ssl_ctx;
rssl->ssl = ssl;
SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
@@ -288,14 +183,12 @@ static int redisSSLConnect(redisContext *c, SSL *ssl) {
ERR_clear_error();
int rv = SSL_connect(rssl->ssl);
if (rv == 1) {
c->privctx = rssl;
return REDIS_OK;
}
rv = SSL_get_error(rssl->ssl, rv);
if (((c->flags & REDIS_BLOCK) == 0) &&
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
c->privctx = rssl;
return REDIS_OK;
}
@@ -310,58 +203,83 @@ static int redisSSLConnect(redisContext *c, SSL *ssl) {
}
__redisSetError(c, REDIS_ERR_IO, err);
}
hi_free(rssl);
return REDIS_ERR;
}
/**
* A wrapper around redisSSLConnect() for users who manage their own context and
* create their own SSL object.
*/
int redisInitiateSSL(redisContext *c, SSL *ssl) {
return redisSSLConnect(c, ssl);
return redisSSLConnect(c, NULL, ssl);
}
/**
* A wrapper around redisSSLConnect() for users who use redisSSLContext and don't
* manage their own SSL objects.
*/
int redisSecureConnection(redisContext *c, const char *capath,
const char *certpath, const char *keypath, const char *servername) {
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
{
if (!c || !redis_ssl_ctx)
return REDIS_ERR;
SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
/* We want to verify that redisSSLConnect() won't fail on this, as it will
* not own the SSL object in that case and we'll end up leaking.
*/
if (c->privctx)
return REDIS_ERR;
/* Initialize global OpenSSL stuff */
static int isInit = 0;
if (!isInit) {
isInit = 1;
SSL_library_init();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks();
#endif
}
SSL *ssl = SSL_new(redis_ssl_ctx->ssl_ctx);
if (!ssl) {
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ssl_ctx) {
__redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX");
goto error;
}
if (redis_ssl_ctx->server_name) {
if (!SSL_set_tlsext_host_name(ssl, redis_ssl_ctx->server_name)) {
__redisSetError(c, REDIS_ERR_OTHER, "Failed to set server_name/SNI");
#ifdef HIREDIS_SSL_TRACE
SSL_CTX_set_info_callback(ssl_ctx, sslLogCallback);
#endif
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) {
__redisSetError(c, REDIS_ERR_OTHER, "certpath and keypath must be specified together");
goto error;
}
if (capath) {
if (!SSL_CTX_load_verify_locations(ssl_ctx, capath, NULL)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid CA certificate");
goto error;
}
}
if (certpath) {
if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, certpath)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client certificate");
goto error;
}
if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, keypath, SSL_FILETYPE_PEM)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client key");
goto error;
}
}
return redisSSLConnect(c, ssl);
ssl = SSL_new(ssl_ctx);
if (!ssl) {
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
goto error;
}
if (servername) {
if (!SSL_set_tlsext_host_name(ssl, servername)) {
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't set server name indication");
goto error;
}
}
return redisSSLConnect(c, ssl_ctx, ssl);
error:
if (ssl)
SSL_free(ssl);
if (ssl) SSL_free(ssl);
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
return REDIS_ERR;
}
static int maybeCheckWant(redisSSL *rssl, int rv) {
static int maybeCheckWant(redisSSLContext *rssl, int rv) {
/**
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
* and true is returned. False is returned otherwise
@@ -381,19 +299,23 @@ static int maybeCheckWant(redisSSL *rssl, int rv) {
* Implementation of redisContextFuncs for SSL connections.
*/
static void redisSSLFree(void *privctx){
redisSSL *rsc = privctx;
static void redisSSLFreeContext(void *privdata){
redisSSLContext *rsc = privdata;
if (!rsc) return;
if (rsc->ssl) {
SSL_free(rsc->ssl);
rsc->ssl = NULL;
}
hi_free(rsc);
if (rsc->ssl_ctx) {
SSL_CTX_free(rsc->ssl_ctx);
rsc->ssl_ctx = NULL;
}
free(rsc);
}
static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
redisSSL *rssl = c->privctx;
static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
redisSSLContext *rssl = c->privdata;
int nread = SSL_read(rssl->ssl, buf, bufcap);
if (nread > 0) {
@@ -434,10 +356,10 @@ static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
}
}
static ssize_t redisSSLWrite(redisContext *c) {
redisSSL *rssl = c->privctx;
static int redisSSLWrite(redisContext *c) {
redisSSLContext *rssl = c->privdata;
size_t len = rssl->lastLen ? rssl->lastLen : hi_sdslen(c->obuf);
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
int rv = SSL_write(rssl->ssl, c->obuf, len);
if (rv > 0) {
@@ -458,7 +380,7 @@ static ssize_t redisSSLWrite(redisContext *c) {
static void redisSSLAsyncRead(redisAsyncContext *ac) {
int rv;
redisSSL *rssl = ac->c.privctx;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;
rssl->wantRead = 0;
@@ -488,7 +410,7 @@ static void redisSSLAsyncRead(redisAsyncContext *ac) {
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
int rv, done = 0;
redisSSL *rssl = ac->c.privctx;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;
rssl->pendingWrite = 0;
@@ -517,7 +439,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
}
redisContextFuncs redisContextSSLFuncs = {
.free_privctx = redisSSLFree,
.free_privdata = redisSSLFreeContext,
.async_read = redisSSLAsyncRead,
.async_write = redisSSLAsyncWrite,
.read = redisSSLRead,
+91 -504
View File
@@ -1,24 +1,22 @@
#include "fmacros.h"
#include "sockcompat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <strings.h>
#include <sys/socket.h>
#include <sys/time.h>
#endif
#include <netdb.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include "hiredis.h"
#include "async.h"
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#endif
#include "net.h"
#include "win32.h"
enum connection_type {
CONN_TCP,
@@ -49,35 +47,15 @@ struct config {
} ssl;
};
struct privdata {
int dtor_counter;
};
struct pushCounters {
int nil;
int str;
};
#ifdef HIREDIS_TEST_SSL
redisSSLContext *_ssl_ctx = NULL;
#endif
/* The following lines make up our testing "framework" :) */
static int tests = 0, fails = 0, skips = 0;
static int tests = 0, fails = 0;
#define test(_s) { printf("#%02d ", ++tests); printf(_s); }
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
static long long usec(void) {
#ifndef _MSC_VER
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
#else
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime) / 10;
#endif
}
/* The assert() calls below have side effects, so we need assert()
@@ -87,43 +65,6 @@ static long long usec(void) {
#define assert(e) (void)(e)
#endif
/* Helper to extract Redis version information. Aborts on any failure. */
#define REDIS_VERSION_FIELD "redis_version:"
void get_redis_version(redisContext *c, int *majorptr, int *minorptr) {
redisReply *reply;
char *eptr, *s, *e;
int major, minor;
reply = redisCommand(c, "INFO");
if (reply == NULL || c->err || reply->type != REDIS_REPLY_STRING)
goto abort;
if ((s = strstr(reply->str, REDIS_VERSION_FIELD)) == NULL)
goto abort;
s += strlen(REDIS_VERSION_FIELD);
/* We need a field terminator and at least 'x.y.z' (5) bytes of data */
if ((e = strstr(s, "\r\n")) == NULL || (e - s) < 5)
goto abort;
/* Extract version info */
major = strtol(s, &eptr, 10);
if (*eptr != '.') goto abort;
minor = strtol(eptr+1, NULL, 10);
/* Push info the caller wants */
if (majorptr) *majorptr = major;
if (minorptr) *minorptr = minor;
freeReplyObject(reply);
return;
abort:
freeReplyObject(reply);
fprintf(stderr, "Error: Cannot determine Redis version, aborting\n");
exit(1);
}
static redisContext *select_database(redisContext *c) {
redisReply *reply;
@@ -146,26 +87,6 @@ static redisContext *select_database(redisContext *c) {
return c;
}
/* Switch protocol */
static void send_hello(redisContext *c, int version) {
redisReply *reply;
int expected;
reply = redisCommand(c, "HELLO %d", version);
expected = version == 3 ? REDIS_REPLY_MAP : REDIS_REPLY_ARRAY;
assert(reply != NULL && reply->type == expected);
freeReplyObject(reply);
}
/* Togggle client tracking */
static void send_client_tracking(redisContext *c, const char *str) {
redisReply *reply;
reply = redisCommand(c, "CLIENT TRACKING %s", str);
assert(reply != NULL && reply->type == REDIS_REPLY_STATUS);
freeReplyObject(reply);
}
static int disconnect(redisContext *c, int keep_fd) {
redisReply *reply;
@@ -184,9 +105,9 @@ static int disconnect(redisContext *c, int keep_fd) {
return -1;
}
static void do_ssl_handshake(redisContext *c) {
static void do_ssl_handshake(redisContext *c, struct config config) {
#ifdef HIREDIS_TEST_SSL
redisInitiateSSLWithContext(c, _ssl_ctx);
redisSecureConnection(c, config.ssl.ca_cert, config.ssl.cert, config.ssl.key, NULL);
if (c->err) {
printf("SSL error: %s\n", c->errstr);
redisFree(c);
@@ -194,6 +115,7 @@ static void do_ssl_handshake(redisContext *c) {
}
#else
(void) c;
(void) config;
#endif
}
@@ -228,7 +150,7 @@ static redisContext *do_connect(struct config config) {
}
if (config.type == CONN_SSL) {
do_ssl_handshake(c);
do_ssl_handshake(c, config);
}
return select_database(c);
@@ -238,7 +160,7 @@ static void do_reconnect(redisContext *c, struct config config) {
redisReconnect(c);
if (config.type == CONN_SSL) {
do_ssl_handshake(c);
do_ssl_handshake(c, config);
}
}
@@ -250,43 +172,43 @@ static void test_format_commands(void) {
len = redisFormatCommand(&cmd,"SET foo bar");
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
hi_free(cmd);
free(cmd);
test("Format command with %%s string interpolation: ");
len = redisFormatCommand(&cmd,"SET %s %s","foo","bar");
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
hi_free(cmd);
free(cmd);
test("Format command with %%s and an empty string: ");
len = redisFormatCommand(&cmd,"SET %s %s","foo","");
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(0+2));
hi_free(cmd);
free(cmd);
test("Format command with an empty string in between proper interpolations: ");
len = redisFormatCommand(&cmd,"SET %s %s","","foo");
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(0+2)+4+(3+2));
hi_free(cmd);
free(cmd);
test("Format command with %%b string interpolation: ");
len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
hi_free(cmd);
free(cmd);
test("Format command with %%b and an empty string: ");
len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(0+2));
hi_free(cmd);
free(cmd);
test("Format command with literal %%: ");
len = redisFormatCommand(&cmd,"SET %% %%");
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(1+2)+4+(1+2));
hi_free(cmd);
free(cmd);
/* Vararg width depends on the type. These tests make sure that the
* width is correctly determined using the format and subsequent varargs
@@ -297,7 +219,7 @@ static void test_format_commands(void) {
len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \
len == 4+5+(12+2)+4+(9+2)); \
hi_free(cmd); \
free(cmd); \
} while(0)
#define FLOAT_WIDTH_TEST(type) do { \
@@ -306,7 +228,7 @@ static void test_format_commands(void) {
len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \
test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \
len == 4+5+(12+2)+4+(9+2)); \
hi_free(cmd); \
free(cmd); \
} while(0)
INTEGER_WIDTH_TEST("d", int);
@@ -337,29 +259,29 @@ static void test_format_commands(void) {
len = redisFormatCommandArgv(&cmd,argc,argv,NULL);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
hi_free(cmd);
free(cmd);
test("Format command by passing argc/argv with lengths: ");
len = redisFormatCommandArgv(&cmd,argc,argv,lens);
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
hi_free(cmd);
free(cmd);
hisds sds_cmd;
sds sds_cmd;
sds_cmd = NULL;
test("Format command into hisds by passing argc/argv without lengths: ");
sds_cmd = sdsempty();
test("Format command into sds by passing argc/argv without lengths: ");
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL);
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
hi_sdsfree(sds_cmd);
sdsfree(sds_cmd);
sds_cmd = NULL;
test("Format command into hisds by passing argc/argv with lengths: ");
sds_cmd = sdsempty();
test("Format command into sds by passing argc/argv with lengths: ");
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens);
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
hi_sdsfree(sds_cmd);
sdsfree(sds_cmd);
}
static void test_append_formatted_commands(struct config config) {
@@ -378,7 +300,7 @@ static void test_append_formatted_commands(struct config config) {
assert(redisGetReply(c, (void*)&reply) == REDIS_OK);
hi_free(cmd);
free(cmd);
freeReplyObject(reply);
disconnect(c, 0);
@@ -386,7 +308,7 @@ static void test_append_formatted_commands(struct config config) {
static void test_reply_reader(void) {
redisReader *reader;
void *reply, *root;
void *reply;
int ret;
int i;
@@ -410,26 +332,16 @@ static void test_reply_reader(void) {
strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0);
redisReaderFree(reader);
test("Set error on nested multi bulks with depth > 7: ");
reader = redisReaderCreate();
test("Can handle arbitrarily nested multi-bulks: ");
for (i = 0; i < 128; i++) {
redisReaderFeed(reader,(char*)"*1\r\n", 4);
}
redisReaderFeed(reader,(char*)"$6\r\nLOLWUT\r\n",12);
ret = redisReaderGetReply(reader,&reply);
root = reply; /* Keep track of the root reply */
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_ARRAY &&
((redisReply*)reply)->elements == 1);
test("Can parse arbitrarily nested multi-bulks correctly: ");
while(i--) {
assert(reply != NULL && ((redisReply*)reply)->type == REDIS_REPLY_ARRAY);
reply = ((redisReply*)reply)->element[0];
for (i = 0; i < 9; i++) {
redisReaderFeed(reader,(char*)"*1\r\n",4);
}
test_cond(((redisReply*)reply)->type == REDIS_REPLY_STRING &&
!memcmp(((redisReply*)reply)->str, "LOLWUT", 6));
freeReplyObject(root);
ret = redisReaderGetReply(reader,NULL);
test_cond(ret == REDIS_ERR &&
strncasecmp(reader->errstr,"No support for",14) == 0);
redisReaderFree(reader);
test("Correctly parses LLONG_MAX: ");
@@ -488,30 +400,6 @@ static void test_reply_reader(void) {
freeReplyObject(reply);
redisReaderFree(reader);
test("Can configure maximum multi-bulk elements: ");
reader = redisReaderCreate();
reader->maxelements = 1024;
redisReaderFeed(reader, "*1025\r\n", 7);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_ERR &&
strcasecmp(reader->errstr, "Multi-bulk length out of range") == 0);
freeReplyObject(reply);
redisReaderFree(reader);
test("Multi-bulk never overflows regardless of maxelements: ");
size_t bad_mbulk_len = (SIZE_MAX / sizeof(void *)) + 3;
char bad_mbulk_reply[100];
snprintf(bad_mbulk_reply, sizeof(bad_mbulk_reply), "*%llu\r\n+asdf\r\n",
(unsigned long long) bad_mbulk_len);
reader = redisReaderCreate();
reader->maxelements = 0; /* Don't rely on default limit */
redisReaderFeed(reader, bad_mbulk_reply, strlen(bad_mbulk_reply));
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_ERR && strcasecmp(reader->errstr, "Out of memory") == 0);
freeReplyObject(reply);
redisReaderFree(reader);
#if LLONG_MAX > SIZE_MAX
test("Set error when array > SIZE_MAX: ");
reader = redisReaderCreate();
@@ -571,32 +459,6 @@ static void test_reply_reader(void) {
((redisReply*)reply)->elements == 0);
freeReplyObject(reply);
redisReaderFree(reader);
/* RESP3 verbatim strings (GitHub issue #802) */
test("Can parse RESP3 verbatim strings: ");
reader = redisReaderCreate();
redisReaderFeed(reader,(char*)"=10\r\ntxt:LOLWUT\r\n",17);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_VERB &&
!memcmp(((redisReply*)reply)->str,"LOLWUT", 6));
freeReplyObject(reply);
redisReaderFree(reader);
/* RESP3 push messages (Github issue #815) */
test("Can parse RESP3 push messages: ");
reader = redisReaderCreate();
redisReaderFeed(reader,(char*)">2\r\n$6\r\nLOLWUT\r\n:42\r\n",21);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_PUSH &&
((redisReply*)reply)->elements == 2 &&
((redisReply*)reply)->element[0]->type == REDIS_REPLY_STRING &&
!memcmp(((redisReply*)reply)->element[0]->str,"LOLWUT",6) &&
((redisReply*)reply)->element[1]->type == REDIS_REPLY_INTEGER &&
((redisReply*)reply)->element[1]->integer == 42);
freeReplyObject(reply);
redisReaderFree(reader);
}
static void test_free_null(void) {
@@ -612,47 +474,6 @@ static void test_free_null(void) {
test_cond(reply == NULL);
}
static void *hi_malloc_fail(size_t size) {
(void)size;
return NULL;
}
static void *hi_calloc_fail(size_t nmemb, size_t size) {
(void)nmemb;
(void)size;
return NULL;
}
static void *hi_realloc_fail(void *ptr, size_t size) {
(void)ptr;
(void)size;
return NULL;
}
static void test_allocator_injection(void) {
hiredisAllocFuncs ha = {
.mallocFn = hi_malloc_fail,
.callocFn = hi_calloc_fail,
.reallocFn = hi_realloc_fail,
.strdupFn = strdup,
.freeFn = free,
};
// Override hiredis allocators
hiredisSetAllocators(&ha);
test("redisContext uses injected allocators: ");
redisContext *c = redisConnect("localhost", 6379);
test_cond(c == NULL);
test("redisReader uses injected allocators: ");
redisReader *reader = redisReaderCreate();
test_cond(reader == NULL);
// Return allocators to default
hiredisResetAllocators();
}
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
static void test_blocking_connection_errors(void) {
redisContext *c;
@@ -670,19 +491,19 @@ static void test_blocking_connection_errors(void) {
(strcmp(c->errstr, "Name or service not known") == 0 ||
strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 ||
strcmp(c->errstr, "Name does not resolve") == 0 ||
strcmp(c->errstr, "nodename nor servname provided, or not known") == 0 ||
strcmp(c->errstr,
"nodename nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "No address associated with hostname") == 0 ||
strcmp(c->errstr, "Temporary failure in name resolution") == 0 ||
strcmp(c->errstr, "hostname nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "no address associated with name") == 0 ||
strcmp(c->errstr, "No such host is known. ") == 0));
strcmp(c->errstr,
"hostname nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "no address associated with name") == 0));
redisFree(c);
} else {
printf("Skipping NXDOMAIN test. Found evil ISP!\n");
freeaddrinfo(ai_tmp);
}
#ifndef _WIN32
test("Returns error when the port is not open: ");
c = redisConnect((char*)"localhost", 1);
test_cond(c->err == REDIS_ERR_IO &&
@@ -693,166 +514,11 @@ static void test_blocking_connection_errors(void) {
c = redisConnectUnix((char*)"/tmp/idontexist.sock");
test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */
redisFree(c);
#endif
}
/* Test push handler */
void push_handler(void *privdata, void *r) {
struct pushCounters *pcounts = privdata;
redisReply *reply = r, *payload;
assert(reply && reply->type == REDIS_REPLY_PUSH && reply->elements == 2);
payload = reply->element[1];
if (payload->type == REDIS_REPLY_ARRAY) {
payload = payload->element[0];
}
if (payload->type == REDIS_REPLY_STRING) {
pcounts->str++;
} else if (payload->type == REDIS_REPLY_NIL) {
pcounts->nil++;
}
freeReplyObject(reply);
}
/* Dummy function just to test setting a callback with redisOptions */
void push_handler_async(redisAsyncContext *ac, void *reply) {
(void)ac;
(void)reply;
}
static void test_resp3_push_handler(redisContext *c) {
struct pushCounters pc = {0};
redisPushFn *old = NULL;
redisReply *reply;
void *privdata;
/* Switch to RESP3 and turn on client tracking */
send_hello(c, 3);
send_client_tracking(c, "ON");
privdata = c->privdata;
c->privdata = &pc;
reply = redisCommand(c, "GET key:0");
assert(reply != NULL);
freeReplyObject(reply);
test("RESP3 PUSH messages are handled out of band by default: ");
reply = redisCommand(c, "SET key:0 val:0");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS);
freeReplyObject(reply);
assert((reply = redisCommand(c, "GET key:0")) != NULL);
freeReplyObject(reply);
old = redisSetPushCallback(c, push_handler);
test("We can set a custom RESP3 PUSH handler: ");
reply = redisCommand(c, "SET key:0 val:0");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.str == 1);
freeReplyObject(reply);
test("We properly handle a NIL invalidation payload: ");
reply = redisCommand(c, "FLUSHDB");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.nil == 1);
freeReplyObject(reply);
/* Unset the push callback and generate an invalidate message making
* sure it is not handled out of band. */
test("With no handler, PUSH replies come in-band: ");
redisSetPushCallback(c, NULL);
assert((reply = redisCommand(c, "GET key:0")) != NULL);
freeReplyObject(reply);
assert((reply = redisCommand(c, "SET key:0 invalid")) != NULL);
test_cond(reply->type == REDIS_REPLY_PUSH);
freeReplyObject(reply);
test("With no PUSH handler, no replies are lost: ");
assert(redisGetReply(c, (void**)&reply) == REDIS_OK);
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS);
freeReplyObject(reply);
/* Return to the originally set PUSH handler */
assert(old != NULL);
redisSetPushCallback(c, old);
/* Switch back to RESP2 and disable tracking */
c->privdata = privdata;
send_client_tracking(c, "OFF");
send_hello(c, 2);
}
redisOptions get_redis_tcp_options(struct config config) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, config.tcp.host, config.tcp.port);
return options;
}
static void test_resp3_push_options(struct config config) {
redisAsyncContext *ac;
redisContext *c;
redisOptions options;
test("We set a default RESP3 handler for redisContext: ");
options = get_redis_tcp_options(config);
assert((c = redisConnectWithOptions(&options)) != NULL);
test_cond(c->push_cb != NULL);
redisFree(c);
test("We don't set a default RESP3 push handler for redisAsyncContext: ");
options = get_redis_tcp_options(config);
assert((ac = redisAsyncConnectWithOptions(&options)) != NULL);
test_cond(ac->c.push_cb == NULL);
redisAsyncFree(ac);
test("Our REDIS_OPT_NO_PUSH_AUTOFREE flag works: ");
options = get_redis_tcp_options(config);
options.options |= REDIS_OPT_NO_PUSH_AUTOFREE;
assert((c = redisConnectWithOptions(&options)) != NULL);
test_cond(c->push_cb == NULL);
redisFree(c);
test("We can use redisOptions to set a custom PUSH handler for redisContext: ");
options = get_redis_tcp_options(config);
options.push_cb = push_handler;
assert((c = redisConnectWithOptions(&options)) != NULL);
test_cond(c->push_cb == push_handler);
redisFree(c);
test("We can use redisOptions to set a custom PUSH handler for redisAsyncContext: ");
options = get_redis_tcp_options(config);
options.async_push_cb = push_handler_async;
assert((ac = redisAsyncConnectWithOptions(&options)) != NULL);
test_cond(ac->push_cb == push_handler_async);
redisAsyncFree(ac);
}
void free_privdata(void *privdata) {
struct privdata *data = privdata;
data->dtor_counter++;
}
static void test_privdata_hooks(struct config config) {
struct privdata data = {0};
redisOptions options;
redisContext *c;
test("We can use redisOptions to set privdata: ");
options = get_redis_tcp_options(config);
REDIS_OPTIONS_SET_PRIVDATA(&options, &data, free_privdata);
assert((c = redisConnectWithOptions(&options)) != NULL);
test_cond(c->privdata == &data);
test("Our privdata destructor fires when we free the context: ");
redisFree(c);
test_cond(data.dtor_counter == 1);
}
static void test_blocking_connection(struct config config) {
redisContext *c;
redisReply *reply;
int major;
c = do_connect(config);
@@ -925,42 +591,14 @@ static void test_blocking_connection(struct config config) {
strcasecmp(reply->element[1]->str,"pong") == 0);
freeReplyObject(reply);
/* Make sure passing NULL to redisGetReply is safe */
test("Can pass NULL to redisGetReply: ");
assert(redisAppendCommand(c, "PING") == REDIS_OK);
test_cond(redisGetReply(c, NULL) == REDIS_OK);
get_redis_version(c, &major, NULL);
if (major >= 6) test_resp3_push_handler(c);
test_resp3_push_options(config);
test_privdata_hooks(config);
disconnect(c, 0);
}
/* Send DEBUG SLEEP 0 to detect if we have this command */
static int detect_debug_sleep(redisContext *c) {
int detected;
redisReply *reply = redisCommand(c, "DEBUG SLEEP 0\r\n");
if (reply == NULL || c->err) {
const char *cause = c->err ? c->errstr : "(none)";
fprintf(stderr, "Error testing for DEBUG SLEEP (Redis error: %s), exiting\n", cause);
exit(-1);
}
detected = reply->type == REDIS_REPLY_STATUS;
freeReplyObject(reply);
return detected;
}
static void test_blocking_connection_timeouts(struct config config) {
redisContext *c;
redisReply *reply;
ssize_t s;
const char *sleep_cmd = "DEBUG SLEEP 3\r\n";
const char *cmd = "DEBUG SLEEP 3\r\n";
struct timeval tv;
c = do_connect(config);
@@ -977,24 +615,14 @@ static void test_blocking_connection_timeouts(struct config config) {
c = do_connect(config);
test("Does not return a reply when the command times out: ");
if (detect_debug_sleep(c)) {
redisAppendFormattedCommand(c, sleep_cmd, strlen(sleep_cmd));
s = c->funcs->write(c);
tv.tv_sec = 0;
tv.tv_usec = 10000;
redisSetTimeout(c, tv);
reply = redisCommand(c, "GET foo");
#ifndef _WIN32
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO &&
strcmp(c->errstr, "Resource temporarily unavailable") == 0);
#else
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_TIMEOUT &&
strcmp(c->errstr, "recv timeout") == 0);
#endif
freeReplyObject(reply);
} else {
test_skipped();
}
redisAppendFormattedCommand(c, cmd, strlen(cmd));
s = c->funcs->write(c);
tv.tv_sec = 0;
tv.tv_usec = 10000;
redisSetTimeout(c, tv);
reply = redisCommand(c, "GET foo");
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0);
freeReplyObject(reply);
test("Reconnect properly reconnects after a timeout: ");
do_reconnect(c, config);
@@ -1021,7 +649,18 @@ static void test_blocking_io_errors(struct config config) {
/* Connect to target given by config. */
c = do_connect(config);
get_redis_version(c, &major, &minor);
{
/* Find out Redis version to determine the path for the next test */
const char *field = "redis_version:";
char *p, *eptr;
reply = redisCommand(c,"INFO");
p = strstr(reply->str,field);
major = strtol(p+strlen(field),&eptr,10);
p = eptr+1; /* char next to the first "." */
minor = strtol(p,&eptr,10);
freeReplyObject(reply);
}
test("Returns I/O error when the connection is lost: ");
reply = redisCommand(c,"QUIT");
@@ -1035,7 +674,6 @@ static void test_blocking_io_errors(struct config config) {
test_cond(reply == NULL);
}
#ifndef _WIN32
/* On 2.0, QUIT will cause the connection to be closed immediately and
* the read(2) for the reply on QUIT will set the error to EOF.
* On >2.0, QUIT will return with OK and another read(2) needed to be
@@ -1043,19 +681,14 @@ static void test_blocking_io_errors(struct config config) {
* conditions, the error will be set to EOF. */
assert(c->err == REDIS_ERR_EOF &&
strcmp(c->errstr,"Server closed the connection") == 0);
#endif
redisFree(c);
c = do_connect(config);
test("Returns I/O error on socket timeout: ");
struct timeval tv = { 0, 1000 };
assert(redisSetTimeout(c,tv) == REDIS_OK);
int respcode = redisGetReply(c,&_reply);
#ifndef _WIN32
test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_IO && errno == EAGAIN);
#else
test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_TIMEOUT);
#endif
test_cond(redisGetReply(c,&_reply) == REDIS_ERR &&
c->err == REDIS_ERR_IO && errno == EAGAIN);
redisFree(c);
}
@@ -1083,18 +716,6 @@ static void test_invalid_timeout_errors(struct config config) {
redisFree(c);
}
/* Wrap malloc to abort on failure so OOM checks don't make the test logic
* harder to follow. */
void *hi_malloc_safe(size_t size) {
void *ptr = hi_malloc(size);
if (ptr == NULL) {
fprintf(stderr, "Error: Out of memory\n");
exit(-1);
}
return ptr;
}
static void test_throughput(struct config config) {
redisContext *c = do_connect(config);
redisReply **replies;
@@ -1106,7 +727,7 @@ static void test_throughput(struct config config) {
freeReplyObject(redisCommand(c,"LPUSH mylist foo"));
num = 1000;
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
t1 = usec();
for (i = 0; i < num; i++) {
replies[i] = redisCommand(c,"PING");
@@ -1114,10 +735,10 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0);
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
t1 = usec();
for (i = 0; i < num; i++) {
replies[i] = redisCommand(c,"LRANGE mylist 0 499");
@@ -1126,10 +747,10 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0);
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
t1 = usec();
for (i = 0; i < num; i++) {
replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000);
@@ -1137,11 +758,11 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0);
num = 10000;
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
for (i = 0; i < num; i++)
redisAppendCommand(c,"PING");
t1 = usec();
@@ -1151,10 +772,10 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
for (i = 0; i < num; i++)
redisAppendCommand(c,"LRANGE mylist 0 499");
t1 = usec();
@@ -1165,10 +786,10 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
replies = hi_malloc_safe(sizeof(redisReply*)*num);
replies = malloc(sizeof(redisReply*)*num);
for (i = 0; i < num; i++)
redisAppendCommand(c,"INCRBY incrkey %d", 1000000);
t1 = usec();
@@ -1178,7 +799,7 @@ static void test_throughput(struct config config) {
}
t2 = usec();
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
hi_free(replies);
free(replies);
printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
disconnect(c, 0);
@@ -1295,8 +916,9 @@ int main(int argc, char **argv) {
};
int throughput = 1;
int test_inherit_fd = 1;
int skips_as_fails = 0;
int test_unix_socket;
/* Ignore broken pipe signal (for I/O error tests). */
signal(SIGPIPE, SIG_IGN);
/* Parse command line options. */
argv++; argc--;
@@ -1314,8 +936,6 @@ int main(int argc, char **argv) {
throughput = 0;
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
test_inherit_fd = 0;
} else if (argc >= 1 && !strcmp(argv[0],"--skips-as-fails")) {
skips_as_fails = 1;
#ifdef HIREDIS_TEST_SSL
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) {
argv++; argc--;
@@ -1340,19 +960,6 @@ int main(int argc, char **argv) {
argv++; argc--;
}
#ifndef _WIN32
/* Ignore broken pipe signal (for I/O error tests). */
signal(SIGPIPE, SIG_IGN);
test_unix_socket = access(cfg.unix_sock.path, F_OK) == 0;
#else
/* Unix sockets don't exist in Windows */
test_unix_socket = 0;
#endif
test_allocator_injection();
test_format_commands();
test_reply_reader();
test_blocking_connection_errors();
@@ -1367,25 +974,15 @@ int main(int argc, char **argv) {
test_append_formatted_commands(cfg);
if (throughput) test_throughput(cfg);
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);
if (test_unix_socket) {
printf("\n");
cfg.type = CONN_UNIX;
test_blocking_connection(cfg);
test_blocking_connection_timeouts(cfg);
test_blocking_io_errors(cfg);
if (throughput) test_throughput(cfg);
} else {
test_skipped();
}
printf("\nTesting against Unix socket connection (%s):\n", cfg.unix_sock.path);
cfg.type = CONN_UNIX;
test_blocking_connection(cfg);
test_blocking_connection_timeouts(cfg);
test_blocking_io_errors(cfg);
if (throughput) test_throughput(cfg);
#ifdef HIREDIS_TEST_SSL
if (cfg.ssl.port && cfg.ssl.host) {
redisInitOpenSSL();
_ssl_ctx = redisCreateSSLContext(cfg.ssl.ca_cert, NULL, cfg.ssl.cert, cfg.ssl.key, NULL, NULL);
assert(_ssl_ctx != NULL);
printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port);
cfg.type = CONN_SSL;
@@ -1395,31 +992,21 @@ int main(int argc, char **argv) {
test_invalid_timeout_errors(cfg);
test_append_formatted_commands(cfg);
if (throughput) test_throughput(cfg);
redisFreeSSLContext(_ssl_ctx);
_ssl_ctx = NULL;
}
#endif
if (test_inherit_fd) {
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
if (test_unix_socket) {
printf("\n");
cfg.type = CONN_FD;
test_blocking_connection(cfg);
} else {
test_skipped();
}
printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path);
cfg.type = CONN_FD;
test_blocking_connection(cfg);
}
if (fails || (skips_as_fails && skips)) {
if (fails) {
printf("*** %d TESTS FAILED ***\n", fails);
if (skips) {
printf("*** %d TESTS SKIPPED ***\n", skips);
}
return 1;
}
printf("ALL TESTS PASSED (%d skipped)\n", skips);
printf("ALL TESTS PASSED\n");
return 0;
}
+1 -9
View File
@@ -4,9 +4,7 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT=${REDIS_PORT:-56379}
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
TEST_SSL=${TEST_SSL:-0}
SKIPS_AS_FAILS=${SKIPS_AS_FAILS-:0}
SSL_TEST_ARGS=
SKIPS_ARG=
tmpdir=$(mktemp -d)
PID_FILE=${tmpdir}/hiredis-test-redis.pid
@@ -69,10 +67,4 @@ fi
cat ${tmpdir}/redis.conf
${REDIS_SERVER} ${tmpdir}/redis.conf
# Wait until we detect the unix socket
while [ ! -S "${SOCK_FILE}" ]; do sleep 1; done
# Treat skips as failures if directed
[ "$SKIPS_AS_FAILS" = 1 ] && SKIPS_ARG="--skips-as-fails"
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS} ${SKIPS_ARG}
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS}
+8 -8
View File
@@ -5,27 +5,27 @@ environment:
- MSYSTEM: MINGW64
CPU: x86_64
MSVC: amd64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW64
CPU: x86_64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW32
CPU: i686
MSVC: x86
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW64
CPU: x86_64
- MSYSTEM: MINGW32
CPU: i686
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW64
CPU: x86_64
MSVC: amd64
- MSYSTEM: MINGW64
CPU: x86_64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW32
CPU: i686
MSVC: x86
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW64
CPU: x86_64
CONFIG_FLAGS: --enable-debug
- MSYSTEM: MINGW32
CPU: i686
CONFIG_FLAGS: --enable-debug
install:
- set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH%
-21
View File
@@ -1,21 +0,0 @@
env:
CIRRUS_CLONE_DEPTH: 1
ARCH: amd64
task:
freebsd_instance:
matrix:
image: freebsd-12-0-release-amd64
image: freebsd-11-2-release-amd64
install_script:
- sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf
- pkg upgrade -y
- pkg install -y autoconf gmake
script:
- autoconf
#- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
- ./configure
- export JFLAG=`sysctl -n kern.smp.cpus`
- gmake -j${JFLAG}
- gmake -j${JFLAG} tests
- gmake check
+1
View File
@@ -30,6 +30,7 @@
/include/jemalloc/internal/public_namespace.h
/include/jemalloc/internal/public_symbols.txt
/include/jemalloc/internal/public_unnamespace.h
/include/jemalloc/internal/size_classes.h
/include/jemalloc/jemalloc.h
/include/jemalloc/jemalloc_defs.h
/include/jemalloc/jemalloc_macros.h
+33 -72
View File
@@ -11,7 +11,7 @@ matrix:
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: &gcc_multilib
addons:
apt:
packages:
- gcc-multilib
@@ -21,10 +21,6 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -41,25 +37,20 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: osx
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: osx
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: osx
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: osx
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -70,39 +61,50 @@ matrix:
env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
addons: *gcc_multilib
addons:
apt:
packages:
- gcc-multilib
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -113,10 +115,6 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -125,10 +123,6 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-libdl" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -137,24 +131,6 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --enable-opt-safety-checks" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-libdl --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-opt-safety-checks --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
@@ -167,25 +143,10 @@ matrix:
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
# Development build
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
# --enable-expermental-smallocx:
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
# Valgrind
- os: linux
env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
addons:
apt:
packages:
- valgrind
before_script:
- autoconf
- scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
- ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS
- make -j3
- make -j3 tests
+2 -2
View File
@@ -1,10 +1,10 @@
Unless otherwise specified, files in the jemalloc source distribution are
subject to the following license:
--------------------------------------------------------------------------------
Copyright (C) 2002-present Jason Evans <jasone@canonware.com>.
Copyright (C) 2002-2018 Jason Evans <jasone@canonware.com>.
All rights reserved.
Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved.
Copyright (C) 2009-present Facebook, Inc. All rights reserved.
Copyright (C) 2009-2018 Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
+1 -137
View File
@@ -4,143 +4,7 @@ brevity. Much more detail can be found in the git revision history:
https://github.com/jemalloc/jemalloc
* 5.2.1 (August 5, 2019)
This release is primarily about Windows. A critical virtual memory leak is
resolved on all Windows platforms. The regression was present in all releases
since 5.0.0.
Bug fixes:
- Fix a severe virtual memory leak on Windows. This regression was first
released in 5.0.0. (@Ignition, @j0t, @frederik-h, @davidtgoldblatt,
@interwq)
- Fix size 0 handling in posix_memalign(). This regression was first released
in 5.2.0. (@interwq)
- Fix the prof_log unit test which may observe unexpected backtraces from
compiler optimizations. The test was first added in 5.2.0. (@marxin,
@gnzlbg, @interwq)
- Fix the declaration of the extent_avail tree. This regression was first
released in 5.1.0. (@zoulasc)
- Fix an incorrect reference in jeprof. This functionality was first released
in 3.0.0. (@prehistoric-penguin)
- Fix an assertion on the deallocation fast-path. This regression was first
released in 5.2.0. (@yinan1048576)
- Fix the TLS_MODEL attribute in headers. This regression was first released
in 5.0.0. (@zoulasc, @interwq)
Optimizations and refactors:
- Implement opt.retain on Windows and enable by default on 64-bit. (@interwq,
@davidtgoldblatt)
- Optimize away a branch on the operator delete[] path. (@mgrice)
- Add format annotation to the format generator function. (@zoulasc)
- Refactor and improve the size class header generation. (@yinan1048576)
- Remove best fit. (@djwatson)
- Avoid blocking on background thread locks for stats. (@oranagra, @interwq)
* 5.2.0 (April 2, 2019)
This release includes a few notable improvements, which are summarized below:
1) improved fast-path performance from the optimizations by @djwatson; 2)
reduced virtual memory fragmentation and metadata usage; and 3) bug fixes on
setting the number of background threads. In addition, peak / spike memory
usage is improved with certain allocation patterns. As usual, the release and
prior dev versions have gone through large-scale production testing.
New features:
- Implement oversize_threshold, which uses a dedicated arena for allocations
crossing the specified threshold to reduce fragmentation. (@interwq)
- Add extents usage information to stats. (@tyleretzel)
- Log time information for sampled allocations. (@tyleretzel)
- Support 0 size in sdallocx. (@djwatson)
- Output rate for certain counters in malloc_stats. (@zinoale)
- Add configure option --enable-readlinkat, which allows the use of readlinkat
over readlink. (@davidtgoldblatt)
- Add configure options --{enable,disable}-{static,shared} to allow not
building unwanted libraries. (@Ericson2314)
- Add configure option --disable-libdl to enable fully static builds.
(@interwq)
- Add mallctl interfaces:
+ opt.oversize_threshold (@interwq)
+ stats.arenas.<i>.extent_avail (@tyleretzel)
+ stats.arenas.<i>.extents.<j>.n{dirty,muzzy,retained} (@tyleretzel)
+ stats.arenas.<i>.extents.<j>.{dirty,muzzy,retained}_bytes
(@tyleretzel)
Portability improvements:
- Update MSVC builds. (@maksqwe, @rustyx)
- Workaround a compiler optimizer bug on s390x. (@rkmisra)
- Make use of pthread_set_name_np(3) on FreeBSD. (@trasz)
- Implement malloc_getcpu() to enable percpu_arena for windows. (@santagada)
- Link against -pthread instead of -lpthread. (@paravoid)
- Make background_thread not dependent on libdl. (@interwq)
- Add stringify to fix a linker directive issue on MSVC. (@daverigby)
- Detect and fall back when 8-bit atomics are unavailable. (@interwq)
- Fall back to the default pthread_create if dlsym(3) fails. (@interwq)
Optimizations and refactors:
- Refactor the TSD module. (@davidtgoldblatt)
- Avoid taking extents_muzzy mutex when muzzy is disabled. (@interwq)
- Avoid taking large_mtx for auto arenas on the tcache flush path. (@interwq)
- Optimize ixalloc by avoiding a size lookup. (@interwq)
- Implement opt.oversize_threshold which uses a dedicated arena for requests
crossing the threshold, also eagerly purges the oversize extents. Default
the threshold to 8 MiB. (@interwq)
- Clean compilation with -Wextra. (@gnzlbg, @jasone)
- Refactor the size class module. (@davidtgoldblatt)
- Refactor the stats emitter. (@tyleretzel)
- Optimize pow2_ceil. (@rkmisra)
- Avoid runtime detection of lazy purging on FreeBSD. (@trasz)
- Optimize mmap(2) alignment handling on FreeBSD. (@trasz)
- Improve error handling for THP state initialization. (@jsteemann)
- Rework the malloc() fast path. (@djwatson)
- Rework the free() fast path. (@djwatson)
- Refactor and optimize the tcache fill / flush paths. (@djwatson)
- Optimize sync / lwsync on PowerPC. (@chmeeedalf)
- Bypass extent_dalloc() when retain is enabled. (@interwq)
- Optimize the locking on large deallocation. (@interwq)
- Reduce the number of pages committed from sanity checking in debug build.
(@trasz, @interwq)
- Deprecate OSSpinLock. (@interwq)
- Lower the default number of background threads to 4 (when the feature
is enabled). (@interwq)
- Optimize the trylock spin wait. (@djwatson)
- Use arena index for arena-matching checks. (@interwq)
- Avoid forced decay on thread termination when using background threads.
(@interwq)
- Disable muzzy decay by default. (@djwatson, @interwq)
- Only initialize libgcc unwinder when profiling is enabled. (@paravoid,
@interwq)
Bug fixes (all only relevant to jemalloc 5.x):
- Fix background thread index issues with max_background_threads. (@djwatson,
@interwq)
- Fix stats output for opt.lg_extent_max_active_fit. (@interwq)
- Fix opt.prof_prefix initialization. (@davidtgoldblatt)
- Properly trigger decay on tcache destroy. (@interwq, @amosbird)
- Fix tcache.flush. (@interwq)
- Detect whether explicit extent zero out is necessary with huge pages or
custom extent hooks, which may change the purge semantics. (@interwq)
- Fix a side effect caused by extent_max_active_fit combined with decay-based
purging, where freed extents can accumulate and not be reused for an
extended period of time. (@interwq, @mpghf)
- Fix a missing unlock on extent register error handling. (@zoulasc)
Testing:
- Simplify the Travis script output. (@gnzlbg)
- Update the test scripts for FreeBSD. (@devnexen)
- Add unit tests for the producer-consumer pattern. (@interwq)
- Add Cirrus-CI config for FreeBSD builds. (@jasone)
- Add size-matching sanity checks on tcache flush. (@davidtgoldblatt,
@interwq)
Incompatible changes:
- Remove --with-lg-page-sizes. (@davidtgoldblatt)
Documentation:
- Attempt to build docs by default, however skip doc building when xsltproc
is missing. (@interwq, @cmuellner)
* 5.1.0 (May 4, 2018)
* 5.1.0 (May 4th, 2018)
This release is primarily about fine-tuning, ranging from several new features
to numerous notable performance and portability enhancements. The release and
+7 -5
View File
@@ -221,6 +221,13 @@ any of the following arguments (not a definitive list) to 'configure':
system page size may change between configuration and execution, e.g. when
cross compiling.
* `--with-lg-page-sizes=<lg-page-sizes>`
Specify the comma-separated base 2 logs of the page sizes to support. This
option may be useful when cross compiling in combination with
`--with-lg-page`, but its primary use case is for integration with FreeBSD's
libc, wherein jemalloc is embedded.
* `--with-lg-hugepage=<lg-hugepage>`
Specify the base 2 log of the system huge page size. This option is useful
@@ -269,11 +276,6 @@ any of the following arguments (not a definitive list) to 'configure':
in the same process, which will almost certainly result in confusing runtime
crashes if pointers leak from one implementation to the other.
* `--disable-libdl`
Disable the usage of libdl, namely dlsym(3) which is required by the lazy
lock option. This can allow building static binaries.
The following environment variables (not a definitive list) impact configure's
behavior:
+8 -62
View File
@@ -47,7 +47,6 @@ REV := @rev@
install_suffix := @install_suffix@
ABI := @abi@
XSLTPROC := @XSLTPROC@
XSLROOT := @XSLROOT@
AUTOCONF := @AUTOCONF@
_RPATH = @RPATH@
RPATH = $(if $(1),$(call _RPATH,$(1)))
@@ -56,12 +55,8 @@ cfghdrs_out := @cfghdrs_out@
cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
cfgoutputs_out := @cfgoutputs_out@
enable_autogen := @enable_autogen@
enable_doc := @enable_doc@
enable_shared := @enable_shared@
enable_static := @enable_static@
enable_prof := @enable_prof@
enable_zone_allocator := @enable_zone_allocator@
enable_experimental_smallocx := @enable_experimental_smallocx@
MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
link_whole_archive := @link_whole_archive@
DSO_LDFLAGS = @DSO_LDFLAGS@
@@ -107,7 +102,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \
$(srcroot)src/extent_dss.c \
$(srcroot)src/extent_mmap.c \
$(srcroot)src/hash.c \
$(srcroot)src/hook.c \
$(srcroot)src/hooks.c \
$(srcroot)src/large.c \
$(srcroot)src/log.c \
$(srcroot)src/malloc_io.c \
@@ -118,12 +113,9 @@ C_SRCS := $(srcroot)src/jemalloc.c \
$(srcroot)src/prng.c \
$(srcroot)src/prof.c \
$(srcroot)src/rtree.c \
$(srcroot)src/safety_check.c \
$(srcroot)src/stats.c \
$(srcroot)src/sc.c \
$(srcroot)src/sz.c \
$(srcroot)src/tcache.c \
$(srcroot)src/test_hooks.c \
$(srcroot)src/ticker.c \
$(srcroot)src/tsd.c \
$(srcroot)src/witness.c
@@ -173,18 +165,14 @@ TESTS_UNIT := \
$(srcroot)test/unit/background_thread_enable.c \
$(srcroot)test/unit/base.c \
$(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/bit_util.c \
$(srcroot)test/unit/binshard.c \
$(srcroot)test/unit/ckh.c \
$(srcroot)test/unit/decay.c \
$(srcroot)test/unit/div.c \
$(srcroot)test/unit/emitter.c \
$(srcroot)test/unit/extent_quantize.c \
$(srcroot)test/unit/extent_util.c \
$(srcroot)test/unit/fork.c \
$(srcroot)test/unit/hash.c \
$(srcroot)test/unit/hook.c \
$(srcroot)test/unit/huge.c \
$(srcroot)test/unit/hooks.c \
$(srcroot)test/unit/junk.c \
$(srcroot)test/unit/junk_alloc.c \
$(srcroot)test/unit/junk_free.c \
@@ -202,7 +190,6 @@ TESTS_UNIT := \
$(srcroot)test/unit/prof_active.c \
$(srcroot)test/unit/prof_gdump.c \
$(srcroot)test/unit/prof_idump.c \
$(srcroot)test/unit/prof_log.c \
$(srcroot)test/unit/prof_reset.c \
$(srcroot)test/unit/prof_tctx.c \
$(srcroot)test/unit/prof_thread_name.c \
@@ -211,17 +198,13 @@ TESTS_UNIT := \
$(srcroot)test/unit/rb.c \
$(srcroot)test/unit/retained.c \
$(srcroot)test/unit/rtree.c \
$(srcroot)test/unit/safety_check.c \
$(srcroot)test/unit/seq.c \
$(srcroot)test/unit/SFMT.c \
$(srcroot)test/unit/sc.c \
$(srcroot)test/unit/size_classes.c \
$(srcroot)test/unit/slab.c \
$(srcroot)test/unit/smoothstep.c \
$(srcroot)test/unit/spin.c \
$(srcroot)test/unit/stats.c \
$(srcroot)test/unit/stats_print.c \
$(srcroot)test/unit/test_hooks.c \
$(srcroot)test/unit/ticker.c \
$(srcroot)test/unit/nstime.c \
$(srcroot)test/unit/tsd.c \
@@ -234,21 +217,15 @@ endif
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
$(srcroot)test/integration/allocated.c \
$(srcroot)test/integration/extent.c \
$(srcroot)test/integration/malloc.c \
$(srcroot)test/integration/mallocx.c \
$(srcroot)test/integration/MALLOCX_ARENA.c \
$(srcroot)test/integration/overflow.c \
$(srcroot)test/integration/posix_memalign.c \
$(srcroot)test/integration/rallocx.c \
$(srcroot)test/integration/sdallocx.c \
$(srcroot)test/integration/slab_sizes.c \
$(srcroot)test/integration/thread_arena.c \
$(srcroot)test/integration/thread_tcache_enabled.c \
$(srcroot)test/integration/xallocx.c
ifeq (@enable_experimental_smallocx@, 1)
TESTS_INTEGRATION += \
$(srcroot)test/integration/smallocx.c
endif
ifeq (@enable_cxx@, 1)
CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
@@ -256,9 +233,7 @@ else
CPP_SRCS :=
TESTS_INTEGRATION_CPP :=
endif
TESTS_STRESS := $(srcroot)test/stress/microbench.c \
$(srcroot)test/stress/hookbench.c
TESTS_STRESS := $(srcroot)test/stress/microbench.c
TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
@@ -299,24 +274,10 @@ all: build_lib
dist: build_doc
$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl
ifneq ($(XSLROOT),)
$(XSLTPROC) -o $@ $(objroot)doc/html.xsl $<
else
ifeq ($(wildcard $(DOCS_HTML)),)
@echo "<p>Missing xsltproc. Doc not built.</p>" > $@
endif
@echo "Missing xsltproc. "$@" not (re)built."
endif
$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl
ifneq ($(XSLROOT),)
$(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $<
else
ifeq ($(wildcard $(DOCS_MAN3)),)
@echo "Missing xsltproc. Doc not built." > $@
endif
@echo "Missing xsltproc. "$@" not (re)built."
endif
build_doc_html: $(DOCS_HTML)
build_doc_man: $(DOCS_MAN3)
@@ -439,7 +400,7 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLI
$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
@mkdir -p $(@D)
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -pthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
$(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
@mkdir -p $(@D)
@@ -451,12 +412,7 @@ $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TE
build_lib_shared: $(DSOS)
build_lib_static: $(STATIC_LIBS)
ifeq ($(enable_shared), 1)
build_lib: build_lib_shared
endif
ifeq ($(enable_static), 1)
build_lib: build_lib_static
endif
build_lib: build_lib_shared build_lib_static
install_bin:
$(INSTALL) -d $(BINDIR)
@@ -493,13 +449,7 @@ install_lib_pc: $(PC)
$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
done
ifeq ($(enable_shared), 1)
install_lib: install_lib_shared
endif
ifeq ($(enable_static), 1)
install_lib: install_lib_static
endif
install_lib: install_lib_pc
install_lib: install_lib_shared install_lib_static install_lib_pc
install_doc_html:
$(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
@@ -515,13 +465,9 @@ install_doc_man:
$(INSTALL) -m 644 $$d $(MANDIR)/man3; \
done
install_doc: build_doc install_doc_html install_doc_man
install_doc: install_doc_html install_doc_man
install: install_bin install_include install_lib
ifeq ($(enable_doc), 1)
install: install_doc
endif
install: install_bin install_include install_lib install_doc
tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
+1 -1
View File
@@ -1 +1 @@
5.2.1-0-g0
5.1.0-0-g0
+1 -2
View File
@@ -2909,7 +2909,6 @@ sub RemoveUninterestingFrames {
'@JEMALLOC_PREFIX@xallocx',
'@JEMALLOC_PREFIX@dallocx',
'@JEMALLOC_PREFIX@sdallocx',
'@JEMALLOC_PREFIX@sdallocx_noflags',
'tc_calloc',
'tc_cfree',
'tc_malloc',
@@ -5367,7 +5366,7 @@ sub GetProcedureBoundaries {
my $demangle_flag = "";
my $cppfilt_flag = "";
my $to_devnull = ">$dev_null 2>&1";
if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) {
if (system(ShellEscape($nm, "--demangle", "image") . $to_devnull) == 0) {
# In this mode, we do "nm --demangle <foo>"
$demangle_flag = "--demangle";
$cppfilt_flag = "";
+231 -623
View File
File diff suppressed because it is too large. Load diff
+139 -251
View File
@@ -175,9 +175,6 @@ fi
],
XSLROOT="${DEFAULT_XSLROOT}"
)
if test "x$XSLTPROC" = "xfalse" ; then
XSLROOT=""
fi
AC_SUBST([XSLROOT])
dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
@@ -245,7 +242,6 @@ if test "x$GCC" = "xyes" ; then
fi
fi
JE_CFLAGS_ADD([-Wall])
JE_CFLAGS_ADD([-Wextra])
JE_CFLAGS_ADD([-Wshorten-64-to-32])
JE_CFLAGS_ADD([-Wsign-compare])
JE_CFLAGS_ADD([-Wundef])
@@ -293,7 +289,6 @@ if test "x$enable_cxx" = "x1" ; then
AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
if test "x${HAVE_CXX14}" = "x1" ; then
JE_CXXFLAGS_ADD([-Wall])
JE_CXXFLAGS_ADD([-Wextra])
JE_CXXFLAGS_ADD([-g3])
SAVED_LIBS="${LIBS}"
@@ -517,7 +512,7 @@ CTARGET='-o $@'
LDTARGET='-o $@'
TEST_LD_MODE=
EXTRA_LDFLAGS=
ARFLAGS='crs'
ARFLAGS='crus'
AROUT=' $@'
CC_MM=1
@@ -541,66 +536,6 @@ AC_PROG_NM
AC_PROG_AWK
dnl ============================================================================
dnl jemalloc version.
dnl
AC_ARG_WITH([version],
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
[Version string])],
[
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
if test $? -eq 0 ; then
echo "$with_version" > "${objroot}VERSION"
else
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
if test $? -ne 0 ; then
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
fi
fi
], [
dnl Set VERSION if source directory is inside a git repository.
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
dnl Pattern globs aren't powerful enough to match both single- and
dnl double-digit version numbers, so iterate over patterns to support up
dnl to version 99.99.99 without any accidental matches.
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
'[0-9][0-9].[0-9][0-9].[0-9]' \
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
if test $? -eq 0 ; then
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
break
fi
done
fi
rm -f "${objroot}VERSION.tmp"
])
if test ! -e "${objroot}VERSION" ; then
if test ! -e "${srcroot}VERSION" ; then
AC_MSG_RESULT(
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
else
cp ${srcroot}VERSION ${objroot}VERSION
fi
fi
jemalloc_version=`cat "${objroot}VERSION"`
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
AC_SUBST([jemalloc_version])
AC_SUBST([jemalloc_version_major])
AC_SUBST([jemalloc_version_minor])
AC_SUBST([jemalloc_version_bugfix])
AC_SUBST([jemalloc_version_nrev])
AC_SUBST([jemalloc_version_gid])
dnl Platform-specific settings. abi and RPATH can probably be determined
dnl programmatically, but doing so is error-prone, which makes it generally
dnl not worth the trouble.
@@ -738,9 +673,6 @@ case "${host}" in
libprefix=""
SOREV="${so}"
PIC_CFLAGS=""
if test "${LG_SIZEOF_PTR}" = "3"; then
default_retain="1"
fi
;;
*)
AC_MSG_RESULT([Unsupported operating system: ${host}])
@@ -854,18 +786,6 @@ if test "x${je_cv_format_printf}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
fi
dnl Check for format_arg(...) attribute support.
JE_CFLAGS_SAVE()
JE_CFLAGS_ADD([-Werror])
JE_CFLAGS_ADD([-herror_on_warning])
JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
[const char * __attribute__((__format_arg__(1))) foo(const char *format);],
[je_cv_format_arg])
JE_CFLAGS_RESTORE()
if test "x${je_cv_format_arg}" = "xyes" ; then
AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ])
fi
dnl Support optional additions to rpath.
AC_ARG_WITH([rpath],
[AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
@@ -896,49 +816,6 @@ AC_PROG_RANLIB
AC_PATH_PROG([LD], [ld], [false], [$PATH])
AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
dnl Enable documentation
AC_ARG_ENABLE([doc],
[AS_HELP_STRING([--enable-documentation], [Build documentation])],
if test "x$enable_doc" = "xno" ; then
enable_doc="0"
else
enable_doc="1"
fi
,
enable_doc="1"
)
AC_SUBST([enable_doc])
dnl Enable shared libs
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared], [Build shared libaries])],
if test "x$enable_shared" = "xno" ; then
enable_shared="0"
else
enable_shared="1"
fi
,
enable_shared="1"
)
AC_SUBST([enable_shared])
dnl Enable static libs
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static], [Build static libaries])],
if test "x$enable_static" = "xno" ; then
enable_static="0"
else
enable_static="1"
fi
,
enable_static="1"
)
AC_SUBST([enable_static])
if test "$enable_shared$enable_static" = "00" ; then
AC_MSG_ERROR([Please enable one of shared or static builds])
fi
dnl Perform no name mangling by default.
AC_ARG_WITH([mangling],
[AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])],
@@ -971,7 +848,7 @@ AC_ARG_WITH([export],
fi]
)
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
dnl Check for additional platform-specific public API functions.
AC_CHECK_FUNC([memalign],
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ])
@@ -1089,6 +966,7 @@ cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh"
cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh"
@@ -1101,6 +979,7 @@ cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk"
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt"
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h"
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h"
cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/size_classes.h"
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h"
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h"
cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h"
@@ -1112,10 +991,6 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i
cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in"
cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in"
dnl ============================================================================
dnl jemalloc build options.
dnl
dnl Do not compile with debugging by default.
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],
@@ -1168,22 +1043,6 @@ if test "x$enable_stats" = "x1" ; then
fi
AC_SUBST([enable_stats])
dnl Do not enable smallocx by default.
AC_ARG_ENABLE([experimental_smallocx],
[AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])],
[if test "x$enable_experimental_smallocx" = "xno" ; then
enable_experimental_smallocx="0"
else
enable_experimental_smallocx="1"
fi
],
[enable_experimental_smallocx="0"]
)
if test "x$enable_experimental_smallocx" = "x1" ; then
AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API])
fi
AC_SUBST([enable_experimental_smallocx])
dnl Do not enable profiling by default.
AC_ARG_ENABLE([prof],
[AS_HELP_STRING([--enable-prof], [Enable allocation profiling])],
@@ -1418,38 +1277,6 @@ if test "x$enable_log" = "x1" ; then
fi
AC_SUBST([enable_log])
dnl Do not use readlinkat by default
AC_ARG_ENABLE([readlinkat],
[AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])],
[if test "x$enable_readlinkat" = "xno" ; then
enable_readlinkat="0"
else
enable_readlinkat="1"
fi
],
[enable_readlinkat="0"]
)
if test "x$enable_readlinkat" = "x1" ; then
AC_DEFINE([JEMALLOC_READLINKAT], [ ])
fi
AC_SUBST([enable_readlinkat])
dnl Avoid extra safety checks by default
AC_ARG_ENABLE([opt-safety-checks],
[AS_HELP_STRING([--enable-opt-safety-checks],
[Perform certain low-overhead checks, even in opt mode])],
[if test "x$enable_opt_safety_checks" = "xno" ; then
enable_opt_safety_checks="0"
else
enable_opt_safety_checks="1"
fi
],
[enable_opt_safety_checks="0"]
)
if test "x$enable_opt_safety_checks" = "x1" ; then
AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ])
fi
AC_SUBST([enable_opt_safety_checks])
JE_COMPILABLE([a program using __builtin_unreachable], [
void foo (void) {
@@ -1506,21 +1333,6 @@ else
fi
fi
JE_COMPILABLE([a program using __builtin_popcountl], [
#include <stdio.h>
#include <strings.h>
#include <string.h>
], [
{
int rv = __builtin_popcountl(0x08);
printf("%d\n", rv);
}
], [je_cv_gcc_builtin_popcountl])
if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount])
AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl])
fi
AC_ARG_WITH([lg_quantum],
[AS_HELP_STRING([--with-lg-quantum=<lg-quantum>],
[Base 2 log of minimum allocation alignment])],
@@ -1618,20 +1430,70 @@ if test "x${LG_PAGE}" != "xundefined" -a \
fi
AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}])
AC_ARG_WITH([lg_page_sizes],
[AS_HELP_STRING([--with-lg-page-sizes=<lg-page-sizes>],
[Base 2 logs of system page sizes to support])],
[LG_PAGE_SIZES="$with_lg_page_sizes"], [LG_PAGE_SIZES="$LG_PAGE"])
dnl ============================================================================
dnl Enable libdl by default.
AC_ARG_ENABLE([libdl],
[AS_HELP_STRING([--disable-libdl],
[Do not use libdl])],
[if test "x$enable_libdl" = "xno" ; then
enable_libdl="0"
else
enable_libdl="1"
dnl jemalloc configuration.
dnl
AC_ARG_WITH([version],
[AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
[Version string])],
[
echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
if test $? -eq 0 ; then
echo "$with_version" > "${objroot}VERSION"
else
echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
if test $? -ne 0 ; then
AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
fi
fi
], [
dnl Set VERSION if source directory is inside a git repository.
if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
dnl Pattern globs aren't powerful enough to match both single- and
dnl double-digit version numbers, so iterate over patterns to support up
dnl to version 99.99.99 without any accidental matches.
for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
'[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
'[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
'[0-9][0-9].[0-9][0-9].[0-9]' \
'[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
(test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
if test $? -eq 0 ; then
mv "${objroot}VERSION.tmp" "${objroot}VERSION"
break
fi
done
fi
rm -f "${objroot}VERSION.tmp"
])
if test ! -e "${objroot}VERSION" ; then
if test ! -e "${srcroot}VERSION" ; then
AC_MSG_RESULT(
[Missing VERSION file, and unable to generate it; creating bogus VERSION])
echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
else
cp ${srcroot}VERSION ${objroot}VERSION
fi
fi
],
[enable_libdl="1"]
)
AC_SUBST([libdl])
jemalloc_version=`cat "${objroot}VERSION"`
jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
AC_SUBST([jemalloc_version])
AC_SUBST([jemalloc_version_major])
AC_SUBST([jemalloc_version_minor])
AC_SUBST([jemalloc_version_bugfix])
AC_SUBST([jemalloc_version_nrev])
AC_SUBST([jemalloc_version_gid])
dnl ============================================================================
dnl Configure pthreads.
@@ -1641,26 +1503,20 @@ if test "x$abi" != "xpecoff" ; then
AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
dnl Some systems may embed pthreads functionality in libc; check for libpthread
dnl first, but try libc too before failing.
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)],
AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)],
[AC_SEARCH_LIBS([pthread_create], , ,
AC_MSG_ERROR([libpthread is missing]))])
wrap_syms="${wrap_syms} pthread_create"
have_pthread="1"
dnl Check if we have dlsym support.
if test "x$enable_libdl" = "x1" ; then
have_dlsym="1"
AC_CHECK_HEADERS([dlfcn.h],
AC_CHECK_FUNC([dlsym], [],
[AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]),
[have_dlsym="0"])
if test "x$have_dlsym" = "x1" ; then
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
fi
else
have_dlsym="0"
dnl Check if we have dlsym support.
have_dlsym="1"
AC_CHECK_HEADERS([dlfcn.h],
AC_CHECK_FUNC([dlsym], [],
[AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]),
[have_dlsym="0"])
if test "x$have_dlsym" = "x1" ; then
AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
fi
JE_COMPILABLE([pthread_atfork(3)], [
#include <pthread.h>
], [
@@ -1924,19 +1780,6 @@ JE_COMPILABLE([GCC __atomic atomics], [
], [je_cv_gcc_atomic_atomics])
if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then
AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS])
dnl check for 8-bit atomic support
JE_COMPILABLE([GCC 8-bit __atomic atomics], [
], [
unsigned char x = 0;
int val = 1;
int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED);
int after_add = (int)x;
return after_add == 1;
], [je_cv_gcc_u8_atomic_atomics])
if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then
AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS])
fi
fi
dnl ============================================================================
@@ -1951,24 +1794,12 @@ JE_COMPILABLE([GCC __sync atomics], [
], [je_cv_gcc_sync_atomics])
if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then
AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS])
dnl check for 8-bit atomic support
JE_COMPILABLE([GCC 8-bit __sync atomics], [
], [
unsigned char x = 0;
int before_add = __sync_fetch_and_add(&x, 1);
int after_add = (int)x;
return (before_add == 0) && (after_add == 1);
], [je_cv_gcc_u8_sync_atomics])
if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then
AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS])
fi
fi
dnl ============================================================================
dnl Check for atomic(3) operations as provided on Darwin.
dnl We need this not for the atomic operations (which are provided above), but
dnl rather for the OS_unfair_lock type it exposes.
dnl rather for the OSSpinLock type it exposes.
JE_COMPILABLE([Darwin OSAtomic*()], [
#include <libkern/OSAtomic.h>
@@ -2039,7 +1870,7 @@ if test "x${je_cv_madvise}" = "xyes" ; then
if test "x${je_cv_madv_dontdump}" = "xyes" ; then
AC_DEFINE([JEMALLOC_MADVISE_DONTDUMP], [ ])
fi
dnl Check for madvise(..., MADV_[NO]HUGEPAGE).
JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [
#include <sys/mman.h>
@@ -2058,6 +1889,40 @@ case "${host_cpu}" in
esac
fi
dnl ============================================================================
dnl Check whether __sync_{add,sub}_and_fetch() are available despite
dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined.
AC_DEFUN([JE_SYNC_COMPARE_AND_SWAP_CHECK],[
AC_CACHE_CHECK([whether to force $1-bit __sync_{add,sub}_and_fetch()],
[je_cv_sync_compare_and_swap_$2],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <stdint.h>
],
[
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2
{
uint$1_t x$1 = 0;
__sync_add_and_fetch(&x$1, 42);
__sync_sub_and_fetch(&x$1, 1);
}
#else
#error __GCC_HAVE_SYNC_COMPARE_AND_SWAP_$2 is defined, no need to force
#endif
])],
[je_cv_sync_compare_and_swap_$2=yes],
[je_cv_sync_compare_and_swap_$2=no])])
if test "x${je_cv_sync_compare_and_swap_$2}" = "xyes" ; then
AC_DEFINE([JE_FORCE_SYNC_COMPARE_AND_SWAP_$2], [ ])
fi
])
if test "x${je_cv_atomic9}" != "xyes" -a "x${je_cv_osatomic}" != "xyes" ; then
JE_SYNC_COMPARE_AND_SWAP_CHECK(32, 4)
JE_SYNC_COMPARE_AND_SWAP_CHECK(64, 8)
fi
dnl ============================================================================
dnl Check for __builtin_clz() and __builtin_clzl().
@@ -2100,6 +1965,21 @@ if test "x${je_cv_os_unfair_lock}" = "xyes" ; then
AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
fi
dnl ============================================================================
dnl Check for spinlock(3) operations as provided on Darwin.
JE_COMPILABLE([Darwin OSSpin*()], [
#include <libkern/OSAtomic.h>
#include <inttypes.h>
], [
OSSpinLock lock = 0;
OSSpinLockLock(&lock);
OSSpinLockUnlock(&lock);
], [je_cv_osspin])
if test "x${je_cv_osspin}" = "xyes" ; then
AC_DEFINE([JEMALLOC_OSSPIN], [ ])
fi
dnl ============================================================================
dnl Darwin-related configuration.
@@ -2152,7 +2032,9 @@ fi
dnl ============================================================================
dnl Enable background threads if possible.
if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then
if test "x${have_pthread}" = "x1" -a "x${have_dlsym}" = "x1" \
-a "x${je_cv_os_unfair_lock}" != "xyes" \
-a "x${je_cv_osspin}" != "xyes" ; then
AC_DEFINE([JEMALLOC_BACKGROUND_THREAD])
fi
@@ -2293,6 +2175,16 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [
srcdir="${srcdir}"
objroot="${objroot}"
])
AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [
mkdir -p "${objroot}include/jemalloc/internal"
"${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" 3 "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h"
], [
SHELL="${SHELL}"
srcdir="${srcdir}"
objroot="${objroot}"
LG_QUANTA="${LG_QUANTA}"
LG_PAGE_SIZES="${LG_PAGE_SIZES}"
])
AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [
mkdir -p "${objroot}include/jemalloc"
cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h"
@@ -2385,13 +2277,9 @@ AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
AC_MSG_RESULT([install_suffix : ${install_suffix}])
AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}])
AC_MSG_RESULT([documentation : ${enable_doc}])
AC_MSG_RESULT([shared libs : ${enable_shared}])
AC_MSG_RESULT([static libs : ${enable_static}])
AC_MSG_RESULT([autogen : ${enable_autogen}])
AC_MSG_RESULT([debug : ${enable_debug}])
AC_MSG_RESULT([stats : ${enable_stats}])
AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}])
AC_MSG_RESULT([prof : ${enable_prof}])
AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
+22 -156
View File
@@ -424,7 +424,7 @@ for (i = 0; i < nbins; i++) {
called repeatedly. General information that never changes during
execution can be omitted by specifying <quote>g</quote> as a character
within the <parameter>opts</parameter> string. Note that
<function>malloc_stats_print()</function> uses the
<function>malloc_message()</function> uses the
<function>mallctl*()</function> functions internally, so inconsistent
statistics can be reported if multiple threads use these functions
simultaneously. If <option>--enable-stats</option> is specified during
@@ -433,11 +433,10 @@ for (i = 0; i < nbins; i++) {
arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can
be specified to omit per size class statistics for bins and large objects,
respectively; <quote>x</quote> can be specified to omit all mutex
statistics; <quote>e</quote> can be used to omit extent statistics.
Unrecognized characters are silently ignored. Note that thread caching
may prevent some statistics from being completely up to date, since extra
locking would be required to merge counters that track thread cache
operations.</para>
statistics. Unrecognized characters are silently ignored. Note that
thread caching may prevent some statistics from being completely up to
date, since extra locking would be required to merge counters that track
thread cache operations.</para>
<para>The <function>malloc_usable_size()</function> function
returns the usable size of the allocation pointed to by
@@ -904,23 +903,6 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
</para></listitem>
</varlistentry>
<varlistentry id="opt.confirm_conf">
<term>
<mallctl>opt.confirm_conf</mallctl>
(<type>bool</type>)
<literal>r-</literal>
</term>
<listitem><para>Confirm-runtime-options-when-program-starts
enabled/disabled. If true, the string specified via
<option>--with-malloc-conf</option>, the string pointed to by the
global variable <varname>malloc_conf</varname>, the <quote>name</quote>
of the file referenced by the symbolic link named
<filename class="symlink">/etc/malloc.conf</filename>, and the value of
the environment variable <envar>MALLOC_CONF</envar>, will be printed in
order. Then, each option being set will be individually printed. This
option is disabled by default.</para></listitem>
</varlistentry>
<varlistentry id="opt.abort_conf">
<term>
<mallctl>opt.abort_conf</mallctl>
@@ -961,19 +943,16 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
<citerefentry><refentrytitle>munmap</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> or equivalent (see <link
linkend="stats.retained">stats.retained</link> for related details).
It also makes jemalloc use <citerefentry>
<refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum>
</citerefentry> or equivalent in a more greedy way, mapping larger
chunks in one go. This option is disabled by default unless discarding
virtual memory is known to trigger platform-specific performance
problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual
memory allocation algorithm that causes semi-permanent VM map holes
under normal jemalloc operation; and 2) for [64-bit] Windows, which
disallows split / merged regions with
<parameter><constant>MEM_RELEASE</constant></parameter>. Although the
same issues may present on 32-bit platforms as well, retaining virtual
memory for 32-bit Linux and Windows is disabled by default due to the
practical possibility of address space exhaustion. </para></listitem>
This option is disabled by default unless discarding virtual memory is
known to trigger
platform-specific performance problems, e.g. for [64-bit] Linux, which
has a quirk in its virtual memory allocation algorithm that causes
semi-permanent VM map holes under normal jemalloc operation. Although
<citerefentry><refentrytitle>munmap</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> causes issues on 32-bit Linux as
well, retaining virtual memory for 32-bit Linux is disabled by default
due to the practical possibility of address space exhaustion.
</para></listitem>
</varlistentry>
<varlistentry id="opt.dss">
@@ -1009,24 +988,6 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
number of CPUs, or one if there is a single CPU.</para></listitem>
</varlistentry>
<varlistentry id="opt.oversize_threshold">
<term>
<mallctl>opt.oversize_threshold</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
</term>
<listitem><para>The threshold in bytes of which requests are considered
oversize. Allocation requests with greater sizes are fulfilled from a
dedicated arena (automatically managed, however not within
<literal>narenas</literal>), in order to reduce fragmentation by not
mixing huge allocations with small ones. In addition, the decay API
guarantees on the extents greater than the specified threshold may be
overridden. Note that requests with arena index specified via
<constant>MALLOCX_ARENA</constant>, or threads associated with explicit
arenas will not be considered. The default threshold is 8MiB. Values
not within large size classes disables this feature.</para></listitem>
</varlistentry>
<varlistentry id="opt.percpu_arena">
<term>
<mallctl>opt.percpu_arena</mallctl>
@@ -1048,7 +1009,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
<varlistentry id="opt.background_thread">
<term>
<mallctl>opt.background_thread</mallctl>
(<type>bool</type>)
(<type>const bool</type>)
<literal>r-</literal>
</term>
<listitem><para>Internal background worker threads enabled/disabled.
@@ -1063,7 +1024,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
<varlistentry id="opt.max_background_threads">
<term>
<mallctl>opt.max_background_threads</mallctl>
(<type>size_t</type>)
(<type>const size_t</type>)
<literal>r-</literal>
</term>
<listitem><para>Maximum number of background threads that will be created
@@ -1094,11 +1055,7 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
linkend="arena.i.dirty_decay_ms"><mallctl>arena.&lt;i&gt;.dirty_decay_ms</mallctl></link>
for related dynamic control options. See <link
linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
for a description of muzzy pages.for a description of muzzy pages. Note
that when the <link
linkend="opt.oversize_threshold"><mallctl>oversize_threshold</mallctl></link>
feature is enabled, the arenas reserved for oversize requests may have
its own default decay settings.</para></listitem>
for a description of muzzy pages.</para></listitem>
</varlistentry>
<varlistentry id="opt.muzzy_decay_ms">
@@ -1806,11 +1763,10 @@ malloc_conf = "xmalloc:true";]]></programlisting>
to control allocation for arenas explicitly created via <link
linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such
that all extents originate from an application-supplied extent allocator
(by specifying the custom extent hook functions during arena creation).
However, the API guarantees for the automatically created arenas may be
relaxed -- hooks set there may be called in a "best effort" fashion; in
addition there may be extents created prior to the application having an
opportunity to take over extent allocation.</para>
(by specifying the custom extent hook functions during arena creation),
but the automatically created arenas will have already created extents
prior to the application having an opportunity to take over extent
allocation.</para>
<programlisting language="C"><![CDATA[
typedef extent_hooks_s extent_hooks_t;
@@ -2637,17 +2593,6 @@ struct extent_hooks_s {
details.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.extent_avail">
<term>
<mallctl>stats.arenas.&lt;i&gt;.extent_avail</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Number of allocated (but unused) extent structs in this
arena.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.base">
<term>
<mallctl>stats.arenas.&lt;i&gt;.base</mallctl>
@@ -2815,28 +2760,6 @@ struct extent_hooks_s {
all bin size classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.small.nfills">
<term>
<mallctl>stats.arenas.&lt;i&gt;.small.nfills</mallctl>
(<type>uint64_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Cumulative number of tcache fills by all small size
classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.small.nflushes">
<term>
<mallctl>stats.arenas.&lt;i&gt;.small.nflushes</mallctl>
(<type>uint64_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Cumulative number of tcache flushes by all small size
classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.large.allocated">
<term>
<mallctl>stats.arenas.&lt;i&gt;.large.allocated</mallctl>
@@ -2887,28 +2810,6 @@ struct extent_hooks_s {
all large size classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.large.nfills">
<term>
<mallctl>stats.arenas.&lt;i&gt;.large.nfills</mallctl>
(<type>uint64_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Cumulative number of tcache fills by all large size
classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.large.nflushes">
<term>
<mallctl>stats.arenas.&lt;i&gt;.large.nflushes</mallctl>
(<type>uint64_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Cumulative number of tcache flushes by all large size
classes.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.bins.j.nmalloc">
<term>
<mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nmalloc</mallctl>
@@ -3008,17 +2909,6 @@ struct extent_hooks_s {
<listitem><para>Current number of slabs.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.bins.j.nonfull_slabs">
<term>
<mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nonfull_slabs</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para>Current number of nonfull slabs.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.bins.mutex">
<term>
<mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.mutex.{counter}</mallctl>
@@ -3032,30 +2922,6 @@ struct extent_hooks_s {
counters</link>.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.extents.n">
<term>
<mallctl>stats.arenas.&lt;i&gt;.extents.&lt;j&gt;.n{extent_type}</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para> Number of extents of the given type in this arena in
the bucket corresponding to page size index &lt;j&gt;. The extent type
is one of dirty, muzzy, or retained.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.extents.bytes">
<term>
<mallctl>stats.arenas.&lt;i&gt;.extents.&lt;j&gt;.{extent_type}_bytes</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
[<option>--enable-stats</option>]
</term>
<listitem><para> Sum of the bytes managed by extents of the given type
in this arena in the bucket corresponding to page size index &lt;j&gt;.
The extent type is one of dirty, muzzy, or retained.</para></listitem>
</varlistentry>
<varlistentry id="stats.arenas.i.lextents.j.nmalloc">
<term>
<mallctl>stats.arenas.&lt;i&gt;.lextents.&lt;j&gt;.nmalloc</mallctl>
+8 -18
View File
@@ -3,8 +3,8 @@
#include "jemalloc/internal/bin.h"
#include "jemalloc/internal/extent_dss.h"
#include "jemalloc/internal/hook.h"
#include "jemalloc/internal/pages.h"
#include "jemalloc/internal/size_classes.h"
#include "jemalloc/internal/stats.h"
extern ssize_t opt_dirty_decay_ms;
@@ -16,17 +16,13 @@ extern const char *percpu_arena_mode_names[];
extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS];
extern malloc_mutex_t arenas_lock;
extern size_t opt_oversize_threshold;
extern size_t oversize_threshold;
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
bin_stats_t *bstats, arena_stats_large_t *lstats,
arena_stats_extents_t *estats);
bin_stats_t *bstats, arena_stats_large_t *lstats);
void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena,
extent_hooks_t **r_extent_hooks, extent_t *extent);
#ifdef JEMALLOC_JET
@@ -60,17 +56,16 @@ void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size,
szind_t ind, bool zero);
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
size_t alignment, bool zero, tcache_t *tcache);
void arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize);
void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize);
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
bool slow_path);
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
szind_t binind, extent_t *extent, void *ptr);
void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena,
extent_t *extent, void *ptr);
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
size_t extra, bool zero, size_t *newsize);
size_t extra, bool zero);
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
size_t size, size_t alignment, bool zero, tcache_t *tcache,
hook_ralloc_args_t *hook_args);
size_t size, size_t alignment, bool zero, tcache_t *tcache);
dss_prec_t arena_dss_prec_get(arena_t *arena);
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
ssize_t arena_dirty_decay_ms_default_get(void);
@@ -84,12 +79,7 @@ void arena_nthreads_inc(arena_t *arena, bool internal);
void arena_nthreads_dec(arena_t *arena, bool internal);
size_t arena_extent_sn_next(arena_t *arena);
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
bool arena_init_huge(void);
bool arena_is_huge(unsigned arena_ind);
arena_t *arena_choose_huge(tsd_t *tsd);
bin_t *arena_bin_choose_lock(tsdn_t *tsdn, arena_t *arena, szind_t binind,
unsigned *binshard);
void arena_boot(sc_data_t *sc_data);
void arena_boot(void);
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
void arena_prefork2(tsdn_t *tsdn, arena_t *arena);
+42 -115
View File
@@ -4,36 +4,10 @@
#include "jemalloc/internal/jemalloc_internal_types.h"
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/rtree.h"
#include "jemalloc/internal/sc.h"
#include "jemalloc/internal/size_classes.h"
#include "jemalloc/internal/sz.h"
#include "jemalloc/internal/ticker.h"
JEMALLOC_ALWAYS_INLINE bool
arena_has_default_hooks(arena_t *arena) {
return (extent_hooks_get(arena) == &extent_hooks_default);
}
JEMALLOC_ALWAYS_INLINE arena_t *
arena_choose_maybe_huge(tsd_t *tsd, arena_t *arena, size_t size) {
if (arena != NULL) {
return arena;
}
/*
* For huge allocations, use the dedicated huge arena if both are true:
* 1) is using auto arena selection (i.e. arena == NULL), and 2) the
* thread is not assigned to a manual arena.
*/
if (unlikely(size >= oversize_threshold)) {
arena_t *tsd_arena = tsd_arena_get(tsd);
if (tsd_arena == NULL || arena_is_auto(tsd_arena)) {
return arena_choose_huge(tsd);
}
}
return arena_choose(tsd, NULL);
}
JEMALLOC_ALWAYS_INLINE prof_tctx_t *
arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
cassert(config_prof);
@@ -54,7 +28,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) {
}
JEMALLOC_ALWAYS_INLINE void
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize,
arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, UNUSED size_t usize,
alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) {
cassert(config_prof);
assert(ptr != NULL);
@@ -73,7 +47,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize,
}
static inline void
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) {
arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, UNUSED prof_tctx_t *tctx) {
cassert(config_prof);
assert(ptr != NULL);
@@ -83,32 +57,6 @@ arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) {
large_prof_tctx_reset(tsdn, extent);
}
JEMALLOC_ALWAYS_INLINE nstime_t
arena_prof_alloc_time_get(tsdn_t *tsdn, const void *ptr,
alloc_ctx_t *alloc_ctx) {
cassert(config_prof);
assert(ptr != NULL);
extent_t *extent = iealloc(tsdn, ptr);
/*
* Unlike arena_prof_prof_tctx_{get, set}, we only call this once we're
* sure we have a sampled allocation.
*/
assert(!extent_slab_get(extent));
return large_prof_alloc_time_get(extent);
}
JEMALLOC_ALWAYS_INLINE void
arena_prof_alloc_time_set(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx,
nstime_t t) {
cassert(config_prof);
assert(ptr != NULL);
extent_t *extent = iealloc(tsdn, ptr);
assert(!extent_slab_get(extent));
large_prof_alloc_time_set(extent, t);
}
JEMALLOC_ALWAYS_INLINE void
arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) {
tsd_t *tsd;
@@ -135,33 +83,14 @@ arena_decay_tick(tsdn_t *tsdn, arena_t *arena) {
arena_decay_ticks(tsdn, arena, 1);
}
/* Purge a single extent to retained / unmapped directly. */
JEMALLOC_ALWAYS_INLINE void
arena_decay_extent(tsdn_t *tsdn,arena_t *arena, extent_hooks_t **r_extent_hooks,
extent_t *extent) {
size_t extent_size = extent_size_get(extent);
extent_dalloc_wrapper(tsdn, arena,
r_extent_hooks, extent);
if (config_stats) {
/* Update stats accordingly. */
arena_stats_lock(tsdn, &arena->stats);
arena_stats_add_u64(tsdn, &arena->stats,
&arena->decay_dirty.stats->nmadvise, 1);
arena_stats_add_u64(tsdn, &arena->stats,
&arena->decay_dirty.stats->purged, extent_size >> LG_PAGE);
arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped,
extent_size);
arena_stats_unlock(tsdn, &arena->stats);
}
}
JEMALLOC_ALWAYS_INLINE void *
arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
tcache_t *tcache, bool slow_path) {
assert(!tsdn_null(tsdn) || tcache == NULL);
assert(size != 0);
if (likely(tcache != NULL)) {
if (likely(size <= SC_SMALL_MAXCLASS)) {
if (likely(size <= SMALL_MAXCLASS)) {
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
tcache, size, ind, zero, slow_path);
}
@@ -190,7 +119,7 @@ arena_salloc(tsdn_t *tsdn, const void *ptr) {
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
(uintptr_t)ptr, true);
assert(szind != SC_NSIZES);
assert(szind != NSIZES);
return sz_index2size(szind);
}
@@ -223,21 +152,11 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
/* Only slab members should be looked up via interior pointers. */
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
assert(szind != SC_NSIZES);
assert(szind != NSIZES);
return sz_index2size(szind);
}
static inline void
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) {
if (config_prof && unlikely(szind < SC_NBINS)) {
arena_dalloc_promoted(tsdn, ptr, NULL, true);
} else {
extent_t *extent = iealloc(tsdn, ptr);
large_dalloc(tsdn, extent);
}
}
static inline void
arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
assert(ptr != NULL);
@@ -254,28 +173,13 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
rtree_ctx, (uintptr_t)ptr, true);
assert(szind == extent_szind_get(extent));
assert(szind < SC_NSIZES);
assert(szind < NSIZES);
assert(slab == extent_slab_get(extent));
}
if (likely(slab)) {
/* Small allocation. */
arena_dalloc_small(tsdn, ptr);
} else {
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
}
}
JEMALLOC_ALWAYS_INLINE void
arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
bool slow_path) {
if (szind < nhbins) {
if (config_prof && unlikely(szind < SC_NBINS)) {
arena_dalloc_promoted(tsdn, ptr, tcache, slow_path);
} else {
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind,
slow_path);
}
} else {
extent_t *extent = iealloc(tsdn, ptr);
large_dalloc(tsdn, extent);
@@ -299,7 +203,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
if (alloc_ctx != NULL) {
szind = alloc_ctx->szind;
slab = alloc_ctx->slab;
assert(szind != SC_NSIZES);
assert(szind != NSIZES);
} else {
rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn));
rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx,
@@ -311,7 +215,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
extent_t *extent = rtree_extent_read(tsdn, &extents_rtree,
rtree_ctx, (uintptr_t)ptr, true);
assert(szind == extent_szind_get(extent));
assert(szind < SC_NSIZES);
assert(szind < NSIZES);
assert(slab == extent_slab_get(extent));
}
@@ -320,14 +224,25 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
slow_path);
} else {
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
if (szind < nhbins) {
if (config_prof && unlikely(szind < NBINS)) {
arena_dalloc_promoted(tsdn, ptr, tcache,
slow_path);
} else {
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
szind, slow_path);
}
} else {
extent_t *extent = iealloc(tsdn, ptr);
large_dalloc(tsdn, extent);
}
}
}
static inline void
arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
assert(ptr != NULL);
assert(size <= SC_LARGE_MAXCLASS);
assert(size <= LARGE_MAXCLASS);
szind_t szind;
bool slab;
@@ -337,7 +252,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
* object, so base szind and slab on the given size.
*/
szind = sz_size2index(size);
slab = (szind < SC_NBINS);
slab = (szind < NBINS);
}
if ((config_prof && opt_prof) || config_debug) {
@@ -349,7 +264,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
(uintptr_t)ptr, true, &szind, &slab);
assert(szind == sz_size2index(size));
assert((config_prof && opt_prof) || slab == (szind < SC_NBINS));
assert((config_prof && opt_prof) || slab == (szind < NBINS));
if (config_debug) {
extent_t *extent = rtree_extent_read(tsdn,
@@ -363,7 +278,8 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
/* Small allocation. */
arena_dalloc_small(tsdn, ptr);
} else {
arena_dalloc_large_no_tcache(tsdn, ptr, szind);
extent_t *extent = iealloc(tsdn, ptr);
large_dalloc(tsdn, extent);
}
}
@@ -372,7 +288,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
alloc_ctx_t *alloc_ctx, bool slow_path) {
assert(!tsdn_null(tsdn) || tcache == NULL);
assert(ptr != NULL);
assert(size <= SC_LARGE_MAXCLASS);
assert(size <= LARGE_MAXCLASS);
if (unlikely(tcache == NULL)) {
arena_sdalloc_no_tcache(tsdn, ptr, size);
@@ -381,7 +297,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
szind_t szind;
bool slab;
alloc_ctx_t local_ctx;
UNUSED alloc_ctx_t local_ctx;
if (config_prof && opt_prof) {
if (alloc_ctx == NULL) {
/* Uncommon case and should be a static check. */
@@ -402,7 +318,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
* object, so base szind and slab on the given size.
*/
szind = sz_size2index(size);
slab = (szind < SC_NBINS);
slab = (szind < NBINS);
}
if (config_debug) {
@@ -420,7 +336,18 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind,
slow_path);
} else {
arena_dalloc_large(tsdn, ptr, tcache, szind, slow_path);
if (szind < nhbins) {
if (config_prof && unlikely(szind < NBINS)) {
arena_dalloc_promoted(tsdn, ptr, tcache,
slow_path);
} else {
tcache_dalloc_large(tsdn_tsd(tsdn),
tcache, ptr, szind, slow_path);
}
} else {
extent_t *extent = iealloc(tsdn, ptr);
large_dalloc(tsdn, extent);
}
}
}
+15 -49
View File
@@ -4,9 +4,7 @@
#include "jemalloc/internal/atomic.h"
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/mutex_prof.h"
#include "jemalloc/internal/sc.h"
JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
#include "jemalloc/internal/size_classes.h"
/*
* In those architectures that support 64-bit atomics, we use atomic updates for
@@ -35,13 +33,6 @@ struct arena_stats_large_s {
* periodically merges into this counter.
*/
arena_stats_u64_t nrequests; /* Partially derived. */
/*
* Number of tcache fills / flushes for large (similarly, periodically
* merged). Note that there is no large tcache batch-fill currently
* (i.e. only fill 1 at a time); however flush may be batched.
*/
arena_stats_u64_t nfills; /* Partially derived. */
arena_stats_u64_t nflushes; /* Partially derived. */
/* Current number of allocations of this size class. */
size_t curlextents; /* Derived. */
@@ -57,22 +48,6 @@ struct arena_stats_decay_s {
arena_stats_u64_t purged;
};
typedef struct arena_stats_extents_s arena_stats_extents_t;
struct arena_stats_extents_s {
/*
* Stats for a given index in the range [0, SC_NPSIZES] in an extents_t.
* We track both bytes and # of extents: two extents in the same bucket
* may have different sizes if adjacent size classes differ by more than
* a page, so bytes cannot always be derived from # of extents.
*/
atomic_zu_t ndirty;
atomic_zu_t dirty_bytes;
atomic_zu_t nmuzzy;
atomic_zu_t muzzy_bytes;
atomic_zu_t nretained;
atomic_zu_t retained_bytes;
};
/*
* Arena stats. Note that fields marked "derived" are not directly maintained
* within the arena code; rather their values are derived during stats merge
@@ -94,9 +69,6 @@ struct arena_stats_s {
*/
atomic_zu_t retained; /* Derived. */
/* Number of extent_t structs allocated by base, but not being used. */
atomic_zu_t extent_avail;
arena_stats_decay_t decay_dirty;
arena_stats_decay_t decay_muzzy;
@@ -108,27 +80,22 @@ struct arena_stats_s {
atomic_zu_t allocated_large; /* Derived. */
arena_stats_u64_t nmalloc_large; /* Derived. */
arena_stats_u64_t ndalloc_large; /* Derived. */
arena_stats_u64_t nfills_large; /* Derived. */
arena_stats_u64_t nflushes_large; /* Derived. */
arena_stats_u64_t nrequests_large; /* Derived. */
/* VM space had to be leaked (undocumented). Normally 0. */
atomic_zu_t abandoned_vm;
/* Number of bytes cached in tcache associated with this arena. */
atomic_zu_t tcache_bytes; /* Derived. */
mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
/* One element for each large size class. */
arena_stats_large_t lstats[SC_NSIZES - SC_NBINS];
arena_stats_large_t lstats[NSIZES - NBINS];
/* Arena uptime. */
nstime_t uptime;
};
static inline bool
arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) {
arena_stats_init(UNUSED tsdn_t *tsdn, arena_stats_t *arena_stats) {
if (config_debug) {
for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
assert(((char *)arena_stats)[i] == 0);
@@ -180,11 +147,11 @@ arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
#endif
}
static inline void
UNUSED static inline void
arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
arena_stats_u64_t *p, uint64_t x) {
#ifdef JEMALLOC_ATOMIC_U64
uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
assert(r - x <= r);
#else
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
@@ -209,8 +176,7 @@ arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
}
static inline size_t
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
atomic_zu_t *p) {
arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
#ifdef JEMALLOC_ATOMIC_U64
return atomic_load_zu(p, ATOMIC_RELAXED);
#else
@@ -220,8 +186,8 @@ arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
}
static inline void
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
atomic_zu_t *p, size_t x) {
arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
size_t x) {
#ifdef JEMALLOC_ATOMIC_U64
atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
#else
@@ -232,10 +198,10 @@ arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
}
static inline void
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats,
atomic_zu_t *p, size_t x) {
arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
size_t x) {
#ifdef JEMALLOC_ATOMIC_U64
size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
assert(r - x <= r);
#else
malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
@@ -252,12 +218,11 @@ arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
}
static inline void
arena_stats_large_flush_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
szind_t szind, uint64_t nrequests) {
arena_stats_lock(tsdn, arena_stats);
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
arena_stats_add_u64(tsdn, arena_stats, &lstats->nrequests, nrequests);
arena_stats_add_u64(tsdn, arena_stats, &lstats->nflushes, 1);
arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind -
NBINS].nrequests, nrequests);
arena_stats_unlock(tsdn, arena_stats);
}
@@ -268,4 +233,5 @@ arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
arena_stats_unlock(tsdn, arena_stats);
}
#endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
+3 -6
View File
@@ -10,7 +10,7 @@
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/ql.h"
#include "jemalloc/internal/sc.h"
#include "jemalloc/internal/size_classes.h"
#include "jemalloc/internal/smoothstep.h"
#include "jemalloc/internal/ticker.h"
@@ -90,9 +90,6 @@ struct arena_s {
*/
atomic_u_t nthreads[2];
/* Next bin shard for binding new threads. Synchronization: atomic. */
atomic_u_t binshard_next;
/*
* When percpu_arena is enabled, to amortize the cost of reading /
* updating the current CPU id, track the most recent thread accessing
@@ -116,6 +113,7 @@ struct arena_s {
/* Synchronization: internal. */
prof_accum_t prof_accum;
uint64_t prof_accumbytes;
/*
* PRNG state for cache index randomization of large allocation base
@@ -198,7 +196,6 @@ struct arena_s {
* Synchronization: extent_avail_mtx.
*/
extent_tree_t extent_avail;
atomic_zu_t extent_avail_cnt;
malloc_mutex_t extent_avail_mtx;
/*
@@ -206,7 +203,7 @@ struct arena_s {
*
* Synchronization: internal.
*/
bins_t bins[SC_NBINS];
bin_t bins[NBINS];
/*
* Base allocator, from which arena metadata are allocated.
+2 -10
View File
@@ -1,15 +1,13 @@
#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H
#define JEMALLOC_INTERNAL_ARENA_TYPES_H
#include "jemalloc/internal/sc.h"
/* Maximum number of regions in one slab. */
#define LG_SLAB_MAXREGS (LG_PAGE - SC_LG_TINY_MIN)
#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN)
#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS)
/* Default decay times in milliseconds. */
#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000)
#define MUZZY_DECAY_MS_DEFAULT (0)
#define MUZZY_DECAY_MS_DEFAULT ZD(10 * 1000)
/* Number of event ticks between time checks. */
#define DECAY_NTICKS_PER_UPDATE 1000
@@ -42,10 +40,4 @@ typedef enum {
#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base)
#define PERCPU_ARENA_DEFAULT percpu_arena_disabled
/*
* When allocation_size >= oversize_threshold, use the dedicated huge arena
* (unless have explicitly spicified arena index). 0 disables the feature.
*/
#define OVERSIZE_THRESHOLD_DEFAULT (8 << 20)
#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */
+1 -10
View File
@@ -1,19 +1,12 @@
#ifndef JEMALLOC_INTERNAL_ATOMIC_H
#define JEMALLOC_INTERNAL_ATOMIC_H
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
#define ATOMIC_INLINE static inline
#define JEMALLOC_U8_ATOMICS
#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS)
# include "jemalloc/internal/atomic_gcc_atomic.h"
# if !defined(JEMALLOC_GCC_U8_ATOMIC_ATOMICS)
# undef JEMALLOC_U8_ATOMICS
# endif
#elif defined(JEMALLOC_GCC_SYNC_ATOMICS)
# include "jemalloc/internal/atomic_gcc_sync.h"
# if !defined(JEMALLOC_GCC_U8_SYNC_ATOMICS)
# undef JEMALLOC_U8_ATOMICS
# endif
#elif defined(_MSC_VER)
# include "jemalloc/internal/atomic_msvc.h"
#elif defined(JEMALLOC_C11_ATOMICS)
@@ -73,8 +66,6 @@ JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR)
JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR)
JEMALLOC_GENERATE_INT_ATOMICS(uint8_t, u8, 0)
JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2)
#ifdef JEMALLOC_ATOMIC_U64
@@ -67,8 +67,7 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
\
ATOMIC_INLINE bool \
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
UNUSED type *expected, type desired, \
atomic_memory_order_t success_mo, \
type *expected, type desired, atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
return __atomic_compare_exchange(&a->repr, expected, &desired, \
true, atomic_enum_to_builtin(success_mo), \
@@ -77,8 +76,7 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
\
ATOMIC_INLINE bool \
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
UNUSED type *expected, type desired, \
atomic_memory_order_t success_mo, \
type *expected, type desired, atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
return __atomic_compare_exchange(&a->repr, expected, &desired, \
false, \
+7 -11
View File
@@ -27,10 +27,8 @@ atomic_fence(atomic_memory_order_t mo) {
asm volatile("" ::: "memory");
# if defined(__i386__) || defined(__x86_64__)
/* This is implicit on x86. */
# elif defined(__ppc64__)
asm volatile("lwsync");
# elif defined(__ppc__)
asm volatile("sync");
asm volatile("lwsync");
# elif defined(__sparc__) && defined(__arch64__)
if (mo == atomic_memory_order_acquire) {
asm volatile("membar #LoadLoad | #LoadStore");
@@ -115,8 +113,8 @@ atomic_store_##short_type(atomic_##short_type##_t *a, \
} \
\
ATOMIC_INLINE type \
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
atomic_memory_order_t mo) { \
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
atomic_memory_order_t mo) { \
/* \
* Because of FreeBSD, we care about gcc 4.2, which doesn't have\
* an atomic exchange builtin. We fake it with a CAS loop. \
@@ -131,9 +129,8 @@ atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
\
ATOMIC_INLINE bool \
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
type *expected, type desired, \
atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
type *expected, type desired, atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
desired); \
if (prev == *expected) { \
@@ -145,9 +142,8 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
} \
ATOMIC_INLINE bool \
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
type *expected, type desired, \
atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
type *expected, type desired, atomic_memory_order_t success_mo, \
atomic_memory_order_t failure_mo) { \
type prev = __sync_val_compare_and_swap(&a->repr, *expected, \
desired); \
if (prev == *expected) { \
@@ -8,6 +8,7 @@ extern atomic_b_t background_thread_enabled_state;
extern size_t n_background_threads;
extern size_t max_background_threads;
extern background_thread_info_t *background_thread_info;
extern bool can_enable_background_thread;
bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
bool background_threads_enable(tsd_t *tsd);
@@ -15,12 +15,7 @@ background_thread_enabled_set(tsdn_t *tsdn, bool state) {
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
arena_background_thread_info_get(arena_t *arena) {
unsigned arena_ind = arena_ind_get(arena);
return &background_thread_info[arena_ind % max_background_threads];
}
JEMALLOC_ALWAYS_INLINE background_thread_info_t *
background_thread_info_get(size_t ind) {
return &background_thread_info[ind % max_background_threads];
return &background_thread_info[arena_ind % ncpus];
}
JEMALLOC_ALWAYS_INLINE uint64_t
@@ -9,7 +9,6 @@
#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX
#define MAX_BACKGROUND_THREAD_LIMIT MALLOCX_ARENA_LIMIT
#define DEFAULT_NUM_BACKGROUND_THREAD 4
typedef enum {
background_thread_stopped,
+2 -2
View File
@@ -3,7 +3,7 @@
#include "jemalloc/internal/jemalloc_internal_types.h"
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/sc.h"
#include "jemalloc/internal/size_classes.h"
/* Embedded at the beginning of every block of base-managed virtual memory. */
struct base_block_s {
@@ -46,7 +46,7 @@ struct base_s {
base_block_t *blocks;
/* Heap of extents that track unused trailing space within blocks. */
extent_heap_t avail[SC_NSIZES];
extent_heap_t avail[NSIZES];
/* Stats, only maintained if config_stats. */
size_t allocated;
+4 -21
View File
@@ -1,12 +1,10 @@
#ifndef JEMALLOC_INTERNAL_BIN_H
#define JEMALLOC_INTERNAL_BIN_H
#include "jemalloc/internal/bin_stats.h"
#include "jemalloc/internal/bin_types.h"
#include "jemalloc/internal/extent_types.h"
#include "jemalloc/internal/extent_structs.h"
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/sc.h"
#include "jemalloc/internal/bin_stats.h"
/*
* A bin contains a set of extents that are currently being used for slab
@@ -43,9 +41,6 @@ struct bin_info_s {
/* Total number of regions in a slab for this bin's size class. */
uint32_t nregs;
/* Number of sharded bins in each arena for this size class. */
uint32_t n_shards;
/*
* Metadata used to manipulate bitmaps for slabs associated with this
* bin.
@@ -53,7 +48,8 @@ struct bin_info_s {
bitmap_info_t bitmap_info;
};
extern bin_info_t bin_infos[SC_NBINS];
extern const bin_info_t bin_infos[NBINS];
typedef struct bin_s bin_t;
struct bin_s {
@@ -82,18 +78,6 @@ struct bin_s {
bin_stats_t stats;
};
/* A set of sharded bins of the same size class. */
typedef struct bins_s bins_t;
struct bins_s {
/* Sharded bins. Dynamically sized. */
bin_t *bin_shards;
};
void bin_shard_sizes_boot(unsigned bin_shards[SC_NBINS]);
bool bin_update_shard_size(unsigned bin_shards[SC_NBINS], size_t start_size,
size_t end_size, size_t nshards);
void bin_boot(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]);
/* Initializes a bin to empty. Returns true on error. */
bool bin_init(bin_t *bin);
@@ -106,7 +90,7 @@ void bin_postfork_child(tsdn_t *tsdn, bin_t *bin);
static inline void
bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
malloc_mutex_lock(tsdn, &bin->lock);
malloc_mutex_prof_accum(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
malloc_mutex_prof_read(tsdn, &dst_bin_stats->mutex_data, &bin->lock);
dst_bin_stats->nmalloc += bin->stats.nmalloc;
dst_bin_stats->ndalloc += bin->stats.ndalloc;
dst_bin_stats->nrequests += bin->stats.nrequests;
@@ -116,7 +100,6 @@ bin_stats_merge(tsdn_t *tsdn, bin_stats_t *dst_bin_stats, bin_t *bin) {
dst_bin_stats->nslabs += bin->stats.nslabs;
dst_bin_stats->reslabs += bin->stats.reslabs;
dst_bin_stats->curslabs += bin->stats.curslabs;
dst_bin_stats->nonfull_slabs += bin->stats.nonfull_slabs;
malloc_mutex_unlock(tsdn, &bin->lock);
}
Loaded 100 of 588 files, more files were not shown because too many files have changed in this diff. Show more