Skip to content

Commit a17386f

Browse files
KochetovNicolaiEnmk
authored andcommitted
Merge pull request ClickHouse#59273 from kitaisreal/atomic-logger
Added AtomicLogger
1 parent f6469b3 commit a17386f

File tree

17 files changed

+224
-90
lines changed

17 files changed

+224
-90
lines changed

base/base/defines.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
# define TSA_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__))) /// function acquires a shared capability, but does not release it
156156
# define TSA_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__))) /// function tries to acquire a shared capability and returns a boolean value indicating success or failure
157157
# define TSA_RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__))) /// function releases the given shared capability
158+
# define TSA_SCOPED_LOCKABLE __attribute__((scoped_lockable)) /// object of a class has scoped lockable capability
158159

159160
/// Macros for suppressing TSA warnings for specific reads/writes (instead of suppressing it for the whole function)
160161
/// They use a lambda function to apply function attribute to a single statement. This enable us to suppress warnings locally instead of
@@ -182,6 +183,7 @@
182183
# define TSA_ACQUIRE_SHARED(...)
183184
# define TSA_TRY_ACQUIRE_SHARED(...)
184185
# define TSA_RELEASE_SHARED(...)
186+
# define TSA_SCOPED_LOCKABLE(...)
185187

186188
# define TSA_SUPPRESS_WARNING_FOR_READ(x) (x)
187189
# define TSA_SUPPRESS_WARNING_FOR_WRITE(x) (x)

base/poco/Foundation/include/Poco/Logger.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -904,13 +904,6 @@ class Foundation_API Logger : public Channel
904904
/// Returns a pointer to the Logger with the given name if it
905905
/// exists, or a null pointer otherwise.
906906

907-
static bool destroy(const std::string & name);
908-
/// Destroys the logger with the specified name. Does nothing
909-
/// if the logger is not found.
910-
///
911-
/// After a logger has been destroyed, all references to it
912-
/// become invalid.
913-
914907
static void shutdown();
915908
/// Shuts down the logging framework and releases all
916909
/// Loggers.
@@ -940,8 +933,6 @@ class Foundation_API Logger : public Channel
940933
static const std::string ROOT; /// The name of the root logger ("").
941934

942935
protected:
943-
typedef std::map<std::string, Logger *> LoggerMap;
944-
945936
Logger(const std::string & name, Channel * pChannel, int level);
946937
~Logger();
947938

@@ -962,8 +953,6 @@ class Foundation_API Logger : public Channel
962953
std::string _name;
963954
Channel * _pChannel;
964955
std::atomic_int _level;
965-
966-
static LoggerMap * _pLoggerMap;
967956
};
968957

969958

base/poco/Foundation/src/Logger.cpp

Lines changed: 86 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Poco/NumberParser.h"
2121
#include "Poco/String.h"
2222

23+
#include <cassert>
2324
#include <mutex>
2425

2526
namespace
@@ -37,12 +38,20 @@ std::mutex & getLoggerMutex()
3738
return *logger_mutex;
3839
}
3940

41+
struct LoggerEntry
42+
{
43+
Poco::Logger * logger;
44+
bool owned_by_shared_ptr = false;
45+
};
46+
47+
using LoggerMap = std::unordered_map<std::string, LoggerEntry>;
48+
LoggerMap * _pLoggerMap = nullptr;
49+
4050
}
4151

4252
namespace Poco {
4353

4454

45-
Logger::LoggerMap* Logger::_pLoggerMap = 0;
4655
const std::string Logger::ROOT;
4756

4857

@@ -134,12 +143,12 @@ void Logger::setLevel(const std::string& name, int level)
134143
if (_pLoggerMap)
135144
{
136145
std::string::size_type len = name.length();
137-
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
146+
for (auto & it : *_pLoggerMap)
138147
{
139148
if (len == 0 ||
140-
(it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.')))
149+
(it.first.compare(0, len, name) == 0 && (it.first.length() == len || it.first[len] == '.')))
141150
{
142-
it->second->setLevel(level);
151+
it.second.logger->setLevel(level);
143152
}
144153
}
145154
}
@@ -153,12 +162,12 @@ void Logger::setChannel(const std::string& name, Channel* pChannel)
153162
if (_pLoggerMap)
154163
{
155164
std::string::size_type len = name.length();
156-
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
165+
for (auto & it : *_pLoggerMap)
157166
{
158167
if (len == 0 ||
159-
(it->first.compare(0, len, name) == 0 && (it->first.length() == len || it->first[len] == '.')))
168+
(it.first.compare(0, len, name) == 0 && (it.first.length() == len || it.first[len] == '.')))
160169
{
161-
it->second->setChannel(pChannel);
170+
it.second.logger->setChannel(pChannel);
162171
}
163172
}
164173
}
@@ -172,12 +181,12 @@ void Logger::setProperty(const std::string& loggerName, const std::string& prope
172181
if (_pLoggerMap)
173182
{
174183
std::string::size_type len = loggerName.length();
175-
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
184+
for (auto & it : *_pLoggerMap)
176185
{
177186
if (len == 0 ||
178-
(it->first.compare(0, len, loggerName) == 0 && (it->first.length() == len || it->first[len] == '.')))
187+
(it.first.compare(0, len, loggerName) == 0 && (it.first.length() == len || it.first[len] == '.')))
179188
{
180-
it->second->setProperty(propertyName, value);
189+
it.second.logger->setProperty(propertyName, value);
181190
}
182191
}
183192
}
@@ -304,35 +313,84 @@ struct LoggerDeleter
304313
{
305314
void operator()(Poco::Logger * logger)
306315
{
307-
if (Logger::destroy(logger->name()))
316+
std::lock_guard<std::mutex> lock(getLoggerMutex());
317+
318+
/// If logger infrastructure is destroyed just decrement logger reference count
319+
if (!_pLoggerMap)
320+
{
321+
logger->release();
308322
return;
323+
}
324+
325+
auto it = _pLoggerMap->find(logger->name());
326+
assert(it != _pLoggerMap->end());
309327

310-
logger->release();
328+
/** If reference count is 1, this means this shared pointer owns logger
329+
* and need destroy it.
330+
*/
331+
size_t reference_count_before_release = logger->release();
332+
if (reference_count_before_release == 1)
333+
{
334+
assert(it->second.owned_by_shared_ptr);
335+
_pLoggerMap->erase(it);
336+
}
311337
}
312338
};
313339

340+
314341
inline LoggerPtr makeLoggerPtr(Logger & logger)
315342
{
316-
logger.duplicate();
317343
return std::shared_ptr<Logger>(&logger, LoggerDeleter());
318344
}
319345

320346
}
321347

348+
322349
Logger& Logger::get(const std::string& name)
323350
{
324351
std::lock_guard<std::mutex> lock(getLoggerMutex());
325352

326-
return unsafeGet(name);
353+
Logger & logger = unsafeGet(name);
354+
355+
/** If there are already shared pointer created for this logger
356+
* we need to increment Logger reference count and now logger
357+
* is owned by logger infrastructure.
358+
*/
359+
auto it = _pLoggerMap->find(name);
360+
if (it->second.owned_by_shared_ptr)
361+
{
362+
it->second.logger->duplicate();
363+
it->second.owned_by_shared_ptr = false;
364+
}
365+
366+
return logger;
327367
}
328368

369+
329370
LoggerPtr Logger::getShared(const std::string & name)
330371
{
331372
std::lock_guard<std::mutex> lock(getLoggerMutex());
373+
bool logger_exists = _pLoggerMap && _pLoggerMap->contains(name);
332374

333-
return makeLoggerPtr(unsafeGet(name));
375+
Logger & logger = unsafeGet(name);
376+
377+
/** If logger already exists, then this shared pointer does not own it.
378+
* If logger does not exists, logger infrastructure could be already destroyed
379+
* or logger was created.
380+
*/
381+
if (logger_exists)
382+
{
383+
logger.duplicate();
384+
}
385+
else if (_pLoggerMap)
386+
{
387+
_pLoggerMap->find(name)->second.owned_by_shared_ptr = true;
388+
}
389+
390+
return makeLoggerPtr(logger);
334391
}
335392

393+
336394
Logger& Logger::unsafeGet(const std::string& name)
337395
{
338396
Logger* pLogger = find(name);
@@ -364,7 +422,10 @@ LoggerPtr Logger::createShared(const std::string & name, Channel * pChannel, int
364422
{
365423
std::lock_guard<std::mutex> lock(getLoggerMutex());
366424

367-
return makeLoggerPtr(unsafeCreate(name, pChannel, level));
425+
Logger & logger = unsafeCreate(name, pChannel, level);
426+
_pLoggerMap->find(name)->second.owned_by_shared_ptr = true;
427+
428+
return makeLoggerPtr(logger);
368429
}
369430

370431
Logger& Logger::root()
@@ -389,10 +450,14 @@ void Logger::shutdown()
389450

390451
if (_pLoggerMap)
391452
{
392-
for (LoggerMap::iterator it = _pLoggerMap->begin(); it != _pLoggerMap->end(); ++it)
453+
for (auto & it : *_pLoggerMap)
393454
{
394-
it->second->release();
455+
if (it.second.owned_by_shared_ptr)
456+
continue;
457+
458+
it.second.logger->release();
395459
}
460+
396461
delete _pLoggerMap;
397462
_pLoggerMap = 0;
398463
}
@@ -405,32 +470,12 @@ Logger* Logger::find(const std::string& name)
405470
{
406471
LoggerMap::iterator it = _pLoggerMap->find(name);
407472
if (it != _pLoggerMap->end())
408-
return it->second;
473+
return it->second.logger;
409474
}
410475
return 0;
411476
}
412477

413478

414-
bool Logger::destroy(const std::string& name)
415-
{
416-
std::lock_guard<std::mutex> lock(getLoggerMutex());
417-
418-
if (_pLoggerMap)
419-
{
420-
LoggerMap::iterator it = _pLoggerMap->find(name);
421-
if (it != _pLoggerMap->end())
422-
{
423-
if (it->second->release() == 1)
424-
_pLoggerMap->erase(it);
425-
426-
return true;
427-
}
428-
}
429-
430-
return false;
431-
}
432-
433-
434479
void Logger::names(std::vector<std::string>& names)
435480
{
436481
std::lock_guard<std::mutex> lock(getLoggerMutex());
@@ -538,7 +583,8 @@ void Logger::add(Logger* pLogger)
538583
{
539584
if (!_pLoggerMap)
540585
_pLoggerMap = new LoggerMap;
541-
_pLoggerMap->insert(LoggerMap::value_type(pLogger->name(), pLogger));
586+
587+
_pLoggerMap->emplace(pLogger->name(), LoggerEntry{pLogger, false /*owned_by_shared_ptr*/});
542588
}
543589

544590

src/Common/AtomicLogger.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
#include <memory>
4+
5+
#include <Common/Logger.h>
6+
#include <Common/SharedMutex.h>
7+
#include <Common/SharedLockGuard.h>
8+
9+
10+
/** AtomicLogger allows to atomically change logger.
11+
* Standard library does not have atomic_shared_ptr, and we do not use std::atomic* operations,
12+
* because standard library implementation uses fixed table of mutexes, and it is better to avoid contention here.
13+
*/
14+
class AtomicLogger
15+
{
16+
public:
17+
explicit AtomicLogger(LoggerPtr logger_)
18+
: logger(std::move(logger_))
19+
{}
20+
21+
explicit AtomicLogger(const std::string & log_name)
22+
: AtomicLogger(::getLogger(log_name))
23+
{}
24+
25+
void store(LoggerPtr new_logger)
26+
{
27+
std::lock_guard lock(log_mutex);
28+
logger = std::move(new_logger);
29+
}
30+
31+
void store(const std::string & new_log_name)
32+
{
33+
auto new_logger = ::getLogger(new_log_name);
34+
store(std::move(new_logger));
35+
}
36+
37+
LoggerPtr load() const
38+
{
39+
DB::SharedLockGuard lock(log_mutex);
40+
return logger;
41+
}
42+
43+
String loadName() const
44+
{
45+
DB::SharedLockGuard lock(log_mutex);
46+
return logger->name();
47+
}
48+
private:
49+
mutable DB::SharedMutex log_mutex;
50+
LoggerPtr logger;
51+
};

src/Common/Exception.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ void tryLogCurrentException(LoggerPtr logger, const std::string & start_of_messa
228228
tryLogCurrentException(logger.get(), start_of_message);
229229
}
230230

231+
void tryLogCurrentException(const AtomicLogger & logger, const std::string & start_of_message)
232+
{
233+
tryLogCurrentException(logger.load(), start_of_message);
234+
}
235+
231236
static void getNoSpaceLeftInfoMessage(std::filesystem::path path, String & msg)
232237
{
233238
path = std::filesystem::absolute(path);
@@ -497,6 +502,11 @@ void tryLogException(std::exception_ptr e, LoggerPtr logger, const std::string &
497502
}
498503
}
499504

505+
void tryLogException(std::exception_ptr e, const AtomicLogger & logger, const std::string & start_of_message)
506+
{
507+
tryLogException(e, logger.load(), start_of_message);
508+
}
509+
500510
std::string getExceptionMessage(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace)
501511
{
502512
return getExceptionMessageAndPattern(e, with_stacktrace, check_embedded_stacktrace).text;

src/Common/Exception.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
#include <Poco/Exception.h>
99

1010
#include <base/defines.h>
11+
#include <base/errnoToString.h>
12+
#include <base/scope_guard.h>
13+
#include <Common/LoggingFormatStringHelpers.h>
14+
#include <Common/Logger.h>
15+
#include <Common/AtomicLogger.h>
1116
#include <Common/StackTrace.h>
1217
#include <Common/LoggingFormatStringHelpers.h>
1318

@@ -212,6 +217,7 @@ using Exceptions = std::vector<std::exception_ptr>;
212217
void tryLogCurrentException(const char * log_name, const std::string & start_of_message = "");
213218
void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_message = "");
214219
void tryLogCurrentException(LoggerPtr logger, const std::string & start_of_message = "");
220+
void tryLogCurrentException(const AtomicLogger & logger, const std::string & start_of_message = "");
215221

216222

217223
/** Prints current exception in canonical format.
@@ -258,6 +264,7 @@ struct ExecutionStatus
258264
void tryLogException(std::exception_ptr e, const char * log_name, const std::string & start_of_message = "");
259265
void tryLogException(std::exception_ptr e, Poco::Logger * logger, const std::string & start_of_message = "");
260266
void tryLogException(std::exception_ptr e, LoggerPtr logger, const std::string & start_of_message = "");
267+
void tryLogException(std::exception_ptr e, const AtomicLogger & logger, const std::string & start_of_message = "");
261268

262269
std::string getExceptionMessage(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace = false);
263270
PreformattedMessage getExceptionMessageAndPattern(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace = false);

0 commit comments

Comments
 (0)