You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by yu...@apache.org on 2013/08/02 05:30:39 UTC
git commit: TS-1330: Fix logging core at checkout_write()
Updated Branches:
refs/heads/t [created] c1c3db9d7
TS-1330: Fix logging core at checkout_write()
== Analysis ==
1. One thread(A) got an LogBuffer object in LogObject::_checkout_write() and ran
into LogBuffer::checkout_write(), before it updated the LogBuffer::m_state,
it was scheduled out by the kernel.
2. Other threads got the same LogBuffer object, but they all finished
_checkout_write() codes and made the LogBuffer object become full, finally
one of these thread flushed the LogBuffer object into write_list queue.
3. The LogBuffer object's m_references == 0 at this time.
4. The flushing thread would call LogBufferManager::flush_buffers() to loop
write_list. As the LogBuffer's m_references == 0, so it would be flushed
and deleted.
5. Now, thread(A) would be scheduled in by the kernel, but the LogBuffer object
has been deleted, so the m_buffer == NULL, that is why entry_header is 0x0.
== Solution ==
1. Remove flushing code from LogObject::log(), we should flush LogBuffer into
queue only when new_buffer is created, so that we can promise that LogBuffer
must be flushed only once.
2. The flushing thread should both check m_references and m_state.s.num_writers.
3. When allocate a new_buffer, should avoid memory leak.
Signed-off-by: Yunkai Zhang <qi...@taobao.com>
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/c1c3db9d
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/c1c3db9d
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/c1c3db9d
Branch: refs/heads/t
Commit: c1c3db9d7b524176e611a6aba3066d1a732b4bd2
Parents: cf62135
Author: Yunkai Zhang <qi...@taobao.com>
Authored: Thu Aug 1 00:31:21 2013 +0800
Committer: Yunkai Zhang <qi...@taobao.com>
Committed: Fri Aug 2 11:25:25 2013 +0800
----------------------------------------------------------------------
proxy/logging/LogBuffer.h | 3 +--
proxy/logging/LogObject.cc | 26 +++++++++++++-------------
2 files changed, 14 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c1c3db9d/proxy/logging/LogBuffer.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogBuffer.h b/proxy/logging/LogBuffer.h
index 31ee951..191b3a5 100644
--- a/proxy/logging/LogBuffer.h
+++ b/proxy/logging/LogBuffer.h
@@ -197,8 +197,6 @@ private:
size_t m_buf_align; // the buffer alignment
size_t m_write_align; // the write alignment mask
- volatile LB_State m_state; // buffer state
-
int m_max_entries; // max number of entries allowed
long m_expiration_time; // buffer expiration time
@@ -207,6 +205,7 @@ private:
uint32_t m_id; // unique buffer id (for debugging)
public:
+ volatile LB_State m_state; // buffer state
volatile int m_references; // oustanding checkout_write references.
private:
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c1c3db9d/proxy/logging/LogObject.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogObject.cc b/proxy/logging/LogObject.cc
index fd12e64..6af216e 100644
--- a/proxy/logging/LogObject.cc
+++ b/proxy/logging/LogObject.cc
@@ -44,7 +44,8 @@ LogBufferManager::flush_buffers(LogBufferSink *sink) {
SList(LogBuffer, write_link) q(write_list.popall()), new_q;
LogBuffer *b = NULL;
while ((b = q.pop())) {
- if (b->m_references) { // Still has outstanding references.
+ if (b->m_references || b->m_state.s.num_writers) {
+ // Still has outstanding references.
write_list.push(b);
} else if (_num_flush_buffers > FLUSH_ARRAY_SIZE) {
delete b;
@@ -433,6 +434,14 @@ LogObject::_checkout_write(size_t * write_offset, size_t bytes_needed) {
head_p old_h;
do {
INK_QUEUE_LD(old_h, m_log_buffer);
+ if (FREELIST_POINTER(old_h) != FREELIST_POINTER(h)) {
+ ink_atomic_increment(&buffer->m_references, -1);
+
+ // another thread should be taking care of creating a new
+ // buffer, so delete new_buffer and try again
+ delete new_buffer;
+ break;
+ }
head_p tmp_h;
SET_FREELIST_POINTER_VERSION(tmp_h, new_buffer, 0);
#if TS_HAS_128BIT_CAS
@@ -441,14 +450,13 @@ LogObject::_checkout_write(size_t * write_offset, size_t bytes_needed) {
result = ink_atomic_cas((int64_t *) &m_log_buffer.data, old_h.data, tmp_h.data);
#endif
} while (!result);
- if (FREELIST_POINTER(old_h) == FREELIST_POINTER(h))
+ if (FREELIST_POINTER(old_h) == FREELIST_POINTER(h)) {
ink_atomic_increment(&buffer->m_references, FREELIST_VERSION(old_h) - 1);
- if (result_code == LogBuffer::LB_FULL_NO_WRITERS) {
- // there are no writers, move the old buffer to the flush list
Debug("log-logbuffer", "adding buffer %d to flush list after checkout", buffer->get_id());
m_buffer_manager.add_to_flush_queue(buffer);
ink_cond_signal(&Log::flush_cond);
+
}
decremented = true;
break;
@@ -604,15 +612,7 @@ LogObject::log(LogAccess * lad, char *text_entry)
ink_strlcpy(&(*buffer)[offset], text_entry, bytes_needed);
}
- LogBuffer::LB_ResultCode result_code = buffer->checkin_write(offset);
-
- if (result_code == LogBuffer::LB_ALL_WRITERS_DONE) {
- // all checkins completed, put this buffer in the flush list
- Debug("log-logbuffer", "adding buffer %d to flush list after checkin", buffer->get_id());
-
- m_buffer_manager.add_to_flush_queue(buffer);
-// ink_cond_signal (&Log::flush_cond);
- }
+ buffer->checkin_write(offset);
LOG_INCREMENT_DYN_STAT(log_stat_event_log_access_stat);