/* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/ #include"precompiled.hpp" #include"logging/logAsyncWriter.hpp" #include"logging/logConfiguration.hpp" #include"logging/logFileOutput.hpp" #include"logging/logFileStreamOutput.hpp" #include"logging/logHandle.hpp" #include"memory/resourceArea.hpp" #include"runtime/atomic.hpp" #include"runtime/os.inline.hpp"
class AsyncLogWriter::AsyncLogLocker : public StackObj { public:
AsyncLogLocker() {
assert(_instance != nullptr, "AsyncLogWriter::_lock is unavailable");
_instance->_lock.lock();
}
// LogDecorator::None applies to 'constant initialization' because of its constexpr constructor. const LogDecorations& AsyncLogWriter::None = LogDecorations(LogLevel::Warning, LogTagSetMapping<LogTag::__NO_TAG>::tagset(),
LogDecorators::None);
void AsyncLogWriter::Buffer::push_flush_token() { bool result = push_back(nullptr, AsyncLogWriter::None, "");
assert(result, "fail to enqueue the flush token.");
}
void AsyncLogWriter::enqueue_locked(LogFileStreamOutput* output, const LogDecorations& decorations, constchar* msg) { // To save space and streamline execution, we just ignore null message. // client should use "" instead.
assert(msg != nullptr, "enqueuing a null message!");
// LogMessageBuffer consists of a multiple-part/multiple-line message. // The lock here guarantees its integrity. void AsyncLogWriter::enqueue(LogFileStreamOutput& output, LogMessageBuffer::Iterator msg_iterator) {
AsyncLogLocker locker;
for (; !msg_iterator.is_at_end(); msg_iterator++) {
enqueue_locked(&output, msg_iterator.decorations(), msg_iterator.message());
}
}
// move counters to snapshot and reset them.
_stats.iterate([&] (LogFileStreamOutput* output, uint32_t& counter) { if (counter > 0) { bool created = snapshot.put(output, counter);
assert(created == true, "sanity check");
counter = 0;
} returntrue;
});
_data_available = false;
}
int req = 0; auto it = _buffer_staging->iterator(); while (it.hasNext()) { const Message* e = it.next();
if (!e->is_token()){
e->output()->write_blocking(e->decorations(), e->message());
} else { // This is a flush token. Record that we found it and then // signal the flushing thread after the loop.
req++;
}
}
LogDecorations decorations(LogLevel::Warning, LogTagSetMapping<LogTag::__NO_TAG>::tagset(),
LogDecorators::All);
snapshot.iterate([&](LogFileStreamOutput* output, uint32_t& counter) { if (counter > 0) {
stringStream ss;
ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", counter);
output->write_blocking(decorations, ss.as_string(false));
} returntrue;
});
if (req > 0) {
assert(req == 1, "Only one token is allowed in queue. AsyncLogWriter::flush() is NOT MT-safe!");
_flush_sem.signal(req);
}
}
void AsyncLogWriter::run() { while (true) {
{
AsyncLogLocker locker;
while (!_data_available) {
_lock.wait(0/* no timeout */);
}
}
void AsyncLogWriter::initialize() { if (!LogConfiguration::is_async_mode()) return;
assert(_instance == nullptr, "initialize() should only be invoked once.");
AsyncLogWriter* self = new AsyncLogWriter(); if (self->_initialized) {
Atomic::release_store_fence(&AsyncLogWriter::_instance, self); // All readers of _instance after the fence see non-NULL. // We use LogOutputList's RCU counters to ensure all synchronous logsites have completed. // After that, we start AsyncLog Thread and it exclusively takes over all logging I/O. for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
ts->wait_until_no_readers();
}
os::start_thread(self);
log_debug(logging, thread)("Async logging thread started.");
} else { delete self;
}
}
// Inserts a flush token into the async output buffer and waits until the AsyncLog thread // signals that it has seen it and completed all dequeued message processing. // This method is not MT-safe in itself, but is guarded by another lock in the usual // usecase - see the comments in the header file for more details. void AsyncLogWriter::flush() { if (_instance != nullptr) {
{
AsyncLogLocker locker; // Push directly in-case we are at logical max capacity, as this must not get dropped.
_instance->_buffer->push_flush_token();
_instance->_data_available = true;
_instance->_lock.notify();
}
_instance->_flush_sem.wait();
}
}
AsyncLogWriter::BufferUpdater::BufferUpdater(size_t newsize) {
AsyncLogLocker locker; auto p = AsyncLogWriter::_instance;
_buf1 = p->_buffer;
_buf2 = p->_buffer_staging;
p->_buffer = new Buffer(newsize);
p->_buffer_staging = new Buffer(newsize);
}
AsyncLogWriter::BufferUpdater::~BufferUpdater() {
AsyncLogWriter::flush(); auto p = AsyncLogWriter::_instance;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.