diff --git a/src/db.cpp b/src/db.cpp index 78860ebb9..d1f9758ea 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1198,7 +1198,7 @@ void shutdownCommand(client *c) { * Also when in Sentinel mode clear the SAVE flag and force NOSAVE. */ if (g_pserver->loading || g_pserver->sentinel_mode) flags = (flags & ~SHUTDOWN_SAVE) | SHUTDOWN_NOSAVE; - if (prepareForShutdown(flags) == C_OK) exit(0); + if (prepareForShutdown(flags) == C_OK) throw ShutdownException(); addReplyError(c,"Errors trying to SHUTDOWN. Check logs."); } diff --git a/src/server.cpp b/src/server.cpp index 637e30650..e4d3ffa80 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2027,7 +2027,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* We received a SIGTERM, shutting down here in a safe way, as it is * not ok doing so inside the signal handler. */ if (g_pserver->shutdown_asap) { - if (prepareForShutdown(SHUTDOWN_NOFLAGS) == C_OK) exit(0); + if (prepareForShutdown(SHUTDOWN_NOFLAGS) == C_OK) throw ShutdownException(); serverLog(LL_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information"); g_pserver->shutdown_asap = 0; } @@ -4027,23 +4027,16 @@ int prepareForShutdown(int flags) { /* Close the listening sockets. Apparently this allows faster restarts. */ closeListeningSockets(1); - for (int ithread = 0; ithread < MAX_EVENT_LOOPS; ++ithread) { - for (int idb = 0; idb < cserver.dbnum; ++idb) { - if (g_pserver->rgthreadvar[ithread].rgdbSnapshot[idb] != nullptr) - g_pserver->db[idb]->endSnapshot(g_pserver->rgthreadvar[ithread].rgdbSnapshot[idb]); - } + for (int iel = 0; iel < cserver.cthreads; ++iel) + { + aePostFunction(g_pserver->rgthreadvar[iel].el, [iel]{ + g_pserver->rgthreadvar[iel].el->stop = 1; + }); } - /* free our databases */ - for (int idb = 0; idb < cserver.dbnum; ++idb) { - delete g_pserver->db[idb]; - g_pserver->db[idb] = nullptr; - } - - delete g_pserver->m_pstorageFactory; - serverLog(LL_WARNING,"%s is now ready to exit, bye bye...", g_pserver->sentinel_mode ? "Sentinel" : "KeyDB"); + return C_OK; } @@ -5352,8 +5345,23 @@ void *workerThreadMain(void *parg) aeEventLoop *el = g_pserver->rgthreadvar[iel].el; aeSetBeforeSleepProc(el, beforeSleep, AE_SLEEP_THREADSAFE); aeSetAfterSleepProc(el, afterSleep, AE_SLEEP_THREADSAFE); - aeMain(el); + try + { + aeMain(el); + } + catch (ShutdownException) + { + } + serverAssert(!GlobalLocksAcquired()); aeDeleteEventLoop(el); + + aeAcquireLock(); + for (int idb = 0; idb < cserver.dbnum; ++idb) { + if (g_pserver->rgthreadvar[iel].rgdbSnapshot[idb] != nullptr) + g_pserver->db[idb]->endSnapshot(g_pserver->rgthreadvar[iel].rgdbSnapshot[idb]); + } + aeReleaseLock(); + return NULL; } @@ -5665,7 +5673,18 @@ int main(int argc, char **argv) { /* The main thread sleeps until all the workers are done. this is so that all worker threads are orthogonal in their startup/shutdown */ void *pvRet; - pthread_join(rgthread[IDX_EVENT_LOOP_MAIN], &pvRet); + for (int iel = 0; iel < cserver.cthreads; ++iel) + pthread_join(rgthread[iel], &pvRet); + + /* free our databases */ + for (int idb = 0; idb < cserver.dbnum; ++idb) { + delete g_pserver->db[idb]; + g_pserver->db[idb] = nullptr; + } + + g_pserver->garbageCollector.shutdown(); + delete g_pserver->m_pstorageFactory; + return 0; } diff --git a/src/server.h b/src/server.h index 5077a9ddd..28dcf509e 100644 --- a/src/server.h +++ b/src/server.h @@ -3405,6 +3405,10 @@ void tlsInit(void); void tlsInitThread(); int tlsConfigure(redisTLSContextConfig *ctx_config); + +class ShutdownException +{}; + #define redisDebug(fmt, ...) \ printf("DEBUG %s:%d > " fmt "\n", __FILE__, __LINE__, __VA_ARGS__) #define redisDebugMark() \