Skip to content

Commit 71a3651

Browse files
judyjosephabdosi
authored andcommitted
DBConnector classes to understand the namespace. (#364)
* DBConnector classes to understand the namespace. * Updates to the initial commit * Updates for comments * Add UT tests for the namespace usecases * Updates to the unit tests * Derive the DIR of the config files from the file path itself. * Fixes when testing and trying to try to connect multiple namespace DB. * Added Support to get DB Id and DB Namespace from Selectable Object. It is helpful in application that are doing select and need to the event is generated from which DB and namespace so that any parituclar action can be taken if needed. * Review comments update, for the variable name. * Further fixes and updating unit tests * Renaming the newly added function in swss::RedisSelect to getDbConnectorId() as it was clashing with swss::TableBase::getDbId() Co-authored-by: Abhishek Dosi <abdosi@microsoft.com>
1 parent 4814fd5 commit 71a3651

11 files changed

+554
-74
lines changed

common/dbconnector.cpp

+191-59
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,11 @@ using namespace std;
1616

1717
namespace swss {
1818

19-
void SonicDBConfig::initialize(const string &file)
19+
void SonicDBConfig::parseDatabaseConfig(const string &file,
20+
std::unordered_map<std::string, RedisInstInfo> &inst_entry,
21+
std::unordered_map<std::string, SonicDBInfo> &db_entry,
22+
std::unordered_map<int, std::string> &separator_entry)
2023
{
21-
22-
SWSS_LOG_ENTER();
23-
24-
if (m_init)
25-
{
26-
SWSS_LOG_ERROR("SonicDBConfig already initialized");
27-
throw runtime_error("SonicDBConfig already initialized");
28-
}
29-
3024
ifstream i(file);
3125
if (i.good())
3226
{
@@ -40,7 +34,7 @@ void SonicDBConfig::initialize(const string &file)
4034
string socket = it.value().at("unix_socket_path");
4135
string hostname = it.value().at("hostname");
4236
int port = it.value().at("port");
43-
m_inst_info[instName] = {socket, {hostname, port}};
37+
inst_entry[instName] = {socket, hostname, port};
4438
}
4539

4640
for (auto it = j["DATABASES"].begin(); it!= j["DATABASES"].end(); it++)
@@ -49,12 +43,12 @@ void SonicDBConfig::initialize(const string &file)
4943
string instName = it.value().at("instance");
5044
int dbId = it.value().at("id");
5145
string separator = it.value().at("separator");
52-
m_db_info[dbName] = {instName, dbId, separator};
46+
db_entry[dbName] = {instName, dbId, separator};
5347

54-
m_db_separator.emplace(dbId, separator);
48+
separator_entry.emplace(dbId, separator);
5549
}
56-
m_init = true;
5750
}
51+
5852
catch (domain_error& e)
5953
{
6054
SWSS_LOG_ERROR("key doesn't exist in json object, NULL value has no iterator >> %s\n", e.what());
@@ -73,32 +67,152 @@ void SonicDBConfig::initialize(const string &file)
7367
}
7468
}
7569

76-
string SonicDBConfig::getDbInst(const string &dbName)
70+
void SonicDBConfig::initializeGlobalConfig(const string &file)
71+
{
72+
std::string local_file, dir_name, ns_name;
73+
std::unordered_map<std::string, SonicDBInfo> db_entry;
74+
std::unordered_map<std::string, RedisInstInfo> inst_entry;
75+
std::unordered_map<int, std::string> separator_entry;
76+
77+
SWSS_LOG_ENTER();
78+
79+
if (m_global_init)
80+
{
81+
SWSS_LOG_ERROR("SonicDBConfig Global config is already initialized");
82+
return;
83+
}
84+
85+
86+
ifstream i(file);
87+
if (i.good())
88+
{
89+
local_file = dir_name = std::string();
90+
91+
// Get the directory name from the file path given as input.
92+
std::string::size_type pos = file.rfind("/");
93+
if( pos != std::string::npos)
94+
{
95+
dir_name = file.substr(0,pos+1);
96+
}
97+
98+
try
99+
{
100+
json j;
101+
i >> j;
102+
103+
for (auto& element : j["INCLUDES"])
104+
{
105+
local_file.append(dir_name);
106+
local_file.append(element["include"]);
107+
108+
if(element["namespace"].empty())
109+
{
110+
// If database_config.json is already initlized via SonicDBConfig::initialize
111+
// skip initializing it here again.
112+
if(m_init)
113+
{
114+
local_file.clear();
115+
continue;
116+
}
117+
ns_name = EMPTY_NAMESPACE;
118+
}
119+
else
120+
{
121+
ns_name = element["namespace"];
122+
}
123+
124+
parseDatabaseConfig(local_file, inst_entry, db_entry, separator_entry);
125+
m_inst_info[ns_name] = inst_entry;
126+
m_db_info[ns_name] = db_entry;
127+
m_db_separator[ns_name] = separator_entry;
128+
129+
inst_entry.clear();
130+
db_entry.clear();
131+
separator_entry.clear();
132+
local_file.clear();
133+
}
134+
}
135+
136+
catch (domain_error& e)
137+
{
138+
SWSS_LOG_ERROR("key doesn't exist in json object, NULL value has no iterator >> %s\n", e.what());
139+
throw runtime_error("key doesn't exist in json object, NULL value has no iterator >> " + string(e.what()));
140+
}
141+
catch (exception &e)
142+
{
143+
SWSS_LOG_ERROR("Sonic database config file syntax error >> %s\n", e.what());
144+
throw runtime_error("Sonic database config file syntax error >> " + string(e.what()));
145+
}
146+
}
147+
else
148+
{
149+
SWSS_LOG_ERROR("Sonic database global config file doesn't exist at %s\n", file.c_str());
150+
throw runtime_error("Sonic database global config file doesn't exist at " + file);
151+
}
152+
153+
// Set it as the global config file is already parsed and init done.
154+
m_global_init = true;
155+
156+
// Make regular init also done
157+
m_init = true;
158+
}
159+
160+
void SonicDBConfig::initialize(const string &file, const string &nameSpace)
161+
{
162+
std::unordered_map<std::string, SonicDBInfo> db_entry;
163+
std::unordered_map<std::string, RedisInstInfo> inst_entry;
164+
std::unordered_map<int, std::string> separator_entry;
165+
166+
SWSS_LOG_ENTER();
167+
168+
if (m_init)
169+
{
170+
SWSS_LOG_ERROR("SonicDBConfig already initialized");
171+
throw runtime_error("SonicDBConfig already initialized");
172+
}
173+
174+
// namespace string is empty, use the file given as input to parse.
175+
if(nameSpace.empty())
176+
{
177+
parseDatabaseConfig(file, inst_entry, db_entry, separator_entry);
178+
m_inst_info[EMPTY_NAMESPACE] = inst_entry;
179+
m_db_info[EMPTY_NAMESPACE] = db_entry;
180+
m_db_separator[EMPTY_NAMESPACE] = separator_entry;
181+
}
182+
else
183+
// namespace is not empty, use DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE.
184+
initializeGlobalConfig();
185+
186+
// Set it as the config file is already parsed and init done.
187+
m_init = true;
188+
}
189+
190+
string SonicDBConfig::getDbInst(const string &dbName, const string &nameSpace)
77191
{
78192
if (!m_init)
79-
initialize();
80-
return m_db_info.at(dbName).instName;
193+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
194+
return m_db_info[nameSpace].at(dbName).instName;
81195
}
82196

83-
int SonicDBConfig::getDbId(const string &dbName)
197+
int SonicDBConfig::getDbId(const string &dbName, const string &nameSpace)
84198
{
85199
if (!m_init)
86-
initialize();
87-
return m_db_info.at(dbName).dbId;
200+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
201+
return m_db_info[nameSpace].at(dbName).dbId;
88202
}
89203

90-
string SonicDBConfig::getSeparator(const string &dbName)
204+
string SonicDBConfig::getSeparator(const string &dbName, const string &nameSpace)
91205
{
92206
if (!m_init)
93-
initialize();
94-
return m_db_info.at(dbName).separator;
207+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
208+
return m_db_info[nameSpace].at(dbName).separator;
95209
}
96210

97-
string SonicDBConfig::getSeparator(int dbId)
211+
string SonicDBConfig::getSeparator(int dbId, const string &nameSpace)
98212
{
99213
if (!m_init)
100-
initialize();
101-
return m_db_separator.at(dbId);
214+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
215+
return m_db_separator[nameSpace].at(dbId);
102216
}
103217

104218
string SonicDBConfig::getSeparator(const DBConnector* db)
@@ -109,42 +223,61 @@ string SonicDBConfig::getSeparator(const DBConnector* db)
109223
}
110224

111225
string dbName = db->getDbName();
226+
string nameSpace = db->getNamespace();
112227
if (dbName.empty())
113228
{
114-
return getSeparator(db->getDbId());
229+
return getSeparator(db->getDbId(), nameSpace);
115230
}
116231
else
117232
{
118-
return getSeparator(dbName);
233+
return getSeparator(dbName, nameSpace);
119234
}
120235
}
121236

122-
string SonicDBConfig::getDbSock(const string &dbName)
237+
string SonicDBConfig::getDbSock(const string &dbName, const string &nameSpace)
123238
{
124239
if (!m_init)
125-
initialize();
126-
return m_inst_info.at(getDbInst(dbName)).first;
240+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
241+
return m_inst_info[nameSpace].at(getDbInst(dbName)).unixSocketPath;
127242
}
128243

129-
string SonicDBConfig::getDbHostname(const string &dbName)
244+
string SonicDBConfig::getDbHostname(const string &dbName, const string &nameSpace)
130245
{
131246
if (!m_init)
132-
initialize();
133-
return m_inst_info.at(getDbInst(dbName)).second.first;
247+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
248+
return m_inst_info[nameSpace].at(getDbInst(dbName)).hostname;
134249
}
135250

136-
int SonicDBConfig::getDbPort(const string &dbName)
251+
int SonicDBConfig::getDbPort(const string &dbName, const string &nameSpace)
137252
{
138253
if (!m_init)
139-
initialize();
140-
return m_inst_info.at(getDbInst(dbName)).second.second;
254+
initialize(DEFAULT_SONIC_DB_CONFIG_FILE, nameSpace);
255+
return m_inst_info[nameSpace].at(getDbInst(dbName)).port;
256+
}
257+
258+
vector<string> SonicDBConfig::getNamespaces()
259+
{
260+
vector<string> list;
261+
262+
if (!m_global_init)
263+
initializeGlobalConfig();
264+
265+
// This API returns back non-empty namespaces.
266+
for (auto it = m_inst_info.cbegin(); it != m_inst_info.cend(); ++it) {
267+
if(!((it->first).empty()))
268+
list.push_back(it->first);
269+
}
270+
271+
return list;
141272
}
142273

143274
constexpr const char *SonicDBConfig::DEFAULT_SONIC_DB_CONFIG_FILE;
144-
unordered_map<string, pair<string, pair<string, int>>> SonicDBConfig::m_inst_info;
145-
unordered_map<string, SonicDBInfo> SonicDBConfig::m_db_info;
146-
unordered_map<int, string> SonicDBConfig::m_db_separator;
275+
constexpr const char *SonicDBConfig::DEFAULT_SONIC_DB_GLOBAL_CONFIG_FILE;
276+
unordered_map<string, unordered_map<string, RedisInstInfo>> SonicDBConfig::m_inst_info;
277+
unordered_map<string, unordered_map<string, SonicDBInfo>> SonicDBConfig::m_db_info;
278+
unordered_map<string, unordered_map<int, string>> SonicDBConfig::m_db_separator;
147279
bool SonicDBConfig::m_init = false;
280+
bool SonicDBConfig::m_global_init = false;
148281

149282
constexpr const char *DBConnector::DEFAULT_UNIXSOCKET;
150283

@@ -164,7 +297,8 @@ DBConnector::~DBConnector()
164297

165298
DBConnector::DBConnector(int dbId, const string& hostname, int port,
166299
unsigned int timeout) :
167-
m_dbId(dbId)
300+
m_dbId(dbId),
301+
m_namespace(EMPTY_NAMESPACE)
168302
{
169303
struct timeval tv = {0, (suseconds_t)timeout * 1000};
170304

@@ -181,7 +315,8 @@ DBConnector::DBConnector(int dbId, const string& hostname, int port,
181315
}
182316

183317
DBConnector::DBConnector(int dbId, const string& unixPath, unsigned int timeout) :
184-
m_dbId(dbId)
318+
m_dbId(dbId),
319+
m_namespace(EMPTY_NAMESPACE)
185320
{
186321
struct timeval tv = {0, (suseconds_t)timeout * 1000};
187322

@@ -192,30 +327,31 @@ DBConnector::DBConnector(int dbId, const string& unixPath, unsigned int timeout)
192327

193328
if (m_conn->err)
194329
throw system_error(make_error_code(errc::address_not_available),
195-
"Unable to connect to redis (unixs-socket)");
330+
"Unable to connect to redis (unix-socket)");
196331

197332
select(this);
198333
}
199334

200-
DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn)
201-
: m_dbId(SonicDBConfig::getDbId(dbName))
335+
DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn, const string& nameSpace)
336+
: m_dbId(SonicDBConfig::getDbId(dbName, nameSpace))
202337
, m_dbName(dbName)
338+
, m_namespace(nameSpace)
203339
{
204340
struct timeval tv = {0, (suseconds_t)timeout * 1000};
205341

206342
if (timeout)
207343
{
208344
if (isTcpConn)
209-
m_conn = redisConnectWithTimeout(SonicDBConfig::getDbHostname(dbName).c_str(), SonicDBConfig::getDbPort(dbName), tv);
345+
m_conn = redisConnectWithTimeout(SonicDBConfig::getDbHostname(dbName, nameSpace).c_str(), SonicDBConfig::getDbPort(dbName, nameSpace), tv);
210346
else
211-
m_conn = redisConnectUnixWithTimeout(SonicDBConfig::getDbSock(dbName).c_str(), tv);
347+
m_conn = redisConnectUnixWithTimeout(SonicDBConfig::getDbSock(dbName, nameSpace).c_str(), tv);
212348
}
213349
else
214350
{
215351
if (isTcpConn)
216-
m_conn = redisConnect(SonicDBConfig::getDbHostname(dbName).c_str(), SonicDBConfig::getDbPort(dbName));
352+
m_conn = redisConnect(SonicDBConfig::getDbHostname(dbName, nameSpace).c_str(), SonicDBConfig::getDbPort(dbName, nameSpace));
217353
else
218-
m_conn = redisConnectUnix(SonicDBConfig::getDbSock(dbName).c_str());
354+
m_conn = redisConnectUnix(SonicDBConfig::getDbSock(dbName, nameSpace).c_str());
219355
}
220356

221357
if (m_conn->err)
@@ -240,19 +376,15 @@ string DBConnector::getDbName() const
240376
return m_dbName;
241377
}
242378

379+
string DBConnector::getNamespace() const
380+
{
381+
return m_namespace;
382+
}
383+
243384
DBConnector *DBConnector::newConnector(unsigned int timeout) const
244385
{
245386
DBConnector *ret;
246-
if (getContext()->connection_type == REDIS_CONN_TCP)
247-
ret = new DBConnector(getDbId(),
248-
getContext()->tcp.host,
249-
getContext()->tcp.port,
250-
timeout);
251-
else
252-
ret = new DBConnector(getDbId(),
253-
getContext()->unix_sock.path,
254-
timeout);
255-
ret->m_dbName = m_dbName;
387+
ret = new DBConnector(getDbName(), timeout, (getContext()->connection_type == REDIS_CONN_TCP), getNamespace());
256388
return ret;
257389
}
258390

0 commit comments

Comments
 (0)