Compare commits
2
Commits
unstable
...
fix_rdb_hang
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
596c056c0c | ||
|
|
ab973e8df4 |
No files matched your search
+1
-1
@@ -365,7 +365,7 @@ typedef struct RedisModuleCommandFilter {
|
||||
static list *moduleCommandFilters;
|
||||
|
||||
/* Module GIL Variables */
|
||||
static readWriteLock s_moduleGIL;
|
||||
static readWriteLock s_moduleGIL("Module GIL");
|
||||
thread_local bool g_fModuleThread = false;
|
||||
|
||||
typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data);
|
||||
|
||||
+13
-11
@@ -2,22 +2,24 @@
|
||||
#include <condition_variable>
|
||||
|
||||
class readWriteLock {
|
||||
std::mutex m_readLock;
|
||||
std::recursive_mutex m_writeLock;
|
||||
std::condition_variable m_cv;
|
||||
fastlock m_readLock;
|
||||
fastlock m_writeLock;
|
||||
std::condition_variable_any m_cv;
|
||||
int m_readCount = 0;
|
||||
int m_writeCount = 0;
|
||||
bool m_writeWaiting = false;
|
||||
public:
|
||||
readWriteLock(const char *name) : m_readLock(name), m_writeLock(name) {}
|
||||
|
||||
void acquireRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
while (m_writeCount > 0 || m_writeWaiting)
|
||||
m_cv.wait(rm);
|
||||
m_readCount++;
|
||||
}
|
||||
|
||||
bool tryAcquireRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock, std::defer_lock);
|
||||
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
|
||||
if (!rm.try_lock())
|
||||
return false;
|
||||
if (m_writeCount > 0 || m_writeWaiting)
|
||||
@@ -27,7 +29,7 @@ public:
|
||||
}
|
||||
|
||||
void acquireWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
m_writeWaiting = true;
|
||||
while (m_readCount > 0)
|
||||
m_cv.wait(rm);
|
||||
@@ -43,7 +45,7 @@ public:
|
||||
}
|
||||
|
||||
void upgradeWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
m_writeWaiting = true;
|
||||
while (m_readCount > 1)
|
||||
m_cv.wait(rm);
|
||||
@@ -60,7 +62,7 @@ public:
|
||||
}
|
||||
|
||||
bool tryAcquireWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock, std::defer_lock);
|
||||
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
|
||||
if (!rm.try_lock())
|
||||
return false;
|
||||
if (m_readCount > 0)
|
||||
@@ -73,14 +75,14 @@ public:
|
||||
}
|
||||
|
||||
void releaseRead() {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
serverAssert(m_readCount > 0);
|
||||
m_readCount--;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void releaseWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
serverAssert(m_writeCount > 0);
|
||||
if (exclusive)
|
||||
m_writeLock.unlock();
|
||||
@@ -89,7 +91,7 @@ public:
|
||||
}
|
||||
|
||||
void downgradeWrite(bool exclusive = true) {
|
||||
std::unique_lock<std::mutex> rm(m_readLock);
|
||||
std::unique_lock<fastlock> rm(m_readLock);
|
||||
serverAssert(m_writeCount > 0);
|
||||
if (exclusive)
|
||||
m_writeLock.unlock();
|
||||
|
||||
+9
-3
@@ -92,7 +92,7 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
|
||||
/* Global vars */
|
||||
namespace GlobalHidden {
|
||||
struct redisServer server; /* Server global state */
|
||||
readWriteLock forkLock;
|
||||
readWriteLock forkLock("Fork (global)");
|
||||
}
|
||||
redisServer *g_pserver = &GlobalHidden::server;
|
||||
readWriteLock *g_forkLock = &GlobalHidden::forkLock;
|
||||
@@ -2632,7 +2632,8 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
|
||||
sleeping_threads++;
|
||||
serverAssert(sleeping_threads <= cserver.cthreads);
|
||||
}
|
||||
|
||||
|
||||
g_forkLock->releaseRead();
|
||||
/* 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();
|
||||
@@ -2653,6 +2654,7 @@ void afterSleep(struct aeEventLoop *eventLoop) {
|
||||
Otherwise you may double acquire the GIL and cause deadlocks in the module */
|
||||
if (!ProcessingEventsWhileBlocked) {
|
||||
if (serverTL->modulesEnabledThisAeLoop) moduleAcquireGIL(TRUE /*fServerThread*/);
|
||||
g_forkLock->acquireRead();
|
||||
wakeTimeThread();
|
||||
}
|
||||
}
|
||||
@@ -6290,7 +6292,8 @@ int redisFork(int purpose) {
|
||||
openChildInfoPipe();
|
||||
}
|
||||
long long startWriteLock = ustime();
|
||||
g_forkLock->acquireWrite();
|
||||
g_forkLock->releaseRead();
|
||||
executeWithoutGlobalLock([](){ g_forkLock->acquireWrite(); });
|
||||
latencyAddSampleIfNeeded("fork-lock",(ustime()-startWriteLock)/1000);
|
||||
if ((childpid = fork()) == 0) {
|
||||
/* Child */
|
||||
@@ -6301,6 +6304,7 @@ int redisFork(int purpose) {
|
||||
} else {
|
||||
/* Parent */
|
||||
g_forkLock->releaseWrite();
|
||||
g_forkLock->acquireRead();
|
||||
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. */
|
||||
@@ -6672,6 +6676,7 @@ void *workerThreadMain(void *parg)
|
||||
}
|
||||
|
||||
moduleAcquireGIL(true); // Normally afterSleep acquires this, but that won't be called on the first run
|
||||
g_forkLock->acquireRead();
|
||||
aeEventLoop *el = g_pserver->rgthreadvar[iel].el;
|
||||
try
|
||||
{
|
||||
@@ -6680,6 +6685,7 @@ void *workerThreadMain(void *parg)
|
||||
catch (ShutdownException)
|
||||
{
|
||||
}
|
||||
g_forkLock->releaseRead();
|
||||
moduleReleaseGIL(true);
|
||||
serverAssert(!GlobalLocksAcquired());
|
||||
aeDeleteEventLoop(el);
|
||||
|
||||
Reference in new issue
Block a user