diff options
author | Sage Weil <sage@inktank.com> | 2012-12-28 13:07:18 -0800 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-01-03 16:23:40 -0800 |
commit | 49416619d733572368e5d2ba7f2b34150c754b23 (patch) | |
tree | 595e9fc62579bf64741bd9735f1adb9231f830b1 | |
parent | f8bb4814d0fd7e08c9b6cdcde02940bf1b42cadd (diff) | |
download | ceph-49416619d733572368e5d2ba7f2b34150c754b23.tar.gz |
log: broadcast cond signals
We were using a single cond, and only signalling one waiter. That means
that if the flusher and several logging threads are waiting, and we hit
a limit, we the logger could signal another logger instead of the flusher,
and we could deadlock.
Similarly, if the flusher empties the queue, it might signal only a single
logger, and that logger could re-signal the flusher, and the other logger
could wait forever.
Intead, break the single cond into two: one for loggers, and one for the
flusher. Always signal the (one) flusher, and always broadcast to all
loggers.
Backport: bobtail, argonaut
Signed-off-by: Sage Weil <sage@inktank.com>
Reviewed-by: Dan Mick <dan.mick@inktank.com>
(cherry picked from commit 813787af3dbb99e42f481af670c4bb0e254e4432)
-rw-r--r-- | src/log/Log.cc | 19 | ||||
-rw-r--r-- | src/log/Log.h | 3 |
2 files changed, 14 insertions, 8 deletions
diff --git a/src/log/Log.cc b/src/log/Log.cc index 55c831d66fd..57bfc10a9d7 100644 --- a/src/log/Log.cc +++ b/src/log/Log.cc @@ -51,7 +51,10 @@ Log::Log(SubsystemMap *s) ret = pthread_mutex_init(&m_queue_mutex, NULL); assert(ret == 0); - ret = pthread_cond_init(&m_cond, NULL); + ret = pthread_cond_init(&m_cond_loggers, NULL); + assert(ret == 0); + + ret = pthread_cond_init(&m_cond_flusher, NULL); assert(ret == 0); // kludge for prealloc testing @@ -73,7 +76,8 @@ Log::~Log() pthread_spin_destroy(&m_lock); pthread_mutex_destroy(&m_queue_mutex); pthread_mutex_destroy(&m_flush_mutex); - pthread_cond_destroy(&m_cond); + pthread_cond_destroy(&m_cond_loggers); + pthread_cond_destroy(&m_cond_flusher); } @@ -139,10 +143,10 @@ void Log::submit_entry(Entry *e) // wait for flush to catch up while (m_new.m_len > m_max_new) - pthread_cond_wait(&m_cond, &m_queue_mutex); + pthread_cond_wait(&m_cond_loggers, &m_queue_mutex); m_new.enqueue(e); - pthread_cond_signal(&m_cond); + pthread_cond_signal(&m_cond_flusher); pthread_mutex_unlock(&m_queue_mutex); } @@ -169,7 +173,7 @@ void Log::flush() pthread_mutex_lock(&m_queue_mutex); EntryQueue t; t.swap(m_new); - pthread_cond_signal(&m_cond); + pthread_cond_broadcast(&m_cond_loggers); pthread_mutex_unlock(&m_queue_mutex); _flush(&t, &m_recent, false); @@ -278,7 +282,8 @@ void Log::stop() assert(is_started()); pthread_mutex_lock(&m_queue_mutex); m_stop = true; - pthread_cond_signal(&m_cond); + pthread_cond_signal(&m_cond_flusher); + pthread_cond_broadcast(&m_cond_loggers); pthread_mutex_unlock(&m_queue_mutex); join(); } @@ -294,7 +299,7 @@ void *Log::entry() continue; } - pthread_cond_wait(&m_cond, &m_queue_mutex); + pthread_cond_wait(&m_cond_flusher, &m_queue_mutex); } pthread_mutex_unlock(&m_queue_mutex); flush(); diff --git a/src/log/Log.h b/src/log/Log.h index ab83a7c86e4..f6a27dc5b37 100644 --- a/src/log/Log.h +++ b/src/log/Log.h @@ -24,7 +24,8 @@ class Log : private Thread pthread_spinlock_t m_lock; pthread_mutex_t m_queue_mutex; pthread_mutex_t m_flush_mutex; - pthread_cond_t m_cond; + pthread_cond_t m_cond_loggers; + pthread_cond_t m_cond_flusher; EntryQueue m_new; ///< new entries EntryQueue m_recent; ///< recent (less new) entries we've already written at low detail |