Skip to content

Commit 9fd7dbf

Browse files
authored
[logger] Make map access thread safe and proper terminate thread (#510)
1 parent e4c3d0b commit 9fd7dbf

File tree

3 files changed

+169
-56
lines changed

3 files changed

+169
-56
lines changed

common/concurrentmap.h

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#pragma once
2+
3+
#include <map>
4+
#include <string>
5+
#include <mutex>
6+
7+
namespace swss
8+
{
9+
template <typename K, typename V>
10+
class ConcurrentMap
11+
{
12+
public:
13+
14+
ConcurrentMap() = default;
15+
16+
public:
17+
18+
size_t size()
19+
{
20+
std::lock_guard<std::mutex> _lock(m_mutex);
21+
22+
return m_map.size();
23+
}
24+
25+
bool contains(const K& key)
26+
{
27+
std::lock_guard<std::mutex> _lock(m_mutex);
28+
29+
return m_map.find(key) != m_map.end();
30+
}
31+
32+
void insert(const std::pair<K,V>& pair)
33+
{
34+
std::lock_guard<std::mutex> _lock(m_mutex);
35+
36+
m_map.insert(pair);
37+
}
38+
39+
void set(const K& key, const V& value)
40+
{
41+
std::lock_guard<std::mutex> _lock(m_mutex);
42+
43+
m_map[key] = value;
44+
}
45+
46+
// return copy
47+
V get(const K& key)
48+
{
49+
std::lock_guard<std::mutex> _lock(m_mutex);
50+
51+
return m_map[key];
52+
}
53+
54+
// return copy
55+
std::map<K,V> getCopy()
56+
{
57+
std::lock_guard<std::mutex> _lock(m_mutex);
58+
59+
return m_map;
60+
}
61+
62+
private:
63+
64+
ConcurrentMap(const ConcurrentMap&);
65+
ConcurrentMap& operator=(const ConcurrentMap&);
66+
67+
private:
68+
69+
std::map<K,V> m_map;
70+
71+
std::mutex m_mutex;
72+
};
73+
}

common/logger.cpp

+70-39
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
#include "consumerstatetable.h"
1515
#include "producerstatetable.h"
1616

17-
namespace swss {
17+
using namespace swss;
1818

19-
void err_exit(const char *fn, int ln, int e, const char *fmt, ...)
19+
#define MUTEX std::lock_guard<std::mutex> _lock(getInstance().m_mutex);
20+
21+
void swss::err_exit(const char *fn, int ln, int e, const char *fmt, ...)
2022
{
2123
va_list ap;
2224
char buff[1024];
@@ -31,13 +33,34 @@ void err_exit(const char *fn, int ln, int e, const char *fmt, ...)
3133
abort();
3234
}
3335

34-
Logger::~Logger() {
35-
if (m_settingThread) {
36-
terminateSettingThread = true;
36+
Logger::~Logger()
37+
{
38+
terminateSettingThread();
39+
}
40+
41+
void Logger::terminateSettingThread()
42+
{
43+
// can't be executed under mutex, since it can cause deadlock
44+
45+
if (m_settingThread)
46+
{
47+
m_runSettingThread = false;
48+
3749
m_settingThread->join();
50+
51+
m_settingThread = nullptr;
3852
}
3953
}
4054

55+
void Logger::restartSettingThread()
56+
{
57+
terminateSettingThread();
58+
59+
m_runSettingThread = true;
60+
61+
m_settingThread.reset(new std::thread(&Logger::settingThread, this));
62+
}
63+
4164
const Logger::PriorityStringMap Logger::priorityStringMap = {
4265
{ "EMERG", SWSS_EMERG },
4366
{ "ALERT", SWSS_ALERT },
@@ -49,7 +72,7 @@ const Logger::PriorityStringMap Logger::priorityStringMap = {
4972
{ "DEBUG", SWSS_DEBUG }
5073
};
5174

52-
void Logger::swssPrioNotify(const std::string &component, const std::string &prioStr)
75+
void Logger::swssPrioNotify(const std::string& component, const std::string& prioStr)
5376
{
5477
auto& logger = getInstance();
5578

@@ -70,7 +93,7 @@ const Logger::OutputStringMap Logger::outputStringMap = {
7093
{ "STDERR", SWSS_STDERR }
7194
};
7295

73-
void Logger::swssOutputNotify(const std::string &component, const std::string &outputStr)
96+
void Logger::swssOutputNotify(const std::string& component, const std::string& outputStr)
7497
{
7598
auto& logger = getInstance();
7699

@@ -85,22 +108,27 @@ void Logger::swssOutputNotify(const std::string &component, const std::string &o
85108
}
86109
}
87110

88-
void Logger::linkToDbWithOutput(const std::string &dbName, const PriorityChangeNotify& prioNotify, const std::string& defPrio, const OutputChangeNotify& outputNotify, const std::string& defOutput)
111+
void Logger::linkToDbWithOutput(
112+
const std::string& dbName,
113+
const PriorityChangeNotify& prioNotify,
114+
const std::string& defPrio,
115+
const OutputChangeNotify& outputNotify,
116+
const std::string& defOutput)
89117
{
90118
auto& logger = getInstance();
91119

92120
// Initialize internal DB with observer
93121
logger.m_settingChangeObservers.insert(std::make_pair(dbName, std::make_pair(prioNotify, outputNotify)));
122+
94123
DBConnector db("LOGLEVEL_DB", 0);
95-
auto keys = db.keys("*");
96124

97125
std::string key = dbName + ":" + dbName;
98126
std::string prio, output;
99127
bool doUpdate = false;
100128
auto prioPtr = db.hget(key, DAEMON_LOGLEVEL);
101129
auto outputPtr = db.hget(key, DAEMON_LOGOUTPUT);
102130

103-
if ( prioPtr == nullptr )
131+
if (prioPtr == nullptr)
104132
{
105133
prio = defPrio;
106134
doUpdate = true;
@@ -110,7 +138,7 @@ void Logger::linkToDbWithOutput(const std::string &dbName, const PriorityChangeN
110138
prio = *prioPtr;
111139
}
112140

113-
if ( outputPtr == nullptr )
141+
if (outputPtr == nullptr)
114142
{
115143
output = defOutput;
116144
doUpdate = true;
@@ -130,26 +158,26 @@ void Logger::linkToDbWithOutput(const std::string &dbName, const PriorityChangeN
130158
table.set(dbName, fieldValues);
131159
}
132160

133-
logger.m_currentPrios[dbName] = prio;
134-
logger.m_currentOutputs[dbName] = output;
161+
logger.m_currentPrios.set(dbName, prio);
162+
logger.m_currentOutputs.set(dbName, output);
163+
135164
prioNotify(dbName, prio);
136165
outputNotify(dbName, output);
137166
}
138167

139-
void Logger::linkToDb(const std::string &dbName, const PriorityChangeNotify& prioNotify, const std::string& defPrio)
168+
void Logger::linkToDb(const std::string& dbName, const PriorityChangeNotify& prioNotify, const std::string& defPrio)
140169
{
141170
linkToDbWithOutput(dbName, prioNotify, defPrio, swssOutputNotify, "SYSLOG");
142171
}
143172

144-
void Logger::linkToDbNative(const std::string &dbName, const char * defPrio)
173+
void Logger::linkToDbNative(const std::string& dbName, const char * defPrio)
145174
{
146-
auto& logger = getInstance();
147-
148175
linkToDb(dbName, swssPrioNotify, defPrio);
149-
logger.m_settingThread.reset(new std::thread(&Logger::settingThread, &logger));
176+
177+
getInstance().restartSettingThread();
150178
}
151179

152-
Logger &Logger::getInstance()
180+
Logger& Logger::getInstance()
153181
{
154182
static Logger m_logger;
155183
return m_logger;
@@ -171,13 +199,13 @@ void Logger::settingThread()
171199
DBConnector db("LOGLEVEL_DB", 0);
172200
std::map<std::string, std::shared_ptr<ConsumerStateTable>> selectables;
173201

174-
while (!terminateSettingThread)
202+
while (m_runSettingThread)
175203
{
176204
if (selectables.size() < m_settingChangeObservers.size())
177205
{
178-
for (const auto& i : m_settingChangeObservers)
206+
for (const auto& i : m_settingChangeObservers.getCopy())
179207
{
180-
const std::string &dbName = i.first;
208+
const std::string& dbName = i.first;
181209
if (selectables.find(dbName) == selectables.end())
182210
{
183211
auto table = std::make_shared<ConsumerStateTable>(&db, dbName);
@@ -208,27 +236,28 @@ void Logger::settingThread()
208236
dynamic_cast<ConsumerStateTable *>(selectable)->pop(koValues);
209237
std::string key = kfvKey(koValues), op = kfvOp(koValues);
210238

211-
if ((op != SET_COMMAND) || (m_settingChangeObservers.find(key) == m_settingChangeObservers.end()))
239+
if (op != SET_COMMAND || !m_settingChangeObservers.contains(key))
212240
{
213241
continue;
214242
}
215243

216-
auto values = kfvFieldsValues(koValues);
217-
for (const auto& i : values)
244+
const auto& values = kfvFieldsValues(koValues);
245+
246+
for (auto& i : values)
218247
{
219-
const std::string &field = fvField(i), &value = fvValue(i);
220-
if ((field == DAEMON_LOGLEVEL) && (value != m_currentPrios[key]))
248+
auto& field = fvField(i);
249+
auto& value = fvValue(i);
250+
251+
if ((field == DAEMON_LOGLEVEL) && (value != m_currentPrios.get(key)))
221252
{
222-
m_currentPrios[key] = value;
223-
m_settingChangeObservers[key].first(key, value);
253+
m_currentPrios.set(key, value);
254+
m_settingChangeObservers.get(key).first(key, value);
224255
}
225-
else if ((field == DAEMON_LOGOUTPUT) && (value != m_currentOutputs[key]))
256+
else if ((field == DAEMON_LOGOUTPUT) && (value != m_currentOutputs.get(key)))
226257
{
227-
m_currentOutputs[key] = value;
228-
m_settingChangeObservers[key].second(key, value);
258+
m_currentOutputs.set(key, value);
259+
m_settingChangeObservers.get(key).second(key, value);
229260
}
230-
231-
break;
232261
}
233262
}
234263
}
@@ -246,14 +275,16 @@ void Logger::write(Priority prio, const char *fmt, ...)
246275

247276
if (m_output == SWSS_SYSLOG)
248277
{
249-
vsyslog(prio, fmt, ap);
278+
vsyslog(prio, fmt, ap);
250279
}
251280
else
252281
{
253282
std::stringstream ss;
254283
ss << std::setw(6) << std::right << priorityToString(prio);
255284
ss << fmt << std::endl;
256-
std::lock_guard<std::mutex> lock(m_mutex);
285+
286+
MUTEX;
287+
257288
if (m_output == SWSS_STDOUT)
258289
{
259290
vprintf(ss.str().c_str(), ap);
@@ -283,7 +314,9 @@ void Logger::wthrow(Priority prio, const char *fmt, ...)
283314
std::stringstream ss;
284315
ss << std::setw(6) << std::right << priorityToString(prio);
285316
ss << fmt << std::endl;
286-
std::lock_guard<std::mutex> lock(m_mutex);
317+
318+
MUTEX;
319+
287320
if (m_output == SWSS_STDOUT)
288321
{
289322
vprintf(ss.str().c_str(), ap);
@@ -363,5 +396,3 @@ Logger::ScopeTimer::~ScopeTimer()
363396

364397
Logger::getInstance().write(swss::Logger::SWSS_NOTICE, ":- %s: %s took %lf sec", m_fun, m_msg.c_str(), duration);
365398
}
366-
367-
};

0 commit comments

Comments
 (0)