mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 18:14:38 +02:00
8267952: async logging supports to dynamically change tags and decorators
Reviewed-by: dholmes, phh
This commit is contained in:
parent
20640a57f3
commit
09bb84685f
9 changed files with 185 additions and 42 deletions
|
@ -41,7 +41,7 @@ class AsyncLogWriter::AsyncLogLocker : public StackObj {
|
|||
};
|
||||
|
||||
void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {
|
||||
if (_buffer.size() >= _buffer_max_size) {
|
||||
if (_buffer.size() >= _buffer_max_size) {
|
||||
bool p_created;
|
||||
uint32_t* counter = _stats.add_if_absent(msg.output(), 0, &p_created);
|
||||
*counter = *counter + 1;
|
||||
|
@ -50,13 +50,12 @@ void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) {
|
|||
return;
|
||||
}
|
||||
|
||||
assert(_buffer.size() < _buffer_max_size, "_buffer is over-sized.");
|
||||
_buffer.push_back(msg);
|
||||
_sem.signal();
|
||||
}
|
||||
|
||||
void AsyncLogWriter::enqueue(LogFileOutput& output, const LogDecorations& decorations, const char* msg) {
|
||||
AsyncLogMessage m(output, decorations, os::strdup(msg));
|
||||
AsyncLogMessage m(&output, decorations, os::strdup(msg));
|
||||
|
||||
{ // critical area
|
||||
AsyncLogLocker locker;
|
||||
|
@ -70,13 +69,13 @@ void AsyncLogWriter::enqueue(LogFileOutput& output, LogMessageBuffer::Iterator m
|
|||
AsyncLogLocker locker;
|
||||
|
||||
for (; !msg_iterator.is_at_end(); msg_iterator++) {
|
||||
AsyncLogMessage m(output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));
|
||||
AsyncLogMessage m(&output, msg_iterator.decorations(), os::strdup(msg_iterator.message()));
|
||||
enqueue_locked(m);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncLogWriter::AsyncLogWriter()
|
||||
: _lock(1), _sem(0), _io_sem(1),
|
||||
: _lock(1), _sem(0), _flush_sem(0),
|
||||
_initialized(false),
|
||||
_stats(17 /*table_size*/) {
|
||||
if (os::create_thread(this, os::asynclog_thread)) {
|
||||
|
@ -98,10 +97,10 @@ class AsyncLogMapIterator {
|
|||
using none = LogTagSetMapping<LogTag::__NO_TAG>;
|
||||
|
||||
if (*counter > 0) {
|
||||
LogDecorations decorations(LogLevel::Warning, none::tagset(), output->decorators());
|
||||
LogDecorations decorations(LogLevel::Warning, none::tagset(), LogDecorators::All);
|
||||
stringStream ss;
|
||||
ss.print(UINT32_FORMAT_W(6) " messages dropped due to async logging", *counter);
|
||||
AsyncLogMessage msg(*output, decorations, ss.as_string(true /*c_heap*/));
|
||||
AsyncLogMessage msg(output, decorations, ss.as_string(true /*c_heap*/));
|
||||
_logs.push_back(msg);
|
||||
*counter = 0;
|
||||
}
|
||||
|
@ -118,7 +117,6 @@ void AsyncLogWriter::write() {
|
|||
// The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without
|
||||
// lock protection. This guarantees I/O jobs don't block logsites.
|
||||
AsyncLogBuffer logs;
|
||||
bool own_io = false;
|
||||
|
||||
{ // critical region
|
||||
AsyncLogLocker locker;
|
||||
|
@ -127,14 +125,11 @@ void AsyncLogWriter::write() {
|
|||
// append meta-messages of dropped counters
|
||||
AsyncLogMapIterator dropped_counters_iter(logs);
|
||||
_stats.iterate(&dropped_counters_iter);
|
||||
own_io = _io_sem.trywait();
|
||||
}
|
||||
|
||||
LinkedListIterator<AsyncLogMessage> it(logs.head());
|
||||
if (!own_io) {
|
||||
_io_sem.wait();
|
||||
}
|
||||
|
||||
int req = 0;
|
||||
while (!it.is_empty()) {
|
||||
AsyncLogMessage* e = it.next();
|
||||
char* msg = e->message();
|
||||
|
@ -142,9 +137,17 @@ void AsyncLogWriter::write() {
|
|||
if (msg != nullptr) {
|
||||
e->output()->write_blocking(e->decorations(), msg);
|
||||
os::free(msg);
|
||||
} else if (e->output() == nullptr) {
|
||||
// This is a flush token. Record that we found it and then
|
||||
// signal the flushing thread after the loop.
|
||||
req++;
|
||||
}
|
||||
}
|
||||
_io_sem.signal();
|
||||
|
||||
if (req > 0) {
|
||||
assert(req == 1, "AsyncLogWriter::flush() is NOT MT-safe!");
|
||||
_flush_sem.signal(req);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncLogWriter::run() {
|
||||
|
@ -181,10 +184,23 @@ AsyncLogWriter* AsyncLogWriter::instance() {
|
|||
return _instance;
|
||||
}
|
||||
|
||||
// write() acquires and releases _io_sem even _buffer is empty.
|
||||
// This guarantees all logging I/O of dequeued messages are done when it returns.
|
||||
// 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) {
|
||||
_instance->write();
|
||||
{
|
||||
using none = LogTagSetMapping<LogTag::__NO_TAG>;
|
||||
AsyncLogLocker locker;
|
||||
LogDecorations d(LogLevel::Off, none::tagset(), LogDecorators::None);
|
||||
AsyncLogMessage token(nullptr, d, nullptr);
|
||||
|
||||
// Push directly in-case we are at logical max capacity, as this must not get dropped.
|
||||
_instance->_buffer.push_back(token);
|
||||
_instance->_sem.signal();
|
||||
}
|
||||
|
||||
_instance->_flush_sem.wait();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue