Compare commits

..
1883 Commits
Author SHA1 Message Date
John Sully 90e23adba5 OS X build break 2020-06-02 00:48:05 -04:00
John Sully 896a68f51b enable yield/pause 2020-06-02 00:16:19 -04:00
John Sully 0f3a54ad79 Fix incorrect memory order (hang on ARM) 2020-06-02 00:15:44 -04:00
John Sully 7877715eaf Wire in mcs lock 2020-06-02 00:01:16 -04:00
John Sully 9cdb8889c2 Use an MCS lock for the AE lock 2020-06-01 23:49:43 -04:00
John Sully 5b885bb164 Undecorated new is OK to use 2020-06-01 23:36:01 -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
antirez 886d287c40 Redis 6.0.4. 2020-05-28 12:18:38 +02:00
antirez 59cd4c9f65 Test: take PSYNC2 test master timeout high during switch.
This will likely avoid false positives due to trailing pings.
2020-05-28 10:56:14 +02:00
antirez 6c1bb7b194 Test: add the tracking unit as default. 2020-05-28 10:22:29 +02:00
Oran Agra 1aee695e52 tests: find_available_port start search from next port
i.e. don't start the search from scratch hitting the used ones again.
this will also reduce the likelihood of collisions (if there are any
left) by increasing the time until we re-use a port we did use in the
past.
2020-05-28 10:09:51 +02:00
Oran Agra a2ae463520 tests: each test client work on a distinct port range
apparently when running tests in parallel (the default of --clients 16),
there's a chance for two tests to use the same port.
specifically, one test might shutdown a master and still have the
replica up, and then another test will re-use the port number of master
for another master, and then that replica will connect to the master of
the other test.

this can cause a master to count too many full syncs and fail a test if
we run the tests with --single integration/psync2 --loop --stop

see Probmem 2 in #7314
2020-05-28 10:09:51 +02:00
Oran Agra 86e562d691 32bit CI needs to build modules correctly 2020-05-28 10:09:51 +02:00
Oran Agra ab2984b1e2 adjust revived meaningful offset tests
these tests create several edge cases that are otherwise uncovered (at
least not consistently) by the test suite, so although they're no longer
testing what they were meant to test, it's still a good idea to keep
them in hope that they'll expose some issue in the future.
2020-05-28 10:09:51 +02:00
Oran Agra 1ff5a222de revive meaningful offset tests 2020-05-28 10:09:51 +02:00
antirez cc549b46a4 Replication: showLatestBacklog() refactored out. 2020-05-28 10:09:51 +02:00
antirez 377dd0515c Drop useless line from replicationCacheMaster(). 2020-05-28 10:09:51 +02:00
antirez 3f8d113f1b Another meaningful offset test removed. 2020-05-28 10:09:51 +02:00
antirez d4541349dc Remove the PSYNC2 meaningful offset test. 2020-05-28 10:09:51 +02:00
antirez 2112a57028 Remove the meaningful offset feature.
After a closer look, the Redis core devleopers all believe that this was
too fragile, caused many bugs that we didn't expect and that were very
hard to track. Better to find an alternative solution that is simpler.
2020-05-28 10:09:51 +02:00
antirez d2eb6e0b47 Set a protocol error if master use the inline protocol.
We want to react a bit more aggressively if we sense that the master is
sending us some corrupted stream. By setting the protocol error we both
ensure that the replica will disconnect, and avoid caching the master so
that a full SYNC will be required. This is protective against
replication bugs.
2020-05-28 10:09:51 +02:00
Oran Agra 9c1df3b769 daily CI test with tls 2020-05-28 10:09:51 +02:00
Oran Agra 115ed1911e avoid using sendfile if tls-replication is enabled
this obviously broke the tests, but went unnoticed so far since tls
wasn't often tested.
2020-05-28 10:09:51 +02:00
antirez 11c748aaca Replication: log backlog creation event. 2020-05-28 10:09:51 +02:00
antirez 8f10137227 Test: PSYNC2 test can now show server logs. 2020-05-28 10:09:51 +02: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
antirez 2e591fc4a4 Clarify what is happening in PR #7320. 2020-05-25 12:08:01 +02:00
zhaozhao.zz cbb51fb8f9 PSYNC2: second_replid_offset should be real meaningful offset
After adjustMeaningfulReplOffset(), all the other related variable
should be updated, including server.second_replid_offset.

Or the old version redis like 5.0 may receive wrong data from
replication stream, cause redis 5.0 can sync with redis 6.0,
but doesn't know meaningful offset.
2020-05-25 12:08:01 +02:00
Oran Agra e0fc88b4d9 add CI for 32bit build 2020-05-25 12:08:01 +02:00
antirez e3f864b5fd Make disconnectSlaves() synchronous in the base case.
Otherwise we run into that:

Backtrace:
src/redis-server 127.0.0.1:21322(logStackTrace+0x45)[0x479035]
src/redis-server 127.0.0.1:21322(sigsegvHandler+0xb9)[0x4797f9]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7fd373c5e390]
src/redis-server 127.0.0.1:21322(_serverAssert+0x6a)[0x47660a]
src/redis-server 127.0.0.1:21322(freeReplicationBacklog+0x42)[0x451282]
src/redis-server 127.0.0.1:21322[0x4552d4]
src/redis-server 127.0.0.1:21322[0x4c5593]
src/redis-server 127.0.0.1:21322(aeProcessEvents+0x2e6)[0x42e786]
src/redis-server 127.0.0.1:21322(aeMain+0x1d)[0x42eb0d]
src/redis-server 127.0.0.1:21322(main+0x4c5)[0x42b145]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fd3738a3830]
src/redis-server 127.0.0.1:21322(_start+0x29)[0x42b409]

Since we disconnect all the replicas and free the replication backlog in
certain replication paths, and the code that will free the replication
backlog expects that no replica is connected.

However we still need to free the replicas asynchronously in certain
cases, as documented in the top comment of disconnectSlaves().
2020-05-25 12:08:01 +02:00
ShooterIT 8af1e513f6 Implements sendfile for redis. 2020-05-25 12:08:01 +02:00
antirez 3c21418cd8 Fix #7306 less aggressively.
Citing from the issue:

btw I suggest we change this fix to something else:
* We revert the fix.
* We add a call that disconnects chained replicas in the place where we trim the replica (that is a master i this case) offset.
This way we can avoid disconnections when there is no trimming of the backlog.

Note that we now want to disconnect replicas asynchronously in
disconnectSlaves(), because it's in general safer now that we can call
it from freeClient(). Otherwise for instance the command:

    CLIENT KILL TYPE master

May crash: clientCommand() starts running the linked of of clients,
looking for clients to kill. However it finds the master, kills it
calling freeClient(), but this in turn calls replicationCacheMaster()
that may also call disconnectSlaves() now. So the linked list iterator
of the clientCommand() will no longer be valid.
2020-05-25 12:08:01 +02: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
Madelyn Olson e201f83cee EAGAIN for tls during diskless load 2020-05-22 12:37:59 +02:00
Qu Chen 58fc456cbd Disconnect chained replicas when the replica performs PSYNC with the master always to avoid replication offset mismatch between master and chained replicas. 2020-05-22 12:37:59 +02:00
hwware 3febc5c29e using moreargs variable 2020-05-22 12:37:59 +02:00
hwware 8d67385593 fix server crash for STRALGO command 2020-05-22 12:37:49 +02:00
ShooterIT 7a35eec540 Replace addDeferredMultiBulkLength with addReplyDeferredLen in comment 2020-05-22 12:37:49 +02:00
Yossi Gottlieb f93e1417b9 TLS: Improve tls-protocols clarity in redis.conf. 2020-05-22 12:37:49 +02:00
ShooterIT d0c9e44545 Fix reply bytes calculation error
Fix #7275.
2020-05-22 12:37:49 +02:00
zhaozhao.zz 1cde6a0603 Tracking: flag CLIENT_TRACKING_BROKEN_REDIR when redir broken 2020-05-22 12:37:49 +02:00
Oran Agra 436be34986 fix a rare active defrag edge case bug leading to stagnation
There's a rare case which leads to stagnation in the defragger, causing
it to keep scanning the keyspace and do nothing (not moving any
allocation), this happens when all the allocator slabs of a certain bin
have the same % utilization, but the slab from which new allocations are
made have a lower utilization.

this commit fixes it by removing the current slab from the overall
average utilization of the bin, and also eliminate any precision loss in
the utilization calculation and move the decision about the defrag to
reside inside jemalloc.

and also add a test that consistently reproduce this issue.
2020-05-22 12:37:49 +02:00
Oran Agra f9d2ffdc5d improve DEBUG MALLCTL to be able to write to write only fields.
also support:
  debug mallctl-str thread.tcache.flush VOID
2020-05-22 12:37:49 +02:00
hujie d7968ee920 fix clear USER_FLAG_ALLCOMMANDS flag in acl
in ACLSetUserCommandBit, when the command bit overflows, no operation
is performed, so no need clear the USER_FLAG_ALLCOMMANDS flag.

in ACLSetUser, when adding subcommand, we don't need to call
ACLGetCommandID ahead since subcommand may be empty.
2020-05-22 12:37:49 +02:00
ShooterIT a902e6b251 Redis Benchmark: generate random test data
The function of generating random data is designed by antirez. See #7196.
2020-05-22 12:37:49 +02:00
hwware 9564ed7c39 Redis-Benchmark: avoid potentical memmory leaking 2020-05-22 12:37:49 +02:00
WuYunlong 2e41827435 Handle keys with hash tag when computing hash slot using tcl cluster client. 2020-05-22 12:37:49 +02:00
WuYunlong eb2c8b2c61 Add a test to prove current tcl cluster client can not handle keys with hash tag. 2020-05-22 12:37:49 +02:00
ShooterIT 928e6976bb Use dictSize to get the size of dict in dict.c 2020-05-22 12:37:49 +02:00
Madelyn Olson cdcf5af5aa Converge hash validation for adding and removing 2020-05-22 12:37:49 +02:00
Benjamin Sergeant e8b09d2203 do not handle --cluster-yes for cluster fix mode 2020-05-22 12:37:49 +02:00
Benjamin Sergeant 57b4fb0d84 fix typo ... 2020-05-22 12:37:49 +02:00
Benjamin Sergeant 29f25e4111 Redis-cli 6.0.1 --cluster-yes doesn't work (fix #7246)
This make it so that all prompts for all redis-cli --cluster commands are automatically answered with a yes.
2020-05-22 12:37:49 +02:00
Oran Agra 00d8b92b89 fix valgrind test failure in replication test
in b4416280c i added more keys to that test to make it run longer
but in valgrind this now means the test times out, give valgrind more
time.
2020-05-22 12:37:49 +02:00
Oran Agra 5e17e6276c add regression test for the race in #7205
with the original version of 6.0.0, this test detects an excessive full
sync.
with the fix in 1a7cd2c0e, this test detects memory corruption,
especially when using libc allocator with or without valgrind.
2020-05-22 12:37:49 +02:00
antirez 96e7c011e2 Improve the PSYNC2 test reliability. 2020-05-22 12:37:49 +02: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
antirez 7803b1148d Redis 6.0.3. 2020-05-16 18:11:58 +02:00
antirez 1eab62f7e5 Remove the client from CLOSE_ASAP list before caching the master.
This was broken in 1a7cd2c: we identified a crash in the CI, what
was happening before the fix should be like that:

1. The client gets in the async free list.
2. However freeClient() gets called again against the same client
   which is a master.
3. The client arrived in freeClient() with the CLOSE_ASAP flag set.
4. The master gets cached, but NOT removed from the CLOSE_ASAP linked
   list.
5. The master client that was cached was immediately removed since it
   was still in the list.
6. Redis accessed a freed cached master.

This is how the crash looked like:

=== REDIS BUG REPORT START: Cut & paste starting from here ===
1092:S 16 May 2020 11:44:09.731 # Redis 999.999.999 crashed by signal: 11
1092:S 16 May 2020 11:44:09.731 # Crashed running the instruction at: 0x447e18
1092:S 16 May 2020 11:44:09.731 # Accessing address: 0xffffffffffffffff
1092:S 16 May 2020 11:44:09.731 # Failed assertion:  (:0)

------ STACK TRACE ------
EIP:
src/redis-server 127.0.0.1:21300(readQueryFromClient+0x48)[0x447e18]

And the 0xffff address access likely comes from accessing an SDS that is
set to NULL (we go -1 offset to read the header).
2020-05-16 18:04:17 +02:00
antirez ae306a3df6 Redis 6.0.2. 2020-05-15 22:29:52 +02:00
Yossi Gottlieb 16ba33c05b TLS: Fix test failures on recent Debian/Ubuntu.
Seems like on some systems choosing specific TLS v1/v1.1 versions no
longer works as expected. Test is reduced for v1.2 now which is still
good enough to test the mechansim, and matters most anyway.
2020-05-15 22:23:24 +02:00
Yossi Gottlieb 77ae66930c TLS: Add crypto locks for older OpenSSL support.
This is really required only for older OpenSSL versions.

Also, at the moment Redis does not use OpenSSL from multiple threads so
this will only be useful if modules end up doing that.
2020-05-15 22:23:24 +02:00
David Carlier 389697988a NetBSD build update.
This platform supports CPU affinity (but not OpenBSD).
2020-05-15 22:23:24 +02:00
Madelyn Olson 2435341d74 Added a refcount on timer events to prevent deletion of recursive timer calls 2020-05-15 22:23:24 +02:00
antirez 80c906bd30 Cache master without checking of deferred close flags.
The context is issue #7205: since the introduction of threaded I/O we close
clients asynchronously by default from readQueryFromClient(). So we
should no longer prevent the caching of the master client, to later
PSYNC incrementally, if such flags are set. However we also don't want
the master client to be cached with such flags (would be closed
immediately after being restored). And yet we want a way to understand
if a master was closed because of a protocol error, and in that case
prevent the caching.
2020-05-15 22:23:24 +02:00
John Sully 4073758874 Remove debugging logs 2020-05-14 22:18:29 -04:00
antirez 74249be4a2 Track events processed while blocked globally.
Related to #7234.
2020-05-14 11:29:43 +02:00
antirez 8bf660af90 Some rework of #7234. 2020-05-14 11:29:43 +02:00
Oran Agra 9da134cd88 fix redis 6.0 not freeing closed connections during loading.
This bug was introduced by a recent change in which readQueryFromClient
is using freeClientAsync, and despite the fact that now
freeClientsInAsyncFreeQueue is in beforeSleep, that's not enough since
it's not called during loading in processEventsWhileBlocked.
furthermore, afterSleep was called in that case but beforeSleep wasn't.

This bug also caused slowness sine the level-triggered mode of epoll
kept signaling these connections as readable causing us to keep doing
connRead again and again for ll of these, which keep accumulating.

now both before and after sleep are called, but not all of their actions
are performed during loading, some are only reserved for the main loop.

fixes issue #7215
2020-05-14 11:29:43 +02:00
antirez f7f219a137 Regression test for #7249. 2020-05-14 11:29:43 +02:00
antirez 693629585b rax.c updated from upstream antirez/rax. 2020-05-14 11:29:43 +02:00
antirez e3b5648df0 Tracking: send eviction messages when evicting entries.
A fix for #7249.
2020-05-14 11:29:43 +02:00
Oran Agra 5c41802d55 fix unstable replication test
this test which has coverage for varoius flows of diskless master was
failing randomly from time to time.

the failure was:
[err]: diskless all replicas drop during rdb pipe in tests/integration/replication.tcl
log message of '*Diskless rdb transfer, last replica dropped, killing fork child*' not found

what seemed to have happened is that the master didn't detect that all
replicas dropped by the time the replication ended, it thought that one
replica is still connected.

now the test takes a few seconds longer but it seems stable.
2020-05-14 11:29:43 +02: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
ShooterIT a23cdbb94b Redis Benchmark: Fix coredump because of double free 2020-05-09 11:14:58 +02:00
antirez 1276058ea8 Cluster: clarify we always resolve the sender. 2020-05-09 11:14:58 +02:00
antirez 002fcde3da Cluster: refactor ping/data delay handling. 2020-05-09 11:14:58 +02:00
antirez 960186a71f Cluster: introduce data_received field.
We want to send pings and pongs at specific intervals, since our packets
also contain information about the configuration of the cluster and are
used for gossip. However since our cluster bus is used in a mixed way
for data (such as Pub/Sub or modules cluster messages) and metadata,
sometimes a very busy channel may delay the reception of pong packets.
So after discussing it in #7216, this commit introduces a new field that
is not exposed in the cluster, is only an internal information about
the last time we received any data from a given node: we use this field
in order to avoid detecting failures, claiming data reception of new
data from the node is a proof of liveness.
2020-05-09 11:14:58 +02:00
antirez cb683a84f7 Don't propagate spurious MULTI on DEBUG LOADAOF. 2020-05-08 10:37:36 +02:00
antirez 3672875b4c stringmatchlen() should not expect null terminated strings. 2020-05-08 10:37:36 +02:00
antirez 84d9766d6a Dump recent backlog on master query generating errors. 2020-05-08 10:37:36 +02:00
Brad Dunbar 24e12641d5 Remove unreachable branch. 2020-05-08 10:37:36 +02:00
Titouan Christophe ec1e106ec5 make struct user anonymous (only typedefed)
This works because this struct is never referenced by its name,
but always by its type.

This prevents a conflict with struct user from <sys/user.h>
when compiling against uclibc.

Signed-off-by: Titouan Christophe <titouan.christophe@railnova.eu>
2020-05-08 10:37:36 +02:00
hwware c7edffbd56 add jemalloc-bg-thread config in redis conf 2020-05-08 10:37:36 +02:00
antirez e48c37316e Test: --dont-clean should do first cleanup. 2020-05-08 10:37:36 +02:00
hwware 8a9c84f4a5 add include guard for lolwut.h 2020-05-08 10:37:36 +02:00
Benjamin Sergeant 1e561cfaaf Add --user argument to redis-benchmark.c (ACL) 2020-05-08 10:37:36 +02:00
antirez d1af82a883 Drop not needed part from #7194. 2020-05-08 10:37:36 +02:00
Muhammad Zahalqa 897a360d06 Fix compiler warnings on function rev(unsigned long) 2020-05-08 10:37:36 +02:00
Guy Benoish 3a441c7d95 XPENDING should not update consumer's seen-time
Same goes for XGROUP DELCONSUMER (But in this case, it doesn't
have any visible effect)
2020-05-08 10:37:35 +02:00
Deliang Yang c57d9146f4 reformat code 2020-05-08 10:37:35 +02:00
antirez ac316d8cc5 Move CRC64 initialization in main(). 2020-05-08 10:37:35 +02:00
Oran Agra 75addb4fe2 optimize memory usage of deferred replies - fixed
When deffered reply is added the previous reply node cannot be used so
all the extra space we allocated in it is wasted. in case someone uses
deffered replies in a loop, each time adding a small reply, each of
these reply nodes (the small string reply) would have consumed a 16k
block.
now when we add anther diferred reply node, we trim the unused portion
of the previous reply block.

see #7123

cherry picked from commit fb732f7a94
with fix to handle a crash with LIBC allocator, which apparently can
return the same pointer despite changing it's size.
i.e. shrinking an allocation of 16k into 56 bytes without changing the
pointer.
2020-05-08 10:37:35 +02:00
Oran Agra 3d3861dd88 add daily github actions with libc malloc and valgrind
* fix memlry leaks with diskless replica short read.
* fix a few timing issues with valgrind runs
* fix issue with valgrind and watchdog schedule signal

about the valgrind WD issue:
the stack trace test in logging.tcl, has issues with valgrind:
==28808== Can't extend stack to 0x1ffeffdb38 during signal delivery for thread 1:
==28808==   too small or bad protection modes

it seems to be some valgrind bug with SA_ONSTACK.
SA_ONSTACK seems unneeded since WD is not recursive (SA_NODEFER was removed),
also, not sure if it's even valid without a call to sigaltstack()
2020-05-08 10:37:35 +02:00
antirez fc7bc32045 Fix CRC64 initialization outside the Redis server itself. 2020-05-08 10:37:35 +02:00
hwware a6e55c096d Client Side Caching: Add Tracking Prefix Number Stats in Server Info 2020-05-08 10:37:35 +02:00
antirez b062fd5235 Fix NetBSD build by fixing redis_set_thread_title() support.
See #7188.
2020-05-08 10:37:35 +02:00
antirez 4efb25d9c0 Rework a bit the documentation for CPU pinning. 2020-05-08 10:37:35 +02:00
zhenwei pi d6436eb7cf Support setcpuaffinity on linux/bsd
Currently, there are several types of threads/child processes of a
redis server. Sometimes we need deeply optimise the performance of
redis, so we would like to isolate threads/processes.

There were some discussion about cpu affinity cases in the issue:
https://github.com/antirez/redis/issues/2863

So implement cpu affinity setting by redis.conf in this patch, then
we can config server_cpulist/bio_cpulist/aof_rewrite_cpulist/
bgsave_cpulist by cpu list.

Examples of cpulist in redis.conf:
server_cpulist 0-7:2      means cpu affinity 0,2,4,6
bio_cpulist 1,3           means cpu affinity 1,3
aof_rewrite_cpulist 8-11  means cpu affinity 8,9,10,11
bgsave_cpulist 1,10-11    means cpu affinity 1,10,11

Test on linux/freebsd, both work fine.

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
2020-05-08 10:37:35 +02:00
John Sully 86f9ed6248 Disable cluster tests
They are unreliable on slow hardware.
2020-05-07 01:49:04 -04:00
antirez 47ff13637e Redis 6.0.1. 2020-05-02 00:10:20 +02:00
antirez db73d0998f Cast printf() argument to the format specifier.
We could use uint64_t specific macros, but after all it's simpler to
just use an obvious equivalent type plus casting: this will be a no op
and is simpler than fixed size types printf macros.
2020-05-02 00:04:19 +02:00
antirez 7c0fe72714 Revert "optimize memory usage of deferred replies"
This reverts commit fb732f7a94.
2020-05-02 00:04:19 +02:00
antirez 8fe25edc75 Save a call to stopThreadedIOIfNeeded() for the base case.
Probably no performance changes, but the code should be trivial to
read as in "No threading? Use the normal function and return".
2020-05-02 00:04:19 +02: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
antirez 17dfd7cabb Redis 6.0.0 GA. 2020-04-30 15:04:41 +02:00
antirez 1f9b82bd56 Update help.h again before Redis 6 GA. 2020-04-30 13:43:58 +02:00
antirez 3fcffe7d04 redis-cli: fix hints with subcommands. 2020-04-30 13:43:58 +02:00
antirez 455d8a05c1 redis-cli command help updated. 2020-04-30 13:02:59 +02:00
zhaozhao.zz 70287bbc94 lazyfree & eviction: record latency generated by lazyfree eviction
1. add eviction-lazyfree monitor
2. put eviction-del & eviction-lazyfree into eviction-cycle
   that means eviction-cycle contains all the latency in
   the eviction cycle including del and lazyfree
3. use getMaxmemoryState to check if we can break in lazyfree-evict
2020-04-30 13:02:59 +02:00
antirez 7be21139aa MIGRATE AUTH2 for ACL support. 2020-04-30 13:02:59 +02:00
antirez e1ee1a49d6 CLIENT KILL USER <username>. 2020-04-30 13:02:59 +02:00
antirez d56f058c08 Fix tracking table max keys option in redis.conf. 2020-04-30 13:02:58 +02:00
antirez 96dd5fc932 redis-cli: safer cluster fix with unreachalbe masters. 2020-04-30 13:02:58 +02:00
antirez 5b59d9c5d7 redis-cli: simplify cluster nodes coverage display. 2020-04-30 13:02:58 +02:00
antirez c163d4addc redis-cli: try to make clusterManagerFixOpenSlot() more readable.
Also improve the message to make clear that there is no *clear* owner,
not that there is no owner at all.
2020-04-30 13:02:58 +02:00
Guy Benoish aab74b7151 XINFO STREAM FULL should have a default COUNT of 10 2020-04-30 13:02:58 +02:00
antirez 606134f9de Comment clearly why we moved some code in #6623. 2020-04-30 13:02:58 +02:00
srzhao ee627bb667 fix pipelined WAIT performance issue.
If client gets blocked again in `processUnblockedClients`, redis will not send
`REPLCONF GETACK *` to slaves untill next eventloop, so the client will be
blocked for 100ms by default(10hz) if no other file event fired.

move server.get_ack_from_slaves sinppet after `processUnblockedClients`, so
that both the first WAIT command that puts client in blocked context and the
following WAIT command processed in processUnblockedClients would trigger
redis-sever to send `REPLCONF GETACK *`, so that the eventloop would get
`REPLCONG ACK <reploffset>` from slaves and unblocked ASAP.
2020-04-30 13:02:58 +02:00
antirez 47b8a7f9b8 Fix create-cluster BIN_PATH. 2020-04-30 13:02:58 +02:00
Guy Benoish 6c0bc608a1 Extend XINFO STREAM output
Introducing XINFO STREAM <key> FULL
2020-04-30 13:02:58 +02:00
hwware 5bfc18950a Fix not used marco in cluster.c 2020-04-30 13:02:58 +02:00
Itamar Haber 56d628f851 Update create-cluster 2020-04-30 13:02:58 +02:00
Itamar Haber cac9d7cf7e Adds BIN_PATH to create-cluster
Allows for setting the binaries path if used outside the upstream repo.

Also documents `call` in usage clause (TODO: port to
`redis-cli --cluster call` or just deprecate it).
2020-04-30 13:02:58 +02: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
Oran Agra b712fba17c hickup, re-fix dictEncObjKeyCompare
come to think of it, in theory (not in practice), getDecodedObject can
return the same original object with refcount incremented, so the
pointer comparision in the previous commit was invalid.
so now instead of checking the encoding, we explicitly check the
refcount.
2020-04-28 11:20:15 +02:00
Oran Agra ea63aea72d fix loading race in psync2 tests 2020-04-28 11:20:15 +02:00
antirez 64e588bfab Rework comment in dictEncObjKeyCompare(). 2020-04-28 11:20:15 +02:00
Oran Agra 0d1e8c93bf allow dictFind using static robj
since the recent addition of OBJ_STATIC_REFCOUNT and the assertion in
incrRefCount it is now impossible to use dictFind using a static robj,
because dictEncObjKeyCompare will call getDecodedObject which tries to
increment the refcount just in order to decrement it later.
2020-04-28 11:20:15 +02:00
Madelyn Olson a1bed447b3 Added crcspeed library 2020-04-28 11:20:15 +02:00
Madelyn Olson a75fa3aad1 Made crc64 test consistent 2020-04-28 11:20:15 +02:00
Madelyn Olson 52c75e9db1 Implemented CRC64 based on slice by 4 2020-04-28 11:20:15 +02:00
Oran Agra 8110ba8880 optimize memory usage of deferred replies
When deffered reply is added the previous reply node cannot be used so
all the extra space we allocated in it is wasted. in case someone uses
deffered replies in a loop, each time adding a small reply, each of
these reply nodes (the small string reply) would have consumed a 16k
block.
now when we add anther diferred reply node, we trim the unused portion
of the previous reply block.

see #7123
2020-04-27 16:46:14 +02:00
Oran Agra e4d2bb62b2 Keep track of meaningful replication offset in replicas too
Now both master and replicas keep track of the last replication offset
that contains meaningful data (ignoring the tailing pings), and both
trim that tail from the replication backlog, and the offset with which
they try to use for psync.

the implication is that if someone missed some pings, or even have
excessive pings that the promoted replica has, it'll still be able to
psync (avoid full sync).

the downside (which was already committed) is that replicas running old
code may fail to psync, since the promoted replica trims pings form it's
backlog.

This commit adds a test that reproduces several cases of promotions and
demotions with stale and non-stale pings

Background:
The mearningful offset on the master was added recently to solve a problem were
the master is left all alone, injecting PINGs into it's backlog when no one is
listening and then gets demoted and tries to replicate from a replica that didn't
have any of the PINGs (or at least not the last ones).

however, consider this case:
master A has two replicas (B and C) replicating directly from it.
there's no traffic at all, and also no network issues, just many pings in the
tail of the backlog. now B gets promoted, A becomes a replica of B, and C
remains a replica of A. when A gets demoted, it trims the pings from its
backlog, and successfully replicate from B. however, C is still aware of
these PINGs, when it'll disconnect and re-connect to A, it'll ask for something
that's not in the backlog anymore (since A trimmed the tail of it's backlog),
and be forced to do a full sync (something it didn't have to do before the
meaningful offset fix).

Besides that, the psync2 test was always failing randomly here and there, it
turns out the reason were PINGs. Investigating it shows the following scenario:

cycle 1: redis #1 is master, and all the rest are direct replicas of #1
cycle 2: redis #2 is promoted to master, #1 is a replica of #2 and #3 is replica of #1
now we see that when #1 is demoted it prints:
17339:S 21 Apr 2020 11:16:38.523 * Using the meaningful offset 3929963 instead of 3929977 to exclude the final PINGs (14 bytes difference)
17339:S 21 Apr 2020 11:16:39.391 * Trying a partial resynchronization (request e2b3f8817735fdfe5fa4626766daa938b61419e5:3929964).
17339:S 21 Apr 2020 11:16:39.392 * Successful partial resynchronization with master.
and when #3 connects to the demoted #2, #2 says:
17339:S 21 Apr 2020 11:16:40.084 * Partial resynchronization not accepted: Requested offset for secondary ID was 3929978, but I can reply up to 3929964

so the issue here is that the meaningful offset feature saved the day for the
demoted master (since it needs to sync from a replica that didn't get the last
ping), but it didn't help one of the other replicas which did get the last ping.
2020-04-27 15:52:49 +02:00
antirez fea9788cc4 Fix STRALGO command flags. 2020-04-27 15:52:49 +02:00
Dave-in-lafayette 2144047e14 fix for unintended crash during panic response
If redis crashes early, before lua is set up (like, if File Descriptor 0 is closed before exec), it will crash again trying to print memory statistics.
2020-04-27 15:52:49 +02:00
Guy Benoish 43329c9b64 Add the stream tag to XSETID tests 2020-04-27 15:52:49 +02:00
Dave-in-lafayette 1e17d3de79 fix for crash during panic before all threads are up
If there's a panic before all threads have been started (say, if file descriptor 0 is closed at exec), the panic response will crash here again.
2020-04-27 15:52:49 +02: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
antirez 3722f89f49 LCS -> STRALGO LCS.
STRALGO should be a container for mostly read-only string
algorithms in Redis. The algorithms should have two main
characteristics:

1. They should be non trivial to compute, and often not part of
programming language standard libraries.
2. They should be fast enough that it is a good idea to have optimized C
implementations.

Next thing I would love to see? A small strings compression algorithm.
2020-04-24 16:49:27 +02:00
antirez 373ae6061a Also use propagate() in streamPropagateGroupID(). 2020-04-24 10:15:04 +02:00
yanhui13 f03f1fad67 add tcl test for cluster slots 2020-04-24 10:15:04 +02:00
yanhui13 374ffdf1c1 optimize the output of cluster slots 2020-04-24 10:15:04 +02:00
antirez 4db38d2efd Minor aesthetic changes to #7135. 2020-04-24 10:15:04 +02:00
Valentino Geron f0a261448c XREADGROUP with NOACK should propagate only one XGROUP SETID command 2020-04-24 10:15:04 +02:00
antirez fbdef6a9bd ACL: re-enable command execution of disabled users.
After all I changed idea again: enabled/disabled should have a more
clear meaning, and it only means: you can't authenticate with such user
with new connections, however old connections continue to work as
expected.
2020-04-24 10:15:04 +02:00
antirez 05a41da75b getRandomBytes(): use HMAC-SHA256.
Now that we have an interface to use this API directly, via ACL GENPASS,
we are no longer sure what people could do with it. So why don't make it
a strong primitive exported by Redis in order to create unique IDs and
so forth?

The implementation was tested against the test vectors that can
be found in RFC4231.
2020-04-24 10:14:48 +02:00
antirez 345c3768de ACL GENPASS: take number of bits as argument. 2020-04-24 10:14:48 +02:00
antirez 639c8a1d91 ACL GENPASS: emit 256 bits instead of 128. 2020-04-24 10:14:48 +02:00
antirez 321acea038 ACL: deny commands execution of disabled users. 2020-04-24 10:14:48 +02:00
Theo Buehler b0920e6e86 TLS: Fix build with SSL_OP_NO_CLIENT_RENEGOTIATION
There is no ssl in this scope, so the build breaks.
All the other options are set directly on the ctx.
2020-04-24 10:14:48 +02:00
Yossi Gottlieb 149b658b56 TLS: Fix build on older verisons of OpenSSL. 2020-04-24 10:14:48 +02:00
antirez 06917e581c Tracking: test expired keys notifications. 2020-04-24 10:14:48 +02:00
antirez e434b2ce4f Tracking: NOLOOP tests. 2020-04-24 10:14:48 +02:00
antirez f3a1728873 Tracking: signal key as modified when evicting. 2020-04-24 10:14:48 +02:00
antirez e63bb7ec8c Tracking: NOLOOP further implementation and fixes. 2020-04-24 10:14:48 +02:00
antirez 6791ff0525 Tracking: NOLOOP internals implementation. 2020-04-24 10:14:48 +02:00
antirez 725b8cc680 Implement redis_set_thread_title for MacOS.
Strange enough, pthread_setname_np() produces a warning for not defined
function even if pthread is included. Moreover the MacOS documentation
claims the return value for the function is void, but actually is int.

Related to #7089.
2020-04-24 10:14:48 +02:00
zhenwei pi 3575b8706d Threaded IO: set thread name for redis-server
Set thread name for each thread of redis-server, this helps us to
monitor the utilization and optimise the performance.

And suggested-by Salvatore, implement this feature for multi
platforms. Currently support linux and bsd, ignore other OS.

An exmaple on Linux:
 # top -d 5 -p `pidof redis-server ` -H

    PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
3682671 root      20   0  227744   8248   3836 R 99.2  0.0   0:19.53 redis-server
3682677 root      20   0  227744   8248   3836 S 26.4  0.0   0:04.15 io_thd_3
3682675 root      20   0  227744   8248   3836 S 23.6  0.0   0:03.98 io_thd_1
3682676 root      20   0  227744   8248   3836 S 23.6  0.0   0:03.97 io_thd_2
3682672 root      20   0  227744   8248   3836 S  0.2  0.0   0:00.02 bio_close_file
3682673 root      20   0  227744   8248   3836 S  0.2  0.0   0:00.02 bio_aof_fsync
3682674 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 bio_lazy_free
3682678 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd
3682682 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd
3682683 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd
3682684 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd
3682685 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd
3682687 root      20   0  227744   8248   3836 S  0.0  0.0   0:00.00 jemalloc_bg_thd

Another exmaple on FreeBSD-12.1:
  PID USERNAME    PRI NICE   SIZE    RES STATE    C   TIME    WCPU COMMAND
 5212 root        100    0    48M  7280K CPU2     2   0:26  99.52% redis-server{redis-server}
 5212 root         38    0    48M  7280K umtxn    4   0:06  26.94% redis-server{io_thd_3}
 5212 root         36    0    48M  7280K umtxn    6   0:06  26.84% redis-server{io_thd_1}
 5212 root         39    0    48M  7280K umtxn    1   0:06  25.30% redis-server{io_thd_2}
 5212 root         20    0    48M  7280K uwait    3   0:00   0.00% redis-server{redis-server}
 5212 root         21    0    48M  7280K uwait    2   0:00   0.00% redis-server{bio_close_file}
 5212 root         21    0    48M  7280K uwait    3   0:00   0.00% redis-server{bio_aof_fsync}
 5212 root         21    0    48M  7280K uwait    0   0:00   0.00% redis-server{bio_lazy_free}

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
2020-04-24 10:14:48 +02:00
antirez a76c67578c Sentinel: small refactoring of sentinelCollectTerminatedScripts().
Related to #7113.
2020-04-24 10:14:48 +02:00
omg-by 3a27064c41 fix(sentinel): sentinel.running_scripts will always increase more times and not reset
when trigger a always fail scripts, sentinel.running_scripts will increase ten times, however it
only decrease one times onretry the maximum. and it will't reset, when it become
SENTINEL_SCRIPT_MAX_RUNNING, sentinel don't trigger scripts.
2020-04-24 10:14:48 +02: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
antirez 5c4c73e2c2 A few comments and name changes for #7103. 2020-04-17 13:02:40 +02:00
Oran Agra 6148f94939 testsuite run the defrag latency test solo
this test is time sensitive and it sometimes fail to pass below the
latency threshold, even on strong machines.

this test was the reson we're running just 2 parallel tests in the
github actions CI, revering this.
2020-04-17 13:02:40 +02:00
Jamie Scott 51d3012d48 Adding acllog-max-len to Redis.conf
While playing with ACLs I noticed that acllog-max-len wasn't in the redis.conf, but was a supported config. 

This PR documents and adds the directive to the redis.conf file.
2020-04-17 13:02:40 +02:00
antirez c39f16c422 Fix XCLAIM propagation in AOF/replicas for blocking XREADGROUP.
See issue #7105.
2020-04-17 12:40:54 +02: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
antirez 7cf0a77d59 Redis 6.0-RC4. 2020-04-16 16:18:02 +02:00
antirez 9f594e2432 Update SDS to latest version. 2020-04-16 16:09:06 +02:00
antirez 48781dd95c RESP3: fix HELLO map len in Sentinel mode.
See #6160.
2020-04-16 11:22:18 +02: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
antirez 371ab0cff8 Don't allow empty spaces in ACL usernames.
Fixes issue #6418.
2020-04-15 18:40:11 +02:00
antirez b86140ac5f Don't allow empty spaces in ACL key patterns.
Fixes issue #6418.
2020-04-15 18:40:11 +02:00
antirez bec68bff29 Use the special static refcount for stack objects. 2020-04-15 16:03:16 +02:00
antirez 414debfd04 Speedup: unblock clients on keys in O(1).
See #7071.
2020-04-15 16:03:16 +02:00
liumiuyong a7ee3c3e77 FIX: truncate max/min longitude,latitude related geo_point (ex: {180, 85.05112878} ) 2020-04-15 16:03:16 +02:00
antirez 0f239e51b0 RDB: refactor some RDB loading code into dbAddRDBLoad(). 2020-04-15 16:03:16 +02:00
Guy Benoish e5b9eb8171 Typo in getTimeoutFromObjectOrReply's error reply 2020-04-15 16:03:16 +02:00
antirez f855db61b0 incrRefCount(): abort on statically allocated object. 2020-04-15 16:03:16 +02:00
antirez 0f31bb5c1a Fix HELLO reply in Sentinel mode, see #6160. 2020-04-15 16:03:16 +02:00
antirez 23094ba015 More powerful DEBUG RELOAD.
Related to #3243.
2020-04-15 16:03:16 +02:00
hwware b92d9a895f fix spelling in acl.c 2020-04-15 16:03:16 +02:00
antirez 8161a7a3ef RDB: clarify a condition in rdbLoadRio(). 2020-04-15 16:03:16 +02:00
antirez 8f896e57ae Fix zsetAdd() top comment spelling. 2020-04-15 16:03:16 +02:00
antirez 61b153073f RDB: load files faster avoiding useless free+realloc.
Reloading of the RDB generated by

    DEBUG POPULATE 5000000
    SAVE

is now 25% faster.

This commit also prepares the ability to have more flexibility when
loading stuff from the RDB, since we no longer use dbAdd() but can
control exactly how things are added in the database.
2020-04-15 16:03:16 +02:00
hayleeliu 8f5157058b fix spelling mistake in bitops.c 2020-04-15 16:03:16 +02:00
antirez ddeda9ceb7 Fix function names in zslDeleteNode() top comment. 2020-04-15 16:03:16 +02:00
antirez bde1f0a8e2 RESP3: change streams items from maps to arrays.
Streams items are similar to dictionaries, however they preserve both
the order, and allow for duplicated field names. So a map is not a
semantically sounding way to deal with this.

https://twitter.com/antirez/status/1248261087553880069
2020-04-15 16:03:16 +02: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
antirez cbcd07777d Fix ACL HELP table missing comma. 2020-04-08 10:56:31 +02:00
mymilkbottles 2437455f27 Judge the log level in advance 2020-04-07 16:53:13 +02:00
antirez 35c64b898c Speedup INFO by counting client memory incrementally.
Related to #5145.

Design note: clients may change type when they turn into replicas or are
moved into the Pub/Sub category and so forth. Moreover the recomputation
of the bytes used is problematic for obvious reasons: it changes
continuously, so as a conservative way to avoid accumulating errors,
each client remembers the contribution it gave to the sum, and removes
it when it is freed or before updating it with the new memory usage.
2020-04-07 16:53:13 +02:00
qetu3790 c3ac717487 fix comments about RESIZE DB opcode in rdb.c
fix comments about RESIZE DB opcode in rdb.c
2020-04-07 16:53:13 +02:00
antirez c8dbcff9db Clarify redis.conf comment about lazyfree-lazy-user-del. 2020-04-07 16:53:13 +02:00
zhaozhao.zz abd5156f25 lazyfree: add a new configuration lazyfree-lazy-user-del
Delete keys in async way when executing DEL command, if
lazyfree-lazy-user-del is yes.
2020-04-07 16:53:13 +02:00
antirez 5719b3054a LCS: more tests. 2020-04-07 16:52:57 +02:00
antirez c89e1f2937 LCS: allow KEYS / STRINGS to be anywhere.
Initially they needed to be at the end so that we could extend to N
strings in the future, but after further consideration I no longer
believe it's worth it.
2020-04-07 16:52:57 +02:00
antirez 0b16f8d444 LCS tests. 2020-04-07 16:52:57 +02:00
antirez 9254a805d7 LCS: get rid of STOREIDX option. Fix get keys helper. 2020-04-07 16:52:57 +02:00
antirez a4c4907035 LCS: fix stale comment. 2020-04-07 16:52:57 +02:00
antirez cb92c23de0 LCS: output LCS len as well in IDX mode. 2020-04-07 16:52:57 +02:00
antirez 56a52e804c LCS: MINMATCHLEN and WITHMATCHLEN options. 2020-04-07 16:52:57 +02:00
antirez ebb09a5c3b LCS: 7x speedup by accessing the array with better locality. 2020-04-07 16:52:57 +02:00
antirez a9f8a8cba0 LCS: implement KEYS option. 2020-04-07 16:52:57 +02:00
antirez 4aa24e62a4 LCS: other fixes to range emission. 2020-04-07 16:52:57 +02:00
antirez 2b67b6b87e LCS: fix emission of last range starting at index 0. 2020-04-07 16:52:57 +02:00
antirez 420aac7274 LCS: implement range indexes option. 2020-04-07 16:52:57 +02:00
antirez a518a9a766 LCS: initial functionality implemented. 2020-04-07 16:52:57 +02:00
srzhao 026cc11b05 Check OOM at script start to get stable lua OOM state.
Checking OOM by `getMaxMemoryState` inside script might get different result
with `freeMemoryIfNeededAndSafe` at script start, because lua stack and
arguments also consume memory.

This leads to memory `borderline` when memory grows near server.maxmemory:

- `freeMemoryIfNeededAndSafe` at script start detects no OOM, no memory freed
- `getMaxMemoryState` inside script detects OOM, script aborted

We solve this 'borderline' issue by saving OOM state at script start to get
stable lua OOM state.

related to issue #6565 and #5250.
2020-04-07 16:52:28 +02:00
Oran Agra 02b594f6ad diffrent fix for runtest --host --port 2020-04-07 16:52:28 +02:00
Guy Benoish f695d18306 Try to fix time-sensitive tests in blockonkey.tcl
There is an inherent race between the deferring client and the
"main" client of the test: While the deferring client issues a blocking
command, we can't know for sure that by the time the "main" client
tries to issue another command (Usually one that unblocks the deferring
client) the deferring client is even blocked...
For lack of a better choice this commit uses TCL's 'after' in order
to give some time for the deferring client to issues its blocking
command before the "main" client does its thing.
This problem probably exists in many other tests but this commit
tries to fix blockonkeys.tcl
2020-04-07 16:52:28 +02:00
Guy Benoish 0e42cfc365 Use __attribute__ only if __GNUC__ is defined 2020-04-07 16:52:28 +02:00
Guy Benoish 024c380b9d Fix no-negative-zero test 2020-04-07 16:52:04 +02:00
Guy Benoish eba28e2cea DEBUG OBJECT should pass keyname to module when loading 2020-04-07 16:52:04 +02:00
Guy Benoish c35a53169f streamReplyWithRange: Redundant XSETIDs to replica
propagate_last_id is declared outside of the loop but used
only from within the loop. Once it's '1' it will never go
back to '0' and will replicate XSETID even for IDs that
don't actually change the last_id.
While not a serious bug (XSETID always used group->last_id
so there's no risk), it does causes redundant traffic
between master and its replicas
2020-04-07 16:52:04 +02:00
Guy Benoish 91ed9b3c47 Modules: Perform printf-like format checks in variadic API 2020-04-07 16:52:04 +02:00
Oran Agra a38ff404bd modules don't signalModifiedKey in setKey() since that's done (optionally) in RM_CloseKey 2020-04-07 16:52:04 +02:00
David Carlier 15c9e79a7d debug, dump registers on arm too. 2020-04-07 16:52:04 +02:00
antirez 6fe66e0969 Simplify comment in moduleTryServeClientBlockedOnKey(). 2020-04-07 16:52:04 +02:00
Valentino Geron 3e0d209625 XREAD and XREADGROUP should not be allowed from scripts when BLOCK option is being used 2020-04-07 16:52:04 +02:00
Oran Agra 814874d68b change CI to build and run the module api tests 2020-04-07 16:52:04 +02:00
hwware cd2b5df971 fix spelling in cluster.c 2020-04-07 16:52:04 +02:00
Guy Benoish 240094c9b0 Stale replica should allow MULTI/EXEC
Example: Client uses a pipe to send the following to a
stale replica:

MULTI
.. do something ...
DISCARD

The replica will reply the MUTLI with -MASTERDOWN and
execute the rest of the commands... A client using a
pipe might not be aware that MULTI failed until it's
too late.

I can't think of a reason why MULTI/EXEC/DISCARD should
not be executed on stale replicas...

Also, enable MULTI/EXEC/DISCARD during loading
2020-04-07 16:52:04 +02:00
Oran Agra 061616c1b1 fix possible warning on incomplete struct init 2020-04-07 16:52:04 +02:00
Valentino Geron 8cdc153f58 XACK should be executed in a "all or nothing" fashion.
First, we must parse the IDs, so that we abort ASAP.
The return value of this command cannot be an error if
the client successfully acknowledged some messages,
so it should be executed in a "all or nothing" fashion.
2020-04-07 16:52:04 +02:00
Xudong Zhang 209f3a1eba fix integer overflow 2020-04-07 16:52:04 +02:00
Guy Benoish 7764996bec Make sure Redis does not reply with negative zero 2020-04-07 16:52:04 +02:00
hwware b35407fa7c add check for not switching between optin optout mode directly 2020-04-07 16:52:04 +02:00
hwware 4395889c9e add check for not providing both optin optout flag 2020-04-07 16:52:04 +02:00
Guy Benoish 1907e0f18f PERSIST should notify a keyspace event 2020-04-07 16:52:04 +02:00
Guy Benoish 193fc241ca Fix memory corruption in moduleHandleBlockedClients
By using a "circular BRPOPLPUSH"-like scenario it was
possible the get the same client on db->blocking_keys
twice (See comment in moduleTryServeClientBlockedOnKey)

The fix was actually already implememnted in
moduleTryServeClientBlockedOnKey but it had a bug:
the funxction should return 0 or 1 (not OK or ERR)

Other changes:
1. Added two commands to blockonkeys.c test module (To
   reproduce the case described above)
2. Simplify blockonkeys.c in order to make testing easier
3. cast raxSize() to avoid warning with format spec
2020-04-07 16:52:03 +02: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
antirez 957e917a84 Redis 6.0-RC3. 2020-03-31 17:56:04 +02:00
antirez ef1b1f01a8 cast raxSize() to avoid warning with format spec. 2020-03-31 17:41:23 +02:00
antirez 9f347fabba Minor changes to #7037. 2020-03-31 17:12:19 +02:00
Guy Benoish a509400d58 Modules: Test MULTI/EXEC replication of RM_Replicate
Makse sure call() doesn't wrap replicated commands with
a redundant MULTI/EXEC

Other, unrelated changes:
1. Formatting compiler warning in INFO CLIENTS
2. Use CLIENT_ID_AOF instead of UINT64_MAX
2020-03-31 17:12:19 +02:00
antirez c3b268a0bc timeout.c created: move client timeouts code there. 2020-03-31 16:57:20 +02:00
Oran Agra 0f7dfc378c AOFRW on an empty stream created with MKSTREAM loads badkly
the AOF will be loaded successfully, but the stream will be missing,
i.e inconsistencies with the original db.

this was because XADD with id of 0-0 would error.

add a test to reproduce.
2020-03-31 16:57:20 +02:00
Guy Benoish 805c8c94a9 RENAME can unblock XREADGROUP
Other changes:
Support stream in serverLogObjectDebugInfo
2020-03-31 16:57:20 +02:00
antirez 97b80b57e9 Fix the propagate Tcl test after module changes. 2020-03-31 16:57:20 +02:00
antirez 4f6b6b8008 Modify the propagate unit test to show more cases. 2020-03-31 16:57:20 +02:00
antirez 616b1cb7ac Fix module commands propagation double MULTI bug.
37a10cef introduced automatic wrapping of MULTI/EXEC for the
alsoPropagate API. However this collides with the built-in mechanism
already present in module.c. To avoid complex changes near Redis 6 GA
this commit introduces the ability to exclude call() MUTLI/EXEC wrapping
for also propagate in order to continue to use the old code paths in
module.c.
2020-03-31 16:57:20 +02:00
antirez 08fdef4bf6 Fix RM_Call() stale comment due to cut&paste. 2020-03-31 16:57:20 +02:00
OMG-By 26b79ca18c fix: dict.c->dictResize()->minimal type 2020-03-31 16:57:20 +02:00
zhaozhao.zz fa41863752 PSYNC2: reset backlog_idx and master_repl_offset correctly 2020-03-31 16:57:20 +02:00
antirez bbbc80acae Precise timeouts: reference client pointer directly. 2020-03-31 16:57:20 +02:00
antirez 67643ead69 Precise timeouts: cleaup the table on unblock.
Now that this mechanism is the sole one used for blocked clients
timeouts, it is more wise to cleanup the table when the client unblocks
for any reason. We use a flag: CLIENT_IN_TO_TABLE, in order to avoid a
radix tree lookup when the client was already removed from the table
because we processed it by scanning the radix tree.
2020-03-31 16:56:46 +02:00
antirez ad94066ec8 Precise timeouts: fix comments after functional change. 2020-03-31 16:56:46 +02:00
antirez a443ec2e9a Precise timeouts: use only radix tree for timeouts. 2020-03-31 16:56:46 +02:00
antirez 6862fd70da Precise timeouts: fast exit for clientsHandleShortTimeout(). 2020-03-31 16:56:46 +02:00
antirez 30f1df8c48 Precise timeouts: fix bugs in initial implementation. 2020-03-31 16:56:46 +02:00
antirez 7add0f2490 Precise timeouts: working initial implementation. 2020-03-31 16:56:46 +02:00
antirez 9d6d177994 Precise timeouts: refactor unblocking on timeout. 2020-03-31 16:56:46 +02:00
antirez 316a8f1545 PSYNC2: fix backlog_idx when adjusting for meaningful offset
See #7002.
2020-03-31 16:56:46 +02:00
伯成 11db53f875 Boost up performance for redis PUB-SUB patterns matching
If lots of clients PSUBSCRIBE to same patterns, multiple pattens matching will take place. This commit change it into just one single pattern matching by using a `dict *` to store the unique pattern and which clients subscribe to it.
2020-03-31 12:47:14 +02: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
antirez e257f121e1 PSYNC2: meaningful offset test. 2020-03-25 15:55:24 +01:00
antirez 5f72f69688 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-03-25 15:55:24 +01:00
antirez 8caa271476 Explain why we allow transactions in -BUSY state.
Related to #7022.
2020-03-25 15:55:24 +01:00
Oran Agra e43cd8316f MULTI/EXEC during LUA script timeout are messed up
Redis refusing to run MULTI or EXEC during script timeout may cause partial
transactions to run.

1) if the client sends MULTI+commands+EXEC in pipeline without waiting for
response, but these arrive to the shards partially while there's a busy script,
and partially after it eventually finishes: we'll end up running only part of
the transaction (since multi was ignored, and exec would fail).

2) similar to the above if EXEC arrives during busy script, it'll be ignored and
the client state remains in a transaction.

the 3rd test which i added for a case where MULTI and EXEC are ok, and
only the body arrives during busy script was already handled correctly
since processCommand calls flagTransaction
2020-03-25 15:55:24 +01:00
antirez 34b8983220 Improve comments of replicationCacheMasterUsingMyself(). 2020-03-25 15:55:24 +01:00
antirez 70a98a43ea Fix BITFIELD_RO test. 2020-03-25 15:55:24 +01:00
antirez 8783304a2d Abort transactions after -READONLY error. Fix #7014. 2020-03-25 15:55:24 +01:00
antirez ec9cf002d5 Minor changes to BITFIELD_RO PR #6951. 2020-03-25 15:55:24 +01:00
bodong.ybd b3e4abf06e Added BITFIELD_RO variants for read-only operations. 2020-03-25 15:55:24 +01:00
antirez 50f8f9504b Modules: updated function doc after #7003. 2020-03-25 15:55:24 +01:00
Guy Benoish f2f3dc5e73 Allow RM_GetContextFlags to work with ctx==NULL 2020-03-25 15:55:24 +01:00
hwware eb80887936 fix potentical memory leak in redis-cli 2020-03-25 15:55:24 +01:00
Yossi Gottlieb cdcab0e820 Fix crashes related to failed/rejected accepts. 2020-03-25 15:55:24 +01:00
Yossi Gottlieb 50dcd9f96d Cluster: fix misleading accept errors. 2020-03-25 15:55:24 +01:00
Yossi Gottlieb 87dbd8f54c Conns: Fix connClose() / connAccept() behavior.
We assume accept handlers may choose to reject a connection and close
it, but connAccept() callers can't distinguish between this state and
other error states requiring connClose().

This makes it safe (and mandatory!) to always call connClose() if
connAccept() fails, and safe for accept handlers to close connections
(which will defer).
2020-03-25 15:55:24 +01:00
hwware 81e8686cc7 remove redundant Semicolon 2020-03-25 15:55:24 +01:00
hwware c7524a7e44 clean CLIENT_TRACKING_CACHING flag when disabled caching 2020-03-25 15:55:24 +01:00
hwware 2dd1ca6af0 add missing commands in cluster help 2020-03-25 15:55:24 +01:00
artix 95324b8190 Support Redis Cluster Proxy PROXY INFO command 2020-03-25 15:55:24 +01:00
zhaozhao.zz 7c07841632 Threaded IO: bugfix client kill may crash redis 2020-03-25 15:54:34 +01:00
zhaozhao.zz b3e0305448 Threaded IO: bugfix #6988 process events while blocked 2020-03-25 15:54:34 +01:00
antirez e628f94436 Restore newline at the end of redis-cli.c 2020-03-25 15:54:34 +01:00
bodong.ybd 76d57161d9 Fix bug of tcl test using external server 2020-03-25 15:54:34 +01:00
박승현 04c53fa145 Update redis.conf 2020-03-25 15:54:34 +01:00
zhaozhao.zz 9cc7038e54 Threaded IO: handle pending reads clients ASAP after event loop 2020-03-25 15:54:34 +01:00
chendianqiang 5d4c4df3ef use correct list for moduleUnregisterUsedAPI 2020-03-25 15:54:34 +01:00
fengpf 0e5820d893 fix comments in latency.c 2020-03-25 15:54:34 +01:00
WuYunlong 0578157d56 Fix master replica inconsistency for upgrading scenario.
Before this commit, when upgrading a replica, expired keys will not
be loaded, thus causing replica having less keys in db. To this point,
master and replica's keys is logically consistent. However, before
the keys in master and replica are physically consistent, that is,
they have the same dbsize, if master got a problem and the replica
got promoted and becomes new master of that partition, and master
updates a key which does not exist on master, but physically exists
on the old master(new replica), the old master would refuse to update
the key, thus causing master and replica data inconsistent.

How could this happen?
That's all because of the wrong judgement of roles while starting up
the server. We can not use server.masterhost to judge if the server
is master or replica, since it fails in cluster mode.

When we start the server, we load rdb and do want to load expired keys,
and do not want to have the ability to active expire keys, if it is
a replica.
2020-03-25 15:54:34 +01:00
antirez da8c7c49bf Example sentinel conf: document requirepass. 2020-03-25 15:54:34 +01:00
guodongxiaren da14982d1e string literal should be const char* 2020-03-25 15:54:34 +01:00
WuYunlong 299f1d0258 Add 14-consistency-check.tcl to prove there is a data consistency issue. 2020-03-25 15:54:34 +01:00
antirez bdb338cf77 Aesthetic changes in PR #6989. 2020-03-25 15:54:34 +01:00
Itamar Haber dc8885a1ca Adds keyspace notifications to migrate and restore 2020-03-25 15:54:34 +01:00
antirez 61b98f32a2 Regression test for #7011. 2020-03-25 15:54:34 +01:00
bodong.ybd bfb18e5519 Remove duplicate obj files in Makefile 2020-03-25 15:54:34 +01:00
antirez 34ea2f4e1a ACL: default user off should not allow automatic authentication.
This fixes issue #7011.
2020-03-25 15:54:34 +01:00
antirez cbbf9b3931 Sentinel: document auth-user directive. 2020-03-25 15:54:34 +01:00
antirez 9c2e42ddfc ACL: Make Redis 6 more backward compatible with requirepass.
Note that this as a side effect fixes Sentinel "requirepass" mode.
2020-03-25 15:54:34 +01:00
antirez d387f67dcb Sentinel: implement auth-user directive for ACLs. 2020-03-25 15:54:34 +01: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
antirez 916dd79f19 Update linenoise. 2020-03-12 15:53:47 +01:00
lifubang c0c67c9be3 add askpass mode
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-03-12 15:53:47 +01:00
lifubang e1c29434b2 update linenoise to https://github.com/antirez/linenoise/tree/fc9667a81d43911a6690fb1e68c16e6e3bb8df05
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-03-12 15:53:47 +01:00
Jamie Scott e5a063bcb4 Remove default guidance in Redis.conf
Removing the default guidance in Redis.conf since this is not an available value.
2020-03-12 15:53:47 +01:00
Jamie Scott d28cbaf770 Update Redis.conf to improve TLS usability
When using TLS with a Redis.conf file the line for TLS reading tls-cert-file redis.crt tls-key-file redis.key is interpreted as one complete directive. I am separating this on two separate lines to improve usability so users do not get the below error.

ubuntu@ip-172-31-29-250:~/redis-6.0-rc1$ ./src/redis-server redis.conf 

*** FATAL CONFIG FILE ERROR ***
Reading the configuration file, at line 145
>>> 'tls-cert-file redis.crt tls-key-file redis.key'
wrong number of arguments
ubuntu@ip-172-31-29-250:~/redis-6.0-rc1$ vi redis.conf 
ubuntu@ip-172-31-29-250:~/redis-6.0-rc1$ ./src/redis-server redis.conf 
23085:C 04 Mar 2020 01:58:12.631 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
23085:C 04 Mar 2020 01:58:12.631 # Redis version=5.9.101, bits=64, commit=00000000, modified=0, pid=23085, just started
23085:C 04 Mar 2020 01:58:12.631 # Configuration loaded
23085:M 04 Mar 2020 01:58:12.632 * Increased maximum number of open files to 10032 (it was originally set to 1024).
2020-03-12 15:53:47 +01:00
Johannes Truschnigg 23d5e8b8e4 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-03-12 15:53:47 +01:00
Oran Agra 6173815408 fix for flaky psync2 test
*** [err]: PSYNC2: total sum of full synchronizations is exactly 4 in tests/integration/psync2.tcl
Expected 5 == 4 (context: type eval line 6 cmd {assert {$sum == 4}} proc ::test)

issue was that sometime the test got an unexpected full sync since it
tried to switch to the replica before it was in sync with it's master.
2020-03-12 15:53:47 +01:00
antirez 70e0e49952 ae.c: fix crash when resizing the event loop.
See #6964. The root cause is that the event loop may be resized from an
event callback itself, causing the event pointer to be invalid.
2020-03-12 15:53:47 +01:00
antirez b3e4aa6797 Fix release notes spelling mistake. 2020-03-06 11:09:52 +01:00
antirez e74e68c84f Redis 6 RC2. 2020-03-05 16:00:17 +01:00
qetu3790 4af0d7fd94 Fix not used constant in lru_test_mode.
LRU_CYCLE_PERIOD is defined,but not used.
2020-03-05 12:51:15 +01:00
hwware 6ef018785b add missing file marco 2020-03-05 12:51:15 +01:00
ShooterIT fe81d5c8a9 Avoid compiler warnings 2020-03-05 12:51:15 +01:00
antirez c2f01d7f9e RDB deletion: document it in example redis.conf. 2020-03-05 12:51:15 +01:00
antirez 127e09bca1 Make sync RDB deletion configurable. Default to no. 2020-03-05 12:51:15 +01:00
antirez a20303c623 Check that the file exists in removeRDBUsedToSyncReplicas(). 2020-03-05 12:51:15 +01:00
antirez baaf869fc3 Introduce bg_unlink(). 2020-03-05 12:51:14 +01:00
antirez be4bc1a5be Remove RDB files used for replication in persistence-less instances. 2020-03-05 12:51:14 +01:00
antirez 7a23b94559 Log RDB deletion in persistence-less instances. 2020-03-05 12:51:14 +01:00
antirez 07dc1b42fb Use a smaller getkeys global buffer.
The idea is that very few commands have a lot of keys, and when this
happens the allocation time becomes neglegible.
2020-03-05 12:51:14 +01:00
Oran Agra 10e71b3d01 Optimize temporary memory allocations for getKeysFromCommand mechanism
now that we may use it more often (ACL), these excessive calls to malloc
and free can become an overhead.
2020-03-05 12:51:14 +01:00
antirez edc0ed1415 Modules: reformat RM_Scan() top comment a bit. 2020-03-05 12:51:14 +01:00
antirez c5319612b4 Modules: more details in RM_Scan API top comment. 2020-03-05 12:51:14 +01:00
Oran Agra fff6b26ae3 RM_Scan disable dict rehashing
The callback approach we took is very efficient, the module can do any
filtering of keys without building any list and cloning strings, it can
also read data from the key's value. but if the user tries to re-open
the key, or any other key, this can cause dict re-hashing (dictFind does
that), and that's very bad to do from inside dictScan.

this commit protects the dict from doing any rehashing during scan, but
also warns the user not to attempt any writes or command calls from
within the callback, for fear of unexpected side effects and crashes.
2020-03-05 12:51:14 +01:00
Guy Benoish 650484604c Add RM_CreateStringFromDouble 2020-03-05 12:51:14 +01:00
Oran Agra 3144a278dd add no_auth to COMMAND INFO 2020-03-05 12:51:14 +01:00
Oran Agra afe0b16c02 module api docs for aux_save and aux_load 2020-03-05 12:51:14 +01:00
Guy Benoish df152b0ce7 streamReplyWithRangeFromConsumerPEL: Redundant streamDecodeID 2020-03-05 12:51:14 +01:00
antirez e3c1f43952 Show Redis version when not understanding a config directive.
This makes simpler to give people help when posting such kind of errors
in the mailing list or other help forums, because sometimes the
directive looks well spelled, but the version of Redis they are using is
not able to support it.
2020-03-05 12:51:14 +01: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
antirez 141c0679a0 Changelog: explain Redis 6 SPOP change. 2020-02-27 18:04:34 +01:00
Hengjian Tang 973297336f modify the read buf size according to the write buf size PROTO_IOBUF_LEN defined before 2020-02-27 18:02:30 +01:00
bodong.ybd fe902461f4 Fix spop return nil #4709 2020-02-27 18:02:30 +01:00
Ariel 15ea13245a fix ThreadSafeContext lock/unlock function names 2020-02-27 18:02:30 +01:00
antirez 9d4219ebac Fix SDS misuse in enumConfigSet(). Related to #6778. 2020-02-27 18:02:30 +01:00
Guy Benoish 4d12c37c54 XREADGROUP should propagate XCALIM/SETID in MULTI/EXEC
Use built-in alsoPropagate mechanism that wraps commands
in MULTI/EXEC before sending them to replica/AOF
2020-02-27 18:02:30 +01:00
antirez 8424306433 Remove useless comment from enumConfigSet(). 2020-02-27 18:02:30 +01:00
Oran Agra 12626ce9bb fix race in module api test for fork
in some cases we were trying to kill the fork before it got created
2020-02-27 18:02:30 +01:00
Ponnuvel Palaniyappan dafb94db79 Fix a potential overflow with strncpy 2020-02-27 18:02:30 +01:00
Guy Benoish 2ecab0b63a Modules: Do not auto-unblock clients if not blocked on keys 2020-02-27 18:02:30 +01:00
antirez ea697b6345 Improve aeDeleteEventLoop() top comment grammar. 2020-02-27 18:02:30 +01:00
Oran Agra 635321d47e fix github actions failing latency test for active defrag - part 2
it seems that running two clients at a time is ok too, resuces action
time from 20 minutes to 10. we'll use this for now, and if one day it
won't be enough we'll have to run just the sensitive tests one by one
separately from the others.

this commit also fixes an issue with the defrag test that appears to be
very rare.
2020-02-27 18:02:30 +01:00
wangyuan21 dd4798802c free time event when delete eventloop 2020-02-27 18:02:30 +01:00
Oran Agra 0b988fa9ec fix github actions failing latency test for active defrag
seems that github actions are slow, using just one client to reduce
false positives.

also adding verbose, testing only on latest ubuntu, and building on
older one.

when doing that, i can reduce the test threshold back to something saner
2020-02-27 18:02:30 +01:00
srzhao ecf3b2ef32 fix impl of aof-child whitelist SIGUSR1 feature. 2020-02-27 18:02:30 +01:00
Oran Agra 60096bc1a1 Fix latency sensitivity of new defrag test
I saw that the new defag test for list was failing in CI recently, so i
reduce it's threshold from 12 to 60.

besides that, i add / improve the latency test for that other two defrag
tests (add a sensitive latency and digest / save checks)

and fix bad usage of debug populate (can't overrides existing keys).
this was the original intention, which creates higher fragmentation.
2020-02-27 18:02:30 +01:00
meir@redislabs.com 2966132c52 Changed log level for module fork api from 'notice' to 'verbos'. 2020-02-27 18:02:30 +01:00
antirez b439542604 Tracking: optin/out implemented. 2020-02-27 18:02:30 +01:00
hwware 7277e5d8a8 format fix 2020-02-27 18:02:30 +01:00
antirez ef3551d149 Test engine: experimental change to avoid busy port problems. 2020-02-27 18:02:30 +01:00
hwware 1bb5ee9c68 fix potentical memory leaks 2020-02-27 18:02:30 +01:00
antirez 72c053519c Test engine: detect timeout when checking for Redis startup. 2020-02-27 18:02:30 +01:00
Oran Agra 349aa24511 Defrag big lists in portions to avoid latency and freeze
When active defrag kicks in and finds a big list, it will create a bookmark to
a node so that it is able to resume iteration from that node later.

The quicklist manages that bookmark, and updates it in case that node is deleted.

This will increase memory usage only on lists of over 1000 (see
active-defrag-max-scan-fields) quicklist nodes (1000 ziplists, not 1000 items)
by 16 bytes.

In 32 bit build, this change reduces the maximum effective config of
list-compress-depth and list-max-ziplist-size (from 32767 to 8191)
2020-02-27 18:00:47 +01:00
antirez 294c9af469 Test engine: better tracking of what workers are doing. 2020-02-27 18:00:47 +01:00
Guy Benoish b4ddc7b7ba XGROUP DESTROY should unblock XREADGROUP with -NOGROUP 2020-02-27 18:00:47 +01:00
hwware ba0270799e add missing subcommand description for debug oom 2020-02-27 18:00:47 +01:00
hayashier 73806f74ca fix typo from fss to rss 2020-02-27 18:00:47 +01:00
Guy Benoish 5d0890c0a8 Fix memory leak in test_ld_conv 2020-02-27 18:00:47 +01:00
antirez b6129f86c1 Test is more complex now, increase default timeout. 2020-02-27 18:00:47 +01:00
Madelyn Olson d1f22eaca4 Give an error message if you specify redirect twice 2020-02-27 18:00:47 +01:00
Madelyn Olson 762fbcb687 Minor CSC fixes and fixed documentation 2020-02-27 18:00:47 +01:00
antirez f15fb727a0 Tracking: fix max-keys configuration directive. 2020-02-27 18:00:46 +01:00
Itamar Haber e374573f30 Fixes segfault on calling trackingGetTotalKeys
... with CSC disabled
2020-02-27 18:00:46 +01:00
antirez 73d47d5749 Signal key as modified when expired on-access.
This fixes WATCH and client side caching with keys expiring because of
a synchronous access and not because of background expiring.
2020-02-27 18:00:46 +01:00
antirez b7cb28d501 Tracking: first set of tests for the feature. 2020-02-27 18:00:46 +01:00
antirez df83892760 Rax.c: populate data field after random walk. 2020-02-27 17:59:57 +01:00
antirez 1db7257107 Tracking: fix operators precedence error in bcast check. 2020-02-27 17:59:57 +01:00
antirez 0517da3618 Tracking: rename INFO field with total items. 2020-02-27 17:59:57 +01:00
antirez fe96e29d5f Tracking: fix behavior when switchinig from normal to BCAST. 2020-02-27 17:59:57 +01:00
antirez 3c16d6b32d Tracking: first conversion from hashing to key names. 2020-02-27 17:59:57 +01:00
antirez f21be1ec55 Tracking: fix sending messages bug + tracking off bug. 2020-02-27 17:59:57 +01:00
Oran Agra 3b4f147775 add no-slowlog option to RM_CreateCommand 2020-02-27 17:59:57 +01:00
antirez 6fb1aa2381 Tracking: BCAST: basic feature now works. 2020-02-27 17:59:57 +01:00
antirez d4fe79a174 Tracking: BCAST: broadcasting of keys in prefixes implemented. 2020-02-27 17:59:57 +01:00
antirez abb81c6351 Tracking: BCAST: registration in the prefix table. 2020-02-27 17:59:57 +01:00
antirez 77da960815 Tracking: BCAST: parsing of the options + skeleton. 2020-02-27 17:59:57 +01:00
antirez 3e8c69a9de Tracking: always reply with an array of keys. 2020-02-27 17:59:57 +01:00
antirez a788c373e6 Tracking: minor change of names and new INFO field. 2020-02-27 17:59:57 +01: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
Khem Raj 5e762d847c Mark extern definition of SDS_NOINIT in sds.h
This helps in avoiding multiple definition of this variable, its also
defined globally in sds.c

Signed-off-by: Khem Raj <raj.khem@gmail.com>
2020-02-12 14:17:54 +01:00
lifubang 54f5499aee correct help info for --user and --pass
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-02-12 14:17:54 +01:00
Seunghoon Woo 0c952b13d0 [FIX] revisit CVE-2015-8080 vulnerability 2020-02-12 14:17:54 +01:00
Guy Benoish dd34f70368 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-02-12 14:17:54 +01:00
lifubang 5e042dbc05 fix ssl flag check for redis-cli
Signed-off-by: lifubang <lifubang@acmcoder.com>
2020-02-12 14:17:54 +01:00
Guy Benoish dcbe8bfad1 Exclude "keymiss" notification from NOTIFY_ALL
Because "keymiss" is "special" compared to the rest of
the notifications (Trying not to break existing apps
using the 'A' format for notifications)

Also updated redis.conf and module.c docs
2020-02-12 14:17:54 +01:00
Oran Agra 36caf2e42b update RM_SignalModifiedKey doc comment 2020-02-12 14:17:40 +01:00
Oran Agra 3067352a8d Add handling of short read of module id in rdb 2020-02-12 14:17:40 +01:00
Yossi Gottlieb 9baaf858f9 TLS: Update documentation. 2020-02-12 14:17:40 +01:00
Oran Agra 4440133e9a A few non-data commands that should be allowed while loading or stale
SELECT, and HELLO are commands that may be executed by the client
as soon as it connects, there's no reason to block them, preventing the
client from doing the rest of his sequence (which might just be INFO or
CONFIG, etc).

MONITOR, DEBUG, SLOWLOG, TIME, LASTSAVE are all non-data accessing
commands, which there's no reason to block.
2020-02-12 14:17:40 +01:00
Oran Agra c957794144 Memory leak when bind config is provided twice 2020-02-12 14:17:40 +01:00
Oran Agra 1333a46b7e fix maxmemory config warning
the warning condition was if usage > limit (saying it'll cause eviction
or oom), but in fact the eviction and oom depends on used minus slave
buffers.

other than fixing the condition, i add info about the current usage and
limit, which may be useful when looking at the log.
2020-02-12 14:17:40 +01:00
Oran Agra 8e7282eb3e Fix client flags to be int64 in module.c
currently there's no bug since the flags these functions handle are
always lower than 32bit, but still better fix the type to prevent future
bugs.
2020-02-12 14:17:40 +01:00
Oran Agra a678390e52 moduleRDBLoadError, add key name, and use panic rather than exit
using panic rather than exit means you get s stack trace of the code
path that experianced the error, and possibly other info.
2020-02-12 14:17:40 +01:00
Oran Agra f42ce57d0f stopAppendOnly resets aof_rewrite_scheduled
althouh in theory, users can do BGREWRITEAOF even if aof is disabled, i
suppose it is more common that the scheduled flag is set by either
startAppendOnly, of a failed initial AOFRW fork (AOF_WAIT_REWRITE)
2020-02-12 14:15:56 +01:00
Oran Agra 919fbf421d reduce repeated calls to use_diskless_load
this function possibly iterates on the module list
2020-02-12 14:15:56 +01:00
Oran Agra df096bc96b add SAVE subcommand to ACL HELP and top comment 2020-02-12 14:15:56 +01:00
Oran Agra 22e45d46fe freeClientAsync don't lock mutex if there's just one thread 2020-02-12 14:15:56 +01:00
Oran Agra a55e584706 DEBUG HELP - add PROTOCOL 2020-02-12 14:15:56 +01:00
Oran Agra ba28924418 move restartAOFAfterSYNC from replicaofCommand to replicationUnsetMaster
replicationUnsetMaster can be called from other places, not just
replicaofCOmmand, and all of these need to restart AOF
2020-02-12 14:15:56 +01:00
Guy Benoish 5a6cfbf4ca Some refactroing using getClientType instead of CLIENT_SLAVE 2020-02-12 14:15:56 +01:00
Guy Benoish fae306b374 Fix small bugs related to replica and monitor ambiguity
1. server.repl_no_slaves_since can be set when a MONITOR client disconnects
2. c->repl_ack_time can be set by a newline from a MONITOR client
3. Improved comments
2020-02-12 14:15:56 +01:00
Yossi Gottlieb 736309660f TLS: Some redis.conf clarifications. 2020-02-12 14:15:56 +01:00
Oran Agra 488e194787 config.c verbose error replies for CONFIG SET, like config file parsing
We noticed that the error replies for the generic mechanism for enums
are very verbose for config file parsing, but not for config set
command.

instead of replicating this code, i did a small refactoring to share
code between CONFIG SET and config file parsing.

and also renamed the enum group functions to be consistent with the
naming of other types.
2020-02-12 14:15:56 +01:00
Oran Agra c82ccf0670 memoryGetKeys helper function so that ACL can limit access to keys for MEMORY command 2020-02-12 14:15:56 +01:00
antirez 51c1a9f8fb ACL LOG: make max log entries configurable. 2020-02-12 14:15:35 +01:00
antirez ea1e1b12c9 ACL LOG: test for AUTH reason. 2020-02-12 14:15:35 +01:00
antirez 7379c78a9b ACL LOG: log failed auth attempts. 2020-02-12 14:15:35 +01:00
antirez 9f6e84f6be ACL LOG: implement a few basic tests. 2020-02-12 14:15:35 +01:00
antirez 82790e510f ACL LOG: also log ACL errors in the scripting/MULTI ctx. 2020-02-12 14:15:35 +01:00
antirez 943008ebac ACL LOG: implement LOG RESET. 2020-02-12 14:15:35 +01:00
antirez e271a61103 ACL LOG: group similar entries in a given time delta. 2020-02-12 14:15:35 +01:00
antirez f1974d5d67 ACL LOG: actually emit entries. 2020-02-12 14:15:35 +01:00
antirez d9b153c9f6 ACL LOG: implement ACL LOG subcommadn skeleton. 2020-02-12 14:15:35 +01:00
antirez 577fc4388b ACL LOG: data structures and initial functions. 2020-02-12 14:15:35 +01: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
Guy Benoish 6fe55c2f29 ld2string should fail if string contains \0 in the middle
This bug affected RM_StringToLongDouble and HINCRBYFLOAT.
I added tests for both cases.

Main changes:
1. Fixed string2ld to fail if string contains \0 in the middle
2. Use string2ld in getLongDoubleFromObject - No point of
   having duplicated code here

The two changes above broke RM_SaveLongDouble/RM_LoadLongDouble
because the long double string was saved with length+1 (An innocent
mistake, but it's actually a bug - The length passed to
RM_SaveLongDouble should not include the last \0).
2020-02-04 10:23:48 +01:00
Leo Murillo f7a94526dd Set ZSKIPLIST_MAXLEVEL to optimal value given 2^64 elements and p=0.25 2020-02-04 10:23:48 +01:00
antirez bbce3ba974 Add more info in the unblockClientFromModule() function. 2020-02-04 10:23:48 +01:00
WuYunlong eecfa9793e Fix lua related memory leak. 2020-02-04 10:23:48 +01:00
Guy Benoish 40295fb3fe Modules: Fix blocked-client-related memory leak
If a blocked module client times-out (or disconnects, unblocked
by CLIENT command, etc.) we need to call moduleUnblockClient
in order to free memory allocated by the module sub-system
and blocked-client private data

Other changes:
Made blockedonkeys.tcl tests a bit more aggressive in order
to smoke-out potential memory leaks
2020-02-04 10:23:48 +01:00
WuYunlong d2509811b7 Add tcl regression test in scripting.tcl to reproduce memory leak. 2020-02-04 10:23:48 +01:00
Yossi Gottlieb 29d4a1502a TLS: Fix missing initialization in redis-cli. 2020-02-04 10:23:48 +01:00
Oran Agra ec0c61da05 fix uninitialized info_cb var in module.c 2020-02-04 10:23:48 +01: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
antirez 721a39ddff Document I/O threads in redis.conf. 2020-01-17 10:47:38 +01:00
antirez cbabf779c2 Simplify #6379 changes. 2020-01-17 10:47:38 +01:00
antirez ecd17e819c Jump to right label on AOF parsing error.
Related to #6054.
2020-01-17 10:47:38 +01:00
antirez 8e9d19bc65 Change error message for #6775. 2020-01-17 10:47:38 +01:00
antirez 5be3a15a82 Setting N I/O threads should mean N-1 additional + 1 main thread. 2020-01-17 10:47:38 +01:00
WuYunlong 658749cc54 Free allocated sds in pfdebugCommand() to avoid memory leak. 2020-01-17 10:47:38 +01:00
antirez 1927932b43 Port PR #6110 to new connection object code. 2020-01-17 10:47:38 +01:00
Vasyl Melnychuk ba146d4c09 Make error when submitting command in incorrect context more explicit
So error message `ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context` will become
`ERR 'get' command submitted, but only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context`
2020-01-17 10:47:38 +01:00
WuYunlong 47988c9666 Fix potential memory leak of clusterLoadConfig(). 2020-01-17 10:47:38 +01:00
antirez f2df5773b1 A few comments about main thread serving I/O as well.
Related to #6110.
2020-01-17 10:47:38 +01:00
WuYunlong cc90f79baf Fix potential memory leak of rioWriteBulkStreamID(). 2020-01-17 10:47:38 +01:00
zhaozhao.zz b3ff8a4b6d Threaded IO: use main thread to handle read work 2020-01-17 10:47:38 +01:00
zhaozhao.zz b1f2c51037 Threaded IO: use main thread to handle write work 2020-01-17 10:47:38 +01: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
ShooterIT 7bbafc5639 Rename rdb asynchronously 2020-01-10 13:16:25 +01:00
Leo Murillo c7f752667e Fix bug on KEYS command where pattern starts with * followed by \x00 (null char). 2020-01-10 13:16:25 +01:00
Jamie Scott ed7ea13a2a Update to directive in redis.conf (missing s)
The directive tls-prefer-server-cipher is actually tls-prefer-server-ciphers in config.c. This results in a failed directive call shown below. This pull request adds the "s" in ciphers so that the directive is able to be properly called in config.c

ubuntu@ip-172-31-16-31:~/redis$ src/redis-server ./redis.conf 

*** FATAL CONFIG FILE ERROR ***
Reading the configuration file, at line 200
>>> 'tls-prefer-server-cipher yes'
Bad directive or wrong number of arguments
2020-01-10 13:16:25 +01:00
antirez 3be7762388 Free fakeclient argv on AOF error.
We exit later, so no bug fixed, but it is more correct.

See #6054, thanks to @ShooterIT for finding the issue.
2020-01-10 13:16:25 +01:00
antirez 15f6b74814 Git ignore: ignore more files. 2020-01-10 13:16:14 +01:00
Guy Benoish 1b5bf40c20 Blocking XREAD[GROUP] should always reply with valid data (or timeout)
This commit solves the following bug:
127.0.0.1:6379> XGROUP CREATE x grp $ MKSTREAM
OK
127.0.0.1:6379> XADD x 666 f v
"666-0"
127.0.0.1:6379> XREADGROUP GROUP grp Alice BLOCK 0 STREAMS x >
1) 1) "x"
   2) 1) 1) "666-0"
         2) 1) "f"
            2) "v"
127.0.0.1:6379> XADD x 667 f v
"667-0"
127.0.0.1:6379> XDEL x 667
(integer) 1
127.0.0.1:6379> XREADGROUP GROUP grp Alice BLOCK 0 STREAMS x >
1) 1) "x"
   2) (empty array)

The root cause is that we use s->last_id in streamCompareID
while we should use the last *valid* ID
2020-01-10 13:16:14 +01:00
John Sully 954c20edd9 Add support for incremental build with header files 2020-01-10 13:16:14 +01:00
WuYunlong 11c3afd711 Fix petential cluster link error.
Funcion adjustOpenFilesLimit() has an implicit parameter, which is server.maxclients.
This function aims to ajust maximum file descriptor number according to server.maxclients
by best effort, which is "bestlimit" could be lower than "maxfiles" but greater than "oldlimit".
When we try to increase "maxclients" using CONFIG SET command, we could increase maximum
file descriptor number to a bigger value without calling aeResizeSetSize the same time.
When later more and more clients connect to server, the allocated fd could be bigger and bigger,
and eventually exceeds events size of aeEventLoop.events. When new nodes joins the cluster,
new link is created, together with new fd, but when calling aeCreateFileEvent, we did not
check the return value. In this case, we have a non-null "link" but the associated fd is not
registered.

So when we dynamically set "maxclients" we could reach an inconsistency between maximum file
descriptor number of the process and server.maxclients. And later could cause cluster link and link
fd inconsistency.

While setting "maxclients" dynamically, we consider it as failed when resulting "maxclients" is not
the same as expected. We try to restore back the maximum file descriptor number when we failed to set
"maxclients" to the specified value, so that server.maxclients could act as a guard as before.
2020-01-10 13:16:14 +01:00
Yossi Gottlieb b752e83db5 Add REDISMODULE_CTX_FLAGS_MULTI_DIRTY. 2020-01-10 13:16:03 +01:00
hwware e16eb87465 typo fix in acl.c 2020-01-10 13:16:03 +01:00
Itamar Haber 35ea9d231b Adjusts 'io_threads_num' max to 128
Instead of 512, use the defined max from networking.c
2020-01-10 13:16:03 +01:00
antirez 3872912679 XCLAIM: Create the consumer only on successful claims.
Fixes #6744.
2020-01-08 12:31:39 +01:00
yz1509 b9a1530345 avoid sentinel changes promoted_slave to be its own replica. 2020-01-08 12:31:25 +01: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
antirez 5e7e5e6b61 Fix active expire division by zero.
Likely fix #6723.

This is what happens AFAIK: we enter the main loop where we expire stuff
until a given percentage of keys is still found to be logically expired.
There are however other potential exit conditions.

However the "sampled" variable is not always incremented inside the
loop, because we may found no valid slot as we scan the hash table, but
just NULLs ad dict entries. So when the do/while loop condition is
triggered at the end, we do (expired*100/sampled), dividing by zero if
we sampled 0 keys.
2020-01-01 18:10:39 +01:00
John Sully dbef17c2e1 Fix issue #130 due to fastlock timeout reduction 2020-01-01 11:52:00 -05:00
antirez e61dde8806 Fix duplicated CLIENT SETNAME reply.
Happened when we set the name to "" to cancel the name.
Was introduced during the RESP3 refactoring.

See #6036.
2019-12-29 15:46:31 +01:00
Guy Benoish cddf1da2e9 Stream: Handle streamID-related edge cases
This commit solves several edge cases that are related to
exhausting the streamID limits: We should correctly calculate
the succeeding streamID instead of blindly incrementing 'seq'
This affects both XREAD and XADD.

Other (unrelated) changes:
Reply with a better error message when trying to add an entry
to a stream that has exhausted last_id
2019-12-29 15:46:31 +01:00
Oran Agra 52ea44e53b config.c adjust config limits and mutable
- make lua-replicate-commands mutable (it never was, but i don't see why)
- make tcp-backlog immutable (fix a recent refactory mistake)
- increase the max limit of a few configs to match what they were before
the recent refactory
2019-12-29 15:46:31 +01:00
antirez 0f28ea16a7 Inline protocol: handle empty strings well.
This bug is from the first version of Redis. Probably the problem here
is that before we used an SDS split function that created empty strings
for additional spaces, like in "SET    foo          bar".
AFAIK later we replaced it with the curretn sdssplitarg() API that has
no such a problem. As a result, we introduced a bug, where it is no
longer possible to do something like:

    SET foo ""

Using the inline protocol. Now it is fixed.
2019-12-29 15:46:31 +01:00
antirez 00e5fefe6d Fix ip and missing mode in RM_GetClusterNodeInfo(). 2019-12-29 15:46:31 +01: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
antirez baafd30ba6 Redis 6.0 RC1. 2019-12-19 17:27:29 +01:00
Salvatore Sanfilippo d3a9dff6b9 Merge pull request #6615 from soloestoy/wrap-also-propagate-as-multi
Wrap also propagate as multi
2019-12-19 09:24:52 +01:00
Salvatore Sanfilippo 9a7b6a9f51 Merge pull request #5780 from soloestoy/lua-multi-more-clear
scripting: flag lua_client as CLIENT_MULTI after redis.replicate_command() immediately
2019-12-19 09:06:28 +01:00
Salvatore Sanfilippo f4b8197060 Merge pull request #6052 from jtru/better-systemd-integration-v2
Better systemd integration v2
2019-12-19 08:54:22 +01:00
antirez c5bc1c14c0 Modules: rewrite top function doc of AvoidReplicaTraffic(). 2019-12-18 17:11:03 +01:00
Salvatore Sanfilippo ef0b45ece8 Merge pull request #6497 from oranagra/avoid_replica_traffic
Add config and module API for AvoidReplicaTraffic
2019-12-18 17:06:05 +01:00
antirez 5a72c5058c Fix GEOHASH negative shifting in a more compatible way. 2019-12-18 12:57:32 +01:00
antirez e6e58e455c Revert "Geo: output 10 chars of geohash, not 11."
This reverts commit 009862ab7e.
2019-12-18 12:54:46 +01:00
antirez 5b9d3ac6c6 Avoid changing setKey() API after #6679 fix. 2019-12-18 11:58:02 +01:00
Salvatore Sanfilippo 9d1baa0705 Merge pull request #6679 from soloestoy/keepttl
Add a new SET option KEEPTTL and fix issue #5256
2019-12-18 11:52:08 +01:00
zhaozhao.zz 58554396d6 incrbyfloat: fix issue #5256 ttl lost after propagate 2019-12-18 15:44:51 +08:00
zhaozhao.zz 24044f3356 add a new SET option KEEPTTL that doesn't remove expire time 2019-12-18 15:20:36 +08: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
Salvatore Sanfilippo b7c78b7651 Merge pull request #5916 from madolson/dev-unstable-acl-module-pr
Add module APIs for custom authentication
2019-12-17 09:58:26 +01:00
antirez 4348d25fc4 Add some comment to PR #6144 changes. 2019-12-17 09:19:47 +01:00
Salvatore Sanfilippo f3d67b3842 Merge pull request #6144 from madolson/dev-unstable-cluster-down
Add configuration option for allowing reads on cluster down
2019-12-17 09:15:20 +01:00
Madelyn Olson 7f04a15311 Removed old auth context reference 2019-12-17 07:51:19 +00:00
Madelyn Olson a511a37bb7 Fixed some documentation 2019-12-17 07:49:21 +00:00
Madelyn Olson 7b3e3d6a13 Resolved merge miss 2019-12-16 23:40:19 -08:00
Madelyn Olson 12caffee61 Added a missed space in lua errors 2019-12-16 23:38:31 -08:00
Madelyn Olson 576a08908b Split error message so dependandent callers give a useful result 2019-12-16 23:34:37 -08:00
Madelyn Olson 44aa22c635 Added better exception handling around scripting and module 2019-12-16 23:33:53 -08:00
Madelyn Olson c95a582a74 Add configuration option for allowing reads on cluster down 2019-12-16 23:33:16 -08:00
Madelyn Olson f891b64a83 Tweaking the documentation 2019-12-17 07:28:55 +00:00
Madelyn Olson 67aa527b22 Added some documentation and fixed a test 2019-12-17 07:15:04 +00:00
Madelyn Olson 034dcf185c Add module APIs for custom authentication 2019-12-17 06:59:59 +00:00
Petr Vaněk 7a3f363f34 readme: fix typo 2019-12-16 15:40:09 -05:00
Salvatore Sanfilippo e9b99c78df Merge pull request #6649 from chaten/unstable
Fix outdated information on max memory policies
2019-12-16 11:25:53 +01:00
antirez 901b7469b9 Clarify change in #6662. 2019-12-16 11:24:19 +01:00
antirez aa3f13761f Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-12-16 11:18:20 +01:00
Salvatore Sanfilippo 276a093753 Merge pull request #6662 from oranagra/fix_hz_div0
init server.hz early to avoid div by 0 during config file loading
2019-12-16 11:18:08 +01:00
antirez 096592506e Modules: allow to execute RM_Call() from the module init function. 2019-12-13 17:34:37 +01:00
Salvatore Sanfilippo ba28738083 Merge pull request #6663 from yossigo/fix-replace-value
Improve RM_ModuleTypeReplaceValue() API.
2019-12-12 18:00:07 +01:00
Yossi Gottlieb 0283db5883 Improve RM_ModuleTypeReplaceValue() API.
With the previous API, a NULL return value was ambiguous and could
represent either an old value of NULL or an error condition. The new API
returns a status code and allows the old value to be returned
by-reference.

This commit also includes test coverage based on
tests/modules/datatype.c which did not exist at the time of the original
commit.
2019-12-12 18:50:11 +02:00
Oran Agra ef6e263fde init server.hz early to avoid div by 0 during config file loading
since the refactory of config.c, it was initialized from config_hz in initServer
but apparently that's too late since the config file loading creates objects
which call LRU_CLOCK
2019-12-12 17:56:02 +02:00
Salvatore Sanfilippo 118db9eeae Merge pull request #6516 from IAmATeaPot418/patch-2
Add no-slowlog to acl command to prevent passwords
2019-12-12 09:41:19 +01:00
antirez d7a87d0ea4 redis-cli: some refactoring about not logging AUTH & co. 2019-12-12 09:40:36 +01:00
Salvatore Sanfilippo 81dc180323 Merge pull request #6524 from itamarhaber/acl-cli
Omits  `ACL SETUSER` from redis-cli's history
2019-12-12 09:33:48 +01:00
antirez 476333d192 Remove useless space from moduleLoad(). 2019-12-12 09:29:10 +01:00
Salvatore Sanfilippo c227f5e7bd Merge pull request #6257 from JohnSully/ModuleSecurity
Modules must have execute permissions to load
2019-12-12 09:27:47 +01:00
Salvatore Sanfilippo 2968d8e3cb Merge branch 'unstable' into ModuleSecurity 2019-12-12 09:27:14 +01:00
Oran Agra b5f3247ca5 Add module API for AvoidReplicaTraffic
This is useful to tell redis and modules to try to avoid doing things that may
increment the replication offset, and should be used when draining a master
and waiting for replicas to be in perfect sync before a failover.
2019-12-12 08:38:09 +02:00
Salvatore Sanfilippo c6fb9d0963 Merge pull request #6656 from oranagra/leak_rm_load_from_str
fix leak in RM_LoadDataTypeFromString, and save
2019-12-11 11:39:27 +01:00
Oran Agra a37cca3644 fix leak in RM_LoadDataTypeFromString, and save 2019-12-11 12:35:00 +02:00
antirez 25b36f8d65 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-12-11 10:18:15 +01:00
antirez 441cd9713c Clients connected and bytes used is too spammy for verbose.
This message is there for ten years, but is hardly useful.
Moreover it is likely that it will fill an entire disk if log ratation
is not configured, for no good reasons.
2019-12-11 10:17:23 +01:00
antirez 29fddf3291 create-cluster script tailall option. 2019-12-11 10:16:25 +01:00
Michael Chaten 389faae58e Change description to be agnostic to the number of policies. 2019-12-09 11:27:53 -08:00
Tais P. Hansen 91eac2cdb3 Fix keydb-cli crashing on read-only filesystem 2019-12-09 14:23:10 -05:00
antirez e4b6070c0f Modules: more clarification about disconnection callback. 2019-12-09 12:15:38 +01:00
Salvatore Sanfilippo 14045adf92 Merge pull request #6653 from oranagra/client_tracking_flag
Add ULL suffix to CLIENT_TRACKING flag to prevent sign extension
2019-12-09 10:41:14 +01:00
Oran Agra 5941730c37 Add ULL suffix to CLIENT_TRACKING flag to prevent sign extension
the code in:
        c->flags &= ~(CLIENT_TRACKING|CLIENT_TRACKING_BROKEN_REDIR);
will do sign extension and turn on all the high 31 bits
no damage so far since we don't have any yet
2019-12-09 10:03:23 +02:00
Michael Chaten 52d83d57f9 Fix outdated information on max memory policies 2019-12-06 11:56:52 -08:00
Salvatore Sanfilippo 7e24e219fd Merge pull request #6645 from eliblight/fix-memcpy
Fix memcpy of id from key to be slightly safer.
2019-12-05 16:51:42 +01:00
Eran Liberty 08c3fe8063 - memcpy(&id,ri.key,ri.key_len);
+        memcpy(&id,ri.key,sizeof(id));

The memcpy from the key to the id reliease on the fact that this key
*should* be 8 bytes long as it was entered as such a few lines up the
code.

BUT if someone will change the code to the point this is no longer true,
current code can trash the stack which makes debugging very hard
while this fix will result in some garbage id, or even page fault.
Both are preferable to stack mangaling.
2019-12-05 13:37:11 +00:00
antirez 2271cf03f5 Modules: clarify when the disconnection callback is called. 2019-12-05 10:38:18 +01:00
antirez ecb742acc5 create-cluster script: allow additional options. 2019-12-03 17:52:04 +01:00
antirez 7b5f4b175b Modules: create timers in contexts without a client. 2019-12-03 16:21:23 +01:00
Salvatore Sanfilippo 89849c8b01 Merge pull request #6638 from oranagra/fix_module_short_read_test
fix crash in module short read test
2019-12-02 18:23:28 +01:00
Oran Agra 5661b19005 fix crash in module short read test 2019-12-02 19:17:35 +02:00
antirez 4092a75d85 Avoid collision with MacOS LIST_HEAD macro after #6384. 2019-12-02 09:13:29 +01:00
Salvatore Sanfilippo e5b5f9a2f6 Merge pull request #6384 from devnexen/apple_smaps_impl
Getting region date per process in Darwin
2019-12-02 09:02:08 +01:00
Salvatore Sanfilippo ce7ec725e3 Merge pull request #6624 from oranagra/config_c_step_3
Additional config.c refractory and bugfixes
2019-12-02 08:59:36 +01:00
Salvatore Sanfilippo ff14945e22 Merge pull request #5360 from youjh90/unstable
update leap year comment when div by 400
2019-12-02 08:56:08 +01:00
Salvatore Sanfilippo 731f10225b Merge pull request #6637 from andygua/add-missed-macro
Added the missed macro definition in slowlog.h
2019-12-02 08:51:05 +01:00
Salvatore Sanfilippo ddde700b64 Merge pull request #6634 from oranagra/fix_gen_write_load
revert an accidental test code change done as part of the tls project
2019-12-02 08:50:20 +01:00
Andy Guan 1ed5f84a79 Added the missed macro definition in slowlog.h 2019-12-02 00:28:41 -05:00
John Sully 98a928147f Fix Issue #107 2019-12-01 18:17:33 -05:00
Oran Agra 07b365b7d7 revert an accidental test code change done as part of the tls project
it seems that commit b087dd1db6 accidentially changed
gen_write_load to not use deferred client, which causes them to be slower and not
generate high load which they should, making some tests less effecitive
2019-12-01 16:10:09 +02:00
Oran Agra 6b4366b85b config.c post refactory cleanup 2019-12-01 08:19:25 +02:00
John Sully 8a9045c028 Fix deadlock in spinlock (mfence) also spin for less time before sleeping 2019-11-30 00:51:58 -05:00
antirez f5d48537f1 Fix Pi build needing -latomic. Issue #6275. 2019-11-29 17:35:59 +01:00
John Sully 6c65a11b8d Fastlock should yield in ARM 2019-11-28 14:26:43 -05:00
Oran Agra 18e72c5cc7 Converting more configs to use generic infra, and moving defaults to config.c
Changes in behavior:
- Change server.stream_node_max_entries from int64_t to long long, so that it can be used by the generic infra
- standard error reply instead of "repl-backlog-size must be 1 or greater" and such
- tls-port and a few TLS booleans were readable (config get) even when USE_OPENSSL was off (now they aren't)
- syslog-enabled, syslog-ident, cluster-enabled, appendfilename, and supervised didn't have a get (now they do)
- pidfile was initialized to NULL in InitServerConfig but had CONFIG_DEFAULT_PID_FILE in rewriteConfig (so the real default was "", but rewrite would cause it to be set), fixed the rewrite.
- TLS config in server.h was uninitialized (if no tls config args were provided)

Adding test for sanity and coverage
2019-11-28 11:24:57 +02:00
Oran Agra 28beb05aa3 More improvements and fixes to generic config infra
- Adding is_valid_fn and update_fn, both return 1 for success and 0 for failure with an optional error message.
- Bugfix in handling boundary check of unsigned numeric types (was boundaries as signed)
- Adding more numeric types to generic mechanism: uint, ulonglong, long, time_t, off_t
- More verbose error replies ("argument must be between" in out of range CONFIG SET (like config file parsing)
2019-11-28 11:11:07 +02:00
Oran Agra e0cc3c99d2 Additional config.c refactory and bugfixes
- add capability for each config to have a callback to check if value is valid and return error string
  will enable converting many of the remaining custom configs into generic ones (reducing the x4 repetition for set,get,config,rewrite)
- add capability for each config to  to run some update code after config is changed (only for CONFIG SET)
  will also enable converting many of the remaining custom configs into generic ones
- add capability to move default values from server.h and server.c to config.c
  will reduce many excess lines in server.h and server.c (plus, no need to rebuild the entire code base when a default change 8-))

other behavior changes:
- fix bug in bool config get (always returning 'yes')
- fix a bug in modifying jemalloc-bg-thread at runtime (didn't call set_jemalloc_bg_thread, due to bad merge conflict resolution (my fault))
- side effect when a failed attempt to enable activedefrag at runtime, we now respond with -ERR and not with -DISABLED
2019-11-26 16:52:28 +02:00
Salvatore Sanfilippo a1b654819c Merge pull request #6598 from oranagra/module-hook-test
try to fix an unstable test (module hook for loading progress)
2019-11-25 17:54:21 +01:00
Salvatore Sanfilippo a40669893e Merge pull request #6609 from daidaotong/macrofix
Add macro in bio.h
2019-11-25 10:04:28 +01:00
Salvatore Sanfilippo 6203ed0474 Merge pull request #6593 from daidaotong/movecommandfix
fix move command: WATCH/MULTI/EXEC mechanism breaks
2019-11-25 10:02:43 +01:00
Salvatore Sanfilippo d39afb687d Merge pull request #6563 from devnexen/fbsd_build_fix2
Add missing header
2019-11-25 09:45:29 +01:00
antirez ef5186d920 config.c: remove trailing spaces, trim comments to 80 cols. 2019-11-22 17:54:22 +01:00
Salvatore Sanfilippo a5e4c95cfd Merge pull request #6607 from madolson/dev-unstable-new-refactor
Refactored configs into types that can be generic
2019-11-22 17:42:42 +01:00
zhaozhao.zz 6b056d29f3 block: propagate BRPOPLPUSH as RPOPLPUSH when unblock 2019-11-22 16:38:49 +08:00
zhaozhao.zz 2c970532dc Propagation: flag module client as CLIENT_MULTI if needed
in case of nested MULTI/EXEC
2019-11-22 16:20:30 +08:00
zhaozhao.zz c73d70fb46 Propagation: propagate EXEC directly in lua script 2019-11-22 15:45:21 +08:00
zhaozhao.zz 37a10cef02 Propagation: wrap commands in also_propagate array with MULIT/EXEC
Random command like SPOP with count is replicated as
some SREM operations, and store them in also_propagate
array to propagate after the call, but this would break
atomicity.

To keep the command's atomicity, wrap also_propagate
array with MULTI/EXEC.
2019-11-22 15:42:49 +08:00
Madelyn Olson e8f4010e27 Changed a tab to a space 2019-11-22 06:44:12 +00:00
Madelyn Olson d50ae36e17 Fixed a bug with enum log printing 2019-11-22 06:28:50 +00:00
Madelyn Olson 818a4e0f70 Fixed some linux warnings 2019-11-22 05:49:52 +00:00
Madelyn Olson 519822bcf9 Added a flag for strings that are stored as NULL 2019-11-21 21:31:53 -08:00
zhaozhao.zz 73841e8c49 scripting: a little refactor about EVAL and redis.call()
Change server.lua_client's flag in a more explicit way.
2019-11-22 11:58:03 +08:00
zhaozhao.zz 097c4a6536 scripting: flag lua_client as CLIENT_MULTI after redis.replicate_commands() immediately
To avoid nested MULTI/EXEC, we check the lua_caller's flag,
if we are in the MULTI context we flag the lua_client as
CLIENT_MULTI, but it's not enough we shoud flag lua_client
as CLIENT_MULTI after redis.replicate_commands() immediately
or the first write command after redis.replicate_commands()
cannot know it's in an transaction, I know the missing CLIENT_MULTI
doesn't have any effect now, but it's a real bug and we should fix
it, in case someday we allow some dangerous command like BLPOP.
2019-11-22 11:51:18 +08: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
Salvatore Sanfilippo b93945585a Merge pull request #6530 from oranagra/rm_get_server_info
Add module api for looking into INFO fields
2019-11-21 10:07:23 +01:00
Salvatore Sanfilippo 64c2508ee3 Merge branch 'unstable' into rm_get_server_info 2019-11-21 10:06:15 +01:00
Salvatore Sanfilippo f1f259de5b Merge pull request #6547 from guybe7/module_api_streams
Support streams in general module API functions
2019-11-21 10:03:50 +01:00
antirez da47d52c79 Recomment PR #6346. 2019-11-21 10:01:49 +01:00
Salvatore Sanfilippo fef1e63c70 Merge pull request #6346 from MeirShpilraien/expose_zmalloc_capabilities
Expose used memory to modules via redismodule api
2019-11-21 09:58:11 +01:00
Salvatore Sanfilippo 70469b76d6 Merge branch 'unstable' into expose_zmalloc_capabilities 2019-11-21 09:57:19 +01:00
Daniel Dai bfd8c1fdd2 macro fix
macro fix
2019-11-20 20:39:04 -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
Maxim Ivanov c7b68d10ea Prune leftover TODO comment
Is it sufficient... ? -- Yes it is. In standalone mode, we say READY=1
at the comment point; however in replicated mode, we delay sending
READY=1 until the replication sync completes.
2019-11-20 19:45:25 +02:00
Madelyn Olson 803d765d49 Refactored renaming types in config 2019-11-20 09:22:38 -08:00
Salvatore Sanfilippo c697edf4f4 Merge pull request #6559 from oranagra/active_defrag_tunables
Adjustments for active defrag defaults
2019-11-20 10:08:08 +01:00
Salvatore Sanfilippo 808394b77d Merge pull request #6603 from daidaotong/typofix
fix typo in scripting.acl
2019-11-20 10:06:33 +01:00
Daniel Dai 99b5696390 fix typo 2019-11-19 20:14:59 -05:00
Johannes Truschnigg 129d14e143 Auto-detect and link libsystemd at compile-time
This adds Makefile/build-system support for USE_SYSTEMD=(yes|no|*). This
variable's value determines whether or not libsystemd will be linked at
build-time.

If USE_SYSTEMD is set to "yes", make will use PKG_CONFIG to check for
libsystemd's presence, and fail the build early if it isn't
installed/detected properly.

If USE_SYSTEM is set to "no", libsystemd will *not* be linked, even if
support for it is available on the system redis is being built on.

For any other value that USE_SYSTEM might assume (e.g. "auto"),
PKG_CONFIG will try to determine libsystemd's presence, and set up the
build process to link against it, if it was indicated as being
installed/available.

This approach has a number of repercussions of its own, most importantly
the following: If you build redis on a system that actually has systemd
support, but no libsystemd-dev package(s) installed, you'll end up
*without* support for systemd notification/status reporting support in
redis-server. This changes established runtime behaviour.

I'm not sure if the build system and/or the server binary should
indicate this. I'm also wondering if not actually having
systemd-notify-support, but requesting it via the server's config,
should result in a fatal error now.
2019-11-19 18:55:44 +02:00
Johannes Truschnigg ec5681f0f1 Do not install SysV init-scripts on systemd-enabled hosts
Also, hint at example service unit files if systemd is detected. Thanks
to @mika for spotting a bug in the original iteration of this patch.
2019-11-19 18:55:44 +02:00
Johannes Truschnigg 5bbc112fb1 Provide example systemd service unit files for redis-server 2019-11-19 18:55:44 +02:00
Johannes Truschnigg 641c64ada1 Use libsystemd's sd_notify for communicating redis status to systemd
Instead of replicating a subset of libsystemd's sd_notify(3) internally,
use the dynamic library provided by systemd to communicate with the
service manager.

When systemd supervision was auto-detected or configured, communicate
the actual server status (i.e. "Loading dataset", "Waiting for
master<->replica sync") to systemd, instead of declaring readiness right
after initializing the server process.
2019-11-19 18:55:44 +02:00
Oran Agra ed2269762b try to fix an unstable test (module hook for loading progress)
there were two lssues, one is taht BGREWRITEAOF failed since the initial one was still in progress
the solution for this one is to enable appendonly from the server startup so there's no initial aofrw.

the other problem was 0 loading progress events, theory is that on some
platforms a sleep of 1 will cause a much greater delay due to the context
switch, but on other platform it doesn't. in theory a sleep of 100 micro
for 1k keys whould take 100ms, and with hz of 500 we should be gettering
50 events (one every 2ms). in practise it doesn't work like that, so trying
to find a sleep that would be long enough but still not cause the test to take
too long.
2019-11-19 15:01:51 +02:00
Salvatore Sanfilippo 45025713a8 Merge pull request #6541 from artix75/module-long-double
Module API: add support for long double conversions and replies
2019-11-19 12:15:53 +01:00
Salvatore Sanfilippo e7144fbed8 Merge branch 'unstable' into module-long-double 2019-11-19 12:15:45 +01:00
Salvatore Sanfilippo e916058f0b Merge pull request #6557 from oranagra/rm_lru_lfu_revized
rename RN_SetLRUOrLFU -> RM_SetLRU and RN_SetLFU
2019-11-19 11:58:07 +01:00
antirez fe5aea38c3 Simplify PR #6551 implementation. 2019-11-19 11:56:02 +01:00
Salvatore Sanfilippo 065872e001 Merge pull request #6551 from pvalsecc/sentinel_kill_pubsub
Redis sentinel kill pubsub client connections as well
2019-11-19 11:53:10 +01:00
antirez 446f24e66d Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-11-19 11:52:40 +01:00
Salvatore Sanfilippo b311a368e0 Merge pull request #6558 from oranagra/module_testrdb_leak
fix leak in module api rdb test
2019-11-19 11:49:43 +01:00
antirez 936e01e5bb Fix stream test after addition of 0-0 ID test. 2019-11-19 11:49:05 +01:00
Salvatore Sanfilippo 2151b82be9 Merge pull request #6571 from wangzhione/patch-2
Update adlist.h
2019-11-19 11:42:46 +01:00
Salvatore Sanfilippo 06a24b9cfa Merge pull request #6597 from yossigo/rm-call-extended-errors
Improve RM_Call() errno classification.
2019-11-19 11:41:32 +01:00
Salvatore Sanfilippo 8e95064408 Merge pull request #6134 from zhouyuan/fix_aof
aof: fix assignment for aof_fsync_offset
2019-11-19 11:40:34 +01:00
Salvatore Sanfilippo 397a8b57cc Merge pull request #6513 from oranagra/test_assertions
test infra: improve prints on failed assertions
2019-11-19 11:34:11 +01:00
antirez ce03d68332 Rename var to fixed_time_expire now that is more general. 2019-11-19 11:28:04 +01:00
antirez b42466b925 Fix patch provided in #6554. 2019-11-19 11:23:43 +01:00
Salvatore Sanfilippo 6a9851c7f8 Merge pull request #6554 from soloestoy/unblock-as-call
expires & blocking: handle ready keys as call()
2019-11-19 11:14:05 +01:00
Yossi Gottlieb 2d1e893b3e Improve RM_Call() errno classification.
RM_Call() will now use EBADF and ENONET in addition to EINVAL in order
to provide more information about errors (i.e. when return value is
NULL).
2019-11-19 12:10:48 +02:00
antirez 77ad9aaafe Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-11-19 11:10:35 +01:00
Salvatore Sanfilippo 2f41c8d518 Merge pull request #6512 from MeirShpilraien/scan_module_impl
Added scan implementation to module api.
2019-11-19 11:08:15 +01:00
Salvatore Sanfilippo 656e40eed2 Merge branch 'unstable' into scan_module_impl 2019-11-19 11:08:02 +01:00
antirez 5b80a41cad Remove additional space from comment. 2019-11-19 11:05:55 +01:00
Salvatore Sanfilippo 1530a3cfc6 Merge pull request #6577 from oranagra/module_doc
module docs, missing LOADING flag
2019-11-19 11:02:58 +01:00
Salvatore Sanfilippo 32a8301073 Merge pull request #4076 from yossigo/add_mt_replacevalue
Add RM_ModuleTypeReplaceValue.
2019-11-19 11:00:01 +01:00
Salvatore Sanfilippo 3d89210477 Merge pull request #3383 from yossigo/datatype_load_save
Redis Module API calls to allow re-use of data type RDB save/load.
2019-11-19 10:55:42 +01:00
Salvatore Sanfilippo a7122f4518 Merge pull request #6579 from oranagra/rm_reply_string_opt
Slightly more efficient RM_ReplyWithEmptyString
2019-11-19 10:54:00 +01:00
Salvatore Sanfilippo 70016f7861 Merge pull request #6574 from guybe7/fix_xadd_empty_id
XADD with ID 0-0 stores an empty key
2019-11-19 10:50:45 +01:00
Salvatore Sanfilippo 64a78f5ba3 Merge pull request #6596 from wangzhione/patch-5
Update mkreleasehdr.sh
2019-11-19 10:48:32 +01:00
喜欢兰花山丘 7c95e89ec3 Update mkreleasehdr.sh
fix date +%s errata
2019-11-19 17:23:47 +08:00
Daniel Dai 4ece8bd7a7 fix move command 2019-11-19 00:02:45 -05:00
antirez 3243252cb0 Expire cycle: document expire effort in redis.conf. 2019-11-18 18:11:38 +01:00
antirez e8ceba4e64 Expire cycle: set a buckets limit as well. 2019-11-18 17:47:19 +01:00
antirez 2ab51a644d Expire cycle: fix parameters computation. 2019-11-18 11:43:42 +01:00
antirez 1ccc270a2c Expire cycle: make expire effort configurable. 2019-11-18 11:33:44 +01:00
antirez 84b01f63db Expire cycle: introduce configurable effort. 2019-11-18 11:30:05 +01: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
antirez 2766805680 Expire cycle: tollerate less stale keys, expire cycle CPU in INFO. 2019-11-15 11:29:34 +01:00
antirez ffc7e509aa Expire cycle: scan hash table buckets directly. 2019-11-15 10:53:19 +01: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
antirez 2f6fe5ce3a Expire cycle: introduce the new state needed for the new algo. 2019-11-14 18:28:01 +01:00
antirez 8d50a8327e Rax library updated. 2019-11-14 12:48:54 +01:00
Oran Agra c426bbf3a5 Slightly more efficient RM_ReplyWithEmptyString
trimming talk about RESP protocol from API docs (should be independent to that anyway)
2019-11-14 09:46:46 +02:00
Oran Agra 2d30afc45f module docs, missing LOADING flag 2019-11-14 09:09:10 +02:00
Yossi Gottlieb 9c76875f41 Add RM_ModuleTypeReplaceValue.
This is a light-weight replace function, useful for use cases such as
realloc()ing an existing value, etc.  Using RM_ModuleTypeSetValue() in
such cases is wasteful and complex as it attempts to delete the old
value, call its destructor, etc.
2019-11-14 08:50:11 +02:00
Guy Benoish 4a12047c61 XADD with ID 0-0 stores an empty key
Calling XADD with 0-0 or 0 would result in creating an
empty key and storing it in the database.
Even worse, because XADD will reply with error the action
will not be replicated, creating a master-replica
inconsistency
2019-11-13 16:47:30 +05:30
喜欢兰花山丘 253d9d6d12 Update adlist.h
Update listGetFree keep format consistent
2019-11-13 10:14:45 +08:00
Oran Agra 0bc3dab095 Adjustments for active defrag defaults and tuning
Reduce default minimum effort, so that when fragmentation is just detected,
the impact on the latency will be minor.

Reduce the default maximum effort, mainly to prevent a case were a sudden
massive deletions, won't trigger an aggressive defrag that will cause latency.

When activedefrag is disabled mid-run, reset the 'running' info field, and
clear the scan cursor, so that when it'll be re-enabled, a new fresh scan will
start.

Clearing the 'running' variable is important since lowering the defragger
tunables mid-scan won't help, the defragger only considers new threshold when
a new scan starts, and during a scan it can only become more aggressive,
(when more severe fragmentation is detected), it'll never go less aggressive.
So by temporarily disabling activedefrag, one can lower th the tunables.

Removing the experimantal warning.
2019-11-12 15:05:29 +02:00
Oran Agra 0f8692b464 Add RM_ScanKey to scan hash, set, zset, changes to RM_Scan API
- Adding RM_ScanKey
- Adding tests for RM_ScanKey
- Refactoring RM_Scan API

Changes in RM_Scan
- cleanup in docs and coding convention
- Moving out of experimantal Api
- Adding ctx to scan callback
- Dont use cursor of -1 as an indication of done (can be a valid cursor)
- Set errno when returning 0 for various reasons
- Rename Cursor to ScanCursor
- Test filters key that are not strings, and opens a key if NULL
2019-11-11 16:05:55 +02:00
meir@redislabs.com 11c6ce812a Added scan implementation to module api.
The implementation expose the following new functions:
1. RedisModule_CursorCreate - allow to create a new cursor object for
keys scanning
2. RedisModule_CursorRestart - restart an existing cursor to restart the
scan
3. RedisModule_CursorDestroy - destroy an existing cursor
4. RedisModule_Scan - scan keys

The RedisModule_Scan function gets a cursor object, a callback and void*
(used as user private data).
The callback will be called for each key in the database proving the key
name and the value as RedisModuleKey.
2019-11-11 16:01:41 +02:00
David Carlier 960c25ac0a Add missing header 2019-11-11 13:06:08 +00:00
Oran Agra 28c20b4ef9 rename RN_SetLRUOrLFU -> RM_SetLRU and RN_SetLFU
- the API name was odd, separated to two apis one for LRU and one for LFU
- the LRU idle time was in 1 second resolution, which might be ok for RDB
  and RESTORE, but i think modules may need higher resolution
- adding tests for LFU and for handling maxmemory policy mismatch
2019-11-10 09:27:01 +02:00
Oran Agra 02f21113ab fix leak in module api rdb test
recently added more reads into that function, if a later read fails, i must
either free what's already allocated, or return the pointer so that the free
callback will release it.
2019-11-10 09:21:19 +02:00
zhaozhao.zz 7059eceeb0 expires & blocking: handle ready keys as call() 2019-11-08 19:06:51 +08:00
Patrick Valsecchi 9593ffde2e Redis sentinel kill pubsub client connections as well
When a redis instance becomes a slave, sentinel also kills pubsub
clients.

Closes #6545
2019-11-07 08:49:19 +01:00
antirez 0f026af185 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-11-06 17:44:42 +01:00
meir@redislabs.com e45239e350 fix documentation 2019-11-06 12:26:03 +02:00
Guy Benoish 1833d008b3 Support streams in general module API functions
Fixes GitHub issue #6492
Added stream support in RM_KeyType and RM_ValueLength.
Also moduleDelKeyIfEmpty was updated, even though it has
no effect now (It will be relevant when stream type direct
API will be coded - i.e. RM_StreamAdd)
2019-11-06 15:52:19 +05:30
meir@redislabs.com c032dc45d1 changed GetUsedMemoryPresentage -> GetUsedMemoryRatio and return value between 0 and 1. 2019-11-06 12:17:09 +02:00
meir@redislabs.com aded138a59 return value between 0 to 100 instead of 0 to 1. 2019-11-06 11:28:52 +02:00
meir@redislabs.com 089ee5979d expose used memory via redismodule api
The exposed functions:
1. RedisModule_GetUsedMemoryPercentage - return the used memory
2. RedisModue_MallocSize - return for a given pointer, the amount of memory allocated for this pointer
2019-11-06 11:28:52 +02:00
antirez 8b2c0f9044 Update PR #6537: use a fresh time outside call().
One problem with the solution proposed so far in #6537 is that key
lookups outside a command execution via call(), still used a cached
time. The cached time needed to be refreshed in multiple places,
especially because of modules callbacks from timers, cluster bus, and
thread safe contexts, that may use RM_Open().

In order to avoid this problem, this commit introduces the ability to
detect if we are inside call(): this way we can use the reference fixed
time only when we are in the context of a command execution or Lua
script, but for the asynchronous lookups, we can still use mstime() to
get a fresh time reference.
2019-11-06 09:57:29 +01:00
antirez 824f5f0b7a Update PR #6537 patch to for generality.
After the thread in #6537 and thanks to the suggestions received, this
commit updates the original patch in order to:

1. Solve the problem of updating the time in multiple places by updating
it in call().
2. Avoid introducing a new field but use our cached time.

This required some minor refactoring to the function updating the time,
and the introduction of a new cached time in microseconds in order to
use less gettimeofday() calls.
2019-11-05 10:14:34 +01:00
zhaozhao.zz e542132b07 expires: refactoring judgment about whether a key is expired
Calling lookupKey*() many times to search a key in one command
may get different result.

That's because lookupKey*() calls expireIfNeeded(), and delete
the key when reach the expire time. So we can get an robj before
the expire time, but a NULL after the expire time.

The worst is that may lead to Redis crash, for example
`RPOPLPUSH foo foo` the first time we get a list form `foo` and
hold the pointer, but when we get `foo` again it's expired and
deleted. Now we hold a freed memory, when execute rpoplpushHandlePush()
redis crash.

To fix it, we can refactor the judgment about whether a key is expired,
using the same basetime `server.cmd_start_mstime` instead of calling
mstime() everytime.
2019-11-05 09:56:39 +01:00
John Sully 5e40ea6ee7 Fix test failure with tcl8.5 (test only issue) 2019-11-04 17:31:29 -08:00
Yossi Gottlieb 5350e7669e Add ModuleDataType to/from string serialization.
Add two new functions that leverage the RedisModuleDataType mechanism
for RDB serialization/deserialization and make it possible to use it
to/from arbitrary strings:

* RM_SaveDataTypeToString()
* RM_LoadDataTypeFromString()
2019-11-04 21:53:59 +02:00
Salvatore Sanfilippo a15a5d7097 Merge pull request #6540 from oranagra/simple_module_api_tests
Test coverage for new module APIs: dbsize, flushall, randomkey, lru get/set
2019-11-04 18:52:31 +01:00
artix a68c19df6c RM_CreateStringFromLongDouble: use new ld2string 'mode' type 2019-11-04 18:49:56 +01:00
artix 060af1858d Fix RedisModule_ReplyWithLongDouble ptr definition, add tests 2019-11-04 18:49:50 +01:00
artix 60ec2b78b3 Start support for long double in modules
New API:

- RedisModule_StringToLongDouble
- RedisModule_CreateStringFromLongDouble
- RedisModule_ReplyWithLongDouble
2019-11-04 18:49:42 +01:00
Oran Agra 3adf10b809 Test coverage for new module APIs: dbsize, flushall, randomkey, lru get/set 2019-11-04 19:30:31 +02:00
Salvatore Sanfilippo 576a7b8caf Merge pull request #6539 from kristoff-it/unstable
fix unreported overflow in autogerenared stream IDs
2019-11-04 17:37:28 +01:00
Salvatore Sanfilippo bbdbfabf9e Merge pull request #6531 from oranagra/rm_save_long_double
Module API for loading and saving long double
2019-11-04 17:33:35 +01:00
Loris Cro b12d2f65d6 fix unreported overflow in autogerenared stream IDs 2019-11-04 16:36:06 +01:00
Loris Cro 3f14bfd809 Merge pull request #1 from antirez/unstable
update to latest unstable
2019-11-04 16:12:09 +01:00
Salvatore Sanfilippo 720d1fd3bb Merge pull request #6486 from oranagra/module_lru_lfu
Module API for controlling LRU and LFU, and OpenKey without TOUCH
2019-11-04 11:05:08 +01:00
Salvatore Sanfilippo 18b62a51e2 Merge branch 'unstable' into module_lru_lfu 2019-11-04 11:04:49 +01:00
Salvatore Sanfilippo 327cb45ed5 Merge pull request #6532 from oranagra/rm_misc_commands
Module API for PUBLISH, FLUSHALL, RANDOMKEY, DBSIZE
2019-11-04 11:02:37 +01:00
Salvatore Sanfilippo 23c681b51d Merge pull request #6535 from guybe7/module_block_on_keys_tests
Modules: Test RedisModule_BlockClientOnKeys
2019-11-04 10:53:59 +01:00
Salvatore Sanfilippo dcc4347c53 Merge pull request #6514 from oranagra/module_hooks
Modules hooks: complete missing hooks for the initial set of hooks
2019-11-04 10:37:16 +01:00
Salvatore Sanfilippo da44c54897 Merge branch 'unstable' into module_hooks 2019-11-04 10:37:06 +01:00
Guy Benoish b81f486c2f Modules: Test RedisModule_BlockClientOnKeys 2019-11-04 14:20:24 +05:30
Oran Agra 0423309768 Add RM_ServerInfoGetFieldUnsigned
rename RM_ServerInfoGetFieldNumerical RM_ServerInfoGetFieldSigned
move string2ull to util.c
fix leak in RM_GetServerInfo when duplicate info fields exist
2019-11-04 08:50:29 +02:00
Oran Agra deebed23e1 Adding RM_ServerInfoGetFieldC 2019-11-04 07:57:52 +02:00
Oran Agra 87332ce524 Module API for PUBLISH, FLUSHALL, RANDOMKEY, DBSIZE 2019-11-04 07:40:52 +02:00
Oran Agra 779aebc91c Module API for loading and saving long double
looks like each platform implements long double differently (different bit count)
so we can't save them as binary, and we also want to avoid creating a new RDB
format version, so we save these are hex strings using "%La".

This commit includes a change in the arguments of ld2string to support this.
as well as tests for coverage and short reads.

coded by @guybe7
2019-11-03 16:42:31 +02:00
Oran Agra 4d580438b0 Add module api for looking into INFO fields
- Add RM_GetServerInfo and friends
- Add auto memory for new opaque struct
- Add tests for new APIs

other minor fixes:
- add const in various char pointers
- requested_section in modulesCollectInfo was actually not sds but char*
- extract new string2d out of getDoubleFromObject for code reuse

Add module API for
2019-11-03 15:02:25 +02:00
antirez fdaea2a7a7 Modules: fix thread safe context creation crash.
See #6525, this likely creates a NULL deference if the client was
terminated by Redis between the creation of the blocked client and the
creation of the thread safe context.
2019-10-31 18:07:33 +01:00
antirez 1ee195d255 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-10-31 17:55:18 +01:00
antirez dd5feec5e8 Modules: block on keys: fix stale comment. 2019-10-31 17:45:07 +01:00
antirez 825adcf3f5 Modules: block on keys: finish implementing RM_UnblockClient(). 2019-10-31 17:39:05 +01:00
Itamar Haber 9f32d0eed2 Ommits from redis-cli's history 2019-10-31 15:45:52 +02:00
antirez 37bf3e18cb Modules: block ok keys: improve example. 2019-10-31 12:31:22 +01:00
antirez 66f55bc5c1 Modules: block on keys: fix bugs in processing order. 2019-10-31 12:23:55 +01:00
antirez 629081f839 Modules: block on keys: fix the top comments. 2019-10-31 11:43:45 +01:00
antirez 91f4bdc9f9 Modules: block on keys: use a better interface.
Using the is_key_ready() callback plus the reply callback later, creates
different issues AFAIK:

1. More complex API.
2. We need to call the reply callback() ASAP if the is_key_ready()
interface returned success, however the internals do not work in that
way, so when the reply callback is called the setup could be different.
To fix that, there is to break the current design that handles the
unblocked clients asyncrhonously, and run the list ASAP.
2019-10-31 11:35:07 +01:00
antirez 4534960b29 Modules: remove spurious call from moduleHandleBlockedClients().
Now we handle propagation when we free the context.
2019-10-31 10:32:59 +01:00
antirez 228bc89ecb Modules: block on keys: example on hellotype.c. 2019-10-31 10:30:54 +01:00
antirez 215b72c0ba Modules: block on keys: implement the internals. 2019-10-30 10:57:44 +01:00
antirez fb6110ac20 Modules: block on keys: export APIs. 2019-10-30 10:20:28 +01:00
antirez 3649568ff2 Modules: block on keys functions layout and mechanism. 2019-10-30 10:11:58 +01:00
Jamie Scott 5eb2290f68 Add no-slowlog to acl command to prevent passwords
Adding no-slowlog to acl command to prevent acl passwords from showing in slowlog
2019-10-29 15:10:07 -07:00
Oran Agra 51c3ff8d75 Modules hooks: complete missing hooks for the initial set of hooks
* replication hooks: role change, master link status, replica online/offline
* persistence hooks: saving, loading, loading progress
* misc hooks: cron loop, shutdown, module loaded/unloaded
* change the way hooks test work, and add tests for all of the above

startLoading() now gets flag indicating what is loaded.
stopLoading() now gets an indication of success or failure.
adding startSaving() and stopSaving() with similar args and role.
2019-10-29 17:59:09 +02:00
Oran Agra a0cfd519e3 test infra: improve prints on failed assertions
sometimes we have several assertions with the same condition in the same test
at different stages, and when these fail (the ones that print the condition
text) you don't know which one it was. other assertions didn't print the
condition text (variable names), just the expected and unexpected values.

So now, all assertions print context line, and conditin text.

besides, one of the major differences between 'assert' and 'assert_equal',
is that the later is able to print the value that doesn't match the expected.
if there is a rare non-reproducible failure, it is helpful to know what was
the value the test encountered and how far it was from the threshold.

So now, adding assert_lessthan and assert_range that can be used in some places.
were we used just 'assert { a > b }' so far.
2019-10-29 17:38:12 +02:00
Oran Agra e978bdf9ef Module API for controlling LRU and LFU, and OpenKey without TOUCH
Some commands would want to open a key without touching it's LRU/LFU
similarly to the OBJECT or DEBUG command do.

Other commands may want to implement logic similar to what RESTORE
does (and in the future MIGRATE) and get/set the LRU or LFU.
2019-10-29 15:03:05 +02:00
Salvatore Sanfilippo 764b420f5f Merge pull request #6487 from oranagra/module_modified_key
Module API for explicit SignalModifiedKey instead of implicit one.
2019-10-29 10:40:22 +01:00
Salvatore Sanfilippo 568dfd4b49 Merge pull request #6470 from gkorland/CI
Add Github action for CI
2019-10-29 10:25:34 +01:00
Salvatore Sanfilippo 94973fd0eb Merge pull request #6508 from guybe7/fix_module_notify_comp_error
Fix compilation error introduced by cee6dead3
2019-10-29 10:07:45 +01:00
Salvatore Sanfilippo 90169cdf16 Merge pull request #6495 from oranagra/rm_call_argv
Module api RM_CallArgv and test
2019-10-29 10:07:05 +01:00
Guy Benoish 43e2a398f9 Fix compilation error introduced by cee6dead3
Need to add calls to REDISMODULE_API_FUNC...
2019-10-28 17:58:07 +05:30
Salvatore Sanfilippo 469a6e5f1a Merge pull request #6481 from guybe7/modules_notify
Modules: Allow notifying custom keyspace events
2019-10-28 12:16:04 +01:00
Oran Agra 0399b5a27e Module api tests for RM_Call
Adding a test for coverage for RM_Call in a new "misc" unit
to be used for various short simple tests

also solves compilation warnings in redismodule.h and fork.c
2019-10-28 12:39:57 +02:00
Guy Benoish cee6dead3c Modules: Allow notifying custom keyspace events
Also, add an API for getting server.notify_keyspace_events

Other (unrelated) changes:
Add RM_GetKeynameFromModuleKey
2019-10-28 15:53:35 +05:30
antirez cfcb475435 LOLWUT 6: always pick a default color sequence. 2019-10-28 11:10:58 +01:00
Oran Agra a12f07792f Module API for explicit SignalModifiedKey instead of implicit one.
This commit also fixes an uninitialized module struct member (that luckily never got released)
2019-10-28 12:09:25 +02:00
antirez 8337e083b6 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-10-28 11:09:09 +01:00
Salvatore Sanfilippo c328c807e7 Merge pull request #6496 from oranagra/module_tests_valgrind
Make module tests pass with valgrind, and fix a leak in diskless load
2019-10-28 10:05:52 +01:00
Salvatore Sanfilippo d2658f8387 Merge pull request #6493 from yossigo/modules-make-cleanup
Modules: improve tests Makefile.
2019-10-28 10:00:40 +01:00
Salvatore Sanfilippo 5aab012676 Merge pull request #6498 from oranagra/rm_latency_add_sample
Module API for LatencyAddSample
2019-10-28 09:59:26 +01:00
Salvatore Sanfilippo e097c99681 Merge pull request #4761 from WJWH/minor-typos
Fix some minor typos in comments
2019-10-28 09:58:38 +01:00
Salvatore Sanfilippo 6f2fc34228 Merge pull request #6502 from happynote3966/typo-fix
fix comment typo in redis-cli.c
2019-10-28 09:57:43 +01:00
Salvatore Sanfilippo c6c65d9ab3 Merge pull request #6503 from cstrotm/unstable
Typo fix: kill -> still
2019-10-28 09:57:19 +01:00
Salvatore Sanfilippo d070221707 Merge pull request #6505 from swilly22/replaywith-module-API-additions
Introduce ReplyWithVerbatimString, ReplyWithEmptyArray, ReplyWithNull…
2019-10-28 09:56:56 +01:00
Salvatore Sanfilippo 24fdc87fe0 Merge pull request #4994 from soloestoy/module-blocked-client
Modules: make unloading module more safe
2019-10-28 09:55:11 +01:00
swilly22 56a7c45521 Introduce ReplyWithVerbatimString, ReplyWithEmptyArray, ReplyWithNullArray and ReplyWithEmptyString to redis module API 2019-10-28 08:50:25 +02:00
zhaozhao.zz c74398e130 Modules: make unloading module more safe
As we know if a module exports module-side data types,
unload it is not allowed. This rule is the same with
blocked clients in module, because we use background
threads to implement module blocked clients, and it's
not safe to unload a module if there are background
threads running. So it's necessary to check if any
blocked clients running in this module when unload it.

Moreover, after that we can ensure that if no modules,
then no module blocked clients even module unloaded.
So, we can call moduleHandleBlockedClients only when
we have installed modules.
2019-10-28 11:31:58 +08:00
Carsten Strotmann cb2ca37f88 Typo fix: kill -> still 2019-10-25 19:38:45 +02:00
happynote3966 cd02c5944f fix comment typo in redis-cli.c 2019-10-25 22:31:55 +09:00
Wander Hillen fb1f4f4e7e Merge branch 'unstable' into minor-typos 2019-10-25 10:18:26 +02: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
Oran Agra e3b1d6d3ad Module API for LatencyAddSample 2019-10-24 14:24:55 +03:00
Yossi Gottlieb 183d264e9e Modules: improve tests Makefile.
Removes some boilerplate per module, add clean target.
2019-10-24 13:21:35 +03:00
antirez 5dd1130272 Remove trailing space from server.c. 2019-10-24 11:20:15 +02:00
antirez 6e98214f74 Modules hooks: test flush event. 2019-10-24 10:51:03 +02:00
antirez 39f2ab595c Modules hooks: initial Tcl test file. 2019-10-24 10:41:25 +02:00
Oran Agra be352633a0 Make module tests pass with valgrind, and fix a leak in diskless load 2019-10-24 09:45:25 +03: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
antirez 7cefbeaad5 Modules hooks: select DB zero by default. 2019-10-23 18:51:44 +02:00
antirez d3266d516b Modules hooks: test module draft. 2019-10-23 18:42:02 +02:00
antirez dddfde85ef Modules hooks: fix memory leak in example module. 2019-10-23 18:39:53 +02:00
antirez 61ac2aef2b Modules hooks: for nested calls, create new fake clients.
We can't use the same client at the same time when re-entering the hook.
2019-10-23 18:39:53 +02:00
antirez 8cccc6b468 Modules hooks: don't call the hook for fake clients. 2019-10-23 18:39:53 +02:00
antirez 83de18805c Modules hooks: do not re-enter in hooks.
Calling a module hook callback may result in callback operations in turn
triggering other events the module is subscribed too. We don't want to
trigger those, it's unsafe and quite confusing, and to do it correcly we
would need to maintain an event list: quite a more complex
implementation.
2019-10-23 18:39:53 +02:00
antirez 89af7e4c85 Modules hooks: select the right DB for FLUSHDB events. 2019-10-23 18:39:53 +02:00
antirez bc1ef48e56 Modules hooks: FLUSHDB event example. 2019-10-23 18:39:53 +02:00
antirez ed833c9f99 Modules hooks: implement the FLUSHDB event. 2019-10-23 18:39:53 +02:00
antirez 8ec2fc3969 Modules hooks: unify structures definitions. 2019-10-23 18:39:53 +02:00
antirez db8c9a8520 Modules hooks: document what yet to implement WIP 2. 2019-10-23 18:39:53 +02:00
antirez 18d1607f5e Modules hooks: document what yet to implement WIP 1. 2019-10-23 18:39:53 +02:00
antirez c379fdbae2 Modules hooks: do more in example client callback. 2019-10-23 18:39:53 +02:00
antirez cf52e0ad44 Module hooks: fixes and an example module. 2019-10-23 18:39:53 +02:00
antirez 94c50314f1 Modules hooks: fix sub event in calls from client change. 2019-10-23 18:39:53 +02:00
antirez 019ac37e9c Modules hooks: fix define / linker issues. Implement one test event. 2019-10-23 18:39:53 +02:00
antirez d54652682d Modules hooks: handle module unloading + API export. 2019-10-23 18:39:53 +02:00
antirez 1e78681df8 Modules hooks: fix a leak and a few more issues. 2019-10-23 18:39:53 +02:00
antirez b9af7e24e4 Modules hooks: event firing logic. 2019-10-23 18:39:53 +02:00
antirez 6e56f513b4 Modules: refactoring of RM_GetClientInfoById(). 2019-10-23 18:39:53 +02:00
antirez 21d8544128 Modules: fix RedisModule_GetClientInfoById() example. 2019-10-23 18:39:53 +02:00
antirez e9b5484ddd Modules: export GetClientInfoById(). 2019-10-23 18:39:53 +02:00
antirez 6ea8641ae0 Modules: add the client ID to the client info structure. 2019-10-23 18:39:53 +02:00
antirez d2d74ca0f3 Modules: RM_GetClientInfoById() draft. 2019-10-23 18:39:53 +02:00
antirez bebb2e1994 Modules hooks: a first version of events and some API. 2019-10-23 18:39:53 +02:00
antirez 3170f63330 Modules hooks: initial design of data structures. 2019-10-23 18:39:53 +02:00
antirez ed2ba31e4c Modules: fix moduleCreateArgvFromUserFormat() casting bug.
In 32 bit systems casting to "long" will cut the result to 32 bit.
2019-10-23 18:39:14 +02: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
Guy Korland 0381f14acc add CI action 2019-10-20 10:04:25 +03:00
Guy Korland 1ac30300f0 Merge branch 'unstable' of github.com:antirez/redis into unstable 2019-10-20 09:59:23 +03:00
antirez 673c9d7029 module: fix propagation API bug. 2019-10-17 18:28:34 +02:00
antirez 97f6e314c1 Modules: allow to check for AOF loading client. 2019-10-17 18:10:50 +02:00
antirez 8651e6a10d Modules: add new flags to context, replica state + more. 2019-10-17 17:49:33 +02: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
Salvatore Sanfilippo efb6495a44 Merge pull request #6236 from yossigo/poc/conns
Abstract Connections I/O API & TLS Support
2019-10-16 17:42:35 +02:00
Yossi Gottlieb 8e29b0b22b Fix Makefile merge issue. 2019-10-16 17:31:02 +03:00
Yossi Gottlieb 0db3b0a0ff Merge remote-tracking branch 'upstream/unstable' into tls 2019-10-16 17:08:07 +03:00
Salvatore Sanfilippo b8e02f2b40 Merge pull request #5926 from JimB123/unstable
Addition of RedisModule_OnUnload hook
2019-10-16 11:13:12 +02:00
Yossi Gottlieb c469f6ad9e Code review minor changes (names, comments). 2019-10-15 17:21:51 +03:00
Yossi Gottlieb 71f10de4de Conns: write() 0 retval should not trigger error. 2019-10-15 17:20:58 +03:00
Yossi Gottlieb 0132189007 Fix compile warnings when BUILD_TLS=no. 2019-10-15 15:24:32 +03: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
antirez dd29d44136 Test: fix implementation-dependent test after code change. 2019-10-10 15:22:42 +02:00
Salvatore Sanfilippo 8e3d910d4e Merge pull request #6429 from charsyam/feature/typo-slave
[trivial] fix typos salves to slaves in replication.c
2019-10-10 14:56:43 +02:00
Salvatore Sanfilippo 363604a27d Merge pull request #6437 from OMG-By/redis-omg_by
there should is AUTH && HELLO non authenticated state.
2019-10-10 14:55:03 +02:00
Salvatore Sanfilippo 1677f4223c Merge pull request #6443 from guybe7/fix_stream_rax_node_limits
Fix usage of server.stream_node_max_*
2019-10-10 14:49:35 +02:00
Salvatore Sanfilippo 14a9da0613 Merge pull request #6145 from oranagra/jemalloc_purge_bg
purge jemalloc after flush, and enable background purging thread
2019-10-10 14:48:59 +02:00
Salvatore Sanfilippo 1d9d27c91a Merge pull request #6438 from daidaotong/unstable
resolve typo in test module
2019-10-10 11:18:47 +02:00
antirez 509fe9cba1 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-10-10 10:31:43 +02:00
antirez 747be463d2 Cluster: fix memory leak of cached master.
This is what happened:

1. Instance starts, is a slave in the cluster configuration, but
actually server.masterhost is not set, so technically the instance
is acting like a master.

2. loadDataFromDisk() calls replicationCacheMasterUsingMyself() even if
the instance is a master, in the case it is logically a slave and the
cluster is enabled. So now we have a cached master even if the instance
is practically configured as a master (from the POV of
server.masterhost value and so forth).

3. clusterCron() sees that the instance requires to replicate from its
master, because logically it is a slave, so it calls
replicationSetMaster() that will in turn call
replicationCacheMasterUsingMyself(): before this commit, this call would
overwrite the old cached master, creating a memory leak.
2019-10-10 10:23:34 +02:00
Guy Benoish 2fae0192e8 Fix usage of server.stream_node_max_* 2019-10-10 09:47:48 +02:00
Daniel Dai 98600c9a11 update typo 2019-10-09 14:15:31 -04:00
omg-by 1a292e0634 there should is AUTH && HELLO non authenticated state. 2019-10-10 00:52:26 +08:00
Salvatore Sanfilippo a92921da13 Merge pull request #6430 from jaamison/jj/unstable
stream.h: fix typo
2019-10-08 17:40:47 +02:00
Salvatore Sanfilippo 17bf0b25c1 Merge pull request #6427 from oranagra/static-analyzer
fix issues found by a static analyzer
2019-10-08 17:10:57 +02:00
antirez 009862ab7e Geo: output 10 chars of geohash, not 11.
This does not limit the actual precision, because the last digit bits were
garbage, and the shift value became even negative in the last iteration.
2019-10-08 17:09:37 +02:00
Yossi Gottlieb d7f2681a0c TLS: Improve CA certifiate configuration options.
This adds support for explicit configuration of a CA certs directory (in
addition to the previously supported bundle file).  For redis-cli, if no
explicit CA configuration is supplied the system-wide default
configuration will be adopted.
2019-10-08 17:58:50 +03:00
Yossi Gottlieb 61733ded14 TLS: Configuration options.
Add configuration options for TLS protocol versions, ciphers/cipher
suites selection, etc.
2019-10-07 21:07:27 +03:00
Oran Agra 6b6294807c TLS: Implement support for write barrier. 2019-10-07 21:06:30 +03:00
Oran Agra 5a47794606 diskless replication rdb transfer uses pipe, and writes to sockets form the parent process.
misc:
- handle SSL_has_pending by iterating though these in beforeSleep, and setting timeout of 0 to aeProcessEvents
- fix issue with epoll signaling EPOLLHUP and EPOLLERR only to the write handlers. (needed to detect the rdb pipe was closed)
- add key-load-delay config for testing
- trim connShutdown which is no longer needed
- rioFdsetWrite -> rioFdWrite - simplified since there's no longer need to write to multiple FDs
- don't detect rdb child exited (don't call wait3) until we detect the pipe is closed
- Cleanup bad optimization from rio.c, add another one
2019-10-07 21:06:30 +03:00
Yossi Gottlieb b087dd1db6 TLS: Connections refactoring and TLS support.
* Introduce a connection abstraction layer for all socket operations and
integrate it across the code base.
* Provide an optional TLS connections implementation based on OpenSSL.
* Pull a newer version of hiredis with TLS support.
* Tests, redis-cli updates for TLS support.
2019-10-07 21:06:13 +03:00
Jamison Judge 3ef6b79c80 stream.h: fix typo 2019-10-07 11:01:01 -07:00
antirez c65347ab17 LOLWUT: version 6: change text message & credits. 2019-10-07 19:19:38 +02:00
antirez c448f6fe55 LOLWUT: version 6: give credits. 2019-10-07 18:57:25 +02:00
antirez 58cdc054e3 LOLWUT: version 6: improve rithm of the image. 2019-10-07 18:41:29 +02:00
antirez c10889150e LOLWUT: version 6 initial output. May change a bit. 2019-10-07 18:24:34 +02:00
charsyam bea0384f5d fix type salves to slaves 2019-10-07 23:48:11 +09:00
antirez f019f28e7b LOLWUT: version 6 initial concept. 2019-10-07 12:35:17 +02:00
Oran Agra d1a005ab39 fix issues found by a static analyzer
cluster.c - stack buffer memory alignment
    The pointer 'buf' is cast to a more strictly aligned pointer type
evict.c - lazyfree_lazy_eviction, lazyfree_lazy_eviction always called
defrag.c - bug in dead code
server.c - casting was missing parenthesis
rax.c - indentation / newline suggested an 'else if' was intended
2019-10-07 09:09:32 +03:00
antirez bd60447066 LOLWUT: ability to specify VERSION <ver> option. 2019-10-04 19:19:54 +02:00
antirez 9073d56eec LOLWUT: refactoring + skeleton of LOLWUT 6. 2019-10-04 19:19:48 +02:00
Oran Agra 0f1969f16f trim the double implementation of jemalloc purge 2019-10-04 14:22:13 +03:00
Oran Agra bf759cc9c3 Merge remote-tracking branch 'antirez/unstable' into jemalloc_purge_bg 2019-10-04 13:53:40 +03:00
antirez ee1cef189f Minor aesthetic changes to #6419. 2019-10-04 12:00:41 +02:00
Salvatore Sanfilippo 264778af0a Merge pull request #6419 from oranagra/lua_timeout_sha
On LUA script timeout, print the script SHA to the log
2019-10-04 11:58:05 +02:00
Salvatore Sanfilippo c326f28833 Merge pull request #6308 from oranagra/repl-diskless-load-config
fix error handling on config parsing of repl-diskless-load
2019-10-04 11:56:08 +02:00
antirez 3eaff2941e Modules: RM_Call(): give pointer to documentation. 2019-10-04 11:46:53 +02:00
antirez 2a81e49dde Modules: RM_Call/Replicate() ability to exclude AOF/replicas. 2019-10-04 11:44:53 +02:00
antirez 1b8b8c029f Modules: add RM_Replicate() Tcl test file & fix the module. 2019-10-03 18:44:50 +02:00
antirez 55a3da87f8 Modules: RM_Replicate() test with threads. 2019-10-03 13:23:53 +02:00
antirez 45cd8e03ca Modules: RM_Replicate() test module: initial implementation. 2019-10-03 13:06:13 +02:00
antirez 1bca62c4b7 Modules: RM_Replicate() in thread safe contexts. 2019-10-03 11:03:46 +02:00
antirez e938bbc543 Modules: implement RM_Replicate() from async callbacks. 2019-10-03 10:56:37 +02:00
antirez c549513acd Modules: handle propagation when ctx is freed. Flag modules commands ctx. 2019-10-02 18:33:40 +02:00
Oran Agra 2e19b94113 RED-31295 - redis: avoid race between dlopen and thread creation
It seeems that since I added the creation of the jemalloc thread redis
sometimes fails to start with the following error:

Inconsistency detected by ld.so: dl-tls.c: 493: _dl_allocate_tls_init: Assertion `listp->slotinfo[cnt].gen <= GL(dl_tls_generation)' failed!

This seems to be due to a race bug in ld.so, in which TLS creation on the
thread, collide with dlopen.

Move the creation of BIO and jemalloc threads to after modules are loaded.

plus small bugfix when trying to disable the jemalloc thread at runtime
2019-10-02 15:39:44 +03:00
antirez 758b39be99 Speedup INFO server section. 2019-10-02 11:30:20 +02:00
antirez f49f0a6f72 SDS: make sdscatfmt() faster by pre-allocating a bit. 2019-10-02 11:30:20 +02:00
Oran Agra 98426e9886 On LUA script timeout, print the script SHA to the log
since the slowlog and other means that can help you detect the bad script
are only exposed after the script is done. it might be a good idea to at least
print the script name (sha) to the log when it timeouts.
2019-10-02 08:40:35 +03: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
antirez 40acb4412d GEORADIUS reply: fix of the previous fix about #6417. 2019-10-01 19:18:55 +02:00
Salvatore Sanfilippo 2e2fe98f9c Merge pull request #6270 from oranagra/modules_info
Extend modules API to allow modules report to redis INFO
2019-10-01 18:02:33 +02:00
antirez 3281ebb495 Fix GEORADIUS replies broken after RESP3 introduction.
This commit fixes #6417.
2019-10-01 10:38:56 +02:00
antirez beebb3c013 Merge branch 'hashed-pass-opcode' into unstable 2019-10-01 10:33:04 +02:00
Oran Agra 1b4f888109 Use sdscatfmt instead of sdscatprintf in module info
sdscatfmt is faster
2019-09-30 21:13:13 +03:00
Oran Agra d5c14c70b7 Merge remote-tracking branch 'antirez/unstable' into modules_info 2019-09-30 20:47:35 +03:00
antirez a9628142fd Clarify a comment about memory total_frag field. 2019-09-30 18:37:59 +02:00
antirez 09041b9359 ACLs: change hashed passwords opcode to also remove them.
Related to PR #6405
2019-09-30 18:28:45 +02:00
Madelyn Olson ea7c3fe7fd Allowed passing in of password hash and fixed config rewrite 2019-09-30 17:57:49 +02:00
Salvatore Sanfilippo eb2114b9cd Merge pull request #6411 from nikhilajayk/unstable
Added cluster host and protected mode variables to the create cluster script.
2019-09-30 17:46:09 +02:00
Salvatore Sanfilippo 2478b47b89 Merge pull request #6304 from dbenders/fix-issue-6141
Fix issue #6141: cluster rebalance does not support binary key
2019-09-30 17:43:58 +02:00
antirez 6a2831c24a Fix comments aesthetics. 2019-09-30 17:17:36 +02:00
antirez 23f5cb4233 Change a bit the style of #6385. 2019-09-30 10:58:15 +02:00
Salvatore Sanfilippo ad45d7e407 Merge pull request #6385 from filipecosta90/perf-reply-ss-error
Improve performance of RM_ReplyWithSimpleString and RM_ReplyWi…
2019-09-30 10:57:05 +02: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
antirez 916c4e5d86 moduleRDBLoadError(): io->ctx may be NULL.
The correct way to access the module about a given IO context is to
deference io->type->module, since io->ctx is only populated if the user
requests an explicit context from an IO object.
2019-09-27 18:42:38 +02:00
antirez 8b5848a4f5 Fix memory leak in moduleLoadFromQueue(). 2019-09-27 18:33:21 +02:00
antirez b394817754 Fix memory leak in RM_UnregisterCommandFilter(). 2019-09-27 18:33:05 +02:00
antirez 0a07f8ffee TerminateModuleForkChild(): fix function prototype. 2019-09-27 12:23:07 +02:00
antirez 721d3c9e0c TerminateModuleForkChild(): move safety checks there.
We don't want that the API could be used directly in an unsafe way,
without checking if there is an active child. Now the safety checks are
moved directly in the function performing the operations.
2019-09-27 12:17:47 +02:00
antirez de1f82aa33 Function renamed hasForkChild() -> hasActiveChildProcess(). 2019-09-27 12:03:09 +02:00
antirez 82845f8d04 TerminateModuleForkChild(): use wait4 for safety.
In theory currently there is only one active child, but the API may
change or for bugs in the implementation we may have several (it was
like that for years because of a bug). Better to wait for a specific
pid and avoid consuing other pending children information.
2019-09-27 11:59:58 +02:00
antirez beb1356b5b Improve error message in BGSAVE. 2019-09-27 11:59:37 +02:00
antirez ae3ef964c1 Modules fork: improve SIGUSR1 handling, fix include.
We can't expect SIGUSR1 to have any specific value range, so let's
define an exit code that we can handle in a special way.
This also fixes an #include <wait.h> that is not standard.
2019-09-27 11:39:45 +02:00
Salvatore Sanfilippo b7c33af4a5 Merge pull request #6247 from oranagra/modules_fork
Module API for Forking
2019-09-27 11:24:45 +02:00
Salvatore Sanfilippo 6129758558 Merge branch 'unstable' into modules_fork 2019-09-27 11:24:06 +02: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
nikhilajayk 6578119a23 Added cluster host and protected mode variables 2019-09-26 21:51:49 +05:30
antirez fddc4757c8 BGREWRITEAOF: improve the generic error message. 2019-09-26 16:14:21 +02:00
Oran Agra 83e87bac76 Fix lastbgsave_status, when new child signal handler get intended kill
And add a test for that.
2019-09-26 15:16:34 +03:00
antirez b7b23bdfb8 INFO: more info about loaded modules.
Related to #6024.
2019-09-26 12:18:55 +02:00
Salvatore Sanfilippo c1ea6175c5 Merge pull request #6024 from itamarhaber/info_modules
Adds a "Modules" section to `INFO`
2019-09-26 11:58:52 +02:00
Salvatore Sanfilippo 959fb5cf68 Merge pull request #6235 from oranagra/module_rdb_load_errors
Allow modules to handle RDB loading errors.
2019-09-26 11:52:42 +02:00
Salvatore Sanfilippo b0a90d8fa8 Merge pull request #4980 from yossigo/rm-assert
Add RedisModule_Assert() API call.
2019-09-26 11:39:29 +02:00
filipecosta90 af15b285fa [fix] fixed the un-refactor bug. 2019-09-25 17:28:42 +01:00
Salvatore Sanfilippo 388bc55344 Merge pull request #6354 from jaredzhu/aarch64-devel
Add aarch64 uc_mcontext debug dump info
2019-09-25 18:14:24 +02:00
antirez b3d6cb268a Modify #6401 changes to fit 80 cols. 2019-09-25 18:08:11 +02:00
Salvatore Sanfilippo f3aaf2b4d8 Merge pull request #6401 from valentinogeron/fix-discard-during-oom
DISCARD should not fail during OOM
2019-09-25 18:07:25 +02:00
Salvatore Sanfilippo f6cf08e582 Merge pull request #6402 from mieko/unstable
Seed SipHash with 128-bit key
2019-09-25 18:03:39 +02:00
antirez 8a531cedb0 ACL: fix ##6408, default user state affecting all the connections. 2019-09-25 17:45:05 +02:00
Mike A. Owens 0a4d2bbd9c Seed SipHash with 128-bit key
SipHash expects a 128-bit key, and we were indeed generating 128-bits,
but restricting them to hex characters 0-9a-f, effectively giving us
only 4 bits-per-byte of key material, and 64 bits overall.

Now, we skip the hex conversion and supply 128 bits of unfiltered
random data.
2019-09-23 19:24:09 -04:00
filipecosta90 733280d9cb [fix] un-refactor the code. [perf] replyWithStatus now makes usage of addReplyProto 2019-09-23 23:45:31 +01:00
antirez eda703ab28 redis-cli: support for ACL style user/pass AUTH. 2019-09-23 19:57:13 +02:00
antirez b21dd082c3 redis-cli: CSV and RAW target for more RESP3 types. 2019-09-23 19:36:06 +02:00
antirez cc108057ff redis-cli: ability to start a session in RESP3 mode. 2019-09-23 17:55:05 +02:00
antirez 8ea185ea30 redis-cli: AUTH can now have 3 arguments as well. 2019-09-23 17:47:36 +02:00
antirez bb7546c913 RESP3: varbatim handling for other redis-cli outputs. 2019-09-23 17:42:57 +02:00
antirez 5e399d5d33 hiredis udpated (RESP3 WIP). 2019-09-23 17:41:04 +02:00
antirez 264708427b RESP3: implementation of verbatim output with TTY target. 2019-09-23 17:39:42 +02:00
valentino 7a73b7f168 DISCARD should not fail during OOM
discard command should not fail during OOM, otherwise client MULTI state
will not be cleared.
2019-09-22 09:22:53 +03:00
antirez c3899720f6 hiredis updated to master version. 2019-09-20 20:08:38 +02:00
David Carlier 5a8a005026 Adding AnonHugePages case + comments 2019-09-20 11:01:36 +01:00
antirez 2e4fa7bb48 Make config.c always_replicate_commands more uniform.
Better if it resembles the other similar code paths.
2019-09-20 11:46:35 +02:00
antirez 1dd36347ed Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-09-20 11:45:02 +02:00
antirez 630638dcde Remove redundant statement in config.c.
Thanks to @guybe7 for spotting the error in the original PR I merged.
2019-09-20 11:44:32 +02:00
Salvatore Sanfilippo f135d6295b Merge pull request #6367 from Dolondro/unstable
Spelling: Typo fixes for API documentation
2019-09-20 11:33:58 +02:00
Salvatore Sanfilippo 3976f4c88e Merge pull request #6368 from suntw2015/unstable
fix rdb function rdbLoadIntegerObject comment
2019-09-20 11:33:27 +02:00
Salvatore Sanfilippo d0050db236 Merge pull request #6389 from ocadaruma/patch-1
Fix typos in hyperloglog.c
2019-09-20 11:24:07 +02:00
Salvatore Sanfilippo 975eb73145 Merge pull request #6400 from mors741/unstable
Fix compilation error
2019-09-20 11:19:56 +02:00
antirez 0a146a8be4 Add useless break for uniformity / future protection. 2019-09-20 11:19:07 +02:00
Salvatore Sanfilippo bd90c99f83 Merge pull request #6398 from trevor211/fixRESP3ToLuaBool
RESP3: Fix function redisProtocolToLuaType about RESP3->Lua bools.
2019-09-20 11:15:20 +02:00
Salvatore Sanfilippo f42ac40d7c Merge pull request #6397 from trevor211/fixConfigWrongFormatHandling
Fix bad handling of unexpected yesno option
2019-09-20 11:14:38 +02:00
Evgeny a1a65d238c Fix compilation error 2019-09-20 01:11:20 -07:00
WuYunlong 30a3644e64 RESP3: Fix function redisProtocolToLuaType about RESP3->Lua bools. 2019-09-20 08:37:23 +08:00
WuYunlong 74e3a622a2 Fix bad handling of unexpected option while loading config "lua-replicate-commands". 2019-09-20 08:14:36 +08: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
antirez 474a923160 RESP3: Use verbatim in LATENCY subcommands. 2019-09-18 18:53:22 +02:00
antirez cb384127d1 RESP3: Use verbatim in CLIENT LIST. 2019-09-18 18:52:13 +02:00
antirez dd2f695d7e RESP3: Use verbatim in CLUSTER subcommands. 2019-09-18 18:51:15 +02:00
antirez 1b3cb3b0de RESP3: Use verbatim in MEMORY subcommands. 2019-09-18 18:48:14 +02:00
antirez ff9a5d231b RESP3: Use verbatim in DEBUG HTSTATS / HTSTATS-KEY. 2019-09-18 18:46:11 +02:00
antirez aca5482fbf RESP3: Use verbatim in INFO output. 2019-09-18 18:33:13 +02:00
antirez 68519b7034 RESP3: Verbatim conversion test in the LOLWUT command.
redis-cli is currently not able to handle it after going in RESP3 mode,
because of hiredis limitations.
2019-09-18 18:28:51 +02:00
antirez 8ea4bdd91d RESP3: Lua double -> RESP3 conversion. 2019-09-17 19:26:46 +02:00
antirez 89f929b12a RESP3: RESP3 double -> Lua conversion. 2019-09-17 19:20:30 +02:00
antirez 19aba4ac78 RESP3: double -> human readable conversion. 2019-09-17 19:08:33 +02:00
antirez e8e30bc402 RESP3: bool and null values in RESP -> human readable conversion. 2019-09-17 18:57:24 +02:00
Okada Haruki c1cc5ca767 Fix typo 2019-09-17 06:18:01 +09:00
antirez f01f0c02d1 RESP3: convert RESP3 null as Lua nil. Implement RESP3->Lua bools. 2019-09-16 18:36:16 +02:00
antirez 6931004969 RESP3: change behavior of Lua returning true/false for RESP3.
Here we introduce a change in the way we convert values from Lua to
Redis when RESP3 is selected: this is possible without breaking the fact
we can return directly what a command returned, because there is no
Redis command in RESP2 that returns true or false to Lua, so the
conversion in the case of RESP2 is totally arbitrary. When a script is
written selecting RESP3 from Lua, it totally makes sense to change such
behavior and return RESP3 true/false when Lua true/false is returned.
2019-09-16 18:18:17 +02:00
antirez 2cc4d0286c RESP3: implement new NULL representation parsing in Lua. 2019-09-16 17:49:47 +02:00
antirez ca81d49006 RESP3: handle set Lua -> Redis conversion. 2019-09-16 12:19:19 +02:00
antirez c792504fab RESP3: handle map Lua -> Redis conversion. 2019-09-16 12:15:39 +02:00
antirez dad38c19c8 RESP3: report set/map as nested tables to Lua. 2019-09-16 11:49:42 +02:00
filipecosta90 4a30a26f8f [add] improved performance of RM_ReplyWithSimpleString and RM_ReplyWithError by making usage addReplyProto instead of addReplySds 2019-09-15 21:16:30 +01:00
David Carlier 819a661be5 Getting region date per process in Darwin 2019-09-15 14:05:00 +01:00
antirez 888efc1b36 RESP3: Lua parsing should depend on lua client, not lua caller.
We want all the scripts to run in RESP2 mode by default. It's up to the
caller to switch to V3 using redis.setresp() if it is really needed.
This way most scripts written for past Redis versions will continue to
work with Redis >= 6 even if the client is in RESP3 mode.
2019-09-13 19:38:39 +02:00
antirez 26b6c697d3 RESP3: Lua debugger support for printing sets and maps. 2019-09-13 19:19:10 +02:00
antirez 93c52ff5ff RESP3: implement lua.setresp(). 2019-09-13 19:01:39 +02:00
John Sully 18d42a5c35 KEYS now only blocks one database 2019-09-12 18:51:10 -04:00
antirez b170a01fa7 ACL: store hashed passwords in memory.
Note that this breaks API compatibility with Redis < 6:

    CONFIG GET requirepass

Will no longer return a cleartext password as well, but the SHA256 hash
of the password set.
2019-09-12 12:54:57 +02:00
antirez ae5054b476 ACL: SHA256 based password hashing function implemented. 2019-09-12 12:33:22 +02:00
antirez 9d2ecf6be3 ACL: add slightly modified version of sha256.c for password hashing.
memory.h include removed, types substituted with stdint types.
2019-09-12 12:21:37 +02:00
antirez f4d37173fe ACL: protect MULTI/EXEC transactions after rules change. 2019-09-11 19:42:10 +02: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
antirez ae8cab3296 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-09-06 12:24:40 +02:00
antirez a092f20d87 handleClientsBlockedOnKeys() refactoring. 2019-09-06 12:24:26 +02:00
suntiawnen 781f3fd8be fix rdb function rdbLoadIntegerObject comment 2019-09-06 12:01:44 +08:00
Doug Nelson cc8f06ece9 Typo fixes in API documentation 2019-09-05 16:25:06 +01:00
Salvatore Sanfilippo 86aade9a02 Merge pull request #6364 from oranagra/fix_module_aux_when
Fix to module aux data rdb format for backwards compatibility with old check-rdb
2019-09-05 13:30:26 +02:00
Oran Agra 3bfcae247a Fix to module aux data rdb format for backwards compatibility with old check-rdb
When implementing the code that saves and loads these aux fields we used rdb
format that was added for that in redis 5.0, but then we added the 'when' field
which meant that the old redis-check-rdb won't be able to skip these.
this fix adds an opcode as if that 'when' is part of the module data.
2019-09-05 14:11:37 +03:00
antirez 89ad0ca566 Fix handleClientsBlockedOnKeys() names in comments. 2019-09-05 13:05:57 +02:00
antirez 12c56a8e75 redis-cli: always report server errors on read errors.
Before this commit we may have not consumer buffers when a read error is
encountered. Such buffers may contain errors that are important clues
for the user: for instance a protocol error in the payload we send in
pipe mode will cause the server to abort the connection. If the user
does not get the protocol error, debugging what is happening can be a
nightmare.

This commit fixes issue #3756.
2019-09-04 17:55:46 +02:00
antirez f7090f43ad AOF: be future-proof and close the file pointer.
Currently useless but we release the fake client, so better to do a full
cleanup. Thanks to @TomMD reporting this in #6353.
2019-09-04 17:20:37 +02:00
zhudacai 00228490 66a5c1cd7e The aarch64 architecture is support normal memory unaligned accesses,
so add the UNALIGNED_LE_CPU to the aarch64 .
2019-09-04 12:14:25 +00:00
antirez b2e10131c0 Rio: fix flag name, function is never used btw.
Thanks to @tnclong for reporting the problem.
2019-09-04 13:01:07 +02:00
antirez 06d490342f RESP3: fix cases of NULL reported instead of empty aggregate. 2019-09-02 12:50:47 +02:00
antirez b12ccc840e Cluster: abort loading nodes data if vars arguments are unbalanced.
See for reference PR #6337. Thanks to @git-hulk for spotting this.
2019-09-02 11:41:20 +02:00
antirez e57067b677 More strict checks and better comments in flushSlaveOutputBuffers().
Related to #6296.
2019-08-31 14:46:24 +02:00
antirez 2303ba1441 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-08-31 14:41:28 +02:00
antirez ca5ccc58c5 Improve comment in flushSlavesOutputBuffers(). 2019-08-31 14:40:09 +02:00
Salvatore Sanfilippo 16435e02bf Merge pull request #6296 from soloestoy/flushSlavesOutputBuffers-bugfix
networking: flushSlavesOutputBuffers bugfix
2019-08-31 14:39:33 +02:00
zhudacai 00228490 d7c25806c0 src/debug.c do not support aarch64 dump utcontext, so add the context
of aarch64.
The content comes from the definition of the sigcontext and tested on
my aarch64 server.

sigcontext defined at the linux kernel code:
arch/arm64/include/uapi/asm/sigcontext.h
2019-08-31 07:47:11 +00:00
jared 5cbc73c657 Merge pull request #1 from antirez/unstable
merge redis
2019-08-30 17:25:56 +08: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
Oran Agra 78bbb9b58d Modlue fork is killed when the parent exists 2019-08-25 10:11:48 +03:00
Salvatore Sanfilippo d5536e0480 Merge pull request #6307 from oranagra/register_rm_reply_with_cstring
RM_ReplyWithCString was missing registration
2019-08-22 20:02:17 +02:00
Oran Agra 61853ad8de Module INFO, support default section for simple modules 2019-08-18 10:01:57 +03:00
Oran Agra 1d6e5dc4dc Module INFO, add support for dict fields, rename API to have common prefix 2019-08-18 09:41:45 +03:00
John Sully 33e0b3e1c0 Fix warnings on newer compilers 2019-08-14 01:03:24 -04:00
Oran Agra 1026d2caf8 fix error handling on config parsing of repl-diskless-load 2019-08-08 14:53:36 +03:00
Oran Agra 0a97149dec RM_ReplyWithCString was missing registration 2019-08-07 13:06:11 +03: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
Diego Bendersky b27f388344 pass len to alloc in clusterManagerMigrateKeysInReply 2019-08-05 17:35:50 -03:00
antirez 0e9b5adbd3 Replication: clarify why repl_put_online_on_ack exists at all. 2019-08-05 17:38:15 +02:00
John Sully 75c6b4c64a Optimize the new expire code 2019-08-02 21:31:05 -04:00
antirez 5e0faf4959 tracking_collisions.c: sha1 + crc64 implemented. 2019-08-02 20:24:27 +02:00
antirez a368209b1d tracking_collisions.c: initial skeleton.
... of a program to just test the hashing functions collisions on a 24
bit output with strings that are very likely Redis key names, and names
of a kind that are particularly prone to collisions.
2019-08-02 20:13:21 +02:00
zhaozhao.zz d3f7eb0c87 networking: flushSlavesOutputBuffers bugfix 2019-08-02 17:17:19 +08:00
antirez 583933e2d6 Fix regression causing EXEC to appear in the slow log.
This was recently introduced with PR #6266.
2019-07-31 19:05:20 +02:00
antirez 2a8a63af44 Make EMBSTR case of #6261 more obvious. 2019-07-31 12:03:10 +02:00
Salvatore Sanfilippo f899c31fbc Merge pull request #6261 from chendq8/robj
make memory usage consistent of robj with OBJ_ENCODING_INT
2019-07-31 11:54:11 +02:00
Salvatore Sanfilippo fc5c2052b5 Merge pull request #6266 from madolson/dev-unstable-hide-auth-and-hello
Hide HELLO and AUTH from slowlog and monitor
2019-07-31 11:12:46 +02:00
antirez e1b13b4d39 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-31 10:37:17 +02:00
antirez b2079cb508 HyperLogLog: fix the fix of a corruption bug. 2019-07-31 10:36:23 +02: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
Salvatore Sanfilippo f0c10d4360 Merge pull request #6277 from devnexen/fbsd_get_rss
Updating resident memory request impl on FreeBSD.
2019-07-30 18:24:38 +02:00
Oran Agra 40c4183196 Log message when modules prevent diskless-load 2019-07-30 16:32:58 +03:00
Oran Agra 07b1abab95 Add test for module diskless short reads 2019-07-30 15:20:03 +03:00
Oran Agra e5187ad2ae Merge remote-tracking branch 'oss/unstable' into module_rdb_load_errors 2019-07-30 15:14:08 +03:00
Oran Agra 4339706e07 Avoid diskelss-load if modules did not declare they handle read errors 2019-07-30 15:11:57 +03:00
Salvatore Sanfilippo f42846e8c7 Merge pull request #6264 from oranagra/modules_api_aux_rdb
Implement module api for aux data in rdb
2019-07-30 11:50:44 +02:00
Salvatore Sanfilippo ce72cac0f8 Merge pull request #6269 from wubostc/patch-1
Reduce the calling stack
2019-07-30 11:41:48 +02:00
antirez e4b3c8bbc3 emptyDbGeneric(): call signalFlushDb() before deleting the keys.
This was broken since a refactoring performed recently by myself.
2019-07-30 11:20:54 +02:00
Salvatore Sanfilippo cc8125a779 Merge pull request #6282 from JohnSully/hll_corruption
Fix HLL corruption bug
2019-07-30 10:24:28 +02:00
John Sully d659654f53 Fix HLL corruption bug 2019-07-29 18:11:52 -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
David Carlier f1c6c658ac Updating resident memory request impl on FreeBSD. 2019-07-28 14:33:57 +01:00
antirez 505a855000 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-25 19:18:26 +02:00
antirez 0714581e0c Mark diskless loads as experimental in redis.conf. 2019-07-25 19:17:58 +02:00
Salvatore Sanfilippo 5591a14c0a Merge pull request #6248 from oranagra/module-log
RM_Log - add support for logging without a context or context without module
2019-07-25 18:48:46 +02: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
Oran Agra e91d9a6fff Extend modules API to allow modules report to redis INFO
this implements #6012
2019-07-24 12:58:15 +03:00
antirez fde5e737dc Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-24 11:45:19 +02:00
antirez e53a26b5d8 Client side caching: document tracking-table-max-fill in redis.conf. 2019-07-24 11:45:10 +02:00
antirez 0b780a5477 Example redis.conf: stay under 80 cols. 2019-07-24 11:38:11 +02:00
antirez 32efd9adf8 Client side caching: config option for table fill rate. 2019-07-24 11:35:01 +02:00
antirez a67d0411e7 Remove experimental warning from diskless replication. 2019-07-24 11:33:53 +02:00
wubostc 48f4cfb601 Reduce the calling stack 2019-07-24 16:22:26 +08: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
Salvatore Sanfilippo dbee7ca007 Merge pull request #6265 from madolson/dev-unstable-remove-create-object
Removed unnecessary creation of Redis objects
2019-07-23 17:05:10 +02:00
antirez c98e7717bb Client side caching: show tracking slots usage in INFO. 2019-07-23 11:02:14 +02:00
antirez 9268493e8d Client side caching: implement full slot limit function. 2019-07-23 10:57:22 +02:00
Salvatore Sanfilippo 47ce1cebeb Merge pull request #6267 from soloestoy/opt-claim-trackingtable
Client side caching: do not reclaim tracking table if it's empty
2019-07-23 09:43:41 +02:00
zhaozhao.zz 9012e587ca Client side caching: do not reclaim tracking table if it's empty 2019-07-23 15:25:00 +08:00
Madelyn Olson 7d21754710 Hide HELLO and AUTH from slowlog and monitor 2019-07-22 22:53:15 -07:00
Madelyn Olson 8fe173452a Removed unecessary creation of Redis objects 2019-07-22 22:52:16 -07:00
Oran Agra 3b6aeea44c Implement module api for aux data in rdb
Other changes:
* fix memory leak in error handling of rdb loading of type OBJ_MODULE
2019-07-22 21:15:33 +03:00
antirez c41f94d2a3 Client side caching: split invalidation into key / slot. 2019-07-22 18:59:53 +02:00
antirez 09c06698e9 Client side caching: redis-cli ability to enable tracking.
This is extremely useful in order to simulate an high load of requests
about different keys, and force Redis to track a lot of informations
about several clients, to simulate real world workloads.
2019-07-22 18:45:47 +02:00
antirez 436d02dd7b Move signalFlushedDb() into a better place.
Now that the call also invalidates client side caching slots, it is
important that after an internal flush operation we both send the
notifications to the clients and, at the same time, are able to reclaim
the memory of the tracking table. This may even fix a few edge cases
related to MULTI/EXEC + WATCH during resync, not sure, but in general
looks more correct.
2019-07-22 12:37:47 +02:00
antirez 7d3992a80a Client side caching: reclaim the tracking table on FLUSHALL. 2019-07-22 12:33:49 +02:00
antirez 842b44dc46 Client side caching: call the invalidation functions always.
Otherwise what happens is that the tracking table will never get garbage
collected if there are no longer clients with tracking enabled.
Now the invalidation function immediately checks if there is any table
allocated, otherwise it returns ASAP, so the overhead when the feature
is not used should be near zero.
2019-07-22 12:29:54 +02:00
antirez f850201c64 Client side caching: don't hash the key if not needed. 2019-07-22 12:10:51 +02:00
antirez e00442eb13 Clinet side caching: take count of used caching slots. 2019-07-22 11:47:44 +02:00
chendianqiang 004c26ec28 make memory usage consistent of robj with OBJ_ENCODING_INT 2019-07-22 17:45:30 +08:00
Oran Agra d7d028a7a7 Allow modules to handle RDB loading errors.
This is especially needed in diskless loading, were a short read could have
caused redis to exit. now the module can handle the error and return to the
caller gracefully.

this fixes #5326
2019-07-21 18:19:32 +03:00
John Sully ff682d7902 Modules must have execute permissions to load 2019-07-19 15:28:31 -04:00
John Sully 156e596f9c Any +x bit is acceptable 2019-07-19 15:26:17 -04:00
antirez bc5cb168f5 RDB: fix MODULE_AUX loading by continuing to next opcode.
Thanks to @JohnSully for noticing this problem.
2019-07-19 11:12:46 +02:00
John Sully fc58516cca Any +x bit is acceptable 2019-07-19 01:42:05 -04:00
John Sully 70534846d1 Modules must have execute permissions to load 2019-07-19 01:37:34 -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
antirez 5f450e4928 RDB: make sure to abort on LZF encoding error. 2019-07-18 18:59:38 +02:00
antirez bd0f06c18c 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-18 18:51:45 +02:00
Salvatore Sanfilippo 41ed85bd26 Merge pull request #6252 from soloestoy/tracking-flushdb
Tracking flushdb
2019-07-18 16:41:37 +02:00
antirez 947319cadd RDB: update rdbLoadRio comment about EOF condition. 2019-07-18 12:37:55 +02:00
zhaozhao.zz f59119aad6 Client side caching: filter clients untracking 2019-07-18 16:46:19 +08:00
John Sully 4e30a5b4e5 Another RESP3 regression 2019-07-17 22:57:52 -04:00
antirez 42b6305964 RDB: try to make error handling code more readable. 2019-07-17 17:30:02 +02:00
antirez 6b72b04a37 Rio: when in error condition avoid doing the operation. 2019-07-17 16:46:22 +02:00
antirez 5189db3d81 RDB: modify rdbReportError() var name for clarity. 2019-07-17 16:46:22 +02:00
antirez 48d91cf4cc Rio: remember read/write error conditions. 2019-07-17 16:46:22 +02:00
Oran Agra c56b4ddc6f prevent diskless replica from terminating on short read
now that replica can read rdb directly from the socket, it should avoid exiting
on short read and instead try to re-sync.

this commit tries to have minimal effects on non-diskless rdb reading.
and includes a test that tries to trigger this scenario on various read cases.
2019-07-17 16:46:22 +02:00
Oran Agra 56258c6b7d Module API for Forking
* create module API for forking child processes.
* refactor duplicate code around creating and tracking forks by AOF and RDB.
* child processes listen to SIGUSR1 and dies exitFromChild in order to
  eliminate a valgrind warning of unhandled signal.
* note that BGSAVE error reply has changed.

valgrind error is:
  Process terminating with default action of signal 10 (SIGUSR1)
2019-07-17 16:40:24 +03:00
zhaozhao.zz 6191ea90a1 Client side caching: implement trackingInvalidateKeysOnFlush() 2019-07-17 20:33:52 +08:00
Oran Agra 6e07fac405 RM_Log - add support for logging without a context or context without module
for instance detached thread safe contexts, or various callbacks that don't
provide a context.
2019-07-17 15:08:18 +03:00
antirez 241d18d954 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-17 12:26:38 +02: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
Salvatore Sanfilippo 5827b69861 Merge pull request #6185 from AlexRenCN/unstable
fix readme.md,Redis data types should add `t_stream.c`.
2019-07-16 18:33:55 +02:00
Salvatore Sanfilippo 4b2579a064 Merge pull request #5779 from madolson/dev-unstable-geo-bugfix
Fixed a rounding bug in geo.tcl
2019-07-15 23:41:57 +02: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
Salvatore Sanfilippo 3f1c84751a Merge pull request #6196 from AngusP/resp3
[RESP3, Minor] in networking.c double representation for -infiinity leaves out comma
2019-07-12 13:08:46 +02:00
Salvatore Sanfilippo 6100a82a3a Merge pull request #5738 from bmerry/fix-swapdb-int-overflow
Make dbSwapDatabases take args as long
2019-07-12 12:36:33 +02:00
antirez 54c4e7f86c Vertically compact code in aofWrite(). 2019-07-12 12:18:33 +02: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
antirez 2a99f199bc Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-10 19:48:44 +02:00
antirez dad0e916ff Client side caching: filter clients no longer there. 2019-07-10 19:46:46 +02:00
Salvatore Sanfilippo 7567323071 Merge pull request #6198 from oranagra/skiplist-mem-usage
missing per-skiplist overheads in MEMORY USAGE
2019-07-10 19:43:24 +02:00
antirez c7aaf8db4d Client side caching: implement CLIENT GETREDIR.
This subcommand may simplify the writing of Redis client libraries
using the tracking feature and/or improve observability and debugging
capabilities.
2019-07-10 18:17:10 +02:00
antirez 923e4fb312 Client side caching: add tracking clients in INFO. 2019-07-10 18:08:31 +02:00
antirez 7c9f6ebc8f Diskless replica: fix disklessLoadRestoreBackups() bug. 2019-07-10 12:36:26 +02:00
antirez 3bbb9a1413 Diskless replica: refactoring of DBs backups. 2019-07-10 11:42:26 +02:00
antirez 3300e98ff0 Diskless replica: fix mispelled var name. 2019-07-10 09:34:21 +02:00
antirez dfcbeaf115 Diskless replica: a few aesthetic changes to rio.c 2019-07-08 18:39:59 +02:00
antirez 81b18fa3a0 Diskless replica: a few aesthetic changes to replication.c. 2019-07-08 18:32:47 +02:00
Salvatore Sanfilippo d984732b35 Merge pull request #6193 from oranagra/diskless_slave_refresh3
diskless replication on slave side (don't store rdb to file), plus some other related fixes
2019-07-08 18:10:16 +02:00
Oran Agra 2de544cfcc diskless replication on slave side (don't store rdb to file), plus some other related fixes
The implementation of the diskless replication was currently diskless only on the master side.
The slave side was still storing the received rdb file to the disk before loading it back in and parsing it.

This commit adds two modes to load rdb directly from socket:
1) when-empty
2) using "swapdb"
the third mode of using diskless slave by flushdb is risky and currently not included.

other changes:
--------------
distinguish between aof configuration and state so that we can re-enable aof only when sync eventually
succeeds (and not when exiting from readSyncBulkPayload after a failed attempt)
also a CONFIG GET and INFO during rdb loading would have lied

When loading rdb from the network, don't kill the server on short read (that can be a network error)

Fix rdb check when performed on preamble AOF

tests:
run replication tests for diskless slave too
make replication test a bit more aggressive
Add test for diskless load swapdb
2019-07-08 15:37:48 +03:00
Salvatore Sanfilippo 722446510f Merge pull request #6116 from AngusP/scan-types
SCAN: New Feature `SCAN cursor [TYPE type]` modifier suggested in issue #6107
2019-07-08 12:53:34 +02:00
Angus Pearson 6eb52e200c Change typeNameCanonicalize -> getObjectTypeName, and other style changes 2019-07-08 11:04:37 +01:00
Salvatore Sanfilippo 4c4b7023dd Merge pull request #6210 from gkorland/patch-3
fix build tracking.c should be tracking.o
2019-07-07 17:49:17 +02:00
Guy Korland 2d07883cab fix build tracking.c should be tracking.o
thanks to @rafie
2019-07-07 18:28:15 +03:00
Salvatore Sanfilippo e8ae07aabf Merge pull request #6162 from madolson/dev-unstable-config-refactor
Refactored yesno configs so there is less duplication
2019-07-07 17:13:11 +02:00
Salvatore Sanfilippo 677e95e2f5 Merge pull request #6161 from swilly22/redismodule-loading-ctx-flag
Extend REDISMODULE_CTX_FLAGS to indicate if redis is  loading
2019-07-07 17:01:29 +02: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
Salvatore Sanfilippo a714004738 Merge pull request #6022 from itamarhaber/RedisModule_ReplyWithCString
Adds RedisModule_ReplyWithCString
2019-07-05 20:25:18 +02:00
antirez 6b29f2d83d Client side caching: RESP2 support. 2019-07-05 12:24:28 +02:00
antirez f099def733 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-07-04 18:34:53 +02:00
Oran Agra 41c5ebcab6 missing per-skiplist overheads in MEMORY USAGE
these had severe impact for small zsets, for instance ones with just one
element that is longer than 64 (causing it not to be ziplist encoded)
2019-07-04 15:20:49 +03:00
antirez 3e43aed1ac Client side caching: fix invalidate message len and content. 2019-07-04 14:07:23 +02:00
antirez 46edb55de9 Client side caching: implement trackingInvalidateKey(). 2019-07-03 19:16:20 +02:00
antirez 506764b3f8 Client side caching: hook inside call() for tracking. 2019-07-03 12:42:16 +02:00
antirez db16a861a1 Client side caching: CLIENT TRACKING subcommand. 2019-07-03 11:58:20 +02:00
Angus Pearson 593f6656c1 RESP3 double representation for -infinity is ,-inf\r\n, not -inf\r\n 2019-07-02 14:28:48 +01:00
antirez c29f3bcf2e Client side caching: enable tracking mode. 2019-06-30 06:19:08 -04:00
antirez 45d64f229e Client side caching: fields and flags for tracking mode. 2019-06-29 20:08:41 -04:00
antirez a28d7918d7 Client side caching: add new file and description. 2019-06-29 09:09:38 -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
zheng.ren01@mljr.com 2d236d7aec fix readme.md,Redis data types should add t_stream.c. 2019-06-25 18:34:35 +08: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
Madelyn Olson dd51fc5a4a Refactored yesno configs so there was less duplication 2019-06-13 12:18:25 -07:00
Angus Pearson 38cd5fd9f6 Spelling cannonical -> canonical 2019-06-13 17:49:33 +01:00
swilly22 f54d95e803 Extend REDISMODULE_CTX_FLAGS to indicate if redis is currently loading from either RDB or AOF 2019-06-12 15:37:19 +03:00
John Sully 46d6caa47c Enable load balancing of UNIX sockets across threads 2019-06-11 01:34:36 -04:00
Angus Pearson e2adea2188 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-06-10 17:41:44 +01:00
Salvatore Sanfilippo 0cabe0cfa7 Merge pull request #6149 from madolson/acl-spelling
Fixed some spelling issues in ACL codepath including a user facing error
2019-06-07 22:54:52 +02:00
Madelyn Olson dd5f437871 Fixed some spelling issues in ACL codepath including user facing error 2019-06-07 13:25:22 -07:00
Salvatore Sanfilippo de035c9481 Merge pull request #6148 from artix75/redis_bm_dev
Redis Benchmark: prevent CONFIG failure from exiting program
2019-06-05 17:29:50 +02:00
artix d3ed53f11b Redis Benchmark: prevent CONFIG failure from exiting program 2019-06-05 16:34:55 +02:00
John Sully 97b65ce19c Fix crash adding duplicate replica. Just send an error instead 2019-06-02 15:50:50 -04:00
Oran Agra 09f99c2a92 make redis purge jemalloc after flush, and enable background purging thread
jemalloc 5 doesn't immediately release memory back to the OS, instead there's a decaying
mechanism, which doesn't work when there's no traffic (no allocations).
this is most evident if there's no traffic after flushdb, the RSS will remain high.

1) enable jemalloc background purging
2) explicitly purge in flushdb
2019-06-02 15:33:14 +03:00
Oran Agra 2fec7d9c6c Jemalloc: Avoid blocking on background thread lock for stats.
Background threads may run for a long time, especially when the # of dirty pages
is high.  Avoid blocking stats calls because of this (which may cause latency
spikes).

see https://github.com/jemalloc/jemalloc/issues/1502

cherry picked from commit 1a71533511027dbe3f9d989659efeec446915d6b
2019-06-02 15:27:38 +03:00
John Sully 55d0ef40b0 Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-06-01 03:23:21 -04:00
Yuan Zhou 412eb67d21 aof: fix assignment for aof_fsync_offset
Signed-off-by: Yuan Zhou <yuan.zhou@intel.com>
2019-05-29 14:48:46 +08:00
Angus Pearson bf963253ec Implement SCAN cursor [TYPE type] modifier suggested in issue #6107.
Add tests to check basic functionality of this optional keyword, and also tested with
a module (redisgraph). Checked quickly with valgrind, no issues.

Copies name the type name canonicalisation code from `typeCommand`, perhaps this would
be better factored out to prevent the two diverging and both needing to be edited to
add new `OBJ_*` types, but this is a little fiddly with C strings.

The [redis-doc](https://github.com/antirez/redis-doc/blob/master/commands.json) repo
will need to be updated with this new arg if accepted.

A quirk to be aware of here is that the GEO commands are backed by zsets not their own
type, so they're not distinguishable from other zsets.

Additionally, for sparse types this has the same behaviour as `MATCH` in that it may
return many empty results before giving something, even for large `COUNT`s.
2019-05-22 16:39:04 +01: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
Salvatore Sanfilippo fd0ee469ab Merge pull request #6100 from chrizel/typo-fixes
Typo fixes in CONTRIBUTING
2019-05-15 17:48:40 +02:00
Christian Zeller 7fababd44e Typo fixes in CONTRIBUTING 2019-05-15 16:10:48 +02:00
antirez fd9407dfc8 Update CONTRIBUTING with present info. 2019-05-15 12:46:01 +02:00
antirez 074d24df1e Narrow the effects of PR #6029 to the exact state.
CLIENT PAUSE may be used, in other contexts, for a long time making all
the slaves time out. Better for now to be more specific about what
should disable senidng PINGs.

An alternative to that would be to virtually refresh the slave
interactions when clients are paused, however for now I went for this
more conservative solution.
2019-05-15 12:16:43 +02:00
Salvatore Sanfilippo caf74e507e Merge pull request #6029 from chendq8/clientpause
fix cluster failover time out
2019-05-15 12:03:19 +02:00
antirez 1a1ba48390 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-05-14 16:55:52 +02:00
antirez 9724ca4e22 Make comment in getClientOutputBufferMemoryUsage() describing the present. 2019-05-13 17:30:06 +02:00
antirez 4f4676a142 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-05-13 17:27:10 +02: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
Salvatore Sanfilippo e633254ccf Merge pull request #6053 from soloestoy/enhance-aof-fsync-everysec
aof: enhance AOF_FSYNC_EVERYSEC, more details in #5985
2019-05-10 18:06:40 +02:00
Salvatore Sanfilippo 34f6d94701 Merge pull request #6074 from trevor211/fixActiveExpire
Do not active expire keys in the background when the switch is off.
2019-05-10 12:39:35 +02:00
Salvatore Sanfilippo 1e9b8d853d Merge pull request #6080 from soloestoy/fix-makefile
Makefile: 1TD -> STD
2019-05-10 12:37:07 +02:00
Salvatore Sanfilippo 2903c56bda Merge pull request #6073 from yossigo/fix/blocked-client-id
Preserve client->id for blocked clients.
2019-05-10 12:32:47 +02:00
Salvatore Sanfilippo 6b490e33c4 Merge pull request #6081 from Happy4Code/mod_comments
change the comments there may have a mis type
2019-05-10 12:28:12 +02:00
Salvatore Sanfilippo 891f4a38f6 Merge pull request #6077 from zltl/patch-7
delete sdsTest() from REDIS_TEST in server.c to fix build failed
2019-05-10 12:27:47 +02:00
Salvatore Sanfilippo 433f763814 Merge pull request #6083 from tangquanawj/fix-inappropriate-add-operation-code
fix-inappropriate-add-operation-code
2019-05-10 12:25:18 +02:00
Salvatore Sanfilippo 402b0d0bd1 Merge pull request #6086 from yongman/fix-uint64-in-defrag
Fix uint64_t hash value in active defrag
2019-05-10 12:23:59 +02:00
Salvatore Sanfilippo 19c3d5b743 Merge pull request #6087 from AngusP/linux-build-warnings
[Minor] Fix build warnings on Linux
2019-05-10 12:23:42 +02:00
Salvatore Sanfilippo 1212f22858 Merge pull request #6091 from soloestoy/fix-test-skip-till
test cases: skiptill -> skip-till
2019-05-10 12:22:19 +02:00
zhaozhao.zz c64aec9ce7 test cases: skiptill -> skip-till 2019-05-10 16:27:25 +08: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
Angus Pearson a1fb0be1d7 Enlarge error buffer in redis-check-aof.c to remove compiler warning of output truncation through snprintf format string 2019-05-08 12:13:45 +01:00
Angus Pearson bea09a7fa6 Add <strings.h> include to deps/hiredis/read.c to fix Implicit Declaration of strcasecmp warning 2019-05-08 11:36:31 +01:00
yongman fb4ee7f0c5 Fix uint64_t hash value in active defrag 2019-05-08 16:29:16 +08:00
唐权 842dd85b26 Update ziplist.c
Hi, @antirez

In the code, to get the size of ziplist, "unsigned int bytes = ZIPLIST_HEADER_SIZE+1;" is correct, 
but why not make it more readable and easy to understand
2019-05-08 12:53:56 +08:00
Salvatore Sanfilippo f674e83215 Merge pull request #6082 from soloestoy/fix-config-rewrite-memleak
fix memory leak when rewrite config file
2019-05-07 10:25:13 +02:00
zhaozhao.zz 48d591a010 fix memory leak when rewrite config file 2019-05-07 15:59:16 +08:00
stan011 d9d3d3065b change the comments there may have a mis type 2019-05-07 14:22:40 +08:00
zhaozhao.zz 340a723b87 Makefile: 1TD -> STD 2019-05-07 13:35:27 +08:00
Salvatore Sanfilippo a72ab70fee Merge pull request #6070 from oranagra/stabilize_repl_tests
make replication tests more stable on slow machines
2019-05-06 18:05:33 +02:00
antirez 3d053dbb6d Threaded IO: handleClientsWithPendingReadsUsingThreads top comment. 2019-05-06 18:02:51 +02:00
antirez 5baeb14cf3 Threaded IO: configuration directive for turning on/off reads. 2019-05-06 18:02:51 +02:00
antirez 1c0c436757 Threaded IO: ability to disable reads from threaded path. 2019-05-06 18:02:51 +02:00
antirez 90d720e7a5 Threaded IO: put fflush() inside tio_debug conditional. 2019-05-06 18:02:51 +02:00
antirez 6ab6a97fe6 Threaded IO: parsing WIP 2: refactoring to parse from thread. 2019-05-06 18:02:51 +02:00
antirez 647a66ebba Threaded IO: parsing WIP 1: set current_client in a better scoped way. 2019-05-06 18:02:51 +02:00
antirez 463ccf8664 Threaded IO: logging should be safe in I/O threads.
Potentially it is possible that we get interleaved writes, even if
serverLog() makes sure to write into a buffer and then use printf(), so
even this should be ok. However in general POSIX guarantees that writing
to the same file pointer object from multiple threads is safe. Anyway
currently we *reopen* the file at each call, but for the standard output
logging.

The logging functions actually also access global configuration while
performing the log (for instance in order to check the log level, the
log filename and so forth), however dunring the I/O threads execution
we cannot alter such shared state in any way.
2019-05-06 18:02:51 +02:00
antirez 8d7d2be24f Threaded IO: process read queue before stopping threads. 2019-05-06 18:02:51 +02:00
antirez 63a0ffd36a Threaded IO: read side WIP 3. 2019-05-06 18:02:51 +02:00
antirez a2245f8ff1 Threaded IO: read side WIP 2. 2019-05-06 18:02:51 +02:00
antirez dd5b105c73 Threaded IO: read side WIP. 2019-05-06 18:02:51 +02:00
antirez 74591fb5bd Threaded IO: hide more debugging printfs under conditional. 2019-05-06 18:02:51 +02:00
antirez 9814b2a5f3 Threaded IO: make num of I/O threads configurable. 2019-05-06 18:02:51 +02:00
antirez 30091dc29f Threaded IO: use main thread if num of threads is 1. 2019-05-06 18:02:51 +02:00
Ubuntu 9bf7f302a7 Threaded IO: stop threads when no longer needed + C11 in Makefile.
Now threads are stopped even when the connections drop immediately to
zero, not allowing the networking code to detect the condition and stop
the threads. serverCron() will handle that.
2019-05-06 18:02:51 +02:00
antirez ea35a81c42 Threaded IO: 3rd version: use the mutex only to stop the thread. 2019-05-06 18:02:51 +02:00
antirez 6f4f36c0fb Threaded IO: second attempt without signaling conditions. 2019-05-06 18:02:51 +02:00
antirez a2dbd9bd97 Threaded IO: allow to disable debug printf. 2019-05-06 18:02:51 +02:00
antirez f468e653b5 Threaded IO: implement handleClientsWithPendingWritesUsingThreads().
This is just an experiment for now, there are a couple of race
conditions, mostly harmless for the performance gain experiment that
this commit represents so far.

The general idea here is to take Redis single threaded and instead
fan-out on expansive kernel calls: write(2) in this case, but the same
concept could be easily implemented for read(2) and protcol parsing.

However just threading writes like in this commit, is enough to evaluate
if the approach is sounding.
2019-05-06 18:02:51 +02:00
liaotonglang b1c7e3393d delete sdsTest() from REDIS_TEST
sdsTest() defined in sds.c dit not match the call in server.c.
remove it from REDIS_TEST, since test-sds defined in Makefile.
2019-05-06 19:24:00 +08:00
WuYunlong 1c0913dc4e Do not active expire keys in the background when the switch is off. 2019-05-06 11:46:07 +08:00
Yossi Gottlieb 9f3679880a Preserve client->id for blocked clients. 2019-05-05 20:32:53 +03:00
Oran Agra ba809f26d4 make replication tests more stable on slow machines
solving few replication related tests race conditions which fail on slow machines

bugfix in slave buffers test: since the test is executed twice, each time with
a different commands count, the threshold for the delta can't be a constant.
2019-05-05 08:25:01 +03:00
Salvatore Sanfilippo 0a6090bfd8 Merge pull request #6051 from vattezhang/unstable
fix: benchmark auth fails when server have requirepass
2019-05-02 09:48:02 +02:00
zhaozhao.zz bcac165fab aof: enhance AOF_FSYNC_EVERYSEC, more details in #5985 2019-04-29 14:38:28 +08:00
Salvatore Sanfilippo 843de8b786 Merge pull request #5971 from devnexen/unstable
build fix
2019-04-26 17:32:21 +02:00
Salvatore Sanfilippo 5ba908fa5f Merge pull request #6002 from yongman/fix-memleak-in-bitfield
Fix memleak in bitfieldCommand
2019-04-26 17:31:42 +02:00
Salvatore Sanfilippo 5c5197fe4f Merge pull request #6013 from rouzier/fix/stream_iterator_init
Fix stream interator start and end key initialize
2019-04-26 17:25:20 +02:00
Salvatore Sanfilippo 2d450d1315 Merge pull request #6039 from git-hulk/fix/benchmark-coredump-in-arguments
FIX: coredump in redis-benchmark
2019-04-26 17:17:55 +02:00
abhay 162208f94d removed obsolete warning as per - https://github.com/antirez/redis/issues/5291 2019-04-26 17:03:16 +02:00
vattezhang 4e38ced488 fix: benchmark auth fails when server have requirepass 2019-04-26 19:47:07 +08:00
vattezhang bc36404c79 update 2019-04-26 18:50:51 +08:00
vattezhang d3d96b041a Merge github.com:antirez/redis into unstable 2019-04-26 18:47:11 +08:00
git-hulk fa97ef34ca FIX: core dump in redis-benchmark when the -r is the last arg 2019-04-24 20:05:35 +08: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
chendianqiang 11f2c6b115 stop ping when client pause 2019-04-17 21:20:10 +08:00
John Sully c4621a5ed2 Start of MVCC support (and more C++) 2019-04-16 23:16:03 -04:00
Itamar Haber 52686f4866 Adds a "Modules" section to INFO
Fixes #6012.

As long as "INFO is broken", this should be adequate IMO. Once we rework
`INFO`, perhaps into RESP3, this implementation should be revisited.
2019-04-16 22:16:12 +03:00
John Sully 1c953a4d5b Fix module linking and crashing issues 2019-04-16 13:34:22 -04:00
Itamar Haber c184b32d4c Uses addReplyBulkCString
Signed-off-by: Itamar Haber <itamar@redislabs.com>
2019-04-16 17:38:33 +03:00
Itamar Haber 26d9d4ec2c Adds RedisModule_ReplyWithCString
Signed-off-by: Itamar Haber <itamar@redislabs.com>
2019-04-16 17:15:23 +03: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
antirez 4a5057000a Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-04-15 16:50:48 +02:00
antirez 487601d85d Test: disable module testing for now. 2019-04-15 16:50:26 +02: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
James Rouzier 3ccdcbc088 Fix start and end key initialize 2019-04-11 12:19:02 -04:00
Salvatore Sanfilippo d044e33c20 Merge pull request #5961 from yossigo/modules-tests
Modules tests
2019-04-11 07:56:23 -07:00
antirez 9e67691ffb Aesthetic change to #5962 to conform to Redis style. 2019-04-10 18:53:35 +02:00
Salvatore Sanfilippo 6de5d25062 Merge pull request #5962 from oranagra/module_blocked_reply
slave corrupts replication stream when module blocked client uses large reply (or POSTPONED_ARRAY)
2019-04-10 09:41:36 -07:00
yongman d490752d58 Fix memleak in bitfieldCommand 2019-04-09 09:24:22 +08: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
antirez c24e32041b ACL: Fix memory leak in ACLResetSubcommandsForCommand().
This commit fixes bug reported at #5998. Thanks to @tomcat1102.
2019-04-08 18:08:37 +02:00
antirez f8a9708aa7 ACL: regression test for #5998. 2019-04-08 18:06:50 +02:00
antirez 75648f99a5 Fix assert comparison in fetchClusterSlotsConfiguration(). 2019-04-08 17:39:26 +02: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
David Carlier 4de88828d9 build fix 2019-03-28 06:38:16 +00: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
Oran Agra acba2fc9b4 slave corrupts replication stream when module blocked client uses large reply (or POSTPONED_ARRAY)
when redis appends the blocked client reply list to the real client, it didn't
bother to check if it is in fact the master client. so a slave executing that
module command will send replies to the master, causing the master to send the
slave error responses, which will mess up the replication offset
(slave will advance it's replication offset, and the master does not)
2019-03-24 14:17:37 +02:00
Yossi Gottlieb ec0b6bd2c3 Add runtest-moduleapi with commandfilter coverage. 2019-03-24 12:03:03 +02:00
Yossi Gottlieb 822a992f91 fix: missing initialization. 2019-03-24 12:00:33 +02:00
Salvatore Sanfilippo 5e8caca036 Merge pull request #5944 from yossigo/command-filtering
Command Filtering API
2019-03-22 17:43:49 +01:00
Salvatore Sanfilippo fcac342955 Merge pull request #3830 from oranagra/diskless_capa_pr
several bugfixes to diskless replication
2019-03-22 17:41:40 +01:00
Salvatore Sanfilippo 122f42844a Merge pull request #5945 from dvirsky/miss_notification
Added keyspace miss notifications support
2019-03-22 17:41:00 +01: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
Dvir Volk 040e52c77f Renamed event name from "miss" to "keymiss" 2019-03-21 20:33:11 +02:00
Oran Agra 29b0a57695 diskless fork kept streaming RDB to a disconnected slave 2019-03-21 20:24:52 +02:00
Yossi Gottlieb 6c0a5fde3d CommandFilter API: REDISMODULE_CMDFILTER_NOSELF.
Add a flag to automatically protect filters from being called
recursively by their own module.
2019-03-21 19:53:12 +02:00
Yossi Gottlieb 4ea3ed896b CommandFilter API: fix UnregisterCommandFilter. 2019-03-21 19:45:41 +02:00
antirez b3408e9a9b More sensible name for function: restartAOFAfterSYNC().
Related to #3829.
2019-03-21 17:21:29 +01:00
antirez 9588fd52ac Mostly aesthetic changes to restartAOF().
See #3829.
2019-03-21 17:18:24 +01:00
Salvatore Sanfilippo 544373ea66 Merge pull request #3829 from oranagra/restart_aof_pr
bugfix to restartAOF, exit will never happen
2019-03-21 17:15:55 +01:00
Yossi Gottlieb e2626f69ec CommandFilter API: Add unregister option.
A filter handle is returned and can be used to unregister a filter.  In
the future it can also be used to further configure or manipulate the
filter.

Filters are now automatically unregistered when a module unloads.
2019-03-21 14:44:49 +02:00
Salvatore Sanfilippo d75c36ee48 Merge pull request #5390 from oranagra/lookup_key_write
change SORT and SPOP to use lookupKeyWrite rather than lookupKeyRead
2019-03-21 13:39:38 +01:00
antirez 9dabbd1ab0 Alter coding style in #4696 to conform to Redis code base. 2019-03-21 12:18:55 +01:00
Salvatore Sanfilippo 5c47e2e964 Merge pull request #4696 from oranagra/zrealloc_fix
Fix zrealloc to behave similarly to je_realloc when size is 0
2019-03-21 12:18:04 +01:00
Salvatore Sanfilippo 5c21eca66e Merge pull request #5243 from oranagra/sigterm_log
Add log when server dies of SIGTERM during loading
2019-03-21 11:54:09 +01:00
Salvatore Sanfilippo ce518cea79 Merge pull request #5391 from oranagra/touch_flags
getKeysFromCommand for TOUCH only extracted the first key.
2019-03-21 11:53:27 +01:00
Salvatore Sanfilippo 684b140a13 Merge pull request #3650 from yossigo/key_name_from_module_io
Add RedisModule_GetKeyNameFromIO()
2019-03-21 11:49:25 +01:00
Dvir Volk bc269c85e1 remove extra linebreak 2019-03-21 12:48:37 +02:00
Dvir Volk 4a0ee5c6ac Added missing REDISMODULE_NOTIFY_KEY_MISS flag to REDISMODULE_NOTIFY_ALL 2019-03-21 12:47:51 +02:00
Dvir Volk 99c2fe0bcf added special flag for keyspace miss notifications 2019-03-21 11:47:14 +02:00
Oran Agra b2e03f8329 diskless replication - notify slave when rdb transfer failed
in diskless replication - master was not notifing the slave that rdb transfer
terminated on error, and lets slave wait for replication timeout
2019-03-20 17:46:19 +02:00
oranagra c9e2900efc bugfix to restartAOF, exit will never happen since retry will get negative.
also reduce an excess sleep
2019-03-20 17:20:07 +02:00
Oran Agra 747174388f change SORT and SPOP to use lookupKeyWrite rather than lookupKeyRead
like in SUNIONSTORE etc, commands that perform writes are expected to open
all keys, even input keys, with lookupKeyWrite
2019-03-20 17:06:22 +02:00
Oran Agra 385f6190a3 getKeysFromCommand for TOUCH only extracted the first key.
also, airty for COMMAND command was wrong.
2019-03-20 17:00:39 +02: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
Yossi Gottlieb dd8b4be46b CommandFilter API: Extend documentation. 2019-03-19 19:48:47 +02:00
Dvir Volk 8620a434a0 Added keyspace miss notifications support 2019-03-19 13:11:37 +02: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
Yossi Gottlieb a9a6a894e8 CommandFilter API: hellofilter and tests. 2019-03-18 23:07:28 +02:00
Yossi Gottlieb 325fc1cb2e CommandFilter API: Support Lua and RM_call() flows. 2019-03-18 23:06:38 +02:00
Yossi Gottlieb 2a5aeef79f CommandFilter API: More cleanup. 2019-03-18 23:05:52 +02:00
Yossi Gottlieb 9095e4dc9b Add command filter Module API tests. 2019-03-18 19:34:52 +02:00
Yossi Gottlieb 6711132083 Add command filtering argument handling API. 2019-03-18 18:36:46 +02:00
antirez 3eaa2cdc44 MANIFESTO: simplicity and lock-in. 2019-03-18 15:49:52 +01:00
antirez a5af648fdd MANIFESTO v2. 2019-03-18 15:38:43 +01:00
Yossi Gottlieb c3e187190b Initial command filter experiment. 2019-03-18 13:50:34 +02:00
antirez 14b17c3615 replicaofCommand() refactoring: stay into 80 cols. 2019-03-18 11:34:40 +01:00
antirez b78ac354f4 redis-check-aof: fix potential overflow.
Bug signaled by @vattezhang in PR #5940 but fixed differently.
2019-03-18 11:16:23 +01:00
antirez 8ea906a3e8 HyperLogLog: fix comment in hllCount(). 2019-03-16 09:15:57 +01:00
Guy Korland c1455dc060 Update config.yml 2019-03-15 22:22:06 +02:00
Guy Korland 656cd1a00a Update pull.yml 2019-03-15 21:35:24 +02:00
Guy Korland c2b7f14c56 Update config.yml 2019-03-15 21:30:09 +02:00
Guy Korland 3c05bc561d add pull app 2019-03-15 21:14:15 +02:00
Guy Korland a2ac5c3840 add CI 2019-03-15 21:09:59 +02:00
antirez e216ceaf0e HyperLogLog: handle wrong offset in the base case. 2019-03-15 17:16:06 +01:00
antirez dca7358279 HyperLogLog: speedup fuzz test. 2019-03-15 17:13:19 +01:00
antirez a4b90be9fc HyperLogLog: enlarge reghisto variable for safety. 2019-03-15 17:10:16 +01:00
antirez 4208666797 HyperLogLog: dense/sparse repr parsing fuzz test. 2019-03-15 13:52:29 +01:00
John Sully 9f13b2bd49 Fix hyperloglog corruption 2019-03-15 13:13:01 +01:00
Yossi Gottlieb a88264d934 Add RedisModule_GetKeyNameFromIO(). 2019-03-15 10:23:27 +02: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 a89ab4d6b0 Fix hyperloglog corruption 2019-03-14 14:02:16 -04:00
antirez 74d6af8f80 Fix ZPOP return type when COUNT=0. Related to #5799. 2019-03-14 17:51:20 +01:00
antirez 052e03495f Fix objectSetLRUOrLFU() when LFU underflows. 2019-03-14 17:06:59 +01:00
Yossi Gottlieb 68fd59056b Add RedisModule_Assert() API call. 2019-03-14 15:00:31 +02:00
antirez d292a51618 Improve comments after merging #5834. 2019-03-14 12:47:36 +01:00
Salvatore Sanfilippo 0cce98f2f9 Merge pull request #5834 from guybe7/trim_module_sds
Trim SDS free space of retained module strings
2019-03-14 12:41:31 +01:00
Salvatore Sanfilippo 178114e766 Merge pull request #5931 from guybe7/fix_notify_classes
Fix mismatching keyspace notification classes
2019-03-14 12:30:10 +01:00
Guy Benoish b2eb48df89 Fix mismatching keyspace notification classes 2019-03-14 12:11:16 +01:00
Salvatore Sanfilippo d3cd2e9a4a Merge pull request #4742 from guybe7/zrangebylex_leak
Fix zlexrangespec mem-leak in genericZrangebylexCommand
2019-03-14 11:44:56 +01:00
Salvatore Sanfilippo ec03f2db6b Merge pull request #4904 from guybe7/memtoll_fix
Use memtoll() in 'CONFIG SET client-output-buffer-limit'
2019-03-14 11:43:55 +01:00
Salvatore Sanfilippo 190b63f993 Merge pull request #5812 from guybe7/fix_string2ld
Increase string2ld's buffer size (and fix HINCRBYFLOAT)
2019-03-14 11:35:01 +01:00
Salvatore Sanfilippo 01ace0b240 Merge pull request #5694 from guybe7/rm_log_args
Check server.verbosity in RM_LogRaw
2019-03-14 11:32:03 +01:00
Salvatore Sanfilippo ebf7274192 Merge pull request #5799 from guybe7/zpop_zero_count
ZPOP should return an empty array if COUNT=0
2019-03-14 11:29:24 +01:00
antirez 6fd4af1f12 Merge branch 'sharedapi' into unstable 2019-03-14 11:24:48 +01: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
Jim Brunner 283d6cfd58 Addition of OnUnload function 2019-03-13 16:31:24 +00: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
vattezhang ad223e2042 fix: fix benchmark cannot exit when NOAUTH err happens 2019-03-13 20:46:33 +08:00
vattezhang 31110f1caf Merge branch 'unstable' of github.com:antirez/redis into unstable 2019-03-13 20:26:54 +08:00
Salvatore Sanfilippo 2537b2140f Merge pull request #5787 from soloestoy/bugfix-xgroup-create-with-mkstream
Streams: checkType before XGROUP CREATE
2019-03-13 12:34:29 +01:00
Salvatore Sanfilippo 71499ab1c6 Merge pull request #5893 from itamarhaber/bzpop-arity
Fixes BZ[REV]POP's arity
2019-03-13 12:27:35 +01:00
Salvatore Sanfilippo c49abcb794 Merge pull request #5898 from bsolomon1124/make-uninstall-tgt
Provide an uninstall target in Makefile
2019-03-13 12:26:43 +01:00
Salvatore Sanfilippo 372cbc37e7 Merge pull request #5884 from chendq8/cluster_failover
Reduce 100ms of cluster failover time on Manual mode
2019-03-13 12:22:23 +01:00
Salvatore Sanfilippo 46a8cb2d18 Merge pull request #5910 from bsolomon1124/install-server-osx-note
Note that install_server.sh is not for Mac OSX
2019-03-13 12:19:03 +01:00
Salvatore Sanfilippo 84d6ce4f56 Merge pull request #5901 from artix75/bm_threads_cluster_dev
Redis Benchmark: add multithread idle mode
2019-03-13 12:18:32 +01:00
Salvatore Sanfilippo 53d1dc170c Merge pull request #5921 from vattezhang/unstable_temp
fix: fix the if condition in clusterManagerShowClusterInfo
2019-03-13 12:18:08 +01:00
Salvatore Sanfilippo 3e648907ee Merge pull request #5907 from spjwebster/xclaim-increment-delivery-count
Increment delivery counter on XCLAIM unless RETRYCOUNT specified
2019-03-13 11:55:46 +01:00
Salvatore Sanfilippo 610aff3251 Merge pull request #5924 from swilly22/redismodule-replicated-cmd-ctx-flag
document additional flag of RM_GetContextFlags
2019-03-13 11:52:07 +01:00
Salvatore Sanfilippo 02dab20026 Merge pull request #5894 from soloestoy/fix-rdb-warning
Fix compile some warnings
2019-03-13 11:47:48 +01:00
zhaozhao.zz 5a3d3d8be4 Fix compile warning in redis-cli.c 2019-03-13 16:54:34 +08:00
swilly22 89bf4db4fa document additional flag of RM_GetContextFlags 2019-03-13 08:22:40 +02:00
Steve Webster dfcb227b50 Only increment delivery count if JUSTID option is omitted 2019-03-12 20:27:53 +00:00
JohnSully 7546c7d8b4 Update README.md 2019-03-12 14:38:03 -04:00
Salvatore Sanfilippo e5acc5ef4f Merge pull request #2774 from rouzier/blocking-list-commands-support-milliseconds-floating
Added millisecond resolution for blpop command && friends
2019-03-12 18:10:28 +01:00
Salvatore Sanfilippo fba6e26e87 Merge pull request #5913 from wurongxin1987/unstable
fix a bufferoverflow bug
2019-03-12 17:25:21 +01:00
Salvatore Sanfilippo b0bc602bb3 Merge pull request #5900 from artix75/cluster_backup
Cluster Manager: add importing/migrating nodes to backup info
2019-03-12 17:21:17 +01:00
Salvatore Sanfilippo c02b414e9a Merge pull request #5903 from soloestoy/sunionstore-lazyfree
try lazyfree temp set in SUNION & SDIFF
2019-03-12 17:20:52 +01:00
Salvatore Sanfilippo 45645aee7f Merge pull request #5915 from swilly22/redismodule-replicated-cmd-ctx-flag
Extend REDISMODULE_CTX_FLAGS to indicate if command was sent by master
2019-03-12 17:17:19 +01:00
artix 5284d67e37 Redis Benchmark: fix possible usage of freed pointer (getRedisConfig)
Fixes issue #5912
2019-03-12 17:07:23 +01:00
Salvatore Sanfilippo f63bbb4335 Merge pull request #5920 from chendq8/aofrewrite
remove temp-rewriteaof-xxx.aof when interrupt aofrewrite
2019-03-12 17:03:02 +01:00
vattezhang bdc783b472 fix: fix the if condition in clusterManagerShowClusterInfo 2019-03-12 22:01:02 +08:00
vattezhang 270a111433 Merge branch 'unstable' of github.com:antirez/redis into unstable 2019-03-12 21:52:20 +08:00
chendianqiang 3621223fbb remove temp-rewriteaof-xxx.aof when interrupt aofrewrite 2019-03-12 20:46:40 +08: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
swilly22 468860ae18 Extend REDISMODULE_CTX_FLAGS to indicate if command was sent by master 2019-03-11 10:02:19 +02:00
antirez 8a46d32be2 Make comment in #5911 stay inside 80 cols. 2019-03-10 09:48:06 +01:00
Salvatore Sanfilippo 55acac04b4 Merge pull request #5911 from JohnSully/unstable
Replicas aren't allowed to run the replicaof command
2019-03-10 09:45:55 +01:00
wurongxin 0298d3ad18 fix a bufferoverflow bug 2019-03-10 15:30:32 +08: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 5b52bc738b Replicas aren't allowed to run the replicaof command 2019-03-09 11:04:48 -05:00
Brad Solomon 79660e4ff4 Note that install_server.sh is not for Mac OSX
It will fail pretty quickly since there is no -f
readlink flag there.
2019-03-09 10:21:15 -05:00
Steve Webster f1e7df4b7c Increment delivery counter on XCLAIM unless RETRYCOUNT specified
The XCLAIM docs state the XCLAIM increments the delivery counter for
messages. This PR makes the code match the documentation - which seems
like the desired behaviour - whilst still allowing RETRYCOUNT to be
specified manually.

My understanding of the way streamPropagateXCLAIM() works is that this
change will safely propagate to replicas since retry count is pulled
directly from the streamNACK struct.

Fixes #5194
2019-03-08 17:09:11 +00:00
Salvatore Sanfilippo 0f03312c23 Merge pull request #5902 from zhouyuan/wip_cleanup
server.h: remove dead code
2019-03-08 16:53:20 +01:00
artix 8fadebfcca Redis Benchmark: handle CLUSTERDOWN error 2019-03-08 11:05:02 +01: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
zhaozhao.zz 0137f1a2e3 try lazyfree temp set in SUNION & SDIFF 2019-03-07 22:08:04 +08:00
Yuan Zhou feb4ebff45 server.h: remove dead code
hashTypeTryObjectEncoding() is not used now
2019-03-07 18:38:27 +08:00
artix c389ad0d52 Redis Benchmark: fix key randomization with zero keyspacelen 2019-03-07 11:30:09 +01:00
artix 0e963e068d Redis Benchmark: add multithread idle mode
Fix issue #5891
2019-03-07 11:14:07 +01:00
Brad Solomon d5b24d31d7 Provide an uninstall target in Makefile
On `make uninstall`, removes:

- /usr/local/bin/redis-benchmark
- /usr/local/bin/redis-check-aof
- /usr/local/bin/redis-check-rdb
- /usr/local/bin/redis-cli
- /usr/local/bin/redis-sentinel
- /usr/local/bin/redis-server

(Only the src/ versions are removed in `make clean`)
2019-03-06 21:24:45 -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
artix 93e51239ce Cluster Manager: add importing/migrating nodes to backup info 2019-03-06 16:38:36 +01:00
John Sully de4217489c defer free 2019-03-05 15:46:19 -05:00
antirez c33cb4938a ACL: GENPASS subcommand. 2019-03-05 15:51:37 +01:00
zhaozhao.zz fb81d1b3f8 Fix compile warning when log aux field 2019-03-04 19:43:00 +08:00
John Sully 3c658b5012 Fix crash with paused clients (accessed when global lock is not acquired) 2019-03-03 22:24:12 -05:00
Itamar Haber cd2743c0e6 Fixes BZ[REV]POP's arity 2019-03-03 23:10:45 +02: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
antirez 4edb1d7e10 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-03-02 21:19:21 +01:00
antirez b9b140e2e2 Use the RDB info fields to provide info to users.
Fix #5790 and 5878.

Maybe a better option was to have such fields named with the first
byte '%' as those are info fields for specification, however now to
break it in a backward incompatible way is not an option, so let's use
the fields actively to provide info when sensible, otherwise ignore
when they are not really helpful.
2019-03-02 21:17:42 +01:00
John Sully 8d3704d93b Merge branch 'unstable' of https://github.com/JohnSully/redis2 into unstable 2019-03-01 16:40:20 -05:00
Salvatore Sanfilippo 56cf413844 Merge pull request #5888 from artix75/cluster_backup
Cluster Manager (redis-cli): new "backup" command
2019-03-01 18:43:13 +01:00
Salvatore Sanfilippo 537d859288 Merge pull request #5889 from artix75/bm_threads_cluster_dev
Redis benchmark: multithread support and cluster support
2019-03-01 18:39:58 +01:00
artix cb1be1ca81 Redis benchmark: update help with threads/cluster options 2019-03-01 18:15:44 +01:00
artix a79b84ab7f Redis benchmark: fix default hset test key 2019-03-01 17:53:14 +01:00
artix 4e78d5cd40 Redis Benchmark: update slots configuration after MOVED/ASK reply 2019-03-01 17:53:14 +01:00
artix daaff484a6 Redis Benchmark: use atomic var for liveclients in 'createClient' 2019-03-01 17:53:14 +01:00
artix 834809cbb3 Redis Benchmark: display 'save' and 'appendonly' configuration 2019-03-01 17:53:14 +01:00
artix 649c947a0f Redis benchmark: add {tag} to all default tests 2019-03-01 17:53:14 +01:00
artix eb8b4feef7 Redis benchmark: fixed issued with config.hostip and code cleanup 2019-03-01 17:53:14 +01:00
artix f95e01266e Redis benchmark: configurable thread count in cluster mode and fixes 2019-03-01 17:53:14 +01:00
artix 5fd5799cf9 Various changes to redis-benchmark thread and cluster support
- MOVED or ASK replies are now handled in cluster mode.
- Only the first slot per node is used in cluster mode.
- Mutlithreading: reduced usage of mutexes in favor of atomic vars.
2019-03-01 17:53:14 +01:00
artix 434f761304 Redis benchmark: table-based slot hashtag placeholder replacement in cluster mode. 2019-03-01 17:53:14 +01:00
artix dfd3cc5f78 Added basic support for clusters to redis-benchmark. 2019-03-01 17:53:14 +01:00
artix 563885d6d9 Thread support for redis-benchmark. 2019-03-01 17:53:14 +01:00
varianfeng ab1e87f5b1 fix corrupt_rdb.c bug.Let the name of input rdb file name be valid. 2019-03-01 17:46:42 +01:00
artix e6156a39bd Cluster Manager backup: remove --cluster-ignore-issue option
Always save the backup, even if there are problems in the cluster.
Just display a warn message and save "cluster_errors" property
inside the json.
2019-03-01 17:41:40 +01:00
artix 5e4dfc5c97 Cluster Manager: check cluster before backup
- Prevent cluster backup if cluster has issues and needs to be fixed.
  This behaviour can be overridden by adding the option
  '--cluster-ignore-issues'
2019-03-01 17:41:40 +01:00
artix fb020ab090 Cluster Manager: 'backup' command 2019-03-01 17:41:40 +01:00
Salvatore Sanfilippo b19e8b9a2c Merge pull request #5875 from chendq8/partialsync
fix:Slave will do full sync when restart with SHUTDOWN SAVE on cluster mode
2019-03-01 17:29:19 +01:00
Salvatore Sanfilippo 80b8f9febc Merge pull request #5873 from madolson/dev-unstable-minor-benchmark-precision-fix
Updated redis-benchmark so it doesn't show 1 value above 2ms
2019-03-01 16:55:09 +01:00
Salvatore Sanfilippo 5f2a256ca9 Merge pull request #5881 from artix75/cluster_manager_join_issues
Cluster Manager: create command checks for issues during "CLUSTER MEET"
2019-03-01 16:51:02 +01:00
chendianqiang a16da79228 optimize cluster failover 2019-03-01 15:28:21 +08:00
artix 6cd64c6a98 Cluster Manager: change join issue message 2019-02-28 16:57:57 +01:00
artix 23ad3faa50 Cluster Manager: change text alert clusterManagerWaitForClusterJoin 2019-02-28 16:57:57 +01:00
artix 2593fb9c0c Cluster Manager: code cleanup 2019-02-28 16:57:57 +01:00
artix 6e9864fe0d Cluster Manager: fix bus error in clusterManagerGetLinkStatus 2019-02-28 16:57:57 +01:00
Artix 121adc604b Cluster Manager: fix memory leaks in clusterManagerGetDisconnectedLinks 2019-02-28 16:57:57 +01:00
artix b013d2c4db Cluster Manager: fix memory leak in clusterManagerWaitForClusterJoin 2019-02-28 16:57:57 +01:00
artix 3578aabc05 Cluster Manager: improve join issue checking 2019-02-28 16:57:57 +01:00
artix 2f499304aa Cluster Manager: check for unreachable nodes during cluster join. 2019-02-28 16:57:57 +01:00
Salvatore Sanfilippo 9b0b0b3942 Merge pull request #3649 from Alkorin/fixTypo
Fix typo (unsupproted => unsupported) in error message
2019-02-27 22:33:22 +01:00
antirez 74fdfc3763 Merge branch 'unstable' of github.com:/antirez/redis into unstable 2019-02-27 22:21:00 +01:00
antirez 68c75f248e Gopher: reply in gopher mode only if argv[0] starts with slash.
As documented but never implemented.
2019-02-27 22:20:31 +01:00
Salvatore Sanfilippo 88b720672c Merge pull request #5877 from vattezhang/unstable_sentinel_cmd
fix: fix sentinel command table and new flags format
2019-02-27 15:45:03 +01:00
vattezhang 9d632230b6 fix: fix sentinel command table and new flags format 2019-02-27 21:35:58 +08:00
vattezhang 0f0f787a37 fix: fix sentinel command table and new flags format 2019-02-27 21:20:00 +08:00
chendianqiang 8f7e97258b fix replicationid will not change for server.masterhost==NULL in cluster mode when restart slave 2019-02-27 17:43:05 +08:00
chendianqiang 49816941a4 Merge pull request #2 from antirez/unstable
merge from redis
2019-02-27 17:22:08 +08:00
antirez f311a529be Make PR #5872 more compatible with Redis coding style. 2019-02-27 09:34:50 +01:00
Salvatore Sanfilippo 0dcb003887 Merge pull request #5872 from madolson/dev-unstable-acl-setuser-fix
Updated acl setuser to be all or nothing
2019-02-27 09:31:57 +01:00
Madelyn Olson b79efef5d6 Updated redis-benchmark so it doesn't show 1 value above 2ms at higher precision 2019-02-26 21:12:55 +00:00
JohnSully 141557963e Update README.md 2019-02-26 15:16:46 -05:00
Madelyn Olson 075a3b8893 Updated acl setuser to be all or nothing 2019-02-26 02:04:29 +00:00
antirez a7780f716e Merge branch 'gopher' into unstable 2019-02-25 18:16:58 +01:00
antirez 40a01a945d Gopher: document the feature in redis.conf. 2019-02-25 17:20:43 +01:00
antirez 21f92e9e34 RESP3: SETNAME option for HELLO. 2019-02-25 16:56:58 +01:00
antirez d4d15315a8 RESP3: AUTH option for HELLO. 2019-02-25 16:55:16 +01:00
antirez 5748439770 RESP3: refactoring of CLIENT SETNAME to implement SETNAME in HELLO. 2019-02-25 16:51:49 +01:00
antirez 3b420034bb RESP3: allow HELLO to be used with version = 2. 2019-02-25 16:41:00 +01:00
antirez 36d1588215 ACL: authCommand() refactored into ACLAuthenticateUser(). 2019-02-25 16:39:44 +01:00
antirez 87594a7470 ACL: move AUTH implementation in acl.c. 2019-02-25 16:33:38 +01:00
antirez e247c9ac6a Gopher: don't add the Lastline. 2019-02-24 21:38:15 +01:00
antirez 8b087dff34 Gopher: TODO list. 2019-02-22 11:17:39 +01:00
antirez f94d711c83 Gopher: basic serving of string type. 2019-02-22 10:21:24 +01:00
antirez e00b22e090 Gopher: initial request handling. 2019-02-21 23:13:08 +01:00
antirez 3de9ccf190 Gopher: config setting to turn support on/off. 2019-02-21 17:28:53 +01:00
vattezhang 4cc43a96f6 benchmark: add auth check in benchmark
When we run benchmark but forget to set the right requirepass, benchmark should return error.
2019-02-18 22:48:55 +08:00
Guy Benoish bdd9a8002a Trim SDS free space of retained module strings
In some cases processMultibulkBuffer uses sdsMakeRoomFor to
expand the querybuf, but later in some cases it uses that query
buffer as is for an argv element (see "Optimization"), which means
that the sds in argv may have a lot of wasted space, and then in case
modules keep that argv RedisString inside their data structure, this
space waste will remain for long (until restarted from rdb).
2019-02-12 14:21:21 +01:00
Guy Benoish b0c8d6c227 Increase string2ld's buffer size (and fix HINCRBYFLOAT)
The string representation of `long double` may take
up to ~5000 chars (see PR #3745).

Before this fix HINCRBYFLOAT would never overflow (since
the string could not exceed 256 chars). Now it can.
2019-01-28 17:58:11 +02:00
Guy Benoish 2502956835 ZPOP should return an empty array if COUNT=0 2019-01-23 11:11:57 +02:00
zhaozhao.zz 645d44d545 Streams: checkType before XGROUP CREATE
Fix issue #5785, in case create group on a key is not stream.
2019-01-16 19:19:14 +08:00
Madelyn Olson b00e1891c0 Fixed a rounding bug in geo.tcl 2019-01-15 07:26:19 +00:00
Bruce Merry 6b818efeb6 Make dbSwapDatabases take args as long
This prevents an integer overflow bug. Closes #5737.
2018-12-31 11:51:03 +02:00
antirez 8a87de130f Modules shared API: export new core APIs. 2018-12-20 17:57:49 +01:00
antirez d3eb0028e9 Modules shared API: also unregister the module as user. 2018-12-20 17:57:46 +01:00
antirez 9403b3d7a3 Modules shared API: prevent unloading of used modules. 2018-12-20 17:57:43 +01:00
antirez 6bb8cdaebe Modules shared API: unregister APIs function. 2018-12-20 17:57:40 +01:00
antirez 27f6e9bb9b Modules shared API: initial core functions.
Based on ideas and code in PR #5560 by @MeirShpilraien.
2018-12-20 17:57:35 +01:00
antirez 850b64c116 Revert shared APIs to modify the design. 2018-12-20 17:56:38 +01:00
MeirShpilraien ab37289fa6 added module ability to register api to be used by other modules 2018-12-20 17:55:18 +01:00
Guy Benoish ed88f77d6d Check server.verbosity in RM_LogRaw 2018-12-13 13:57:38 +01:00
jem a344c4cfad ignore vscode conf dir 2018-09-18 20:42:09 +08:00
jem 42366959ec update leap year comment when div by 400 2018-09-18 17:04:00 +08:00
Oran Agra 17c5f17686 Add log when server dies of SIGTERM during loading
this is very confusing to see the server disappears as if it got SIGKILL when it was not the case.
2018-08-13 17:43:29 +03:00
chendianqiang 68ceb46697 Merge pull request #1 from antirez/unstable
update
2018-07-20 19:20:14 +08:00
Guy Benoish 8c8e85df87 Use memtoll() in 'CONFIG SET client-output-buffer-limit' 2018-04-18 13:01:53 +03:00
Wander Hillen dda8cc1821 More typos 2018-03-16 09:59:17 +01:00
Wander Hillen dcffca0a31 Fix typos, add some periods 2018-03-16 09:59:14 +01:00
Guy Benoish b660fc2fbe Fix zlexrangespec mem-leak in genericZrangebylexCommand 2018-03-07 10:40:37 +07:00
Oran Agra 5def65008f Fix zrealloc to behave similarly to je_realloc when size is 0
According to C11, the behavior of realloc with size 0 is now deprecated.
it can either behave as free(ptr) and return NULL, or return a valid pointer.
but in zmalloc it can lead to zmalloc_oom_handler and panic.
and that can affect modules that use it.

It looks like both glibc allocator and jemalloc behave like so:
  realloc(malloc(32),0) returns NULL
  realloc(NULL,0) returns a valid pointer

This commit changes zmalloc to behave the same
2018-02-21 11:04:13 +02:00
Thomas SOËTE a286832170 Fix typo (unsupproted => unsupported) in error message 2016-11-30 15:26:59 +01:00
James Rouzier eca0187370 If the unit of a timeout is seconds treat it a float 2016-02-23 12:05:29 -05:00
308 changed files with 44601 additions and 14596 deletions

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
** 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 ==="
Please copy everything after this line.
**To Reproduce**
Do you know how to reproduce this? If so please provide repro steps.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**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 [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+55
View File
@@ -0,0 +1,55 @@
name: CI
on: [push, pull_request]
jobs:
test-ubuntu-latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: make
run: |
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 tcl8.5 tcl-tls
./runtest --clients 2 --verbose --tls
- name: cluster-test
run: |
./runtest-cluster --tls
- name: sentinel test
run: |
./runtest-sentinel
- name: module tests
run: |
./runtest-moduleapi
build-ubuntu-old:
runs-on: ubuntu-16.04
steps:
- uses: actions/checkout@v1
- name: make -j2
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make -j2
build-macos-latest:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: make
run: make -j2
build-libc-malloc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make MALLOC=libc -j2
+89
View File
@@ -0,0 +1,89 @@
name: Daily
on:
schedule:
- cron: '0 7 * * *'
jobs:
test-jemalloc:
runs-on: ubuntu-latest
timeout-minutes: 1200
steps:
- uses: actions/checkout@v1
- 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
test-libc-malloc:
runs-on: ubuntu-latest
timeout-minutes: 1200
steps:
- uses: actions/checkout@v1
- 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
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- 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@v1
- 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
timeout-minutes: 14400
steps:
- uses: actions/checkout@v1
- name: make
run: |
sudo apt-get -y install uuid-dev libcurl4-openssl-dev
make valgrind
- name: test
run: |
sudo apt-get install tcl8.5 valgrind -y
./runtest --valgrind --verbose --clients 1
- name: module api test
run: ./runtest-moduleapi --valgrind --verbose --clients 1
+22
View File
@@ -0,0 +1,22 @@
name: Endurance
on:
schedule:
- cron: '30 * * * *'
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 tcl8.5
./runtest --loopn 5 --config server-threads 3 --clients 5
+6 -1
View File
@@ -1,6 +1,9 @@
.*.swp
core
*.o
*.xo
*.so
*.d
*.log
dump.rdb
redis-benchmark
@@ -27,7 +30,7 @@ release.h
src/transfer.sh
src/configs
redis.ds
src/redis.conf
src/keydb.conf
src/nodes.conf
deps/lua/src/lua
deps/lua/src/luac
@@ -36,3 +39,5 @@ deps/lua/src/liblua.a
.prerequisites
*.dSYM
Makefile.dep
.vscode/*
.idea/*
+3
View File
@@ -0,0 +1,3 @@
[submodule "deps/depot_tools"]
path = deps/depot_tools
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
-56
View File
@@ -1,56 +0,0 @@
{
"files.associations": {
"zmalloc.h": "c",
"stat.h": "c",
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"fstream": "cpp",
"functional": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"numeric": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"scoped_allocator": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"utility": "cpp"
}
}
+2072 -11
View File
File diff suppressed because it is too large. Load diff
+15 -5
View File
@@ -14,9 +14,7 @@ each source file that you contribute.
PLEASE DO NOT POST GENERAL QUESTIONS that are not about bugs or suspected
bugs in the Github issues system. We'll be very happy to help you and provide
all the support at the Reddit sub:
http://reddit.com/r/redis
all the support in the mailing list.
There is also an active community of Redis users at Stack Overflow:
@@ -24,7 +22,12 @@ each source file that you contribute.
# How to provide a patch for a new feature
1. If it is a major feature or a semantical change, please post it as a new submission in r/redis on Reddit at http://reddit.com/r/redis. Try to be passionate about why the feature is needed, make users upvote your proposal to gain traction and so forth. Read feedbacks about the community. But in this first step **please don't write code yet**.
1. If it is a major feature or a semantical change, please don't start coding
straight away: if your feature is not a conceptual fit you'll lose a lot of
time writing the code without any reason. Start by posting in the mailing list
and creating an issue at Github with the description of, exactly, what you want
to accomplish and why. Use cases are important for features to be accepted.
Here you'll see if there is consensus about your idea.
2. If in step 1 you get an acknowledgment from the project leaders, use the
following procedure to submit a patch:
@@ -35,6 +38,13 @@ each source file that you contribute.
d. Initiate a pull request on github ( https://help.github.com/articles/creating-a-pull-request/ )
e. Done :)
For minor fixes just open a pull request on Github.
3. Keep in mind that we are very overloaded, so issues and PRs sometimes wait
for a *very* long time. However this is not lack of interest, as the project
gets more and more users, we find ourselves in a constant need to prioritize
certain issues/PRs over others. If you think your issue/PR is very important
try to popularize it, have other users commenting and sharing their point of
view and so forth. This helps.
4. For minor fixes just open a pull request on Github.
Thanks!
+10
View File
@@ -0,0 +1,10 @@
FROM ubuntu:18.04
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qqy \
build-essential nasm autotools-dev autoconf libcurl4-openssl-dev libjemalloc-dev tcl tcl-dev uuid-dev libcurl4-openssl-dev \
&& apt-get clean
CMD make
-67
View File
@@ -1,67 +0,0 @@
[Note: this is the Redis manifesto, for general information about
installing and running Redis read the README file instead.]
Redis Manifesto
===============
1 - A DSL for Abstract Data Types. Redis is a DSL (Domain Specific Language)
that manipulates abstract data types and implemented as a TCP daemon.
Commands manipulate a key space where keys are binary-safe strings and
values are different kinds of abstract data types. Every data type
represents an abstract version of a fundamental data structure. For instance
Redis Lists are an abstract representation of linked lists. In Redis, the
essence of a data type isn't just the kind of operations that the data types
support, but also the space and time complexity of the data type and the
operations performed upon it.
2 - Memory storage is #1. The Redis data set, composed of defined key-value
pairs, is primarily stored in the computer's memory. The amount of memory in
all kinds of computers, including entry-level servers, is increasing
significantly each year. Memory is fast, and allows Redis to have very
predictable performance. Datasets composed of 10k or 40 millions keys will
perform similarly. Complex data types like Redis Sorted Sets are easy to
implement and manipulate in memory with good performance, making Redis very
simple. Redis will continue to explore alternative options (where data can
be optionally stored on disk, say) but the main goal of the project remains
the development of an in-memory database.
3 - Fundamental data structures for a fundamental API. The Redis API is a direct
consequence of fundamental data structures. APIs can often be arbitrary but
not an API that resembles the nature of fundamental data structures. If we
ever meet intelligent life forms from another part of the universe, they'll
likely know, understand and recognize the same basic data structures we have
in our computer science books. Redis will avoid intermediate layers in API,
so that the complexity is obvious and more complex operations can be
performed as the sum of the basic operations.
4 - Code is like a poem; it's not just something we write to reach some
practical result. Sometimes people that are far from the Redis philosophy
suggest using other code written by other authors (frequently in other
languages) in order to implement something Redis currently lacks. But to us
this is like if Shakespeare decided to end Enrico IV using the Paradiso from
the Divina Commedia. Is using any external code a bad idea? Not at all. Like
in "One Thousand and One Nights" smaller self contained stories are embedded
in a bigger story, we'll be happy to use beautiful self contained libraries
when needed. At the same time, when writing the Redis story we're trying to
write smaller stories that will fit in to other code.
5 - We're against complexity. We believe designing systems is a fight against
complexity. We'll accept to fight the complexity when it's worthwhile but
we'll try hard to recognize when a small feature is not worth 1000s of lines
of code. Most of the time the best way to fight complexity is by not
creating it at all.
6 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits
naturally into a distributed version of Redis and 2) a more complex API that
supports multi-key operations. Both are useful if used judiciously but
there's no way to make the more complex multi-keys API distributed in an
opaque way without violating our other principles. We don't want to provide
the illusion of something that will work magically when actually it can't in
all cases. Instead we'll provide commands to quickly migrate keys from one
instance to another to perform multi-key operations and expose the tradeoffs
to the user.
7 - We optimize for joy. We believe writing code is a lot of hard work, and the
only way it can be worth is by enjoying it. When there is no longer joy in
writing code, the best thing to do is stop. To prevent this, we'll avoid
taking paths that will make Redis less of a joy to develop.
+104 -9
View File
@@ -1,16 +1,51 @@
![Current Release](https://img.shields.io/github/release/JohnSully/KeyDB.svg)
![CI](https://github.com/JohnSully/KeyDB/workflows/CI/badge.svg?branch=unstable)
[![Join the chat at https://gitter.im/KeyDB/community](https://badges.gitter.im/KeyDB/community.svg)](https://gitter.im/KeyDB/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![StackShare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/eq-alpha-technology-inc/eq-alpha-technology-inc)
##### 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).
##### Have feedback? Take our quick survey: https://www.surveymonkey.com/r/Y9XNS93
What is KeyDB?
--------------
KeyDB is a high performance fork of Redis focussing on multithreading, memory efficiency, and high throughput. In addition to multithreading KeyDB also has features only available in Redis Enterprise such as FLASH storage support, and some not available at all such as direct backup to AWS S3.
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.
On the same hardware KeyDB can perform twice as many queries per second as Redis, with 60% lower latency.
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.
On the same hardware KeyDB can perform twice as many queries per second as Redis, with 60% lower latency. Active-Replication simplifies hot-spare failover allowing you to easily distribute writes over replicas and use simple TCP based load balancing/failover. KeyDB's higher performance allows you to do more on less hardware which reduces operation costs and complexity.
<img src="https://keydb.dev/assets/img/blog/5x_opspersecVSdatasize.PNG"/>
See the full benchmark results and setup information here: https://docs.keydb.dev/blog/2019/10/07/blog-post/
Why fork Redis?
---------------
The Redis maintainers have continually reiterated that they do not plan to support multithreading. While we have great respect for the redis team, we feel the analysis justifying this decision is incorrect. In addition we wanted open source implementations of features currently only available in proprietary modules. We feel a fork is the best way to accelerate development in the areas of most interest to us.
KeyDB has a different philosophy on how the codebase should evolve. We feel that ease of use, high performance, and a "batteries included" approach is the best way to create a good user experience. While we have great respect for the Redis maintainers it is our opinion that the Redis approach focuses too much on simplicity of the code base at the expense of complexity for the user. This results in the need for external components and workarounds to solve common problems - resulting in more complexity overall.
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.
Additional Resources
--------------------
Try our docker container: https://hub.docker.com/r/eqalpha/keydb
Talk on Gitter: https://gitter.im/KeyDB
Visit our Website: https://keydb.dev
See options for channel partners and support contracts: https://keydb.dev/support.html
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.
We plan to track the Redis repo closely and hope our projects can learn from each other.
Benchmarking KeyDB
------------------
@@ -25,32 +60,56 @@ New Configuration Options
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 one.
scratch-file-path /path
If you would like to use the FLASH backed 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.
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 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. This requires the AWS CLI tools to be installed and configured which are used under the hood to transfer the data.
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
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
--------------
KeyDB can be compiled and is tested for use on Linux. KeyDB currently relies on SO_REUSEADDR's load balancing behavior which is available only in Linux. When we support marshalling connections across threads we plan to support other operating systems such as FreeBSD.
KeyDB can be compiled and is tested for use on Linux. KeyDB currently relies on SO_REUSEPORT's load balancing behavior which is available only in Linux. When we support marshalling connections across threads we plan to support other operating systems such as FreeBSD.
Install dependencies:
% 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
You can enable flash support with (Note: autoconf and autotools must be installed):
To build with TLS support, you'll need OpenSSL development libraries (e.g.
libssl-dev on Debian/Ubuntu) and run:
% make BUILD_TLS=yes
You can enable flash support with:
% make MALLOC=memkind
***Note that the following dependencies may be needed:
% sudo apt-get install autoconf autotools-dev libnuma-dev libtool
If TLS is built, running the tests with TLS enabled (you will need `tcl-tls`
installed):
% ./utils/gen-test-certs.sh
% ./runtest --tls
Fixing build problems with dependencies or cached build options
---------
@@ -133,6 +192,14 @@ as options using the command line. Examples:
All the options in keydb.conf are also supported as options using the command
line, with exactly the same name.
Running Redis with TLS:
------------------
Please consult the [TLS.md](TLS.md) file for more information on
how to use Redis with TLS.
Playing with KeyDB
------------------
@@ -153,7 +220,7 @@ then in another terminal try the following:
(integer) 2
keydb>
You can find the list of all the available commands at http://redis.io/commands.
You can find the list of all the available commands at https://docs.keydb.dev/docs/commands/
Installing KeyDB
-----------------
@@ -174,6 +241,8 @@ for Ubuntu and Debian systems:
% cd utils
% ./install_server.sh
_Note_: `install_server.sh` will not work on Mac OSX; it is built for Linux only.
The script will ask you a few questions and will setup everything you need
to run KeyDB properly as a background daemon that will start again on
system reboots.
@@ -181,6 +250,32 @@ system reboots.
You'll be able to stop and start KeyDB using the script named
`/etc/init.d/keydb_<portnumber>`, for instance `/etc/init.d/keydb_6379`.
Multithreading Architecture
---------------------------
KeyDB works by running the normal Redis event loop on multiple threads. Network IO, and query parsing are done concurrently. Each connection is assigned a thread on accept(). Access to the core hash table is guarded by spinlock. Because the hashtable access is extremely fast this lock has low contention. Transactions hold the lock for the duration of the EXEC command. Modules work in concert with the GIL which is only acquired when all server threads are paused. This maintains the atomicity guarantees modules expect.
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
-----------------
+77
View File
@@ -0,0 +1,77 @@
TLS Support
===========
Getting Started
---------------
### Building
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 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 Redis and Redis
Cluster tests in TLS mode.
### Running manually
To manually run a Redis server with TLS mode (assuming `gen-test-certs.sh` was
invoked so sample certificates/keys are available):
./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 `redis-cli`:
./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 Redis Cluster use TLS across nodes use `--tls-cluster yes`.
Connections
-----------
All socket operations now go through a connection abstraction layer that hides
I/O and read/write event handling from the caller.
Note that unlike Redis, KeyDB fully supports multithreading of TLS connections.
To-Do List
----------
- [ ] Add session caching support. Check if/how it's handled by clients to
assess how useful/important it is.
- [ ] 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.
- [ ] redis-cli `--slave` and `--rdb` support.
Multi-port
----------
Consider the implications of allowing TLS to be configured on a separate port,
making Redis listening on multiple ports:
1. Startup banner port notification
2. Proctitle
3. How slaves announce themselves
4. Cluster bus port calculation
+5 -1
View File
@@ -41,9 +41,13 @@ distclean:
.PHONY: distclean
ifeq ($(BUILD_TLS),yes)
HIREDIS_MAKE_FLAGS = USE_SSL=1
endif
hiredis: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd hiredis && $(MAKE) static
cd hiredis && $(MAKE) static $(HIREDIS_MAKE_FLAGS)
.PHONY: hiredis
+1
View File
@@ -5,3 +5,4 @@
/*.dylib
/*.a
/*.pc
*.dSYM
+63 -11
View File
@@ -26,20 +26,72 @@ addons:
- libc6-dev-i386
- libc6-dbg:i386
- gcc-multilib
- g++-multilib
- valgrind
env:
- CFLAGS="-Werror"
- PRE="valgrind --track-origins=yes --leak-check=full"
- TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror"
- TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full"
- BITS="32"
- BITS="64"
script:
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON";
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
CXXFLAGS="-m32 -Werror";
LDFLAGS="-m32";
EXTRA_CMAKE_OPTS=;
else
CFLAGS="-Werror";
CXXFLAGS="-Werror";
fi;
else
TEST_PREFIX="valgrind --track-origins=yes --leak-check=full";
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
CXXFLAGS="-m32 -Werror";
LDFLAGS="-m32";
EXTRA_CMAKE_OPTS=;
else
CFLAGS="-Werror";
CXXFLAGS="-Werror";
fi;
fi;
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
- mkdir build/ && cd build/
- cmake .. ${EXTRA_CMAKE_OPTS}
- make VERBOSE=1
- ctest -V
matrix:
exclude:
- os: osx
env: PRE="valgrind --track-origins=yes --leak-check=full"
include:
# Windows MinGW cross compile on Linux
- os: linux
dist: xenial
compiler: mingw
addons:
apt:
packages:
- ninja-build
- gcc-mingw-w64-x86-64
- g++-mingw-w64-x86-64
script:
- mkdir build && cd build
- CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on
- ninja -v
- os: osx
env: TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full"
script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example
# Windows MSVC 2017
- os: windows
compiler: msvc
env:
- MATRIX_EVAL="CC=cl.exe && CXX=cl.exe"
before_install:
- eval "${MATRIX_EVAL}"
install:
- choco install ninja
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 &&
ninja -v'
- ctest -V
+13 -2
View File
@@ -12,6 +12,16 @@
compare to other values, casting might be necessary or can be removed, if
casting was applied before.
### 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.
* `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])
@@ -50,8 +60,9 @@
* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
* Fix warnings, when compiled with -Wshadow
* Make hiredis compile in Cygwin on Windows, now CI-tested
**BREAKING CHANGES**:
* 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`.
* Remove backwards compatibility macro's
+90
View File
@@ -0,0 +1,90 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.4.0)
INCLUDE(GNUInstallDirs)
PROJECT(hiredis)
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
MACRO(getVersionBit name)
SET(VERSION_REGEX "^#define ${name} (.+)$")
FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h"
VERSION_BIT REGEX ${VERSION_REGEX})
STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
ENDMACRO(getVersionBit)
getVersionBit(HIREDIS_MAJOR)
getVersionBit(HIREDIS_MINOR)
getVersionBit(HIREDIS_PATCH)
getVersionBit(HIREDIS_SONAME)
SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}")
MESSAGE("Detected version: ${VERSION}")
PROJECT(hiredis VERSION "${VERSION}")
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
ADD_LIBRARY(hiredis SHARED
async.c
dict.c
hiredis.c
net.c
read.c
sds.c
sockcompat.c)
SET_TARGET_PROPERTIES(hiredis
PROPERTIES
VERSION "${HIREDIS_SONAME}")
IF(WIN32 OR MINGW)
TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
ENDIF()
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC .)
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
INSTALL(TARGETS hiredis
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
INSTALL(FILES hiredis.h read.h sds.h async.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
INSTALL(DIRECTORY adapters
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
IF(ENABLE_SSL)
IF (NOT OPENSSL_ROOT_DIR)
IF (APPLE)
SET(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
ENDIF()
ENDIF()
FIND_PACKAGE(OpenSSL REQUIRED)
ADD_LIBRARY(hiredis_ssl SHARED
ssl.c)
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
INSTALL(TARGETS hiredis_ssl
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)
ENDIF()
IF(NOT (WIN32 OR MINGW))
ENABLE_TESTING()
ADD_EXECUTABLE(hiredis-test test.c)
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
ENDIF()
# Add examples
IF(ENABLE_EXAMPLES)
ADD_SUBDIRECTORY(examples)
ENDIF(ENABLE_EXAMPLES)
+83 -23
View File
@@ -3,11 +3,17 @@
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
# This file is released under the BSD license, see the COPYING file
OBJ=net.o hiredis.o sds.o async.o read.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
ifeq ($(USE_SSL),1)
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
endif
TESTS=hiredis-test
LIBNAME=libhiredis
SSL_LIBNAME=libhiredis_ssl
PKGCONFNAME=hiredis.pc
SSL_PKGCONFNAME=hiredis_ssl.pc
HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}')
@@ -39,7 +45,7 @@ export REDIS_TEST_CONFIG
CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++')
OPTIMIZATION?=-O3
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers
DEBUG_FLAGS?= -g -ggdb
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS)
REAL_LDFLAGS=$(LDFLAGS)
@@ -49,12 +55,30 @@ STLIBSUFFIX=a
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=$(AR) rcs
# Platform-specific overrides
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
USE_SSL?=0
# This is required for test.c only
ifeq ($(USE_SSL),1)
CFLAGS+=-DHIREDIS_TEST_SSL
endif
ifeq ($(uname_S),Linux)
SSL_LDFLAGS=-lssl -lcrypto
else
OPENSSL_PREFIX?=/usr/local/opt/openssl
CFLAGS+=-I$(OPENSSL_PREFIX)/include
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
endif
ifeq ($(uname_S),SunOS)
REAL_LDFLAGS+= -ldl -lnsl -lsocket
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
@@ -66,40 +90,61 @@ ifeq ($(uname_S),Darwin)
endif
all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
ifeq ($(USE_SSL),1)
all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
endif
# Deps (use make dep to generate this)
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
net.o: net.c fmacros.h net.h hiredis.h read.h sds.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
test.o: test.c fmacros.h hiredis.h read.h sds.h
$(DYLIBNAME): $(OBJ)
$(DYLIB_MAKE_CMD) $(OBJ)
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)
$(STLIBNAME): $(OBJ)
$(STLIB_MAKE_CMD) $(OBJ)
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
$(SSL_DYLIBNAME): $(SSL_OBJ)
$(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
$(SSL_STLIBNAME): $(SSL_OBJ)
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)
dynamic: $(DYLIBNAME)
static: $(STLIBNAME)
ifeq ($(USE_SSL),1)
dynamic: $(SSL_DYLIBNAME)
static: $(SSL_STLIBNAME)
endif
# Binaries:
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS)
hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS)
hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS)
hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS)
hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS)
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:
@@ -116,7 +161,7 @@ hiredis-example-libuv:
@false
else
hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS)
endif
ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),)
@@ -133,32 +178,33 @@ hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME)
endif
hiredis-example: examples/example.c $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
examples: $(EXAMPLES)
hiredis-test: test.o $(STLIBNAME)
TEST_LIBS = $(STLIBNAME)
ifeq ($(USE_SSL),1)
TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread
endif
hiredis-test: test.o $(TEST_LIBS)
hiredis-%: %.o $(STLIBNAME)
$(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)
test: hiredis-test
./hiredis-test
check: hiredis-test
@echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) -
$(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \
( kill `cat /tmp/hiredis-test-redis.pid` && false )
kill `cat /tmp/hiredis-test-redis.pid`
TEST_SSL=$(USE_SSL) ./test.sh
.c.o:
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
clean:
rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
dep:
$(CC) -MM *.c
$(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c
INSTALL?= cp -pPR
@@ -175,6 +221,20 @@ $(PKGCONFNAME): hiredis.h
@echo Libs: -L\$${libdir} -lhiredis >> $@
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
$(SSL_PKGCONFNAME): hiredis.h
@echo "Generating $@ for pkgconfig..."
@echo prefix=$(PREFIX) > $@
@echo exec_prefix=\$${prefix} >> $@
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
@echo >> $@
@echo Name: hiredis_ssl >> $@
@echo Description: SSL Support for hiredis. >> $@
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
@echo Requires: hiredis >> $@
@echo Libs: -L\$${libdir} -lhiredis_ssl >> $@
@echo Libs.private: -lssl -lcrypto >> $@
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 $(INSTALL_INCLUDE_PATH)
+2 -1
View File
@@ -286,6 +286,7 @@ return `REDIS_ERR`. The function to set the disconnect callback has the followin
```c
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
```
`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
### Sending commands and their callbacks
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
@@ -406,6 +407,6 @@ as soon as possible in order to prevent allocation of useless memory.
## AUTHORS
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
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)
+88 -24
View File
@@ -34,48 +34,113 @@
#include "../hiredis.h"
#include "../async.h"
#define REDIS_LIBEVENT_DELETED 0x01
#define REDIS_LIBEVENT_ENTERED 0x02
typedef struct redisLibeventEvents {
redisAsyncContext *context;
struct event *rev, *wev;
struct event *ev;
struct event_base *base;
struct timeval tv;
short flags;
short state;
} redisLibeventEvents;
static void redisLibeventReadEvent(int fd, short event, void *arg) {
((void)fd); ((void)event);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
redisAsyncHandleRead(e->context);
static void redisLibeventDestroy(redisLibeventEvents *e) {
free(e);
}
static void redisLibeventWriteEvent(int fd, short event, void *arg) {
((void)fd); ((void)event);
static void redisLibeventHandler(int fd, short event, void *arg) {
((void)fd);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
redisAsyncHandleWrite(e->context);
e->state |= REDIS_LIBEVENT_ENTERED;
#define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\
redisLibeventDestroy(e);\
return; \
}
if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleTimeout(e->context);
CHECK_DELETED();
}
if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleRead(e->context);
CHECK_DELETED();
}
if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleWrite(e->context);
CHECK_DELETED();
}
e->state &= ~REDIS_LIBEVENT_ENTERED;
#undef CHECK_DELETED
}
static void redisLibeventUpdate(void *privdata, short flag, int isRemove) {
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL;
if (isRemove) {
if ((e->flags & flag) == 0) {
return;
} else {
e->flags &= ~flag;
}
} else {
if (e->flags & flag) {
return;
} else {
e->flags |= flag;
}
}
event_del(e->ev);
event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST,
redisLibeventHandler, privdata);
event_add(e->ev, tv);
}
static void redisLibeventAddRead(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_add(e->rev,NULL);
redisLibeventUpdate(privdata, EV_READ, 0);
}
static void redisLibeventDelRead(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_del(e->rev);
redisLibeventUpdate(privdata, EV_READ, 1);
}
static void redisLibeventAddWrite(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_add(e->wev,NULL);
redisLibeventUpdate(privdata, EV_WRITE, 0);
}
static void redisLibeventDelWrite(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_del(e->wev);
redisLibeventUpdate(privdata, EV_WRITE, 1);
}
static void redisLibeventCleanup(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_free(e->rev);
event_free(e->wev);
free(e);
if (!e) {
return;
}
event_del(e->ev);
event_free(e->ev);
e->ev = NULL;
if (e->state & REDIS_LIBEVENT_ENTERED) {
e->state |= REDIS_LIBEVENT_DELETED;
} else {
redisLibeventDestroy(e);
}
}
static void redisLibeventSetTimeout(void *privdata, struct timeval tv) {
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
short flags = e->flags;
e->flags = 0;
e->tv = tv;
redisLibeventUpdate(e, flags, 0);
}
static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
@@ -87,7 +152,7 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisLibeventEvents*)malloc(sizeof(*e));
e = (redisLibeventEvents*)calloc(1, sizeof(*e));
e->context = ac;
/* Register functions to start/stop listening for events */
@@ -96,13 +161,12 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
ac->ev.addWrite = redisLibeventAddWrite;
ac->ev.delWrite = redisLibeventDelWrite;
ac->ev.cleanup = redisLibeventCleanup;
ac->ev.scheduleTimer = redisLibeventSetTimeout;
ac->ev.data = e;
/* Initialize and install read/write events */
e->rev = event_new(base, c->fd, EV_READ, redisLibeventReadEvent, e);
e->wev = event_new(base, c->fd, EV_WRITE, redisLibeventWriteEvent, e);
event_add(e->rev, NULL);
event_add(e->wev, NULL);
e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e);
e->base = base;
return REDIS_OK;
}
#endif
+4 -3
View File
@@ -5,8 +5,9 @@ environment:
CC: gcc
- CYG_BASH: C:\cygwin\bin\bash
CC: gcc
TARGET: 32bit
TARGET_VARS: 32bit-vars
CFLAGS: -m32
CXXFLAGS: -m32
LDFLAGS: -m32
clone_depth: 1
@@ -20,4 +21,4 @@ install:
build_script:
- 'echo building...'
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; make LDFLAGS=$LDFLAGS CC=$CC $TARGET CFLAGS=$CFLAGS && make LDFLAGS=$LDFLAGS CC=$CC $TARGET_VARS hiredis-example"'
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; mkdir build && cd build && cmake .. -G \"Unix Makefiles\" && make VERBOSE=1"'
+113 -63
View File
@@ -32,7 +32,9 @@
#include "fmacros.h"
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
#include <strings.h>
#endif
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -40,22 +42,9 @@
#include "net.h"
#include "dict.c"
#include "sds.h"
#include "win32.h"
#define _EL_ADD_READ(ctx) do { \
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
} while(0)
#define _EL_DEL_READ(ctx) do { \
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
} while(0)
#define _EL_ADD_WRITE(ctx) do { \
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
} while(0)
#define _EL_DEL_WRITE(ctx) do { \
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
} while(0)
#define _EL_CLEANUP(ctx) do { \
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
} while(0);
#include "async_private.h"
/* Forward declaration of function in hiredis.c */
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);
@@ -126,6 +115,7 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
ac->ev.addWrite = NULL;
ac->ev.delWrite = NULL;
ac->ev.cleanup = NULL;
ac->ev.scheduleTimer = NULL;
ac->onConnect = NULL;
ac->onDisconnect = NULL;
@@ -150,56 +140,52 @@ static void __redisAsyncCopyError(redisAsyncContext *ac) {
ac->errstr = c->errstr;
}
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
redisOptions myOptions = *options;
redisContext *c;
redisAsyncContext *ac;
c = redisConnectNonBlock(ip,port);
if (c == NULL)
myOptions.options |= REDIS_OPT_NONBLOCK;
c = redisConnectWithOptions(&myOptions);
if (c == NULL) {
return NULL;
}
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
__redisAsyncCopyError(ac);
return ac;
}
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
return redisAsyncConnectWithOptions(&options);
}
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
const char *source_addr) {
redisContext *c = redisConnectBindNonBlock(ip,port,source_addr);
redisAsyncContext *ac = redisAsyncInitialize(c);
__redisAsyncCopyError(ac);
return ac;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.endpoint.tcp.source_addr = source_addr;
return redisAsyncConnectWithOptions(&options);
}
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
const char *source_addr) {
redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr);
redisAsyncContext *ac = redisAsyncInitialize(c);
__redisAsyncCopyError(ac);
return ac;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.options |= REDIS_OPT_REUSEADDR;
options.endpoint.tcp.source_addr = source_addr;
return redisAsyncConnectWithOptions(&options);
}
redisAsyncContext *redisAsyncConnectUnix(const char *path) {
redisContext *c;
redisAsyncContext *ac;
c = redisConnectUnixNonBlock(path);
if (c == NULL)
return NULL;
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
__redisAsyncCopyError(ac);
return ac;
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
return redisAsyncConnectWithOptions(&options);
}
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
@@ -328,7 +314,7 @@ void redisAsyncFree(redisAsyncContext *ac) {
}
/* Helper function to make the disconnect happen and clean up. */
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
void __redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
/* Make sure error is accessible if there is any */
@@ -344,9 +330,15 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
c->flags |= REDIS_DISCONNECTING;
}
/* cleanup event library on disconnect.
* this is safe to call multiple times */
_EL_CLEANUP(ac);
/* For non-clean disconnects, __redisAsyncFree() will execute pending
* callbacks with a NULL-reply. */
__redisAsyncFree(ac);
if (!(c->flags & REDIS_NO_AUTO_FREE)) {
__redisAsyncFree(ac);
}
}
/* Tries to do a clean disconnect from Redis, meaning it stops new commands
@@ -358,6 +350,9 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
void redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
c->flags |= REDIS_DISCONNECTING;
/** unset the auto-free flag here, because disconnect undoes this */
c->flags &= ~REDIS_NO_AUTO_FREE;
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
__redisAsyncDisconnect(ac);
}
@@ -408,7 +403,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
/* Unset subscribed flag only when no pipelined pending subscribe. */
if (reply->element[2]->integer == 0
if (reply->element[2]->integer == 0
&& dictSize(ac->sub.channels) == 0
&& dictSize(ac->sub.patterns) == 0)
c->flags &= ~REDIS_SUBSCRIBED;
@@ -524,6 +519,18 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
}
}
void redisAsyncRead(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
if (redisBufferRead(c) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Always re-schedule reads */
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
}
/* This function should be called when the socket is readable.
* It processes all replies that can be read and executes their callbacks.
*/
@@ -539,28 +546,13 @@ void redisAsyncHandleRead(redisAsyncContext *ac) {
return;
}
if (redisBufferRead(c) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Always re-schedule reads */
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
c->funcs->async_read(ac);
}
void redisAsyncHandleWrite(redisAsyncContext *ac) {
void redisAsyncWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
int done = 0;
if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}
if (redisBufferWrite(c,&done) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
@@ -575,6 +567,51 @@ void redisAsyncHandleWrite(redisAsyncContext *ac) {
}
}
void redisAsyncHandleWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}
c->funcs->async_write(ac);
}
void __redisSetError(redisContext *c, int type, const char *str);
void redisAsyncHandleTimeout(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;
if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) {
/* Nothing to do - just an idle timeout */
return;
}
if (!c->err) {
__redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout");
}
if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) {
ac->onConnect(ac, REDIS_ERR);
}
while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) {
__redisRunCallback(ac, &cb, NULL);
}
/**
* TODO: Don't automatically sever the connection,
* rather, allow to ignore <x> responses before the queue is clear
*/
__redisAsyncDisconnect(ac);
}
/* Sets a pointer to the first argument and its length starting at p. Returns
* the number of bytes to skip to get to the following argument. */
static const char *nextArgument(const char *start, const char **str, size_t *len) {
@@ -714,3 +751,16 @@ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
int status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
return status;
}
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
if (!ac->c.timeout) {
ac->c.timeout = calloc(1, sizeof(tv));
}
if (tv.tv_sec == ac->c.timeout->tv_sec &&
tv.tv_usec == ac->c.timeout->tv_usec) {
return;
}
*ac->c.timeout = tv;
}
+8
View File
@@ -57,6 +57,7 @@ typedef struct redisCallbackList {
/* Connection callback prototypes */
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
typedef void(redisTimerCallback)(void *timer, void *privdata);
/* Context for an async connection to Redis */
typedef struct redisAsyncContext {
@@ -81,6 +82,7 @@ typedef struct redisAsyncContext {
void (*addWrite)(void *privdata);
void (*delWrite)(void *privdata);
void (*cleanup)(void *privdata);
void (*scheduleTimer)(void *privdata, struct timeval tv);
} ev;
/* Called when either the connection is terminated due to an error or per
@@ -106,6 +108,7 @@ typedef struct redisAsyncContext {
} redisAsyncContext;
/* Functions that proxy to hiredis */
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
@@ -113,12 +116,17 @@ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
redisAsyncContext *redisAsyncConnectUnix(const char *path);
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
void redisAsyncDisconnect(redisAsyncContext *ac);
void redisAsyncFree(redisAsyncContext *ac);
/* Handle read/write events */
void redisAsyncHandleRead(redisAsyncContext *ac);
void redisAsyncHandleWrite(redisAsyncContext *ac);
void redisAsyncHandleTimeout(redisAsyncContext *ac);
void redisAsyncRead(redisAsyncContext *ac);
void redisAsyncWrite(redisAsyncContext *ac);
/* Command functions for an async context. Write the command to the
* output buffer and register the provided callback. */
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis 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_ASYNC_PRIVATE_H
#define __HIREDIS_ASYNC_PRIVATE_H
#define _EL_ADD_READ(ctx) \
do { \
refreshTimeout(ctx); \
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
} while (0)
#define _EL_DEL_READ(ctx) do { \
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
} while(0)
#define _EL_ADD_WRITE(ctx) \
do { \
refreshTimeout(ctx); \
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
} while (0)
#define _EL_DEL_WRITE(ctx) do { \
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
} while(0)
#define _EL_CLEANUP(ctx) do { \
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
ctx->ev.cleanup = NULL; \
} while(0);
static inline void refreshTimeout(redisAsyncContext *ctx) {
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);
// }
}
}
void __redisAsyncDisconnect(redisAsyncContext *ac);
void redisProcessCallbacks(redisAsyncContext *ac);
#endif /* __HIREDIS_ASYNC_PRIVATE_H */
+46
View File
@@ -0,0 +1,46 @@
INCLUDE(FindPkgConfig)
# Check for GLib
PKG_CHECK_MODULES(GLIB2 glib-2.0)
if (GLIB2_FOUND)
INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS})
LINK_DIRECTORIES(${GLIB2_LIBRARY_DIRS})
ADD_EXECUTABLE(example-glib example-glib.c)
TARGET_LINK_LIBRARIES(example-glib hiredis ${GLIB2_LIBRARIES})
ENDIF(GLIB2_FOUND)
FIND_PATH(LIBEV ev.h
HINTS /usr/local /usr/opt/local
ENV LIBEV_INCLUDE_DIR)
if (LIBEV)
# Just compile and link with libev
ADD_EXECUTABLE(example-libev example-libev.c)
TARGET_LINK_LIBRARIES(example-libev hiredis ev)
ENDIF()
FIND_PATH(LIBEVENT event.h)
if (LIBEVENT)
ADD_EXECUTABLE(example-libevent example-libevent)
TARGET_LINK_LIBRARIES(example-libevent hiredis event)
ENDIF()
FIND_PATH(LIBUV uv.h)
IF (LIBUV)
ADD_EXECUTABLE(example-libuv example-libuv.c)
TARGET_LINK_LIBRARIES(example-libuv hiredis uv)
ENDIF()
IF (APPLE)
FIND_LIBRARY(CF CoreFoundation)
ADD_EXECUTABLE(example-macosx example-macosx.c)
TARGET_LINK_LIBRARIES(example-macosx hiredis ${CF})
ENDIF()
IF (ENABLE_SSL)
ADD_EXECUTABLE(example-ssl example-ssl.c)
TARGET_LINK_LIBRARIES(example-ssl hiredis hiredis_ssl)
ENDIF()
ADD_EXECUTABLE(example example.c)
TARGET_LINK_LIBRARIES(example hiredis)
+73
View File
@@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <hiredis_ssl.h>
#include <async.h>
#include <adapters/libevent.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
struct event_base *base = event_base_new();
if (argc < 5) {
fprintf(stderr,
"Usage: %s <key> <host> <port> <cert> <certKey> [ca]\n", argv[0]);
exit(1);
}
const char *value = argv[1];
size_t nvalue = strlen(value);
const char *hostname = argv[2];
int port = atoi(argv[3]);
const char *cert = argv[4];
const char *certKey = argv[5];
const char *caCert = argc > 5 ? argv[6] : NULL;
redisAsyncContext *c = redisAsyncConnect(hostname, port);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) {
printf("SSL Error!\n");
exit(1);
}
redisLibeventAttach(c,base);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
event_base_dispatch(base);
return 0;
}
+13 -2
View File
@@ -9,7 +9,12 @@
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
if (reply == NULL) {
if (c->errstr) {
printf("errstr: %s\n", c->errstr);
}
return;
}
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
@@ -35,8 +40,14 @@ void disconnectCallback(const redisAsyncContext *c, int status) {
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
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.timeout = &tv;
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
+97
View File
@@ -0,0 +1,97 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
#include <hiredis_ssl.h>
int main(int argc, char **argv) {
unsigned int j;
redisContext *c;
redisReply *reply;
if (argc < 4) {
printf("Usage: %s <host> <port> <cert> <key> [ca]\n", argv[0]);
exit(1);
}
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
int port = atoi(argv[2]);
const char *cert = argv[3];
const char *key = argv[4];
const char *ca = argc > 4 ? argv[5] : NULL;
struct timeval tv = { 1, 500000 }; // 1.5 seconds
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
options.timeout = &tv;
c = redisConnectWithOptions(&options);
if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
redisFree(c);
} else {
printf("Connection error: can't allocate redis context\n");
}
exit(1);
}
if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) {
printf("Couldn't initialize SSL!\n");
printf("Error: %s\n", c->errstr);
redisFree(c);
exit(1);
}
/* PING server */
reply = redisCommand(c,"PING");
printf("PING: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key */
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
printf("SET: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key using binary safe API */
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);
/* Try a GET and two INCR */
reply = redisCommand(c,"GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* again ... */
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* Create a list of numbers, from 0 to 9 */
reply = redisCommand(c,"DEL mylist");
freeReplyObject(reply);
for (j = 0; j < 10; j++) {
char buf[64];
snprintf(buf,64,"%u",j);
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
freeReplyObject(reply);
}
/* Let's check what we have inside the list */
reply = redisCommand(c,"LRANGE mylist 0 -1");
if (reply->type == REDIS_REPLY_ARRAY) {
for (j = 0; j < reply->elements; j++) {
printf("%u) %s\n", j, reply->element[j]->str);
}
}
freeReplyObject(reply);
/* Disconnects and frees the context */
redisFree(c);
return 0;
}
+15 -2
View File
@@ -5,14 +5,27 @@
#include <hiredis.h>
int main(int argc, char **argv) {
unsigned int j;
unsigned int j, isunix = 0;
redisContext *c;
redisReply *reply;
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
if (argc > 2) {
if (*argv[2] == 'u' || *argv[2] == 'U') {
isunix = 1;
/* in this case, host is the path to the unix socket */
printf("Will connect to unix socket @%s\n", hostname);
}
}
int port = (argc > 2) ? atoi(argv[2]) : 6379;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
c = redisConnectWithTimeout(hostname, port, timeout);
if (isunix) {
c = redisConnectUnixWithTimeout(hostname, timeout);
} else {
c = redisConnectWithTimeout(hostname, port, timeout);
}
if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
+134 -122
View File
@@ -34,7 +34,6 @@
#include "fmacros.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
@@ -42,10 +41,20 @@
#include "hiredis.h"
#include "net.h"
#include "sds.h"
#include "async.h"
#include "win32.h"
static redisContextFuncs redisContextDefaultFuncs = {
.free_privdata = NULL,
.async_read = redisAsyncRead,
.async_write = redisAsyncWrite,
.read = redisNetRead,
.write = redisNetWrite
};
static redisReply *createReplyObject(int type);
static void *createStringObject(const redisReadTask *task, char *str, size_t len);
static void *createArrayObject(const redisReadTask *task, int elements);
static void *createArrayObject(const redisReadTask *task, size_t elements);
static void *createIntegerObject(const redisReadTask *task, long long value);
static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len);
static void *createNilObject(const redisReadTask *task);
@@ -112,21 +121,34 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
if (r == NULL)
return NULL;
buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
assert(task->type == REDIS_REPLY_ERROR ||
task->type == REDIS_REPLY_STATUS ||
task->type == REDIS_REPLY_STRING);
task->type == REDIS_REPLY_STRING ||
task->type == REDIS_REPLY_VERB);
/* Copy string value */
memcpy(buf,str,len);
buf[len] = '\0';
if (task->type == REDIS_REPLY_VERB) {
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;
} else {
buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
memcpy(buf,str,len);
buf[len] = '\0';
r->len = len;
}
r->str = buf;
r->len = len;
if (task->parent) {
parent = task->parent->obj;
@@ -138,7 +160,7 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
return r;
}
static void *createArrayObject(const redisReadTask *task, int elements) {
static void *createArrayObject(const redisReadTask *task, size_t elements) {
redisReply *r, *parent;
r = createReplyObject(task->type);
@@ -649,29 +671,30 @@ redisReader *redisReaderCreate(void) {
return redisReaderCreateWithFunctions(&defaultFunctions);
}
static redisContext *redisContextInit(void) {
static redisContext *redisContextInit(const redisOptions *options) {
redisContext *c;
c = calloc(1,sizeof(redisContext));
c = calloc(1, sizeof(*c));
if (c == NULL)
return NULL;
c->funcs = &redisContextDefaultFuncs;
c->obuf = sdsempty();
c->reader = redisReaderCreate();
c->fd = REDIS_INVALID_FD;
if (c->obuf == NULL || c->reader == NULL) {
redisFree(c);
return NULL;
}
(void)options; /* options are used in other functions */
return c;
}
void redisFree(redisContext *c) {
if (c == NULL)
return;
if (c->fd > 0)
close(c->fd);
redisNetClose(c);
sdsfree(c->obuf);
redisReaderFree(c->reader);
@@ -680,12 +703,16 @@ void redisFree(redisContext *c) {
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));
free(c);
}
int redisFreeKeepFd(redisContext *c) {
int fd = c->fd;
c->fd = -1;
redisFD redisFreeKeepFd(redisContext *c) {
redisFD fd = c->fd;
c->fd = REDIS_INVALID_FD;
redisFree(c);
return fd;
}
@@ -694,10 +721,13 @@ int redisReconnect(redisContext *c) {
c->err = 0;
memset(c->errstr, '\0', strlen(c->errstr));
if (c->fd > 0) {
close(c->fd);
if (c->privdata && c->funcs->free_privdata) {
c->funcs->free_privdata(c->privdata);
c->privdata = NULL;
}
redisNetClose(c);
sdsfree(c->obuf);
redisReaderFree(c->reader);
@@ -718,112 +748,107 @@ int redisReconnect(redisContext *c) {
return REDIS_ERR;
}
redisContext *redisConnectWithOptions(const redisOptions *options) {
redisContext *c = redisContextInit(options);
if (c == NULL) {
return NULL;
}
if (!(options->options & REDIS_OPT_NONBLOCK)) {
c->flags |= REDIS_BLOCK;
}
if (options->options & REDIS_OPT_REUSEADDR) {
c->flags |= REDIS_REUSEADDR;
}
if (options->options & REDIS_OPT_NOAUTOFREE) {
c->flags |= REDIS_NO_AUTO_FREE;
}
if (options->type == REDIS_CONN_TCP) {
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
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->timeout);
} else if (options->type == REDIS_CONN_USERFD) {
c->fd = options->endpoint.fd;
c->flags |= REDIS_CONNECTED;
} else {
// Unknown type - FIXME - FREE
return NULL;
}
if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
redisContextSetTimeout(c, *options->timeout);
}
return c;
}
/* Connect to a Redis instance. On error the field error in the returned
* context will be set to the return value of the error function.
* When no set of reply functions is given, the default set will be used. */
redisContext *redisConnect(const char *ip, int port) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags |= REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,NULL);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
return redisConnectWithOptions(&options);
}
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags |= REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,&tv);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.timeout = &tv;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectNonBlock(const char *ip, int port) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags &= ~REDIS_BLOCK;
redisContextConnectTcp(c,ip,port,NULL);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.options |= REDIS_OPT_NONBLOCK;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectBindNonBlock(const char *ip, int port,
const char *source_addr) {
redisContext *c = redisContextInit();
if (c == NULL)
return NULL;
c->flags &= ~REDIS_BLOCK;
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.endpoint.tcp.source_addr = source_addr;
options.options |= REDIS_OPT_NONBLOCK;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
const char *source_addr) {
redisContext *c = redisContextInit();
if (c == NULL)
return NULL;
c->flags &= ~REDIS_BLOCK;
c->flags |= REDIS_REUSEADDR;
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.endpoint.tcp.source_addr = source_addr;
options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectUnix(const char *path) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags |= REDIS_BLOCK;
redisContextConnectUnix(c,path,NULL);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
return redisConnectWithOptions(&options);
}
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags |= REDIS_BLOCK;
redisContextConnectUnix(c,path,&tv);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
options.timeout = &tv;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectUnixNonBlock(const char *path) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->flags &= ~REDIS_BLOCK;
redisContextConnectUnix(c,path,NULL);
return c;
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
options.options |= REDIS_OPT_NONBLOCK;
return redisConnectWithOptions(&options);
}
redisContext *redisConnectFd(int fd) {
redisContext *c;
c = redisContextInit();
if (c == NULL)
return NULL;
c->fd = fd;
c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
return c;
redisContext *redisConnectFd(redisFD fd) {
redisOptions options = {0};
options.type = REDIS_CONN_USERFD;
options.endpoint.fd = fd;
return redisConnectWithOptions(&options);
}
/* Set read/write timeout on a blocking socket. */
@@ -853,22 +878,15 @@ int redisBufferRead(redisContext *c) {
if (c->err)
return REDIS_ERR;
nread = read(c->fd,buf,sizeof(buf));
if (nread == -1) {
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
nread = c->funcs->read(c, buf, sizeof(buf));
if (nread > 0) {
if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {
__redisSetError(c, c->reader->err, c->reader->errstr);
return REDIS_ERR;
} else {
__redisSetError(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}
} else if (nread == 0) {
__redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
} else if (nread < 0) {
return REDIS_ERR;
} else {
if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
__redisSetError(c,c->reader->err,c->reader->errstr);
return REDIS_ERR;
}
}
return REDIS_OK;
}
@@ -883,21 +901,15 @@ int redisBufferRead(redisContext *c) {
* c->errstr to hold the appropriate error string.
*/
int redisBufferWrite(redisContext *c, int *done) {
int nwritten;
/* Return early when the context has seen an error. */
if (c->err)
return REDIS_ERR;
if (sdslen(c->obuf) > 0) {
nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
if (nwritten == -1) {
if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
} else {
__redisSetError(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}
int nwritten = c->funcs->write(c);
if (nwritten < 0) {
return REDIS_ERR;
} else if (nwritten > 0) {
if (nwritten == (signed)sdslen(c->obuf)) {
sdsfree(c->obuf);
+99 -4
View File
@@ -35,7 +35,11 @@
#define __HIREDIS_H
#include "read.h"
#include <stdarg.h> /* for va_list */
#ifndef _MSC_VER
#include <sys/time.h> /* for struct timeval */
#else
struct timeval; /* forward declaration */
#endif
#include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for sds */
@@ -74,6 +78,12 @@
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
#define REDIS_REUSEADDR 0x80
/**
* Flag that indicates the user does not want the context to
* be automatically freed upon error
*/
#define REDIS_NO_AUTO_FREE 0x200
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
@@ -92,6 +102,8 @@ typedef struct redisReply {
size_t len; /* Length of string */
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
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 */
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
@@ -111,14 +123,93 @@ void redisFreeSdsCommand(sds cmd);
enum redisConnectionType {
REDIS_CONN_TCP,
REDIS_CONN_UNIX
REDIS_CONN_UNIX,
REDIS_CONN_USERFD
};
struct redisSsl;
#define REDIS_OPT_NONBLOCK 0x01
#define REDIS_OPT_REUSEADDR 0x02
/**
* Don't automatically free the async object on a connection failure,
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
*/
#define REDIS_OPT_NOAUTOFREE 0x04
/* 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
* all bits set (~0) is INVALID_SOCKET. */
#ifndef _WIN32
typedef int redisFD;
#define REDIS_INVALID_FD -1
#else
#ifdef _WIN64
typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */
#else
typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */
#endif
#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */
#endif
typedef struct {
/*
* the type of connection to use. This also indicates which
* `endpoint` member field to use
*/
int type;
/* bit field of REDIS_OPT_xxx */
int options;
/* timeout value. if NULL, no timeout is used */
const struct timeval *timeout;
union {
/** use this field for tcp/ip connections */
struct {
const char *source_addr;
const char *ip;
int port;
} tcp;
/** use this field for unix domain sockets */
const char *unix_socket;
/**
* use this field to have hiredis operate an already-open
* file descriptor */
redisFD fd;
} endpoint;
} redisOptions;
/**
* Helper macros to initialize options to their specified fields.
*/
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
(opts)->type = REDIS_CONN_TCP; \
(opts)->endpoint.tcp.ip = ip_; \
(opts)->endpoint.tcp.port = port_;
#define REDIS_OPTIONS_SET_UNIX(opts, path) \
(opts)->type = REDIS_CONN_UNIX; \
(opts)->endpoint.unix_socket = path;
struct redisAsyncContext;
struct redisContext;
typedef struct redisContextFuncs {
void (*free_privdata)(void *);
void (*async_read)(struct redisAsyncContext *);
void (*async_write)(struct redisAsyncContext *);
int (*read)(struct redisContext *, char *, size_t);
int (*write)(struct redisContext *);
} redisContextFuncs;
/* Context for a connection to Redis */
typedef struct redisContext {
const redisContextFuncs *funcs; /* Function table */
int err; /* Error flags, 0 when there is no error */
char errstr[128]; /* String representation of error when applicable */
int fd;
redisFD fd;
int flags;
char *obuf; /* Write buffer */
redisReader *reader; /* Protocol reader */
@@ -139,8 +230,12 @@ typedef struct redisContext {
/* For non-blocking connect */
struct sockadr *saddr;
size_t addrlen;
/* Additional private data for hiredis addons such as SSL */
void *privdata;
} redisContext;
redisContext *redisConnectWithOptions(const redisOptions *options);
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
redisContext *redisConnectNonBlock(const char *ip, int port);
@@ -151,7 +246,7 @@ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
redisContext *redisConnectFd(int fd);
redisContext *redisConnectFd(redisFD fd);
/**
* Reconnect the given context using the saved information.
@@ -167,7 +262,7 @@ int redisReconnect(redisContext *c);
int redisSetTimeout(redisContext *c, const struct timeval tv);
int redisEnableKeepAlive(redisContext *c);
void redisFree(redisContext *c);
int redisFreeKeepFd(redisContext *c);
redisFD redisFreeKeepFd(redisContext *c);
int redisBufferRead(redisContext *c);
int redisBufferWrite(redisContext *c, int *done);
+11
View File
@@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis
Name: hiredis
Description: Minimalistic C client library for Redis.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lhiredis
Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2019, Redis Labs
*
* 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_SSL_H
#define __HIREDIS_SSL_H
/* This is the underlying struct for SSL in ssl.h, which is not included to
* keep build dependencies short here.
*/
struct ssl_st;
/**
* Secure the connection using SSL. This should be done before any command is
* executed on the connection.
*/
int redisSecureConnection(redisContext *c, const char *capath, const char *certpath,
const char *keypath, const char *servername);
/**
* Initiate SSL/TLS negotiation on a provided context.
*/
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
#endif /* __HIREDIS_SSL_H */
+12
View File
@@ -0,0 +1,12 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis
Name: hiredis_ssl
Description: SSL Support for hiredis.
Version: @PROJECT_VERSION@
Requires: hiredis
Libs: -L${libdir} -lhiredis_ssl
Libs.private: -lssl -lcrypto
+87 -35
View File
@@ -34,36 +34,64 @@
#include "fmacros.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <poll.h>
#include <limits.h>
#include <stdlib.h>
#include "net.h"
#include "sds.h"
#include "sockcompat.h"
#include "win32.h"
/* Defined in hiredis.c */
void __redisSetError(redisContext *c, int type, const char *str);
static void redisContextCloseFd(redisContext *c) {
if (c && c->fd >= 0) {
void redisNetClose(redisContext *c) {
if (c && c->fd != REDIS_INVALID_FD) {
close(c->fd);
c->fd = -1;
c->fd = REDIS_INVALID_FD;
}
}
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 */
return 0;
} else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {
/* especially in windows */
__redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");
return -1;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
} else if (nread == 0) {
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
return -1;
} else {
return nread;
}
}
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 */
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
return nwritten;
}
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
int errorno = errno; /* snprintf() may change errno */
char buf[128] = { 0 };
@@ -79,15 +107,15 @@ static int redisSetReuseAddr(redisContext *c) {
int on = 1;
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
return REDIS_OK;
}
static int redisCreateSocket(redisContext *c, int type) {
int s;
if ((s = socket(type, SOCK_STREAM, 0)) == -1) {
redisFD s;
if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}
@@ -101,6 +129,7 @@ static int redisCreateSocket(redisContext *c, int type) {
}
static int redisSetBlocking(redisContext *c, int blocking) {
#ifndef _WIN32
int flags;
/* Set the socket nonblocking.
@@ -108,7 +137,7 @@ static int redisSetBlocking(redisContext *c, int blocking) {
* interrupted by a signal. */
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
@@ -119,15 +148,23 @@ static int redisSetBlocking(redisContext *c, int blocking) {
if (fcntl(c->fd, F_SETFL, flags) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
#else
u_long mode = blocking ? 0 : 1;
if (ioctl(c->fd, FIONBIO, &mode) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)");
redisNetClose(c);
return REDIS_ERR;
}
#endif /* _WIN32 */
return REDIS_OK;
}
int redisKeepAlive(redisContext *c, int interval) {
int val = 1;
int fd = c->fd;
redisFD fd = c->fd;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
@@ -170,7 +207,7 @@ 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)");
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
return REDIS_OK;
@@ -212,12 +249,12 @@ static int redisContextWaitReady(redisContext *c, long msec) {
if ((res = poll(wfd, 1, msec)) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
} else if (res == 0) {
errno = ETIMEDOUT;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
@@ -230,7 +267,7 @@ static int redisContextWaitReady(redisContext *c, long msec) {
}
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisContextCloseFd(c);
redisNetClose(c);
return REDIS_ERR;
}
@@ -277,11 +314,18 @@ int redisCheckSocketError(redisContext *c) {
}
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
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;
}
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) {
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
return REDIS_ERR;
}
@@ -291,7 +335,8 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout,
const char *source_addr) {
int s, rv, n;
redisFD s;
int rv, n;
char _port[6]; /* strlen("65535"); */
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
int blocking = (c->flags & REDIS_BLOCK);
@@ -360,7 +405,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
}
for (p = servinfo; p != NULL; p = p->ai_next) {
addrretry:
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
continue;
c->fd = s;
@@ -401,16 +446,14 @@ addrretry:
}
/* For repeat connection */
if (c->saddr) {
free(c->saddr);
}
free(c->saddr);
c->saddr = malloc(p->ai_addrlen);
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
c->addrlen = p->ai_addrlen;
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
if (errno == EHOSTUNREACH) {
redisContextCloseFd(c);
redisNetClose(c);
continue;
} else if (errno == EINPROGRESS) {
if (blocking) {
@@ -424,7 +467,7 @@ addrretry:
if (++reuses >= REDIS_CONNECT_RETRIES) {
goto error;
} else {
redisContextCloseFd(c);
redisNetClose(c);
goto addrretry;
}
} else {
@@ -471,8 +514,9 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
}
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
#ifndef _WIN32
int blocking = (c->flags & REDIS_BLOCK);
struct sockaddr_un sa;
struct sockaddr_un *sa;
long timeout_msec = -1;
if (redisCreateSocket(c,AF_UNIX) < 0)
@@ -499,9 +543,11 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
return REDIS_ERR;
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
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);
if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) {
if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
@@ -516,4 +562,10 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
#else
/* We currently do not support Unix sockets for Windows. */
/* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */
errno = EPROTONOSUPPORT;
return REDIS_ERR;
#endif /* _WIN32 */
}
+4
View File
@@ -37,6 +37,10 @@
#include "hiredis.h"
void redisNetClose(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);
int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
+22 -5
View File
@@ -34,6 +34,7 @@
#include <stdlib.h>
#ifndef _MSC_VER
#include <unistd.h>
#include <strings.h>
#endif
#include <assert.h>
#include <errno.h>
@@ -43,6 +44,7 @@
#include "read.h"
#include "sds.h"
#include "win32.h"
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
size_t len;
@@ -293,9 +295,9 @@ static int processLineItem(redisReader *r) {
buf[len] = '\0';
if (strcasecmp(buf,",inf") == 0) {
d = 1.0/0.0; /* Positive infinite. */
d = INFINITY; /* Positive infinite. */
} else if (strcasecmp(buf,",-inf") == 0) {
d = -1.0/0.0; /* Nevative infinite. */
d = -INFINITY; /* Nevative infinite. */
} else {
d = strtod((char*)buf,&eptr);
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
@@ -378,10 +380,18 @@ static int processBulkItem(redisReader *r) {
/* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= r->len) {
if ((cur->type == REDIS_REPLY_VERB && len < 4) ||
(cur->type == REDIS_REPLY_VERB && s[5] != ':'))
{
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Verbatim string 4 bytes of content type are "
"missing or incorrectly encoded.");
return REDIS_ERR;
}
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,s+2,len);
else
obj = (void*)REDIS_REPLY_STRING;
obj = (void*)(long)cur->type;
success = 1;
}
}
@@ -429,7 +439,7 @@ static int processAggregateItem(redisReader *r) {
root = (r->ridx == 0);
if (elements < -1 || elements > INT_MAX) {
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Multi-bulk length out of range");
return REDIS_ERR;
@@ -522,6 +532,9 @@ static int processItem(redisReader *r) {
case '#':
cur->type = REDIS_REPLY_BOOL;
break;
case '=':
cur->type = REDIS_REPLY_VERB;
break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
@@ -542,6 +555,7 @@ static int processItem(redisReader *r) {
case REDIS_REPLY_BOOL:
return processLineItem(r);
case REDIS_REPLY_STRING:
case REDIS_REPLY_VERB:
return processBulkItem(r);
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
@@ -656,8 +670,11 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Emit a reply when there is one. */
if (r->ridx == -1) {
if (reply != NULL)
if (reply != NULL) {
*reply = r->reply;
} else if (r->reply != NULL && r->fn && r->fn->freeObject) {
r->fn->freeObject(r->reply);
}
r->reply = NULL;
}
return REDIS_OK;
+3 -2
View File
@@ -45,6 +45,7 @@
#define REDIS_ERR_EOF 3 /* End of file */
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
#define REDIS_ERR_OOM 5 /* Out of memory */
#define REDIS_ERR_TIMEOUT 6 /* Timed out */
#define REDIS_ERR_OTHER 2 /* Everything else... */
#define REDIS_REPLY_STRING 1
@@ -55,12 +56,12 @@
#define REDIS_REPLY_ERROR 6
#define REDIS_REPLY_DOUBLE 7
#define REDIS_REPLY_BOOL 8
#define REDIS_REPLY_VERB 9
#define REDIS_REPLY_MAP 9
#define REDIS_REPLY_SET 10
#define REDIS_REPLY_ATTR 11
#define REDIS_REPLY_PUSH 12
#define REDIS_REPLY_BIGNUM 13
#define REDIS_REPLY_VERB 14
#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
@@ -79,7 +80,7 @@ typedef struct redisReadTask {
typedef struct redisReplyObjectFunctions {
void *(*createString)(const redisReadTask*, char*, size_t);
void *(*createArray)(const redisReadTask*, int);
void *(*createArray)(const redisReadTask*, size_t);
void *(*createInteger)(const redisReadTask*, long long);
void *(*createDouble)(const redisReadTask*, double, char*, size_t);
void *(*createNil)(const redisReadTask*);
+1 -1
View File
@@ -1035,7 +1035,7 @@ sds *sdssplitargs(const char *line, int *argc) {
s_free(vector);
return NULL;
}
vector = new_vector;
vector[*argc] = current;
(*argc)++;
+28 -15
View File
@@ -34,6 +34,9 @@
#define __SDS_H
#define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#define __attribute__(x)
#endif
#include <sys/types.h>
#include <stdarg.h>
@@ -45,31 +48,41 @@ typedef char *sds;
* However is here to document the layout of type 5 SDS strings. */
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__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
#ifndef __cplusplus
char buf[];
#endif
};
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 */
#ifndef __cplusplus
char buf[];
#endif
};
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 */
#ifndef __cplusplus
char buf[];
#endif
};
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 */
#ifndef __cplusplus
char buf[];
#endif
};
#define SDS_TYPE_5 0
@@ -83,7 +96,7 @@ struct __attribute__ ((__packed__)) sdshdr64 {
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
inline size_t sdslen(const sds s) {
static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
switch(__builtin_expect((flags&SDS_TYPE_MASK), SDS_TYPE_5)) {
@@ -133,20 +146,20 @@ static inline void sdssetlen(sds s, size_t newlen) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len = newlen;
SDS_HDR(8,s)->len = (uint8_t)newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len = newlen;
SDS_HDR(16,s)->len = (uint16_t)newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len = newlen;
SDS_HDR(32,s)->len = (uint32_t)newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len = newlen;
SDS_HDR(64,s)->len = (uint64_t)newlen;
break;
}
}
@@ -157,21 +170,21 @@ static inline void sdsinclen(sds s, size_t inc) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len += inc;
SDS_HDR(8,s)->len += (uint8_t)inc;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len += inc;
SDS_HDR(16,s)->len += (uint16_t)inc;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len += inc;
SDS_HDR(32,s)->len += (uint32_t)inc;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len += inc;
SDS_HDR(64,s)->len += (uint64_t)inc;
break;
}
}
@@ -201,16 +214,16 @@ static inline void sdssetalloc(sds s, size_t newlen) {
/* Nothing to do, this type has no total allocation info. */
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->alloc = newlen;
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->alloc = newlen;
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->alloc = newlen;
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->alloc = newlen;
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
break;
}
}
+248
View File
@@ -0,0 +1,248 @@
/*
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
*
* 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.
*/
#define REDIS_SOCKCOMPAT_IMPLEMENTATION
#include "sockcompat.h"
#ifdef _WIN32
static int _wsaErrorToErrno(int err) {
switch (err) {
case WSAEWOULDBLOCK:
return EWOULDBLOCK;
case WSAEINPROGRESS:
return EINPROGRESS;
case WSAEALREADY:
return EALREADY;
case WSAENOTSOCK:
return ENOTSOCK;
case WSAEDESTADDRREQ:
return EDESTADDRREQ;
case WSAEMSGSIZE:
return EMSGSIZE;
case WSAEPROTOTYPE:
return EPROTOTYPE;
case WSAENOPROTOOPT:
return ENOPROTOOPT;
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
case WSAEOPNOTSUPP:
return EOPNOTSUPP;
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
case WSAEADDRINUSE:
return EADDRINUSE;
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
case WSAENETDOWN:
return ENETDOWN;
case WSAENETUNREACH:
return ENETUNREACH;
case WSAENETRESET:
return ENETRESET;
case WSAECONNABORTED:
return ECONNABORTED;
case WSAECONNRESET:
return ECONNRESET;
case WSAENOBUFS:
return ENOBUFS;
case WSAEISCONN:
return EISCONN;
case WSAENOTCONN:
return ENOTCONN;
case WSAETIMEDOUT:
return ETIMEDOUT;
case WSAECONNREFUSED:
return ECONNREFUSED;
case WSAELOOP:
return ELOOP;
case WSAENAMETOOLONG:
return ENAMETOOLONG;
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
case WSAENOTEMPTY:
return ENOTEMPTY;
default:
/* We just return a generic I/O error if we could not find a relevant error. */
return EIO;
}
}
static void _updateErrno(int success) {
errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError());
}
static int _initWinsock() {
static int s_initialized = 0;
if (!s_initialized) {
static WSADATA wsadata;
int err = WSAStartup(MAKEWORD(2,2), &wsadata);
if (err != 0) {
errno = _wsaErrorToErrno(err);
return 0;
}
s_initialized = 1;
}
return 1;
}
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
/* Note: This function is likely to be called before other functions, so run init here. */
if (!_initWinsock()) {
return EAI_FAIL;
}
switch (getaddrinfo(node, service, hints, res)) {
case 0: return 0;
case WSATRY_AGAIN: return EAI_AGAIN;
case WSAEINVAL: return EAI_BADFLAGS;
case WSAEAFNOSUPPORT: return EAI_FAMILY;
case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY;
case WSAHOST_NOT_FOUND: return EAI_NONAME;
case WSATYPE_NOT_FOUND: return EAI_SERVICE;
case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE;
default: return EAI_FAIL; /* Including WSANO_RECOVERY */
}
}
const char *win32_gai_strerror(int errcode) {
switch (errcode) {
case 0: errcode = 0; break;
case EAI_AGAIN: errcode = WSATRY_AGAIN; break;
case EAI_BADFLAGS: errcode = WSAEINVAL; break;
case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break;
case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break;
case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break;
case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break;
case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break;
default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */
}
return gai_strerror(errcode);
}
void win32_freeaddrinfo(struct addrinfo *res) {
freeaddrinfo(res);
}
SOCKET win32_socket(int domain, int type, int protocol) {
SOCKET s;
/* Note: This function is likely to be called before other functions, so run init here. */
if (!_initWinsock()) {
return INVALID_SOCKET;
}
_updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET);
return s;
}
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) {
int ret = ioctlsocket(fd, (long)request, argp);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = bind(sockfd, addr, addrlen);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = connect(sockfd, addr, addrlen);
_updateErrno(ret != SOCKET_ERROR);
/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
* logic consistent. */
if (errno == EWOULDBLOCK) {
errno = EINPROGRESS;
}
return ret != SOCKET_ERROR ? ret : -1;
}
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) {
int ret = 0;
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
if (*optlen >= sizeof (struct timeval)) {
struct timeval *tv = optval;
DWORD timeout = 0;
socklen_t dwlen = 0;
ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen);
tv->tv_sec = timeout / 1000;
tv->tv_usec = (timeout * 1000) % 1000000;
} else {
ret = WSAEFAULT;
}
*optlen = sizeof (struct timeval);
} else {
ret = getsockopt(sockfd, level, optname, (char*)optval, optlen);
}
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
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))) {
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 {
ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
}
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
int win32_close(SOCKET fd) {
int ret = closesocket(fd);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) {
int ret = recv(sockfd, (char*)buf, (int)len, flags);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) {
int ret = send(sockfd, (const char*)buf, (int)len, flags);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
int ret = WSAPoll(fds, nfds, timeout);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
#endif /* _WIN32 */
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
*
* 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 __SOCKCOMPAT_H
#define __SOCKCOMPAT_H
#ifndef _WIN32
/* For POSIX systems we use the standard BSD socket API. */
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#else
/* For Windows we use winsock. */
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stddef.h>
#ifdef _MSC_VER
typedef signed long ssize_t;
#endif
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
const char *win32_gai_strerror(int errcode);
void win32_freeaddrinfo(struct addrinfo *res);
SOCKET win32_socket(int domain, int type, int protocol);
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp);
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen);
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
int win32_close(SOCKET fd);
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags);
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
typedef ULONG nfds_t;
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
#undef gai_strerror
#define gai_strerror(errcode) win32_gai_strerror(errcode)
#define freeaddrinfo(res) win32_freeaddrinfo(res)
#define socket(domain, type, protocol) win32_socket(domain, type, protocol)
#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp)
#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen)
#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen)
#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen)
#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen)
#define close(fd) win32_close(fd)
#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags)
#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags)
#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout)
#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */
#endif /* _WIN32 */
#endif /* __SOCKCOMPAT_H */
+448
View File
@@ -0,0 +1,448 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2019, Redis Labs
*
* 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 "hiredis.h"
#include "async.h"
#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "async_private.h"
void __redisSetError(redisContext *c, int type, const char *str);
/* 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;
/**
* OpenSSL SSL object.
*/
SSL *ssl;
/**
* SSL_write() requires to be called again with the same arguments it was
* previously called with in the event of an SSL_read/SSL_write situation
*/
size_t lastLen;
/** Whether the SSL layer requires read (possibly before a write) */
int wantRead;
/**
* Whether a write was requested prior to a read. If set, the write()
* should resume whenever a read takes place, if possible
*/
int pendingWrite;
} 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.
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define HIREDIS_USE_CRYPTO_LOCKS
#endif
#ifdef HIREDIS_USE_CRYPTO_LOCKS
typedef pthread_mutex_t sslLockType;
static void sslLockInit(sslLockType *l) {
pthread_mutex_init(l, NULL);
}
static void sslLockAcquire(sslLockType *l) {
pthread_mutex_lock(l);
}
static void sslLockRelease(sslLockType *l) {
pthread_mutex_unlock(l);
}
static pthread_mutex_t *ossl_locks;
static void opensslDoLock(int mode, int lkid, const char *f, int line) {
sslLockType *l = ossl_locks + lkid;
if (mode & CRYPTO_LOCK) {
sslLockAcquire(l);
} else {
sslLockRelease(l);
}
(void)f;
(void)line;
}
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;
}
nlocks = CRYPTO_num_locks();
ossl_locks = malloc(sizeof(*ossl_locks) * nlocks);
for (ii = 0; ii < nlocks; ii++) {
sslLockInit(ossl_locks + ii);
}
CRYPTO_set_locking_callback(opensslDoLock);
}
#endif /* HIREDIS_USE_CRYPTO_LOCKS */
/**
* SSL Connection initialization.
*/
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;
}
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);
SSL_set_fd(rssl->ssl, c->fd);
SSL_set_connect_state(rssl->ssl);
ERR_clear_error();
int rv = SSL_connect(rssl->ssl);
if (rv == 1) {
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)) {
return REDIS_OK;
}
if (c->err == 0) {
char err[512];
if (rv == SSL_ERROR_SYSCALL)
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno));
else {
unsigned long e = ERR_peek_last_error();
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",
ERR_reason_error_string(e));
}
__redisSetError(c, REDIS_ERR_IO, err);
}
return REDIS_ERR;
}
int redisInitiateSSL(redisContext *c, SSL *ssl) {
return redisSSLConnect(c, NULL, ssl);
}
int redisSecureConnection(redisContext *c, const char *capath,
const char *certpath, const char *keypath, const char *servername) {
SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
/* Initialize global OpenSSL stuff */
static int isInit = 0;
if (!isInit) {
isInit = 1;
SSL_library_init();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks();
#endif
}
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ssl_ctx) {
__redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX");
goto error;
}
#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;
}
}
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_ctx) SSL_CTX_free(ssl_ctx);
return REDIS_ERR;
}
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
*/
if (rv == SSL_ERROR_WANT_READ) {
rssl->wantRead = 1;
return 1;
} else if (rv == SSL_ERROR_WANT_WRITE) {
rssl->pendingWrite = 1;
return 1;
} else {
return 0;
}
}
/**
* Implementation of redisContextFuncs for SSL connections.
*/
static void redisSSLFreeContext(void *privdata){
redisSSLContext *rsc = privdata;
if (!rsc) return;
if (rsc->ssl) {
SSL_free(rsc->ssl);
rsc->ssl = NULL;
}
if (rsc->ssl_ctx) {
SSL_CTX_free(rsc->ssl_ctx);
rsc->ssl_ctx = NULL;
}
free(rsc);
}
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) {
return nread;
} else if (nread == 0) {
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
return -1;
} else {
int err = SSL_get_error(rssl->ssl, nread);
if (c->flags & REDIS_BLOCK) {
/**
* In blocking mode, we should never end up in a situation where
* we get an error without it being an actual error, except
* in the case of EINTR, which can be spuriously received from
* debuggers or whatever.
*/
if (errno == EINTR) {
return 0;
} else {
const char *msg = NULL;
if (errno == EAGAIN) {
msg = "Resource temporarily unavailable";
}
__redisSetError(c, REDIS_ERR_IO, msg);
return -1;
}
}
/**
* We can very well get an EWOULDBLOCK/EAGAIN, however
*/
if (maybeCheckWant(rssl, err)) {
return 0;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
}
static int redisSSLWrite(redisContext *c) {
redisSSLContext *rssl = c->privdata;
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
int rv = SSL_write(rssl->ssl, c->obuf, len);
if (rv > 0) {
rssl->lastLen = 0;
} else if (rv < 0) {
rssl->lastLen = len;
int err = SSL_get_error(rssl->ssl, rv);
if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) {
return 0;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
return rv;
}
static void redisSSLAsyncRead(redisAsyncContext *ac) {
int rv;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;
rssl->wantRead = 0;
if (rssl->pendingWrite) {
int done;
/* This is probably just a write event */
rssl->pendingWrite = 0;
rv = redisBufferWrite(c, &done);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
return;
} else if (!done) {
_EL_ADD_WRITE(ac);
}
}
rv = redisBufferRead(c);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
}
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
int rv, done = 0;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;
rssl->pendingWrite = 0;
rv = redisBufferWrite(c, &done);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
return;
}
if (!done) {
if (rssl->wantRead) {
/* Need to read-before-write */
rssl->pendingWrite = 1;
_EL_DEL_WRITE(ac);
} else {
/* No extra reads needed, just need to write more */
_EL_ADD_WRITE(ac);
}
} else {
/* Already done! */
_EL_DEL_WRITE(ac);
}
/* Always reschedule a read */
_EL_ADD_READ(ac);
}
redisContextFuncs redisContextSSLFuncs = {
.free_privdata = redisSSLFreeContext,
.async_read = redisSSLAsyncRead,
.async_write = redisSSLAsyncWrite,
.read = redisSSLRead,
.write = redisSSLWrite
};
+83 -10
View File
@@ -13,12 +13,16 @@
#include <limits.h>
#include "hiredis.h"
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#endif
#include "net.h"
enum connection_type {
CONN_TCP,
CONN_UNIX,
CONN_FD
CONN_FD,
CONN_SSL
};
struct config {
@@ -33,6 +37,14 @@ struct config {
struct {
const char *path;
} unix_sock;
struct {
const char *host;
int port;
const char *ca_cert;
const char *cert;
const char *key;
} ssl;
};
/* The following lines make up our testing "framework" :) */
@@ -93,11 +105,27 @@ static int disconnect(redisContext *c, int keep_fd) {
return -1;
}
static void do_ssl_handshake(redisContext *c, struct config config) {
#ifdef HIREDIS_TEST_SSL
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);
exit(1);
}
#else
(void) c;
(void) config;
#endif
}
static redisContext *do_connect(struct config config) {
redisContext *c = NULL;
if (config.type == CONN_TCP) {
c = redisConnect(config.tcp.host, config.tcp.port);
} else if (config.type == CONN_SSL) {
c = redisConnect(config.ssl.host, config.ssl.port);
} else if (config.type == CONN_UNIX) {
c = redisConnectUnix(config.unix_sock.path);
} else if (config.type == CONN_FD) {
@@ -121,9 +149,21 @@ static redisContext *do_connect(struct config config) {
exit(1);
}
if (config.type == CONN_SSL) {
do_ssl_handshake(c, config);
}
return select_database(c);
}
static void do_reconnect(redisContext *c, struct config config) {
redisReconnect(c);
if (config.type == CONN_SSL) {
do_ssl_handshake(c, config);
}
}
static void test_format_commands(void) {
char *cmd;
int len;
@@ -360,7 +400,8 @@ static void test_reply_reader(void) {
freeReplyObject(reply);
redisReaderFree(reader);
test("Set error when array > INT_MAX: ");
#if LLONG_MAX > SIZE_MAX
test("Set error when array > SIZE_MAX: ");
reader = redisReaderCreate();
redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29);
ret = redisReaderGetReply(reader,&reply);
@@ -369,7 +410,6 @@ static void test_reply_reader(void) {
freeReplyObject(reply);
redisReaderFree(reader);
#if LLONG_MAX > SIZE_MAX
test("Set error when bulk > SIZE_MAX: ");
reader = redisReaderCreate();
redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28);
@@ -434,22 +474,23 @@ static void test_free_null(void) {
test_cond(reply == NULL);
}
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
static void test_blocking_connection_errors(void) {
redisContext *c;
struct addrinfo hints = {.ai_family = AF_INET};
struct addrinfo *ai_tmp = NULL;
const char *bad_domain = "idontexist.com";
int rv = getaddrinfo(bad_domain, "6379", &hints, &ai_tmp);
int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp);
if (rv != 0) {
// Address does *not* exist
test("Returns error when host cannot be resolved: ");
// First see if this domain name *actually* resolves to NXDOMAIN
c = redisConnect("dontexist.com", 6379);
c = redisConnect(HIREDIS_BAD_DOMAIN, 6379);
test_cond(
c->err == REDIS_ERR_OTHER &&
(strcmp(c->errstr, "Name or service not known") == 0 ||
strcmp(c->errstr, "Can't resolve: sadkfjaskfjsa.com") == 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, "No address associated with hostname") == 0 ||
@@ -574,7 +615,8 @@ static void test_blocking_connection_timeouts(struct config config) {
c = do_connect(config);
test("Does not return a reply when the command times out: ");
s = write(c->fd, cmd, strlen(cmd));
redisAppendFormattedCommand(c, cmd, strlen(cmd));
s = c->funcs->write(c);
tv.tv_sec = 0;
tv.tv_usec = 10000;
redisSetTimeout(c, tv);
@@ -583,7 +625,7 @@ static void test_blocking_connection_timeouts(struct config config) {
freeReplyObject(reply);
test("Reconnect properly reconnects after a timeout: ");
redisReconnect(c);
do_reconnect(c, config);
reply = redisCommand(c, "PING");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
freeReplyObject(reply);
@@ -591,7 +633,7 @@ static void test_blocking_connection_timeouts(struct config config) {
test("Reconnect properly uses owned parameters: ");
config.tcp.host = "foo";
config.unix_sock.path = "foo";
redisReconnect(c);
do_reconnect(c, config);
reply = redisCommand(c, "PING");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
freeReplyObject(reply);
@@ -894,6 +936,23 @@ int main(int argc, char **argv) {
throughput = 0;
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
test_inherit_fd = 0;
#ifdef HIREDIS_TEST_SSL
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) {
argv++; argc--;
cfg.ssl.port = atoi(argv[0]);
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-host")) {
argv++; argc--;
cfg.ssl.host = argv[0];
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-ca-cert")) {
argv++; argc--;
cfg.ssl.ca_cert = argv[0];
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-cert")) {
argv++; argc--;
cfg.ssl.cert = argv[0];
} else if (argc >= 2 && !strcmp(argv[0],"--ssl-key")) {
argv++; argc--;
cfg.ssl.key = argv[0];
#endif
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
exit(1);
@@ -922,6 +981,20 @@ int main(int argc, char **argv) {
test_blocking_io_errors(cfg);
if (throughput) test_throughput(cfg);
#ifdef HIREDIS_TEST_SSL
if (cfg.ssl.port && cfg.ssl.host) {
printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port);
cfg.type = CONN_SSL;
test_blocking_connection(cfg);
test_blocking_connection_timeouts(cfg);
test_blocking_io_errors(cfg);
test_invalid_timeout_errors(cfg);
test_append_formatted_commands(cfg);
if (throughput) test_throughput(cfg);
}
#endif
if (test_inherit_fd) {
printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path);
cfg.type = CONN_FD;
Vendored Executable
+70
View File
@@ -0,0 +1,70 @@
#!/bin/sh -ue
REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT=${REDIS_PORT:-56379}
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
TEST_SSL=${TEST_SSL:-0}
SSL_TEST_ARGS=
tmpdir=$(mktemp -d)
PID_FILE=${tmpdir}/hiredis-test-redis.pid
SOCK_FILE=${tmpdir}/hiredis-test-redis.sock
if [ "$TEST_SSL" = "1" ]; then
SSL_CA_CERT=${tmpdir}/ca.crt
SSL_CA_KEY=${tmpdir}/ca.key
SSL_CERT=${tmpdir}/redis.crt
SSL_KEY=${tmpdir}/redis.key
openssl genrsa -out ${tmpdir}/ca.key 4096
openssl req \
-x509 -new -nodes -sha256 \
-key ${SSL_CA_KEY} \
-days 3650 \
-subj '/CN=Hiredis Test CA' \
-out ${SSL_CA_CERT}
openssl genrsa -out ${SSL_KEY} 2048
openssl req \
-new -sha256 \
-key ${SSL_KEY} \
-subj '/CN=Hiredis Test Cert' | \
openssl x509 \
-req -sha256 \
-CA ${SSL_CA_CERT} \
-CAkey ${SSL_CA_KEY} \
-CAserial ${tmpdir}/ca.txt \
-CAcreateserial \
-days 365 \
-out ${SSL_CERT}
SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}"
fi
cleanup() {
set +e
kill $(cat ${PID_FILE})
rm -rf ${tmpdir}
}
trap cleanup INT TERM EXIT
cat > ${tmpdir}/redis.conf <<EOF
daemonize yes
pidfile ${PID_FILE}
port ${REDIS_PORT}
bind 127.0.0.1
unixsocket ${SOCK_FILE}
EOF
if [ "$TEST_SSL" = "1" ]; then
cat >> ${tmpdir}/redis.conf <<EOF
tls-port ${REDIS_SSL_PORT}
tls-ca-cert-file ${SSL_CA_CERT}
tls-cert-file ${SSL_CERT}
tls-key-file ${SSL_KEY}
EOF
fi
cat ${tmpdir}/redis.conf
${REDIS_SERVER} ${tmpdir}/redis.conf
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS}
+16 -2
View File
@@ -2,10 +2,20 @@
#define _WIN32_HELPER_INCLUDE
#ifdef _MSC_VER
#include <winsock2.h> /* for struct timeval */
#ifndef inline
#define inline __inline
#endif
#ifndef strcasecmp
#define strcasecmp stricmp
#endif
#ifndef strncasecmp
#define strncasecmp strnicmp
#endif
#ifndef va_copy
#define va_copy(d,s) ((d) = (s))
#endif
@@ -37,6 +47,10 @@ __inline int c99_snprintf(char* str, size_t size, const char* format, ...)
return count;
}
#endif
#endif /* _MSC_VER */
#endif
#endif
#ifdef _WIN32
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
#endif /* _WIN32 */
#endif /* _WIN32_HELPER_INCLUDE */
@@ -216,7 +216,7 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra,
}
JEMALLOC_ALWAYS_INLINE int
iget_defrag_hint(tsdn_t *tsdn, void* ptr, int *bin_util, int *run_util) {
iget_defrag_hint(tsdn_t *tsdn, void* ptr) {
int defrag = 0;
rtree_ctx_t rtree_ctx_fallback;
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
@@ -232,11 +232,22 @@ iget_defrag_hint(tsdn_t *tsdn, void* ptr, int *bin_util, int *run_util) {
malloc_mutex_lock(tsdn, &bin->lock);
/* don't bother moving allocations from the slab currently used for new allocations */
if (slab != bin->slabcur) {
const bin_info_t *bin_info = &bin_infos[binind];
size_t availregs = bin_info->nregs * bin->stats.curslabs;
*bin_util = ((long long)bin->stats.curregs<<16) / availregs;
*run_util = ((long long)(bin_info->nregs - extent_nfree_get(slab))<<16) / bin_info->nregs;
defrag = 1;
int free_in_slab = extent_nfree_get(slab);
if (free_in_slab) {
const bin_info_t *bin_info = &bin_infos[binind];
int curslabs = bin->stats.curslabs;
size_t curregs = bin->stats.curregs;
if (bin->slabcur) {
/* remove slabcur from the overall utilization */
curregs -= bin_info->nregs - extent_nfree_get(bin->slabcur);
curslabs -= 1;
}
/* Compare the utilization ratio of the slab in question to the total average,
* to avoid precision lost and division, we do that by extrapolating the usage
* of the slab as if all slabs have the same usage. If this slab is less used
* than the average, we'll prefer to evict the data to hopefully more used ones */
defrag = (bin_info->nregs - free_in_slab) * curslabs <= curregs;
}
}
malloc_mutex_unlock(tsdn, &bin->lock);
}
+7 -1
View File
@@ -787,7 +787,13 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
nstime_init(&stats->run_interval, 0);
for (unsigned i = 0; i < max_background_threads; i++) {
background_thread_info_t *info = &background_thread_info[i];
malloc_mutex_lock(tsdn, &info->mtx);
if (malloc_mutex_trylock(tsdn, &info->mtx)) {
/*
* Each background thread run may take a long time;
* avoid waiting on the stats if the thread is active.
*/
continue;
}
if (info->state != background_thread_stopped) {
num_runs += info->tot_n_runs;
nstime_add(&stats->run_interval, &info->tot_sleep_time);
+3 -5
View File
@@ -3326,12 +3326,10 @@ jemalloc_postfork_child(void) {
/******************************************************************************/
/* Helps the application decide if a pointer is worth re-allocating in order to reduce fragmentation.
* returns 0 if the allocation is in the currently active run,
* or when it is not causing any frag issue (large or huge bin)
* returns the bin utilization and run utilization both in fixed point 16:16.
* returns 1 if the allocation should be moved, and 0 if the allocation be kept.
* If the application decides to re-allocate it should use MALLOCX_TCACHE_NONE when doing so. */
JEMALLOC_EXPORT int JEMALLOC_NOTHROW
get_defrag_hint(void* ptr, int *bin_util, int *run_util) {
get_defrag_hint(void* ptr) {
assert(ptr != NULL);
return iget_defrag_hint(TSDN_NULL, ptr, bin_util, run_util);
return iget_defrag_hint(TSDN_NULL, ptr);
}
+24 -1
View File
@@ -21,7 +21,7 @@ So what usually happens is either:
The result is a pollution of binaries without line editing support.
So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to Linenoise if not.
So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporting line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to Linenoise if not.
## Terminals, in 2010.
@@ -126,6 +126,24 @@ Linenoise has direct support for persisting the history into an history
file. The functions `linenoiseHistorySave` and `linenoiseHistoryLoad` do
just that. Both functions return -1 on error and 0 on success.
## Mask mode
Sometimes it is useful to allow the user to type passwords or other
secrets that should not be displayed. For such situations linenoise supports
a "mask mode" that will just replace the characters the user is typing
with `*` characters, like in the following example:
$ ./linenoise_example
hello> get mykey
echo: 'get mykey'
hello> /mask
hello> *********
You can enable and disable mask mode using the following two functions:
void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void);
## Completion
Linenoise supports completion, which is the ability to complete the user
@@ -222,3 +240,8 @@ Sometimes you may want to clear the screen as a result of something the
user typed. You can do this by calling the following function:
void linenoiseClearScreen(void);
## Related projects
* [Linenoise NG](https://github.com/arangodb/linenoise-ng) is a fork of Linenoise that aims to add more advanced features like UTF-8 support, Windows support and other features. Uses C++ instead of C as development language.
* [Linenoise-swift](https://github.com/andybest/linenoise-swift) is a reimplementation of Linenoise written in Swift.
+5
View File
@@ -55,6 +55,7 @@ int main(int argc, char **argv) {
*
* The typed string is returned as a malloc() allocated string by
* linenoise, so the user needs to free() it. */
while((line = linenoise("hello> ")) != NULL) {
/* Do something with the string. */
if (line[0] != '\0' && line[0] != '/') {
@@ -65,6 +66,10 @@ int main(int argc, char **argv) {
/* The "/historylen" command will change the history len. */
int len = atoi(line+11);
linenoiseHistorySetMaxLen(len);
} else if (!strncmp(line, "/mask", 5)) {
linenoiseMaskModeEnable();
} else if (!strncmp(line, "/unmask", 7)) {
linenoiseMaskModeDisable();
} else if (line[0] == '/') {
printf("Unreconized command: %s\n", line);
}
+29 -3
View File
@@ -125,6 +125,7 @@ static linenoiseHintsCallback *hintsCallback = NULL;
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
static struct termios orig_termios; /* In order to restore at exit.*/
static int maskmode = 0; /* Show "***" instead of input. For passwords. */
static int rawmode = 0; /* For atexit() function to check if restore is needed*/
static int mlmode = 0; /* Multi line mode. Default is single line. */
static int atexit_registered = 0; /* Register atexit just 1 time. */
@@ -197,6 +198,19 @@ FILE *lndebug_fp = NULL;
/* ======================= Low level terminal handling ====================== */
/* Enable "mask mode". When it is enabled, instead of the input that
* the user is typing, the terminal will just display a corresponding
* number of asterisks, like "****". This is useful for passwords and other
* secrets that should not be displayed. */
void linenoiseMaskModeEnable(void) {
maskmode = 1;
}
/* Disable mask mode. */
void linenoiseMaskModeDisable(void) {
maskmode = 0;
}
/* Set if to use or not the multi line mode. */
void linenoiseSetMultiLine(int ml) {
mlmode = ml;
@@ -485,6 +499,8 @@ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
if (bold == 1 && color == -1) color = 37;
if (color != -1 || bold != 0)
snprintf(seq,64,"\033[%d;%d;49m",bold,color);
else
seq[0] = '\0';
abAppend(ab,seq,strlen(seq));
abAppend(ab,hint,hintlen);
if (color != -1 || bold != 0)
@@ -523,7 +539,11 @@ static void refreshSingleLine(struct linenoiseState *l) {
abAppend(&ab,seq,strlen(seq));
/* Write the prompt and the current buffer content */
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,buf,len);
if (maskmode == 1) {
while (len--) abAppend(&ab,"*",1);
} else {
abAppend(&ab,buf,len);
}
/* Show hits if any. */
refreshShowHints(&ab,l,plen);
/* Erase to right */
@@ -577,7 +597,12 @@ static void refreshMultiLine(struct linenoiseState *l) {
/* Write the prompt and the current buffer content */
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,l->buf,l->len);
if (maskmode == 1) {
unsigned int i;
for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
} else {
abAppend(&ab,l->buf,l->len);
}
/* Show hits if any. */
refreshShowHints(&ab,l,plen);
@@ -645,7 +670,8 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
/* Avoid a full update of the line in the
* trivial case. */
if (write(l->ofd,&c,1) == -1) return -1;
char d = (maskmode==1) ? '*' : c;
if (write(l->ofd,&d,1) == -1) return -1;
} else {
refreshLine(l);
}
+2
View File
@@ -65,6 +65,8 @@ int linenoiseHistoryLoad(const char *filename);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void);
#ifdef __cplusplus
}
+6 -4
View File
@@ -89,12 +89,14 @@ typedef struct Header {
} Header;
static int getnum (const char **fmt, int df) {
static int getnum (lua_State *L, const char **fmt, int df) {
if (!isdigit(**fmt)) /* no number? */
return df; /* return default value */
else {
int a = 0;
do {
if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0')))
luaL_error(L, "integral size overflow");
a = a*10 + *((*fmt)++) - '0';
} while (isdigit(**fmt));
return a;
@@ -115,9 +117,9 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) {
case 'f': return sizeof(float);
case 'd': return sizeof(double);
case 'x': return 1;
case 'c': return getnum(fmt, 1);
case 'c': return getnum(L, fmt, 1);
case 'i': case 'I': {
int sz = getnum(fmt, sizeof(int));
int sz = getnum(L, fmt, sizeof(int));
if (sz > MAXINTSIZE)
luaL_error(L, "integral size %d is larger than limit of %d",
sz, MAXINTSIZE);
@@ -150,7 +152,7 @@ static void controloptions (lua_State *L, int opt, const char **fmt,
case '>': h->endian = BIG; return;
case '<': h->endian = LITTLE; return;
case '!': {
int a = getnum(fmt, MAXALIGN);
int a = getnum(L, fmt, MAXALIGN);
if (!isp2(a))
luaL_error(L, "alignment %d is not a power of 2", a);
h->align = a;
+13
View File
@@ -0,0 +1,13 @@
="repl-stream-db"
="repl-id"
="repl-offset"
="lua"
="redis-ver"
="ctime"
="used-mem"
="aof-preamble"
="redis-bits"
="mvcc-tstamp"
="keydb-subexpire-key"
="keydb-subexpire-when"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+501 -171
View File
File diff suppressed because it is too large. Load diff
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
TCL_VERSIONS="8.5 8.6"
TCLSH=""
for VERSION in $TCL_VERSIONS; do
TCL=`which tclsh$VERSION 2>/dev/null` && TCLSH=$TCL
done
if [ -z $TCLSH ]
then
echo "You need tcl 8.5 or newer in order to run the Redis test"
exit 1
fi
make -C tests/modules && \
$TCLSH tests/test_helper.tcl \
--single unit/moduleapi/commandfilter \
--single unit/moduleapi/fork \
--single unit/moduleapi/testrdb \
--single unit/moduleapi/infotest \
--single unit/moduleapi/propagate \
--single unit/moduleapi/hooks \
--single unit/moduleapi/misc \
--single unit/moduleapi/blockonkeys \
--single unit/moduleapi/scan \
--single unit/moduleapi/datatype \
--single unit/moduleapi/auth \
"${@}"
+20
View File
@@ -102,6 +102,18 @@ sentinel monitor mymaster 127.0.0.1 6379 2
#
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# sentinel auth-user <master-name> <username>
#
# This is useful in order to authenticate to instances having ACL capabilities,
# that is, running Redis 6.0 or greater. When just auth-pass is provided the
# Sentinel instance will authenticate to Redis using the old "AUTH <pass>"
# method. When also an username is provided, it will use "AUTH <user> <pass>".
# In the Redis servers side, the ACL to provide just minimal access to
# Sentinel instances, should be configured along the following lines:
#
# user sentinel-user >somepassword +client +subscribe +publish \
# +ping +info +multi +slaveof +config +client +exec on
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached replica or sentinel) should
@@ -112,6 +124,14 @@ sentinel monitor mymaster 127.0.0.1 6379 2
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000
# requirepass <password>
#
# You can configure Sentinel itself to require a password, however when doing
# so Sentinel will try to authenticate with the same password to all the
# other Sentinels. So you need to configure all your Sentinels in a given
# group with the same "requirepass" password. Check the following documentation
# for more info: https://redis.io/topics/sentinel
# sentinel parallel-syncs <master-name> <numreplicas>
#
# How many replicas we can reconfigure to point to the new replica simultaneously
+112 -28
View File
@@ -20,19 +20,20 @@ DEPENDENCY_TARGETS=hiredis linenoise lua
NODEPS:=clean distclean
# Default settings
STD=-std=c99 -pedantic -DREDIS_STATIC=''
CXX_STD=-std=c++14 -pedantic -fno-rtti
STD=-std=c11 -pedantic -DREDIS_STATIC=''
CXX_STD=-std=c++14 -pedantic -fno-rtti -D__STDC_FORMAT_MACROS
ifneq (,$(findstring clang,$(CC)))
ifneq (,$(findstring FreeBSD,$(uname_S)))
STD+=-Wno-c11-extensions
endif
endif
WARN=-Wall -Werror -W -Wno-missing-field-initializers
WARN=-Wall -W -Wno-missing-field-initializers
OPT=$(OPTIMIZATION)
PREFIX?=/usr/local
INSTALL_BIN=$(PREFIX)/bin
INSTALL=install
PKG_CONFIG?=pkg-config
# Default allocator defaults to Jemalloc if it's not an ARM
MALLOC=libc
@@ -45,8 +46,18 @@ endif
endif
USEASM?=true
# Do we use our assembly spinlock?
ifneq ($(SANITIZE),)
CFLAGS+= -fsanitize=$(SANITIZE) -DSANITIZE
CXXFLAGS+= -fsanitize=$(SANITIZE) -DSANITIZE
LDFLAGS+= -fsanitize=$(SANITIZE)
MALLOC=libc
USEASM=false
endif
# Do we use our assembly spinlock? X64 only
ifeq ($(uname_S),Linux)
ifeq ($(uname_M),x86_64)
ifneq ($(@@),32bit)
ifeq ($(USEASM),true)
ASM_OBJ+= fastlock_x64.o
@@ -55,13 +66,21 @@ ifeq ($(USEASM),true)
endif
endif
endif
endif
ifeq ($(COMPILER_NAME),clang)
CXXFLAGS+= -stdlib=libc++
LDFLAGS+= -latomic
endif
# To get ARM stack traces if Redis crashes we need a special C flag.
ifneq (,$(filter aarch64 armv,$(uname_M)))
CFLAGS+=-funwind-tables
CXXFLAGS+=-funwind-tables
else
ifneq (,$(findstring armv,$(uname_M)))
CFLAGS+=-funwind-tables
CXXFLAGS+=-funwind-tables
endif
endif
@@ -86,27 +105,36 @@ endif
-include .make-settings
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_CXXFLAGS=$(CXX_STD) $(WARN) $(OPT) $(DEBUG) $(CXXFLAGS) $(REDIS_CFLAGS)
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
FINAL_LIBS=-lm
FINAL_LIBS+=-lm -lcurl
DEBUG=-g -ggdb
ifneq ($(uname_S),Darwin)
FINAL_LIBS+=-latomic
endif
ifeq ($(uname_S),SunOS)
# SunOS
ifneq ($(@@),32bit)
CFLAGS+= -m64
CXXFLAGS+= -m64
LDFLAGS+= -m64
endif
DEBUG=-g
DEBUG_FLAGS=-g
export CFLAGS LDFLAGS DEBUG DEBUG_FLAGS
export CFLAGS CXXFLAGS LDFLAGS DEBUG DEBUG_FLAGS
INSTALL=cp -pf
FINAL_CFLAGS+= -D__EXTENSIONS__ -D_XPG6
FINAL_CXXFLAGS+= -D__EXTENSIONS__ -D_XPG6
FINAL_LIBS+= -ldl -lnsl -lsocket -lresolv -lpthread -lrt
else
ifeq ($(uname_S),Darwin)
# Darwin
FINAL_LIBS+= -ldl
OPENSSL_CFLAGS=-I/usr/local/opt/openssl/include
OPENSSL_LDFLAGS=-L/usr/local/opt/openssl/lib
else
ifeq ($(uname_S),AIX)
# AIX
@@ -118,6 +146,7 @@ ifeq ($(uname_S),OpenBSD)
FINAL_LIBS+= -lpthread
ifeq ($(USE_BACKTRACE),yes)
FINAL_CFLAGS+= -DUSE_BACKTRACE -I/usr/local/include
FINAL_CXXFLAGS+= -DUSE_BACKTRACE -I/usr/local/include
FINAL_LDFLAGS+= -L/usr/local/lib
FINAL_LIBS+= -lexecinfo
endif
@@ -130,10 +159,22 @@ else
ifeq ($(uname_S),DragonFly)
# FreeBSD
FINAL_LIBS+= -lpthread -lexecinfo
else
ifeq ($(uname_S),OpenBSD)
# OpenBSD
FINAL_LIBS+= -lpthread -lexecinfo
else
ifeq ($(uname_S),NetBSD)
# NetBSD
FINAL_LIBS+= -lpthread -lexecinfo
else
# All the other OSes (notably Linux)
FINAL_LDFLAGS+= -rdynamic
FINAL_LIBS+=-ldl -pthread -lrt
FINAL_LIBS+=-ldl -pthread -lrt -luuid
FINAL_CFLAGS += -DMOTD
FINAL_CXXFLAGS += -DMOTD
endif
endif
endif
endif
endif
@@ -144,6 +185,30 @@ endif
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
FINAL_CXXFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
# Determine systemd support and/or build preference (defaulting to auto-detection)
BUILD_WITH_SYSTEMD=no
# If 'USE_SYSTEMD' in the environment is neither "no" nor "yes", try to
# auto-detect libsystemd's presence and link accordingly.
ifneq ($(USE_SYSTEMD),no)
LIBSYSTEMD_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libsystemd && echo $$?)
# If libsystemd cannot be detected, continue building without support for it
# (unless a later check tells us otherwise)
ifeq ($(LIBSYSTEMD_PKGCONFIG),0)
BUILD_WITH_SYSTEMD=yes
endif
endif
ifeq ($(USE_SYSTEMD),yes)
ifneq ($(LIBSYSTEMD_PKGCONFIG),0)
$(error USE_SYSTEMD is set to "$(USE_SYSTEMD)", but $(PKG_CONFIG) cannot find libsystemd)
endif
# Force building with libsystemd
BUILD_WITH_SYSTEMD=yes
endif
ifeq ($(BUILD_WITH_SYSTEMD),yes)
FINAL_LIBS+=$(shell $(PKG_CONFIG) --libs libsystemd)
FINAL_CFLAGS+= -DHAVE_LIBSYSTEMD
endif
ifeq ($(MALLOC),tcmalloc)
FINAL_CFLAGS+= -DUSE_TCMALLOC
FINAL_CXXFLAGS+= -DUSE_TCMALLOC
@@ -170,9 +235,16 @@ ifeq ($(MALLOC),memkind)
FINAL_LIBS := ../deps/memkind/src/.libs/libmemkind.a -lnuma $(FINAL_LIBS)
endif
ifeq ($(BUILD_TLS),yes)
FINAL_CFLAGS+=-DUSE_OPENSSL $(OPENSSL_CXXFLAGS)
FINAL_CXXFLAGS+=-DUSE_OPENSSL $(OPENSSL_CXXFLAGS)
FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a -lssl -lcrypto
endif
REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
REDIS_CXX=$(QUIET_CC)$(CC) $(FINAL_CXXFLAGS)
REDIS_NASM=$(QUIET_CC)nasm -felf64
REDIS_CXX=$(QUIET_CC)$(CXX) $(FINAL_CXXFLAGS)
KEYDB_AS=$(QUIET_CC) as --64 -g
REDIS_LD=$(QUIET_LINK)$(CXX) $(FINAL_LDFLAGS)
REDIS_INSTALL=$(QUIET_INSTALL)$(INSTALL)
@@ -184,18 +256,18 @@ MAKECOLOR="\033[32;1m"
ENDCOLOR="\033[0m"
ifndef V
QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR) 1>&2;
QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR);
QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR);
QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR);
endif
REDIS_SERVER_NAME=keydb-server
REDIS_SENTINEL_NAME=keydb-sentinel
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o acl.o storage.o rdb-s3.o fastlock.o $(ASM_OBJ)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o acl.o storage.o rdb-s3.o fastlock.o new.o tracking.o cron.o connection.o tls.o sha256.o motd.o timeout.o setcpuaffinity.o $(ASM_OBJ)
REDIS_CLI_NAME=keydb-cli
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o $(ASM_OBJ)
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o redis-cli-cpphelper.o zmalloc.o release.o anet.o ae.o crcspeed.o crc64.o siphash.o crc16.o storage-lite.o fastlock.o new.o motd.o $(ASM_OBJ)
REDIS_BENCHMARK_NAME=keydb-benchmark
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o zmalloc.o redis-benchmark.o storage-lite.o fastlock.o $(ASM_OBJ)
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o redis-benchmark.o storage-lite.o fastlock.o new.o $(ASM_OBJ)
REDIS_CHECK_RDB_NAME=keydb-check-rdb
REDIS_CHECK_AOF_NAME=keydb-check-aof
@@ -219,27 +291,31 @@ persist-settings: distclean
echo OPT=$(OPT) >> .make-settings
echo MALLOC=$(MALLOC) >> .make-settings
echo CFLAGS=$(CFLAGS) >> .make-settings
echo CXXFLAGS=$(CXXFLAGS) >> .make-settings
echo LDFLAGS=$(LDFLAGS) >> .make-settings
echo REDIS_CFLAGS=$(REDIS_CFLAGS) >> .make-settings
echo REDIS_CXXFLAGS=$(REDIS_CXXFLAGS) >> .make-settings
echo REDIS_LDFLAGS=$(REDIS_LDFLAGS) >> .make-settings
echo PREV_FINAL_CFLAGS=$(FINAL_CFLAGS) >> .make-settings
echo PREV_FINAL_CXXFLAGS=$(FINAL_CXXFLAGS) >> .make-settings
echo PREV_FINAL_LDFLAGS=$(FINAL_LDFLAGS) >> .make-settings
-(cd modules && $(MAKE))
-(cd ../deps && $(MAKE) $(DEPENDENCY_TARGETS))
.PHONY: persist-settings
# Prerequisites target
.make-prerequisites:
@touch $@
# Clean everything, persist settings and build dependencies if anything changed
ifneq ($(strip $(PREV_FINAL_CFLAGS)), $(strip $(FINAL_CFLAGS)))
.make-prerequisites: persist-settings
endif
ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
else ifneq ($(strip $(PREV_FINAL_CXXFLAGS)), $(strip $(FINAL_CXXFLAGS)))
.make-prerequisites: persist-settings
else ifneq ($(strip $(PREV_FINAL_LDFLAGS)), $(strip $(FINAL_LDFLAGS)))
.make-prerequisites: persist-settings
else
.make-prerequisites:
endif
@touch $@
# keydb-server
$(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
@@ -265,28 +341,33 @@ $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)
dict-benchmark: dict.c zmalloc.c sds.c siphash.c
dict-benchmark: dict.cpp zmalloc.cpp sds.c siphash.c
$(REDIS_CC) $(FINAL_CFLAGS) $^ -D DICT_BENCHMARK_MAIN -o $@ $(FINAL_LIBS)
DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d)
-include $(DEP)
# Because the jemalloc.h header is generated as a part of the jemalloc build,
# building it should complete before building any other object. Instead of
# depending on a single artifact, build all dependencies first.
%.o: %.c .make-prerequisites
$(REDIS_CC) -c $<
$(REDIS_CC) -MMD -o $@ -c $<
%.o: %.cpp .make-prerequisites
$(REDIS_CXX) -c $<
$(REDIS_CXX) -MMD -o $@ -c $<
%.o: %.asm .make-prerequisites
$(REDIS_NASM) $<
$(KEYDB_AS) $< -o $@
clean:
rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark
rm -f $(DEP)
.PHONY: clean
distclean: clean
-(cd ../deps && $(MAKE) distclean)
-(cd modules && $(MAKE) clean)
-(rm -f .make-*)
.PHONY: distclean
@@ -306,7 +387,7 @@ lcov:
@genhtml --legend -o lcov-html redis.info
test-sds: sds.c sds.h
$(REDIS_CC) sds.c zmalloc.c -DSDS_TEST_MAIN $(FINAL_LIBS) -o /tmp/sds_test
$(REDIS_CC) sds.c zmalloc.cpp -DSDS_TEST_MAIN $(FINAL_LIBS) -o /tmp/sds_test
/tmp/sds_test
.PHONY: lcov
@@ -318,7 +399,7 @@ bench: $(REDIS_BENCHMARK_NAME)
@echo ""
@echo "WARNING: if it fails under Linux you probably need to install libc6-dev-i386"
@echo ""
$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
$(MAKE) CXXFLAGS="-m32" CFLAGS="-m32" LDFLAGS="-m32"
gcov:
$(MAKE) REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage"
@@ -343,3 +424,6 @@ install: all
$(REDIS_INSTALL) $(REDIS_CHECK_RDB_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_CHECK_AOF_NAME) $(INSTALL_BIN)
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
uninstall:
rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
+524 -109
View File
File diff suppressed because it is too large. Load diff
+17 -3
View File
@@ -327,12 +327,11 @@ listNode *listIndex(list *list, long index) {
}
/* Rotate the list removing the tail node and inserting it to the head. */
void listRotate(list *list) {
listNode *tail = list->tail;
void listRotateTailToHead(list *list) {
if (listLength(list) <= 1) return;
/* Detach current tail */
listNode *tail = list->tail;
list->tail = tail->prev;
list->tail->next = NULL;
/* Move it as head */
@@ -342,6 +341,21 @@ void listRotate(list *list) {
list->head = tail;
}
/* Rotate the list removing the head node and inserting it to the tail. */
void listRotateHeadToTail(list *list) {
if (listLength(list) <= 1) return;
listNode *head = list->head;
/* Detach current head */
list->head = head->next;
list->head->prev = NULL;
/* Move it as tail */
list->tail->next = head;
head->next = NULL;
head->prev = list->tail;
list->tail = head;
}
/* Add all the elements of the list 'o' at the end of the
* list 'l'. The list 'other' remains empty but otherwise valid. */
void listJoin(list *l, list *o) {
+4 -3
View File
@@ -52,7 +52,7 @@ typedef struct list {
listNode *head;
listNode *tail;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
void (*free)(const void *ptr);
int (*match)(void *ptr, void *key);
unsigned long len;
} list;
@@ -70,7 +70,7 @@ typedef struct list {
#define listSetMatchMethod(l,m) ((l)->match = (m))
#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetFreeMethod(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)
/* Prototypes */
@@ -89,7 +89,8 @@ listNode *listSearchKey(list *list, void *key);
listNode *listIndex(list *list, long index);
void listRewind(list *list, listIter *li);
void listRewindTail(list *list, listIter *li);
void listRotate(list *list);
void listRotateTailToHead(list *list);
void listRotateHeadToTail(list *list);
void listJoin(list *l, list *o);
/* Directions for iterators */
+158 -32
View File
@@ -30,6 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmacros.h"
#include <condition_variable>
#include <atomic>
#include <mutex>
@@ -46,10 +47,9 @@
#include "ae.h"
#include "fastlock.h"
extern "C" {
#include "zmalloc.h"
#include "config.h"
}
#include "mcs_lock.h"
#ifdef USE_MUTEX
thread_local int cOwnLock = 0;
@@ -82,11 +82,49 @@ public:
mutex_wrapper g_lock;
#else
fastlock g_lock;
//fastlock g_lock("AE (global)");
McsLock g_lock;
thread_local McsLock::node m_node;
class McsLockGuard
{
McsLock &m_lock;
bool fReleased = false;
public:
McsLockGuard(McsLock &lock)
: m_lock(lock)
{
m_lock.lock(&m_node);
}
McsLockGuard(McsLock &lock, std::defer_lock_t)
: m_lock(lock)
{
fReleased = true;
}
void lock() {
m_lock.lock(&m_node);
fReleased = false;
}
void unlock() {
m_lock.unlock(&m_node);
fReleased = true;
}
~McsLockGuard()
{
if (!fReleased)
m_lock.unlock(&m_node);
}
};
#endif
thread_local aeEventLoop *g_eventLoopThisThread = NULL;
#define AE_ASSERT(x) if (!(x)) do { fprintf(stderr, "AE_ASSER FAILURE\n"); *((volatile int*)0) = 1; } while(0)
#define AE_ASSERT(x) if (!(x)) do { fprintf(stderr, "AE_ASSERT FAILURE %s: %d\n", __FILE__, __LINE__); *((volatile int*)1) = 1; } while(0)
/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
@@ -124,6 +162,7 @@ struct aeCommand
AE_ASYNC_OP op;
int fd;
int mask;
bool fLock = true;
union {
aePostFunctionProc *proc;
aeFileProc *fproc;
@@ -168,7 +207,9 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
case AE_ASYNC_OP::PostFunction:
{
std::unique_lock<decltype(g_lock)> ulock(g_lock);
McsLockGuard ulock(g_lock, std::defer_lock);
if (cmd.fLock)
ulock.lock();
((aePostFunctionProc*)cmd.proc)(cmd.clientData);
break;
}
@@ -178,7 +219,9 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
if (cmd.pctl != nullptr)
cmd.pctl->mutexcv.lock();
std::unique_lock<decltype(g_lock)> ulock(g_lock);
McsLockGuard ulock(g_lock, std::defer_lock);
if (cmd.fLock)
ulock.lock();
(*cmd.pfn)();
if (cmd.pctl != nullptr)
@@ -193,6 +236,36 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
}
}
// Unlike write() this is an all or nothing thing. We will block if a partial write is hit
ssize_t safe_write(int fd, const void *pv, size_t cb)
{
const char *pcb = (const char*)pv;
ssize_t written = 0;
do
{
ssize_t rval = write(fd, pcb, cb);
if (rval > 0)
{
pcb += rval;
cb -= rval;
written += rval;
}
else if (errno == EAGAIN)
{
if (written == 0)
break;
// if we've already written something then we're committed so keep trying
}
else
{
if (rval == 0)
return written;
return rval;
}
} while (cb);
return written;
}
int aeCreateRemoteFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData, int fSynchronous)
{
@@ -201,28 +274,31 @@ int aeCreateRemoteFileEvent(aeEventLoop *eventLoop, int fd, int mask,
int ret = AE_OK;
aeCommand cmd;
aeCommand cmd = {};
cmd.op = AE_ASYNC_OP::CreateFileEvent;
cmd.fd = fd;
cmd.mask = mask;
cmd.fproc = proc;
cmd.clientData = clientData;
cmd.pctl = nullptr;
cmd.fLock = true;
if (fSynchronous)
cmd.pctl = new aeCommandControl();
std::unique_lock<std::mutex> ulock(cmd.pctl->mutexcv, std::defer_lock);
if (fSynchronous)
{
cmd.pctl = new (MALLOC_LOCAL) aeCommandControl();
cmd.pctl->mutexcv.lock();
auto size = write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
}
auto size = safe_write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
if (size != sizeof(cmd))
{
AE_ASSERT(size == sizeof(cmd) || size <= 0);
AE_ASSERT(errno == EAGAIN);
ret = AE_ERR;
}
if (fSynchronous)
{
std::unique_lock<std::mutex> ulock(cmd.pctl->mutexcv, std::defer_lock);
cmd.pctl->cv.wait(ulock);
ret = cmd.pctl->rval;
delete cmd.pctl;
@@ -238,16 +314,18 @@ int aePostFunction(aeEventLoop *eventLoop, aePostFunctionProc *proc, void *arg)
proc(arg);
return AE_OK;
}
aeCommand cmd;
aeCommand cmd = {};
cmd.op = AE_ASYNC_OP::PostFunction;
cmd.proc = proc;
cmd.clientData = arg;
cmd.fLock = true;
auto size = write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
AE_ASSERT(size == sizeof(cmd));
if (size != sizeof(cmd))
return AE_ERR;
return AE_OK;
}
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fSynchronous)
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fSynchronous, bool fLock)
{
if (eventLoop == g_eventLoopThisThread)
{
@@ -255,20 +333,25 @@ int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fSynch
return AE_OK;
}
aeCommand cmd;
aeCommand cmd = {};
cmd.op = AE_ASYNC_OP::PostCppFunction;
cmd.pfn = new std::function<void()>(fn);
cmd.pfn = new (MALLOC_LOCAL) std::function<void()>(fn);
cmd.pctl = nullptr;
cmd.fLock = fLock;
if (fSynchronous)
cmd.pctl = new aeCommandControl();
std::unique_lock<std::mutex> ulock(cmd.pctl->mutexcv, std::defer_lock);
if (fSynchronous)
{
cmd.pctl = new (MALLOC_LOCAL) aeCommandControl();
cmd.pctl->mutexcv.lock();
}
auto size = write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
if (size != sizeof(cmd))
return AE_ERR;
AE_ASSERT(size == sizeof(cmd));
int ret = AE_OK;
if (fSynchronous)
{
std::unique_lock<std::mutex> ulock(cmd.pctl->mutexcv, std::defer_lock);
cmd.pctl->cv.wait(ulock);
ret = cmd.pctl->rval;
delete cmd.pctl;
@@ -292,13 +375,14 @@ aeEventLoop *aeCreateEventLoop(int setsize) {
eventLoop->maxfd = -1;
eventLoop->beforesleep = NULL;
eventLoop->aftersleep = NULL;
eventLoop->flags = 0;
if (aeApiCreate(eventLoop) == -1) goto err;
/* Events with mask == AE_NONE are not set. So let's initialize the
* vector with it. */
for (i = 0; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
fastlock_init(&eventLoop->flock);
fastlock_init(&eventLoop->flock, "event loop");
int rgfd[2];
if (pipe(rgfd) < 0)
goto err;
@@ -325,6 +409,14 @@ int aeGetSetSize(aeEventLoop *eventLoop) {
return eventLoop->setsize;
}
/* Tells the next iteration/s of the event processing to set timeout of 0. */
void aeSetDontWait(aeEventLoop *eventLoop, int noWait) {
if (noWait)
eventLoop->flags |= AE_DONT_WAIT;
else
eventLoop->flags &= ~AE_DONT_WAIT;
}
/* Resize the maximum set size of the event loop.
* If the requested set size is smaller than the current set size, but
* there is already a file descriptor in use that is >= the requested
@@ -355,10 +447,19 @@ extern "C" void aeDeleteEventLoop(aeEventLoop *eventLoop) {
aeApiFree(eventLoop);
zfree(eventLoop->events);
zfree(eventLoop->fired);
zfree(eventLoop);
fastlock_free(&eventLoop->flock);
close(eventLoop->fdCmdRead);
close(eventLoop->fdCmdWrite);
/* Free the time events list. */
auto *te = eventLoop->timeEventHead;
while (te)
{
auto *teNext = te->next;
zfree(te);
te = teNext;
}
zfree(eventLoop);
}
extern "C" void aeStop(aeEventLoop *eventLoop) {
@@ -396,6 +497,7 @@ void aeDeleteFileEventAsync(aeEventLoop *eventLoop, int fd, int mask)
cmd.op = AE_ASYNC_OP::DeleteFileEvent;
cmd.fd = fd;
cmd.mask = mask;
cmd.fLock = true;
auto cb = write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
AE_ASSERT(cb == sizeof(cmd));
}
@@ -473,6 +575,7 @@ extern "C" long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long millise
te->clientData = clientData;
te->prev = NULL;
te->next = eventLoop->timeEventHead;
te->refcount = 0;
if (te->next)
te->next->prev = te;
eventLoop->timeEventHead = te;
@@ -522,7 +625,7 @@ static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
/* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) {
std::unique_lock<decltype(g_lock)> ulock(g_lock);
McsLockGuard ulock(g_lock);
int processed = 0;
aeTimeEvent *te;
long long maxId;
@@ -554,6 +657,13 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
/* Remove events scheduled for deletion. */
if (te->id == AE_DELETED_EVENT_ID) {
aeTimeEvent *next = te->next;
/* If a reference exists for this timer event,
* don't free it. This is currently incremented
* for recursive timerProc calls */
if (te->refcount) {
te = next;
continue;
}
if (te->prev)
te->prev->next = te->next;
else
@@ -583,7 +693,9 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
int retval;
id = te->id;
te->refcount++;
retval = te->timeProc(eventLoop, id, te->clientData);
te->refcount--;
processed++;
if (retval != AE_NOMORE) {
aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
@@ -599,7 +711,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
extern "C" void ProcessEventCore(aeEventLoop *eventLoop, aeFileEvent *fe, int mask, int fd)
{
#define LOCK_IF_NECESSARY(fe, tsmask) \
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock); \
McsLockGuard ulock(g_lock, std::defer_lock); \
if (!(fe->mask & tsmask)) \
ulock.lock()
@@ -628,6 +740,7 @@ extern "C" void ProcessEventCore(aeEventLoop *eventLoop, aeFileEvent *fe, int ma
LOCK_IF_NECESSARY(fe, AE_READ_THREADSAFE);
fe->rfileProc(eventLoop,fd,fe->clientData,mask | (fe->mask & AE_READ_THREADSAFE));
fired++;
fe = &eventLoop->events[fd]; /* Refresh in case of resize. */
}
/* Fire the writable event. */
@@ -664,6 +777,7 @@ extern "C" void ProcessEventCore(aeEventLoop *eventLoop, aeFileEvent *fe, int ma
* if flags has AE_DONT_WAIT set the function returns ASAP until all
* the events that's possible to process without to wait are processed.
* if flags has AE_CALL_AFTER_SLEEP set, the aftersleep callback is called.
* if flags has AE_CALL_BEFORE_SLEEP set, the beforesleep callback is called.
*
* The function returns the number of events processed. */
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
@@ -718,14 +832,26 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
}
}
if (eventLoop->flags & AE_DONT_WAIT) {
tv.tv_sec = tv.tv_usec = 0;
tvp = &tv;
}
if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP) {
McsLockGuard ulock(g_lock, std::defer_lock);
if (!(eventLoop->beforesleepFlags & AE_SLEEP_THREADSAFE))
ulock.lock();
eventLoop->beforesleep(eventLoop);
}
/* Call the multiplexing API, will return only on timeout or when
* some event fires. */
numevents = aeApiPoll(eventLoop, tvp);
/* After sleep callback. */
if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP) {
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
if (!(eventLoop->beforesleepFlags & AE_SLEEP_THREADSAFE))
McsLockGuard ulock(g_lock, std::defer_lock);
if (!(eventLoop->aftersleepFlags & AE_SLEEP_THREADSAFE))
ulock.lock();
eventLoop->aftersleep(eventLoop);
}
@@ -775,7 +901,7 @@ void aeMain(aeEventLoop *eventLoop) {
g_eventLoopThisThread = eventLoop;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL) {
std::unique_lock<decltype(g_lock)> ulock(g_lock, std::defer_lock);
McsLockGuard ulock(g_lock, std::defer_lock);
if (!(eventLoop->beforesleepFlags & AE_SLEEP_THREADSAFE))
ulock.lock();
eventLoop->beforesleep(eventLoop);
@@ -802,20 +928,20 @@ void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep,
void aeAcquireLock()
{
g_lock.lock();
g_lock.lock(&m_node);
}
int aeTryAcquireLock()
int aeTryAcquireLock(int fWeak)
{
return g_lock.try_lock();
return g_lock.try_lock(&m_node, fWeak);
}
void aeReleaseLock()
{
g_lock.unlock();
g_lock.unlock(&m_node);
}
int aeThreadOwnsLock()
{
return g_lock.fOwnLock();
return m_node.depth > 0;
}
+11 -6
View File
@@ -58,11 +58,12 @@ extern "C" {
#define AE_WRITE_THREADSAFE 16
#define AE_SLEEP_THREADSAFE 32
#define AE_FILE_EVENTS 1
#define AE_TIME_EVENTS 2
#define AE_FILE_EVENTS (1<<0)
#define AE_TIME_EVENTS (1<<1)
#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)
#define AE_DONT_WAIT 4
#define AE_CALL_AFTER_SLEEP 8
#define AE_DONT_WAIT (1<<2)
#define AE_CALL_BEFORE_SLEEP (1<<3)
#define AE_CALL_AFTER_SLEEP (1<<4)
#define AE_NOMORE -1
#define AE_DELETED_EVENT_ID -1
@@ -97,6 +98,8 @@ typedef struct aeTimeEvent {
void *clientData;
struct aeTimeEvent *prev;
struct aeTimeEvent *next;
int refcount; /* refcount to prevent timer events from being
* freed in recursive time event calls. */
} aeTimeEvent;
/* A fired event */
@@ -124,6 +127,7 @@ typedef struct aeEventLoop {
int fdCmdWrite;
int fdCmdRead;
int cevents;
int flags;
} aeEventLoop;
/* Prototypes */
@@ -131,7 +135,7 @@ aeEventLoop *aeCreateEventLoop(int setsize);
int aePostFunction(aeEventLoop *eventLoop, aePostFunctionProc *proc, void *arg);
#ifdef __cplusplus
} // EXTERN C
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fSynchronous = false);
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fSynchronous = false, bool fLock = true);
extern "C" {
#endif
void aeDeleteEventLoop(aeEventLoop *eventLoop);
@@ -157,9 +161,10 @@ void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep
void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep, int flags);
int aeGetSetSize(aeEventLoop *eventLoop);
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);
void aeSetDontWait(aeEventLoop *eventLoop, int noWait);
void aeAcquireLock();
int aeTryAcquireLock();
int aeTryAcquireLock(int fWeak);
void aeReleaseLock();
int aeThreadOwnsLock();
+2 -2
View File
@@ -125,8 +125,8 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
if (e->events & EPOLLIN) mask |= AE_READABLE;
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE|AE_READABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE|AE_READABLE;
eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;
}
+9 -9
View File
@@ -39,10 +39,10 @@ typedef struct aeApiState {
} aeApiState;
static int aeApiCreate(aeEventLoop *eventLoop) {
aeApiState *state = zmalloc(sizeof(aeApiState));
aeApiState *state = (aeApiState*)zmalloc(sizeof(aeApiState), MALLOC_LOCAL);
if (!state) return -1;
state->events = zmalloc(sizeof(struct kevent)*eventLoop->setsize, MALLOC_LOCAL);
state->events = (struct kevent*)zmalloc(sizeof(struct kevent)*eventLoop->setsize, MALLOC_LOCAL);
if (!state->events) {
zfree(state);
return -1;
@@ -58,14 +58,14 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
}
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
aeApiState *state = eventLoop->apidata;
aeApiState *state = (aeApiState*)eventLoop->apidata;
state->events = zrealloc(state->events, sizeof(struct kevent)*setsize, MALLOC_LOCAL);
state->events = (struct kevent*)zrealloc(state->events, sizeof(struct kevent)*setsize, MALLOC_LOCAL);
return 0;
}
static void aeApiFree(aeEventLoop *eventLoop) {
aeApiState *state = eventLoop->apidata;
aeApiState *state = (aeApiState*)eventLoop->apidata;
close(state->kqfd);
zfree(state->events);
@@ -73,7 +73,7 @@ static void aeApiFree(aeEventLoop *eventLoop) {
}
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = eventLoop->apidata;
aeApiState *state = (aeApiState*)eventLoop->apidata;
struct kevent ke;
if (mask & AE_READABLE) {
@@ -88,7 +88,7 @@ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
}
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = eventLoop->apidata;
aeApiState *state = (aeApiState*)eventLoop->apidata;
struct kevent ke;
if (mask & AE_READABLE) {
@@ -102,7 +102,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
}
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
aeApiState *state = (aeApiState*)eventLoop->apidata;
int retval, numevents = 0;
if (tvp != NULL) {
@@ -133,6 +133,6 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
return numevents;
}
static char *aeApiName(void) {
static const char *aeApiName(void) {
return "kqueue";
}
+79
View File
@@ -0,0 +1,79 @@
#pragma once
class AeLocker
{
bool m_fArmed = false;
public:
AeLocker()
{
}
void arm(client *c) // if a client is passed, then the client is already locked
{
if (m_fArmed)
return;
serverAssertDebug(!GlobalLocksAcquired());
if (c != nullptr)
{
serverAssert(!m_fArmed);
serverAssert(c->lock.fOwnLock());
if (!aeTryAcquireLock(true /*fWeak*/)) // avoid locking the client if we can
{
bool fOwnClientLock = true;
int clientNesting = 1;
for (;;)
{
if (fOwnClientLock)
{
clientNesting = c->lock.unlock_recursive();
fOwnClientLock = false;
}
aeAcquireLock();
if (!c->lock.try_lock(false)) // ensure a strong try because aeAcquireLock is expensive
{
aeReleaseLock();
}
else
{
break;
}
}
c->lock.lock_recursive(clientNesting);
}
m_fArmed = true;
}
else if (!m_fArmed)
{
m_fArmed = true;
aeAcquireLock();
}
}
void disarm()
{
serverAssert(m_fArmed);
m_fArmed = false;
aeReleaseLock();
}
bool isArmed() const
{
return m_fArmed;
}
void release()
{
m_fArmed = false;
}
~AeLocker()
{
if (m_fArmed)
aeReleaseLock();
}
};
+36 -18
View File
@@ -193,6 +193,20 @@ int anetSendTimeout(char *err, int fd, long long ms) {
return ANET_OK;
}
/* Set the socket receive timeout (SO_RCVTIMEO socket option) to the specified
* number of milliseconds, or disable it if the 'ms' argument is zero. */
int anetRecvTimeout(char *err, int fd, long long ms) {
struct timeval tv;
tv.tv_sec = ms/1000;
tv.tv_usec = (ms%1000)*1000;
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
anetSetError(err, "setsockopt SO_RCVTIMEO: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
}
/* anetGenericResolve() is called by anetResolve() and anetResolveIP() to
* do the actual work. It resolves the hostname "host" and set the string
* representation of the IP address into the buffer pointed by "ipbuf".
@@ -276,8 +290,8 @@ static int anetCreateSocket(char *err, int domain) {
#define ANET_CONNECT_NONBLOCK 1
#define ANET_CONNECT_BE_BINDING 2 /* Best effort binding. */
#define ANET_CONNECT_REUSEPORT 4
static int anetTcpGenericConnect(char *err, char *addr, int port,
char *source_addr, int flags)
static int anetTcpGenericConnect(char *err, const char *addr, int port,
const char *source_addr, int flags)
{
int s = ANET_ERR, rv;
char portstr[6]; /* strlen("65535") + 1; */
@@ -359,31 +373,31 @@ end:
}
}
int anetTcpConnect(char *err, char *addr, int port)
int anetTcpConnect(char *err, const char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONE);
}
int anetTcpNonBlockConnect(char *err, char *addr, int port)
int anetTcpNonBlockConnect(char *err, const char *addr, int port)
{
return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONBLOCK);
}
int anetTcpNonBlockBindConnect(char *err, char *addr, int port,
char *source_addr)
int anetTcpNonBlockBindConnect(char *err, const char *addr, int port,
const char *source_addr)
{
return anetTcpGenericConnect(err,addr,port,source_addr,
ANET_CONNECT_NONBLOCK);
}
int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port,
char *source_addr)
int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port,
const char *source_addr)
{
return anetTcpGenericConnect(err,addr,port,source_addr,
ANET_CONNECT_NONBLOCK|ANET_CONNECT_BE_BINDING);
}
int anetUnixGenericConnect(char *err, char *path, int flags)
int anetUnixGenericConnect(char *err, const char *path, int flags)
{
int s;
struct sockaddr_un sa;
@@ -411,12 +425,12 @@ int anetUnixGenericConnect(char *err, char *path, int flags)
return s;
}
int anetUnixConnect(char *err, char *path)
int anetUnixConnect(char *err, const char *path)
{
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE);
}
int anetUnixNonBlockConnect(char *err, char *path)
int anetUnixNonBlockConnect(char *err, const char *path)
{
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK);
}
@@ -476,7 +490,7 @@ static int anetV6Only(char *err, int s) {
return ANET_OK;
}
static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog, int fReusePort)
static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog, int fReusePort, int fFirstListen)
{
int s = -1, rv;
char _port[6]; /* strlen("65535") */
@@ -498,8 +512,12 @@ static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backl
if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
if (fReusePort && anetSetReusePort(err,s) == ANET_ERR) goto error;
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) s = ANET_ERR;
if (fReusePort && !fFirstListen && anetSetReusePort(err,s) == ANET_ERR) goto error;
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) {
s = ANET_ERR;
goto end;
}
if (fReusePort && fFirstListen && anetSetReusePort(err,s) == ANET_ERR) goto error;
goto end;
}
if (p == NULL) {
@@ -515,14 +533,14 @@ end:
return s;
}
int anetTcpServer(char *err, int port, char *bindaddr, int backlog, int fReusePort)
int anetTcpServer(char *err, int port, char *bindaddr, int backlog, int fReusePort, int fFirstListen)
{
return _anetTcpServer(err, port, bindaddr, AF_INET, backlog, fReusePort);
return _anetTcpServer(err, port, bindaddr, AF_INET, backlog, fReusePort, fFirstListen);
}
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog, int fReusePort)
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog, int fReusePort, int fFirstListen)
{
return _anetTcpServer(err, port, bindaddr, AF_INET6, backlog, fReusePort);
return _anetTcpServer(err, port, bindaddr, AF_INET6, backlog, fReusePort, fFirstListen);
}
int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
+9 -8
View File
@@ -53,17 +53,17 @@ extern "C" {
#undef ip_len
#endif
int anetTcpConnect(char *err, char *addr, int port);
int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr);
int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr);
int anetUnixConnect(char *err, char *path);
int anetUnixNonBlockConnect(char *err, char *path);
int anetTcpConnect(char *err, const char *addr, int port);
int anetTcpNonBlockConnect(char *err, const char *addr, int port);
int anetTcpNonBlockBindConnect(char *err, const char *addr, int port, const char *source_addr);
int anetTcpNonBlockBestEffortBindConnect(char *err, const char *addr, int port, const char *source_addr);
int anetUnixConnect(char *err, const char *path);
int anetUnixNonBlockConnect(char *err, const char *path);
int anetRead(int fd, char *buf, int count);
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len);
int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len);
int anetTcpServer(char *err, int port, char *bindaddr, int backlog, int fReusePort);
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog, int fReusePort);
int anetTcpServer(char *err, int port, char *bindaddr, int backlog, int fReusePort, int fFirstListen);
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog, int fReusePort, int fFirstListen);
int anetUnixServer(char *err, char *path, mode_t perm, int backlog);
int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);
int anetUnixAccept(char *err, int serversock);
@@ -74,6 +74,7 @@ int anetEnableTcpNoDelay(char *err, int fd);
int anetDisableTcpNoDelay(char *err, int fd);
int anetTcpKeepAlive(char *err, int fd);
int anetSendTimeout(char *err, int fd, long long ms);
int anetRecvTimeout(char *err, int fd, long long ms);
int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);
int anetKeepAlive(char *err, int fd, int interval);
int anetSockName(int fd, char *ip, size_t ip_len, int *port);
+417 -268
View File
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -27,7 +27,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
char *ascii_logo =
const char *ascii_logo =
" \n"
" \n"
" KeyDB %s (%s/%d) %s bit\n"
@@ -36,4 +36,6 @@ char *ascii_logo =
" Port: %d\n"
" PID: %ld\n"
" \n"
" \n\n";
" %s\n"
" \n"
" \n";
+25 -11
View File
@@ -4,7 +4,7 @@
* Currently there is only a single operation, that is a background close(2)
* system call. This is needed as when the process is the last owner of a
* reference to a file closing it means unlinking it, and the deletion of the
* file is slow, blocking the server.
* file is slow, blocking the g_pserver->
*
* In the future we'll either continue implementing new things we need or
* we'll switch to libeio. However there are probably long term uses for this
@@ -85,7 +85,7 @@ struct bio_job {
void *bioProcessBackgroundJobs(void *arg);
void lazyfreeFreeObjectFromBioThread(robj *o);
void lazyfreeFreeDatabaseFromBioThread(dict *ht1, dict *ht2);
void lazyfreeFreeDatabaseFromBioThread(dict *ht1, expireset *set);
void lazyfreeFreeSlotsMapFromBioThread(rax *rt);
/* Make sure we have enough stack to perform all the things we do in the
@@ -101,9 +101,9 @@ void bioInit(void) {
/* Initialization of state vars and objects */
for (j = 0; j < BIO_NUM_OPS; j++) {
pthread_mutex_init(&bio_mutex[j],NULL);
pthread_cond_init(&bio_newjob_cond[j],NULL);
pthread_cond_init(&bio_step_cond[j],NULL);
serverAssert(pthread_mutex_init(&bio_mutex[j],NULL) == 0);
serverAssert(pthread_cond_init(&bio_newjob_cond[j],NULL) == 0);
serverAssert(pthread_cond_init(&bio_step_cond[j],NULL) == 0);
bio_jobs[j] = listCreate();
bio_pending[j] = 0;
}
@@ -129,7 +129,7 @@ void bioInit(void) {
}
void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3) {
struct bio_job *job = zmalloc(sizeof(*job), MALLOC_LOCAL);
struct bio_job *job = (bio_job*)zmalloc(sizeof(*job), MALLOC_LOCAL);
job->time = time(NULL);
job->arg1 = arg1;
@@ -154,6 +154,20 @@ void *bioProcessBackgroundJobs(void *arg) {
return NULL;
}
switch (type) {
case BIO_CLOSE_FILE:
redis_set_thread_title("bio_close_file");
break;
case BIO_AOF_FSYNC:
redis_set_thread_title("bio_aof_fsync");
break;
case BIO_LAZY_FREE:
redis_set_thread_title("bio_lazy_free");
break;
}
redisSetCpuAffinity(g_pserver->bio_cpulist);
/* Make the thread killable at any time, so that bioKillThreads()
* can work reliably. */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
@@ -178,7 +192,7 @@ void *bioProcessBackgroundJobs(void *arg) {
}
/* Pop the job from the queue. */
ln = listFirst(bio_jobs[type]);
job = ln->value;
job = (bio_job*)ln->value;
/* It is now possible to unlock the background system as we know have
* a stand alone job structure to process.*/
pthread_mutex_unlock(&bio_mutex[type]);
@@ -194,11 +208,11 @@ void *bioProcessBackgroundJobs(void *arg) {
* arg2 & arg3 -> free two dictionaries (a Redis DB).
* only arg3 -> free the skiplist. */
if (job->arg1)
lazyfreeFreeObjectFromBioThread(job->arg1);
lazyfreeFreeObjectFromBioThread((robj*)job->arg1);
else if (job->arg2 && job->arg3)
lazyfreeFreeDatabaseFromBioThread(job->arg2,job->arg3);
lazyfreeFreeDatabaseFromBioThread((dict*)job->arg2,(expireset*)job->arg3);
else if (job->arg3)
lazyfreeFreeSlotsMapFromBioThread(job->arg3);
lazyfreeFreeSlotsMapFromBioThread((rax*)job->arg3);
} else {
serverPanic("Wrong job type in bioProcessBackgroundJobs().");
}
@@ -254,7 +268,7 @@ void bioKillThreads(void) {
int err, j;
for (j = 0; j < BIO_NUM_OPS; j++) {
if (pthread_cancel(bio_threads[j]) == 0) {
if (bio_threads[j] && pthread_cancel(bio_threads[j]) == 0) {
if ((err = pthread_join(bio_threads[j],NULL)) != 0) {
serverLog(LL_WARNING,
"Bio thread for job type #%d can be joined: %s",
+9
View File
@@ -1,3 +1,4 @@
#pragma once
/*
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
@@ -27,6 +28,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Exported API */
void bioInit(void);
void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3);
@@ -40,3 +45,7 @@ void bioKillThreads(void);
#define BIO_AOF_FSYNC 1 /* Deferred AOF fsync. */
#define BIO_LAZY_FREE 2 /* Deferred objects freeing. */
#define BIO_NUM_OPS 3
#ifdef __cplusplus
}
#endif
+236 -136
View File
@@ -37,9 +37,9 @@
/* Count number of bits set in the binary array pointed by 's' and long
* 'count' bytes. The implementation of this function is required to
* work with a input string length up to 512 MB. */
size_t redisPopcount(void *s, long count) {
size_t redisPopcount(const void *s, long count) {
size_t bits = 0;
unsigned char *p = s;
unsigned char *p = (unsigned char*)s;
uint32_t *p4;
static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
@@ -98,7 +98,7 @@ size_t redisPopcount(void *s, long count) {
* no zero bit is found, it returns count*8 assuming the string is zero
* padded on the right. However if 'bit' is 1 it is possible that there is
* not a single set bit in the bitmap. In this special case -1 is returned. */
long redisBitpos(void *s, unsigned long count, int bit) {
long redisBitpos(const void *s, unsigned long count, int bit) {
unsigned long *l;
unsigned char *c;
unsigned long skipval, word = 0, one;
@@ -269,7 +269,7 @@ int64_t getSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits) {
* then zero is returned, otherwise in case of overflow, 1 is returned,
* otherwise in case of underflow, -1 is returned.
*
* When non-zero is returned (oferflow or underflow), if not NULL, *limit is
* When non-zero is returned (overflow or underflow), if not NULL, *limit is
* set to the value the operation should result when an overflow happens,
* depending on the specified overflow semantics:
*
@@ -396,6 +396,8 @@ void printBits(unsigned char *p, unsigned long count) {
#define BITOP_OR 1
#define BITOP_XOR 2
#define BITOP_NOT 3
#define BITOP_LSHIFT 4
#define BITOP_RSHIFT 5
#define BITFIELDOP_GET 0
#define BITFIELDOP_SET 1
@@ -410,8 +412,8 @@ void printBits(unsigned char *p, unsigned long count) {
* is multiplied by 'bits'. This is useful for the BITFIELD command. */
int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int bits) {
long long loffset;
char *err = "bit offset is not an integer or out of range";
char *p = ptrFromObj(o);
const char *err = "bit offset is not an integer or out of range";
char *p = szFromObj(o);
size_t plen = sdslen(p);
int usehash = 0;
@@ -445,8 +447,8 @@ int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int b
*
* On error C_ERR is returned and an error is sent to the client. */
int getBitfieldTypeFromArgument(client *c, robj *o, int *sign, int *bits) {
char *p = ptrFromObj(o);
char *err = "Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is.";
char *p = szFromObj(o);
const char *err = "Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is.";
long long llbits;
if (p[0] == 'i') {
@@ -485,7 +487,7 @@ robj *lookupStringForBitCommand(client *c, size_t maxbit) {
} else {
if (checkType(c,o,OBJ_STRING)) return NULL;
o = dbUnshareStringValue(c->db,c->argv[1],o);
o->m_ptr = sdsgrowzero(ptrFromObj(o),byte+1);
o->m_ptr = sdsgrowzero(szFromObj(o),byte+1);
}
return o;
}
@@ -503,18 +505,18 @@ robj *lookupStringForBitCommand(client *c, size_t maxbit) {
*
* If the source object is NULL the function is guaranteed to return NULL
* and set 'len' to 0. */
unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
const unsigned char *getObjectReadOnlyString(robj_roptr o, long *len, char *llbuf) {
serverAssert(o->type == OBJ_STRING);
unsigned char *p = NULL;
const unsigned char *p = NULL;
/* Set the 'p' pointer to the string, that can be just a stack allocated
* array if our string was integer encoded. */
if (o && o->encoding == OBJ_ENCODING_INT) {
p = (unsigned char*) llbuf;
p = (const unsigned char*) llbuf;
if (len) *len = ll2string(llbuf,LONG_STR_SIZE,(long)ptrFromObj(o));
} else if (o) {
p = (unsigned char*) ptrFromObj(o);
if (len) *len = sdslen(ptrFromObj(o));
p = (const unsigned char*) ptrFromObj(o);
if (len) *len = sdslen(szFromObj(o));
} else {
if (len) *len = 0;
}
@@ -524,7 +526,7 @@ unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
/* SETBIT key offset bitvalue */
void setbitCommand(client *c) {
robj *o;
char *err = "bit is not an integer or out of range";
const char *err = "bit is not an integer or out of range";
size_t bitoffset;
ssize_t byte, bit;
int byteval, bitval;
@@ -554,15 +556,15 @@ void setbitCommand(client *c) {
byteval &= ~(1 << bit);
byteval |= ((on & 0x1) << bit);
((uint8_t*)ptrFromObj(o))[byte] = byteval;
signalModifiedKey(c->db,c->argv[1]);
signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
server.dirty++;
g_pserver->dirty++;
addReply(c, bitval ? shared.cone : shared.czero);
}
/* GETBIT key offset */
void getbitCommand(client *c) {
robj *o;
robj_roptr o;
char llbuf[32];
size_t bitoffset;
size_t byte, bit;
@@ -571,13 +573,13 @@ void getbitCommand(client *c) {
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset,0,0) != C_OK)
return;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == nullptr ||
checkType(c,o,OBJ_STRING)) return;
byte = bitoffset >> 3;
bit = 7 - (bitoffset & 0x7);
if (sdsEncodedObject(o)) {
if (byte < sdslen(ptrFromObj(o)))
if (byte < sdslen(szFromObj(o)))
bitval = ((uint8_t*)ptrFromObj(o))[byte] & (1 << bit);
} else {
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)ptrFromObj(o)))
@@ -589,10 +591,12 @@ void getbitCommand(client *c) {
/* BITOP op_name target_key src_key1 src_key2 src_key3 ... src_keyN */
void bitopCommand(client *c) {
char *opname = ptrFromObj(c->argv[1]);
robj *o, *targetkey = c->argv[2];
unsigned long op, j, numkeys;
robj **objects; /* Array of source objects. */
char *opname = szFromObj(c->argv[1]);
robj *targetkey = c->argv[2];
robj_roptr o;
int op;
unsigned long j, numkeys;
robj_roptr *objects; /* Array of source objects. */
unsigned char **src; /* Array of source strings pointers. */
unsigned long *len, maxlen = 0; /* Array of length of src strings,
and max len. */
@@ -608,6 +612,10 @@ void bitopCommand(client *c) {
op = BITOP_XOR;
else if((opname[0] == 'n' || opname[0] == 'N') && !strcasecmp(opname,"not"))
op = BITOP_NOT;
else if (!strcasecmp(opname, "lshift"))
op = BITOP_LSHIFT;
else if (!strcasecmp(opname, "rshift"))
op = BITOP_RSHIFT;
else {
addReply(c,shared.syntaxerr);
return;
@@ -619,16 +627,33 @@ void bitopCommand(client *c) {
return;
}
bool fShiftOp = (op == BITOP_LSHIFT) || (op == BITOP_RSHIFT);
long long shift = 0;
/* Sanity check: SHIFTS only accept a single arg and an integer */
if (fShiftOp) {
if (c->argc != 5) {
addReplyError(c,"BITOP SHIFT must be called with a single source key and an integer shift.");
return;
}
if (getLongLongFromObject(c->argv[4], &shift) != C_OK) {
addReplyError(c, "BITOP SHIFT's last parameter must be an integer");
return;
}
if (op == BITOP_RSHIFT)
shift = -shift;
}
/* Lookup keys, and store pointers to the string objects into an array. */
numkeys = c->argc - 3;
src = zmalloc(sizeof(unsigned char*) * numkeys, MALLOC_LOCAL);
len = zmalloc(sizeof(long) * numkeys, MALLOC_LOCAL);
objects = zmalloc(sizeof(robj*) * numkeys, MALLOC_LOCAL);
numkeys = c->argc - (fShiftOp ? 4 : 3);
src = (unsigned char**)zmalloc(sizeof(unsigned char*) * numkeys, MALLOC_LOCAL);
len = (unsigned long*)zmalloc(sizeof(long) * numkeys, MALLOC_LOCAL);
objects = (robj_roptr*)zmalloc(sizeof(robj_roptr) * numkeys, MALLOC_LOCAL);
for (j = 0; j < numkeys; j++) {
o = lookupKeyRead(c->db,c->argv[j+3]);
/* Handle non-existing keys as empty strings. */
if (o == NULL) {
objects[j] = NULL;
if (o == nullptr) {
objects[j] = nullptr;
src[j] = NULL;
len[j] = 0;
minlen = 0;
@@ -647,100 +672,149 @@ void bitopCommand(client *c) {
return;
}
objects[j] = getDecodedObject(o);
src[j] = ptrFromObj(objects[j]);
len[j] = sdslen(ptrFromObj(objects[j]));
src[j] = (unsigned char*)ptrFromObj(objects[j]);
len[j] = sdslen(szFromObj(objects[j]));
if (len[j] > maxlen) maxlen = len[j];
if (j == 0 || len[j] < minlen) minlen = len[j];
}
/* Compute the bit operation, if at least one string is not empty. */
if (maxlen) {
res = (unsigned char*) sdsnewlen(NULL,maxlen);
unsigned char output, byte;
unsigned long i;
if (fShiftOp)
{
long newlen = (long)maxlen + shift/CHAR_BIT;
if (shift > 0 && (shift % CHAR_BIT) != 0)
newlen++;
/* Fast path: as far as we have data for all the input bitmaps we
* can take a fast path that performs much better than the
* vanilla algorithm. On ARM we skip the fast path since it will
* result in GCC compiling the code using multiple-words load/store
* operations that are not supported even in ARM >= v6. */
j = 0;
#ifndef USE_ALIGNED_ACCESS
if (minlen >= sizeof(unsigned long)*4 && numkeys <= 16) {
unsigned long *lp[16];
unsigned long *lres = (unsigned long*) res;
if (newlen < 0)
newlen = 0;
if (newlen)
{
res = (unsigned char*) sdsnewlen(NULL,newlen);
if (shift >= 0)
{ // left shift
long byteoffset = shift/CHAR_BIT;
memset(res, 0, byteoffset);
long srcLen = newlen - byteoffset - ((shift % CHAR_BIT) ? 1 : 0);
/* Note: sds pointer is always aligned to 8 byte boundary. */
memcpy(lp,src,sizeof(unsigned long*)*numkeys);
memcpy(res,src[0],minlen);
/* Different branches per different operations for speed (sorry). */
if (op == BITOP_AND) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] &= lp[i][0];
lres[1] &= lp[i][1];
lres[2] &= lp[i][2];
lres[3] &= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
// now the bitshift+copy
unsigned bitshift = shift % CHAR_BIT;
unsigned char carry = 0;
for (long iSrc = 0; iSrc < srcLen; ++iSrc)
{
res[byteoffset+iSrc] = (src[0][iSrc] << bitshift) | carry;
carry = src[0][iSrc] >> (CHAR_BIT - bitshift);
}
} else if (op == BITOP_OR) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] |= lp[i][0];
lres[1] |= lp[i][1];
lres[2] |= lp[i][2];
lres[3] |= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
} else if (op == BITOP_XOR) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] ^= lp[i][0];
lres[1] ^= lp[i][1];
lres[2] ^= lp[i][2];
lres[3] ^= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
} else if (op == BITOP_NOT) {
while(minlen >= sizeof(unsigned long)*4) {
lres[0] = ~lres[0];
lres[1] = ~lres[1];
lres[2] = ~lres[2];
lres[3] = ~lres[3];
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
if (bitshift)
res[newlen-1] = carry;
}
else
{ // right shift
long byteoffset = -shift/CHAR_BIT;
unsigned bitshift = -shift % CHAR_BIT;
if (bitshift)
++byteoffset;
res[0] = (src[0][byteoffset] << (CHAR_BIT-bitshift));
if (byteoffset > 0)
res[0] |= (src[0][byteoffset-1] >> bitshift);
for (long idx = 1; idx < newlen; ++idx)
{
res[idx] = (src[0][byteoffset+idx] << (CHAR_BIT-bitshift)) | (src[0][byteoffset+idx-1] >> bitshift);
}
}
}
#endif
maxlen = newlen; // this is to ensure we DEL below if newlen was 0
}
else
{
/* Compute the bit operation, if at least one string is not empty. */
if (maxlen) {
res = (unsigned char*) sdsnewlen(NULL,maxlen);
unsigned char output, byte;
unsigned long i;
/* j is set to the next byte to process by the previous loop. */
for (; j < maxlen; j++) {
output = (len[0] <= j) ? 0 : src[0][j];
if (op == BITOP_NOT) output = ~output;
for (i = 1; i < numkeys; i++) {
byte = (len[i] <= j) ? 0 : src[i][j];
switch(op) {
case BITOP_AND: output &= byte; break;
case BITOP_OR: output |= byte; break;
case BITOP_XOR: output ^= byte; break;
/* Fast path: as far as we have data for all the input bitmaps we
* can take a fast path that performs much better than the
* vanilla algorithm. On ARM we skip the fast path since it will
* result in GCC compiling the code using multiple-words load/store
* operations that are not supported even in ARM >= v6. */
j = 0;
#ifndef USE_ALIGNED_ACCESS
if (minlen >= sizeof(unsigned long)*4 && numkeys <= 16) {
unsigned long *lp[16];
unsigned long *lres = (unsigned long*) res;
/* Note: sds pointer is always aligned to 8 byte boundary. */
memcpy(lp,src,sizeof(unsigned long*)*numkeys);
memcpy(res,src[0],minlen);
/* Different branches per different operations for speed (sorry). */
if (op == BITOP_AND) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] &= lp[i][0];
lres[1] &= lp[i][1];
lres[2] &= lp[i][2];
lres[3] &= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
} else if (op == BITOP_OR) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] |= lp[i][0];
lres[1] |= lp[i][1];
lres[2] |= lp[i][2];
lres[3] |= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
} else if (op == BITOP_XOR) {
while(minlen >= sizeof(unsigned long)*4) {
for (i = 1; i < numkeys; i++) {
lres[0] ^= lp[i][0];
lres[1] ^= lp[i][1];
lres[2] ^= lp[i][2];
lres[3] ^= lp[i][3];
lp[i]+=4;
}
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
} else if (op == BITOP_NOT) {
while(minlen >= sizeof(unsigned long)*4) {
lres[0] = ~lres[0];
lres[1] = ~lres[1];
lres[2] = ~lres[2];
lres[3] = ~lres[3];
lres+=4;
j += sizeof(unsigned long)*4;
minlen -= sizeof(unsigned long)*4;
}
}
}
res[j] = output;
#endif
/* j is set to the next byte to process by the previous loop. */
for (; j < maxlen; j++) {
output = (len[0] <= j) ? 0 : src[0][j];
if (op == BITOP_NOT) output = ~output;
for (i = 1; i < numkeys; i++) {
byte = (len[i] <= j) ? 0 : src[i][j];
switch(op) {
case BITOP_AND: output &= byte; break;
case BITOP_OR: output |= byte; break;
case BITOP_XOR: output ^= byte; break;
}
}
res[j] = output;
}
}
}
for (j = 0; j < numkeys; j++) {
@@ -753,27 +827,27 @@ void bitopCommand(client *c) {
/* Store the computed value into the target key */
if (maxlen) {
o = createObject(OBJ_STRING,res);
setKey(c->db,targetkey,o);
robj *o = createObject(OBJ_STRING,res);
setKey(c,c->db,targetkey,o);
notifyKeyspaceEvent(NOTIFY_STRING,"set",targetkey,c->db->id);
decrRefCount(o);
} else if (dbDelete(c->db,targetkey)) {
signalModifiedKey(c->db,targetkey);
signalModifiedKey(c,c->db,targetkey);
notifyKeyspaceEvent(NOTIFY_GENERIC,"del",targetkey,c->db->id);
}
server.dirty++;
g_pserver->dirty++;
addReplyLongLong(c,maxlen); /* Return the output string length in bytes. */
}
/* BITCOUNT key [start end] */
void bitcountCommand(client *c) {
robj *o;
robj_roptr o;
long start, end, strlen;
unsigned char *p;
const unsigned char *p;
char llbuf[LONG_STR_SIZE];
/* Lookup, check for type, and return 0 for non existing keys. */
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == nullptr ||
checkType(c,o,OBJ_STRING)) return;
p = getObjectReadOnlyString(o,&strlen,llbuf);
@@ -816,9 +890,9 @@ void bitcountCommand(client *c) {
/* BITPOS key bit [start [end]] */
void bitposCommand(client *c) {
robj *o;
robj_roptr o;
long bit, start, end, strlen;
unsigned char *p;
const unsigned char *p;
char llbuf[LONG_STR_SIZE];
int end_given = 0;
@@ -834,7 +908,7 @@ void bitposCommand(client *c) {
/* If the key does not exist, from our point of view it is an infinite
* array of 0 bits. If the user is looking for the fist clear bit return 0,
* If the user is looking for the first set bit, return -1. */
if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) {
if ((o = lookupKeyRead(c->db,c->argv[1])) == nullptr) {
addReplyLongLong(c, bit ? -1 : 0);
return;
}
@@ -902,6 +976,9 @@ void bitposCommand(client *c) {
* OVERFLOW [WRAP|SAT|FAIL]
*/
#define BITFIELD_FLAG_NONE 0
#define BITFIELD_FLAG_READONLY (1<<0)
struct bitfieldOp {
uint64_t offset; /* Bitfield offset. */
int64_t i64; /* Increment amount (INCRBY) or SET value */
@@ -911,8 +988,11 @@ struct bitfieldOp {
int sign; /* True if signed, otherwise unsigned op. */
};
void bitfieldCommand(client *c) {
robj *o;
/* This implements both the BITFIELD command and the BITFIELD_RO command
* when flags is set to BITFIELD_FLAG_READONLY: in this case only the
* GET subcommand is allowed, other subcommands will return an error. */
void bitfieldGeneric(client *c, int flags) {
robj_roptr o;
size_t bitoffset;
int j, numops = 0, changes = 0;
struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
@@ -922,7 +1002,7 @@ void bitfieldCommand(client *c) {
for (j = 2; j < c->argc; j++) {
int remargs = c->argc-j-1; /* Remaining args other than current. */
char *subcmd = ptrFromObj(c->argv[j]); /* Current command name. */
char *subcmd = szFromObj(c->argv[j]); /* Current command name. */
int opcode; /* Current operation code. */
long long i64 = 0; /* Signed SET value. */
int sign = 0; /* Signed or unsigned type? */
@@ -935,7 +1015,7 @@ void bitfieldCommand(client *c) {
else if (!strcasecmp(subcmd,"incrby") && remargs >= 3)
opcode = BITFIELDOP_INCRBY;
else if (!strcasecmp(subcmd,"overflow") && remargs >= 1) {
char *owtypename = ptrFromObj(c->argv[j+1]);
char *owtypename = szFromObj(c->argv[j+1]);
j++;
if (!strcasecmp(owtypename,"wrap"))
owtype = BFOVERFLOW_WRAP;
@@ -978,7 +1058,7 @@ void bitfieldCommand(client *c) {
}
/* Populate the array of operations we'll process. */
ops = zrealloc(ops,sizeof(*ops)*(numops+1), MALLOC_SHARED);
ops = (bitfieldOp*)zrealloc(ops,sizeof(*ops)*(numops+1), MALLOC_SHARED);
ops[numops].offset = bitoffset;
ops[numops].i64 = i64;
ops[numops].opcode = opcode;
@@ -994,12 +1074,24 @@ void bitfieldCommand(client *c) {
/* Lookup for read is ok if key doesn't exit, but errors
* if it's not a string. */
o = lookupKeyRead(c->db,c->argv[1]);
if (o != NULL && checkType(c,o,OBJ_STRING)) return;
if (o != nullptr && checkType(c,o,OBJ_STRING)) {
zfree(ops);
return;
}
} else {
if (flags & BITFIELD_FLAG_READONLY) {
zfree(ops);
addReplyError(c, "BITFIELD_RO only supports the GET subcommand");
return;
}
/* Lookup by making room up to the farest bit reached by
* this operation. */
if ((o = lookupStringForBitCommand(c,
highest_write_offset)) == NULL) return;
highest_write_offset)) == nullptr) {
zfree(ops);
return;
}
}
addReplyArrayLen(c,numops);
@@ -1023,7 +1115,7 @@ void bitfieldCommand(client *c) {
int64_t oldval, newval, wrapped, retval;
int overflow;
oldval = getSignedBitfield(ptrFromObj(o),thisop->offset,
oldval = getSignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
thisop->bits);
if (thisop->opcode == BITFIELDOP_INCRBY) {
@@ -1044,7 +1136,7 @@ void bitfieldCommand(client *c) {
* NULL to signal the condition. */
if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
addReplyLongLong(c,retval);
setSignedBitfield(ptrFromObj(o),thisop->offset,
setSignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
thisop->bits,newval);
} else {
addReplyNull(c);
@@ -1053,7 +1145,7 @@ void bitfieldCommand(client *c) {
uint64_t oldval, newval, wrapped, retval;
int overflow;
oldval = getUnsignedBitfield(ptrFromObj(o),thisop->offset,
oldval = getUnsignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
thisop->bits);
if (thisop->opcode == BITFIELDOP_INCRBY) {
@@ -1073,7 +1165,7 @@ void bitfieldCommand(client *c) {
* NULL to signal the condition. */
if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
addReplyLongLong(c,retval);
setUnsignedBitfield(ptrFromObj(o),thisop->offset,
setUnsignedBitfield((unsigned char*)ptrFromObj(o),thisop->offset,
thisop->bits,newval);
} else {
addReplyNull(c);
@@ -1084,10 +1176,10 @@ void bitfieldCommand(client *c) {
/* GET */
unsigned char buf[9];
long strlen = 0;
unsigned char *src = NULL;
const unsigned char *src = NULL;
char llbuf[LONG_STR_SIZE];
if (o != NULL)
if (o != nullptr)
src = getObjectReadOnlyString(o,&strlen,llbuf);
/* For GET we use a trick: before executing the operation
@@ -1117,9 +1209,17 @@ void bitfieldCommand(client *c) {
}
if (changes) {
signalModifiedKey(c->db,c->argv[1]);
signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
server.dirty += changes;
g_pserver->dirty += changes;
}
zfree(ops);
}
void bitfieldCommand(client *c) {
bitfieldGeneric(c, BITFIELD_FLAG_NONE);
}
void bitfieldroCommand(client *c) {
bitfieldGeneric(c, BITFIELD_FLAG_READONLY);
}
+332 -281
View File
@@ -31,9 +31,6 @@
*
* API:
*
* getTimeoutFromObjectOrReply() is just an utility function to parse a
* timeout argument since blocking operations usually require a timeout.
*
* blockClient() set the CLIENT_BLOCKED flag in the client, and set the
* specified block type 'btype' filed to one of BLOCKED_* macros.
*
@@ -64,64 +61,52 @@
*/
#include "server.h"
#include <mutex>
int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where);
/* Get a timeout value from an object and store it into 'timeout'.
* The final timeout is always stored as milliseconds as a time where the
* timeout will expire, however the parsing is performed according to
* the 'unit' that can be seconds or milliseconds.
*
* Note that if the timeout is zero (usually from the point of view of
* commands API this means no timeout) the value stored into 'timeout'
* is zero. */
int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeout, int unit) {
long long tval;
if (getLongLongFromObjectOrReply(c,object,&tval,
"timeout is not an integer or out of range") != C_OK)
return C_ERR;
if (tval < 0) {
addReplyError(c,"timeout is negative");
return C_ERR;
}
if (tval > 0) {
if (unit == UNIT_SECONDS) tval *= 1000;
tval += mstime();
}
*timeout = tval;
return C_OK;
}
/* This structure represents the blocked key information that we store
* in the client structure. Each client blocked on keys, has a
* client->bpop.keys hash table. The keys of the hash table are Redis
* keys pointers to 'robj' structures. The value is this structure.
* The structure has two goals: firstly we store the list node that this
* client uses to be listed in the database "blocked clients for this key"
* list, so we can later unblock in O(1) without a list scan.
* Secondly for certain blocking types, we have additional info. Right now
* the only use for additional info we have is when clients are blocked
* on streams, as we have to remember the ID it blocked for. */
typedef struct bkinfo {
listNode *listnode; /* List node for db->blocking_keys[key] list. */
streamID stream_id; /* Stream ID if we blocked in a stream. */
} bkinfo;
/* Block a client for the specific operation type. Once the CLIENT_BLOCKED
* flag is set client query buffer is not longer processed, but accumulated,
* and will be processed when the client is unblocked. */
void blockClient(client *c, int btype) {
serverAssert(aeThreadOwnsLock());
serverAssert(GlobalLocksAcquired());
c->flags |= CLIENT_BLOCKED;
c->btype = btype;
server.blocked_clients++;
server.blocked_clients_by_type[btype]++;
g_pserver->blocked_clients++;
g_pserver->blocked_clients_by_type[btype]++;
addClientToTimeoutTable(c);
}
/* This function is called in the beforeSleep() function of the event loop
* in order to process the pending input buffer of clients that were
* unblocked after a blocking operation. */
void processUnblockedClients(int iel) {
serverAssert(aeThreadOwnsLock());
serverAssert(GlobalLocksAcquired());
listNode *ln;
client *c;
list *unblocked_clients = server.rgthreadvar[iel].unblocked_clients;
serverAssert(iel == (serverTL - server.rgthreadvar));
list *unblocked_clients = g_pserver->rgthreadvar[iel].unblocked_clients;
serverAssert(iel == (serverTL - g_pserver->rgthreadvar));
while (listLength(unblocked_clients)) {
ln = listFirst(unblocked_clients);
serverAssert(ln != NULL);
c = ln->value;
c = (client*)ln->value;
listDelNode(unblocked_clients,ln);
AssertCorrectThread(c);
@@ -134,7 +119,7 @@ void processUnblockedClients(int iel) {
* the code is conceptually more correct this way. */
if (!(c->flags & CLIENT_BLOCKED)) {
if (c->querybuf && sdslen(c->querybuf) > 0) {
processInputBufferAndReplicate(c);
processInputBuffer(c, CMD_CALL_FULL);
}
}
fastlock_unlock(&c->lock);
@@ -160,11 +145,11 @@ void processUnblockedClients(int iel) {
void queueClientForReprocessing(client *c) {
/* The client may already be into the unblocked list because of a previous
* blocking operation, don't add back it into the list multiple times. */
serverAssert(aeThreadOwnsLock());
serverAssert(GlobalLocksAcquired());
fastlock_lock(&c->lock);
if (!(c->flags & CLIENT_UNBLOCKED)) {
c->flags |= CLIENT_UNBLOCKED;
listAddNodeTail(server.rgthreadvar[c->iel].unblocked_clients,c);
listAddNodeTail(g_pserver->rgthreadvar[c->iel].unblocked_clients,c);
}
fastlock_unlock(&c->lock);
}
@@ -172,7 +157,8 @@ void queueClientForReprocessing(client *c) {
/* Unblock a client calling the right function depending on the kind
* of operation the client is blocking for. */
void unblockClient(client *c) {
serverAssert(aeThreadOwnsLock());
serverAssert(GlobalLocksAcquired());
serverAssert(c->lock.fOwnLock());
if (c->btype == BLOCKED_LIST ||
c->btype == BLOCKED_ZSET ||
c->btype == BLOCKED_STREAM) {
@@ -180,16 +166,18 @@ void unblockClient(client *c) {
} else if (c->btype == BLOCKED_WAIT) {
unblockClientWaitingReplicas(c);
} else if (c->btype == BLOCKED_MODULE) {
if (moduleClientIsBlockedOnKeys(c)) unblockClientWaitingData(c);
unblockClientFromModule(c);
} else {
serverPanic("Unknown btype in unblockClient().");
}
/* Clear the flags, and put the client in the unblocked list so that
* we'll process new commands in its query buffer ASAP. */
server.blocked_clients--;
server.blocked_clients_by_type[c->btype]--;
g_pserver->blocked_clients--;
g_pserver->blocked_clients_by_type[c->btype]--;
c->flags &= ~CLIENT_BLOCKED;
c->btype = BLOCKED_NONE;
removeClientFromTimeoutTable(c);
queueClientForReprocessing(c);
}
@@ -200,9 +188,9 @@ void replyToBlockedClientTimedOut(client *c) {
if (c->btype == BLOCKED_LIST ||
c->btype == BLOCKED_ZSET ||
c->btype == BLOCKED_STREAM) {
addReplyNullArray(c);
addReplyNullArrayAsync(c);
} else if (c->btype == BLOCKED_WAIT) {
addReplyLongLong(c,replicationCountAcksByOffset(c->bpop.reploffset));
addReplyLongLongAsync(c,replicationCountAcksByOffset(c->bpop.reploffset));
} else if (c->btype == BLOCKED_MODULE) {
moduleBlockedClientTimedOut(c);
} else {
@@ -212,19 +200,19 @@ void replyToBlockedClientTimedOut(client *c) {
/* Mass-unblock clients because something changed in the instance that makes
* blocking no longer safe. For example clients blocked in list operations
* in an instance which turns from master to slave is unsafe, so this function
* is called when a master turns into a slave.
* in an instance which turns from master to replica is unsafe, so this function
* is called when a master turns into a replica.
*
* The semantics is to send an -UNBLOCKED error to the client, disconnecting
* it at the same time. */
void disconnectAllBlockedClients(void) {
serverAssert(aeThreadOwnsLock());
serverAssert(GlobalLocksAcquired());
listNode *ln;
listIter li;
listRewind(server.clients,&li);
listRewind(g_pserver->clients,&li);
while((ln = listNext(&li))) {
client *c = listNodeValue(ln);
client *c = (client*)listNodeValue(ln);
fastlock_lock(&c->lock);
if (c->flags & CLIENT_BLOCKED) {
@@ -238,6 +226,251 @@ void disconnectAllBlockedClients(void) {
}
}
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a list key, and there may be new
* data to fetch (the key is ready). */
void serveClientsBlockedOnListKey(robj *o, readyList *rl) {
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
dictEntry *de = dictFind(rl->db->blocking_keys,rl->key);
if (de) {
list *clients = (list*)dictGetVal(de);
int numclients = listLength(clients);
while(numclients--) {
listNode *clientnode = listFirst(clients);
client *receiver = (client*)clientnode->value;
std::unique_lock<decltype(receiver->lock)> lock(receiver->lock);
if (receiver->btype != BLOCKED_LIST) {
/* Put at the tail, so that at the next call
* we'll not run into it again. */
listRotateHeadToTail(clients);
continue;
}
robj *dstkey = receiver->bpop.target;
int where = (receiver->lastcmd &&
receiver->lastcmd->proc == blpopCommand) ?
LIST_HEAD : LIST_TAIL;
robj *value = listTypePop(o,where);
if (value) {
/* Protect receiver->bpop.target, that will be
* freed by the next unblockClient()
* call. */
if (dstkey) incrRefCount(dstkey);
unblockClient(receiver);
if (serveClientBlockedOnList(receiver,
rl->key,dstkey,rl->db,value,
where) == C_ERR)
{
/* If we failed serving the client we need
* to also undo the POP operation. */
listTypePush(o,value,where);
}
if (dstkey) decrRefCount(dstkey);
decrRefCount(value);
} else {
break;
}
}
}
if (listTypeLength(o) == 0) {
dbDelete(rl->db,rl->key);
notifyKeyspaceEvent(NOTIFY_GENERIC,"del",rl->key,rl->db->id);
}
/* We don't call signalModifiedKey() as it was already called
* when an element was pushed on the list. */
}
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a sorted set key, and there may be new
* data to fetch (the key is ready). */
void serveClientsBlockedOnSortedSetKey(robj *o, readyList *rl) {
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
dictEntry *de = dictFind(rl->db->blocking_keys,rl->key);
if (de) {
list *clients = (list*)dictGetVal(de);
int numclients = listLength(clients);
unsigned long zcard = zsetLength(o);
while(numclients-- && zcard) {
listNode *clientnode = listFirst(clients);
client *receiver = (client*)clientnode->value;
std::unique_lock<decltype(receiver->lock)> lock(receiver->lock);
if (receiver->btype != BLOCKED_ZSET) {
/* Put at the tail, so that at the next call
* we'll not run into it again. */
listRotateHeadToTail(clients);
continue;
}
int where = (receiver->lastcmd &&
receiver->lastcmd->proc == bzpopminCommand)
? ZSET_MIN : ZSET_MAX;
unblockClient(receiver);
genericZpopCommand(receiver,&rl->key,1,where,1,NULL);
zcard--;
/* Replicate the command. */
robj *argv[2];
struct redisCommand *cmd = where == ZSET_MIN ?
cserver.zpopminCommand :
cserver.zpopmaxCommand;
argv[0] = createStringObject(cmd->name,strlen(cmd->name));
argv[1] = rl->key;
incrRefCount(rl->key);
propagate(cmd,receiver->db->id,
argv,2,PROPAGATE_AOF|PROPAGATE_REPL);
decrRefCount(argv[0]);
decrRefCount(argv[1]);
}
}
}
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* when there may be clients blocked on a stream key, and there may be new
* data to fetch (the key is ready). */
void serveClientsBlockedOnStreamKey(robj *o, readyList *rl) {
dictEntry *de = dictFind(rl->db->blocking_keys,rl->key);
stream *s = (stream*)ptrFromObj(o);
/* We need to provide the new data arrived on the stream
* to all the clients that are waiting for an offset smaller
* than the current top item. */
if (de) {
list *clients = (list*)dictGetVal(de);
listNode *ln;
listIter li;
listRewind(clients,&li);
while((ln = listNext(&li))) {
client *receiver = (client*)listNodeValue(ln);
if (receiver->btype != BLOCKED_STREAM) continue;
std::unique_lock<decltype(receiver->lock)> lock(receiver->lock);
bkinfo *bki = (bkinfo*)dictFetchValue(receiver->bpop.keys,rl->key);
streamID *gt = &bki->stream_id;
/* If we blocked in the context of a consumer
* group, we need to resolve the group and update the
* last ID the client is blocked for: this is needed
* because serving other clients in the same consumer
* group will alter the "last ID" of the consumer
* group, and clients blocked in a consumer group are
* always blocked for the ">" ID: we need to deliver
* only new messages and avoid unblocking the client
* otherwise. */
streamCG *group = NULL;
if (receiver->bpop.xread_group) {
group = streamLookupCG(s,
szFromObj(receiver->bpop.xread_group));
/* If the group was not found, send an error
* to the consumer. */
if (!group) {
addReplyErrorAsync(receiver,
"-NOGROUP the consumer group this client "
"was blocked on no longer exists");
unblockClient(receiver);
continue;
} else {
*gt = group->last_id;
}
}
if (streamCompareID(&s->last_id, gt) > 0) {
streamID start = *gt;
streamIncrID(&start);
/* Lookup the consumer for the group, if any. */
streamConsumer *consumer = NULL;
int noack = 0;
if (group) {
consumer =
streamLookupConsumer(group,
szFromObj(receiver->bpop.xread_consumer),
SLC_NONE);
noack = receiver->bpop.xread_group_noack;
}
/* Emit the two elements sub-array consisting of
* the name of the stream and the data we
* extracted from it. Wrapped in a single-item
* array, since we have just one key. */
if (receiver->resp == 2) {
addReplyArrayLenAsync(receiver,1);
addReplyArrayLenAsync(receiver,2);
} else {
addReplyMapLenAsync(receiver,1);
}
addReplyBulkAsync(receiver,rl->key);
streamPropInfo pi = {
rl->key,
receiver->bpop.xread_group
};
streamReplyWithRange(receiver,s,&start,NULL,
receiver->bpop.xread_count,
0, group, consumer, noack, &pi);
/* Note that after we unblock the client, 'gt'
* and other receiver->bpop stuff are no longer
* valid, so we must do the setup above before
* this call. */
unblockClient(receiver);
}
}
}
}
/* Helper function for handleClientsBlockedOnKeys(). This function is called
* in order to check if we can serve clients blocked by modules using
* RM_BlockClientOnKeys(), when the corresponding key was signaled as ready:
* our goal here is to call the RedisModuleBlockedClient reply() callback to
* see if the key is really able to serve the client, and in that case,
* unblock it. */
void serveClientsBlockedOnKeyByModule(readyList *rl) {
dictEntry *de;
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
de = dictFind(rl->db->blocking_keys,rl->key);
if (de) {
list *clients = (list*)dictGetVal(de);
int numclients = listLength(clients);
while(numclients--) {
listNode *clientnode = listFirst(clients);
client *receiver = (client*)clientnode->value;
/* Put at the tail, so that at the next call
* we'll not run into it again: clients here may not be
* ready to be served, so they'll remain in the list
* sometimes. We want also be able to skip clients that are
* not blocked for the MODULE type safely. */
listRotateHeadToTail(clients);
if (receiver->btype != BLOCKED_MODULE) continue;
/* Note that if *this* client cannot be served by this key,
* it does not mean that another client that is next into the
* list cannot be served as well: they may be blocked by
* different modules with different triggers to consider if a key
* is ready or not. This means we can't exit the loop but need
* to continue after the first failure. */
if (!moduleTryServeClientBlockedOnKey(receiver, rl->key)) continue;
moduleUnblockClient(receiver);
}
}
}
/* This function should be called by Redis every time a single command,
* a MULTI/EXEC block, or a Lua script, terminated its execution after
* being called by a client. It handles serving clients blocked in
@@ -245,7 +478,7 @@ void disconnectAllBlockedClients(void) {
*
* All the keys with at least one client blocked that received at least
* one new element via some write operation are accumulated into
* the server.ready_keys list. This function will run the list and will
* the g_pserver->ready_keys list. This function will run the list and will
* serve clients accordingly. Note that the function will iterate again and
* again as a result of serving BRPOPLPUSH we can have new blocking clients
* to serve because of the PUSH side of BRPOPLPUSH.
@@ -260,233 +493,51 @@ void disconnectAllBlockedClients(void) {
* be used only for a single type, like virtually any Redis application will
* do, the function is already fair. */
void handleClientsBlockedOnKeys(void) {
serverAssert(aeThreadOwnsLock());
while(listLength(server.ready_keys) != 0) {
serverAssert(GlobalLocksAcquired());
while(listLength(g_pserver->ready_keys) != 0) {
list *l;
/* Point server.ready_keys to a fresh list and save the current one
/* Point g_pserver->ready_keys to a fresh list and save the current one
* locally. This way as we run the old list we are free to call
* signalKeyAsReady() that may push new elements in server.ready_keys
* signalKeyAsReady() that may push new elements in g_pserver->ready_keys
* when handling clients blocked into BRPOPLPUSH. */
l = server.ready_keys;
server.ready_keys = listCreate();
l = g_pserver->ready_keys;
g_pserver->ready_keys = listCreate();
while(listLength(l) != 0) {
listNode *ln = listFirst(l);
readyList *rl = ln->value;
readyList *rl = (readyList*)ln->value;
/* First of all remove this key from db->ready_keys so that
* we can safely call signalKeyAsReady() against this key. */
dictDelete(rl->db->ready_keys,rl->key);
/* Even if we are not inside call(), increment the call depth
* in order to make sure that keys are expired against a fixed
* reference time, and not against the wallclock time. This
* way we can lookup an object multiple times (BRPOPLPUSH does
* that) without the risk of it being freed in the second
* lookup, invalidating the first one.
* See https://github.com/antirez/redis/pull/6554. */
serverTL->fixed_time_expire++;
updateCachedTime(0);
/* Serve clients blocked on list key. */
robj *o = lookupKeyWrite(rl->db,rl->key);
if (o != NULL && o->type == OBJ_LIST) {
dictEntry *de;
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
de = dictFind(rl->db->blocking_keys,rl->key);
if (de) {
list *clients = dictGetVal(de);
int numclients = listLength(clients);
while(numclients--) {
listNode *clientnode = listFirst(clients);
client *receiver = clientnode->value;
if (receiver->btype != BLOCKED_LIST) {
/* Put at the tail, so that at the next call
* we'll not run into it again. */
listDelNode(clients,clientnode);
listAddNodeTail(clients,receiver);
continue;
}
robj *dstkey = receiver->bpop.target;
int where = (receiver->lastcmd &&
receiver->lastcmd->proc == blpopCommand) ?
LIST_HEAD : LIST_TAIL;
robj *value = listTypePop(o,where);
if (value) {
/* Protect receiver->bpop.target, that will be
* freed by the next unblockClient()
* call. */
if (dstkey) incrRefCount(dstkey);
fastlock_lock(&receiver->lock);
unblockClient(receiver);
if (serveClientBlockedOnList(receiver,
rl->key,dstkey,rl->db,value,
where) == C_ERR)
{
/* If we failed serving the client we need
* to also undo the POP operation. */
listTypePush(o,value,where);
}
if (dstkey) decrRefCount(dstkey);
fastlock_unlock(&receiver->lock);
decrRefCount(value);
} else {
break;
}
}
}
if (listTypeLength(o) == 0) {
dbDelete(rl->db,rl->key);
notifyKeyspaceEvent(NOTIFY_GENERIC,"del",rl->key,rl->db->id);
}
/* We don't call signalModifiedKey() as it was already called
* when an element was pushed on the list. */
}
/* Serve clients blocked on sorted set key. */
else if (o != NULL && o->type == OBJ_ZSET) {
dictEntry *de;
/* We serve clients in the same order they blocked for
* this key, from the first blocked to the last. */
de = dictFind(rl->db->blocking_keys,rl->key);
if (de) {
list *clients = dictGetVal(de);
int numclients = listLength(clients);
unsigned long zcard = zsetLength(o);
while(numclients-- && zcard) {
listNode *clientnode = listFirst(clients);
client *receiver = clientnode->value;
if (receiver->btype != BLOCKED_ZSET) {
/* Put at the tail, so that at the next call
* we'll not run into it again. */
listDelNode(clients,clientnode);
listAddNodeTail(clients,receiver);
continue;
}
fastlock_lock(&receiver->lock);
int where = (receiver->lastcmd &&
receiver->lastcmd->proc == bzpopminCommand)
? ZSET_MIN : ZSET_MAX;
unblockClient(receiver);
genericZpopCommand(receiver,&rl->key,1,where,1,NULL);
zcard--;
/* Replicate the command. */
robj *argv[2];
struct redisCommand *cmd = where == ZSET_MIN ?
server.zpopminCommand :
server.zpopmaxCommand;
argv[0] = createStringObject(cmd->name,strlen(cmd->name));
argv[1] = rl->key;
incrRefCount(rl->key);
propagate(cmd,receiver->db->id,
argv,2,PROPAGATE_AOF|PROPAGATE_REPL);
fastlock_unlock(&receiver->lock);
decrRefCount(argv[0]);
decrRefCount(argv[1]);
}
}
}
/* Serve clients blocked on stream key. */
else if (o != NULL && o->type == OBJ_STREAM) {
dictEntry *de = dictFind(rl->db->blocking_keys,rl->key);
stream *s = ptrFromObj(o);
/* We need to provide the new data arrived on the stream
* to all the clients that are waiting for an offset smaller
* than the current top item. */
if (de) {
list *clients = dictGetVal(de);
listNode *ln;
listIter li;
listRewind(clients,&li);
while((ln = listNext(&li))) {
client *receiver = listNodeValue(ln);
if (receiver->btype != BLOCKED_STREAM) continue;
streamID *gt = dictFetchValue(receiver->bpop.keys,
rl->key);
/* If we blocked in the context of a consumer
* group, we need to resolve the group and update the
* last ID the client is blocked for: this is needed
* because serving other clients in the same consumer
* group will alter the "last ID" of the consumer
* group, and clients blocked in a consumer group are
* always blocked for the ">" ID: we need to deliver
* only new messages and avoid unblocking the client
* otherwise. */
streamCG *group = NULL;
if (receiver->bpop.xread_group) {
group = streamLookupCG(s,
ptrFromObj(receiver->bpop.xread_group));
/* If the group was not found, send an error
* to the consumer. */
if (!group) {
fastlock_lock(&receiver->lock);
addReplyErrorAsync(receiver,
"-NOGROUP the consumer group this client "
"was blocked on no longer exists");
unblockClient(receiver);
fastlock_unlock(&receiver->lock);
continue;
} else {
*gt = group->last_id;
}
}
if (streamCompareID(&s->last_id, gt) > 0) {
streamID start = *gt;
start.seq++; /* Can't overflow, it's an uint64_t */
/* Lookup the consumer for the group, if any. */
streamConsumer *consumer = NULL;
int noack = 0;
if (group) {
consumer = streamLookupConsumer(group,
ptrFromObj(receiver->bpop.xread_consumer),
1);
noack = receiver->bpop.xread_group_noack;
}
fastlock_lock(&receiver->lock);
/* Emit the two elements sub-array consisting of
* the name of the stream and the data we
* extracted from it. Wrapped in a single-item
* array, since we have just one key. */
if (receiver->resp == 2) {
addReplyArrayLenAsync(receiver,1);
addReplyArrayLenAsync(receiver,2);
} else {
addReplyMapLenAsync(receiver,1);
}
addReplyBulkAsync(receiver,rl->key);
streamPropInfo pi = {
rl->key,
receiver->bpop.xread_group
};
streamReplyWithRange(receiver,s,&start,NULL,
receiver->bpop.xread_count,
0, group, consumer, noack, &pi);
/* Note that after we unblock the client, 'gt'
* and other receiver->bpop stuff are no longer
* valid, so we must do the setup above before
* this call. */
unblockClient(receiver);
fastlock_unlock(&receiver->lock);
}
}
}
if (o != NULL) {
if (o->type == OBJ_LIST)
serveClientsBlockedOnListKey(o,rl);
else if (o->type == OBJ_ZSET)
serveClientsBlockedOnSortedSetKey(o,rl);
else if (o->type == OBJ_STREAM)
serveClientsBlockedOnStreamKey(o,rl);
/* We want to serve clients blocked on module keys
* regardless of the object type: we don't know what the
* module is trying to accomplish right now. */
serveClientsBlockedOnKeyByModule(rl);
}
serverTL->fixed_time_expire--;
/* Free this item. */
decrRefCount(rl->key);
@@ -535,17 +586,15 @@ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeo
if (target != NULL) incrRefCount(target);
for (j = 0; j < numkeys; j++) {
/* The value associated with the key name in the bpop.keys dictionary
* is NULL for lists and sorted sets, or the stream ID for streams. */
void *key_data = NULL;
if (btype == BLOCKED_STREAM) {
key_data = zmalloc(sizeof(streamID), MALLOC_SHARED);
memcpy(key_data,ids+j,sizeof(streamID));
}
/* Allocate our bkinfo structure, associated to each key the client
* is blocked for. */
bkinfo *bki = (bkinfo*)zmalloc(sizeof(*bki));
if (btype == BLOCKED_STREAM)
bki->stream_id = ids[j];
/* If the key already exists in the dictionary ignore it. */
if (dictAdd(c->bpop.keys,keys[j],key_data) != DICT_OK) {
zfree(key_data);
if (dictAdd(c->bpop.keys,keys[j],bki) != DICT_OK) {
zfree(bki);
continue;
}
incrRefCount(keys[j]);
@@ -561,9 +610,10 @@ void blockForKeys(client *c, int btype, robj **keys, int numkeys, mstime_t timeo
incrRefCount(keys[j]);
serverAssertWithInfo(c,keys[j],retval == DICT_OK);
} else {
l = dictGetVal(de);
l = (list*)dictGetVal(de);
}
listAddNodeTail(l,c);
bki->listnode = listLast(l);
}
blockClient(c,btype);
}
@@ -579,12 +629,13 @@ void unblockClientWaitingData(client *c) {
di = dictGetIterator(c->bpop.keys);
/* The client may wait for multiple keys, so unblock it for every key. */
while((de = dictNext(di)) != NULL) {
robj *key = dictGetKey(de);
robj *key = (robj*)dictGetKey(de);
bkinfo *bki = (bkinfo*)dictGetVal(de);
/* Remove this client from the list of clients waiting for this key. */
l = dictFetchValue(c->db->blocking_keys,key);
l = (list*)dictFetchValue(c->db->blocking_keys,key);
serverAssertWithInfo(c,key,l != NULL);
listDelNode(l,listSearchKey(l,c));
listDelNode(l,bki->listnode);
/* If the list is empty we need to remove it to avoid wasting memory */
if (listLength(l) == 0)
dictDelete(c->db->blocking_keys,key);
@@ -606,12 +657,12 @@ void unblockClientWaitingData(client *c) {
}
/* If the specified key has clients blocked waiting for list pushes, this
* function will put the key reference into the server.ready_keys list.
* function will put the key reference into the g_pserver->ready_keys list.
* Note that db->ready_keys is a hash table that allows us to avoid putting
* the same key again and again in the list in case of multiple pushes
* made by a script or in the context of MULTI/EXEC.
*
* The list will be finally processed by handleClientsBlockedOnLists() */
* The list will be finally processed by handleClientsBlockedOnKeys() */
void signalKeyAsReady(redisDb *db, robj *key) {
readyList *rl;
@@ -621,12 +672,12 @@ void signalKeyAsReady(redisDb *db, robj *key) {
/* Key was already signaled? No need to queue it again. */
if (dictFind(db->ready_keys,key) != NULL) return;
/* Ok, we need to queue this key into server.ready_keys. */
rl = zmalloc(sizeof(*rl), MALLOC_SHARED);
/* Ok, we need to queue this key into g_pserver->ready_keys. */
rl = (readyList*)zmalloc(sizeof(*rl), MALLOC_SHARED);
rl->key = key;
rl->db = db;
incrRefCount(key);
listAddNodeTail(server.ready_keys,rl);
listAddNodeTail(g_pserver->ready_keys,rl);
/* We also add the key in the db->ready_keys dictionary in order
* to avoid adding it multiple times into a list with a simple O(1)
+24 -22
View File
@@ -34,52 +34,54 @@
* RDB / AOF saving process from the child to the parent (for instance
* the amount of copy on write memory used) */
void openChildInfoPipe(void) {
if (pipe(server.child_info_pipe) == -1) {
if (pipe(g_pserver->child_info_pipe) == -1) {
/* On error our two file descriptors should be still set to -1,
* but we call anyway cloesChildInfoPipe() since can't hurt. */
closeChildInfoPipe();
} else if (anetNonBlock(NULL,server.child_info_pipe[0]) != ANET_OK) {
} else if (anetNonBlock(NULL,g_pserver->child_info_pipe[0]) != ANET_OK) {
closeChildInfoPipe();
} else {
memset(&server.child_info_data,0,sizeof(server.child_info_data));
memset(&g_pserver->child_info_data,0,sizeof(g_pserver->child_info_data));
}
}
/* Close the pipes opened with openChildInfoPipe(). */
void closeChildInfoPipe(void) {
if (server.child_info_pipe[0] != -1 ||
server.child_info_pipe[1] != -1)
if (g_pserver->child_info_pipe[0] != -1 ||
g_pserver->child_info_pipe[1] != -1)
{
close(server.child_info_pipe[0]);
close(server.child_info_pipe[1]);
server.child_info_pipe[0] = -1;
server.child_info_pipe[1] = -1;
close(g_pserver->child_info_pipe[0]);
close(g_pserver->child_info_pipe[1]);
g_pserver->child_info_pipe[0] = -1;
g_pserver->child_info_pipe[1] = -1;
}
}
/* Send COW data to parent. The child should call this function after populating
* the corresponding fields it want to sent (according to the process type). */
void sendChildInfo(int ptype) {
if (server.child_info_pipe[1] == -1) return;
server.child_info_data.magic = CHILD_INFO_MAGIC;
server.child_info_data.process_type = ptype;
ssize_t wlen = sizeof(server.child_info_data);
if (write(server.child_info_pipe[1],&server.child_info_data,wlen) != wlen) {
if (g_pserver->child_info_pipe[1] == -1) return;
g_pserver->child_info_data.magic = CHILD_INFO_MAGIC;
g_pserver->child_info_data.process_type = ptype;
ssize_t wlen = sizeof(g_pserver->child_info_data);
if (write(g_pserver->child_info_pipe[1],&g_pserver->child_info_data,wlen) != wlen) {
/* Nothing to do on error, this will be detected by the other side. */
}
}
/* Receive COW data from parent. */
void receiveChildInfo(void) {
if (server.child_info_pipe[0] == -1) return;
ssize_t wlen = sizeof(server.child_info_data);
if (read(server.child_info_pipe[0],&server.child_info_data,wlen) == wlen &&
server.child_info_data.magic == CHILD_INFO_MAGIC)
if (g_pserver->child_info_pipe[0] == -1) return;
ssize_t wlen = sizeof(g_pserver->child_info_data);
if (read(g_pserver->child_info_pipe[0],&g_pserver->child_info_data,wlen) == wlen &&
g_pserver->child_info_data.magic == CHILD_INFO_MAGIC)
{
if (server.child_info_data.process_type == CHILD_INFO_TYPE_RDB) {
server.stat_rdb_cow_bytes = server.child_info_data.cow_size;
} else if (server.child_info_data.process_type == CHILD_INFO_TYPE_AOF) {
server.stat_aof_cow_bytes = server.child_info_data.cow_size;
if (g_pserver->child_info_data.process_type == CHILD_INFO_TYPE_RDB) {
g_pserver->stat_rdb_cow_bytes = g_pserver->child_info_data.cow_size;
} else if (g_pserver->child_info_data.process_type == CHILD_INFO_TYPE_AOF) {
g_pserver->stat_aof_cow_bytes = g_pserver->child_info_data.cow_size;
} else if (g_pserver->child_info_data.process_type == CHILD_INFO_TYPE_MODULE) {
g_pserver->stat_module_cow_bytes = g_pserver->child_info_data.cow_size;
}
}
}
File diff suppressed because it is too large. Load diff
+3 -6
View File
@@ -17,15 +17,10 @@ extern "C" {
/* The following defines are amount of time, sometimes expressed as
* multiplicators of the node timeout value (when ending with MULT). */
#define CLUSTER_DEFAULT_NODE_TIMEOUT 15000
#define CLUSTER_DEFAULT_SLAVE_VALIDITY 10 /* Slave max data age factor. */
#define CLUSTER_DEFAULT_REQUIRE_FULL_COVERAGE 1
#define CLUSTER_DEFAULT_SLAVE_NO_FAILOVER 0 /* Failover by default. */
#define CLUSTER_FAIL_REPORT_VALIDITY_MULT 2 /* Fail report validity. */
#define CLUSTER_FAIL_UNDO_TIME_MULT 2 /* Undo fail if master is back. */
#define CLUSTER_FAIL_UNDO_TIME_ADD 10 /* Some additional time. */
#define CLUSTER_FAILOVER_DELAY 5 /* Seconds */
#define CLUSTER_DEFAULT_MIGRATION_BARRIER 1
#define CLUSTER_MF_TIMEOUT 5000 /* Milliseconds to do a manual failover. */
#define CLUSTER_MF_PAUSE_MULT 2 /* Master pause manual failover mult. */
#define CLUSTER_SLAVE_MIGRATION_DELAY 5000 /* Delay for slave migration. */
@@ -38,13 +33,14 @@ extern "C" {
#define CLUSTER_REDIR_MOVED 4 /* -MOVED redirection required. */
#define CLUSTER_REDIR_DOWN_STATE 5 /* -CLUSTERDOWN, global state. */
#define CLUSTER_REDIR_DOWN_UNBOUND 6 /* -CLUSTERDOWN, unbound slot. */
#define CLUSTER_REDIR_DOWN_RO_STATE 7 /* -CLUSTERDOWN, allow reads. */
struct clusterNode;
/* clusterLink encapsulates everything needed to talk with a remote node. */
typedef struct clusterLink {
mstime_t ctime; /* Link creation time */
int fd; /* TCP socket file descriptor */
connection *conn; /* Connection to remote node */
sds sndbuf; /* Packet send buffer */
sds rcvbuf; /* Packet reception buffer */
struct clusterNode *node; /* Node related to this link if any, or NULL */
@@ -132,6 +128,7 @@ typedef struct clusterNode {
tables. */
mstime_t ping_sent; /* Unix time we sent latest ping */
mstime_t pong_received; /* Unix time we received the pong */
mstime_t data_received; /* Unix time we received any data */
mstime_t fail_time; /* Unix time when FAIL flag was set */
mstime_t voted_time; /* Last time we voted for a slave of this master */
mstime_t repl_offset_time; /* Unix time we received offset for this node */
+153
View File
@@ -0,0 +1,153 @@
#pragma once
#include <type_traits>
#include <assert.h>
/*************************************************
* compactvector - similar to std::vector but optimized for minimal memory
*
* Notable differences:
* - Limited to 2^32 elements
* - Grows linearly not exponentially
*
*************************************************/
template<typename T, bool MEMMOVE_SAFE=false>
class compactvector
{
static_assert(MEMMOVE_SAFE || std::is_trivially_copyable<T>::value, "compactvector requires trivially copyable types");
T *m_data = nullptr;
unsigned m_celem = 0;
unsigned m_max = 0;
public:
typedef T* iterator;
compactvector() noexcept = default;
~compactvector() noexcept
{
clear(); // call dtors
zfree(m_data);
}
compactvector(compactvector &) noexcept = delete;
compactvector(compactvector &&src) noexcept
{
m_data = src.m_data;
m_celem = src.m_celem;
m_max = src.m_max;
src.m_data = nullptr;
src.m_celem = 0;
src.m_max = 0;
}
compactvector &operator=(const compactvector&) noexcept = delete;
compactvector &operator=(compactvector &&src) noexcept
{
zfree(m_data);
m_data = src.m_data;
m_celem = src.m_celem;
m_max = src.m_max;
src.m_data = nullptr;
src.m_celem = 0;
src.m_max = 0;
return *this;
}
inline T* begin() { return m_data; }
inline const T* begin() const { return m_data; }
inline T* end() { return m_data + m_celem; }
inline const T* end() const { return m_data + m_celem; }
T* insert(T* where, T &val)
{
assert(where >= m_data);
size_t idx = where - m_data;
if (m_celem >= m_max)
{
if (m_max < 2)
m_max = 2;
else
m_max = m_max + 4;
m_data = (T*)zrealloc(m_data, sizeof(T) * m_max, MALLOC_LOCAL);
m_max = zmalloc_usable(m_data) / sizeof(T);
}
assert(idx < m_max);
where = m_data + idx;
memmove(reinterpret_cast<void*>(m_data + idx + 1), reinterpret_cast<const void*>(m_data + idx), (m_celem - idx)*sizeof(T));
new(m_data + idx) T(std::move(val));
++m_celem;
return where;
}
T &operator[](size_t idx)
{
assert(idx < m_celem);
return m_data[idx];
}
const T &operator[](size_t idx) const
{
assert(idx < m_celem);
return m_data[idx];
}
T& back() { assert(m_celem > 0); return m_data[m_celem-1]; }
const T& back() const { assert(m_celem > 0); return m_data[m_celem-1]; }
void erase(T* where)
{
assert(where >= m_data);
size_t idx = where - m_data;
assert(idx < m_celem);
where->~T();
memmove(reinterpret_cast<void*>(where), reinterpret_cast<const void*>(where+1), ((m_celem - idx - 1)*sizeof(T)));
--m_celem;
if (m_celem == 0)
{
zfree(m_data);
m_data = nullptr;
m_max = 0;
}
}
void shrink_to_fit()
{
if (m_max == m_celem)
return;
m_data = (T*)zrealloc(m_data, sizeof(T) * m_celem, MALLOC_LOCAL);
m_max = m_celem; // NOTE: We do not get the usable size here, because this could cause us to continually realloc
}
size_t bytes_used() const
{
return sizeof(this) + (m_max * sizeof(T));
}
void clear()
{
for (size_t idx = 0; idx < m_celem; ++idx)
m_data[idx].~T();
zfree(m_data);
m_data = nullptr;
m_celem = 0;
m_max = 0;
}
bool empty() const noexcept
{
return m_celem == 0;
}
size_t size() const noexcept
{
return m_celem;
}
T* data() noexcept { return m_data; }
const T* data() const noexcept { return m_data; }
};
static_assert(sizeof(compactvector<void*>) <= 16, "not compact");
-2408
View File
File diff suppressed because it is too large. Load diff
+2379
View File
File diff suppressed because it is too large. Load diff
+39
View File
@@ -126,8 +126,14 @@
#if ((defined __linux && defined(__GLIBC__)) || defined __APPLE__)
#define USE_SETPROCTITLE
#define INIT_SETPROCTITLE_REPLACEMENT
#ifdef __cplusplus
extern "C" {
#endif
void spt_init(int argc, char *argv[]);
void setproctitle(const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif
/* Byte ordering detection */
@@ -226,4 +232,37 @@ void setproctitle(const char *fmt, ...);
#define USE_ALIGNED_ACCESS
#endif
/* Define for redis_set_thread_title */
#ifdef __linux__
#define redis_set_thread_title(name) pthread_setname_np(pthread_self(), name)
#else
#if (defined __FreeBSD__ || defined __OpenBSD__)
#include <pthread_np.h>
#define redis_set_thread_title(name) pthread_set_name_np(pthread_self(), name)
#elif defined __NetBSD__
#include <pthread.h>
#define redis_set_thread_title(name) pthread_setname_np(pthread_self(), name, NULL)
#else
#if (defined __APPLE__ && defined(MAC_OS_X_VERSION_10_7))
#ifdef __cplusplus
extern "C"
#endif
int pthread_setname_np(const char *name);
#include <pthread.h>
#define redis_set_thread_title(name) pthread_setname_np(name)
#else
#define redis_set_thread_title(name)
#endif
#endif
#endif
/* Check if we can use setcpuaffinity(). */
#if (defined __linux || defined __NetBSD__ || defined __FreeBSD__)
#define USE_SETCPUAFFINITY
#ifdef __cplusplus
extern "C"
#endif
void setcpuaffinity(const char *cpulist);
#endif
#endif
+431
View File
@@ -0,0 +1,431 @@
/*
* Copyright (c) 2019, Redis Labs
* 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 "server.h"
#include "connhelpers.h"
/* The connections module provides a lean abstraction of network connections
* to avoid direct socket and async event management across the Redis code base.
*
* It does NOT provide advanced connection features commonly found in similar
* libraries such as complete in/out buffer management, throttling, etc. These
* functions remain in networking.c.
*
* The primary goal is to allow transparent handling of TCP and TLS based
* connections. To do so, connections have the following properties:
*
* 1. A connection may live before its corresponding socket exists. This
* allows various context and configuration setting to be handled before
* establishing the actual connection.
* 2. The caller may register/unregister logical read/write handlers to be
* called when the connection has data to read from/can accept writes.
* These logical handlers may or may not correspond to actual AE events,
* depending on the implementation (for TCP they are; for TLS they aren't).
*/
extern ConnectionType CT_Socket;
/* When a connection is created we must know its type already, but the
* underlying socket may or may not exist:
*
* - For accepted connections, it exists as we do not model the listen/accept
* part; So caller calls connCreateSocket() followed by connAccept().
* - For outgoing connections, the socket is created by the connection module
* itself; So caller calls connCreateSocket() followed by connConnect(),
* which registers a connect callback that fires on connected/error state
* (and after any transport level handshake was done).
*
* NOTE: An earlier version relied on connections being part of other structs
* and not independently allocated. This could lead to further optimizations
* like using container_of(), etc. However it was discontinued in favor of
* this approach for these reasons:
*
* 1. In some cases conns are created/handled outside the context of the
* containing struct, in which case it gets a bit awkward to copy them.
* 2. Future implementations may wish to allocate arbitrary data for the
* connection.
* 3. The container_of() approach is anyway risky because connections may
* be embedded in different structs, not just client.
*/
connection *connCreateSocket() {
connection *conn = (connection*)zcalloc(sizeof(connection), MALLOC_LOCAL);
conn->type = &CT_Socket;
conn->fd = -1;
return conn;
}
/* Create a new socket-type connection that is already associated with
* an accepted connection.
*
* The socket is not read for I/O until connAccept() was called and
* invoked the connection-level accept handler.
*/
connection *connCreateAcceptedSocket(int fd) {
connection *conn = connCreateSocket();
conn->fd = fd;
conn->state = CONN_STATE_ACCEPTING;
return conn;
}
static int connSocketConnect(connection *conn, const char *addr, int port, const char *src_addr,
ConnectionCallbackFunc connect_handler) {
int fd = anetTcpNonBlockBestEffortBindConnect(NULL,addr,port,src_addr);
if (fd == -1) {
conn->state = CONN_STATE_ERROR;
conn->last_errno = errno;
return C_ERR;
}
conn->fd = fd;
conn->state = CONN_STATE_CONNECTING;
conn->conn_handler = connect_handler;
aeCreateFileEvent(serverTL->el, conn->fd, AE_WRITABLE,
conn->type->ae_handler, conn);
return C_OK;
}
/* Returns true if a write handler is registered */
int connHasWriteHandler(connection *conn) {
return conn->write_handler != NULL;
}
/* Returns true if a read handler is registered */
int connHasReadHandler(connection *conn) {
return conn->read_handler != NULL;
}
/* Associate a private data pointer with the connection */
void connSetPrivateData(connection *conn, void *data) {
conn->private_data = data;
}
/* Get the associated private data pointer */
void *connGetPrivateData(connection *conn) {
return conn->private_data;
}
/* ------ Pure socket connections ------- */
/* A very incomplete list of implementation-specific calls. Much of the above shall
* move here as we implement additional connection types.
*/
/* Close the connection and free resources. */
static void connSocketClose(connection *conn) {
if (conn->fd != -1) {
aeDeleteFileEvent(serverTL->el,conn->fd,AE_READABLE);
aeDeleteFileEvent(serverTL->el,conn->fd,AE_WRITABLE);
close(conn->fd);
conn->fd = -1;
}
/* If called from within a handler, schedule the close but
* keep the connection until the handler returns.
*/
if (connHasRefs(conn)) {
conn->flags |= CONN_FLAG_CLOSE_SCHEDULED;
return;
}
zfree(conn);
}
static int connSocketWrite(connection *conn, const void *data, size_t data_len) {
int ret = write(conn->fd, data, data_len);
if (ret < 0 && errno != EAGAIN) {
conn->last_errno = errno;
conn->state = CONN_STATE_ERROR;
}
return ret;
}
static int connSocketRead(connection *conn, void *buf, size_t buf_len) {
int ret = read(conn->fd, buf, buf_len);
if (!ret) {
conn->state = CONN_STATE_CLOSED;
} else if (ret < 0 && errno != EAGAIN) {
conn->last_errno = errno;
conn->state = CONN_STATE_ERROR;
}
return ret;
}
static int connSocketAccept(connection *conn, ConnectionCallbackFunc accept_handler) {
int ret = C_OK;
if (conn->state != CONN_STATE_ACCEPTING) return C_ERR;
conn->state = CONN_STATE_CONNECTED;
connIncrRefs(conn);
if (!callHandler(conn, accept_handler)) ret = C_ERR;
connDecrRefs(conn);
return ret;
}
/* Register a write handler, to be called when the connection is writable.
* If NULL, the existing handler is removed.
*
* The barrier flag indicates a write barrier is requested, resulting with
* CONN_FLAG_WRITE_BARRIER set. This will ensure that the write handler is
* always called before and not after the read handler in a single event
* loop.
*/
static int connSocketSetWriteHandler(connection *conn, ConnectionCallbackFunc func, int barrier, bool fThreadSafe) {
if (func == conn->write_handler) return C_OK;
conn->write_handler = func;
if (barrier)
conn->flags |= CONN_FLAG_WRITE_BARRIER;
else
conn->flags &= ~CONN_FLAG_WRITE_BARRIER;
int flags = AE_WRITABLE;
if (fThreadSafe)
flags |= AE_WRITE_THREADSAFE;
if (!conn->write_handler)
aeDeleteFileEvent(serverTL->el,conn->fd,AE_WRITABLE);
else
if (aeCreateFileEvent(serverTL->el,conn->fd,flags,
conn->type->ae_handler,conn) == AE_ERR) return C_ERR;
return C_OK;
}
/* Register a read handler, to be called when the connection is readable.
* If NULL, the existing handler is removed.
*/
static int connSocketSetReadHandler(connection *conn, ConnectionCallbackFunc func, bool fThreadSafe) {
if (func == conn->read_handler) return C_OK;
int flags = AE_READABLE;
if (fThreadSafe)
flags |= AE_READ_THREADSAFE;
conn->read_handler = func;
if (!conn->read_handler)
aeDeleteFileEvent(serverTL->el,conn->fd,AE_READABLE);
else
if (aeCreateFileEvent(serverTL->el,conn->fd,
flags,conn->type->ae_handler,conn) == AE_ERR) return C_ERR;
return C_OK;
}
static const char *connSocketGetLastError(connection *conn) {
return strerror(conn->last_errno);
}
static void connSocketEventHandler(struct aeEventLoop *el, int fd, void *clientData, int mask)
{
UNUSED(el);
UNUSED(fd);
connection *conn = (connection*)clientData;
if (conn->state == CONN_STATE_CONNECTING &&
(mask & AE_WRITABLE) && conn->conn_handler) {
if (connGetSocketError(conn)) {
conn->last_errno = errno;
conn->state = CONN_STATE_ERROR;
} else {
conn->state = CONN_STATE_CONNECTED;
}
if (!conn->write_handler) aeDeleteFileEvent(serverTL->el,conn->fd,AE_WRITABLE);
if (!callHandler(conn, conn->conn_handler)) return;
conn->conn_handler = NULL;
}
/* Normally we execute the readable event first, and the writable
* event later. This is useful as sometimes we may be able
* to serve the reply of a query immediately after processing the
* query.
*
* However if WRITE_BARRIER is set in the mask, our application is
* asking us to do the reverse: never fire the writable event
* after the readable. In such a case, we invert the calls.
* This is useful when, for instance, we want to do things
* in the beforeSleep() hook, like fsync'ing a file to disk,
* before replying to a client. */
int invert = conn->flags & CONN_FLAG_WRITE_BARRIER;
int call_write = (mask & AE_WRITABLE) && conn->write_handler;
int call_read = (mask & AE_READABLE) && conn->read_handler;
/* Handle normal I/O flows */
if (!invert && call_read) {
if (!callHandler(conn, conn->read_handler)) return;
}
/* Fire the writable event. */
if (call_write) {
if (!callHandler(conn, conn->write_handler)) return;
}
/* If we have to invert the call, fire the readable event now
* after the writable one. */
if (invert && call_read) {
if (!callHandler(conn, conn->read_handler)) return;
}
}
static int connSocketBlockingConnect(connection *conn, const char *addr, int port, long long timeout) {
int fd = anetTcpNonBlockConnect(NULL,addr,port);
if (fd == -1) {
conn->state = CONN_STATE_ERROR;
conn->last_errno = errno;
return C_ERR;
}
if ((aeWait(fd, AE_WRITABLE, timeout) & AE_WRITABLE) == 0) {
conn->state = CONN_STATE_ERROR;
conn->last_errno = ETIMEDOUT;
}
conn->fd = fd;
conn->state = CONN_STATE_CONNECTED;
return C_OK;
}
/* Connection-based versions of syncio.c functions.
* NOTE: This should ideally be refactored out in favor of pure async work.
*/
static ssize_t connSocketSyncWrite(connection *conn, const char *ptr, ssize_t size, long long timeout) {
return syncWrite(conn->fd, ptr, size, timeout);
}
static ssize_t connSocketSyncRead(connection *conn, char *ptr, ssize_t size, long long timeout) {
return syncRead(conn->fd, ptr, size, timeout);
}
static ssize_t connSocketSyncReadLine(connection *conn, char *ptr, ssize_t size, long long timeout) {
return syncReadLine(conn->fd, ptr, size, timeout);
}
ConnectionType CT_Socket = {
connSocketEventHandler,
connSocketConnect,
connSocketWrite,
connSocketRead,
connSocketClose,
connSocketAccept,
connSocketSetWriteHandler,
connSocketSetReadHandler,
connSocketGetLastError,
connSocketBlockingConnect,
connSocketSyncWrite,
connSocketSyncRead,
connSocketSyncReadLine
};
int connGetSocketError(connection *conn) {
int sockerr = 0;
socklen_t errlen = sizeof(sockerr);
if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &sockerr, &errlen) == -1)
sockerr = errno;
return sockerr;
}
int connPeerToString(connection *conn, char *ip, size_t ip_len, int *port) {
return anetPeerToString(conn ? conn->fd : -1, ip, ip_len, port);
}
int connFormatPeer(connection *conn, char *buf, size_t buf_len) {
return anetFormatPeer(conn ? conn->fd : -1, buf, buf_len);
}
int connSockName(connection *conn, char *ip, size_t ip_len, int *port) {
return anetSockName(conn->fd, ip, ip_len, port);
}
int connBlock(connection *conn) {
if (conn->fd == -1) return C_ERR;
return anetBlock(NULL, conn->fd);
}
int connNonBlock(connection *conn) {
if (conn->fd == -1) return C_ERR;
return anetNonBlock(NULL, conn->fd);
}
int connEnableTcpNoDelay(connection *conn) {
if (conn->fd == -1) return C_ERR;
return anetEnableTcpNoDelay(NULL, conn->fd);
}
int connDisableTcpNoDelay(connection *conn) {
if (conn->fd == -1) return C_ERR;
return anetDisableTcpNoDelay(NULL, conn->fd);
}
int connKeepAlive(connection *conn, int interval) {
if (conn->fd == -1) return C_ERR;
return anetKeepAlive(NULL, conn->fd, interval);
}
int connSendTimeout(connection *conn, long long ms) {
return anetSendTimeout(NULL, conn->fd, ms);
}
int connRecvTimeout(connection *conn, long long ms) {
return anetRecvTimeout(NULL, conn->fd, ms);
}
int connGetState(connection *conn) {
return conn->state;
}
void connSetThreadAffinity(connection *conn, int cpu) {
#ifdef HAVE_SO_INCOMING_CPU
if (setsockopt(conn->fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, sizeof(cpu)) != 0)
{
serverLog(LL_WARNING, "Failed to set socket affinity");
}
#endif
}
/* Return a text that describes the connection, suitable for inclusion
* in CLIENT LIST and similar outputs.
*
* For sockets, we always return "fd=<fdnum>" to maintain compatibility.
*/
const char *connGetInfo(connection *conn, char *buf, size_t buf_len) {
snprintf(buf, buf_len-1, "fd=%i", conn->fd);
return buf;
}
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (c) 2019, Redis Labs
* 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 __REDIS_CONNECTION_H
#define __REDIS_CONNECTION_H
#include <atomic>
#define CONN_INFO_LEN 32
struct aeEventLoop;
typedef struct connection connection;
typedef enum {
CONN_STATE_NONE = 0,
CONN_STATE_CONNECTING,
CONN_STATE_ACCEPTING,
CONN_STATE_CONNECTED,
CONN_STATE_CLOSED,
CONN_STATE_ERROR
} ConnectionState;
#define CONN_FLAG_CLOSE_SCHEDULED (1<<0) /* Closed scheduled by a handler */
#define CONN_FLAG_WRITE_BARRIER (1<<1) /* Write barrier requested */
#define CONN_FLAG_READ_THREADSAFE (1<<2)
#define CONN_FLAG_WRITE_THREADSAFE (1<<3)
typedef void (*ConnectionCallbackFunc)(struct connection *conn);
typedef struct ConnectionType {
void (*ae_handler)(struct aeEventLoop *el, int fd, void *clientData, int mask);
int (*connect)(struct connection *conn, const char *addr, int port, const char *source_addr, ConnectionCallbackFunc connect_handler);
int (*write)(struct connection *conn, const void *data, size_t data_len);
int (*read)(struct connection *conn, void *buf, size_t buf_len);
void (*close)(struct connection *conn);
int (*accept)(struct connection *conn, ConnectionCallbackFunc accept_handler);
int (*set_write_handler)(struct connection *conn, ConnectionCallbackFunc handler, int barrier, bool fThreadSafe);
int (*set_read_handler)(struct connection *conn, ConnectionCallbackFunc handler, bool fThreadSafe);
const char *(*get_last_error)(struct connection *conn);
int (*blocking_connect)(struct connection *conn, const char *addr, int port, long long timeout);
ssize_t (*sync_write)(struct connection *conn, const char *ptr, ssize_t size, long long timeout);
ssize_t (*sync_read)(struct connection *conn, char *ptr, ssize_t size, long long timeout);
ssize_t (*sync_readline)(struct connection *conn, char *ptr, ssize_t size, long long timeout);
void (*marshal_thread)(struct connection *conn);
} ConnectionType;
struct connection {
ConnectionType *type;
std::atomic<ConnectionState> state;
short int flags;
short int refs;
int last_errno;
void *private_data;
ConnectionCallbackFunc conn_handler;
ConnectionCallbackFunc write_handler;
ConnectionCallbackFunc read_handler;
int fd;
};
/* The connection module does not deal with listening and accepting sockets,
* so we assume we have a socket when an incoming connection is created.
*
* The fd supplied should therefore be associated with an already accept()ed
* socket.
*
* connAccept() may directly call accept_handler(), or return and call it
* at a later time. This behavior is a bit awkward but aims to reduce the need
* to wait for the next event loop, if no additional handshake is required.
*
* IMPORTANT: accept_handler may decide to close the connection, calling connClose().
* To make this safe, the connection is only marked with CONN_FLAG_CLOSE_SCHEDULED
* in this case, and connAccept() returns with an error.
*
* connAccept() callers must always check the return value and on error (C_ERR)
* a connClose() must be called.
*/
static inline int connAccept(connection *conn, ConnectionCallbackFunc accept_handler) {
return conn->type->accept(conn, accept_handler);
}
/* Establish a connection. The connect_handler will be called when the connection
* is established, or if an error has occured.
*
* The connection handler will be responsible to set up any read/write handlers
* as needed.
*
* If C_ERR is returned, the operation failed and the connection handler shall
* not be expected.
*/
static inline int connConnect(connection *conn, const char *addr, int port, const char *src_addr,
ConnectionCallbackFunc connect_handler) {
return conn->type->connect(conn, addr, port, src_addr, connect_handler);
}
/* Blocking connect.
*
* NOTE: This is implemented in order to simplify the transition to the abstract
* connections, but should probably be refactored out of cluster.c and replication.c,
* in favor of a pure async implementation.
*/
static inline int connBlockingConnect(connection *conn, const char *addr, int port, long long timeout) {
return conn->type->blocking_connect(conn, addr, port, timeout);
}
/* Write to connection, behaves the same as write(2).
*
* Like write(2), a short write is possible. A -1 return indicates an error.
*
* The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
* connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
*/
static inline int connWrite(connection *conn, const void *data, size_t data_len) {
return conn->type->write(conn, data, data_len);
}
/* Read from the connection, behaves the same as read(2).
*
* Like read(2), a short read is possible. A return value of 0 will indicate the
* connection was closed, and -1 will indicate an error.
*
* The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
* connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
*/
static inline int connRead(connection *conn, void *buf, size_t buf_len) {
return conn->type->read(conn, buf, buf_len);
}
/* Register a write handler, to be called when the connection is writable.
* If NULL, the existing handler is removed.
*/
static inline int connSetWriteHandler(connection *conn, ConnectionCallbackFunc func, bool fThreadSafe = false) {
return conn->type->set_write_handler(conn, func, 0, fThreadSafe);
}
/* Register a read handler, to be called when the connection is readable.
* If NULL, the existing handler is removed.
*/
static inline int connSetReadHandler(connection *conn, ConnectionCallbackFunc func, bool fThreadSafe = false) {
return conn->type->set_read_handler(conn, func, fThreadSafe);
}
/* Set a write handler, and possibly enable a write barrier, this flag is
* cleared when write handler is changed or removed.
* With barroer enabled, we never fire the event if the read handler already
* fired in the same event loop iteration. Useful when you want to persist
* things to disk before sending replies, and want to do that in a group fashion. */
static inline int connSetWriteHandlerWithBarrier(connection *conn, ConnectionCallbackFunc func, int barrier, bool fThreadSafe = false) {
return conn->type->set_write_handler(conn, func, barrier, fThreadSafe);
}
static inline void connClose(connection *conn) {
conn->type->close(conn);
}
/* Returns the last error encountered by the connection, as a string. If no error,
* a NULL is returned.
*/
static inline const char *connGetLastError(connection *conn) {
return conn->type->get_last_error(conn);
}
static inline ssize_t connSyncWrite(connection *conn, const char *ptr, ssize_t size, long long timeout) {
return conn->type->sync_write(conn, ptr, size, timeout);
}
static inline ssize_t connSyncRead(connection *conn, char *ptr, ssize_t size, long long timeout) {
return conn->type->sync_read(conn, ptr, size, timeout);
}
static inline ssize_t connSyncReadLine(connection *conn, char *ptr, ssize_t size, long long timeout) {
return conn->type->sync_readline(conn, ptr, size, timeout);
}
static inline void connMarshalThread(connection *conn) {
if (conn->type->marshal_thread != nullptr)
conn->type->marshal_thread(conn);
}
connection *connCreateSocket();
connection *connCreateAcceptedSocket(int fd);
connection *connCreateTLS();
connection *connCreateAcceptedTLS(int fd, int require_auth);
void connSetPrivateData(connection *conn, void *data);
void *connGetPrivateData(connection *conn);
int connGetState(connection *conn);
int connHasWriteHandler(connection *conn);
int connHasReadHandler(connection *conn);
int connGetSocketError(connection *conn);
void connSetThreadAffinity(connection *conn, int cpu);
/* anet-style wrappers to conns */
int connBlock(connection *conn);
int connNonBlock(connection *conn);
int connEnableTcpNoDelay(connection *conn);
int connDisableTcpNoDelay(connection *conn);
int connKeepAlive(connection *conn, int interval);
int connSendTimeout(connection *conn, long long ms);
int connRecvTimeout(connection *conn, long long ms);
int connPeerToString(connection *conn, char *ip, size_t ip_len, int *port);
int connFormatPeer(connection *conn, char *buf, size_t buf_len);
int connSockName(connection *conn, char *ip, size_t ip_len, int *port);
const char *connGetInfo(connection *conn, char *buf, size_t buf_len);
/* Helpers for tls special considerations */
int tlsHasPendingData();
int tlsProcessPendingData();
#endif /* __REDIS_CONNECTION_H */
+88
View File
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2019, Redis Labs
* 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 __REDIS_CONNHELPERS_H
#define __REDIS_CONNHELPERS_H
#include "connection.h"
/* These are helper functions that are common to different connection
* implementations (currently sockets in connection.c and TLS in tls.c).
*
* Currently helpers implement the mechanisms for invoking connection
* handlers and tracking connection references, to allow safe destruction
* of connections from within a handler.
*/
/* Incremenet connection references.
*
* Inside a connection handler, we guarantee refs >= 1 so it is always
* safe to connClose().
*
* In other cases where we don't want to prematurely lose the connection,
* it can go beyond 1 as well; currently it is only done by connAccept().
*/
static inline void connIncrRefs(connection *conn) {
conn->refs++;
}
/* Decrement connection references.
*
* Note that this is not intended to provide any automatic free logic!
* callHandler() takes care of that for the common flows, and anywhere an
* explicit connIncrRefs() is used, the caller is expected to take care of
* that.
*/
static inline void connDecrRefs(connection *conn) {
conn->refs--;
}
static inline int connHasRefs(connection *conn) {
return conn->refs;
}
/* Helper for connection implementations to call handlers:
* 1. Increment refs to protect the connection.
* 2. Execute the handler (if set).
* 3. Decrement refs and perform deferred close, if refs==0.
*/
static inline int callHandler(connection *conn, ConnectionCallbackFunc handler) {
connIncrRefs(conn);
if (handler) handler(conn);
connDecrRefs(conn);
if (conn->flags & CONN_FLAG_CLOSE_SCHEDULED) {
if (!connHasRefs(conn)) connClose(conn);
return 0;
}
return 1;
}
#endif /* __REDIS_CONNHELPERS_H */
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -1,5 +1,3 @@
#include "server.h"
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style)
@@ -29,6 +27,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>
/* CRC16 implementation according to CCITT standards.
*
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
+835
View File
@@ -0,0 +1,835 @@
#ifndef _CRC16_TABLE_H__
#define _CRC16_TABLE_H__
/* A table of the shortest possible alphanumeric string that is mapped by redis' crc16
* to any given redis cluster slot.
*
* The array indexes are slot numbers, so that given a desired slot, this string is guaranteed
* to make redis cluster route a request to the shard holding this slot
*/
const char *crc16_slot_table[] = {
"06S", "Qi", "5L5", "4Iu", "4gY", "460", "1Y7", "1LV", "0QG", "ru", "7Ok", "4ji", "4DE", "65n", "2JH", "I8", "F9", "SX", "7nF", "4KD",
"4eh", "6PK", "2ke", "1Ng", "0Sv", "4L", "491", "4hX", "4Ft", "5C4", "2Hy", "09R", "021", "0cX", "4Xv", "6mU", "6Cy", "42R", "0Mt", "nF",
"cv", "1Pe", "5kK", "6NI", "74L", "4UF", "0nh", "MZ", "2TJ", "0ai", "4ZG", "6od", "6AH", "40c", "0OE", "lw", "aG", "0Bu", "5iz", "6Lx",
"5R7", "4Ww", "0lY", "Ok", "5n3", "4ks", "8YE", "7g", "2KR", "1nP", "714", "64t", "69D", "4Ho", "07I", "Ps", "2hN", "1ML", "4fC", "7CA",
"avs", "4iB", "0Rl", "5V", "2Ic", "08H", "4Gn", "66E", "aUo", "b4e", "05x", "RB", "8f", "8VD", "4dr", "5a2", "4zp", "6OS", "bl", "355",
"0or", "1j2", "75V", "bno", "4Yl", "6lO", "Ap", "0bB", "0Ln", "2yM", "6Bc", "43H", "4xA", "6Mb", "22D", "14", "0mC", "Nq", "6cN", "4Vm",
"ban", "aDl", "CA", "14Z", "8GG", "mm", "549", "41y", "53t", "464", "1Y3", "1LR", "06W", "Qm", "5L1", "4Iq", "4DA", "65j", "2JL", "1oN",
"0QC", "6y", "7Oo", "4jm", "4el", "6PO", "9x", "1Nc", "04f", "2EM", "7nB", "bqs", "4Fp", "5C0", "d6F", "09V", "0Sr", "4H", "495", "bRo",
"aio", "42V", "0Mp", "nB", "025", "17u", "4Xr", "6mQ", "74H", "4UB", "0nl", "3Kn", "cr", "1Pa", "5kO", "6NM", "6AL", "40g", "0OA", "ls",
"2TN", "0am", "4ZC", "aEr", "5R3", "4Ws", "18t", "Oo", "aC", "0Bq", "bCl", "afn", "2KV", "1nT", "5Uz", "64p", "5n7", "4kw", "0PY", "7c",
"2hJ", "1MH", "4fG", "6Sd", "7mi", "4Hk", "07M", "Pw", "2Ig", "08L", "4Gj", "66A", "7LD", "4iF", "0Rh", "5R", "8b", "1Oy", "4dv", "5a6",
"7oX", "4JZ", "0qt", "RF", "0ov", "LD", "4A9", "4TX", "4zt", "6OW", "bh", "0AZ", "z9", "oX", "6Bg", "43L", "4Yh", "6lK", "At", "0bF",
"0mG", "Nu", "6cJ", "4Vi", "4xE", "6Mf", "2vH", "10", "8GC", "mi", "5p5", "4uu", "5Kx", "4N8", "CE", "1pV", "0QO", "6u", "7Oc", "4ja",
"4DM", "65f", "3Za", "I0", "0rS", "Qa", "68V", "b7F", "4gQ", "468", "dSo", "285", "274", "4D", "499", "4hP", "b8G", "67W", "0h3", "09Z",
"F1", "SP", "7nN", "4KL", "51I", "6PC", "9t", "1No", "21g", "1Pm", "5kC", "6NA", "74D", "4UN", "X3", "MR", "029", "0cP", "bbM", "79t",
"4c3", "42Z", "8Dd", "nN", "aO", "8Ke", "4yS", "4l2", "76u", "635", "0lQ", "Oc", "BS", "W2", "4ZO", "6ol", "7Qa", "40k", "0OM", "2zn",
"69L", "4Hg", "07A", "2Fj", "2hF", "k6", "4fK", "6Sh", "7Ny", "6K9", "0PU", "7o", "2KZ", "1nX", "4EW", "4P6", "7oT", "4JV", "05p", "RJ",
"8n", "1Ou", "4dz", "6QY", "7LH", "4iJ", "d7", "qV", "2Ik", "1li", "4Gf", "66M", "4Yd", "6lG", "Ax", "0bJ", "z5", "oT", "6Bk", "4wH",
"4zx", "aeI", "bd", "0AV", "0oz", "LH", "4A5", "4TT", "5Kt", "4N4", "CI", "14R", "0NW", "me", "541", "41q", "4xI", "6Mj", "22L", "u4",
"0mK", "Ny", "6cF", "4Ve", "4DI", "65b", "2JD", "I4", "0QK", "6q", "7Og", "4je", "4gU", "4r4", "2iX", "1LZ", "0rW", "Qe", "5L9", "4Iy",
"4Fx", "5C8", "0h7", "1mw", "0Sz", "pH", "7MV", "4hT", "4ed", "6PG", "9p", "1Nk", "F5", "ST", "7nJ", "4KH", "7pH", "4UJ", "X7", "MV",
"cz", "1Pi", "5kG", "6NE", "4c7", "4vV", "0Mx", "nJ", "0v5", "0cT", "4Xz", "6mY", "6bX", "5GZ", "0lU", "Og", "aK", "0By", "4yW", "4l6",
"6AD", "40o", "0OI", "2zj", "BW", "W6", "4ZK", "6oh", "2hB", "k2", "4fO", "6Sl", "69H", "4Hc", "07E", "2Fn", "d5e", "83m", "4ES", "4P2",
"a0F", "bQL", "0PQ", "7k", "8j", "1Oq", "50W", "hbv", "7oP", "4JR", "05t", "RN", "2Io", "08D", "4Gb", "66I", "7LL", "4iN", "d3", "5Z",
"z1", "oP", "6Bo", "43D", "5IA", "6lC", "2Wm", "0bN", "8ff", "LL", "4A1", "4TP", "cPn", "aeM", "0T3", "0AR", "0NS", "ma", "545", "41u",
"5Kp", "4N0", "CM", "14V", "0mO", "2Xl", "6cB", "4Va", "4xM", "6Mn", "22H", "18", "04s", "SI", "7nW", "4KU", "4ey", "6PZ", "9m", "1Nv",
"e4", "pU", "7MK", "4hI", "4Fe", "67N", "2Hh", "09C", "06B", "Qx", "68O", "4Id", "4gH", "6Rk", "2iE", "j5", "0QV", "6l", "5o8", "4jx",
"4DT", "4Q5", "2JY", "82j", "BJ", "0ax", "4ZV", "4O7", "552", "40r", "0OT", "lf", "aV", "t7", "4yJ", "6Li", "6bE", "4Wf", "0lH", "Oz",
"2Vj", "0cI", "4Xg", "6mD", "6Ch", "42C", "0Me", "nW", "cg", "1Pt", "5kZ", "6NX", "7pU", "4UW", "0ny", "MK", "7LQ", "4iS", "267", "5G",
"0i0", "08Y", "b9D", "66T", "7oM", "4JO", "G2", "RS", "8w", "1Ol", "4dc", "7Aa", "atS", "4kb", "0PL", "7v", "2KC", "H3", "4EN", "64e",
"69U", "b6E", "07X", "Pb", "dRl", "296", "4fR", "4s3", "4xP", "4m1", "22U", "8Jf", "0mR", "0x3", "77v", "626", "5Km", "6no", "CP", "V1",
"0NN", "3kL", "7Pb", "41h", "4za", "6OB", "20d", "0AO", "Y0", "LQ", "6an", "4TM", "bcN", "78w", "Aa", "0bS", "8Eg", "oM", "4b0", "43Y",
"51T", "azL", "9i", "1Nr", "04w", "SM", "7nS", "4KQ", "4Fa", "67J", "2Hl", "09G", "e0", "4Y", "7MO", "4hM", "4gL", "6Ro", "2iA", "j1",
"06F", "2Gm", "68K", "5YA", "4DP", "4Q1", "d4f", "82n", "0QR", "6h", "a1E", "bPO", "556", "40v", "0OP", "lb", "BN", "15U", "4ZR", "4O3",
"6bA", "4Wb", "0lL", "2Yo", "aR", "t3", "4yN", "6Lm", "6Cl", "42G", "0Ma", "nS", "2Vn", "0cM", "4Xc", "79i", "74Y", "4US", "8ge", "MO",
"cc", "1Pp", "bAL", "adN", "0i4", "1lt", "5WZ", "66P", "7LU", "4iW", "0Ry", "5C", "8s", "1Oh", "4dg", "6QD", "7oI", "4JK", "G6", "RW",
"2KG", "H7", "4EJ", "64a", "7Nd", "4kf", "0PH", "7r", "1X8", "1MY", "4fV", "4s7", "69Q", "4Hz", "0sT", "Pf", "0mV", "Nd", "5S8", "4Vx",
"4xT", "4m5", "22Q", "0Cz", "0NJ", "mx", "7Pf", "41l", "5Ki", "6nk", "CT", "V5", "Y4", "LU", "6aj", "4TI", "4ze", "6OF", "by", "0AK",
"2l9", "oI", "4b4", "4wU", "4Yy", "6lZ", "Ae", "0bW", "0So", "4U", "7MC", "4hA", "4Fm", "67F", "3XA", "09K", "0ps", "SA", "aTl", "b5f",
"4eq", "6PR", "9e", "8WG", "8XF", "6d", "5o0", "4jp", "707", "65w", "1z2", "1oS", "06J", "Qp", "68G", "4Il", "53i", "6Rc", "2iM", "1LO",
"23G", "07", "4yB", "6La", "6bM", "4Wn", "18i", "Or", "BB", "0ap", "c4D", "aEo", "5q2", "40z", "8FD", "ln", "co", "346", "5kR", "6NP",
"74U", "bol", "0nq", "MC", "2Vb", "0cA", "4Xo", "6mL", "7SA", "42K", "0Mm", "2xN", "7oE", "4JG", "05a", "2DJ", "2jf", "1Od", "4dk", "6QH",
"482", "5yz", "0Ru", "5O", "0i8", "08Q", "4Gw", "5B7", "5M6", "4Hv", "07P", "Pj", "1X4", "1MU", "4fZ", "473", "7Nh", "4kj", "0PD", "sv",
"2KK", "1nI", "4EF", "64m", "5Ke", "6ng", "CX", "V9", "0NF", "mt", "7Pj", "4uh", "4xX", "4m9", "1F6", "0Cv", "0mZ", "Nh", "5S4", "4Vt",
"4Yu", "6lV", "Ai", "16r", "0Lw", "oE", "4b8", "43Q", "4zi", "6OJ", "bu", "0AG", "Y8", "LY", "6af", "4TE", "4Fi", "67B", "2Hd", "09O",
"e8", "4Q", "7MG", "4hE", "4eu", "6PV", "9a", "1Nz", "0pw", "SE", "aTh", "4KY", "4DX", "4Q9", "1z6", "1oW", "0QZ", "rh", "5o4", "4jt",
"4gD", "6Rg", "2iI", "j9", "06N", "Qt", "68C", "4Ih", "6bI", "4Wj", "0lD", "Ov", "aZ", "03", "4yF", "6Le", "5q6", "4tv", "0OX", "lj",
"BF", "0at", "4ZZ", "6oy", "74Q", "5Ez", "0nu", "MG", "ck", "1Px", "5kV", "6NT", "6Cd", "42O", "0Mi", "2xJ", "2Vf", "0cE", "4Xk", "6mH",
"2jb", "8VY", "4do", "6QL", "7oA", "4JC", "05e", "2DN", "d7E", "08U", "4Gs", "5B3", "486", "bSl", "0Rq", "5K", "1X0", "1MQ", "52w", "477",
"5M2", "4Hr", "07T", "Pn", "2KO", "1nM", "4EB", "64i", "7Nl", "4kn", "8YX", "7z", "0NB", "mp", "7Pn", "41d", "5Ka", "6nc", "2UM", "14G",
"19w", "Nl", "5S0", "4Vp", "bBo", "agm", "1F2", "0Cr", "0Ls", "oA", "ahl", "43U", "4Yq", "6lR", "Am", "16v", "0oo", "2ZL", "6ab", "4TA",
"4zm", "6ON", "bq", "0AC", "2VY", "0cz", "4XT", "4M5", "570", "42p", "0MV", "nd", "cT", "v5", "5ki", "6Nk", "74n", "4Ud", "0nJ", "Mx",
"By", "0aK", "4Ze", "6oF", "6Aj", "40A", "y4", "lU", "ae", "0BW", "4yy", "581", "4B4", "4WU", "18R", "OI", "06q", "QK", "7lU", "4IW",
"53R", "6RX", "0I4", "1Lt", "g6", "rW", "7OI", "4jK", "4Dg", "65L", "2Jj", "1oh", "0pH", "Sz", "7nd", "4Kf", "4eJ", "6Pi", "2kG", "h7",
"0ST", "4n", "7Mx", "4hz", "4FV", "4S7", "1x8", "09p", "4zR", "4o3", "bN", "8Hd", "0oP", "Lb", "75t", "604", "4YN", "6lm", "AR", "T3",
"0LL", "2yo", "6BA", "43j", "4xc", "agR", "22f", "0CM", "0ma", "NS", "6cl", "4VO", "baL", "aDN", "Cc", "14x", "8Ge", "mO", "7PQ", "4uS",
"7NS", "4kQ", "245", "7E", "0k2", "1nr", "coo", "64V", "69f", "4HM", "E0", "PQ", "2hl", "1Mn", "4fa", "6SB", "7Lb", "5yA", "0RN", "5t",
"2IA", "J1", "4GL", "66g", "aUM", "b4G", "05Z", "0d3", "8D", "8Vf", "4dP", "459", "574", "42t", "0MR", "0X3", "dln", "17W", "4XP", "4M1",
"74j", "5EA", "0nN", "3KL", "cP", "29", "5km", "6No", "6An", "40E", "y0", "lQ", "2Tl", "0aO", "4Za", "6oB", "4B0", "4WQ", "18V", "OM",
"aa", "0BS", "bCN", "585", "53V", "axN", "0I0", "1Lp", "06u", "QO", "68x", "4IS", "4Dc", "65H", "2Jn", "1ol", "g2", "rS", "7OM", "4jO",
"4eN", "6Pm", "9Z", "h3", "04D", "2Eo", "aTS", "4Kb", "4FR", "4S3", "d6d", "09t", "0SP", "4j", "a3G", "bRM", "0oT", "Lf", "6aY", "4Tz",
"4zV", "4o7", "bJ", "0Ax", "0LH", "oz", "6BE", "43n", "4YJ", "6li", "AV", "T7", "0me", "NW", "6ch", "4VK", "4xg", "6MD", "22b", "0CI",
"0Ny", "mK", "7PU", "4uW", "5KZ", "6nX", "Cg", "1pt", "0k6", "1nv", "4Ey", "64R", "7NW", "4kU", "241", "7A", "2hh", "1Mj", "4fe", "6SF",
"69b", "4HI", "E4", "PU", "2IE", "J5", "4GH", "66c", "7Lf", "4id", "0RJ", "5p", "2jY", "8Vb", "4dT", "4q5", "5O8", "4Jx", "0qV", "Rd",
"21E", "25", "5ka", "6Nc", "74f", "4Ul", "0nB", "Mp", "1f2", "0cr", "bbo", "79V", "578", "42x", "395", "nl", "am", "364", "4yq", "589",
"76W", "bmn", "0ls", "OA", "Bq", "0aC", "4Zm", "6oN", "6Ab", "40I", "0Oo", "2zL", "0Qm", "6W", "7OA", "4jC", "4Do", "65D", "2Jb", "82Q",
"06y", "QC", "68t", "b7d", "4gs", "5b3", "dSM", "8UE", "8ZD", "4f", "5m2", "4hr", "725", "67u", "1x0", "09x", "04H", "Sr", "7nl", "4Kn",
"4eB", "6Pa", "9V", "1NM", "4YF", "6le", "AZ", "0bh", "0LD", "ov", "6BI", "43b", "4zZ", "6Oy", "bF", "0At", "0oX", "Lj", "5Q6", "4Tv",
"5KV", "6nT", "Ck", "14p", "0Nu", "mG", "7PY", "41S", "4xk", "6MH", "22n", "0CE", "0mi", "2XJ", "6cd", "4VG", "69n", "4HE", "E8", "PY",
"2hd", "1Mf", "4fi", "6SJ", "ath", "4kY", "0Pw", "7M", "2Kx", "1nz", "4Eu", "6pV", "5O4", "4Jt", "05R", "Rh", "8L", "1OW", "4dX", "451",
"7Lj", "4ih", "0RF", "qt", "2II", "J9", "4GD", "66o", "74b", "4Uh", "0nF", "Mt", "cX", "21", "5ke", "6Ng", "5s4", "4vt", "0MZ", "nh",
"1f6", "0cv", "4XX", "4M9", "4B8", "4WY", "0lw", "OE", "ai", "1Rz", "4yu", "6LV", "6Af", "40M", "y8", "lY", "Bu", "0aG", "4Zi", "6oJ",
"4Dk", "6qH", "2Jf", "1od", "0Qi", "6S", "7OE", "4jG", "4gw", "5b7", "0I8", "1Lx", "0ru", "QG", "68p", "5Yz", "4FZ", "67q", "1x4", "1mU",
"0SX", "4b", "5m6", "4hv", "4eF", "6Pe", "9R", "1NI", "04L", "Sv", "7nh", "4Kj", "8EX", "or", "6BM", "43f", "4YB", "6la", "2WO", "0bl",
"8fD", "Ln", "5Q2", "4Tr", "cPL", "aeo", "bB", "0Ap", "0Nq", "mC", "ajn", "41W", "5KR", "6nP", "Co", "14t", "0mm", "2XN", "77I", "4VC",
"4xo", "6ML", "22j", "0CA", "3xA", "1Mb", "4fm", "6SN", "69j", "4HA", "07g", "2FL", "d5G", "83O", "4Eq", "64Z", "a0d", "bQn", "0Ps", "7I",
"8H", "1OS", "50u", "455", "5O0", "4Jp", "05V", "Rl", "2IM", "08f", "5Wa", "66k", "7Ln", "4il", "0RB", "5x", "Bh", "0aZ", "4Zt", "6oW",
"4a9", "40P", "0Ov", "lD", "at", "0BF", "4yh", "6LK", "6bg", "4WD", "Z9", "OX", "2VH", "U8", "4XE", "6mf", "6CJ", "42a", "0MG", "nu",
"cE", "1PV", "5kx", "4n8", "5P5", "4Uu", "8gC", "Mi", "04Q", "Sk", "5N7", "4Kw", "51r", "442", "9O", "1NT", "0SE", "pw", "7Mi", "4hk",
"4FG", "67l", "2HJ", "09a", "3", "QZ", "68m", "4IF", "4gj", "6RI", "2ig", "1Le", "0Qt", "6N", "7OX", "4jZ", "4Dv", "5A6", "0j9", "1oy",
"4xr", "6MQ", "22w", "377", "0mp", "NB", "77T", "blm", "5KO", "6nM", "Cr", "14i", "0Nl", "3kn", "ajs", "41J", "4zC", "aer", "20F", "36",
"0oA", "Ls", "6aL", "4To", "bcl", "78U", "AC", "0bq", "386", "oo", "5r3", "4ws", "5l1", "4iq", "9Kf", "5e", "1y3", "1lR", "736", "66v",
"7oo", "4Jm", "05K", "Rq", "8U", "1ON", "4dA", "6Qb", "7NB", "bQs", "0Pn", "7T", "2Ka", "1nc", "4El", "64G", "69w", "b6g", "07z", "1v2",
"dRN", "8TF", "4fp", "5c0", "akm", "40T", "0Or", "1J2", "Bl", "15w", "4Zp", "6oS", "6bc", "5Ga", "0ln", "2YM", "ap", "0BB", "4yl", "6LO",
"6CN", "42e", "0MC", "nq", "2VL", "0co", "4XA", "6mb", "5P1", "4Uq", "8gG", "Mm", "cA", "1PR", "bAn", "adl", "51v", "446", "9K", "1NP",
"04U", "So", "5N3", "4Ks", "4FC", "67h", "2HN", "09e", "0SA", "ps", "7Mm", "4ho", "4gn", "6RM", "2ic", "1La", "7", "2GO", "68i", "4IB",
"4Dr", "5A2", "d4D", "82L", "0Qp", "6J", "a1g", "bPm", "0mt", "NF", "6cy", "4VZ", "4xv", "6MU", "0V9", "0CX", "0Nh", "mZ", "7PD", "41N",
"5KK", "6nI", "Cv", "14m", "0oE", "Lw", "6aH", "4Tk", "4zG", "6Od", "20B", "32", "0LY", "ok", "5r7", "4ww", "5Iz", "6lx", "AG", "0bu",
"1y7", "1lV", "4GY", "4R8", "5l5", "4iu", "1Bz", "5a", "8Q", "i8", "4dE", "6Qf", "7ok", "4Ji", "05O", "Ru", "2Ke", "1ng", "4Eh", "64C",
"7NF", "4kD", "f9", "7P", "2hy", "3m9", "4ft", "5c4", "69s", "4HX", "0sv", "PD", "23e", "0BN", "5iA", "6LC", "6bo", "4WL", "Z1", "OP",
"0t3", "0aR", "c4f", "aEM", "4a1", "40X", "8Ff", "lL", "cM", "8Ig", "5kp", "4n0", "74w", "617", "0nS", "Ma", "3Fa", "U0", "4XM", "6mn",
"6CB", "42i", "0MO", "2xl", "0SM", "4w", "7Ma", "4hc", "4FO", "67d", "2HB", "K2", "04Y", "Sc", "aTN", "b5D", "4eS", "4p2", "9G", "8We",
"256", "6F", "7OP", "4jR", "cnl", "65U", "0j1", "1oq", "D3", "QR", "68e", "4IN", "4gb", "6RA", "2io", "1Lm", "5KG", "6nE", "Cz", "14a",
"x7", "mV", "7PH", "41B", "4xz", "592", "0V5", "0CT", "0mx", "NJ", "4C7", "4VV", "4YW", "4L6", "AK", "0by", "0LU", "og", "563", "43s",
"4zK", "6Oh", "bW", "w6", "0oI", "2Zj", "6aD", "4Tg", "7og", "4Je", "05C", "Ry", "2jD", "i4", "4dI", "6Qj", "5l9", "4iy", "0RW", "5m",
"2IX", "08s", "4GU", "4R4", "7mV", "4HT", "07r", "PH", "0H7", "1Mw", "4fx", "5c8", "7NJ", "4kH", "f5", "sT", "2Ki", "1nk", "4Ed", "64O",
"6bk", "4WH", "Z5", "OT", "ax", "0BJ", "4yd", "6LG", "4a5", "4tT", "0Oz", "lH", "Bd", "0aV", "4Zx", "aEI", "5P9", "4Uy", "0nW", "Me",
"cI", "1PZ", "5kt", "4n4", "6CF", "42m", "0MK", "ny", "2VD", "U4", "4XI", "6mj", "4FK", "6sh", "2HF", "K6", "0SI", "4s", "7Me", "4hg",
"4eW", "4p6", "9C", "1NX", "0pU", "Sg", "7ny", "6k9", "4Dz", "65Q", "0j5", "1ou", "0Qx", "6B", "7OT", "4jV", "4gf", "6RE", "2ik", "1Li",
"D7", "QV", "68a", "4IJ", "x3", "mR", "7PL", "41F", "5KC", "6nA", "2Uo", "14e", "19U", "NN", "4C3", "4VR", "bBM", "596", "0V1", "0CP",
"0LQ", "oc", "567", "43w", "4YS", "4L2", "AO", "16T", "0oM", "2Zn", "75i", "4Tc", "4zO", "6Ol", "bS", "w2", "8Y", "i0", "4dM", "6Qn",
"7oc", "4Ja", "05G", "2Dl", "d7g", "08w", "4GQ", "4R0", "a2D", "bSN", "0RS", "5i", "0H3", "1Ms", "52U", "ayM", "7mR", "4HP", "07v", "PL",
"2Km", "1no", "5UA", "64K", "7NN", "4kL", "f1", "7X", "5nw", "4k7", "fJ", "0Ex", "0kT", "Hf", "6eY", "4Pz", "5Mk", "6hi", "EV", "P7",
"0HH", "kz", "6FE", "47n", "48o", "6ID", "26b", "0GI", "0ie", "JW", "6gh", "4RK", "5OZ", "6jX", "Gg", "0dU", "0Jy", "iK", "4d6", "4qW",
"4z4", "4oU", "1DZ", "3A", "Ye", "0zW", "4Ay", "5D9", "6yj", "4LI", "A4", "TU", "zy", "0YK", "4be", "6WF", "6XG", "4md", "0VJ", "1p",
"2ME", "N5", "4CH", "62c", "5K8", "4Nx", "0uV", "Vd", "xH", "8Rb", "5pu", "4u5", "D", "13W", "5Lq", "4I1", "534", "46t", "0IR", "28y",
"gP", "69", "5om", "6Jo", "6dC", "5AA", "0jN", "3OL", "2Pl", "0eO", "aT1", "6kB", "6En", "44E", "98", "hQ", "ea", "0FS", "49u", "abL",
"4F0", "4SQ", "8ag", "KM", "02u", "UO", "4X2", "4MS", "57V", "a8F", "0M0", "0XQ", "c2", "vS", "7KM", "4nO", "5PB", "61H", "2Nn", "1kl",
"00D", "2Ao", "6zA", "4Ob", "4aN", "6Tm", "yR", "l3", "0WP", "0j", "a7G", "58W", "4BR", "4W3", "ZN", "84l", "0kP", "Hb", "71t", "644",
"5ns", "4k3", "fN", "8Ld", "0HL", "29g", "6FA", "47j", "5Mo", "6hm", "ER", "P3", "0ia", "JS", "6gl", "4RO", "48k", "7Ya", "26f", "0GM",
"8Ce", "iO", "4d2", "4qS", "beL", "hYw", "Gc", "0dQ", "Ya", "0zS", "cko", "60V", "4z0", "4oQ", "205", "3E", "2ll", "0YO", "4ba", "6WB",
"6yn", "4LM", "A0", "TQ", "2MA", "N1", "4CL", "62g", "6XC", "59I", "0VN", "1t", "xL", "8Rf", "54y", "419", "aQM", "b0G", "01Z", "3PP",
"530", "46p", "0IV", "jd", "DH", "0gz", "5Lu", "4I5", "6dG", "4Qd", "0jJ", "Ix", "gT", "r5", "5oi", "6Jk", "6Ej", "44A", "0Kg", "hU",
"Fy", "0eK", "5ND", "6kF", "4F4", "4SU", "1xZ", "KI", "ee", "0FW", "49q", "5x9", "57R", "6VX", "0M4", "0XU", "02q", "UK", "4X6", "4MW",
"5PF", "61L", "2Nj", "1kh", "c6", "vW", "7KI", "4nK", "4aJ", "6Ti", "yV", "l7", "0tH", "Wz", "6zE", "4Of", "4BV", "4W7", "ZJ", "0yx",
"0WT", "0n", "6YY", "4lz", "5Mc", "6ha", "2SO", "0fl", "1Xa", "kr", "6FM", "47f", "bDm", "aao", "fB", "0Ep", "8bD", "Hn", "5U2", "4Pr",
"5OR", "5Z3", "Go", "10t", "0Jq", "iC", "ann", "45W", "48g", "6IL", "ds", "0GA", "0im", "3Lo", "73I", "4RC", "6yb", "4LA", "03g", "2BL",
"zq", "0YC", "4bm", "6WN", "a4d", "bUn", "0Ts", "3I", "Ym", "87O", "4Aq", "5D1", "5K0", "4Np", "01V", "Vl", "2nQ", "1KS", "54u", "415",
"6XO", "4ml", "0VB", "1x", "2MM", "0xn", "5Sa", "62k", "gX", "61", "5oe", "6Jg", "6dK", "4Qh", "0jF", "It", "L", "0gv", "5Ly", "4I9",
"5w4", "4rt", "0IZ", "jh", "ei", "1Vz", "5mT", "5x5", "4F8", "4SY", "0hw", "KE", "Fu", "0eG", "5NH", "6kJ", "6Ef", "44M", "90", "hY",
"0Ui", "2S", "7KE", "4nG", "5PJ", "6uH", "Xw", "1kd", "0vu", "UG", "6xx", "790", "4cw", "5f7", "0M8", "0XY", "0WX", "0b", "5i6", "4lv",
"4BZ", "63q", "ZF", "0yt", "00L", "Wv", "6zI", "4Oj", "4aF", "6Te", "yZ", "0Zh", "0HD", "kv", "6FI", "47b", "5Mg", "6he", "EZ", "0fh",
"0kX", "Hj", "5U6", "4Pv", "7N9", "6Ky", "fF", "0Et", "0Ju", "iG", "6Dx", "45S", "5OV", "5Z7", "Gk", "0dY", "0ii", "3Lk", "6gd", "4RG",
"48c", "6IH", "dw", "0GE", "zu", "0YG", "4bi", "6WJ", "6yf", "4LE", "A8", "TY", "Yi", "1jz", "4Au", "5D5", "4z8", "4oY", "0Tw", "3M",
"xD", "1KW", "54q", "411", "5K4", "4Nt", "01R", "Vh", "2MI", "N9", "4CD", "62o", "6XK", "4mh", "0VF", "ut", "6dO", "4Ql", "0jB", "Ip",
"25E", "65", "5oa", "6Jc", "538", "46x", "9Pg", "jl", "H", "0gr", "bfo", "aCm", "72W", "bin", "0hs", "KA", "em", "324", "49y", "5x1",
"6Eb", "44I", "94", "3nm", "Fq", "0eC", "5NL", "6kN", "5PN", "61D", "Xs", "86Q", "0Um", "2W", "7KA", "4nC", "4cs", "5f3", "39W", "8QE",
"02y", "UC", "aRn", "794", "765", "63u", "ZB", "0yp", "9Ne", "0f", "5i2", "4lr", "4aB", "6Ta", "2oO", "0Zl", "00H", "Wr", "6zM", "4On",
"5lW", "5y6", "dj", "0GX", "0it", "JF", "6gy", "4RZ", "5OK", "6jI", "Gv", "0dD", "83", "iZ", "6De", "45N", "5nf", "6Kd", "24B", "72",
"0kE", "Hw", "6eH", "4Pk", "5Mz", "6hx", "EG", "0fu", "0HY", "kk", "5v7", "4sw", "5h5", "4mu", "1Fz", "1a", "2MT", "0xw", "4CY", "4V8",
"7kk", "4Ni", "01O", "Vu", "xY", "m8", "54l", "6Uf", "6Zg", "4oD", "b9", "3P", "Yt", "0zF", "4Ah", "60C", "4Y9", "4LX", "0wv", "TD",
"zh", "0YZ", "4bt", "5g4", "Fl", "11w", "5NQ", "6kS", "aom", "44T", "0Kr", "1N2", "ep", "0FB", "49d", "6HO", "6fc", "5Ca", "0hn", "3Ml",
"U", "0go", "bfr", "6ib", "6GN", "46e", "0IC", "jq", "gA", "0Ds", "bEn", "hyU", "5T1", "4Qq", "8cG", "Im", "00U", "Wo", "5J3", "4Os",
"55v", "406", "yC", "0Zq", "0WA", "ts", "6YL", "4lo", "4BC", "63h", "2LN", "0ym", "02d", "2CO", "6xa", "4MB", "4cn", "6VM", "2mc", "1Ha",
"0Up", "2J", "a5g", "bTm", "5PS", "5E2", "Xn", "86L", "0ip", "JB", "73T", "bhm", "48z", "5y2", "dn", "337", "87", "3on", "6Da", "45J",
"5OO", "6jM", "Gr", "10i", "0kA", "Hs", "6eL", "4Po", "5nb", "aar", "24F", "76", "8AE", "ko", "5v3", "4ss", "bgl", "aBn", "EC", "0fq",
"2MP", "0xs", "776", "62v", "5h1", "4mq", "9Of", "1e", "2nL", "1KN", "54h", "6Ub", "7ko", "4Nm", "01K", "Vq", "Yp", "0zB", "4Al", "60G",
"6Zc", "bUs", "0Tn", "3T", "zl", "8PF", "4bp", "5g0", "aSm", "787", "03z", "1r2", "4e9", "44P", "0Kv", "hD", "Fh", "0eZ", "5NU", "6kW",
"6fg", "4SD", "0hj", "KX", "et", "0FF", "5mI", "6HK", "6GJ", "46a", "0IG", "ju", "Q", "Q8", "5Ld", "6if", "5T5", "4Qu", "1zz", "Ii",
"gE", "0Dw", "5ox", "4j8", "55r", "402", "yG", "0Zu", "00Q", "Wk", "5J7", "4Ow", "4BG", "63l", "2LJ", "0yi", "0WE", "tw", "6YH", "4lk",
"4cj", "6VI", "2mg", "0XD", "0vh", "UZ", "6xe", "4MF", "5PW", "5E6", "Xj", "1ky", "0Ut", "2N", "7KX", "4nZ", "5OC", "6jA", "2Qo", "0dL",
"1ZA", "iR", "6Dm", "45F", "48v", "acO", "db", "0GP", "94M", "JN", "4G3", "4RR", "5Mr", "4H2", "EO", "12T", "0HQ", "kc", "527", "47w",
"5nn", "6Kl", "fS", "s2", "0kM", "3NO", "71i", "4Pc", "7kc", "4Na", "01G", "3PM", "xQ", "m0", "54d", "6Un", "a6D", "59T", "0VS", "1i",
"197", "85o", "4CQ", "4V0", "4Y1", "4LP", "03v", "TL", "0L3", "0YR", "56U", "a9E", "6Zo", "4oL", "b1", "3X", "2Om", "0zN", "5QA", "60K",
"ex", "0FJ", "49l", "6HG", "6fk", "4SH", "0hf", "KT", "Fd", "0eV", "5NY", "aAI", "4e5", "4pT", "0Kz", "hH", "gI", "1TZ", "5ot", "4j4",
"5T9", "4Qy", "0jW", "Ie", "DU", "Q4", "5Lh", "6ij", "6GF", "46m", "0IK", "jy", "0WI", "0s", "6YD", "4lg", "4BK", "6wh", "ZW", "O6",
"0tU", "Wg", "6zX", "6o9", "4aW", "4t6", "yK", "0Zy", "0Ux", "2B", "7KT", "4nV", "bzI", "61Q", "Xf", "1ku", "02l", "UV", "6xi", "4MJ",
"4cf", "6VE", "2mk", "0XH", "0Jd", "iV", "6Di", "45B", "5OG", "6jE", "Gz", "0dH", "0ix", "JJ", "4G7", "4RV", "48r", "6IY", "df", "0GT",
"0HU", "kg", "523", "47s", "5Mv", "4H6", "EK", "0fy", "0kI", "3NK", "6eD", "4Pg", "5nj", "6Kh", "fW", "s6", "xU", "m4", "5ph", "6Uj",
"7kg", "4Ne", "01C", "Vy", "193", "1hZ", "4CU", "4V4", "5h9", "4my", "0VW", "1m", "zd", "0YV", "4bx", "5g8", "4Y5", "4LT", "03r", "TH",
"Yx", "0zJ", "4Ad", "60O", "6Zk", "4oH", "b5", "wT", "6fo", "4SL", "0hb", "KP", "27e", "0FN", "49h", "6HC", "4e1", "44X", "8Bf", "hL",
"0p3", "0eR", "bdO", "aAM", "70w", "657", "0jS", "Ia", "gM", "8Mg", "5op", "4j0", "6GB", "46i", "0IO", "28d", "Y", "Q0", "5Ll", "6in",
"4BO", "63d", "ZS", "O2", "0WM", "0w", "7Ia", "4lc", "4aS", "4t2", "yO", "8Se", "00Y", "Wc", "aPN", "b1D", "bzM", "61U", "Xb", "1kq",
"216", "2F", "7KP", "4nR", "4cb", "6VA", "2mo", "0XL", "02h", "UR", "6xm", "4MN", "5j7", "4ow", "0TY", "3c", "YG", "0zu", "5Qz", "60p",
"6yH", "4Lk", "03M", "Tw", "2lJ", "0Yi", "4bG", "6Wd", "6Xe", "4mF", "0Vh", "1R", "2Mg", "0xD", "4Cj", "62A", "7kX", "4NZ", "0ut", "VF",
"xj", "1Ky", "5pW", "5e6", "5nU", "6KW", "fh", "0EZ", "0kv", "HD", "4E9", "4PX", "5MI", "6hK", "Et", "0fF", "0Hj", "kX", "6Fg", "47L",
"48M", "6If", "dY", "50", "0iG", "Ju", "6gJ", "4Ri", "5Ox", "4J8", "GE", "0dw", "1Zz", "ii", "5t5", "4qu", "02W", "Um", "5H1", "4Mq",
"57t", "424", "2mP", "0Xs", "0UC", "2y", "7Ko", "4nm", "bzr", "61j", "2NL", "1kN", "00f", "2AM", "6zc", "bus", "4al", "6TO", "yp", "0ZB",
"0Wr", "0H", "a7e", "58u", "4Bp", "5G0", "Zl", "84N", "f", "13u", "5LS", "5Y2", "amo", "46V", "0Ip", "jB", "gr", "1Ta", "5oO", "6JM",
"6da", "4QB", "0jl", "3On", "2PN", "0em", "5Nb", "aAr", "6EL", "44g", "0KA", "hs", "eC", "0Fq", "49W", "abn", "5V3", "4Ss", "8aE", "Ko",
"YC", "0zq", "754", "60t", "5j3", "4os", "9Md", "3g", "2lN", "0Ym", "4bC", "7GA", "6yL", "4Lo", "03I", "Ts", "2Mc", "1ha", "4Cn", "62E",
"6Xa", "4mB", "0Vl", "1V", "xn", "8RD", "5pS", "5e2", "aQo", "b0e", "01x", "VB", "0kr", "1n2", "71V", "bjo", "5nQ", "6KS", "fl", "315",
"0Hn", "29E", "6Fc", "47H", "5MM", "6hO", "Ep", "0fB", "0iC", "Jq", "6gN", "4Rm", "48I", "6Ib", "26D", "54", "8CG", "im", "509", "45y",
"ben", "hYU", "GA", "0ds", "4cY", "420", "2mT", "0Xw", "02S", "Ui", "5H5", "4Mu", "5Pd", "61n", "XY", "M8", "0UG", "vu", "7Kk", "4ni",
"4ah", "6TK", "yt", "0ZF", "B9", "WX", "6zg", "4OD", "4Bt", "5G4", "Zh", "0yZ", "0Wv", "0L", "4y9", "4lX", "6Gy", "46R", "0It", "jF",
"b", "0gX", "5LW", "5Y6", "6de", "4QF", "0jh", "IZ", "gv", "0DD", "5oK", "6JI", "6EH", "44c", "0KE", "hw", "2PJ", "0ei", "5Nf", "6kd",
"5V7", "4Sw", "0hY", "Kk", "eG", "0Fu", "49S", "6Hx", "7ia", "4Lc", "03E", "2Bn", "zS", "o2", "4bO", "6Wl", "a4F", "bUL", "0TQ", "3k",
"YO", "87m", "4AS", "4T2", "7kP", "4NR", "01t", "VN", "xb", "1Kq", "54W", "hfv", "6Xm", "4mN", "1FA", "1Z", "2Mo", "0xL", "4Cb", "62I",
"5MA", "6hC", "2Sm", "0fN", "0Hb", "kP", "6Fo", "47D", "bDO", "aaM", "0P3", "0ER", "8bf", "HL", "4E1", "4PP", "5Op", "4J0", "GM", "10V",
"0JS", "ia", "505", "45u", "48E", "6In", "dQ", "58", "0iO", "3LM", "6gB", "4Ra", "0UK", "2q", "7Kg", "4ne", "5Ph", "61b", "XU", "M4",
"0vW", "Ue", "5H9", "4My", "4cU", "4v4", "2mX", "1HZ", "0Wz", "tH", "4y5", "4lT", "4Bx", "5G8", "Zd", "0yV", "B5", "WT", "6zk", "4OH",
"4ad", "6TG", "yx", "0ZJ", "gz", "0DH", "5oG", "6JE", "6di", "4QJ", "0jd", "IV", "n", "0gT", "680", "6iY", "4g7", "4rV", "0Ix", "jJ",
"eK", "0Fy", "5mv", "4h6", "6fX", "5CZ", "0hU", "Kg", "FW", "S6", "5Nj", "6kh", "6ED", "44o", "0KI", "3nK", "zW", "o6", "4bK", "6Wh",
"6yD", "4Lg", "03A", "2Bj", "YK", "0zy", "4AW", "4T6", "6ZX", "6O9", "0TU", "3o", "xf", "1Ku", "54S", "6UY", "7kT", "4NV", "01p", "VJ",
"2Mk", "0xH", "4Cf", "62M", "6Xi", "4mJ", "0Vd", "uV", "0Hf", "kT", "6Fk", "4sH", "5ME", "6hG", "Ex", "0fJ", "0kz", "HH", "4E5", "4PT",
"5nY", "aaI", "fd", "0EV", "0JW", "ie", "501", "45q", "5Ot", "4J4", "GI", "10R", "0iK", "Jy", "6gF", "4Re", "48A", "6Ij", "dU", "q4",
"5Pl", "61f", "XQ", "M0", "0UO", "2u", "7Kc", "4na", "4cQ", "428", "39u", "8Qg", "0vS", "Ua", "aRL", "b3F", "bxO", "63W", "0l3", "0yR",
"234", "0D", "4y1", "4lP", "55I", "6TC", "2om", "0ZN", "B1", "WP", "6zo", "4OL", "6dm", "4QN", "1zA", "IR", "25g", "0DL", "5oC", "6JA",
"4g3", "46Z", "9PE", "jN", "j", "0gP", "684", "aCO", "72u", "675", "0hQ", "Kc", "eO", "8Oe", "5mr", "4h2", "7Ua", "44k", "0KM", "3nO",
"FS", "S2", "5Nn", "6kl", "4x6", "4mW", "0Vy", "1C", "0m4", "0xU", "5SZ", "62P", "7kI", "4NK", "C6", "VW", "2nj", "1Kh", "54N", "6UD",
"6ZE", "4of", "0TH", "3r", "YV", "L7", "4AJ", "60a", "6yY", "4Lz", "0wT", "Tf", "zJ", "0Yx", "4bV", "4w7", "5lu", "4i5", "dH", "0Gz",
"0iV", "Jd", "5W8", "4Rx", "5Oi", "6jk", "GT", "R5", "0JJ", "ix", "6DG", "45l", "5nD", "6KF", "fy", "0EK", "0kg", "HU", "6ej", "4PI",
"5MX", "5X9", "Ee", "0fW", "1XZ", "kI", "4f4", "4sU", "00w", "WM", "4Z0", "4OQ", "55T", "hgu", "ya", "0ZS", "a0", "0Y", "6Yn", "4lM",
"4Ba", "63J", "2Ll", "0yO", "02F", "2Cm", "6xC", "aG0", "4cL", "6Vo", "2mA", "n1", "0UR", "2h", "a5E", "bTO", "5Pq", "4U1", "XL", "86n",
"FN", "11U", "5Ns", "4K3", "516", "44v", "0KP", "hb", "eR", "p3", "49F", "6Hm", "6fA", "4Sb", "0hL", "3MN", "w", "0gM", "5LB", "7ya",
"6Gl", "46G", "0Ia", "jS", "gc", "0DQ", "bEL", "hyw", "4D2", "4QS", "8ce", "IO", "0m0", "0xQ", "byL", "62T", "4x2", "4mS", "227", "1G",
"2nn", "1Kl", "54J", "7Ea", "7kM", "4NO", "C2", "VS", "YR", "L3", "4AN", "60e", "6ZA", "4ob", "0TL", "3v", "zN", "8Pd", "4bR", "4w3",
"aSO", "b2E", "03X", "Tb", "0iR", "3LP", "73v", "666", "48X", "4i1", "dL", "8Nf", "0JN", "3oL", "6DC", "45h", "5Om", "6jo", "GP", "R1",
"0kc", "HQ", "6en", "4PM", "a09", "6KB", "24d", "0EO", "8Ag", "kM", "4f0", "47Y", "697", "aBL", "Ea", "0fS", "4ay", "5d9", "ye", "0ZW",
"00s", "WI", "4Z4", "4OU", "4Be", "63N", "Zy", "0yK", "a4", "tU", "6Yj", "4lI", "4cH", "6Vk", "2mE", "n5", "02B", "Ux", "6xG", "4Md",
"5Pu", "4U5", "XH", "86j", "0UV", "2l", "5k8", "4nx", "512", "44r", "0KT", "hf", "FJ", "0ex", "5Nw", "4K7", "6fE", "4Sf", "0hH", "Kz",
"eV", "p7", "49B", "6Hi", "6Gh", "46C", "0Ie", "jW", "s", "0gI", "5LF", "6iD", "4D6", "4QW", "0jy", "IK", "gg", "0DU", "5oZ", "6JX",
"7kA", "4NC", "01e", "3Po", "xs", "8RY", "54F", "6UL", "a6f", "59v", "0Vq", "1K", "d3E", "85M", "4Cs", "5F3", "5I2", "4Lr", "03T", "Tn",
"zB", "0Yp", "56w", "437", "6ZM", "4on", "1Da", "3z", "2OO", "0zl", "4AB", "60i", "5Oa", "6jc", "2QM", "0dn", "0JB", "ip", "6DO", "45d",
"48T", "acm", "1B2", "0Gr", "94o", "Jl", "5W0", "4Rp", "5MP", "5X1", "Em", "12v", "0Hs", "kA", "all", "47U", "5nL", "6KN", "fq", "0EC",
"0ko", "3Nm", "6eb", "4PA", "a8", "0Q", "6Yf", "4lE", "4Bi", "63B", "Zu", "0yG", "0tw", "WE", "4Z8", "4OY", "4au", "5d5", "yi", "1Jz",
"0UZ", "vh", "5k4", "4nt", "5Py", "4U9", "XD", "1kW", "02N", "Ut", "6xK", "4Mh", "4cD", "6Vg", "2mI", "n9", "eZ", "43", "49N", "6He",
"6fI", "4Sj", "0hD", "Kv", "FF", "0et", "7n9", "6ky", "5u6", "4pv", "0KX", "hj", "gk", "0DY", "5oV", "5z7", "6dx", "5Az", "0ju", "IG",
"Dw", "0gE", "5LJ", "6iH", "6Gd", "46O", "0Ii", "28B", "xw", "1Kd", "54B", "6UH", "7kE", "4NG", "01a", "3Pk", "0m8", "0xY", "4Cw", "5F7",
"6Xx", "59r", "0Vu", "1O", "zF", "0Yt", "4bZ", "433", "5I6", "4Lv", "03P", "Tj", "YZ", "0zh", "4AF", "60m", "6ZI", "4oj", "0TD", "wv",
"0JF", "it", "6DK", "4qh", "5Oe", "6jg", "GX", "R9", "0iZ", "Jh", "5W4", "4Rt", "48P", "4i9", "dD", "0Gv", "0Hw", "kE", "4f8", "47Q",
"5MT", "5X5", "Ei", "12r", "0kk", "HY", "6ef", "4PE", "5nH", "6KJ", "fu", "0EG", "4Bm", "63F", "Zq", "0yC", "0Wo", "0U", "6Yb", "4lA",
"4aq", "5d1", "ym", "8SG", "0ts", "WA", "aPl", "b1f", "747", "61w", "2NQ", "1kS", "9Lg", "2d", "5k0", "4np", "57i", "6Vc", "2mM", "0Xn",
"02J", "Up", "6xO", "4Ml", "6fM", "4Sn", "1xa", "Kr", "27G", "47", "49J", "6Ha", "5u2", "44z", "8BD", "hn", "FB", "0ep", "bdm", "aAo",
"70U", "bkl", "0jq", "IC", "go", "306", "5oR", "5z3", "7WA", "46K", "0Im", "28F", "Ds", "0gA", "5LN", "6iL", "0cY", "020", "6mT", "4Xw",
"42S", "6Cx", "nG", "0Mu", "1Pd", "cw", "6NH", "5kJ", "4UG", "74M", "3Kk", "0ni", "0ah", "BZ", "6oe", "4ZF", "40b", "6AI", "lv", "0OD",
"0Bt", "aF", "6Ly", "4yZ", "4Wv", "5R6", "Oj", "0lX", "Qh", "06R", "4It", "5L4", "461", "4gX", "1LW", "1Y6", "rt", "0QF", "4jh", "7Oj",
"65o", "4DD", "I9", "2JI", "SY", "F8", "4KE", "7nG", "6PJ", "4ei", "1Nf", "2kd", "4M", "0Sw", "4hY", "490", "5C5", "4Fu", "09S", "2Hx",
"6OR", "4zq", "354", "bm", "LA", "0os", "bnn", "75W", "6lN", "4Ym", "0bC", "Aq", "2yL", "0Lo", "43I", "6Bb", "6Mc", "5ha", "15", "22E",
"Np", "0mB", "4Vl", "6cO", "aDm", "bao", "1pS", "1e2", "ml", "8GF", "41x", "548", "4kr", "5n2", "7f", "8YD", "1nQ", "2KS", "64u", "715",
"4Hn", "69E", "Pr", "07H", "1MM", "2hO", "6Sa", "4fB", "4iC", "7LA", "5W", "0Rm", "08I", "2Ib", "66D", "4Go", "b4d", "aUn", "RC", "05y",
"8VE", "8g", "5a3", "4ds", "42W", "ain", "nC", "0Mq", "17t", "024", "6mP", "4Xs", "4UC", "74I", "3Ko", "0nm", "8IY", "cs", "6NL", "5kN",
"40f", "6AM", "lr", "8FX", "0al", "2TO", "6oa", "4ZB", "4Wr", "5R2", "On", "18u", "0Bp", "aB", "afo", "bCm", "465", "53u", "1LS", "1Y2",
"Ql", "06V", "4Ip", "5L0", "65k", "5Ta", "1oO", "2JM", "6x", "0QB", "4jl", "7On", "6PN", "4em", "1Nb", "9y", "2EL", "04g", "4KA", "7nC",
"5C1", "4Fq", "09W", "d6G", "4I", "0Ss", "bRn", "494", "LE", "0ow", "4TY", "4A8", "6OV", "4zu", "1Qz", "bi", "oY", "z8", "43M", "6Bf",
"6lJ", "4Yi", "0bG", "Au", "Nt", "0mF", "4Vh", "6cK", "6Mg", "4xD", "11", "22A", "mh", "0NZ", "4ut", "5p4", "4N9", "5Ky", "1pW", "CD",
"1nU", "2KW", "64q", "4EZ", "4kv", "5n6", "7b", "0PX", "1MI", "2hK", "6Se", "4fF", "4Hj", "69A", "Pv", "07L", "08M", "2If", "6rH", "4Gk",
"4iG", "7LE", "5S", "0Ri", "1Ox", "8c", "5a7", "4dw", "5Zz", "7oY", "RG", "0qu", "1Pl", "21f", "adR", "5kB", "4UO", "74E", "MS", "X2",
"0cQ", "028", "79u", "bbL", "4vS", "4c2", "nO", "8De", "8Kd", "aN", "4l3", "4yR", "634", "76t", "Ob", "0lP", "W3", "BR", "6om", "4ZN",
"40j", "6AA", "2zo", "0OL", "6t", "0QN", "5zA", "7Ob", "65g", "4DL", "I1", "2JA", "0g3", "06Z", "b7G", "68W", "469", "4gP", "284", "dSn",
"4E", "275", "4hQ", "498", "67V", "b8F", "1mr", "0h2", "SQ", "F0", "4KM", "7nO", "6PB", "4ea", "1Nn", "9u", "6lF", "4Ye", "0bK", "Ay",
"oU", "z4", "43A", "6Bj", "6OZ", "4zy", "0AW", "be", "LI", "2O9", "4TU", "4A4", "4N5", "5Ku", "14S", "CH", "md", "0NV", "41p", "540",
"6Mk", "4xH", "u5", "22M", "Nx", "0mJ", "4Vd", "6cG", "4Hf", "69M", "Pz", "0sH", "k7", "2hG", "6Si", "4fJ", "4kz", "7Nx", "7n", "0PT",
"1nY", "dqh", "4P7", "4EV", "4JW", "7oU", "RK", "05q", "1Ot", "8o", "6QX", "50R", "4iK", "7LI", "qW", "d6", "08A", "2Ij", "66L", "4Gg",
"4UK", "74A", "MW", "X6", "1Ph", "21b", "6ND", "5kF", "4vW", "4c6", "nK", "0My", "0cU", "0v4", "6mX", "5HZ", "4Wz", "6bY", "Of", "0lT",
"0Bx", "aJ", "4l7", "4yV", "40n", "6AE", "lz", "0OH", "W7", "BV", "6oi", "4ZJ", "65c", "4DH", "I5", "2JE", "6p", "0QJ", "4jd", "7Of",
"4r5", "4gT", "280", "2iY", "Qd", "0rV", "4Ix", "5L8", "5C9", "4Fy", "1mv", "0h6", "4A", "1CZ", "4hU", "7MW", "6PF", "4ee", "1Nj", "9q",
"SU", "F4", "4KI", "7nK", "oQ", "z0", "43E", "6Bn", "6lB", "4Ya", "0bO", "2Wl", "LM", "8fg", "4TQ", "4A0", "aeL", "cPo", "0AS", "ba",
"3kP", "0NR", "41t", "544", "4N1", "5Kq", "14W", "CL", "2Xm", "0mN", "5FA", "6cC", "6Mo", "4xL", "19", "22I", "k3", "2hC", "6Sm", "4fN",
"4Hb", "69I", "2Fo", "07D", "83l", "d5d", "4P3", "4ER", "bQM", "a0G", "7j", "0PP", "1Op", "8k", "hbw", "50V", "4JS", "7oQ", "RO", "05u",
"08E", "2In", "66H", "4Gc", "4iO", "7LM", "qS", "d2", "0ay", "BK", "4O6", "4ZW", "40s", "553", "lg", "0OU", "t6", "aW", "6Lh", "4yK",
"4Wg", "6bD", "2Yj", "0lI", "0cH", "2Vk", "6mE", "4Xf", "42B", "6Ci", "nV", "0Md", "1Pu", "cf", "6NY", "bAI", "4UV", "7pT", "MJ", "0nx",
"SH", "04r", "4KT", "7nV", "azI", "4ex", "1Nw", "9l", "pT", "e5", "4hH", "7MJ", "67O", "4Fd", "09B", "2Hi", "Qy", "06C", "4Ie", "68N",
"6Rj", "4gI", "j4", "2iD", "6m", "0QW", "4jy", "5o9", "4Q4", "4DU", "1oZ", "2JX", "4m0", "4xQ", "8Jg", "22T", "Na", "0mS", "627", "77w",
"6nn", "5Kl", "V0", "CQ", "3kM", "0NO", "41i", "7Pc", "6OC", "5jA", "0AN", "20e", "LP", "Y1", "4TL", "6ao", "78v", "bcO", "0bR", "0w3",
"oL", "8Ef", "43X", "4b1", "4iR", "7LP", "5F", "266", "08X", "0i1", "66U", "b9E", "4JN", "7oL", "RR", "G3", "1Om", "8v", "6QA", "4db",
"4kc", "7Na", "7w", "0PM", "H2", "2KB", "64d", "4EO", "b6D", "69T", "Pc", "07Y", "297", "dRm", "4s2", "4fS", "40w", "557", "lc", "0OQ",
"15T", "BO", "4O2", "4ZS", "4Wc", "76i", "2Yn", "0lM", "t2", "aS", "6Ll", "4yO", "42F", "6Cm", "nR", "8Dx", "0cL", "2Vo", "6mA", "4Xb",
"4UR", "74X", "MN", "8gd", "1Pq", "cb", "adO", "bAM", "azM", "51U", "1Ns", "9h", "SL", "04v", "4KP", "7nR", "67K", "5VA", "09F", "2Hm",
"4X", "e1", "4hL", "7MN", "6Rn", "4gM", "j0", "3ya", "2Gl", "06G", "4Ia", "68J", "4Q0", "4DQ", "82o", "d4g", "6i", "0QS", "bPN", "a1D",
"Ne", "0mW", "4Vy", "5S9", "4m4", "4xU", "1SZ", "22P", "my", "0NK", "41m", "7Pg", "6nj", "5Kh", "V4", "CU", "LT", "Y5", "4TH", "6ak",
"6OG", "4zd", "0AJ", "bx", "oH", "0Lz", "4wT", "4b5", "78r", "4Yx", "0bV", "Ad", "1lu", "0i5", "66Q", "4Gz", "4iV", "7LT", "5B", "0Rx",
"1Oi", "8r", "6QE", "4df", "4JJ", "7oH", "RV", "G7", "H6", "2KF", "6ph", "4EK", "4kg", "7Ne", "7s", "0PI", "1MX", "1X9", "4s6", "4fW",
"5XZ", "69P", "Pg", "0sU", "06", "23F", "afr", "4yC", "4Wo", "6bL", "Os", "0lA", "0aq", "BC", "aEn", "c4E", "4ts", "5q3", "lo", "8FE",
"347", "cn", "6NQ", "5kS", "bom", "74T", "MB", "0np", "17i", "2Vc", "6mM", "4Xn", "42J", "6Ca", "2xO", "0Ml", "4T", "0Sn", "5xa", "7MB",
"67G", "4Fl", "09J", "2Ha", "1u2", "04z", "b5g", "aTm", "6PS", "4ep", "8WF", "9d", "6e", "8XG", "4jq", "5o1", "65v", "706", "1oR", "1z3",
"Qq", "06K", "4Im", "68F", "6Rb", "4gA", "1LN", "2iL", "6nf", "5Kd", "V8", "CY", "mu", "0NG", "41a", "7Pk", "4m8", "4xY", "0Cw", "1F7",
"Ni", "19r", "4Vu", "5S5", "6lW", "4Yt", "0bZ", "Ah", "oD", "0Lv", "43P", "4b9", "6OK", "4zh", "0AF", "bt", "LX", "Y9", "4TD", "6ag",
"4JF", "7oD", "RZ", "0qh", "1Oe", "2jg", "6QI", "4dj", "4iZ", "483", "5N", "0Rt", "08P", "0i9", "5B6", "4Gv", "4Hw", "5M7", "Pk", "07Q",
"1MT", "1X5", "472", "52r", "4kk", "7Ni", "sw", "0PE", "1nH", "2KJ", "64l", "4EG", "4Wk", "6bH", "Ow", "0lE", "02", "23B", "6Ld", "4yG",
"4tw", "5q7", "lk", "0OY", "0au", "BG", "6ox", "5Jz", "4UZ", "74P", "MF", "0nt", "1Py", "cj", "6NU", "5kW", "42N", "6Ce", "nZ", "0Mh",
"0cD", "2Vg", "6mI", "4Xj", "67C", "4Fh", "09N", "2He", "4P", "e9", "4hD", "7MF", "6PW", "4et", "3n9", "2ky", "SD", "0pv", "4KX", "7nZ",
"4Q8", "4DY", "1oV", "1z7", "6a", "1Az", "4ju", "5o5", "6Rf", "4gE", "j8", "2iH", "Qu", "06O", "4Ii", "68B", "mq", "0NC", "41e", "7Po",
"6nb", "bar", "14F", "2UL", "Nm", "19v", "4Vq", "5S1", "agl", "bBn", "0Cs", "1F3", "1I2", "0Lr", "43T", "ahm", "6lS", "4Yp", "16w", "Al",
"2ZM", "0on", "5Da", "6ac", "6OO", "4zl", "0AB", "bp", "1Oa", "8z", "6QM", "4dn", "4JB", "aUs", "2DO", "05d", "08T", "d7D", "5B2", "4Gr",
"bSm", "487", "5J", "0Rp", "1MP", "1X1", "476", "52v", "4Hs", "5M3", "Po", "07U", "1nL", "2KN", "64h", "4EC", "4ko", "7Nm", "ss", "0PA",
"QJ", "06p", "4IV", "7lT", "6RY", "4gz", "1Lu", "0I5", "rV", "g7", "4jJ", "7OH", "65M", "4Df", "1oi", "2Jk", "2Ej", "04A", "4Kg", "7ne",
"6Ph", "4eK", "h6", "2kF", "4o", "0SU", "5xZ", "7My", "4S6", "4FW", "09q", "1x9", "17R", "2VX", "4M4", "4XU", "42q", "571", "ne", "0MW",
"v4", "cU", "6Nj", "5kh", "4Ue", "74o", "My", "0nK", "0aJ", "Bx", "6oG", "4Zd", "4tH", "6Ak", "lT", "y5", "0BV", "ad", "580", "4yx",
"4WT", "4B5", "OH", "0lz", "4kP", "7NR", "7D", "244", "1ns", "0k3", "64W", "con", "4HL", "69g", "PP", "E1", "1Mo", "2hm", "6SC", "52I",
"4ia", "7Lc", "5u", "0RO", "J0", "3Ya", "66f", "4GM", "b4F", "aUL", "Ra", "0qS", "8Vg", "8E", "458", "4dQ", "4o2", "4zS", "8He", "bO",
"Lc", "0oQ", "605", "75u", "6ll", "4YO", "T2", "AS", "2yn", "0LM", "43k", "7Ra", "6MA", "4xb", "0CL", "22g", "NR", "19I", "4VN", "6cm",
"aDO", "baM", "14y", "Cb", "mN", "8Gd", "41Z", "7PP", "axO", "53W", "1Lq", "0I1", "QN", "06t", "4IR", "68y", "65I", "4Db", "1om", "2Jo",
"6Z", "g3", "4jN", "7OL", "6Pl", "4eO", "h2", "2kB", "2En", "04E", "4Kc", "7na", "4S2", "4FS", "09u", "d6e", "4k", "0SQ", "bRL", "a3F",
"42u", "575", "na", "0MS", "17V", "dlo", "4M0", "4XQ", "4Ua", "74k", "3KM", "0nO", "28", "cQ", "6Nn", "5kl", "40D", "6Ao", "lP", "y1",
"0aN", "2Tm", "6oC", "5JA", "4WP", "4B1", "OL", "18W", "0BR", "0W3", "584", "bCO", "1nw", "0k7", "64S", "4Ex", "4kT", "7NV", "sH", "0Pz",
"1Mk", "2hi", "6SG", "4fd", "4HH", "69c", "PT", "E5", "J4", "2ID", "66b", "4GI", "4ie", "7Lg", "5q", "0RK", "1OZ", "8A", "4q4", "4dU",
"4Jy", "5O9", "Re", "0qW", "Lg", "0oU", "5DZ", "6aX", "4o6", "4zW", "0Ay", "bK", "2yj", "0LI", "43o", "6BD", "6lh", "4YK", "T6", "AW",
"NV", "0md", "4VJ", "6ci", "6ME", "4xf", "0CH", "22c", "mJ", "0Nx", "4uV", "7PT", "6nY", "baI", "1pu", "Cf", "6V", "0Ql", "4jB", "aus",
"65E", "4Dn", "1oa", "2Jc", "QB", "06x", "b7e", "68u", "5b2", "4gr", "8UD", "dSL", "4g", "8ZE", "4hs", "5m3", "67t", "724", "09y", "1x1",
"Ss", "04I", "4Ko", "7nm", "azr", "4eC", "1NL", "9W", "24", "21D", "6Nb", "bAr", "4Um", "74g", "Mq", "0nC", "0cs", "1f3", "79W", "bbn",
"42y", "579", "nm", "394", "365", "al", "588", "4yp", "bmo", "76V", "1i2", "0lr", "0aB", "Bp", "6oO", "4Zl", "40H", "6Ac", "2zM", "0On",
"4HD", "69o", "PX", "E9", "1Mg", "2he", "6SK", "4fh", "4kX", "7NZ", "7L", "0Pv", "3N9", "2Ky", "6pW", "4Et", "4Ju", "5O5", "Ri", "05S",
"1OV", "8M", "450", "4dY", "4ii", "7Lk", "qu", "0RG", "J8", "2IH", "66n", "4GE", "6ld", "4YG", "0bi", "2WJ", "ow", "0LE", "43c", "6BH",
"6Ox", "5jz", "0Au", "bG", "Lk", "0oY", "4Tw", "5Q7", "6nU", "5KW", "14q", "Cj", "mF", "0Nt", "41R", "7PX", "6MI", "4xj", "0CD", "22o",
"NZ", "0mh", "4VF", "6ce", "65A", "4Dj", "1oe", "2Jg", "6R", "0Qh", "4jF", "7OD", "5b6", "4gv", "1Ly", "0I9", "QF", "0rt", "4IZ", "68q",
"67p", "5Vz", "1mT", "1x5", "4c", "0SY", "4hw", "5m7", "6Pd", "4eG", "1NH", "9S", "Sw", "04M", "4Kk", "7ni", "4Ui", "74c", "Mu", "0nG",
"20", "cY", "6Nf", "5kd", "4vu", "5s5", "ni", "390", "0cw", "1f7", "4M8", "4XY", "4WX", "4B9", "OD", "0lv", "0BZ", "ah", "6LW", "4yt",
"40L", "6Ag", "lX", "y9", "0aF", "Bt", "6oK", "4Zh", "1Mc", "2ha", "6SO", "4fl", "5Xa", "69k", "2FM", "07f", "83N", "d5F", "6pS", "4Ep",
"bQo", "a0e", "7H", "0Pr", "1OR", "8I", "454", "50t", "4Jq", "5O1", "Rm", "05W", "08g", "2IL", "66j", "4GA", "4im", "7Lo", "5y", "0RC",
"os", "0LA", "43g", "6BL", "78I", "4YC", "0bm", "2WN", "Lo", "8fE", "4Ts", "5Q3", "aen", "cPM", "0Aq", "bC", "mB", "0Np", "41V", "ajo",
"6nQ", "5KS", "14u", "Cn", "2XO", "0ml", "4VB", "6ca", "6MM", "4xn", "1Sa", "22k", "Sj", "04P", "4Kv", "5N6", "443", "4eZ", "1NU", "9N",
"pv", "0SD", "4hj", "7Mh", "67m", "4FF", "1mI", "2HK", "2GJ", "2", "4IG", "68l", "6RH", "4gk", "1Ld", "2if", "6O", "0Qu", "5zz", "7OY",
"5A7", "4Dw", "1ox", "0j8", "15r", "Bi", "6oV", "4Zu", "40Q", "4a8", "lE", "0Ow", "0BG", "au", "6LJ", "4yi", "4WE", "6bf", "OY", "Z8",
"U9", "2VI", "6mg", "4XD", "4vh", "6CK", "nt", "0MF", "1PW", "cD", "4n9", "5ky", "4Ut", "5P4", "Mh", "0nZ", "4ip", "5l0", "5d", "9Kg",
"08z", "1y2", "66w", "737", "4Jl", "7on", "Rp", "05J", "1OO", "8T", "6Qc", "50i", "4kA", "7NC", "7U", "0Po", "1nb", "dqS", "64F", "4Em",
"b6f", "69v", "PA", "0ss", "8TG", "dRO", "5c1", "4fq", "6MP", "4xs", "376", "22v", "NC", "0mq", "bll", "77U", "6nL", "5KN", "14h", "Cs",
"3ko", "0Nm", "41K", "7PA", "6Oa", "4zB", "37", "20G", "Lr", "8fX", "4Tn", "6aM", "78T", "bcm", "0bp", "AB", "on", "387", "43z", "5r2",
"447", "51w", "1NQ", "9J", "Sn", "04T", "4Kr", "5N2", "67i", "4FB", "09d", "2HO", "4z", "1Ca", "4hn", "7Ml", "6RL", "4go", "8UY", "2ib",
"2GN", "6", "4IC", "68h", "5A3", "4Ds", "82M", "d4E", "6K", "0Qq", "bPl", "a1f", "40U", "akl", "lA", "0Os", "15v", "Bm", "6oR", "4Zq",
"4WA", "6bb", "2YL", "0lo", "0BC", "aq", "6LN", "4ym", "42d", "6CO", "np", "0MB", "0cn", "2VM", "6mc", "5Ha", "4Up", "5P0", "Ml", "8gF",
"1PS", "1E2", "adm", "bAo", "1lW", "1y6", "4R9", "4GX", "4it", "5l4", "qh", "0RZ", "i9", "8P", "6Qg", "4dD", "4Jh", "7oj", "Rt", "05N",
"1nf", "2Kd", "64B", "4Ei", "4kE", "7NG", "7Q", "f8", "1Mz", "2hx", "5c5", "4fu", "4HY", "69r", "PE", "0sw", "NG", "0mu", "5Fz", "6cx",
"6MT", "4xw", "0CY", "0V8", "3kk", "0Ni", "41O", "7PE", "6nH", "5KJ", "14l", "Cw", "Lv", "0oD", "4Tj", "6aI", "6Oe", "4zF", "33", "bZ",
"oj", "0LX", "4wv", "5r6", "6ly", "4YZ", "0bt", "AF", "4v", "0SL", "4hb", "awS", "67e", "4FN", "K3", "2HC", "Sb", "04X", "b5E", "aTO",
"4p3", "4eR", "8Wd", "9F", "6G", "257", "4jS", "7OQ", "65T", "cnm", "1op", "0j0", "QS", "D2", "4IO", "68d", "7Ba", "4gc", "1Ll", "2in",
"0BO", "23d", "6LB", "4ya", "4WM", "6bn", "OQ", "Z0", "0aS", "Ba", "aEL", "c4g", "40Y", "4a0", "lM", "8Fg", "8If", "cL", "4n1", "5kq",
"616", "74v", "3KP", "0nR", "U1", "2VA", "6mo", "4XL", "42h", "6CC", "2xm", "0MN", "4Jd", "7of", "Rx", "05B", "i5", "2jE", "6Qk", "4dH",
"4ix", "5l8", "5l", "0RV", "08r", "2IY", "4R5", "4GT", "4HU", "7mW", "PI", "07s", "1Mv", "0H6", "5c9", "4fy", "4kI", "7NK", "sU", "f4",
"1nj", "2Kh", "64N", "4Ee", "6nD", "5KF", "1ph", "2Uj", "mW", "x6", "41C", "7PI", "593", "5hZ", "0CU", "0V4", "NK", "0my", "4VW", "4C6",
"4L7", "4YV", "0bx", "AJ", "of", "0LT", "43r", "562", "6Oi", "4zJ", "w7", "bV", "Lz", "0oH", "4Tf", "6aE", "67a", "4FJ", "K7", "2HG",
"4r", "0SH", "4hf", "7Md", "4p7", "4eV", "1NY", "9B", "Sf", "0pT", "4Kz", "7nx", "65P", "5TZ", "1ot", "0j4", "6C", "0Qy", "4jW", "7OU",
"6RD", "4gg", "1Lh", "2ij", "QW", "D6", "4IK", "7lI", "4WI", "6bj", "OU", "Z4", "0BK", "ay", "6LF", "4ye", "4tU", "4a4", "lI", "2o9",
"0aW", "Be", "6oZ", "4Zy", "4Ux", "5P8", "Md", "0nV", "8Ib", "cH", "4n5", "5ku", "42l", "6CG", "nx", "0MJ", "U5", "2VE", "6mk", "4XH",
"i1", "8X", "6Qo", "4dL", "5ZA", "7ob", "2Dm", "05F", "08v", "d7f", "4R1", "4GP", "bSO", "a2E", "5h", "0RR", "1Mr", "0H2", "ayL", "52T",
"4HQ", "69z", "PM", "07w", "1nn", "2Kl", "64J", "4Ea", "4kM", "7NO", "7Y", "f0", "mS", "x2", "41G", "7PM", "aDR", "5KB", "14d", "2Un",
"NO", "19T", "4VS", "4C2", "597", "bBL", "0CQ", "0V0", "ob", "0LP", "43v", "566", "4L3", "4YR", "16U", "AN", "2Zo", "0oL", "4Tb", "6aA",
"6Om", "4zN", "w3", "bR", "4oT", "4z5", "wH", "0Tz", "0zV", "Yd", "5D8", "4Ax", "4LH", "6yk", "TT", "A5", "0YJ", "zx", "6WG", "4bd",
"4me", "6XF", "1q", "0VK", "N4", "2MD", "62b", "4CI", "4Ny", "5K9", "Ve", "0uW", "1KZ", "xI", "4u4", "5pt", "4k6", "5nv", "0Ey", "fK",
"Hg", "0kU", "641", "6eX", "6hh", "5Mj", "P6", "EW", "29b", "0HI", "47o", "6FD", "6IE", "48n", "0GH", "dz", "JV", "0id", "4RJ", "6gi",
"6jY", "beI", "0dT", "Gf", "iJ", "0Jx", "4qV", "4d7", "UN", "02t", "4MR", "4X3", "a8G", "57W", "0XP", "0M1", "2Z", "c3", "4nN", "7KL",
"61I", "5PC", "1km", "2No", "2An", "00E", "4Oc", "7ja", "6Tl", "4aO", "l2", "yS", "0k", "0WQ", "58V", "a7F", "4W2", "4BS", "84m", "ZO",
"13V", "E", "4I0", "5Lp", "46u", "535", "ja", "0IS", "68", "gQ", "6Jn", "5ol", "4Qa", "6dB", "3OM", "0jO", "0eN", "2Pm", "6kC", "5NA",
"44D", "6Eo", "hP", "99", "0FR", "0S3", "abM", "49t", "4SP", "4F1", "KL", "8af", "0zR", "0o3", "60W", "ckn", "4oP", "4z1", "3D", "204",
"0YN", "2lm", "6WC", "56I", "4LL", "6yo", "TP", "A1", "N0", "903", "62f", "4CM", "4ma", "6XB", "1u", "0VO", "8Rg", "xM", "418", "54x",
"b0F", "aQL", "Va", "0uS", "Hc", "0kQ", "645", "71u", "4k2", "5nr", "8Le", "fO", "29f", "0HM", "47k", "7Va", "6hl", "5Mn", "P2", "ES",
"JR", "1yA", "4RN", "6gm", "6IA", "48j", "0GL", "26g", "iN", "8Cd", "45Z", "4d3", "hYv", "beM", "0dP", "Gb", "6VY", "4cz", "0XT", "0M5",
"UJ", "02p", "4MV", "4X7", "61M", "5PG", "1ki", "Xz", "vV", "c7", "4nJ", "7KH", "6Th", "4aK", "l6", "yW", "2Aj", "00A", "4Og", "6zD",
"4W6", "4BW", "0yy", "ZK", "0o", "0WU", "58R", "6YX", "46q", "531", "je", "0IW", "13R", "A", "4I4", "5Lt", "4Qe", "6dF", "Iy", "0jK",
"r4", "gU", "6Jj", "5oh", "4pH", "6Ek", "hT", "0Kf", "0eJ", "Fx", "6kG", "5NE", "4ST", "4F5", "KH", "0hz", "0FV", "ed", "5x8", "49p",
"bvs", "6yc", "2BM", "03f", "0YB", "zp", "6WO", "4bl", "bUo", "a4e", "3H", "0Tr", "87N", "Yl", "5D0", "4Ap", "4Nq", "5K1", "Vm", "01W",
"1KR", "xA", "414", "54t", "4mm", "6XN", "1y", "0VC", "0xo", "2ML", "62j", "4CA", "7xA", "5Mb", "0fm", "2SN", "ks", "0HA", "47g", "6FL",
"aan", "bDl", "0Eq", "fC", "Ho", "8bE", "4Ps", "5U3", "5Z2", "5OS", "10u", "Gn", "iB", "0Jp", "45V", "ano", "6IM", "48f", "1Wa", "dr",
"3Ln", "0il", "4RB", "6ga", "2R", "0Uh", "4nF", "7KD", "61A", "5PK", "1ke", "Xv", "UF", "0vt", "4MZ", "6xy", "5f6", "4cv", "0XX", "0M9",
"0c", "0WY", "4lw", "5i7", "63p", "5Rz", "0yu", "ZG", "Ww", "00M", "4Ok", "6zH", "6Td", "4aG", "0Zi", "2oJ", "60", "gY", "6Jf", "5od",
"4Qi", "6dJ", "Iu", "0jG", "0gw", "M", "4I8", "5Lx", "4ru", "5w5", "ji", "1Yz", "0FZ", "eh", "5x4", "5mU", "4SX", "4F9", "KD", "0hv",
"0eF", "Ft", "6kK", "5NI", "44L", "6Eg", "hX", "91", "0YF", "zt", "6WK", "4bh", "4LD", "6yg", "TX", "A9", "0zZ", "Yh", "5D4", "4At",
"4oX", "4z9", "3L", "0Tv", "1KV", "xE", "410", "54p", "4Nu", "5K5", "Vi", "01S", "N8", "2MH", "62n", "4CE", "4mi", "6XJ", "uu", "0VG",
"kw", "0HE", "47c", "6FH", "6hd", "5Mf", "0fi", "2SJ", "Hk", "0kY", "4Pw", "5U7", "6Kx", "5nz", "0Eu", "fG", "iF", "0Jt", "45R", "6Dy",
"5Z6", "5OW", "0dX", "Gj", "JZ", "0ih", "4RF", "6ge", "6II", "48b", "0GD", "dv", "61E", "5PO", "1ka", "Xr", "2V", "0Ul", "4nB", "aqs",
"5f2", "4cr", "8QD", "39V", "UB", "02x", "795", "aRo", "63t", "764", "0yq", "ZC", "0g", "9Nd", "4ls", "5i3", "7DA", "4aC", "0Zm", "2oN",
"Ws", "00I", "4Oo", "6zL", "4Qm", "6dN", "Iq", "0jC", "64", "25D", "6Jb", "bEr", "46y", "539", "jm", "9Pf", "0gs", "I", "aCl", "bfn",
"bio", "72V", "1m2", "0hr", "325", "el", "5x0", "49x", "44H", "6Ec", "3nl", "95", "0eB", "Fp", "6kO", "5NM", "4mt", "5h4", "uh", "0VZ",
"0xv", "2MU", "4V9", "4CX", "4Nh", "7kj", "Vt", "01N", "m9", "xX", "6Ug", "54m", "4oE", "6Zf", "3Q", "b8", "0zG", "Yu", "60B", "4Ai",
"4LY", "4Y8", "TE", "0ww", "1Iz", "zi", "5g5", "4bu", "5y7", "5lV", "0GY", "dk", "JG", "0iu", "5Bz", "6gx", "6jH", "5OJ", "0dE", "Gw",
"3ok", "82", "45O", "6Dd", "6Ke", "5ng", "73", "fZ", "Hv", "0kD", "4Pj", "6eI", "6hy", "7m9", "0ft", "EF", "kj", "0HX", "4sv", "5v6",
"Wn", "00T", "4Or", "5J2", "407", "55w", "0Zp", "yB", "0z", "1Ga", "4ln", "6YM", "63i", "4BB", "0yl", "2LO", "2CN", "02e", "4MC", "7hA",
"6VL", "4co", "0XA", "2mb", "2K", "0Uq", "bTl", "a5f", "5E3", "5PR", "86M", "Xo", "11v", "Fm", "6kR", "5NP", "44U", "aol", "hA", "0Ks",
"0FC", "eq", "6HN", "49e", "4SA", "6fb", "3Mm", "0ho", "0gn", "T", "6ic", "5La", "46d", "6GO", "jp", "0IB", "0Dr", "1A2", "hyT", "bEo",
"4Qp", "5T0", "Il", "8cF", "0xr", "2MQ", "62w", "777", "4mp", "5h0", "1d", "9Og", "1KO", "2nM", "6Uc", "54i", "4Nl", "7kn", "Vp", "01J",
"0zC", "Yq", "60F", "4Am", "4oA", "6Zb", "3U", "0To", "8PG", "zm", "5g1", "4bq", "786", "aSl", "TA", "0ws", "JC", "0iq", "bhl", "73U",
"5y3", "5lR", "336", "do", "3oo", "86", "45K", "7TA", "6jL", "5ON", "0dA", "Gs", "Hr", "8bX", "4Pn", "6eM", "6Ka", "5nc", "77", "24G",
"kn", "8AD", "47z", "5v2", "aBo", "bgm", "0fp", "EB", "403", "4aZ", "0Zt", "yF", "Wj", "00P", "4Ov", "5J6", "63m", "4BF", "0yh", "ZZ",
"tv", "0WD", "4lj", "6YI", "6VH", "4ck", "0XE", "2mf", "2CJ", "02a", "4MG", "6xd", "5E7", "5PV", "1kx", "Xk", "2O", "0Uu", "bTh", "7KY",
"44Q", "4e8", "hE", "0Kw", "11r", "Fi", "6kV", "5NT", "4SE", "6ff", "KY", "0hk", "0FG", "eu", "6HJ", "49a", "4rh", "6GK", "jt", "0IF",
"Q9", "P", "6ig", "5Le", "4Qt", "5T4", "Ih", "0jZ", "0Dv", "gD", "4j9", "5oy", "aD0", "7kb", "3PL", "01F", "m1", "xP", "6Uo", "54e",
"59U", "a6E", "1h", "0VR", "85n", "196", "4V1", "4CP", "4LQ", "4Y0", "TM", "03w", "0YS", "za", "a9D", "56T", "4oM", "6Zn", "3Y", "b0",
"0zO", "2Ol", "60J", "4Aa", "7za", "5OB", "0dM", "2Qn", "iS", "0Ja", "45G", "6Dl", "acN", "48w", "0GQ", "dc", "JO", "94L", "4RS", "4G2",
"4H3", "5Ms", "12U", "EN", "kb", "0HP", "47v", "526", "6Km", "5no", "s3", "fR", "3NN", "0kL", "4Pb", "6eA", "0r", "0WH", "4lf", "6YE",
"63a", "4BJ", "O7", "ZV", "Wf", "0tT", "4Oz", "6zY", "4t7", "4aV", "0Zx", "yJ", "2C", "0Uy", "4nW", "7KU", "61P", "5PZ", "1kt", "Xg",
"UW", "02m", "4MK", "6xh", "6VD", "4cg", "0XI", "2mj", "0FK", "ey", "6HF", "49m", "4SI", "6fj", "KU", "0hg", "0eW", "Fe", "6kZ", "5NX",
"4pU", "4e4", "hI", "2k9", "0Dz", "gH", "4j5", "5ou", "4Qx", "5T8", "Id", "0jV", "Q5", "DT", "6ik", "5Li", "46l", "6GG", "jx", "0IJ",
"m5", "xT", "6Uk", "54a", "4Nd", "7kf", "Vx", "01B", "0xz", "192", "4V5", "4CT", "4mx", "5h8", "1l", "0VV", "0YW", "ze", "5g9", "4by",
"4LU", "4Y4", "TI", "03s", "0zK", "Yy", "60N", "4Ae", "4oI", "6Zj", "wU", "b4", "iW", "0Je", "45C", "6Dh", "6jD", "5OF", "0dI", "2Qj",
"JK", "0iy", "4RW", "4G6", "6IX", "48s", "0GU", "dg", "kf", "0HT", "47r", "522", "4H7", "5Mw", "0fx", "EJ", "Hz", "0kH", "4Pf", "6eE",
"6Ki", "5nk", "s7", "fV", "63e", "4BN", "O3", "ZR", "0v", "0WL", "4lb", "6YA", "4t3", "4aR", "8Sd", "yN", "Wb", "00X", "b1E", "aPO",
"61T", "bzL", "1kp", "Xc", "2G", "217", "4nS", "7KQ", "7Fa", "4cc", "0XM", "2mn", "US", "02i", "4MO", "6xl", "4SM", "6fn", "KQ", "0hc",
"0FO", "27d", "6HB", "49i", "44Y", "4e0", "hM", "8Bg", "0eS", "Fa", "aAL", "bdN", "656", "70v", "3OP", "0jR", "8Mf", "gL", "4j1", "5oq",
"46h", "6GC", "28e", "0IN", "Q1", "X", "6io", "5Lm", "6KV", "5nT", "1Uz", "fi", "HE", "0kw", "4PY", "4E8", "6hJ", "5MH", "0fG", "Eu",
"kY", "0Hk", "47M", "6Ff", "6Ig", "48L", "51", "dX", "Jt", "0iF", "4Rh", "6gK", "4J9", "5Oy", "0dv", "GD", "ih", "0JZ", "4qt", "5t4",
"4ov", "5j6", "3b", "0TX", "0zt", "YF", "60q", "4AZ", "4Lj", "6yI", "Tv", "03L", "0Yh", "zZ", "6We", "4bF", "4mG", "6Xd", "1S", "0Vi",
"0xE", "2Mf", "6vH", "4Ck", "bth", "7kY", "VG", "0uu", "1Kx", "xk", "5e7", "5pV", "13t", "g", "5Y3", "5LR", "46W", "amn", "jC", "0Iq",
"0DA", "gs", "6JL", "5oN", "4QC", "70I", "3Oo", "0jm", "0el", "2PO", "6ka", "5Nc", "44f", "6EM", "hr", "8BX", "0Fp", "eB", "abo", "49V",
"4Sr", "5V2", "Kn", "8aD", "Ul", "02V", "4Mp", "5H0", "425", "57u", "0Xr", "2mQ", "2x", "0UB", "4nl", "7Kn", "61k", "5Pa", "1kO", "2NM",
"2AL", "00g", "4OA", "6zb", "6TN", "4am", "0ZC", "yq", "0I", "0Ws", "58t", "a7d", "5G1", "4Bq", "84O", "Zm", "HA", "0ks", "bjn", "71W",
"6KR", "5nP", "314", "fm", "29D", "0Ho", "47I", "6Fb", "6hN", "5ML", "0fC", "Eq", "Jp", "0iB", "4Rl", "6gO", "6Ic", "48H", "55", "26E",
"il", "8CF", "45x", "508", "hYT", "beo", "0dr", "1a2", "0zp", "YB", "60u", "755", "4or", "5j2", "3f", "9Me", "0Yl", "2lO", "6Wa", "4bB",
"4Ln", "6yM", "Tr", "03H", "0xA", "2Mb", "62D", "4Co", "4mC", "7HA", "1W", "0Vm", "8RE", "xo", "5e3", "54Z", "b0d", "aQn", "VC", "01y",
"46S", "6Gx", "jG", "0Iu", "0gY", "c", "5Y7", "5LV", "4QG", "6dd", "3Ok", "0ji", "0DE", "gw", "6JH", "5oJ", "44b", "6EI", "hv", "0KD",
"0eh", "FZ", "6ke", "5Ng", "4Sv", "5V6", "Kj", "0hX", "0Ft", "eF", "6Hy", "49R", "421", "4cX", "0Xv", "2mU", "Uh", "02R", "4Mt", "5H4",
"61o", "5Pe", "M9", "XX", "vt", "0UF", "4nh", "7Kj", "6TJ", "4ai", "0ZG", "yu", "WY", "B8", "4OE", "6zf", "5G5", "4Bu", "1iz", "Zi",
"0M", "0Ww", "4lY", "4y8", "6hB", "aW1", "0fO", "2Sl", "kQ", "0Hc", "47E", "6Fn", "aaL", "bDN", "0ES", "fa", "HM", "8bg", "4PQ", "4E0",
"4J1", "5Oq", "10W", "GL", "3oP", "0JR", "45t", "504", "6Io", "48D", "59", "dP", "3LL", "0iN", "5BA", "6gC", "4Lb", "6yA", "2Bo", "03D",
"o3", "zR", "6Wm", "4bN", "bUM", "a4G", "3j", "0TP", "87l", "YN", "4T3", "4AR", "4NS", "7kQ", "VO", "01u", "1Kp", "xc", "hfw", "54V",
"4mO", "6Xl", "uS", "0Va", "0xM", "2Mn", "62H", "4Cc", "0DI", "25b", "6JD", "5oF", "4QK", "6dh", "IW", "0je", "0gU", "o", "6iX", "5LZ",
"4rW", "4g6", "jK", "0Iy", "0Fx", "eJ", "4h7", "5mw", "4Sz", "6fY", "Kf", "0hT", "S7", "FV", "6ki", "5Nk", "44n", "6EE", "hz", "0KH",
"2p", "0UJ", "4nd", "7Kf", "61c", "5Pi", "M5", "XT", "Ud", "0vV", "4Mx", "5H8", "4v5", "4cT", "0Xz", "2mY", "0A", "1GZ", "4lU", "4y4",
"5G9", "4By", "0yW", "Ze", "WU", "B4", "4OI", "6zj", "6TF", "4ae", "0ZK", "yy", "kU", "0Hg", "47A", "6Fj", "6hF", "5MD", "0fK", "Ey",
"HI", "2K9", "4PU", "4E4", "6KZ", "5nX", "0EW", "fe", "id", "0JV", "45p", "500", "4J5", "5Ou", "0dz", "GH", "Jx", "0iJ", "4Rd", "6gG",
"6Ik", "5li", "q5", "dT", "o7", "zV", "6Wi", "4bJ", "4Lf", "6yE", "Tz", "0wH", "0zx", "YJ", "4T7", "4AV", "4oz", "6ZY", "3n", "0TT",
"1Kt", "xg", "6UX", "54R", "4NW", "7kU", "VK", "01q", "0xI", "2Mj", "62L", "4Cg", "4mK", "6Xh", "uW", "0Ve", "4QO", "6dl", "IS", "0ja",
"0DM", "25f", "7Za", "5oB", "4rS", "4g2", "jO", "9PD", "0gQ", "k", "aCN", "685", "674", "72t", "Kb", "0hP", "8Od", "eN", "4h3", "49Z",
"44j", "6EA", "3nN", "0KL", "S3", "FR", "6km", "5No", "61g", "5Pm", "M1", "XP", "2t", "0UN", "ad0", "7Kb", "429", "4cP", "8Qf", "39t",
"0c3", "02Z", "b3G", "aRM", "63V", "bxN", "0yS", "Za", "0E", "235", "4lQ", "4y0", "6TB", "4aa", "0ZO", "2ol", "WQ", "B0", "4OM", "6zn",
"4i4", "5lt", "1WZ", "dI", "Je", "0iW", "4Ry", "5W9", "6jj", "5Oh", "R4", "GU", "iy", "0JK", "45m", "6DF", "6KG", "5nE", "0EJ", "fx",
"HT", "0kf", "4PH", "6ek", "5X8", "5MY", "0fV", "Ed", "kH", "0Hz", "4sT", "4f5", "4mV", "4x7", "1B", "0Vx", "0xT", "0m5", "62Q", "4Cz",
"4NJ", "7kH", "VV", "C7", "1Ki", "xz", "6UE", "54O", "4og", "6ZD", "3s", "0TI", "L6", "YW", "6th", "4AK", "6l9", "6yX", "Tg", "0wU",
"0Yy", "zK", "4w6", "4bW", "11T", "FO", "4K2", "5Nr", "44w", "517", "hc", "0KQ", "p2", "eS", "6Hl", "49G", "4Sc", "72i", "3MO", "0hM",
"0gL", "v", "6iA", "5LC", "46F", "6Gm", "jR", "1YA", "0DP", "gb", "hyv", "bEM", "4QR", "4D3", "IN", "8cd", "WL", "00v", "4OP", "4Z1",
"hgt", "55U", "0ZR", "0O3", "0X", "a1", "4lL", "6Yo", "63K", "5RA", "0yN", "2Lm", "2Cl", "02G", "4Ma", "6xB", "6Vn", "4cM", "n0", "39i",
"2i", "0US", "bTN", "a5D", "4U0", "5Pp", "86o", "XM", "Ja", "0iS", "667", "73w", "4i0", "48Y", "8Ng", "dM", "3oM", "0JO", "45i", "6DB",
"6jn", "5Ol", "R0", "GQ", "HP", "0kb", "4PL", "6eo", "6KC", "5nA", "0EN", "24e", "kL", "8Af", "47X", "4f1", "aBM", "696", "0fR", "0s3",
"0xP", "0m1", "62U", "byM", "4mR", "4x3", "1F", "226", "1Km", "2no", "6UA", "54K", "4NN", "7kL", "VR", "C3", "L2", "YS", "60d", "4AO",
"4oc", "7Ja", "3w", "0TM", "8Pe", "zO", "4w2", "4bS", "b2D", "aSN", "Tc", "03Y", "44s", "513", "hg", "0KU", "0ey", "FK", "4K6", "5Nv",
"4Sg", "6fD", "3MK", "0hI", "p6", "eW", "6Hh", "49C", "46B", "6Gi", "jV", "0Id", "0gH", "r", "6iE", "5LG", "4QV", "4D7", "IJ", "0jx",
"0DT", "gf", "6JY", "bEI", "5d8", "4ax", "0ZV", "yd", "WH", "00r", "4OT", "4Z5", "63O", "4Bd", "0yJ", "Zx", "tT", "a5", "4lH", "6Yk",
"6Vj", "4cI", "n4", "2mD", "Uy", "02C", "4Me", "6xF", "4U4", "5Pt", "1kZ", "XI", "2m", "0UW", "4ny", "5k9", "6jb", "ber", "0do", "2QL",
"iq", "0JC", "45e", "6DN", "acl", "48U", "0Gs", "dA", "Jm", "94n", "4Rq", "5W1", "5X0", "5MQ", "12w", "El", "1M2", "0Hr", "47T", "alm",
"6KO", "5nM", "0EB", "fp", "3Nl", "0kn", "bjs", "6ec", "4NB", "aQs", "3Pn", "01d", "1Ka", "xr", "6UM", "54G", "59w", "a6g", "1J", "0Vp",
"85L", "d3D", "5F2", "4Cr", "4Ls", "5I3", "To", "03U", "0Yq", "zC", "436", "56v", "4oo", "6ZL", "ws", "0TA", "0zm", "2ON", "60h", "4AC",
"42", "27B", "6Hd", "49O", "4Sk", "6fH", "Kw", "0hE", "0eu", "FG", "6kx", "5Nz", "4pw", "5u7", "hk", "0KY", "0DX", "gj", "5z6", "5oW",
"4QZ", "6dy", "IF", "0jt", "0gD", "Dv", "6iI", "5LK", "46N", "6Ge", "jZ", "0Ih", "0P", "a9", "4lD", "6Yg", "63C", "4Bh", "0yF", "Zt",
"WD", "0tv", "4OX", "4Z9", "5d4", "4at", "0ZZ", "yh", "2a", "1Ez", "4nu", "5k5", "4U8", "5Px", "1kV", "XE", "Uu", "02O", "4Mi", "6xJ",
"6Vf", "4cE", "n8", "2mH", "iu", "0JG", "45a", "6DJ", "6jf", "5Od", "R8", "GY", "Ji", "1yz", "4Ru", "5W5", "4i8", "48Q", "0Gw", "dE",
"kD", "0Hv", "47P", "4f9", "5X4", "5MU", "0fZ", "Eh", "HX", "0kj", "4PD", "6eg", "6KK", "5nI", "0EF", "ft", "1Ke", "xv", "6UI", "54C",
"4NF", "7kD", "VZ", "0uh", "0xX", "0m9", "5F6", "4Cv", "4mZ", "6Xy", "1N", "0Vt", "0Yu", "zG", "432", "56r", "4Lw", "5I7", "Tk", "03Q",
"0zi", "2OJ", "60l", "4AG", "4ok", "6ZH", "ww", "0TE", "4So", "6fL", "Ks", "0hA", "46", "27F", "7XA", "49K", "4ps", "5u3", "ho", "8BE",
"0eq", "FC", "aAn", "bdl", "bkm", "70T", "IB", "0jp", "307", "gn", "5z2", "5oS", "46J", "6Ga", "28G", "0Il", "13i", "z", "6iM", "5LO",
"63G", "4Bl", "0yB", "Zp", "0T", "0Wn", "58i", "6Yc", "5d0", "4ap", "8SF", "yl", "1q2", "00z", "b1g", "aPm", "61v", "746", "1kR", "XA",
"2e", "9Lf", "4nq", "5k1", "6Vb", "4cA", "0Xo", "2mL", "Uq", "02K", "4Mm", "6xN", "8YG", "7e", "5n1", "4kq", "716", "64v", "2KP", "1nR",
"07K", "Pq", "69F", "4Hm", "4fA", "6Sb", "2hL", "1MN", "0Rn", "5T", "7LB", "5ya", "4Gl", "66G", "2Ia", "08J", "05z", "1t2", "aUm", "b4g",
"4dp", "5a0", "8d", "8VF", "bn", "357", "4zr", "6OQ", "75T", "bnm", "0op", "LB", "Ar", "16i", "4Yn", "6lM", "6Ba", "43J", "0Ll", "2yO",
"22F", "16", "4xC", "agr", "6cL", "4Vo", "0mA", "Ns", "CC", "14X", "bal", "aDn", "5p3", "4us", "8GE", "mo", "5L7", "4Iw", "06Q", "Qk",
"1Y5", "1LT", "53r", "462", "7Oi", "4jk", "0QE", "rw", "2JJ", "1oH", "4DG", "65l", "7nD", "4KF", "0ph", "SZ", "2kg", "1Ne", "4ej", "6PI",
"493", "4hZ", "0St", "4N", "0h9", "09P", "4Fv", "5C6", "4Xt", "6mW", "023", "0cZ", "0Mv", "nD", "4c9", "42P", "5kI", "6NK", "ct", "1Pg",
"X9", "MX", "74N", "4UD", "4ZE", "6of", "BY", "W8", "0OG", "lu", "6AJ", "40a", "4yY", "4l8", "aE", "0Bw", "18r", "Oi", "5R5", "4Wu",
"4EY", "4P8", "2KT", "1nV", "8YC", "7a", "5n5", "4ku", "4fE", "6Sf", "2hH", "k8", "07O", "Pu", "69B", "4Hi", "4Gh", "66C", "2Ie", "08N",
"d9", "5P", "7LF", "4iD", "4dt", "5a4", "2jy", "3o9", "0qv", "RD", "7oZ", "4JX", "6ay", "4TZ", "0ot", "LF", "bj", "0AX", "4zv", "6OU",
"6Be", "43N", "0Lh", "oZ", "Av", "0bD", "4Yj", "6lI", "6cH", "4Vk", "0mE", "Nw", "22B", "12", "4xG", "6Md", "5p7", "4uw", "0NY", "mk",
"CG", "1pT", "5Kz", "6nx", "1Y1", "1LP", "53v", "466", "5L3", "4Is", "06U", "Qo", "2JN", "1oL", "4DC", "65h", "7Om", "4jo", "0QA", "rs",
"9z", "1Na", "4en", "6PM", "aTs", "4KB", "04d", "2EO", "d6D", "09T", "4Fr", "5C2", "497", "bRm", "0Sp", "4J", "0Mr", "1H2", "aim", "42T",
"4Xp", "6mS", "027", "17w", "0nn", "3Kl", "74J", "5Ea", "5kM", "6NO", "cp", "1Pc", "0OC", "lq", "6AN", "40e", "4ZA", "6ob", "2TL", "0ao",
"18v", "Om", "5R1", "4Wq", "bCn", "afl", "aA", "0Bs", "07C", "Py", "69N", "4He", "4fI", "6Sj", "2hD", "k4", "0PW", "7m", "5n9", "4ky",
"4EU", "4P4", "2KX", "1nZ", "05r", "RH", "7oV", "4JT", "4dx", "5a8", "8l", "1Ow", "d5", "qT", "7LJ", "4iH", "4Gd", "66O", "2Ii", "08B",
"Az", "0bH", "4Yf", "6lE", "6Bi", "43B", "z7", "oV", "bf", "0AT", "4zz", "6OY", "4A7", "4TV", "0ox", "LJ", "CK", "14P", "5Kv", "4N6",
"543", "41s", "0NU", "mg", "22N", "u6", "4xK", "6Mh", "6cD", "4Vg", "0mI", "2Xj", "7Oa", "4jc", "0QM", "6w", "2JB", "I2", "4DO", "65d",
"68T", "b7D", "06Y", "Qc", "dSm", "287", "4gS", "4r2", "7MP", "4hR", "276", "4F", "0h1", "09X", "b8E", "67U", "7nL", "4KN", "F3", "SR",
"9v", "1Nm", "4eb", "6PA", "5kA", "6NC", "21e", "1Po", "X1", "MP", "74F", "4UL", "bbO", "79v", "0v3", "0cR", "8Df", "nL", "4c1", "42X",
"4yQ", "4l0", "aM", "8Kg", "0lS", "Oa", "76w", "637", "4ZM", "6on", "BQ", "W0", "0OO", "2zl", "6AB", "40i", "4fM", "6Sn", "3xa", "k0",
"07G", "2Fl", "69J", "4Ha", "4EQ", "4P0", "d5g", "83o", "0PS", "7i", "a0D", "bQN", "50U", "hbt", "8h", "1Os", "05v", "RL", "7oR", "4JP",
"5WA", "66K", "2Im", "08F", "d1", "5X", "7LN", "4iL", "6Bm", "43F", "z3", "oR", "2Wo", "0bL", "4Yb", "6lA", "4A3", "4TR", "8fd", "LN",
"bb", "0AP", "cPl", "aeO", "547", "41w", "0NQ", "mc", "CO", "14T", "5Kr", "4N2", "77i", "4Vc", "0mM", "2Xn", "22J", "u2", "4xO", "6Ml",
"2JF", "I6", "4DK", "6qh", "7Oe", "4jg", "0QI", "6s", "1Y9", "1LX", "4gW", "4r6", "68P", "5YZ", "0rU", "Qg", "0h5", "1mu", "4Fz", "67Q",
"7MT", "4hV", "0Sx", "4B", "9r", "1Ni", "4ef", "6PE", "7nH", "4KJ", "F7", "SV", "X5", "MT", "74B", "4UH", "5kE", "6NG", "cx", "1Pk",
"0Mz", "nH", "4c5", "4vT", "4Xx", "79r", "0v7", "0cV", "0lW", "Oe", "5R9", "4Wy", "4yU", "4l4", "aI", "1RZ", "0OK", "ly", "6AF", "40m",
"4ZI", "6oj", "BU", "W4", "265", "5E", "488", "4iQ", "b9F", "66V", "0i2", "1lr", "G0", "RQ", "7oO", "4JM", "4da", "6QB", "8u", "1On",
"0PN", "7t", "7Nb", "aa0", "4EL", "64g", "2KA", "H1", "07Z", "0f3", "69W", "b6G", "4fP", "479", "dRn", "294", "22W", "8Jd", "4xR", "4m3",
"77t", "624", "0mP", "Nb", "CR", "V3", "5Ko", "6nm", "ajS", "41j", "0NL", "3kN", "20f", "0AM", "4zc", "aeR", "6al", "4TO", "Y2", "LS",
"Ac", "0bQ", "bcL", "78u", "4b2", "4wS", "8Ee", "oO", "7nU", "4KW", "04q", "SK", "9o", "1Nt", "51R", "6PX", "7MI", "4hK", "e6", "pW",
"2Hj", "09A", "4Fg", "67L", "68M", "4If", "0rH", "Qz", "2iG", "j7", "4gJ", "6Ri", "7Ox", "4jz", "0QT", "6n", "1z8", "1oY", "4DV", "4Q7",
"4ZT", "4O5", "BH", "0az", "0OV", "ld", "550", "40p", "4yH", "6Lk", "aT", "t5", "0lJ", "Ox", "6bG", "4Wd", "4Xe", "6mF", "2Vh", "0cK",
"0Mg", "nU", "6Cj", "42A", "5kX", "6NZ", "ce", "1Pv", "2N9", "MI", "7pW", "4UU", "4Gy", "5B9", "0i6", "1lv", "1BZ", "5A", "7LW", "4iU",
"4de", "6QF", "8q", "1Oj", "G4", "RU", "7oK", "4JI", "4EH", "64c", "2KE", "H5", "0PJ", "7p", "7Nf", "4kd", "4fT", "4s5", "2hY", "290",
"0sV", "Pd", "5M8", "4Hx", "6cY", "4Vz", "0mT", "Nf", "1F8", "0Cx", "4xV", "4m7", "7Pd", "41n", "0NH", "mz", "CV", "V7", "5Kk", "6ni",
"6ah", "4TK", "Y6", "LW", "20b", "0AI", "4zg", "6OD", "4b6", "4wW", "0Ly", "oK", "Ag", "0bU", "5IZ", "6lX", "9k", "1Np", "51V", "azN",
"7nQ", "4KS", "04u", "SO", "2Hn", "09E", "4Fc", "67H", "7MM", "4hO", "e2", "pS", "2iC", "j3", "4gN", "6Rm", "68I", "4Ib", "06D", "2Go",
"d4d", "82l", "4DR", "4Q3", "a1G", "bPM", "0QP", "6j", "0OR", "0Z3", "554", "40t", "4ZP", "4O1", "BL", "15W", "0lN", "2Ym", "6bC", "5GA",
"4yL", "6Lo", "aP", "09", "0Mc", "nQ", "6Cn", "42E", "4Xa", "6mB", "2Vl", "0cO", "8gg", "MM", "7pS", "4UQ", "bAN", "adL", "ca", "1Pr",
"G8", "RY", "7oG", "4JE", "4di", "6QJ", "2jd", "1Of", "0Rw", "5M", "480", "4iY", "4Gu", "5B5", "2Ix", "08S", "07R", "Ph", "5M4", "4Ht",
"4fX", "471", "1X6", "1MW", "0PF", "st", "7Nj", "4kh", "4ED", "64o", "2KI", "H9", "CZ", "14A", "5Kg", "6ne", "7Ph", "41b", "0ND", "mv",
"1F4", "0Ct", "4xZ", "6My", "5S6", "4Vv", "0mX", "Nj", "Ak", "0bY", "4Yw", "6lT", "6Bx", "43S", "0Lu", "oG", "bw", "0AE", "4zk", "6OH",
"6ad", "4TG", "0oi", "2ZJ", "7MA", "4hC", "0Sm", "4W", "2Hb", "09I", "4Fo", "67D", "aTn", "b5d", "04y", "SC", "9g", "8WE", "4es", "6PP",
"5o2", "4jr", "8XD", "6f", "1z0", "1oQ", "705", "65u", "68E", "4In", "06H", "Qr", "2iO", "1LM", "4gB", "6Ra", "5ia", "6Lc", "23E", "05",
"0lB", "Op", "6bO", "4Wl", "c4F", "aEm", "1d2", "0ar", "8FF", "ll", "558", "40x", "5kP", "6NR", "cm", "344", "0ns", "MA", "74W", "bon",
"4Xm", "6mN", "3FA", "0cC", "0Mo", "2xL", "6Cb", "42I", "4dm", "6QN", "8y", "1Ob", "05g", "2DL", "7oC", "4JA", "4Gq", "5B1", "d7G", "08W",
"0Rs", "5I", "484", "bSn", "52u", "475", "1X2", "1MS", "07V", "Pl", "5M0", "4Hp", "5Ua", "64k", "2KM", "1nO", "0PB", "7x", "7Nn", "4kl",
"7Pl", "41f", "8GX", "mr", "2UO", "14E", "5Kc", "6na", "5S2", "4Vr", "19u", "Nn", "1F0", "0Cp", "bBm", "ago", "ahn", "43W", "0Lq", "oC",
"Ao", "16t", "4Ys", "6lP", "75I", "4TC", "0om", "2ZN", "bs", "0AA", "4zo", "6OL", "2Hf", "09M", "4Fk", "6sH", "7ME", "4hG", "0Si", "4S",
"9c", "1Nx", "4ew", "6PT", "7nY", "bqh", "0pu", "SG", "1z4", "1oU", "4DZ", "65q", "5o6", "4jv", "0QX", "6b", "2iK", "1LI", "4gF", "6Re",
"68A", "4Ij", "06L", "Qv", "0lF", "Ot", "6bK", "4Wh", "4yD", "6Lg", "aX", "01", "0OZ", "lh", "5q4", "4tt", "4ZX", "4O9", "BD", "0av",
"0nw", "ME", "74S", "4UY", "5kT", "6NV", "ci", "1Pz", "0Mk", "nY", "6Cf", "42M", "4Xi", "6mJ", "2Vd", "0cG", "bL", "8Hf", "4zP", "4o1",
"75v", "606", "0oR", "0z3", "AP", "T1", "4YL", "6lo", "6BC", "43h", "0LN", "2ym", "22d", "0CO", "4xa", "6MB", "6cn", "4VM", "0mc", "NQ",
"Ca", "14z", "baN", "aDL", "7PS", "41Y", "8Gg", "mM", "247", "7G", "7NQ", "4kS", "com", "64T", "0k0", "1np", "E2", "PS", "69d", "4HO",
"4fc", "7Ca", "2hn", "1Ml", "0RL", "5v", "avS", "4ib", "4GN", "66e", "2IC", "J3", "05X", "Rb", "aUO", "b4E", "4dR", "4q3", "8F", "8Vd",
"4XV", "4M7", "1f8", "0cx", "0MT", "nf", "572", "42r", "5kk", "6Ni", "cV", "v7", "0nH", "Mz", "74l", "4Uf", "4Zg", "6oD", "2Tj", "0aI",
"y6", "lW", "6Ah", "40C", "5iZ", "583", "ag", "0BU", "0ly", "OK", "4B6", "4WW", "7lW", "4IU", "06s", "QI", "0I6", "1Lv", "4gy", "5b9",
"7OK", "4jI", "g4", "rU", "2Jh", "1oj", "4De", "65N", "7nf", "4Kd", "04B", "Sx", "2kE", "h5", "4eH", "6Pk", "5m8", "4hx", "0SV", "4l",
"2HY", "09r", "4FT", "4S5", "5Q8", "4Tx", "0oV", "Ld", "bH", "0Az", "4zT", "4o5", "6BG", "43l", "0LJ", "ox", "AT", "T5", "4YH", "6lk",
"6cj", "4VI", "0mg", "NU", "2vh", "0CK", "4xe", "6MF", "7PW", "4uU", "2n9", "mI", "Ce", "1pv", "5KX", "6nZ", "5UZ", "64P", "0k4", "1nt",
"0Py", "7C", "7NU", "4kW", "4fg", "6SD", "2hj", "1Mh", "E6", "PW", "7mI", "4HK", "4GJ", "66a", "2IG", "J7", "0RH", "5r", "7Ld", "4if",
"4dV", "4q7", "8B", "1OY", "0qT", "Rf", "7ox", "4Jz", "0MP", "nb", "576", "42v", "4XR", "4M3", "dll", "17U", "0nL", "3KN", "74h", "4Ub",
"5ko", "6Nm", "cR", "v3", "y2", "lS", "6Al", "40G", "4Zc", "aER", "2Tn", "0aM", "18T", "OO", "4B2", "4WS", "bCL", "587", "ac", "0BQ",
"0I2", "1Lr", "53T", "axL", "68z", "4IQ", "06w", "QM", "2Jl", "1on", "4Da", "65J", "7OO", "4jM", "g0", "6Y", "9X", "h1", "4eL", "6Po",
"7nb", "aA0", "04F", "2Em", "d6f", "09v", "4FP", "4S1", "a3E", "bRO", "0SR", "4h", "AX", "T9", "4YD", "6lg", "6BK", "4wh", "0LF", "ot",
"bD", "0Av", "4zX", "4o9", "5Q4", "4Tt", "0oZ", "Lh", "Ci", "14r", "5KT", "6nV", "ajh", "41Q", "0Nw", "mE", "22l", "0CG", "4xi", "6MJ",
"6cf", "4VE", "0mk", "NY", "07a", "2FJ", "69l", "4HG", "4fk", "6SH", "2hf", "1Md", "0Pu", "7O", "7NY", "bQh", "4Ew", "6pT", "0k8", "1nx",
"05P", "Rj", "5O6", "4Jv", "4dZ", "453", "8N", "1OU", "0RD", "qv", "7Lh", "4ij", "4GF", "66m", "2IK", "1lI", "5kc", "6Na", "21G", "27",
"8gX", "Mr", "74d", "4Un", "bbm", "79T", "1f0", "0cp", "397", "nn", "5s2", "42z", "4ys", "6LP", "ao", "366", "0lq", "OC", "76U", "bml",
"4Zo", "6oL", "Bs", "0aA", "0Om", "2zN", "7QA", "40K", "7OC", "4jA", "0Qo", "6U", "3ZA", "1ob", "4Dm", "65F", "68v", "b7f", "0rs", "QA",
"dSO", "8UG", "4gq", "5b1", "5m0", "4hp", "8ZF", "4d", "1x2", "09z", "727", "67w", "7nn", "4Kl", "04J", "Sp", "9T", "1NO", "51i", "6Pc",
"6BO", "43d", "0LB", "op", "2WM", "0bn", "5Ia", "6lc", "5Q0", "4Tp", "8fF", "Ll", "1D2", "0Ar", "cPN", "aem", "ajl", "41U", "0Ns", "mA",
"Cm", "14v", "5KP", "6nR", "6cb", "4VA", "0mo", "2XL", "22h", "0CC", "4xm", "6MN", "4fo", "6SL", "2hb", "8TY", "07e", "2FN", "69h", "4HC",
"4Es", "64X", "d5E", "83M", "0Pq", "7K", "a0f", "bQl", "50w", "457", "8J", "1OQ", "05T", "Rn", "5O2", "4Jr", "4GB", "66i", "2IO", "08d",
"1Ba", "5z", "7Ll", "4in", "0nD", "Mv", "7ph", "4Uj", "5kg", "6Ne", "cZ", "23", "0MX", "nj", "5s6", "4vv", "4XZ", "6my", "1f4", "0ct",
"0lu", "OG", "6bx", "5Gz", "4yw", "6LT", "ak", "0BY", "0Oi", "2zJ", "6Ad", "40O", "4Zk", "6oH", "Bw", "0aE", "2Jd", "1of", "4Di", "65B",
"7OG", "4jE", "g8", "6Q", "2ix", "1Lz", "4gu", "5b5", "68r", "4IY", "0rw", "QE", "1x6", "1mW", "4FX", "4S9", "5m4", "4ht", "0SZ", "ph",
"9P", "h9", "4eD", "6Pg", "7nj", "4Kh", "04N", "St", "22u", "375", "4xp", "598", "77V", "blo", "0mr", "1h2", "Cp", "14k", "5KM", "6nO",
"7PB", "41H", "0Nn", "3kl", "20D", "34", "4zA", "6Ob", "6aN", "4Tm", "0oC", "Lq", "AA", "0bs", "bcn", "78W", "569", "43y", "384", "om",
"9Kd", "5g", "5l3", "4is", "734", "66t", "1y1", "08y", "05I", "Rs", "7om", "4Jo", "4dC", "7AA", "8W", "1OL", "0Pl", "7V", "ats", "4kB",
"4En", "64E", "2Kc", "1na", "07x", "PB", "69u", "b6e", "4fr", "5c2", "dRL", "8TD", "4Zv", "6oU", "Bj", "0aX", "0Ot", "lF", "6Ay", "40R",
"4yj", "6LI", "av", "0BD", "0lh", "OZ", "6be", "4WF", "4XG", "6md", "2VJ", "0ci", "0ME", "nw", "6CH", "42c", "5kz", "6Nx", "cG", "1PT",
"0nY", "Mk", "5P7", "4Uw", "5N5", "4Ku", "04S", "Si", "9M", "1NV", "4eY", "440", "7Mk", "4hi", "0SG", "pu", "2HH", "K8", "4FE", "67n",
"68o", "4ID", "1", "QX", "2ie", "1Lg", "4gh", "6RK", "7OZ", "4jX", "0Qv", "6L", "2Jy", "3O9", "4Dt", "5A4", "4C9", "4VX", "0mv", "ND",
"22q", "0CZ", "4xt", "6MW", "7PF", "41L", "x9", "mX", "Ct", "14o", "5KI", "6nK", "6aJ", "4Ti", "0oG", "Lu", "bY", "30", "4zE", "6Of",
"5r5", "4wu", "380", "oi", "AE", "0bw", "4YY", "4L8", "5Wz", "66p", "1y5", "1lT", "0RY", "5c", "5l7", "4iw", "4dG", "6Qd", "8S", "1OH",
"05M", "Rw", "7oi", "4Jk", "4Ej", "64A", "2Kg", "1ne", "0Ph", "7R", "7ND", "4kF", "4fv", "5c6", "0H9", "1My", "0st", "PF", "69q", "4HZ",
"0Op", "lB", "ako", "40V", "4Zr", "6oQ", "Bn", "15u", "0ll", "2YO", "6ba", "4WB", "4yn", "6LM", "ar", "1Ra", "0MA", "ns", "6CL", "42g",
"4XC", "79I", "2VN", "0cm", "8gE", "Mo", "5P3", "4Us", "bAl", "adn", "cC", "1PP", "9I", "1NR", "51t", "444", "5N1", "4Kq", "04W", "Sm",
"2HL", "09g", "4FA", "67j", "7Mo", "4hm", "0SC", "4y", "2ia", "1Lc", "4gl", "6RO", "68k", "5Ya", "5", "2GM", "d4F", "82N", "4Dp", "5A0",
"a1e", "bPo", "0Qr", "6H", "Cx", "14c", "5KE", "6nG", "7PJ", "4uH", "x5", "mT", "0V7", "0CV", "4xx", "590", "4C5", "4VT", "0mz", "NH",
"AI", "16R", "4YU", "4L4", "561", "43q", "0LW", "oe", "bU", "w4", "4zI", "6Oj", "6aF", "4Te", "0oK", "Ly", "05A", "2Dj", "7oe", "4Jg",
"4dK", "6Qh", "2jF", "i6", "0RU", "5o", "7Ly", "5yZ", "4GW", "4R6", "1y9", "08q", "07p", "PJ", "7mT", "4HV", "4fz", "6SY", "0H5", "1Mu",
"f7", "sV", "7NH", "4kJ", "4Ef", "64M", "2Kk", "1ni", "4yb", "6LA", "23g", "0BL", "Z3", "OR", "6bm", "4WN", "c4d", "aEO", "Bb", "0aP",
"8Fd", "lN", "4a3", "40Z", "5kr", "4n2", "cO", "8Ie", "0nQ", "Mc", "74u", "615", "4XO", "6ml", "2VB", "U2", "0MM", "2xn", "7Sa", "42k",
"7Mc", "4ha", "0SO", "4u", "3Xa", "K0", "4FM", "67f", "aTL", "b5F", "0pS", "Sa", "9E", "8Wg", "4eQ", "448", "7OR", "4jP", "254", "6D",
"0j3", "1os", "cnn", "65W", "68g", "4IL", "9", "QP", "2im", "1Lo", "53I", "6RC", "7PN", "41D", "x1", "mP", "2Um", "14g", "5KA", "6nC",
"4C1", "4VP", "19W", "NL", "0V3", "0CR", "bBO", "594", "565", "43u", "0LS", "oa", "AM", "16V", "4YQ", "4L0", "6aB", "4Ta", "0oO", "2Zl",
"bQ", "38", "4zM", "6On", "4dO", "6Ql", "2jB", "i2", "05E", "2Dn", "7oa", "4Jc", "4GS", "4R2", "d7e", "08u", "0RQ", "5k", "a2F", "bSL",
"52W", "ayO", "0H1", "1Mq", "07t", "PN", "69y", "4HR", "4Eb", "64I", "2Ko", "1nm", "f3", "7Z", "7NL", "4kN", "Z7", "OV", "6bi", "4WJ",
"4yf", "6LE", "az", "0BH", "0Ox", "lJ", "4a7", "4tV", "4Zz", "6oY", "Bf", "0aT", "0nU", "Mg", "74q", "5EZ", "5kv", "4n6", "cK", "1PX",
"0MI", "2xj", "6CD", "42o", "4XK", "6mh", "2VF", "U6", "2HD", "K4", "4FI", "67b", "7Mg", "4he", "0SK", "4q", "9A", "1NZ", "4eU", "4p4",
"5N9", "4Ky", "0pW", "Se", "0j7", "1ow", "4Dx", "5A8", "7OV", "4jT", "0Qz", "rH", "2ii", "1Lk", "4gd", "6RG", "68c", "4IH", "D5", "QT",
"5Ls", "4I3", "F", "13U", "0IP", "jb", "536", "46v", "5oo", "6Jm", "gR", "r3", "0jL", "3ON", "6dA", "4Qb", "5NB", "aAR", "2Pn", "0eM",
"0Ka", "hS", "6El", "44G", "49w", "abN", "ec", "0FQ", "8ae", "KO", "4F2", "4SS", "4X0", "4MQ", "02w", "UM", "0M2", "0XS", "57T", "a8D",
"7KO", "4nM", "c0", "2Y", "2Nl", "1kn", "aJ1", "61J", "6zC", "aE0", "00F", "2Am", "yP", "l1", "4aL", "6To", "a7E", "58U", "0WR", "0h",
"ZL", "84n", "4BP", "4W1", "fH", "0Ez", "5nu", "4k5", "5U8", "4Px", "0kV", "Hd", "ET", "P5", "5Mi", "6hk", "6FG", "47l", "0HJ", "kx",
"dy", "0GK", "48m", "6IF", "6gj", "4RI", "0ig", "JU", "Ge", "0dW", "5OX", "5Z9", "4d4", "4qU", "1ZZ", "iI", "0Ty", "3C", "4z6", "4oW",
"5QZ", "60P", "Yg", "0zU", "A6", "TW", "6yh", "4LK", "4bg", "6WD", "2lj", "0YI", "0VH", "1r", "6XE", "4mf", "4CJ", "62a", "2MG", "N7",
"0uT", "Vf", "7kx", "4Nz", "5pw", "4u7", "xJ", "1KY", "0IT", "jf", "532", "46r", "5Lw", "4I7", "B", "0gx", "0jH", "Iz", "6dE", "4Qf",
"5ok", "6Ji", "gV", "r7", "0Ke", "hW", "6Eh", "44C", "5NF", "6kD", "2Pj", "0eI", "0hy", "KK", "4F6", "4SW", "49s", "6HX", "eg", "0FU",
"0M6", "0XW", "4cy", "5f9", "4X4", "4MU", "02s", "UI", "Xy", "1kj", "5PD", "61N", "7KK", "4nI", "c4", "vU", "yT", "l5", "4aH", "6Tk",
"6zG", "4Od", "00B", "Wx", "ZH", "0yz", "4BT", "4W5", "5i8", "4lx", "0WV", "0l", "71v", "646", "0kR", "3NP", "fL", "8Lf", "5nq", "4k1",
"6FC", "47h", "0HN", "29e", "EP", "P1", "5Mm", "6ho", "6gn", "4RM", "0ic", "JQ", "26d", "0GO", "48i", "6IB", "4d0", "45Y", "8Cg", "iM",
"Ga", "0dS", "beN", "hYu", "ckm", "60T", "Yc", "0zQ", "207", "3G", "4z2", "4oS", "4bc", "7Ga", "2ln", "0YM", "A2", "TS", "6yl", "4LO",
"4CN", "62e", "2MC", "N3", "0VL", "1v", "6XA", "4mb", "5ps", "4u3", "xN", "8Rd", "01X", "Vb", "aQO", "b0E", "5og", "6Je", "gZ", "63",
"0jD", "Iv", "6dI", "4Qj", "7l9", "6iy", "N", "0gt", "0IX", "jj", "5w6", "4rv", "5mV", "5x7", "ek", "0FY", "0hu", "KG", "6fx", "5Cz",
"5NJ", "6kH", "Fw", "0eE", "92", "3nk", "6Ed", "44O", "7KG", "4nE", "c8", "2Q", "Xu", "1kf", "5PH", "61B", "4X8", "4MY", "0vw", "UE",
"2mx", "1Hz", "4cu", "5f5", "5i4", "4lt", "0WZ", "th", "ZD", "0yv", "4BX", "4W9", "6zK", "4Oh", "00N", "Wt", "yX", "l9", "4aD", "6Tg",
"2SM", "0fn", "5Ma", "6hc", "6FO", "47d", "0HB", "kp", "24Y", "0Er", "bDo", "aam", "5U0", "4Pp", "8bF", "Hl", "Gm", "10v", "5OP", "5Z1",
"anl", "45U", "0Js", "iA", "dq", "0GC", "48e", "6IN", "6gb", "4RA", "0io", "3Lm", "03e", "2BN", "7iA", "4LC", "4bo", "6WL", "zs", "0YA",
"0Tq", "3K", "a4f", "bUl", "4As", "5D3", "Yo", "87M", "01T", "Vn", "5K2", "4Nr", "54w", "417", "xB", "1KQ", "1Fa", "1z", "6XM", "4mn",
"4CB", "62i", "2MO", "0xl", "1za", "Ir", "6dM", "4Qn", "5oc", "6Ja", "25G", "67", "9Pe", "jn", "5w2", "46z", "bfm", "aCo", "J", "0gp",
"0hq", "KC", "72U", "bil", "5mR", "5x3", "eo", "326", "96", "3no", "7UA", "44K", "5NN", "6kL", "Fs", "0eA", "Xq", "1kb", "5PL", "61F",
"7KC", "4nA", "0Uo", "2U", "39U", "8QG", "4cq", "5f1", "aRl", "796", "0vs", "UA", "2LQ", "0yr", "767", "63w", "5i0", "4lp", "9Ng", "0d",
"2oM", "0Zn", "55i", "6Tc", "6zO", "4Ol", "00J", "Wp", "6FK", "4sh", "0HF", "kt", "EX", "P9", "5Me", "6hg", "5U4", "4Pt", "0kZ", "Hh",
"fD", "0Ev", "5ny", "4k9", "4d8", "45Q", "0Jw", "iE", "Gi", "10r", "5OT", "5Z5", "6gf", "4RE", "0ik", "JY", "du", "0GG", "48a", "6IJ",
"4bk", "6WH", "zw", "0YE", "03a", "2BJ", "6yd", "4LG", "4Aw", "5D7", "Yk", "0zY", "0Tu", "3O", "6Zx", "bUh", "54s", "413", "xF", "1KU",
"01P", "Vj", "5K6", "4Nv", "4CF", "62m", "2MK", "0xh", "0VD", "uv", "6XI", "4mj", "5NS", "6kQ", "Fn", "11u", "0Kp", "hB", "aoo", "44V",
"49f", "6HM", "er", "1Va", "0hl", "3Mn", "6fa", "4SB", "5Lb", "7yA", "W", "0gm", "0IA", "js", "6GL", "46g", "bEl", "hyW", "gC", "0Dq",
"8cE", "Io", "5T3", "4Qs", "5J1", "4Oq", "00W", "Wm", "yA", "0Zs", "55t", "404", "6YN", "4lm", "0WC", "0y", "2LL", "0yo", "4BA", "63j",
"6xc", "bws", "02f", "2CM", "2ma", "0XB", "4cl", "6VO", "a5e", "bTo", "0Ur", "2H", "Xl", "86N", "5PQ", "5E0", "dh", "0GZ", "5lU", "5y4",
"4G9", "4RX", "0iv", "JD", "Gt", "0dF", "5OI", "6jK", "6Dg", "45L", "81", "iX", "fY", "70", "5nd", "6Kf", "6eJ", "4Pi", "0kG", "Hu",
"EE", "0fw", "5Mx", "4H8", "5v5", "4su", "1Xz", "ki", "0VY", "1c", "5h7", "4mw", "5Sz", "62p", "2MV", "0xu", "01M", "Vw", "7ki", "4Nk",
"54n", "6Ud", "2nJ", "1KH", "0Th", "3R", "6Ze", "4oF", "4Aj", "60A", "Yv", "0zD", "0wt", "TF", "6yy", "4LZ", "4bv", "5g6", "zj", "0YX",
"0Kt", "hF", "6Ey", "44R", "5NW", "6kU", "Fj", "0eX", "0hh", "KZ", "6fe", "4SF", "49b", "6HI", "ev", "0FD", "0IE", "jw", "6GH", "46c",
"5Lf", "6id", "S", "0gi", "0jY", "Ik", "5T7", "4Qw", "5oz", "6Jx", "gG", "0Du", "yE", "0Zw", "4aY", "400", "5J5", "4Ou", "00S", "Wi",
"ZY", "O8", "4BE", "63n", "6YJ", "4li", "0WG", "tu", "2me", "0XF", "4ch", "6VK", "6xg", "4MD", "02b", "UX", "Xh", "3K9", "5PU", "5E4",
"7KZ", "4nX", "0Uv", "2L", "73V", "bho", "0ir", "1l2", "dl", "335", "48x", "5y0", "6Dc", "45H", "85", "3ol", "Gp", "0dB", "5OM", "6jO",
"6eN", "4Pm", "0kC", "Hq", "24D", "74", "bDr", "6Kb", "529", "47y", "8AG", "km", "EA", "0fs", "bgn", "aBl", "774", "62t", "199", "0xq",
"9Od", "1g", "5h3", "4ms", "54j", "7EA", "2nN", "1KL", "01I", "Vs", "7km", "4No", "4An", "60E", "Yr", "1ja", "0Tl", "3V", "6Za", "4oB",
"4br", "5g2", "zn", "8PD", "03x", "TB", "aSo", "785", "49n", "6HE", "ez", "0FH", "0hd", "KV", "6fi", "4SJ", "bdI", "6kY", "Ff", "0eT",
"0Kx", "hJ", "4e7", "4pV", "5ov", "4j6", "gK", "0Dy", "0jU", "Ig", "6dX", "5AZ", "5Lj", "6ih", "DW", "Q6", "0II", "28b", "6GD", "46o",
"6YF", "4le", "0WK", "0q", "ZU", "O4", "4BI", "63b", "5J9", "4Oy", "0tW", "We", "yI", "1JZ", "4aU", "4t4", "7KV", "4nT", "0Uz", "vH",
"Xd", "1kw", "5PY", "5E8", "6xk", "4MH", "02n", "UT", "2mi", "0XJ", "4cd", "6VG", "2Qm", "0dN", "5OA", "6jC", "6Do", "45D", "89", "iP",
"0R3", "0GR", "48t", "acM", "4G1", "4RP", "94O", "JL", "EM", "12V", "5Mp", "4H0", "525", "47u", "0HS", "ka", "fQ", "78", "5nl", "6Kn",
"6eB", "4Pa", "0kO", "3NM", "01E", "3PO", "7ka", "4Nc", "54f", "6Ul", "xS", "m2", "0VQ", "1k", "a6F", "59V", "4CS", "4V2", "195", "85m",
"03t", "TN", "4Y3", "4LR", "56W", "a9G", "zb", "0YP", "b3", "3Z", "6Zm", "4oN", "4Ab", "60I", "2Oo", "0zL", "1xA", "KR", "6fm", "4SN",
"49j", "6HA", "27g", "0FL", "8Bd", "hN", "4e3", "44Z", "bdM", "aAO", "Fb", "0eP", "0jQ", "Ic", "70u", "655", "5or", "4j2", "gO", "8Me",
"0IM", "28f", "7Wa", "46k", "5Ln", "6il", "DS", "Q2", "ZQ", "O0", "4BM", "63f", "6YB", "4la", "0WO", "0u", "yM", "8Sg", "4aQ", "408",
"aPL", "b1F", "0tS", "Wa", "0n3", "1ks", "bzO", "61W", "7KR", "4nP", "214", "2D", "2mm", "0XN", "57I", "6VC", "6xo", "4ML", "02j", "UP",
"6Dk", "4qH", "0Jf", "iT", "Gx", "0dJ", "5OE", "6jG", "4G5", "4RT", "0iz", "JH", "dd", "0GV", "48p", "5y8", "521", "47q", "0HW", "ke",
"EI", "12R", "5Mt", "4H4", "6eF", "4Pe", "0kK", "Hy", "fU", "s4", "5nh", "6Kj", "54b", "6Uh", "xW", "m6", "01A", "3PK", "7ke", "4Ng",
"4CW", "4V6", "191", "0xy", "0VU", "1o", "6XX", "59R", "4bz", "6WY", "zf", "0YT", "03p", "TJ", "4Y7", "4LV", "4Af", "60M", "Yz", "0zH",
"b7", "wV", "6Zi", "4oJ", "5H3", "4Ms", "02U", "Uo", "2mR", "0Xq", "57v", "426", "7Km", "4no", "0UA", "vs", "2NN", "1kL", "5Pb", "61h",
"6za", "4OB", "00d", "2AO", "yr", "1Ja", "4an", "6TM", "a7g", "58w", "0Wp", "0J", "Zn", "84L", "4Br", "5G2", "5LQ", "5Y0", "d", "13w",
"0Ir", "1L2", "amm", "46T", "5oM", "6JO", "gp", "0DB", "0jn", "3Ol", "6dc", "5Aa", "bdr", "6kb", "2PL", "0eo", "0KC", "hq", "6EN", "44e",
"49U", "abl", "eA", "0Fs", "8aG", "Km", "5V1", "4Sq", "1Dz", "3a", "5j5", "4ou", "4AY", "4T8", "YE", "0zw", "03O", "Tu", "6yJ", "4Li",
"4bE", "6Wf", "zY", "o8", "0Vj", "1P", "6Xg", "4mD", "4Ch", "62C", "2Me", "0xF", "0uv", "VD", "7kZ", "4NX", "5pU", "5e4", "xh", "3k9",
"fj", "0EX", "5nW", "6KU", "6ey", "4PZ", "0kt", "HF", "Ev", "0fD", "5MK", "6hI", "6Fe", "47N", "0Hh", "kZ", "26B", "52", "48O", "6Id",
"6gH", "4Rk", "0iE", "Jw", "GG", "0du", "5Oz", "6jx", "5t7", "4qw", "0JY", "ik", "2mV", "0Xu", "57r", "422", "5H7", "4Mw", "02Q", "Uk",
"2NJ", "1kH", "5Pf", "61l", "7Ki", "4nk", "0UE", "vw", "yv", "0ZD", "4aj", "6TI", "6ze", "4OF", "0th", "WZ", "Zj", "0yX", "4Bv", "5G6",
"6Yy", "4lZ", "0Wt", "0N", "0Iv", "jD", "4g9", "46P", "5LU", "5Y4", "Dh", "0gZ", "0jj", "IX", "6dg", "4QD", "5oI", "6JK", "gt", "0DF",
"0KG", "hu", "6EJ", "44a", "5Nd", "6kf", "FY", "S8", "1xz", "Ki", "5V5", "4Su", "49Q", "4h8", "eE", "0Fw", "756", "60v", "YA", "0zs",
"9Mf", "3e", "5j1", "4oq", "4bA", "6Wb", "2lL", "0Yo", "03K", "Tq", "6yN", "4Lm", "4Cl", "62G", "2Ma", "0xB", "0Vn", "1T", "6Xc", "59i",
"54Y", "5e0", "xl", "8RF", "01z", "1p2", "aQm", "b0g", "71T", "bjm", "0kp", "HB", "fn", "317", "5nS", "6KQ", "6Fa", "47J", "0Hl", "29G",
"Er", "12i", "5MO", "6hM", "6gL", "4Ro", "0iA", "Js", "26F", "56", "48K", "7YA", "5t3", "4qs", "8CE", "io", "GC", "0dq", "bel", "hYW",
"7Ke", "4ng", "0UI", "2s", "XW", "M6", "5Pj", "6uh", "6xX", "6m9", "0vU", "Ug", "2mZ", "0Xy", "4cW", "4v6", "4y7", "4lV", "0Wx", "0B",
"Zf", "0yT", "4Bz", "63Q", "6zi", "4OJ", "B7", "WV", "yz", "0ZH", "4af", "6TE", "5oE", "6JG", "gx", "0DJ", "0jf", "IT", "6dk", "4QH",
"5LY", "5Y8", "l", "0gV", "0Iz", "jH", "4g5", "4rT", "5mt", "4h4", "eI", "1VZ", "0hW", "Ke", "5V9", "4Sy", "5Nh", "6kj", "FU", "S4",
"0KK", "hy", "6EF", "44m", "03G", "2Bl", "6yB", "4La", "4bM", "6Wn", "zQ", "o0", "0TS", "3i", "a4D", "bUN", "4AQ", "4T0", "YM", "87o",
"01v", "VL", "7kR", "4NP", "54U", "hft", "0N3", "1Ks", "0Vb", "1X", "6Xo", "4mL", "5SA", "62K", "2Mm", "0xN", "2So", "0fL", "5MC", "6hA",
"6Fm", "47F", "1XA", "kR", "fb", "0EP", "bDM", "aaO", "4E3", "4PR", "8bd", "HN", "GO", "10T", "5Or", "4J2", "507", "45w", "0JQ", "ic",
"dS", "q2", "48G", "6Il", "73i", "4Rc", "0iM", "3LO", "XS", "M2", "5Pn", "61d", "7Ka", "4nc", "0UM", "2w", "39w", "8Qe", "4cS", "4v2",
"aRN", "b3D", "02Y", "Uc", "Zb", "0yP", "bxM", "63U", "4y3", "4lR", "236", "0F", "2oo", "0ZL", "4ab", "6TA", "6zm", "4ON", "B3", "WR",
"0jb", "IP", "6do", "4QL", "5oA", "6JC", "25e", "0DN", "9PG", "jL", "4g1", "46X", "686", "aCM", "h", "0gR", "0hS", "Ka", "72w", "677",
"49Y", "4h0", "eM", "8Og", "0KO", "3nM", "6EB", "44i", "5Nl", "6kn", "FQ", "S0", "4bI", "6Wj", "zU", "o4", "03C", "Ty", "6yF", "4Le",
"4AU", "4T4", "YI", "1jZ", "0TW", "3m", "5j9", "4oy", "54Q", "5e8", "xd", "1Kw", "01r", "VH", "7kV", "4NT", "4Cd", "62O", "2Mi", "0xJ",
"0Vf", "uT", "6Xk", "4mH", "6Fi", "47B", "0Hd", "kV", "Ez", "0fH", "5MG", "6hE", "4E7", "4PV", "0kx", "HJ", "ff", "0ET", "bDI", "6KY",
"503", "45s", "0JU", "ig", "GK", "0dy", "5Ov", "4J6", "6gD", "4Rg", "0iI", "3LK", "dW", "q6", "48C", "6Ih", "4Z2", "4OS", "00u", "WO",
"yc", "0ZQ", "55V", "hgw", "6Yl", "4lO", "a2", "tS", "2Ln", "0yM", "4Bc", "63H", "6xA", "4Mb", "02D", "2Co", "2mC", "n3", "4cN", "6Vm",
"a5G", "bTM", "0UP", "2j", "XN", "86l", "5Ps", "4U3", "5Nq", "4K1", "FL", "11W", "0KR", "3nP", "514", "44t", "49D", "6Ho", "eP", "49",
"0hN", "3ML", "6fC", "5CA", "aV1", "6iB", "u", "0gO", "0Ic", "jQ", "6Gn", "46E", "bEN", "hyu", "ga", "0DS", "8cg", "IM", "4D0", "4QQ",
"1FZ", "1A", "4x4", "4mU", "4Cy", "5F9", "0m6", "0xW", "C4", "VU", "7kK", "4NI", "54L", "6UF", "xy", "1Kj", "0TJ", "3p", "6ZG", "4od",
"4AH", "60c", "YT", "L5", "0wV", "Td", "5I8", "4Lx", "4bT", "4w5", "zH", "0Yz", "dJ", "0Gx", "5lw", "4i7", "6gY", "4Rz", "0iT", "Jf",
"GV", "R7", "5Ok", "6ji", "6DE", "45n", "0JH", "iz", "24b", "0EI", "5nF", "6KD", "6eh", "4PK", "0ke", "HW", "Eg", "0fU", "5MZ", "6hX",
"4f6", "4sW", "0Hy", "kK", "yg", "0ZU", "55R", "6TX", "4Z6", "4OW", "00q", "WK", "2Lj", "0yI", "4Bg", "63L", "6Yh", "4lK", "a6", "tW",
"2mG", "n7", "4cJ", "6Vi", "6xE", "4Mf", "0vH", "Uz", "XJ", "1kY", "5Pw", "4U7", "7Kx", "4nz", "0UT", "2n", "0KV", "hd", "510", "44p",
"5Nu", "4K5", "FH", "0ez", "0hJ", "Kx", "6fG", "4Sd", "5mi", "6Hk", "eT", "p5", "0Ig", "jU", "6Gj", "46A", "5LD", "6iF", "q", "0gK",
"1zZ", "II", "4D4", "4QU", "5oX", "5z9", "ge", "0DW", "byN", "62V", "0m2", "0xS", "225", "1E", "4x0", "4mQ", "54H", "6UB", "2nl", "1Kn",
"C0", "VQ", "7kO", "4NM", "4AL", "60g", "YP", "L1", "0TN", "3t", "6ZC", "ae0", "4bP", "439", "zL", "8Pf", "03Z", "0b3", "aSM", "b2G",
"73t", "664", "0iP", "Jb", "dN", "8Nd", "48Z", "4i3", "6DA", "45j", "0JL", "3oN", "GR", "R3", "5Oo", "6jm", "6el", "4PO", "0ka", "HS",
"24f", "0EM", "5nB", "aaR", "4f2", "4sS", "8Ae", "kO", "Ec", "0fQ", "695", "aBN", "6Yd", "4lG", "0Wi", "0S", "Zw", "0yE", "4Bk", "6wH",
"6zx", "buh", "0tu", "WG", "yk", "0ZY", "4aw", "5d7", "5k6", "4nv", "0UX", "2b", "XF", "1kU", "741", "61q", "6xI", "4Mj", "02L", "Uv",
"2mK", "0Xh", "4cF", "6Ve", "49L", "6Hg", "eX", "41", "0hF", "Kt", "6fK", "4Sh", "5Ny", "4K9", "FD", "0ev", "0KZ", "hh", "5u4", "4pt",
"5oT", "5z5", "gi", "1Tz", "0jw", "IE", "4D8", "4QY", "5LH", "6iJ", "Du", "0gG", "0Ik", "jY", "6Gf", "46M", "01g", "3Pm", "7kC", "4NA",
"54D", "6UN", "xq", "1Kb", "0Vs", "1I", "a6d", "59t", "4Cq", "5F1", "d3G", "85O", "03V", "Tl", "5I0", "4Lp", "56u", "435", "2lQ", "0Yr",
"0TB", "3x", "6ZO", "4ol", "5Qa", "60k", "2OM", "0zn", "2QO", "0dl", "5Oc", "6ja", "6DM", "45f", "1Za", "ir", "dB", "0Gp", "48V", "aco",
"5W2", "4Rr", "94m", "Jn", "Eo", "12t", "5MR", "5X3", "aln", "47W", "0Hq", "kC", "fs", "0EA", "5nN", "6KL", "71I", "4PC", "0km", "3No",
"Zs", "0yA", "4Bo", "63D", "7IA", "4lC", "0Wm", "0W", "yo", "8SE", "4as", "5d3", "aPn", "b1d", "00y", "WC", "XB", "1kQ", "745", "61u",
"5k2", "4nr", "9Le", "2f", "2mO", "0Xl", "4cB", "6Va", "6xM", "4Mn", "02H", "Ur", "0hB", "Kp", "6fO", "4Sl", "49H", "6Hc", "27E", "45",
"8BF", "hl", "518", "44x", "bdo", "aAm", "2PQ", "0er", "0js", "IA", "70W", "bkn", "5oP", "5z1", "gm", "304", "0Io", "28D", "6Gb", "46I",
"5LL", "6iN", "y", "0gC", "5pH", "6UJ", "xu", "1Kf", "C8", "VY", "7kG", "4NE", "4Cu", "5F5", "2Mx", "1hz", "0Vw", "1M", "4x8", "4mY",
"4bX", "431", "zD", "0Yv", "03R", "Th", "5I4", "4Lt", "4AD", "60o", "YX", "L9", "0TF", "wt", "6ZK", "4oh", "6DI", "45b", "0JD", "iv",
"GZ", "0dh", "5Og", "6je", "5W6", "4Rv", "0iX", "Jj", "dF", "0Gt", "48R", "6Iy", "6Fx", "47S", "0Hu", "kG", "Ek", "0fY", "5MV", "5X7",
"6ed", "4PG", "0ki", "3Nk", "fw", "0EE", "5nJ", "6KH", "356", "bo", "6OP", "4zs", "bnl", "75U", "LC", "0oq", "0bA", "As", "6lL", "4Yo",
"43K", "7RA", "2yN", "0Lm", "17", "22G", "6Ma", "4xB", "4Vn", "6cM", "Nr", "19i", "14Y", "CB", "aDo", "bam", "41z", "5p2", "mn", "8GD",
"7d", "8YF", "4kp", "5n0", "64w", "717", "1nS", "2KQ", "Pp", "07J", "4Hl", "69G", "6Sc", "52i", "1MO", "2hM", "5U", "0Ro", "4iA", "7LC",
"66F", "4Gm", "08K", "3YA", "RA", "0qs", "b4f", "aUl", "5a1", "4dq", "8VG", "8e", "6mV", "4Xu", "17r", "022", "nE", "0Mw", "42Q", "4c8",
"6NJ", "5kH", "1Pf", "cu", "MY", "X8", "4UE", "74O", "6og", "4ZD", "W9", "BX", "lt", "0OF", "4th", "6AK", "4l9", "4yX", "0Bv", "aD",
"Oh", "0lZ", "4Wt", "5R4", "4Iv", "5L6", "Qj", "06P", "1LU", "1Y4", "463", "4gZ", "4jj", "7Oh", "rv", "0QD", "1oI", "2JK", "65m", "4DF",
"4KG", "7nE", "2EJ", "04a", "1Nd", "2kf", "6PH", "4ek", "5xz", "492", "4O", "0Su", "09Q", "0h8", "5C7", "4Fw", "5Dz", "6ax", "LG", "0ou",
"0AY", "bk", "6OT", "4zw", "43O", "6Bd", "2yJ", "0Li", "0bE", "Aw", "6lH", "4Yk", "4Vj", "6cI", "Nv", "0mD", "13", "22C", "6Me", "4xF",
"4uv", "5p6", "mj", "0NX", "1pU", "CF", "6ny", "7k9", "4P9", "4EX", "1nW", "2KU", "sh", "0PZ", "4kt", "5n4", "6Sg", "4fD", "k9", "2hI",
"Pt", "07N", "4Hh", "69C", "66B", "4Gi", "08O", "2Id", "5Q", "d8", "4iE", "7LG", "5a5", "4du", "1Oz", "8a", "RE", "0qw", "4JY", "aUh",
"nA", "0Ms", "42U", "ail", "6mR", "4Xq", "17v", "026", "3Km", "0no", "4UA", "74K", "6NN", "5kL", "1Pb", "cq", "lp", "0OB", "40d", "6AO",
"6oc", "5Ja", "0an", "2TM", "Ol", "18w", "4Wp", "5R0", "afm", "bCo", "0Br", "1G2", "1LQ", "1Y0", "467", "53w", "4Ir", "5L2", "Qn", "06T",
"1oM", "2JO", "65i", "4DB", "4jn", "7Ol", "6z", "1Aa", "8WY", "2kb", "6PL", "4eo", "4KC", "7nA", "2EN", "04e", "09U", "d6E", "5C3", "4Fs",
"bRl", "496", "4K", "0Sq", "0bI", "2Wj", "6lD", "4Yg", "43C", "6Bh", "oW", "z6", "0AU", "bg", "6OX", "5jZ", "4TW", "4A6", "LK", "0oy",
"14Q", "CJ", "4N7", "5Kw", "41r", "542", "mf", "0NT", "u7", "22O", "6Mi", "4xJ", "4Vf", "6cE", "Nz", "0mH", "Px", "07B", "4Hd", "69O",
"6Sk", "4fH", "k5", "2hE", "7l", "0PV", "4kx", "5n8", "4P5", "4ET", "83j", "2KY", "RI", "05s", "4JU", "7oW", "5a9", "4dy", "1Ov", "8m",
"qU", "d4", "4iI", "7LK", "66N", "4Ge", "08C", "2Ih", "6NB", "a59", "1Pn", "21d", "MQ", "X0", "4UM", "74G", "79w", "bbN", "0cS", "0v2",
"nM", "8Dg", "42Y", "4c0", "4l1", "4yP", "8Kf", "aL", "0y3", "0lR", "636", "76v", "6oo", "4ZL", "W1", "BP", "2zm", "0ON", "40h", "6AC",
"4jb", "auS", "6v", "0QL", "I3", "2JC", "65e", "4DN", "b7E", "68U", "Qb", "06X", "286", "dSl", "4r3", "4gR", "4hS", "7MQ", "4G", "277",
"09Y", "0h0", "67T", "b8D", "4KO", "7nM", "SS", "F2", "1Nl", "9w", "azR", "4ec", "43G", "6Bl", "oS", "z2", "0bM", "2Wn", "78i", "4Yc",
"4TS", "4A2", "LO", "8fe", "0AQ", "bc", "aeN", "cPm", "41v", "546", "mb", "0NP", "14U", "CN", "4N3", "5Ks", "4Vb", "6cA", "2Xo", "0mL",
"u3", "22K", "6Mm", "4xN", "6So", "4fL", "k1", "2hA", "2Fm", "07F", "5XA", "69K", "4P1", "4EP", "83n", "d5f", "7h", "0PR", "bQO", "a0E",
"hbu", "50T", "1Or", "8i", "RM", "05w", "4JQ", "7oS", "66J", "4Ga", "08G", "2Il", "5Y", "d0", "4iM", "7LO", "MU", "X4", "4UI", "74C",
"6NF", "5kD", "1Pj", "cy", "nI", "2m9", "4vU", "4c4", "6mZ", "4Xy", "0cW", "0v6", "Od", "0lV", "4Wx", "5R8", "4l5", "4yT", "0Bz", "aH",
"lx", "0OJ", "40l", "6AG", "6ok", "4ZH", "W5", "BT", "I7", "2JG", "65a", "4DJ", "4jf", "7Od", "6r", "0QH", "1LY", "1Y8", "4r7", "4gV",
"4Iz", "68Q", "Qf", "0rT", "1mt", "0h4", "67P", "5VZ", "4hW", "7MU", "4C", "0Sy", "1Nh", "9s", "6PD", "4eg", "4KK", "7nI", "SW", "F6",
"8Je", "22V", "4m2", "4xS", "625", "77u", "Nc", "0mQ", "V2", "CS", "6nl", "5Kn", "41k", "7Pa", "3kO", "0NM", "0AL", "20g", "6OA", "4zb",
"4TN", "6am", "LR", "Y3", "0bP", "Ab", "78t", "bcM", "43Z", "4b3", "oN", "8Ed", "5D", "264", "4iP", "489", "66W", "b9G", "08Z", "0i3",
"RP", "G1", "4JL", "7oN", "6QC", "50I", "1Oo", "8t", "7u", "0PO", "4ka", "7Nc", "64f", "4EM", "H0", "963", "Pa", "0sS", "b6F", "69V",
"478", "4fQ", "295", "dRo", "4O4", "4ZU", "15R", "BI", "le", "0OW", "40q", "551", "6Lj", "4yI", "t4", "aU", "Oy", "0lK", "4We", "6bF",
"6mG", "4Xd", "0cJ", "2Vi", "nT", "0Mf", "4vH", "6Ck", "adI", "5kY", "1Pw", "cd", "MH", "0nz", "4UT", "7pV", "4KV", "7nT", "SJ", "04p",
"1Nu", "9n", "6PY", "4ez", "4hJ", "7MH", "pV", "e7", "1mi", "2Hk", "67M", "4Ff", "4Ig", "68L", "2Gj", "06A", "j6", "2iF", "6Rh", "4gK",
"5zZ", "7Oy", "6o", "0QU", "1oX", "1z9", "4Q6", "4DW", "5FZ", "6cX", "Ng", "0mU", "0Cy", "1F9", "4m6", "4xW", "41o", "7Pe", "3kK", "0NI",
"V6", "CW", "6nh", "5Kj", "4TJ", "6ai", "LV", "Y7", "0AH", "bz", "6OE", "4zf", "4wV", "4b7", "oJ", "0Lx", "0bT", "Af", "6lY", "4Yz",
"5B8", "4Gx", "1lw", "0i7", "qH", "0Rz", "4iT", "7LV", "6QG", "4dd", "1Ok", "8p", "RT", "G5", "4JH", "7oJ", "64b", "4EI", "H4", "2KD",
"7q", "0PK", "4ke", "7Ng", "4s4", "4fU", "1MZ", "2hX", "Pe", "0sW", "4Hy", "5M9", "la", "0OS", "40u", "555", "4O0", "4ZQ", "15V", "BM",
"2Yl", "0lO", "4Wa", "6bB", "6Ln", "4yM", "08", "aQ", "nP", "0Mb", "42D", "6Co", "6mC", "5HA", "0cN", "2Vm", "ML", "8gf", "4UP", "74Z",
"adM", "bAO", "1Ps", "0U3", "1Nq", "9j", "azO", "51W", "4KR", "7nP", "SN", "04t", "09D", "2Ho", "67I", "4Fb", "4hN", "7ML", "4Z", "e3",
"j2", "2iB", "6Rl", "4gO", "4Ic", "68H", "2Gn", "06E", "82m", "d4e", "4Q2", "4DS", "bPL", "a1F", "6k", "0QQ", "1pH", "2UJ", "6nd", "5Kf",
"41c", "7Pi", "mw", "0NE", "0Cu", "1F5", "6Mx", "5hz", "4Vw", "5S7", "Nk", "0mY", "0bX", "Aj", "6lU", "4Yv", "43R", "6By", "oF", "0Lt",
"0AD", "bv", "6OI", "4zj", "4TF", "6ae", "LZ", "0oh", "RX", "G9", "4JD", "7oF", "6QK", "4dh", "1Og", "2je", "5L", "0Rv", "4iX", "481",
"5B4", "4Gt", "08R", "2Iy", "Pi", "07S", "4Hu", "5M5", "470", "4fY", "1MV", "1X7", "su", "0PG", "4ki", "7Nk", "64n", "4EE", "H8", "2KH",
"6Lb", "4yA", "04", "23D", "Oq", "0lC", "4Wm", "6bN", "aEl", "c4G", "0as", "BA", "lm", "8FG", "40y", "559", "6NS", "5kQ", "345", "cl",
"1k2", "0nr", "boo", "74V", "6mO", "4Xl", "0cB", "2Va", "2xM", "0Mn", "42H", "6Cc", "4hB", "aws", "4V", "0Sl", "09H", "2Hc", "67E", "4Fn",
"b5e", "aTo", "SB", "04x", "8WD", "9f", "6PQ", "4er", "4js", "5o3", "6g", "8XE", "1oP", "1z1", "65t", "704", "4Io", "68D", "Qs", "06I",
"1LL", "2iN", "7BA", "4gC", "41g", "7Pm", "ms", "0NA", "14D", "2UN", "aDr", "5Kb", "4Vs", "5S3", "No", "19t", "0Cq", "1F1", "agn", "bBl",
"43V", "aho", "oB", "0Lp", "16u", "An", "6lQ", "4Yr", "4TB", "6aa", "2ZO", "0ol", "1Qa", "br", "6OM", "4zn", "6QO", "4dl", "1Oc", "8x",
"2DM", "05f", "5Za", "7oB", "5B0", "4Gp", "08V", "d7F", "5H", "0Rr", "bSo", "485", "474", "52t", "1MR", "1X3", "Pm", "07W", "4Hq", "5M1",
"64j", "4EA", "1nN", "2KL", "7y", "0PC", "4km", "7No", "Ou", "0lG", "4Wi", "6bJ", "6Lf", "4yE", "00", "aY", "li", "8FC", "4tu", "5q5",
"4O8", "4ZY", "0aw", "BE", "MD", "0nv", "4UX", "74R", "6NW", "5kU", "341", "ch", "nX", "0Mj", "42L", "6Cg", "6mK", "4Xh", "0cF", "2Ve",
"09L", "2Hg", "67A", "4Fj", "4hF", "7MD", "4R", "0Sh", "1Ny", "9b", "6PU", "4ev", "4KZ", "7nX", "SF", "0pt", "1oT", "1z5", "65p", "5Tz",
"4jw", "5o7", "6c", "0QY", "1LH", "2iJ", "6Rd", "4gG", "4Ik", "7li", "Qw", "06M", "7F", "246", "4kR", "7NP", "64U", "col", "1nq", "0k1",
"PR", "E3", "4HN", "69e", "6SA", "4fb", "1Mm", "2ho", "5w", "0RM", "4ic", "7La", "66d", "4GO", "J2", "2IB", "Rc", "05Y", "b4D", "aUN",
"4q2", "4dS", "8Ve", "8G", "8Hg", "bM", "4o0", "4zQ", "607", "75w", "La", "0oS", "T0", "AQ", "6ln", "4YM", "43i", "6BB", "2yl", "0LO",
"0CN", "22e", "6MC", "5hA", "4VL", "6co", "NP", "0mb", "1ps", "0u3", "aDM", "baO", "41X", "7PR", "mL", "8Gf", "4IT", "7lV", "QH", "06r",
"1Lw", "0I7", "5b8", "4gx", "4jH", "7OJ", "rT", "g5", "1ok", "2Ji", "65O", "4Dd", "4Ke", "7ng", "Sy", "04C", "h4", "2kD", "6Pj", "4eI",
"4hy", "5m9", "4m", "0SW", "09s", "2HX", "4S4", "4FU", "4M6", "4XW", "0cy", "1f9", "ng", "0MU", "42s", "573", "6Nh", "5kj", "v6", "cW",
"3KK", "0nI", "4Ug", "74m", "6oE", "4Zf", "0aH", "Bz", "lV", "y7", "40B", "6Ai", "582", "4yz", "0BT", "af", "OJ", "0lx", "4WV", "4B7",
"64Q", "4Ez", "1nu", "0k5", "7B", "0Px", "4kV", "7NT", "6SE", "4ff", "1Mi", "2hk", "PV", "E7", "4HJ", "69a", "6rh", "4GK", "J6", "2IF",
"5s", "0RI", "4ig", "7Le", "4q6", "4dW", "1OX", "8C", "Rg", "0qU", "5ZZ", "7oy", "4Ty", "5Q9", "Le", "0oW", "1QZ", "bI", "4o4", "4zU",
"43m", "6BF", "oy", "0LK", "T4", "AU", "6lj", "4YI", "4VH", "6ck", "NT", "0mf", "0CJ", "22a", "6MG", "4xd", "4uT", "7PV", "mH", "0Nz",
"1pw", "Cd", "aDI", "5KY", "1Ls", "0I3", "axM", "53U", "4IP", "7lR", "QL", "06v", "1oo", "2Jm", "65K", "5TA", "4jL", "7ON", "6X", "g1",
"h0", "9Y", "6Pn", "4eM", "4Ka", "7nc", "2El", "04G", "09w", "d6g", "4S0", "4FQ", "bRN", "a3D", "4i", "0SS", "nc", "0MQ", "42w", "577",
"4M2", "4XS", "17T", "dlm", "3KO", "0nM", "4Uc", "74i", "6Nl", "5kn", "v2", "cS", "lR", "y3", "40F", "6Am", "6oA", "4Zb", "0aL", "2To",
"ON", "18U", "4WR", "4B3", "586", "bCM", "0BP", "ab", "PZ", "0sh", "4HF", "69m", "6SI", "4fj", "1Me", "2hg", "7N", "0Pt", "4kZ", "7NX",
"6pU", "4Ev", "1ny", "0k9", "Rk", "05Q", "4Jw", "5O7", "452", "50r", "1OT", "8O", "qw", "0RE", "4ik", "7Li", "66l", "4GG", "08a", "2IJ",
"T8", "AY", "6lf", "4YE", "43a", "6BJ", "ou", "0LG", "0Aw", "bE", "4o8", "4zY", "4Tu", "5Q5", "Li", "8fC", "14s", "Ch", "6nW", "5KU",
"41P", "7PZ", "mD", "0Nv", "0CF", "22m", "6MK", "4xh", "4VD", "6cg", "NX", "0mj", "5za", "7OB", "6T", "0Qn", "1oc", "2Ja", "65G", "4Dl",
"b7g", "68w", "1w2", "06z", "8UF", "dSN", "5b0", "4gp", "4hq", "5m1", "4e", "8ZG", "1mR", "1x3", "67v", "726", "4Km", "7no", "Sq", "04K",
"1NN", "9U", "6Pb", "4eA", "adr", "5kb", "26", "21F", "Ms", "0nA", "4Uo", "74e", "79U", "bbl", "0cq", "1f1", "no", "396", "4vs", "5s3",
"6LQ", "4yr", "367", "an", "OB", "0lp", "bmm", "76T", "6oM", "4Zn", "15i", "Br", "2zO", "0Ol", "40J", "6Aa", "6SM", "4fn", "1Ma", "2hc",
"2FO", "07d", "4HB", "69i", "64Y", "4Er", "83L", "d5D", "7J", "0Pp", "bQm", "a0g", "456", "50v", "1OP", "8K", "Ro", "05U", "4Js", "5O3",
"66h", "4GC", "08e", "2IN", "qs", "0RA", "4io", "7Lm", "43e", "6BN", "oq", "0LC", "0bo", "2WL", "6lb", "4YA", "4Tq", "5Q1", "Lm", "8fG",
"0As", "bA", "ael", "cPO", "41T", "ajm", "1K2", "0Nr", "14w", "Cl", "6nS", "5KQ", "5Fa", "6cc", "2XM", "0mn", "0CB", "22i", "6MO", "4xl",
"1og", "2Je", "65C", "4Dh", "4jD", "7OF", "6P", "g9", "3l9", "2iy", "5b4", "4gt", "4IX", "68s", "QD", "0rv", "1mV", "1x7", "4S8", "4FY",
"4hu", "5m5", "4a", "1Cz", "h8", "9Q", "6Pf", "4eE", "4Ki", "7nk", "Su", "04O", "Mw", "0nE", "4Uk", "74a", "6Nd", "5kf", "22", "21B",
"nk", "0MY", "4vw", "5s7", "6mx", "5Hz", "0cu", "1f5", "OF", "0lt", "4WZ", "6by", "6LU", "4yv", "0BX", "aj", "lZ", "0Oh", "40N", "6Ae",
"6oI", "4Zj", "0aD", "Bv", "5f", "9Ke", "4ir", "5l2", "66u", "735", "08x", "1y0", "Rr", "05H", "4Jn", "7ol", "6Qa", "4dB", "1OM", "8V",
"7W", "0Pm", "4kC", "7NA", "64D", "4Eo", "83Q", "2Kb", "PC", "07y", "b6d", "69t", "5c3", "4fs", "8TE", "dRM", "374", "22t", "599", "4xq",
"bln", "77W", "NA", "0ms", "14j", "Cq", "6nN", "5KL", "41I", "7PC", "3km", "0No", "35", "20E", "6Oc", "5ja", "4Tl", "6aO", "Lp", "0oB",
"0br", "1g2", "78V", "bco", "43x", "568", "ol", "385", "4Kt", "5N4", "Sh", "04R", "1NW", "9L", "441", "4eX", "4hh", "7Mj", "pt", "0SF",
"K9", "2HI", "67o", "4FD", "4IE", "68n", "QY", "0", "1Lf", "2id", "6RJ", "4gi", "4jY", "auh", "6M", "0Qw", "1oz", "2Jx", "5A5", "4Du",
"6oT", "4Zw", "0aY", "Bk", "lG", "0Ou", "40S", "6Ax", "6LH", "4yk", "0BE", "aw", "2YJ", "0li", "4WG", "6bd", "6me", "4XF", "0ch", "2VK",
"nv", "0MD", "42b", "6CI", "6Ny", "7K9", "1PU", "cF", "Mj", "0nX", "4Uv", "5P6", "66q", "4GZ", "1lU", "1y4", "5b", "0RX", "4iv", "5l6",
"6Qe", "4dF", "1OI", "8R", "Rv", "05L", "4Jj", "7oh", "6pH", "4Ek", "1nd", "2Kf", "7S", "0Pi", "4kG", "7NE", "5c7", "4fw", "1Mx", "0H8",
"PG", "0su", "5Xz", "69p", "4VY", "4C8", "NE", "0mw", "1Sz", "22p", "6MV", "4xu", "41M", "7PG", "mY", "x8", "14n", "Cu", "6nJ", "5KH",
"4Th", "6aK", "Lt", "0oF", "31", "bX", "6Og", "4zD", "4wt", "5r4", "oh", "0LZ", "0bv", "AD", "4L9", "4YX", "1NS", "9H", "445", "51u",
"4Kp", "5N0", "Sl", "04V", "09f", "2HM", "67k", "5Va", "4hl", "7Mn", "4x", "0SB", "1Lb", "3yA", "6RN", "4gm", "4IA", "68j", "2GL", "4",
"82O", "d4G", "5A1", "4Dq", "bPn", "a1d", "6I", "0Qs", "lC", "0Oq", "40W", "akn", "6oP", "4Zs", "15t", "Bo", "2YN", "0lm", "4WC", "76I",
"6LL", "4yo", "0BA", "as", "nr", "8DX", "42f", "6CM", "6ma", "4XB", "0cl", "2VO", "Mn", "8gD", "4Ur", "5P2", "ado", "bAm", "1PQ", "cB",
"Rz", "0qH", "4Jf", "7od", "6Qi", "4dJ", "i7", "2jG", "5n", "0RT", "4iz", "7Lx", "4R7", "4GV", "08p", "1y8", "PK", "07q", "4HW", "7mU",
"6SX", "52R", "1Mt", "0H4", "sW", "f6", "4kK", "7NI", "64L", "4Eg", "1nh", "2Kj", "14b", "Cy", "6nF", "5KD", "41A", "7PK", "mU", "x4",
"0CW", "0V6", "591", "4xy", "4VU", "4C4", "NI", "19R", "0bz", "AH", "4L5", "4YT", "43p", "560", "od", "0LV", "w5", "bT", "6Ok", "4zH",
"4Td", "6aG", "Lx", "0oJ", "5xA", "7Mb", "4t", "0SN", "K1", "2HA", "67g", "4FL", "b5G", "aTM", "0e3", "04Z", "8Wf", "9D", "449", "4eP",
"4jQ", "7OS", "6E", "255", "1or", "0j2", "65V", "cno", "4IM", "68f", "QQ", "8", "1Ln", "2il", "6RB", "4ga", "afR", "4yc", "0BM", "23f",
"OS", "Z2", "4WO", "6bl", "aEN", "c4e", "0aQ", "Bc", "lO", "8Fe", "4tS", "4a2", "4n3", "5ks", "8Id", "cN", "Mb", "0nP", "614", "74t",
"6mm", "4XN", "U3", "2VC", "2xo", "0ML", "42j", "6CA", "6Qm", "4dN", "i3", "8Z", "2Do", "05D", "4Jb", "aUS", "4R3", "4GR", "08t", "d7d",
"5j", "0RP", "bSM", "a2G", "ayN", "52V", "1Mp", "0H0", "PO", "07u", "4HS", "69x", "64H", "4Ec", "1nl", "2Kn", "sS", "f2", "4kO", "7NM",
"41E", "7PO", "mQ", "x0", "14f", "2Ul", "6nB", "aQ1", "4VQ", "4C0", "NM", "19V", "0CS", "0V2", "595", "bBN", "43t", "564", "0Y3", "0LR",
"16W", "AL", "4L1", "4YP", "5DA", "6aC", "2Zm", "0oN", "39", "bP", "6Oo", "4zL", "K5", "2HE", "67c", "4FH", "4hd", "7Mf", "4p", "0SJ",
"8Wb", "2kY", "4p5", "4eT", "4Kx", "5N8", "Sd", "0pV", "1ov", "0j6", "5A9", "4Dy", "4jU", "7OW", "6A", "1AZ", "1Lj", "2ih", "6RF", "4ge",
"4II", "68b", "QU", "D4", "OW", "Z6", "4WK", "6bh", "6LD", "4yg", "0BI", "23b", "lK", "0Oy", "4tW", "4a6", "6oX", "5JZ", "0aU", "Bg",
"Mf", "0nT", "4Uz", "74p", "4n7", "5kw", "1PY", "cJ", "nz", "0MH", "42n", "6CE", "6mi", "4XJ", "U7", "2VG", "4MP", "4X1", "UL", "02v",
"0XR", "0M3", "a8E", "57U", "4nL", "7KN", "2X", "c1", "1ko", "2Nm", "61K", "5PA", "4Oa", "6zB", "2Al", "00G", "l0", "yQ", "6Tn", "4aM",
"58T", "a7D", "0i", "0WS", "84o", "ZM", "4W0", "4BQ", "4I2", "5Lr", "13T", "G", "jc", "0IQ", "46w", "537", "6Jl", "5on", "r2", "gS",
"3OO", "0jM", "4Qc", "70i", "6kA", "5NC", "0eL", "2Po", "hR", "8Bx", "44F", "6Em", "abO", "49v", "0FP", "eb", "KN", "8ad", "4SR", "4F3",
"3B", "0Tx", "4oV", "4z7", "60Q", "4Az", "0zT", "Yf", "TV", "A7", "4LJ", "6yi", "6WE", "4bf", "0YH", "zz", "1s", "0VI", "4mg", "6XD",
"6vh", "4CK", "N6", "2MF", "Vg", "0uU", "6n9", "7ky", "4u6", "5pv", "1KX", "xK", "1UZ", "fI", "4k4", "5nt", "4Py", "5U9", "He", "0kW",
"P4", "EU", "6hj", "5Mh", "47m", "6FF", "ky", "0HK", "0GJ", "dx", "6IG", "48l", "4RH", "6gk", "JT", "0if", "0dV", "Gd", "5Z8", "5OY",
"4qT", "4d5", "iH", "0Jz", "0XV", "0M7", "5f8", "4cx", "4MT", "4X5", "UH", "02r", "1kk", "Xx", "61O", "5PE", "4nH", "7KJ", "vT", "c5",
"l4", "yU", "6Tj", "4aI", "4Oe", "6zF", "Wy", "00C", "1iZ", "ZI", "4W4", "4BU", "4ly", "5i9", "0m", "0WW", "jg", "0IU", "46s", "533",
"4I6", "5Lv", "0gy", "C", "3OK", "0jI", "4Qg", "6dD", "6Jh", "5oj", "r6", "gW", "hV", "0Kd", "44B", "6Ei", "6kE", "5NG", "0eH", "Fz",
"KJ", "0hx", "4SV", "4F7", "6HY", "49r", "0FT", "ef", "60U", "ckl", "0zP", "Yb", "3F", "206", "4oR", "4z3", "6WA", "4bb", "0YL", "2lo",
"TR", "A3", "4LN", "6ym", "62d", "4CO", "N2", "2MB", "1w", "0VM", "4mc", "7Ha", "4u2", "54z", "8Re", "xO", "Vc", "01Y", "b0D", "aQN",
"647", "71w", "Ha", "0kS", "8Lg", "fM", "4k0", "5np", "47i", "6FB", "29d", "0HO", "P0", "EQ", "6hn", "5Ml", "4RL", "6go", "JP", "0ib",
"0GN", "26e", "6IC", "48h", "45X", "4d1", "iL", "8Cf", "0dR", "0q3", "hYt", "beO", "4nD", "7KF", "2P", "c9", "1kg", "Xt", "61C", "5PI",
"4MX", "4X9", "UD", "0vv", "0XZ", "2my", "5f4", "4ct", "4lu", "5i5", "0a", "1Gz", "0yw", "ZE", "4W8", "4BY", "4Oi", "6zJ", "Wu", "00O",
"l8", "yY", "6Tf", "4aE", "6Jd", "5of", "62", "25B", "Iw", "0jE", "4Qk", "6dH", "6ix", "5Lz", "0gu", "O", "jk", "0IY", "4rw", "5w7",
"5x6", "5mW", "0FX", "ej", "KF", "0ht", "4SZ", "6fy", "6kI", "5NK", "0eD", "Fv", "hZ", "93", "44N", "6Ee", "2BO", "03d", "4LB", "6ya",
"6WM", "4bn", "1Ia", "zr", "3J", "0Tp", "bUm", "a4g", "5D2", "4Ar", "87L", "Yn", "Vo", "01U", "4Ns", "5K3", "416", "54v", "1KP", "xC",
"us", "0VA", "4mo", "6XL", "62h", "4CC", "0xm", "2MN", "0fo", "2SL", "6hb", "bgr", "47e", "6FN", "kq", "0HC", "0Es", "fA", "aal", "bDn",
"4Pq", "5U1", "Hm", "8bG", "10w", "Gl", "5Z0", "5OQ", "45T", "anm", "1O2", "0Jr", "0GB", "dp", "6IO", "48d", "5Ba", "6gc", "3Ll", "0in",
"1kc", "Xp", "61G", "5PM", "bTs", "7KB", "2T", "0Un", "8QF", "39T", "5f0", "4cp", "797", "aRm", "1s2", "02z", "0ys", "ZA", "63v", "766",
"4lq", "5i1", "0e", "9Nf", "0Zo", "2oL", "6Tb", "4aA", "4Om", "6zN", "Wq", "00K", "Is", "0jA", "4Qo", "6dL", "7ZA", "5ob", "66", "25F",
"jo", "9Pd", "4rs", "5w3", "aCn", "bfl", "0gq", "K", "KB", "0hp", "bim", "72T", "5x2", "49z", "327", "en", "3nn", "97", "44J", "6Ea",
"6kM", "5NO", "11i", "Fr", "6WI", "4bj", "0YD", "zv", "TZ", "0wh", "4LF", "6ye", "5D6", "4Av", "0zX", "Yj", "3N", "0Tt", "4oZ", "6Zy",
"412", "54r", "1KT", "xG", "Vk", "01Q", "4Nw", "5K7", "62l", "4CG", "0xi", "2MJ", "uw", "0VE", "4mk", "6XH", "47a", "6FJ", "ku", "0HG",
"P8", "EY", "6hf", "5Md", "4Pu", "5U5", "Hi", "8bC", "0Ew", "fE", "4k8", "5nx", "45P", "4d9", "iD", "0Jv", "0dZ", "Gh", "5Z4", "5OU",
"4RD", "6gg", "JX", "0ij", "0GF", "dt", "6IK", "5lI", "4Op", "5J0", "Wl", "00V", "0Zr", "2oQ", "405", "55u", "4ll", "6YO", "0x", "0WB",
"0yn", "2LM", "63k", "5Ra", "4MA", "6xb", "2CL", "02g", "0XC", "39I", "6VN", "4cm", "bTn", "a5d", "2I", "0Us", "86O", "Xm", "5E1", "5PP",
"6kP", "5NR", "11t", "Fo", "hC", "0Kq", "44W", "aon", "6HL", "49g", "0FA", "es", "3Mo", "0hm", "4SC", "72I", "6ia", "5Lc", "0gl", "V",
"jr", "1Ya", "46f", "6GM", "hyV", "bEm", "0Dp", "gB", "In", "8cD", "4Qr", "5T2", "1b", "0VX", "4mv", "5h6", "62q", "4CZ", "0xt", "2MW",
"Vv", "01L", "4Nj", "7kh", "6Ue", "54o", "1KI", "xZ", "3S", "0Ti", "4oG", "6Zd", "6tH", "4Ak", "0zE", "Yw", "TG", "0wu", "780", "6yx",
"5g7", "4bw", "0YY", "zk", "1Wz", "di", "5y5", "5lT", "4RY", "4G8", "JE", "0iw", "0dG", "Gu", "6jJ", "5OH", "45M", "6Df", "iY", "80",
"71", "fX", "6Kg", "5ne", "4Ph", "6eK", "Ht", "0kF", "0fv", "ED", "4H9", "5My", "4st", "5v4", "kh", "0HZ", "0Zv", "yD", "401", "4aX",
"4Ot", "5J4", "Wh", "00R", "O9", "ZX", "63o", "4BD", "4lh", "6YK", "tt", "0WF", "0XG", "2md", "6VJ", "4ci", "4ME", "6xf", "UY", "02c",
"1kz", "Xi", "5E5", "5PT", "4nY", "aqh", "2M", "0Uw", "hG", "0Ku", "44S", "6Ex", "6kT", "5NV", "0eY", "Fk", "3Mk", "0hi", "4SG", "6fd",
"6HH", "49c", "0FE", "ew", "jv", "0ID", "46b", "6GI", "6ie", "5Lg", "0gh", "R", "Ij", "0jX", "4Qv", "5T6", "6Jy", "7O9", "0Dt", "gF",
"62u", "775", "0xp", "198", "1f", "9Oe", "4mr", "5h2", "6Ua", "54k", "1KM", "2nO", "Vr", "01H", "4Nn", "7kl", "60D", "4Ao", "0zA", "Ys",
"3W", "0Tm", "4oC", "7JA", "5g3", "4bs", "8PE", "zo", "TC", "03y", "784", "aSn", "bhn", "73W", "JA", "0is", "334", "dm", "5y1", "48y",
"45I", "6Db", "3om", "84", "0dC", "Gq", "6jN", "5OL", "4Pl", "6eO", "Hp", "0kB", "75", "24E", "6Kc", "5na", "47x", "528", "kl", "8AF",
"0fr", "1c2", "aBm", "bgo", "4ld", "6YG", "0p", "0WJ", "O5", "ZT", "63c", "4BH", "4Ox", "5J8", "Wd", "0tV", "0Zz", "yH", "4t5", "4aT",
"4nU", "7KW", "2A", "1EZ", "1kv", "Xe", "5E9", "5PX", "4MI", "6xj", "UU", "02o", "0XK", "2mh", "6VF", "4ce", "6HD", "49o", "0FI", "27b",
"KW", "0he", "4SK", "6fh", "6kX", "5NZ", "0eU", "Fg", "hK", "0Ky", "4pW", "4e6", "4j7", "5ow", "0Dx", "gJ", "If", "0jT", "4Qz", "6dY",
"6ii", "5Lk", "Q7", "DV", "jz", "0IH", "46n", "6GE", "3PN", "01D", "4Nb", "aQS", "6Um", "54g", "m3", "xR", "1j", "0VP", "59W", "a6G",
"4V3", "4CR", "85l", "194", "TO", "03u", "4LS", "4Y2", "a9F", "56V", "0YQ", "zc", "wS", "b2", "4oO", "6Zl", "60H", "4Ac", "0zM", "2On",
"0dO", "2Ql", "6jB", "aU1", "45E", "6Dn", "iQ", "88", "0GS", "da", "acL", "48u", "4RQ", "4G0", "JM", "94N", "12W", "EL", "4H1", "5Mq",
"47t", "524", "29y", "0HR", "79", "fP", "6Ko", "5nm", "aZ0", "6eC", "3NL", "0kN", "O1", "ZP", "63g", "4BL", "58I", "6YC", "0t", "0WN",
"8Sf", "yL", "409", "4aP", "b1G", "aPM", "0a3", "00Z", "1kr", "Xa", "61V", "bzN", "4nQ", "7KS", "2E", "215", "0XO", "2ml", "6VB", "4ca",
"4MM", "6xn", "UQ", "02k", "KS", "0ha", "4SO", "6fl", "7Xa", "49k", "0FM", "27f", "hO", "8Be", "4pS", "4e2", "aAN", "bdL", "0eQ", "Fc",
"Ib", "0jP", "654", "70t", "4j3", "5os", "8Md", "gN", "28g", "0IL", "46j", "6GA", "6im", "5Lo", "Q3", "Z", "6Ui", "54c", "m7", "xV",
"Vz", "0uH", "4Nf", "7kd", "4V7", "4CV", "0xx", "190", "1n", "0VT", "4mz", "6XY", "6WX", "56R", "0YU", "zg", "TK", "03q", "4LW", "4Y6",
"60L", "4Ag", "0zI", "2Oj", "wW", "b6", "4oK", "6Zh", "45A", "6Dj", "iU", "0Jg", "0dK", "Gy", "6jF", "5OD", "4RU", "4G4", "JI", "1yZ",
"0GW", "de", "5y9", "48q", "47p", "520", "kd", "0HV", "0fz", "EH", "4H5", "5Mu", "4Pd", "6eG", "Hx", "0kJ", "s5", "fT", "6Kk", "5ni",
"5Y1", "5LP", "13v", "e", "jA", "0Is", "46U", "aml", "6JN", "5oL", "0DC", "gq", "3Om", "0jo", "4QA", "6db", "6kc", "5Na", "0en", "2PM",
"hp", "0KB", "44d", "6EO", "abm", "49T", "0Fr", "1C2", "Kl", "8aF", "4Sp", "5V0", "4Mr", "5H2", "Un", "02T", "0Xp", "2mS", "427", "57w",
"4nn", "7Kl", "2z", "1Ea", "1kM", "2NO", "61i", "5Pc", "4OC", "7jA", "2AN", "00e", "0ZA", "ys", "6TL", "4ao", "58v", "a7f", "0K", "0Wq",
"84M", "Zo", "5G3", "4Bs", "0EY", "fk", "6KT", "5nV", "bjh", "6ex", "HG", "0ku", "0fE", "Ew", "6hH", "5MJ", "47O", "6Fd", "29B", "0Hi",
"53", "dZ", "6Ie", "48N", "4Rj", "6gI", "Jv", "0iD", "0dt", "GF", "6jy", "7o9", "4qv", "5t6", "ij", "0JX", "wh", "0TZ", "4ot", "5j4",
"4T9", "4AX", "0zv", "YD", "Tt", "03N", "4Lh", "6yK", "6Wg", "4bD", "o9", "zX", "1Q", "0Vk", "4mE", "6Xf", "62B", "4Ci", "0xG", "2Md",
"VE", "0uw", "4NY", "aQh", "5e5", "5pT", "1Kz", "xi", "jE", "0Iw", "46Q", "4g8", "5Y5", "5LT", "13r", "a", "IY", "0jk", "4QE", "6df",
"6JJ", "5oH", "0DG", "gu", "ht", "0KF", "4ph", "6EK", "6kg", "5Ne", "S9", "FX", "Kh", "0hZ", "4St", "5V4", "4h9", "49P", "0Fv", "eD",
"0Xt", "2mW", "423", "4cZ", "4Mv", "5H6", "Uj", "02P", "1kI", "XZ", "61m", "5Pg", "4nj", "7Kh", "vv", "0UD", "0ZE", "yw", "6TH", "4ak",
"4OG", "6zd", "2AJ", "00a", "0yY", "Zk", "5G7", "4Bw", "58r", "6Yx", "0O", "0Wu", "bjl", "71U", "HC", "0kq", "316", "fo", "6KP", "5nR",
"47K", "7VA", "29F", "0Hm", "0fA", "Es", "6hL", "5MN", "4Rn", "6gM", "Jr", "1ya", "57", "26G", "6Ia", "48J", "45z", "5t2", "in", "8CD",
"0dp", "GB", "hYV", "bem", "60w", "757", "0zr", "2OQ", "3d", "9Mg", "4op", "5j0", "6Wc", "56i", "0Yn", "2lM", "Tp", "03J", "4Ll", "6yO",
"62F", "4Cm", "0xC", "dwS", "1U", "0Vo", "4mA", "6Xb", "5e1", "54X", "8RG", "xm", "VA", "0us", "b0f", "aQl", "6JF", "5oD", "0DK", "gy",
"IU", "0jg", "4QI", "6dj", "5Y9", "5LX", "0gW", "m", "jI", "1YZ", "4rU", "4g4", "4h5", "5mu", "0Fz", "eH", "Kd", "0hV", "4Sx", "5V8",
"6kk", "5Ni", "S5", "FT", "hx", "0KJ", "44l", "6EG", "4nf", "7Kd", "2r", "0UH", "M7", "XV", "61a", "5Pk", "4Mz", "6xY", "Uf", "0vT",
"0Xx", "39r", "4v7", "4cV", "4lW", "4y6", "0C", "0Wy", "0yU", "Zg", "63P", "5RZ", "4OK", "6zh", "WW", "B6", "0ZI", "2oj", "6TD", "4ag",
"0fM", "2Sn", "7xa", "5MB", "47G", "6Fl", "kS", "0Ha", "0EQ", "fc", "aaN", "bDL", "4PS", "4E2", "HO", "8be", "10U", "GN", "4J3", "5Os",
"45v", "506", "ib", "0JP", "q3", "dR", "6Im", "48F", "4Rb", "6gA", "3LN", "0iL", "2Bm", "03F", "aF0", "6yC", "6Wo", "4bL", "o1", "zP",
"3h", "0TR", "bUO", "a4E", "4T1", "4AP", "87n", "YL", "VM", "01w", "4NQ", "7kS", "hfu", "54T", "1Kr", "xa", "1Y", "0Vc", "4mM", "6Xn",
"62J", "4Ca", "0xO", "2Ml", "IQ", "0jc", "4QM", "6dn", "6JB", "a19", "0DO", "25d", "jM", "9PF", "46Y", "4g0", "aCL", "687", "0gS", "i",
"3MP", "0hR", "676", "72v", "4h1", "49X", "8Of", "eL", "3nL", "0KN", "44h", "6EC", "6ko", "5Nm", "S1", "FP", "M3", "XR", "61e", "5Po",
"4nb", "aqS", "2v", "0UL", "8Qd", "39v", "4v3", "4cR", "b3E", "aRO", "Ub", "02X", "0yQ", "Zc", "63T", "bxL", "4lS", "4y2", "0G", "237",
"0ZM", "2on", "7Da", "4ac", "4OO", "6zl", "WS", "B2", "47C", "6Fh", "kW", "0He", "0fI", "2Sj", "6hD", "5MF", "4PW", "4E6", "HK", "0ky",
"0EU", "fg", "6KX", "5nZ", "45r", "502", "if", "0JT", "0dx", "GJ", "4J7", "5Ow", "4Rf", "6gE", "Jz", "0iH", "q7", "dV", "6Ii", "48B",
"6Wk", "4bH", "o5", "zT", "Tx", "03B", "4Ld", "6yG", "4T5", "4AT", "0zz", "YH", "3l", "0TV", "4ox", "5j8", "5e9", "54P", "1Kv", "xe",
"VI", "01s", "4NU", "7kW", "62N", "4Ce", "0xK", "2Mh", "uU", "0Vg", "4mI", "6Xj", "4K0", "5Np", "11V", "FM", "ha", "0KS", "44u", "515",
"6Hn", "49E", "48", "eQ", "3MM", "0hO", "4Sa", "6fB", "6iC", "5LA", "0gN", "t", "jP", "0Ib", "46D", "6Go", "hyt", "bEO", "0DR", "0Q3",
"IL", "8cf", "4QP", "4D1", "4OR", "4Z3", "WN", "00t", "0ZP", "yb", "hgv", "55W", "4lN", "6Ym", "0Z", "a3", "0yL", "2Lo", "63I", "4Bb",
"4Mc", "7ha", "2Cn", "02E", "n2", "2mB", "6Vl", "4cO", "bTL", "a5F", "2k", "0UQ", "86m", "XO", "4U2", "5Pr", "0Gy", "dK", "4i6", "5lv",
"5BZ", "6gX", "Jg", "0iU", "R6", "GW", "6jh", "5Oj", "45o", "6DD", "3oK", "0JI", "0EH", "fz", "6KE", "5nG", "4PJ", "6ei", "HV", "0kd",
"0fT", "Ef", "6hY", "690", "4sV", "4f7", "kJ", "0Hx", "uH", "0Vz", "4mT", "4x5", "5F8", "4Cx", "0xV", "0m7", "VT", "C5", "4NH", "7kJ",
"6UG", "54M", "1Kk", "xx", "3q", "0TK", "4oe", "6ZF", "60b", "4AI", "L4", "YU", "Te", "0wW", "4Ly", "5I9", "4w4", "4bU", "1IZ", "zI",
"he", "0KW", "44q", "511", "4K4", "5Nt", "11R", "FI", "Ky", "0hK", "4Se", "6fF", "6Hj", "49A", "p4", "eU", "jT", "0If", "4rH", "6Gk",
"6iG", "5LE", "0gJ", "p", "IH", "0jz", "4QT", "4D5", "5z8", "5oY", "0DV", "gd", "0ZT", "yf", "6TY", "4az", "4OV", "4Z7", "WJ", "00p",
"0yH", "Zz", "63M", "4Bf", "4lJ", "6Yi", "tV", "a7", "n6", "2mF", "6Vh", "4cK", "4Mg", "6xD", "2Cj", "02A", "1kX", "XK", "4U6", "5Pv",
"6N9", "7Ky", "2o", "0UU", "665", "73u", "Jc", "0iQ", "8Ne", "dO", "4i2", "5lr", "45k", "7Ta", "3oO", "0JM", "R2", "GS", "6jl", "5On",
"4PN", "6em", "HR", "8bx", "0EL", "24g", "6KA", "5nC", "47Z", "4f3", "kN", "8Ad", "0fP", "Eb", "aBO", "694", "62W", "byO", "0xR", "0m3",
"1D", "224", "4mP", "4x1", "6UC", "54I", "1Ko", "2nm", "VP", "C1", "4NL", "7kN", "60f", "4AM", "L0", "YQ", "3u", "0TO", "4oa", "6ZB",
"438", "4bQ", "8Pg", "zM", "Ta", "0wS", "b2F", "aSL", "6Hf", "49M", "40", "eY", "Ku", "0hG", "4Si", "6fJ", "4K8", "5Nx", "0ew", "FE",
"hi", "8BC", "4pu", "5u5", "5z4", "5oU", "0DZ", "gh", "ID", "0jv", "4QX", "4D9", "6iK", "5LI", "0gF", "Dt", "jX", "0Ij", "46L", "6Gg",
"4lF", "6Ye", "0R", "0Wh", "0yD", "Zv", "63A", "4Bj", "4OZ", "6zy", "WF", "0tt", "0ZX", "yj", "5d6", "4av", "4nw", "5k7", "2c", "0UY",
"1kT", "XG", "61p", "5Pz", "4Mk", "6xH", "Uw", "02M", "0Xi", "2mJ", "6Vd", "4cG", "0dm", "2QN", "7zA", "5Ob", "45g", "6DL", "is", "0JA",
"0Gq", "dC", "acn", "48W", "4Rs", "5W3", "Jo", "94l", "12u", "En", "5X2", "5MS", "47V", "alo", "kB", "0Hp", "1Ua", "fr", "6KM", "5nO",
"4PB", "6ea", "3Nn", "0kl", "3Pl", "01f", "bts", "7kB", "6UO", "54E", "1Kc", "xp", "1H", "0Vr", "59u", "a6e", "5F0", "4Cp", "85N", "d3F",
"Tm", "03W", "4Lq", "5I1", "434", "56t", "0Ys", "zA", "3y", "0TC", "4om", "6ZN", "60j", "4AA", "0zo", "2OL", "Kq", "0hC", "4Sm", "6fN",
"6Hb", "49I", "44", "27D", "hm", "8BG", "44y", "519", "aAl", "bdn", "0es", "FA", "1o2", "0jr", "bko", "70V", "5z0", "5oQ", "305", "gl",
"28E", "0In", "46H", "6Gc", "6iO", "5LM", "0gB", "x", "1ia", "Zr", "63E", "4Bn", "4lB", "6Ya", "0V", "0Wl", "8SD", "yn", "5d2", "4ar",
"b1e", "aPo", "WB", "00x", "1kP", "XC", "61t", "744", "4ns", "5k3", "2g", "9Ld", "0Xm", "2mN", "7FA", "4cC", "4Mo", "6xL", "Us", "02I",
"45c", "6DH", "iw", "0JE", "0di", "2QJ", "6jd", "5Of", "4Rw", "5W7", "Jk", "0iY", "0Gu", "dG", "6Ix", "48S", "47R", "6Fy", "kF", "0Ht",
"0fX", "Ej", "5X6", "5MW", "4PF", "6ee", "HZ", "0kh", "0ED", "fv", "6KI", "5nK", "6UK", "54A", "1Kg", "xt", "VX", "C9", "4ND", "7kF",
"5F4", "4Ct", "0xZ", "2My", "1L", "0Vv", "4mX", "4x9", "430", "4bY", "0Yw", "zE", "Ti", "03S", "4Lu", "5I5", "60n", "4AE", "L8", "YY",
"wu", "0TG", "4oi", "6ZJ" };
#endif
+117 -152
View File
@@ -1,16 +1,5 @@
/* Redis uses the CRC64 variant with "Jones" coefficients and init value of 0.
*
* Specification of this CRC64 variant follows:
* Name: crc-64-jones
* Width: 64 bites
* Poly: 0xad93d23594c935a9
* Reflected In: True
* Xor_In: 0xffffffffffffffff
* Reflected_Out: True
* Xor_Out: 0x0
* Check("123456789"): 0xe9c6d914c4b8d9ca
*
* Copyright (c) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
/* Copyright (c) 2014, Matt Stancliff <matt@genges.com>
* Copyright (c) 2020, Amazon Web Services
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,147 +26,100 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. */
#include <stdint.h>
#include "crc64.h"
#include "crcspeed.h"
static uint64_t crc64_table[8][256] = {{0}};
static const uint64_t crc64_tab[256] = {
UINT64_C(0x0000000000000000), UINT64_C(0x7ad870c830358979),
UINT64_C(0xf5b0e190606b12f2), UINT64_C(0x8f689158505e9b8b),
UINT64_C(0xc038e5739841b68f), UINT64_C(0xbae095bba8743ff6),
UINT64_C(0x358804e3f82aa47d), UINT64_C(0x4f50742bc81f2d04),
UINT64_C(0xab28ecb46814fe75), UINT64_C(0xd1f09c7c5821770c),
UINT64_C(0x5e980d24087fec87), UINT64_C(0x24407dec384a65fe),
UINT64_C(0x6b1009c7f05548fa), UINT64_C(0x11c8790fc060c183),
UINT64_C(0x9ea0e857903e5a08), UINT64_C(0xe478989fa00bd371),
UINT64_C(0x7d08ff3b88be6f81), UINT64_C(0x07d08ff3b88be6f8),
UINT64_C(0x88b81eabe8d57d73), UINT64_C(0xf2606e63d8e0f40a),
UINT64_C(0xbd301a4810ffd90e), UINT64_C(0xc7e86a8020ca5077),
UINT64_C(0x4880fbd87094cbfc), UINT64_C(0x32588b1040a14285),
UINT64_C(0xd620138fe0aa91f4), UINT64_C(0xacf86347d09f188d),
UINT64_C(0x2390f21f80c18306), UINT64_C(0x594882d7b0f40a7f),
UINT64_C(0x1618f6fc78eb277b), UINT64_C(0x6cc0863448deae02),
UINT64_C(0xe3a8176c18803589), UINT64_C(0x997067a428b5bcf0),
UINT64_C(0xfa11fe77117cdf02), UINT64_C(0x80c98ebf2149567b),
UINT64_C(0x0fa11fe77117cdf0), UINT64_C(0x75796f2f41224489),
UINT64_C(0x3a291b04893d698d), UINT64_C(0x40f16bccb908e0f4),
UINT64_C(0xcf99fa94e9567b7f), UINT64_C(0xb5418a5cd963f206),
UINT64_C(0x513912c379682177), UINT64_C(0x2be1620b495da80e),
UINT64_C(0xa489f35319033385), UINT64_C(0xde51839b2936bafc),
UINT64_C(0x9101f7b0e12997f8), UINT64_C(0xebd98778d11c1e81),
UINT64_C(0x64b116208142850a), UINT64_C(0x1e6966e8b1770c73),
UINT64_C(0x8719014c99c2b083), UINT64_C(0xfdc17184a9f739fa),
UINT64_C(0x72a9e0dcf9a9a271), UINT64_C(0x08719014c99c2b08),
UINT64_C(0x4721e43f0183060c), UINT64_C(0x3df994f731b68f75),
UINT64_C(0xb29105af61e814fe), UINT64_C(0xc849756751dd9d87),
UINT64_C(0x2c31edf8f1d64ef6), UINT64_C(0x56e99d30c1e3c78f),
UINT64_C(0xd9810c6891bd5c04), UINT64_C(0xa3597ca0a188d57d),
UINT64_C(0xec09088b6997f879), UINT64_C(0x96d1784359a27100),
UINT64_C(0x19b9e91b09fcea8b), UINT64_C(0x636199d339c963f2),
UINT64_C(0xdf7adabd7a6e2d6f), UINT64_C(0xa5a2aa754a5ba416),
UINT64_C(0x2aca3b2d1a053f9d), UINT64_C(0x50124be52a30b6e4),
UINT64_C(0x1f423fcee22f9be0), UINT64_C(0x659a4f06d21a1299),
UINT64_C(0xeaf2de5e82448912), UINT64_C(0x902aae96b271006b),
UINT64_C(0x74523609127ad31a), UINT64_C(0x0e8a46c1224f5a63),
UINT64_C(0x81e2d7997211c1e8), UINT64_C(0xfb3aa75142244891),
UINT64_C(0xb46ad37a8a3b6595), UINT64_C(0xceb2a3b2ba0eecec),
UINT64_C(0x41da32eaea507767), UINT64_C(0x3b024222da65fe1e),
UINT64_C(0xa2722586f2d042ee), UINT64_C(0xd8aa554ec2e5cb97),
UINT64_C(0x57c2c41692bb501c), UINT64_C(0x2d1ab4dea28ed965),
UINT64_C(0x624ac0f56a91f461), UINT64_C(0x1892b03d5aa47d18),
UINT64_C(0x97fa21650afae693), UINT64_C(0xed2251ad3acf6fea),
UINT64_C(0x095ac9329ac4bc9b), UINT64_C(0x7382b9faaaf135e2),
UINT64_C(0xfcea28a2faafae69), UINT64_C(0x8632586aca9a2710),
UINT64_C(0xc9622c4102850a14), UINT64_C(0xb3ba5c8932b0836d),
UINT64_C(0x3cd2cdd162ee18e6), UINT64_C(0x460abd1952db919f),
UINT64_C(0x256b24ca6b12f26d), UINT64_C(0x5fb354025b277b14),
UINT64_C(0xd0dbc55a0b79e09f), UINT64_C(0xaa03b5923b4c69e6),
UINT64_C(0xe553c1b9f35344e2), UINT64_C(0x9f8bb171c366cd9b),
UINT64_C(0x10e3202993385610), UINT64_C(0x6a3b50e1a30ddf69),
UINT64_C(0x8e43c87e03060c18), UINT64_C(0xf49bb8b633338561),
UINT64_C(0x7bf329ee636d1eea), UINT64_C(0x012b592653589793),
UINT64_C(0x4e7b2d0d9b47ba97), UINT64_C(0x34a35dc5ab7233ee),
UINT64_C(0xbbcbcc9dfb2ca865), UINT64_C(0xc113bc55cb19211c),
UINT64_C(0x5863dbf1e3ac9dec), UINT64_C(0x22bbab39d3991495),
UINT64_C(0xadd33a6183c78f1e), UINT64_C(0xd70b4aa9b3f20667),
UINT64_C(0x985b3e827bed2b63), UINT64_C(0xe2834e4a4bd8a21a),
UINT64_C(0x6debdf121b863991), UINT64_C(0x1733afda2bb3b0e8),
UINT64_C(0xf34b37458bb86399), UINT64_C(0x8993478dbb8deae0),
UINT64_C(0x06fbd6d5ebd3716b), UINT64_C(0x7c23a61ddbe6f812),
UINT64_C(0x3373d23613f9d516), UINT64_C(0x49aba2fe23cc5c6f),
UINT64_C(0xc6c333a67392c7e4), UINT64_C(0xbc1b436e43a74e9d),
UINT64_C(0x95ac9329ac4bc9b5), UINT64_C(0xef74e3e19c7e40cc),
UINT64_C(0x601c72b9cc20db47), UINT64_C(0x1ac40271fc15523e),
UINT64_C(0x5594765a340a7f3a), UINT64_C(0x2f4c0692043ff643),
UINT64_C(0xa02497ca54616dc8), UINT64_C(0xdafce7026454e4b1),
UINT64_C(0x3e847f9dc45f37c0), UINT64_C(0x445c0f55f46abeb9),
UINT64_C(0xcb349e0da4342532), UINT64_C(0xb1eceec59401ac4b),
UINT64_C(0xfebc9aee5c1e814f), UINT64_C(0x8464ea266c2b0836),
UINT64_C(0x0b0c7b7e3c7593bd), UINT64_C(0x71d40bb60c401ac4),
UINT64_C(0xe8a46c1224f5a634), UINT64_C(0x927c1cda14c02f4d),
UINT64_C(0x1d148d82449eb4c6), UINT64_C(0x67ccfd4a74ab3dbf),
UINT64_C(0x289c8961bcb410bb), UINT64_C(0x5244f9a98c8199c2),
UINT64_C(0xdd2c68f1dcdf0249), UINT64_C(0xa7f41839ecea8b30),
UINT64_C(0x438c80a64ce15841), UINT64_C(0x3954f06e7cd4d138),
UINT64_C(0xb63c61362c8a4ab3), UINT64_C(0xcce411fe1cbfc3ca),
UINT64_C(0x83b465d5d4a0eece), UINT64_C(0xf96c151de49567b7),
UINT64_C(0x76048445b4cbfc3c), UINT64_C(0x0cdcf48d84fe7545),
UINT64_C(0x6fbd6d5ebd3716b7), UINT64_C(0x15651d968d029fce),
UINT64_C(0x9a0d8ccedd5c0445), UINT64_C(0xe0d5fc06ed698d3c),
UINT64_C(0xaf85882d2576a038), UINT64_C(0xd55df8e515432941),
UINT64_C(0x5a3569bd451db2ca), UINT64_C(0x20ed197575283bb3),
UINT64_C(0xc49581ead523e8c2), UINT64_C(0xbe4df122e51661bb),
UINT64_C(0x3125607ab548fa30), UINT64_C(0x4bfd10b2857d7349),
UINT64_C(0x04ad64994d625e4d), UINT64_C(0x7e7514517d57d734),
UINT64_C(0xf11d85092d094cbf), UINT64_C(0x8bc5f5c11d3cc5c6),
UINT64_C(0x12b5926535897936), UINT64_C(0x686de2ad05bcf04f),
UINT64_C(0xe70573f555e26bc4), UINT64_C(0x9ddd033d65d7e2bd),
UINT64_C(0xd28d7716adc8cfb9), UINT64_C(0xa85507de9dfd46c0),
UINT64_C(0x273d9686cda3dd4b), UINT64_C(0x5de5e64efd965432),
UINT64_C(0xb99d7ed15d9d8743), UINT64_C(0xc3450e196da80e3a),
UINT64_C(0x4c2d9f413df695b1), UINT64_C(0x36f5ef890dc31cc8),
UINT64_C(0x79a59ba2c5dc31cc), UINT64_C(0x037deb6af5e9b8b5),
UINT64_C(0x8c157a32a5b7233e), UINT64_C(0xf6cd0afa9582aa47),
UINT64_C(0x4ad64994d625e4da), UINT64_C(0x300e395ce6106da3),
UINT64_C(0xbf66a804b64ef628), UINT64_C(0xc5bed8cc867b7f51),
UINT64_C(0x8aeeace74e645255), UINT64_C(0xf036dc2f7e51db2c),
UINT64_C(0x7f5e4d772e0f40a7), UINT64_C(0x05863dbf1e3ac9de),
UINT64_C(0xe1fea520be311aaf), UINT64_C(0x9b26d5e88e0493d6),
UINT64_C(0x144e44b0de5a085d), UINT64_C(0x6e963478ee6f8124),
UINT64_C(0x21c640532670ac20), UINT64_C(0x5b1e309b16452559),
UINT64_C(0xd476a1c3461bbed2), UINT64_C(0xaeaed10b762e37ab),
UINT64_C(0x37deb6af5e9b8b5b), UINT64_C(0x4d06c6676eae0222),
UINT64_C(0xc26e573f3ef099a9), UINT64_C(0xb8b627f70ec510d0),
UINT64_C(0xf7e653dcc6da3dd4), UINT64_C(0x8d3e2314f6efb4ad),
UINT64_C(0x0256b24ca6b12f26), UINT64_C(0x788ec2849684a65f),
UINT64_C(0x9cf65a1b368f752e), UINT64_C(0xe62e2ad306bafc57),
UINT64_C(0x6946bb8b56e467dc), UINT64_C(0x139ecb4366d1eea5),
UINT64_C(0x5ccebf68aecec3a1), UINT64_C(0x2616cfa09efb4ad8),
UINT64_C(0xa97e5ef8cea5d153), UINT64_C(0xd3a62e30fe90582a),
UINT64_C(0xb0c7b7e3c7593bd8), UINT64_C(0xca1fc72bf76cb2a1),
UINT64_C(0x45775673a732292a), UINT64_C(0x3faf26bb9707a053),
UINT64_C(0x70ff52905f188d57), UINT64_C(0x0a2722586f2d042e),
UINT64_C(0x854fb3003f739fa5), UINT64_C(0xff97c3c80f4616dc),
UINT64_C(0x1bef5b57af4dc5ad), UINT64_C(0x61372b9f9f784cd4),
UINT64_C(0xee5fbac7cf26d75f), UINT64_C(0x9487ca0fff135e26),
UINT64_C(0xdbd7be24370c7322), UINT64_C(0xa10fceec0739fa5b),
UINT64_C(0x2e675fb4576761d0), UINT64_C(0x54bf2f7c6752e8a9),
UINT64_C(0xcdcf48d84fe75459), UINT64_C(0xb71738107fd2dd20),
UINT64_C(0x387fa9482f8c46ab), UINT64_C(0x42a7d9801fb9cfd2),
UINT64_C(0x0df7adabd7a6e2d6), UINT64_C(0x772fdd63e7936baf),
UINT64_C(0xf8474c3bb7cdf024), UINT64_C(0x829f3cf387f8795d),
UINT64_C(0x66e7a46c27f3aa2c), UINT64_C(0x1c3fd4a417c62355),
UINT64_C(0x935745fc4798b8de), UINT64_C(0xe98f353477ad31a7),
UINT64_C(0xa6df411fbfb21ca3), UINT64_C(0xdc0731d78f8795da),
UINT64_C(0x536fa08fdfd90e51), UINT64_C(0x29b7d047efec8728),
};
#define POLY UINT64_C(0xad93d23594c935a9)
/******************** BEGIN GENERATED PYCRC FUNCTIONS ********************/
/**
* Generated on Sun Dec 21 14:14:07 2014,
* by pycrc v0.8.2, https://www.tty1.net/pycrc/
*
* LICENSE ON GENERATED CODE:
* ==========================
* As of version 0.6, pycrc is released under the terms of the MIT licence.
* The code generated by pycrc is not considered a substantial portion of the
* software, therefore the author of pycrc will not claim any copyright on
* the generated code.
* ==========================
*
* CRC configuration:
* Width = 64
* Poly = 0xad93d23594c935a9
* XorIn = 0xffffffffffffffff
* ReflectIn = True
* XorOut = 0x0000000000000000
* ReflectOut = True
* Algorithm = bit-by-bit-fast
*
* Modifications after generation (by matt):
* - included finalize step in-line with update for single-call generation
* - re-worked some inner variable architectures
* - adjusted function parameters to match expected prototypes.
*****************************************************************************/
uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) {
uint64_t j;
/**
* Reflect all bits of a \a data word of \a data_len bytes.
*
* \param data The data word to be reflected.
* \param data_len The width of \a data expressed in number of bits.
* \return The reflected data.
*****************************************************************************/
static inline uint_fast64_t crc_reflect(uint_fast64_t data, size_t data_len) {
uint_fast64_t ret = data & 0x01;
for (j = 0; j < l; j++) {
uint8_t byte = s[j];
crc = crc64_tab[(uint8_t)crc ^ byte] ^ (crc >> 8);
for (size_t i = 1; i < data_len; i++) {
data >>= 1;
ret = (ret << 1) | (data & 0x01);
}
return crc;
return ret;
}
/**
* Update the crc value with new data.
*
* \param crc The current crc value.
* \param data Pointer to a buffer of \a data_len bytes.
* \param data_len Number of bytes in the \a data buffer.
* \return The updated crc value.
******************************************************************************/
uint64_t _crc64(uint_fast64_t crc, const void *in_data, const uint64_t len) {
const uint8_t *data = in_data;
unsigned long long bit;
for (uint64_t offset = 0; offset < len; offset++) {
uint8_t c = data[offset];
for (uint_fast8_t i = 0x01; i & 0xff; i <<= 1) {
bit = crc & 0x8000000000000000;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= POLY;
}
}
crc &= 0xffffffffffffffff;
}
crc = crc & 0xffffffffffffffff;
return crc_reflect(crc, 64) ^ 0x0000000000000000;
}
/******************** END GENERATED PYCRC FUNCTIONS ********************/
/* Initializes the 16KB lookup tables. */
void crc64_init(void) {
crcspeed64native_init(_crc64, crc64_table);
}
/* Compute crc64 */
uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) {
return crcspeed64native(crc64_table, crc, (void *) s, l);
}
/* Test main */
@@ -188,8 +130,31 @@ uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) {
int crc64Test(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);
printf("e9c6d914c4b8d9ca == %016llx\n",
(unsigned long long) crc64(0,(unsigned char*)"123456789",9));
crc64_init();
printf("[calcula]: e9c6d914c4b8d9ca == %016" PRIx64 "\n",
(uint64_t)_crc64(0, "123456789", 9));
printf("[64speed]: e9c6d914c4b8d9ca == %016" PRIx64 "\n",
(uint64_t)crc64(0, "123456789", 9));
char li[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed "
"do eiusmod tempor incididunt ut labore et dolore magna "
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis "
"aute irure dolor in reprehenderit in voluptate velit esse "
"cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia "
"deserunt mollit anim id est laborum.";
printf("[calcula]: c7794709e69683b3 == %016" PRIx64 "\n",
(uint64_t)_crc64(0, li, sizeof(li)));
printf("[64speed]: c7794709e69683b3 == %016" PRIx64 "\n",
(uint64_t)crc64(0, li, sizeof(li)));
return 0;
}
#endif
#ifdef REDIS_TEST_MAIN
int main(int argc, char *argv[]) {
return crc64Test(argc, argv);
}
#endif
Loaded 100 of 308 files, more files were not shown because too many files have changed in this diff. Show more