From ad18db98b55bcd97cf15685af652f9d538da35b3 Mon Sep 17 00:00:00 2001 From: benschermel Date: Mon, 16 Aug 2021 22:10:31 +0000 Subject: [PATCH 01/17] add keydb-diagnostic-tool to packaging Former-commit-id: 45bb6e801f5249f11edd93423c5fd0d3d92d53b2 --- pkg/deb/debian/keydb-tools.install | 1 + pkg/deb/debian_dh9/keydb-tools.install | 1 + pkg/rpm/generate_rpms.sh | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/deb/debian/keydb-tools.install b/pkg/deb/debian/keydb-tools.install index 166faeafd..3cdaf4328 100644 --- a/pkg/deb/debian/keydb-tools.install +++ b/pkg/deb/debian/keydb-tools.install @@ -5,3 +5,4 @@ src/keydb-check-rdb /usr/bin src/keydb-cli /usr/bin src/keydb-server /usr/bin src/keydb-sentinel /usr/bin +src/keydb-diagnostic-tool /usr/bin diff --git a/pkg/deb/debian_dh9/keydb-tools.install b/pkg/deb/debian_dh9/keydb-tools.install index 80ffefe07..00281bf0e 100644 --- a/pkg/deb/debian_dh9/keydb-tools.install +++ b/pkg/deb/debian_dh9/keydb-tools.install @@ -5,3 +5,4 @@ src/keydb-check-aof /usr/bin src/keydb-check-rdb /usr/bin src/keydb-cli /usr/bin src/keydb-sentinel /usr/bin +src/keydb-diagnostic-tool /usr/bin diff --git a/pkg/rpm/generate_rpms.sh b/pkg/rpm/generate_rpms.sh index abc1f9d91..be5d67a7c 100755 --- a/pkg/rpm/generate_rpms.sh +++ b/pkg/rpm/generate_rpms.sh @@ -25,7 +25,13 @@ mkdir -p $DIR/keydb_build/keydb_rpm/var/log/keydb # move binaries to bin rm $DIR/keydb_build/keydb_rpm/usr/bin/* -cp $DIR/../../src/keydb-* $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-server $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-sentinel $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-cli $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-benchmark $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-check-aof $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-check-rdb $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-diagnostic-tool $DIR/keydb_build/keydb_rpm/usr/bin/ # update spec file with build info sed -i '2d' $DIR/keydb_build/keydb.spec From cfc4ff96d389494ce496f8f0912b638e689d5b2b Mon Sep 17 00:00:00 2001 From: benschermel Date: Mon, 16 Aug 2021 23:21:07 +0000 Subject: [PATCH 02/17] add keydb-diagnostic-tool to packaging Former-commit-id: 971725cc8c9a4592d3e63f53e3dd10b6ca27e72f --- pkg/deb/debian/keydb-tools.install | 1 + pkg/deb/debian_dh9/keydb-tools.install | 1 + pkg/rpm/generate_rpms.sh | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/deb/debian/keydb-tools.install b/pkg/deb/debian/keydb-tools.install index 166faeafd..3cdaf4328 100644 --- a/pkg/deb/debian/keydb-tools.install +++ b/pkg/deb/debian/keydb-tools.install @@ -5,3 +5,4 @@ src/keydb-check-rdb /usr/bin src/keydb-cli /usr/bin src/keydb-server /usr/bin src/keydb-sentinel /usr/bin +src/keydb-diagnostic-tool /usr/bin diff --git a/pkg/deb/debian_dh9/keydb-tools.install b/pkg/deb/debian_dh9/keydb-tools.install index 80ffefe07..00281bf0e 100644 --- a/pkg/deb/debian_dh9/keydb-tools.install +++ b/pkg/deb/debian_dh9/keydb-tools.install @@ -5,3 +5,4 @@ src/keydb-check-aof /usr/bin src/keydb-check-rdb /usr/bin src/keydb-cli /usr/bin src/keydb-sentinel /usr/bin +src/keydb-diagnostic-tool /usr/bin diff --git a/pkg/rpm/generate_rpms.sh b/pkg/rpm/generate_rpms.sh index abc1f9d91..be5d67a7c 100755 --- a/pkg/rpm/generate_rpms.sh +++ b/pkg/rpm/generate_rpms.sh @@ -25,7 +25,13 @@ mkdir -p $DIR/keydb_build/keydb_rpm/var/log/keydb # move binaries to bin rm $DIR/keydb_build/keydb_rpm/usr/bin/* -cp $DIR/../../src/keydb-* $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-server $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-sentinel $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-cli $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-benchmark $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-check-aof $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-check-rdb $DIR/keydb_build/keydb_rpm/usr/bin/ +cp $DIR/../../src/keydb-diagnostic-tool $DIR/keydb_build/keydb_rpm/usr/bin/ # update spec file with build info sed -i '2d' $DIR/keydb_build/keydb.spec From b8bb658e47d35f0522a34bcd99e0a86e995ac893 Mon Sep 17 00:00:00 2001 From: benschermel Date: Sun, 22 Aug 2021 22:18:22 +0000 Subject: [PATCH 03/17] update pkg conf file Former-commit-id: 03a52dade1fe8cf5a10bbab113e14f73fade0373 --- pkg/deb/conf/keydb.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/deb/conf/keydb.conf b/pkg/deb/conf/keydb.conf index 20df32e42..8bf03a0c5 100644 --- a/pkg/deb/conf/keydb.conf +++ b/pkg/deb/conf/keydb.conf @@ -261,7 +261,7 @@ tcp-keepalive 300 # By default KeyDB does not run as a daemon. Use 'yes' if you need it. # Note that KeyDB will write a pid file in /var/run/keydb.pid when daemonized. -daemonize no +daemonize yes # If you run KeyDB from upstart or systemd, KeyDB can interact with your # supervision tree. Options: @@ -284,7 +284,7 @@ daemonize no # # Creating a pid file is best effort: if KeyDB is not able to create it # nothing bad happens, the server will start and run normally. -pidfile /var/run/keydb_6379.pid +pidfile /var/run/keydb/keydb-server.pid # Specify the server verbosity level. # This can be one of: From 77ecd63dc206454d38647640854db6830cd1cac2 Mon Sep 17 00:00:00 2001 From: benschermel Date: Wed, 8 Sep 2021 02:28:17 +0000 Subject: [PATCH 04/17] update deb packaging to build with systemd flag Former-commit-id: d7bd4f7a1c8d6195b60ccf6417ebb77fba097398 --- pkg/deb/debian/control | 1 + pkg/deb/debian/rules | 1 + pkg/deb/debian_dh9/control | 1 + pkg/deb/debian_dh9/rules | 1 + 4 files changed, 4 insertions(+) diff --git a/pkg/deb/debian/control b/pkg/deb/debian/control index 077d493bc..f1946d3d0 100644 --- a/pkg/deb/debian/control +++ b/pkg/deb/debian/control @@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 9~), dpkg-dev (>= 1.17.5), systemd, + libsystemd-dev , procps , build-essential , tcl , diff --git a/pkg/deb/debian/rules b/pkg/deb/debian/rules index a039b220f..957e05f9a 100755 --- a/pkg/deb/debian/rules +++ b/pkg/deb/debian/rules @@ -3,6 +3,7 @@ include /usr/share/dpkg/buildflags.mk export BUILD_TLS=yes +export USE_SYSTEMD=yes export CFLAGS CPPFLAGS LDFLAGS export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -ldl -latomic $(LUA_LDFLAGS) diff --git a/pkg/deb/debian_dh9/control b/pkg/deb/debian_dh9/control index 077d493bc..f1946d3d0 100644 --- a/pkg/deb/debian_dh9/control +++ b/pkg/deb/debian_dh9/control @@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 9~), dpkg-dev (>= 1.17.5), systemd, + libsystemd-dev , procps , build-essential , tcl , diff --git a/pkg/deb/debian_dh9/rules b/pkg/deb/debian_dh9/rules index 0a8f0f1c6..a568ae470 100755 --- a/pkg/deb/debian_dh9/rules +++ b/pkg/deb/debian_dh9/rules @@ -9,6 +9,7 @@ include /usr/share/dpkg/buildflags.mk #LUA_LDFLAGS = $(addprefix -llua5.1-,$(LUA_LIBS_DEBIAN)) $(addprefix ../deps/lua/src/,$(LUA_OBJECTS)) export BUILD_TLS=yes +export USE_SYSTEMD=yes export CFLAGS CPPFLAGS LDFLAGS export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -ldl -latomic $(LUA_LDFLAGS) From 591f0c77c46c8c41488bbd63d0a3764f4b8d582c Mon Sep 17 00:00:00 2001 From: VivekSainiEQ Date: Tue, 2 Nov 2021 17:43:17 +0000 Subject: [PATCH 05/17] Check that cluster connection is valid before setting write handler Former-commit-id: 6a0a005ff2587c1c2647d3a077472b8bca38a074 --- src/cluster.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cluster.cpp b/src/cluster.cpp index 4f1cc7710..29b27ac44 100644 --- a/src/cluster.cpp +++ b/src/cluster.cpp @@ -2447,7 +2447,10 @@ void clusterSendMessage(clusterLink *link, unsigned char *msg, size_t msglen) { if (sdslen(link->sndbuf) == 0 && msglen != 0) { aePostFunction(g_pserver->rgthreadvar[IDX_EVENT_LOOP_MAIN].el, [link] { - connSetWriteHandlerWithBarrier(link->conn, clusterWriteHandler, 1); + /* The connection could be timed out before this posted function executes (thanks to TCP keepalive). + * So check that the connection is still there before setting the write handler, otherwise you segfault */ + if (link->conn != nullptr) + connSetWriteHandlerWithBarrier(link->conn, clusterWriteHandler, 1); }); } From 83b23eafd06da5e39506b8c8b3676ad473158fe8 Mon Sep 17 00:00:00 2001 From: VivekSainiEQ Date: Fri, 5 Nov 2021 00:30:34 +0000 Subject: [PATCH 06/17] Backported time thread code from enterprise Former-commit-id: b03eab2a0628df157c1f6b6242bb500ca826ef45 --- src/blocked.cpp | 1 - src/networking.cpp | 4 ---- src/server.cpp | 60 ++++++++++++++++++++++++++++++++++++---------- src/server.h | 3 ++- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/blocked.cpp b/src/blocked.cpp index 55c165336..7a17eaae9 100644 --- a/src/blocked.cpp +++ b/src/blocked.cpp @@ -592,7 +592,6 @@ void handleClientsBlockedOnKeys(void) { * lookup, invalidating the first one. * See https://github.com/redis/redis/pull/6554. */ serverTL->fixed_time_expire++; - updateCachedTime(0); /* Serve clients blocked on the key. */ robj *o = lookupKeyWrite(rl->db,rl->key); diff --git a/src/networking.cpp b/src/networking.cpp index 91310f9ab..71c9fc663 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -3869,10 +3869,6 @@ void processEventsWhileBlocked(int iel) { listNode *ln; listRewind(g_pserver->clients, &li); - /* Update our cached time since it is used to create and update the last - * interaction time with clients and for other important things. */ - updateCachedTime(0); - // All client locks must be acquired *after* the global lock is reacquired to prevent deadlocks // so unlock here, and save them for reacquisition later while ((ln = listNext(&li)) != nullptr) diff --git a/src/server.cpp b/src/server.cpp index 7dc38179a..60454fe58 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include "aelocker.h" #include "motd.h" #include "t_nhash.h" @@ -94,6 +95,10 @@ struct redisServer server; /* Server global state */ redisServer *g_pserver = &GlobalHidden::server; struct redisServerConst cserver; __thread struct redisServerThreadVars *serverTL = NULL; // thread local server vars +std::mutex time_thread_mutex; +std::condition_variable time_thread_cv; +int sleeping_threads = 0; +void wakeTimeThread(); /* Our command table. * @@ -2007,7 +2012,7 @@ void databasesCron(bool fMainThread) { * info or not using the 'update_daylight_info' argument. Normally we update * such info only when calling this function from serverCron() but not when * calling it from call(). */ -void updateCachedTime(int update_daylight_info) { +void updateCachedTime() { long long t = ustime(); __atomic_store(&g_pserver->ustime, &t, __ATOMIC_RELAXED); t /= 1000; @@ -2020,12 +2025,10 @@ void updateCachedTime(int update_daylight_info) { * context is safe since we will never fork() while here, in the main * thread. The logging function will call a thread safe version of * localtime that has no locks. */ - if (update_daylight_info) { - struct tm tm; - time_t ut = g_pserver->unixtime; - localtime_r(&ut,&tm); - __atomic_store(&g_pserver->daylight_active, &tm.tm_isdst, __ATOMIC_RELAXED); - } + struct tm tm; + time_t ut = g_pserver->unixtime; + localtime_r(&ut,&tm); + __atomic_store(&g_pserver->daylight_active, &tm.tm_isdst, __ATOMIC_RELAXED); } void checkChildrenDone(void) { @@ -2152,9 +2155,6 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { * handler if we don't return here fast enough. */ if (g_pserver->watchdog_period) watchdogScheduleSignal(g_pserver->watchdog_period); - /* Update the time cache. */ - updateCachedTime(1); - g_pserver->hz = g_pserver->config_hz; /* Adapt the g_pserver->hz value to the number of configured clients. If we have * many clients, we want to call serverCron() with an higher frequency. */ @@ -2412,7 +2412,6 @@ int serverCronLite(struct aeEventLoop *eventLoop, long long id, void *clientData void blockingOperationStarts() { if(!g_pserver->blocking_op_nesting++){ - updateCachedTime(0); g_pserver->blocked_last_cron = g_pserver->mstime; } } @@ -2623,6 +2622,14 @@ void beforeSleep(struct aeEventLoop *eventLoop) { locker.disarm(); if (!fSentReplies) handleClientsWithPendingWrites(iel, aof_state); + + // Scope lock_guard + { + std::lock_guard lock(time_thread_mutex); + sleeping_threads++; + serverAssert(sleeping_threads <= cserver.cthreads); + } + /* Determine whether the modules are enabled before sleeping, and use that result both here, and after wakeup to avoid double acquire or release of the GIL */ serverTL->modulesEnabledThisAeLoop = !!moduleCount(); @@ -2642,6 +2649,7 @@ void afterSleep(struct aeEventLoop *eventLoop) { Don't check here that modules are enabled, rather use the result from beforeSleep Otherwise you may double acquire the GIL and cause deadlocks in the module */ if (!ProcessingEventsWhileBlocked) { + wakeTimeThread(); if (serverTL->modulesEnabledThisAeLoop) moduleAcquireGIL(TRUE /*fServerThread*/); } } @@ -2839,7 +2847,7 @@ void initMasterInfo(redisMaster *master) void initServerConfig(void) { int j; - updateCachedTime(true); + updateCachedTime(); getRandomHexChars(g_pserver->runid,CONFIG_RUN_ID_SIZE); g_pserver->runid[CONFIG_RUN_ID_SIZE] = '\0'; changeReplicationId(); @@ -4006,7 +4014,6 @@ void call(client *c, int flags) { prev_err_count = g_pserver->stat_total_error_replies; g_pserver->fixed_time_expire++; - updateCachedTime(0); incrementMvccTstamp(); elapsedStart(&call_timer); try { @@ -6534,6 +6541,31 @@ void OnTerminate() serverPanic("std::teminate() called"); } +void wakeTimeThread() { + updateCachedTime(); + std::lock_guard lock(time_thread_mutex); + if (sleeping_threads >= cserver.cthreads) + time_thread_cv.notify_one(); + sleeping_threads--; + serverAssert(sleeping_threads >= 0); +} + +void *timeThreadMain(void*) { + timespec delay; + delay.tv_sec = 0; + delay.tv_nsec = 100; + while (true) { + { + std::unique_lock lock(time_thread_mutex); + if (sleeping_threads >= cserver.cthreads) { + time_thread_cv.wait(lock); + } + } + updateCachedTime(); + clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, NULL); + } +} + void *workerThreadMain(void *parg) { int iel = (int)((int64_t)parg); @@ -6930,6 +6962,8 @@ int main(int argc, char **argv) { setOOMScoreAdj(-1); serverAssert(cserver.cthreads > 0 && cserver.cthreads <= MAX_EVENT_LOOPS); + pthread_create(&cserver.time_thread_id, nullptr, timeThreadMain, nullptr); + pthread_attr_t tattr; pthread_attr_init(&tattr); pthread_attr_setstacksize(&tattr, 1 << 23); // 8 MB diff --git a/src/server.h b/src/server.h index 22ec2fa07..7d813c4a0 100644 --- a/src/server.h +++ b/src/server.h @@ -1536,6 +1536,7 @@ struct redisServerConst { pid_t pid; /* Main process pid. */ time_t stat_starttime; /* Server start time */ pthread_t main_thread_id; /* Main thread id */ + pthread_t time_thread_id; char *configfile; /* Absolute config file path, or NULL */ char *executable; /* Absolute executable file path. */ char **exec_argv; /* Executable argv vector (copy). */ @@ -2637,7 +2638,7 @@ void resetErrorTableStats(void); void adjustOpenFilesLimit(void); void incrementErrorCount(const char *fullerr, size_t namelen); void closeListeningSockets(int unlink_unix_socket); -void updateCachedTime(int update_daylight_info); +void updateCachedTime(void); void resetServerStats(void); void activeDefragCycle(void); unsigned int getLRUClock(void); From 18f082e302eb4cf2fa60189bfb6a5b986d5d77db Mon Sep 17 00:00:00 2001 From: benschermel Date: Thu, 11 Nov 2021 02:19:56 +0000 Subject: [PATCH 07/17] update license Former-commit-id: b253a7aa8d5fffcb46b40c30a8cd8b0b60489345 --- pkg/deb/debian/copyright | 92 +++++++++++++++++++++++++++++++++--- pkg/deb/debian_dh9/copyright | 17 ++++--- 2 files changed, 96 insertions(+), 13 deletions(-) diff --git a/pkg/deb/debian/copyright b/pkg/deb/debian/copyright index c7e2428e7..54c1e45b6 100644 --- a/pkg/deb/debian/copyright +++ b/pkg/deb/debian/copyright @@ -1,16 +1,94 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Contact: John Sully -Upstream-Name: keydb-pro -Source: https://github.com/JohnSully/KeyDB-Pro +Upstream-Name: KeyDB +Source: https://github.com/EQ-Alpha/KeyDB Files: * -Copyright: © 2006-2014 Salvatore Sanfilippo -Copyright © 2019, John Sully -License: Proprietary +Copyright: + © 2006-2014 Salvatore Sanfilippo + © 2019-2021 John Sully + © 2019-2021 EQ-Alpha Technology Ltd. +License: BSD-3-clause -Files: debian/* -Copyright: © 2009 Chris Lamb +Files: + src/rio.* + src/t_zset.c + src/ziplist.h + src/intset.* + src/redis-check-aof.c + deps/hiredis/* + deps/linenoise/* +Copyright: + © 2009-2012 Pieter Noordhuis + © 2009-2012 Salvatore Sanfilippo +License: BSD-3-clause + +Files: + src/lzf.h + src/lzfP.h + src/lzf_d.c + src/lzf_c.c +Copyright: + © 2000-2007 Marc Alexander Lehmann + © 2009-2012 Salvatore Sanfilippo +License: BSD-2-clause + +Files: src/setproctitle.c +Copyright: + © 2010 William Ahern + © 2013 Salvatore Sanfilippo + © 2013 Stam He +License: BSD-3-clause + +Files: src/ae_evport.c +Copyright: © 2012 Joyent, Inc. +License: BSD-3-clause + +Files: src/ae_kqueue.c +Copyright: © 2009 Harish Mallipeddi +License: BSD-3-clause + +Files: utils/install_server.sh +Copyright: © 2011 Dvir Volk +License: BSD-3-clause + +Files: deps/jemalloc/* +Copyright: + © 2002-2012 Jason Evans + © 2007-2012 Mozilla Foundation + © 2009-2012 Facebook, Inc. +License: BSD-3-clause + +Files: src/pqsort.* +Copyright: © 1992-1993 The Regents of the University of California +License: BSD-3-clause + +Files: deps/lua/* +Copyright: © 1994-2012 Lua.org, PUC-Ri +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +Files: pkg/deb/debian/* +Copyright: + © 2009 Chris Lamb + © 2020-2021 EQ-Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause diff --git a/pkg/deb/debian_dh9/copyright b/pkg/deb/debian_dh9/copyright index 59975672f..c04e4fce7 100644 --- a/pkg/deb/debian_dh9/copyright +++ b/pkg/deb/debian_dh9/copyright @@ -1,11 +1,14 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Contact: John Sully -Upstream-Name: keydb -Source: https://github.com/JohnSully/KeyDB +Upstream-Name: KeyDB +Source: https://github.com/EQ-Alpha/KeyDB Files: * -Copyright: © 2006-2014 Salvatore Sanfilippo -Copyright © 2019, John Sully +Copyright: + © 2006-2014 Salvatore Sanfilippo + © 2019-2021 John Sully + © 2019-2021 EQ-Alpha Technology Ltd. + License: BSD-3-clause Files: @@ -82,8 +85,10 @@ License: MIT OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Files: debian/* -Copyright: © 2009 Chris Lamb +Files: pkg/deb/debian_dh9/* +Copyright: + © 2009 Chris Lamb + © 2020-2021 EQ-Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause From 3df64e5a4264f1fb4a34d7269dd0584bd63c544d Mon Sep 17 00:00:00 2001 From: benschermel Date: Thu, 11 Nov 2021 02:36:20 +0000 Subject: [PATCH 08/17] fix typo Former-commit-id: d1fc7b96ed6bb18776ef334882d8c00fb3c068d0 --- pkg/deb/debian/copyright | 4 ++-- pkg/deb/debian_dh9/copyright | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/deb/debian/copyright b/pkg/deb/debian/copyright index 54c1e45b6..3fa28347c 100644 --- a/pkg/deb/debian/copyright +++ b/pkg/deb/debian/copyright @@ -7,7 +7,7 @@ Files: * Copyright: © 2006-2014 Salvatore Sanfilippo © 2019-2021 John Sully - © 2019-2021 EQ-Alpha Technology Ltd. + © 2019-2021 EQ Alpha Technology Ltd. License: BSD-3-clause @@ -88,7 +88,7 @@ License: MIT Files: pkg/deb/debian/* Copyright: © 2009 Chris Lamb - © 2020-2021 EQ-Alpha Technology Ltd. + © 2020-2021 EQ Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause diff --git a/pkg/deb/debian_dh9/copyright b/pkg/deb/debian_dh9/copyright index c04e4fce7..24000363f 100644 --- a/pkg/deb/debian_dh9/copyright +++ b/pkg/deb/debian_dh9/copyright @@ -7,7 +7,7 @@ Files: * Copyright: © 2006-2014 Salvatore Sanfilippo © 2019-2021 John Sully - © 2019-2021 EQ-Alpha Technology Ltd. + © 2019-2021 EQ Alpha Technology Ltd. License: BSD-3-clause @@ -88,7 +88,7 @@ License: MIT Files: pkg/deb/debian_dh9/* Copyright: © 2009 Chris Lamb - © 2020-2021 EQ-Alpha Technology Ltd. + © 2020-2021 EQ Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause From 81d925775816a68a5f52cb2d667ab62759ccb2a4 Mon Sep 17 00:00:00 2001 From: benschermel Date: Sat, 13 Nov 2021 17:50:42 +0000 Subject: [PATCH 09/17] update release packaging Former-commit-id: 639179471ec155ce3ec4443095c44b66cfe66cfe --- pkg/deb/debian/control | 1 + pkg/deb/debian/copyright | 92 +++++++++++++++++++++++++++++++++--- pkg/deb/debian/rules | 1 + pkg/deb/debian_dh9/control | 1 + pkg/deb/debian_dh9/copyright | 17 ++++--- pkg/deb/debian_dh9/rules | 1 + 6 files changed, 100 insertions(+), 13 deletions(-) diff --git a/pkg/deb/debian/control b/pkg/deb/debian/control index 077d493bc..f1946d3d0 100644 --- a/pkg/deb/debian/control +++ b/pkg/deb/debian/control @@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 9~), dpkg-dev (>= 1.17.5), systemd, + libsystemd-dev , procps , build-essential , tcl , diff --git a/pkg/deb/debian/copyright b/pkg/deb/debian/copyright index c7e2428e7..3fa28347c 100644 --- a/pkg/deb/debian/copyright +++ b/pkg/deb/debian/copyright @@ -1,16 +1,94 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Contact: John Sully -Upstream-Name: keydb-pro -Source: https://github.com/JohnSully/KeyDB-Pro +Upstream-Name: KeyDB +Source: https://github.com/EQ-Alpha/KeyDB Files: * -Copyright: © 2006-2014 Salvatore Sanfilippo -Copyright © 2019, John Sully -License: Proprietary +Copyright: + © 2006-2014 Salvatore Sanfilippo + © 2019-2021 John Sully + © 2019-2021 EQ Alpha Technology Ltd. +License: BSD-3-clause -Files: debian/* -Copyright: © 2009 Chris Lamb +Files: + src/rio.* + src/t_zset.c + src/ziplist.h + src/intset.* + src/redis-check-aof.c + deps/hiredis/* + deps/linenoise/* +Copyright: + © 2009-2012 Pieter Noordhuis + © 2009-2012 Salvatore Sanfilippo +License: BSD-3-clause + +Files: + src/lzf.h + src/lzfP.h + src/lzf_d.c + src/lzf_c.c +Copyright: + © 2000-2007 Marc Alexander Lehmann + © 2009-2012 Salvatore Sanfilippo +License: BSD-2-clause + +Files: src/setproctitle.c +Copyright: + © 2010 William Ahern + © 2013 Salvatore Sanfilippo + © 2013 Stam He +License: BSD-3-clause + +Files: src/ae_evport.c +Copyright: © 2012 Joyent, Inc. +License: BSD-3-clause + +Files: src/ae_kqueue.c +Copyright: © 2009 Harish Mallipeddi +License: BSD-3-clause + +Files: utils/install_server.sh +Copyright: © 2011 Dvir Volk +License: BSD-3-clause + +Files: deps/jemalloc/* +Copyright: + © 2002-2012 Jason Evans + © 2007-2012 Mozilla Foundation + © 2009-2012 Facebook, Inc. +License: BSD-3-clause + +Files: src/pqsort.* +Copyright: © 1992-1993 The Regents of the University of California +License: BSD-3-clause + +Files: deps/lua/* +Copyright: © 1994-2012 Lua.org, PUC-Ri +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +Files: pkg/deb/debian/* +Copyright: + © 2009 Chris Lamb + © 2020-2021 EQ Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause diff --git a/pkg/deb/debian/rules b/pkg/deb/debian/rules index a039b220f..957e05f9a 100755 --- a/pkg/deb/debian/rules +++ b/pkg/deb/debian/rules @@ -3,6 +3,7 @@ include /usr/share/dpkg/buildflags.mk export BUILD_TLS=yes +export USE_SYSTEMD=yes export CFLAGS CPPFLAGS LDFLAGS export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -ldl -latomic $(LUA_LDFLAGS) diff --git a/pkg/deb/debian_dh9/control b/pkg/deb/debian_dh9/control index 077d493bc..f1946d3d0 100644 --- a/pkg/deb/debian_dh9/control +++ b/pkg/deb/debian_dh9/control @@ -6,6 +6,7 @@ Build-Depends: debhelper (>= 9~), dpkg-dev (>= 1.17.5), systemd, + libsystemd-dev , procps , build-essential , tcl , diff --git a/pkg/deb/debian_dh9/copyright b/pkg/deb/debian_dh9/copyright index 59975672f..24000363f 100644 --- a/pkg/deb/debian_dh9/copyright +++ b/pkg/deb/debian_dh9/copyright @@ -1,11 +1,14 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Contact: John Sully -Upstream-Name: keydb -Source: https://github.com/JohnSully/KeyDB +Upstream-Name: KeyDB +Source: https://github.com/EQ-Alpha/KeyDB Files: * -Copyright: © 2006-2014 Salvatore Sanfilippo -Copyright © 2019, John Sully +Copyright: + © 2006-2014 Salvatore Sanfilippo + © 2019-2021 John Sully + © 2019-2021 EQ Alpha Technology Ltd. + License: BSD-3-clause Files: @@ -82,8 +85,10 @@ License: MIT OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Files: debian/* -Copyright: © 2009 Chris Lamb +Files: pkg/deb/debian_dh9/* +Copyright: + © 2009 Chris Lamb + © 2020-2021 EQ Alpha Technology Ltd. License: BSD-3-clause License: BSD-2-clause diff --git a/pkg/deb/debian_dh9/rules b/pkg/deb/debian_dh9/rules index 0a8f0f1c6..a568ae470 100755 --- a/pkg/deb/debian_dh9/rules +++ b/pkg/deb/debian_dh9/rules @@ -9,6 +9,7 @@ include /usr/share/dpkg/buildflags.mk #LUA_LDFLAGS = $(addprefix -llua5.1-,$(LUA_LIBS_DEBIAN)) $(addprefix ../deps/lua/src/,$(LUA_OBJECTS)) export BUILD_TLS=yes +export USE_SYSTEMD=yes export CFLAGS CPPFLAGS LDFLAGS export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_LDFLAGS_MAINT_APPEND = -ldl -latomic $(LUA_LDFLAGS) From 1ab337d7603d4473f381b0a5ae7d02faf53b36a8 Mon Sep 17 00:00:00 2001 From: VivekSainiEQ Date: Mon, 15 Nov 2021 23:45:46 +0000 Subject: [PATCH 10/17] bump version Former-commit-id: 2d25e62ece9ecaff4252197c050031737fc1f211 --- src/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h b/src/version.h index 120dbe031..aa4aa5b8d 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ -#define KEYDB_REAL_VERSION "6.2.0" -#define KEYDB_VERSION_NUM 0x00060200 +#define KEYDB_REAL_VERSION "6.2.1" +#define KEYDB_VERSION_NUM 0x00060201 extern const char *KEYDB_SET_VERSION; // Unlike real version, this can be overriden by the config From e8bcf8fbac60708787875e43e4d5127b74e9c570 Mon Sep 17 00:00:00 2001 From: benschermel Date: Wed, 17 Nov 2021 18:22:36 +0000 Subject: [PATCH 11/17] update deb changelog Former-commit-id: 5169f974b1ae05ce383242f3820033e9214b9a72 --- pkg/deb/master_changelog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/deb/master_changelog b/pkg/deb/master_changelog index 9066034ca..32f771972 100644 --- a/pkg/deb/master_changelog +++ b/pkg/deb/master_changelog @@ -1,3 +1,17 @@ +keydb (6:6.2.1-1distribution_placeholder) codename_placeholder; urgency=medium + + * This release of KeyDB is at parity with Redis 6.2.6. In addition, the following changes were included: + * Systemd support for release packages + * Fixes to buffer overflows in the `BITOP SHIFT` and `CRON` commands + * Server times are now computed on a seperate thread to improve performance + * Now enforces syslog identity and facility as soon as possible + * Removed erroneous use of LOG_... flags when using syslog + * Fixed erroneous `#endif` leading to build errors on some platforms + * Fixed the incorrect counting of client connections + * Issues resolved: #355, #370 + + -- Ben Schermel Wed, 17 Nov 2021 20:00:37 +0000 + keydb (6:6.2.0-1distribution_placeholder) codename_placeholder; urgency=medium * Removed unused command line options(-a, -d, -P, -r, -q, --csv, -l, -I, -e, --precision, --cluster, --enable-tracking) From 9f09e3aa9c4a4771dca450ad69b232ff7c3071bc Mon Sep 17 00:00:00 2001 From: John Sully Date: Thu, 23 Dec 2021 13:12:34 -0500 Subject: [PATCH 12/17] Fix module test break Former-commit-id: 50dfee2039e199f60f927790e7ac81625402b191 --- src/module.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/module.cpp b/src/module.cpp index fb2a66fc1..252082036 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -4289,7 +4289,14 @@ RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const ch if (!(flags & REDISMODULE_ARGV_NO_REPLICAS)) call_flags |= CMD_CALL_PROPAGATE_REPL; } + + { + aeAcquireLock(); + std::unique_lock ul(c->lock); call(c,call_flags); + aeReleaseLock(); + } + g_pserver->replication_allowed = prev_replication_allowed; serverAssert((c->flags & CLIENT_BLOCKED) == 0); From ff5e5f89ed92c2cb05cde1b0fdc8c6dd4b3f1902 Mon Sep 17 00:00:00 2001 From: John Sully Date: Thu, 23 Dec 2021 13:12:59 -0500 Subject: [PATCH 13/17] Apple build break fix Former-commit-id: 7a32ec39fdb738e9c3cd2b73ee18355ced793a65 --- src/server.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server.cpp b/src/server.cpp index 60454fe58..ab75ac589 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -6562,7 +6562,11 @@ void *timeThreadMain(void*) { } } updateCachedTime(); +#if defined(__APPLE__) + nanosleep(&delay, nullptr); +#else clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, NULL); +#endif } } From b38157b581aefae4e8e7e530f153212b88ba4c82 Mon Sep 17 00:00:00 2001 From: John Sully Date: Thu, 23 Dec 2021 13:17:14 -0500 Subject: [PATCH 14/17] Fix deadlock issue #183 cause by lock inversion Former-commit-id: e070651039975ad1d5be4a5f7cbb28eeefcb0015 --- src/networking.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/networking.cpp b/src/networking.cpp index cc031a25a..903552cf4 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -1942,7 +1942,9 @@ void ProcessPendingAsyncWrites() bool fResult = c->postFunction([](client *c) { c->fPendingAsyncWriteHandler = false; clientInstallWriteHandler(c); + c->lock.unlock(); handleClientsWithPendingWrites(c->iel, g_pserver->aof_state); + c->lock.lock(); }, false); if (!fResult) From d652b13a326be90095f5039458e91d160809618d Mon Sep 17 00:00:00 2001 From: John Sully Date: Thu, 23 Dec 2021 14:20:41 -0500 Subject: [PATCH 15/17] Remove double free in keydb-benchmark Former-commit-id: b4528b797de8ea81d4bfabbfd86231c6a904e7f4 --- src/redis-benchmark.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/redis-benchmark.cpp b/src/redis-benchmark.cpp index a33ef2dab..59904947d 100644 --- a/src/redis-benchmark.cpp +++ b/src/redis-benchmark.cpp @@ -1984,7 +1984,6 @@ int main(int argc, const char **argv) { } while(config.loop); zfree(data); - zfree(data); if (config.redis_config != NULL) freeRedisConfig(config.redis_config); return 0; From ec255fea11fd6f5d0deaa3800bef12ea5da7fbd0 Mon Sep 17 00:00:00 2001 From: christianEQ Date: Thu, 13 Jan 2022 00:07:03 +0000 Subject: [PATCH 16/17] bump version Former-commit-id: 35dc4df1df72ac0ff8224ad664426f26bd4c8868 --- src/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/version.h b/src/version.h index aa4aa5b8d..9de1b0dea 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ -#define KEYDB_REAL_VERSION "6.2.1" -#define KEYDB_VERSION_NUM 0x00060201 +#define KEYDB_REAL_VERSION "6.2.2" +#define KEYDB_VERSION_NUM 0x00060202 extern const char *KEYDB_SET_VERSION; // Unlike real version, this can be overriden by the config From 4e2e461acc6f7927ff83c1d05264f6beeec0d1f3 Mon Sep 17 00:00:00 2001 From: MalavanEQAlpha <83238889+MalavanEQAlpha@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:17:32 -0500 Subject: [PATCH 17/17] Merge pull request #386 from EQ-Alpha/fix_rdb_hang add readwrite lock for forking Former-commit-id: dabb81960f6ccc7f62c53648127924fc2fef7cdc --- src/module.cpp | 65 +++++-------------------- src/networking.cpp | 91 +++++++++-------------------------- src/readwritelock.h | 113 ++++++++++++++++++++++++++++++++++++++++++++ src/server.cpp | 79 ++++++++++++++++++++++++++++++- src/server.h | 6 +++ 5 files changed, 231 insertions(+), 123 deletions(-) create mode 100644 src/readwritelock.h diff --git a/src/module.cpp b/src/module.cpp index 252082036..3233bed3e 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -365,11 +365,7 @@ typedef struct RedisModuleCommandFilter { static list *moduleCommandFilters; /* Module GIL Variables */ -static int s_cAcquisitionsServer = 0; -static int s_cAcquisitionsModule = 0; -static std::mutex s_mutex; -static std::condition_variable s_cv; -static std::recursive_mutex s_mutexModule; +static readWriteLock s_moduleGIL; thread_local bool g_fModuleThread = false; typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data); @@ -5969,95 +5965,58 @@ void RM_ThreadSafeContextUnlock(RedisModuleCtx *ctx) { // as the server thread acquisition is sufficient. If we did try to lock we would deadlock static bool FModuleCallBackLock(bool fServerThread) { - return !fServerThread && aeThreadOwnsLock() && !g_fModuleThread && s_cAcquisitionsServer > 0; + return !fServerThread && aeThreadOwnsLock() && !g_fModuleThread && s_moduleGIL.hasReader(); } void moduleAcquireGIL(int fServerThread, int fExclusive) { - std::unique_lock lock(s_mutex); - int *pcheck = fServerThread ? &s_cAcquisitionsModule : &s_cAcquisitionsServer; - if (FModuleCallBackLock(fServerThread)) { return; } - while (*pcheck > 0) - s_cv.wait(lock); - if (fServerThread) { - ++s_cAcquisitionsServer; + s_moduleGIL.acquireRead(); } else { - // only try to acquire the mutexModule in exclusive mode - if (fExclusive){ - // It is possible that another module thread holds the GIL (and s_mutexModule as a result). - // When said thread goes to release the GIL, it will wait for s_mutex, which this thread owns. - // This thread is however waiting for the GIL (and s_mutexModule) that the other thread owns. - // As a result, a deadlock has occured. - // We release the lock on s_mutex and wait until we are able to safely acquire the GIL - // in order to prevent this deadlock from occuring. - while (!s_mutexModule.try_lock()) - s_cv.wait(lock); - } - ++s_cAcquisitionsModule; - fModuleGILWlocked++; + s_moduleGIL.acquireWrite(fExclusive); } } int moduleTryAcquireGIL(bool fServerThread, int fExclusive) { - std::unique_lock lock(s_mutex, std::defer_lock); - if (!lock.try_lock()) - return 1; - int *pcheck = fServerThread ? &s_cAcquisitionsModule : &s_cAcquisitionsServer; - if (FModuleCallBackLock(fServerThread)) { return 0; } - if (*pcheck > 0) - return 1; - if (fServerThread) { - ++s_cAcquisitionsServer; + if (!s_moduleGIL.tryAcquireRead()) + return 1; } else { - // only try to acquire the mutexModule in exclusive mode - if (fExclusive){ - if (!s_mutexModule.try_lock()) - return 1; - } - ++s_cAcquisitionsModule; - fModuleGILWlocked++; + if (!s_moduleGIL.tryAcquireWrite(fExclusive)) + return 1; } return 0; } void moduleReleaseGIL(int fServerThread, int fExclusive) { - std::unique_lock lock(s_mutex); - if (FModuleCallBackLock(fServerThread)) { return; } - + if (fServerThread) { - --s_cAcquisitionsServer; + s_moduleGIL.releaseRead(); } else { - // only try to release the mutexModule in exclusive mode - if (fExclusive) - s_mutexModule.unlock(); - --s_cAcquisitionsModule; - fModuleGILWlocked--; + s_moduleGIL.releaseWrite(fExclusive); } - s_cv.notify_all(); } int moduleGILAcquiredByModule(void) { - return fModuleGILWlocked > 0; + return s_moduleGIL.hasWriter(); } diff --git a/src/networking.cpp b/src/networking.cpp index 76223b76d..b920ec4d7 100644 --- a/src/networking.cpp +++ b/src/networking.cpp @@ -3863,82 +3863,37 @@ int checkClientPauseTimeoutAndReturnIfPaused(void) { * * The function returns the total number of events processed. */ void processEventsWhileBlocked(int iel) { - serverAssert(GlobalLocksAcquired()); - int iterations = 4; /* See the function top-comment. */ - std::vector vecclients; - listIter li; - listNode *ln; - listRewind(g_pserver->clients, &li); - - // All client locks must be acquired *after* the global lock is reacquired to prevent deadlocks - // so unlock here, and save them for reacquisition later - while ((ln = listNext(&li)) != nullptr) - { - client *c = (client*)listNodeValue(ln); - if (c->lock.fOwnLock()) { - serverAssert(c->flags & CLIENT_PROTECTED); // If the client is not protected we have no gurantee they won't be free'd in the event loop - c->lock.unlock(); - vecclients.push_back(c); + int eventsCount = 0; + executeWithoutGlobalLock([&](){ + int iterations = 4; /* See the function top-comment. */ + try + { + ProcessingEventsWhileBlocked = 1; + while (iterations--) { + long long startval = g_pserver->events_processed_while_blocked; + long long ae_events = aeProcessEvents(g_pserver->rgthreadvar[iel].el, + AE_FILE_EVENTS|AE_DONT_WAIT| + AE_CALL_BEFORE_SLEEP|AE_CALL_AFTER_SLEEP); + /* Note that g_pserver->events_processed_while_blocked will also get + * incremeted by callbacks called by the event loop handlers. */ + eventsCount += ae_events; + long long events = eventsCount - startval; + if (!events) break; + } + ProcessingEventsWhileBlocked = 0; } - } - - /* Since we're about to release our lock we need to flush the repl backlog queue */ - bool fReplBacklog = g_pserver->repl_batch_offStart >= 0; - if (fReplBacklog) { - flushReplBacklogToClients(); - g_pserver->repl_batch_idxStart = -1; - g_pserver->repl_batch_offStart = -1; - } - - long long eventsCount = 0; - aeReleaseLock(); - serverAssert(!GlobalLocksAcquired()); - try - { - ProcessingEventsWhileBlocked = 1; - while (iterations--) { - long long startval = g_pserver->events_processed_while_blocked; - long long ae_events = aeProcessEvents(g_pserver->rgthreadvar[iel].el, - AE_FILE_EVENTS|AE_DONT_WAIT| - AE_CALL_BEFORE_SLEEP|AE_CALL_AFTER_SLEEP); - /* Note that g_pserver->events_processed_while_blocked will also get - * incremeted by callbacks called by the event loop handlers. */ - eventsCount += ae_events; - long long events = eventsCount - startval; - if (!events) break; + catch (...) + { + ProcessingEventsWhileBlocked = 0; + throw; } - ProcessingEventsWhileBlocked = 0; - } - catch (...) - { - // Caller expects us to be locked so fix and rethrow - ProcessingEventsWhileBlocked = 0; - AeLocker locker; - locker.arm(nullptr); - locker.release(); - for (client *c : vecclients) - c->lock.lock(); - throw; - } - - AeLocker locker; - locker.arm(nullptr); - locker.release(); + }); g_pserver->events_processed_while_blocked += eventsCount; whileBlockedCron(); - // Restore it so the calling code is not confused - if (fReplBacklog) { - g_pserver->repl_batch_idxStart = g_pserver->repl_backlog_idx; - g_pserver->repl_batch_offStart = g_pserver->master_repl_offset; - } - - for (client *c : vecclients) - c->lock.lock(); - // If a different thread processed the shutdown we need to abort the lua command or we will hang if (serverTL->el->stop) throw ShutdownException(); diff --git a/src/readwritelock.h b/src/readwritelock.h new file mode 100644 index 000000000..d03e1c82b --- /dev/null +++ b/src/readwritelock.h @@ -0,0 +1,113 @@ +#pragma once +#include + +class readWriteLock { + std::mutex m_readLock; + std::recursive_mutex m_writeLock; + std::condition_variable m_cv; + int m_readCount = 0; + int m_writeCount = 0; + bool m_writeWaiting = false; +public: + void acquireRead() { + std::unique_lock rm(m_readLock); + while (m_writeCount > 0 || m_writeWaiting) + m_cv.wait(rm); + m_readCount++; + } + + bool tryAcquireRead() { + std::unique_lock rm(m_readLock, std::defer_lock); + if (!rm.try_lock()) + return false; + if (m_writeCount > 0 || m_writeWaiting) + return false; + m_readCount++; + return true; + } + + void acquireWrite(bool exclusive = true) { + std::unique_lock rm(m_readLock); + m_writeWaiting = true; + while (m_readCount > 0) + m_cv.wait(rm); + if (exclusive) { + /* Another thread might have the write lock while we have the read lock + but won't be able to release it until they can acquire the read lock + so release the read lock and try again instead of waiting to avoid deadlock */ + while(!m_writeLock.try_lock()) + m_cv.wait(rm); + } + m_writeCount++; + m_writeWaiting = false; + } + + void upgradeWrite(bool exclusive = true) { + std::unique_lock rm(m_readLock); + m_writeWaiting = true; + while (m_readCount > 1) + m_cv.wait(rm); + if (exclusive) { + /* Another thread might have the write lock while we have the read lock + but won't be able to release it until they can acquire the read lock + so release the read lock and try again instead of waiting to avoid deadlock */ + while(!m_writeLock.try_lock()) + m_cv.wait(rm); + } + m_writeCount++; + m_readCount--; + m_writeWaiting = false; + } + + bool tryAcquireWrite(bool exclusive = true) { + std::unique_lock rm(m_readLock, std::defer_lock); + if (!rm.try_lock()) + return false; + if (m_readCount > 0) + return false; + if (exclusive) + if (!m_writeLock.try_lock()) + return false; + m_writeCount++; + return true; + } + + void releaseRead() { + std::unique_lock rm(m_readLock); + serverAssert(m_readCount > 0); + m_readCount--; + m_cv.notify_all(); + } + + void releaseWrite(bool exclusive = true) { + std::unique_lock rm(m_readLock); + serverAssert(m_writeCount > 0); + if (exclusive) + m_writeLock.unlock(); + m_writeCount--; + m_cv.notify_all(); + } + + void downgradeWrite(bool exclusive = true) { + std::unique_lock rm(m_readLock); + serverAssert(m_writeCount > 0); + if (exclusive) + m_writeLock.unlock(); + m_writeCount--; + while (m_writeCount > 0 || m_writeWaiting) + m_cv.wait(rm); + m_readCount++; + } + + bool hasReader() { + return m_readCount > 0; + } + + bool hasWriter() { + return m_writeCount > 0; + } + + bool writeWaiting() { + return m_writeWaiting; + } +}; \ No newline at end of file diff --git a/src/server.cpp b/src/server.cpp index ab75ac589..80e755d73 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -67,6 +67,7 @@ #include "aelocker.h" #include "motd.h" #include "t_nhash.h" +#include "readwritelock.h" #ifdef __linux__ #include #include @@ -91,8 +92,10 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan; /* Global vars */ namespace GlobalHidden { struct redisServer server; /* Server global state */ +readWriteLock forkLock; } redisServer *g_pserver = &GlobalHidden::server; +readWriteLock *g_forkLock = &GlobalHidden::forkLock; struct redisServerConst cserver; __thread struct redisServerThreadVars *serverTL = NULL; // thread local server vars std::mutex time_thread_mutex; @@ -2649,8 +2652,8 @@ void afterSleep(struct aeEventLoop *eventLoop) { Don't check here that modules are enabled, rather use the result from beforeSleep Otherwise you may double acquire the GIL and cause deadlocks in the module */ if (!ProcessingEventsWhileBlocked) { - wakeTimeThread(); if (serverTL->modulesEnabledThisAeLoop) moduleAcquireGIL(TRUE /*fServerThread*/); + wakeTimeThread(); } } @@ -6218,6 +6221,63 @@ void closeChildUnusedResourceAfterFork() { cserver.pidfile = NULL; } +void executeWithoutGlobalLock(std::function func) { + serverAssert(GlobalLocksAcquired()); + + std::vector vecclients; + listIter li; + listNode *ln; + listRewind(g_pserver->clients, &li); + + // All client locks must be acquired *after* the global lock is reacquired to prevent deadlocks + // so unlock here, and save them for reacquisition later + while ((ln = listNext(&li)) != nullptr) + { + client *c = (client*)listNodeValue(ln); + if (c->lock.fOwnLock()) { + serverAssert(c->flags & CLIENT_PROTECTED || c->flags & CLIENT_EXECUTING_COMMAND); // If the client is not protected we have no gurantee they won't be free'd in the event loop + c->lock.unlock(); + vecclients.push_back(c); + } + } + + /* Since we're about to release our lock we need to flush the repl backlog queue */ + bool fReplBacklog = g_pserver->repl_batch_offStart >= 0; + if (fReplBacklog) { + flushReplBacklogToClients(); + g_pserver->repl_batch_idxStart = -1; + g_pserver->repl_batch_offStart = -1; + } + + aeReleaseLock(); + serverAssert(!GlobalLocksAcquired()); + try { + func(); + } + catch (...) { + // Caller expects us to be locked so fix and rethrow + AeLocker locker; + locker.arm(nullptr); + locker.release(); + for (client *c : vecclients) + c->lock.lock(); + throw; + } + + AeLocker locker; + locker.arm(nullptr); + locker.release(); + + // Restore it so the calling code is not confused + if (fReplBacklog) { + g_pserver->repl_batch_idxStart = g_pserver->repl_backlog_idx; + g_pserver->repl_batch_offStart = g_pserver->master_repl_offset; + } + + for (client *c : vecclients) + c->lock.lock(); +} + /* purpose is one of CHILD_TYPE_ types */ int redisFork(int purpose) { int childpid; @@ -6229,7 +6289,9 @@ int redisFork(int purpose) { openChildInfoPipe(); } - + long long startWriteLock = ustime(); + g_forkLock->acquireWrite(); + latencyAddSampleIfNeeded("fork-lock",(ustime()-startWriteLock)/1000); if ((childpid = fork()) == 0) { /* Child */ g_pserver->in_fork_child = purpose; @@ -6238,6 +6300,7 @@ int redisFork(int purpose) { closeChildUnusedResourceAfterFork(); } else { /* Parent */ + g_forkLock->releaseWrite(); g_pserver->stat_total_forks++; g_pserver->stat_fork_time = ustime()-start; g_pserver->stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / g_pserver->stat_fork_time / (1024*1024*1024); /* GB per second. */ @@ -6554,20 +6617,32 @@ void *timeThreadMain(void*) { timespec delay; delay.tv_sec = 0; delay.tv_nsec = 100; + int cycle_count = 0; + g_forkLock->acquireRead(); while (true) { { std::unique_lock lock(time_thread_mutex); if (sleeping_threads >= cserver.cthreads) { + g_forkLock->releaseRead(); time_thread_cv.wait(lock); + g_forkLock->acquireRead(); + cycle_count = 0; } } updateCachedTime(); + if (cycle_count == MAX_CYCLES_TO_HOLD_FORK_LOCK) { + g_forkLock->releaseRead(); + g_forkLock->acquireRead(); + cycle_count = 0; + } #if defined(__APPLE__) nanosleep(&delay, nullptr); #else clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, NULL); #endif + cycle_count++; } + g_forkLock->releaseRead(); } void *workerThreadMain(void *parg) diff --git a/src/server.h b/src/server.h index 7d813c4a0..d0c443934 100644 --- a/src/server.h +++ b/src/server.h @@ -96,6 +96,7 @@ typedef long long ustime_t; /* microsecond time type. */ #include "connection.h" /* Connection abstraction */ #include "serverassert.h" #include "expire.h" +#include "readwritelock.h" #define REDISMODULE_CORE 1 #include "redismodule.h" /* Redis modules API defines. */ @@ -733,6 +734,9 @@ typedef enum { #define REDISMODULE_AUX_BEFORE_RDB (1<<0) #define REDISMODULE_AUX_AFTER_RDB (1<<1) +/* Number of cycles before time thread gives up fork lock */ +#define MAX_CYCLES_TO_HOLD_FORK_LOCK 10 + struct RedisModule; struct RedisModuleIO; struct RedisModuleDigest; @@ -2113,6 +2117,7 @@ typedef struct { //extern struct redisServer server; extern redisServer *g_pserver; +extern readWriteLock *g_forkLock; extern struct redisServerConst cserver; extern __thread struct redisServerThreadVars *serverTL; // thread local server vars extern struct sharedObjectsStruct shared; @@ -2496,6 +2501,7 @@ void sendChildInfo(childInfoType info_type, size_t keys, const char *pname); void receiveChildInfo(void); /* Fork helpers */ +void executeWithoutGlobalLock(std::function func); int redisFork(int type); int hasActiveChildProcess(); void resetChildState();