MongoDBStorageMixin.cpp
Go to the documentation of this file.
2
3#include <SimoxUtility/algorithm/string.h>
4
8
9#include "util/filesystem.h"
10
12{
13 std::unique_ptr<mongocxx::instance> MongoDBStorageMixin::MongoCXXInstance = nullptr;
14 std::atomic_bool MongoDBStorageMixin::MongoCXXInitialized = false;
15 std::recursive_mutex MongoDBStorageMixin::MongoCXXConnectionPoolMutex;
16 std::map<std::string, std::unique_ptr<mongocxx::pool>>
17 MongoDBStorageMixin::MongoCXXConnectionPool = {};
18
19 void
21 {
22 std::filesystem::path armarx_config_home = std::string(getenv("ARMARX_USER_CONFIG_DIR"));
23 if (!util::fs::directoryExists(armarx_config_home))
24 {
25 ARMARX_WARNING << ("Could not find an ArmarX Config folder. Tried: '" +
26 armarx_config_home.string() +
27 "' (from ARMARX_USER_CONFIG_DIR). If not set via scenario params "
28 "this means that LTM is disabled.");
29 return;
30 }
31
32 std::ifstream cFile(armarx_config_home / "default.cfg");
33 if (cFile.is_open())
34 {
35 std::string line;
36 while (getline(cFile, line))
37 {
38 line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
39 if (line.empty() || line[0] == '#')
40 {
41 continue;
42 }
43 auto delimiterPos = line.find("=");
44 const auto name = simox::alg::to_lower(line.substr(0, delimiterPos));
45 const auto value = line.substr(delimiterPos + 1);
46 if (host.empty() && name == "armarx.mongohost")
47 {
48 host = value;
49 }
50 if (port == 0 && name == "armarx.mongoport")
51 {
52 port = (unsigned int)std::stoi(value);
53 }
54 if (user.empty() && name == "armarx.mongouser")
55 {
56 user = value;
57 }
58 if (password.empty() && name == "armarx.mongopassword")
59 {
60 password = value;
61 }
62 }
63 }
64 }
65
66 bool
68 {
69 // we always need a host and a port
70 return !host.empty() and port != 0;
71 }
72
73 std::string
75 {
76 std::stringstream ss;
77 ss << "mongodb://";
78
79 if (!user.empty())
80 {
81 ss << user;
82 if (!password.empty())
83 {
84 ss << ":" << password;
85 }
86 ss << "@";
87 }
88 ss << host;
89 return ss.str();
90 }
91
92 std::string
94 {
95 // TODO: What happens if a connection exists and you would like to open another one with a different user (e.g. that sees different things)?
96 return "mongodb://" + host + ":" + std::to_string(port);
97 }
98
99 std::string
101 {
102 return baseUri() + ":" + std::to_string(port) +
103 "/?minPoolSize=" + std::to_string(minPoolSize) +
104 "&maxPoolSize=" + std::to_string(maxPoolSize);
105 }
106
107 std::string
109 {
110 return uri();
111 }
112
114 const std::string& en,
115 const armem::MemoryID& id) :
116 settings(settings), exportName(en), _id(id)
117 {
118 }
119
120 void
121 MongoDBStorageMixin::setHost(const std::string& n)
122 {
123 settings.host = n;
124 }
125
126 void
127 MongoDBStorageMixin::setPort(const unsigned int n)
128 {
129 settings.port = n;
130 }
131
132 void
133 MongoDBStorageMixin::setUser(const std::string& n)
134 {
135 settings.user = n;
136 }
137
138 void
140 {
141 settings.password = n;
142 }
143
144 void
146 {
147 std::lock_guard l(MongoCXXConnectionPoolMutex);
148 if (!MongoCXXInitialized.exchange(true))
149 {
150 ARMARX_IMPORTANT << "INITIALIZE MONGODB";
151 MongoCXXInstance =
152 std::make_unique<mongocxx::instance>(); // This should be done only once.
153 }
154
155 const auto key = settings.key();
156 const auto uri = settings.uri();
157 auto it = MongoCXXConnectionPool.find(key);
158 if (it == MongoCXXConnectionPool.end())
159 {
160 ARMARX_INFO << "Establishing new connection to: " << uri << " from id: " << _id.str();
161 mongocxx::uri u(uri);
162 auto pool = std::make_unique<mongocxx::pool>(u);
163 MongoCXXConnectionPool.emplace(settings.key(), std::move(pool));
164 }
165 }
166
167 mongocxx::pool*
168 MongoDBStorageMixin::getPool(bool tryToConnect) const
169 {
170 std::lock_guard l(MongoCXXConnectionPoolMutex);
171 const auto key = settings.key();
172 auto it = MongoCXXConnectionPool.find(key);
173 if (it == MongoCXXConnectionPool.end())
174 {
175 if (tryToConnect)
176 {
177 // try to establish a connection and try again
178 connect();
179 return getPool(false);
180 }
181 return nullptr;
182 }
183 else
184 {
185 return it->second.get();
186 }
187 }
188
189 mongocxx::pool*
190 MongoDBStorageMixin::ensurePool() const
191 {
192 std::lock_guard l(MongoCXXConnectionPoolMutex);
193 auto pool = getPool();
194 if (pool)
195 {
196 return pool;
197 }
198 else
199 {
200 throw armarx::LocalException("Pool could not be ensured...");
201 }
202 }
203
204 void
206 {
207 // ensure a connection is made if not done already
208 connect();
209 }
210
211 void
215
216 bool
218 {
219 std::lock_guard l(MongoCXXConnectionPoolMutex);
220
221 try
222 {
223 auto client = ensurePool()->acquire();
224 auto admin = client->database("admin");
225 auto result = admin.run_command(bsoncxx::builder::basic::make_document(
226 bsoncxx::builder::basic::kvp("isMaster", 1)));
227 return true;
228 }
229 catch (const std::exception& xcp)
230 {
231 return false;
232 }
233 return false; // should never happen
234 }
235
236 std::string
241
242 std::string
247
248 std::string
250 {
251 ARMARX_CHECK(!_id.memoryName.empty() and !_id.coreSegmentName.empty());
252 return util::mongodb::toCollectionName(_id.removeLeafItem());
253 }
254
255 std::string
257 {
258 return exportName;
259 }
260
261 std::optional<mongocxx::database>
263 {
264 auto client = this->ensurePool()->acquire();
266 }
267
268 std::optional<mongocxx::collection>
270 {
271 auto db = databaseExists();
272 if (!db)
273 {
274 return std::nullopt;
275 }
276
278 }
279
280 std::optional<mongocxx::collection>
282 {
283 auto db = databaseExists();
284 if (!db)
285 {
286 return std::nullopt;
287 }
288
290 }
291
292 std::optional<nlohmann::json>
297
298 std::optional<nlohmann::json>
299 MongoDBStorageMixin::documentExists(const std::string& id) const
300 {
301 auto coll = collectionExists();
302 if (!coll)
303 {
304 return std::nullopt;
305 }
306
307 nlohmann::json query;
310 }
311
312 mongocxx::database
314 {
315 auto client = this->ensurePool()->acquire();
316 return util::mongodb::ensureDatabaseExists(*client, getDatabaseName(), createIfNotExistent);
317 }
318
319 mongocxx::collection
321 {
322 auto db = ensureDatabaseExists(createIfNotExistent);
323 return util::mongodb::ensureCollectionExists(db, getCollectionName(), createIfNotExistent);
324 }
325
326 mongocxx::collection
328 {
329 auto db = ensureDatabaseExists(createIfNotExistent);
331 db, getPreviousCollectionName(), createIfNotExistent);
332 }
333
334 nlohmann::json
336 {
337 return ensureDocumentExists(getDocumentName(), createIfNotExistent);
338 }
339
340 nlohmann::json
341 MongoDBStorageMixin::ensureDocumentExists(const std::string& id, bool createIfNotExistent)
342 {
343 auto coll = ensureCollectionExists(createIfNotExistent);
344
345 nlohmann::json query;
347 return util::mongodb::ensureDocumentExists(coll, query, createIfNotExistent);
348 }
349
350 void
351 MongoDBStorageMixin::writeDataToDocument(const std::string& id, const nlohmann::json& data)
352 {
353 auto coll = ensureCollectionExists(true);
354
355 nlohmann::json query;
357
358 nlohmann::json update;
359 update[DATA] = data;
361 }
362
363 void
365 {
366 auto coll = ensurePreviousCollectionExists(true);
367
368 nlohmann::json query;
369 query[ID] = _id.str();
370
371 nlohmann::json update;
372 update[FOREIGN_KEY] = getCollectionName();
374 }
375
376 void
378 {
379 auto coll = ensurePreviousCollectionExists(true);
380
381 nlohmann::json query;
382 query[ID] = _id.str();
383
384 nlohmann::json update;
385 update[FOREIGN_KEY] = getCollectionName();
386 update[TYPE] = type;
387
389 }
390
391 nlohmann::json
392 MongoDBStorageMixin::readDataFromDocument(const std::string& id) const
393 {
394 auto coll = collectionExists();
395 if (!coll)
396 {
397 // What to do here?
398 return {};
399 }
400
401 if (!documentExists())
402 {
403 // What to do here?
404 return {};
405 }
406
407 auto query =
408 nlohmann::json::parse(std::string("{\"") + ID + "\": " + getDocumentName() + "}");
410 }
411
412 void
417
418 nlohmann::json
423
424 std::vector<nlohmann::json>
426 {
427 auto coll = collectionExists();
428 if (!coll)
429 {
430 return {};
431 }
432 return util::mongodb::getAllDocuments(*coll);
433 }
434
437 {
438 return settings;
439 }
440
441 void
443 {
444 ARMARX_CHECK_NOT_EMPTY(_id.memoryName) << " The full id was: " << _id.str();
445
446 _id = n;
447 }
448
449 void
451 {
452 exportName = n;
453 }
454
455 void
456 MongoDBStorageMixin::configureMixin(const nlohmann::json& json)
457 {
458 }
459} // namespace armarx::armem::server::ltm::detail::mixin
#define ARMARX_CHECK_NOT_EMPTY(c)
void initializeFromArmarXConfig()
Fills missing fields from armarx config file.
void configureMixin(const nlohmann::json &json)
configuration
mongocxx::collection ensureCollectionExists(bool createIfNotExistent=false)
nlohmann::json ensureDocumentExists(bool createIfNotExistent=false)
mongocxx::database ensureDatabaseExists(bool createIfNotExistent=false)
std::optional< mongocxx::collection > collectionExists() const
mongocxx::collection ensurePreviousCollectionExists(bool createIfNotExistent=false)
std::optional< mongocxx::collection > previousCollectionExists() const
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file is part of ArmarX.
bool directoryExists(const std::filesystem::path &p)
std::optional< mongocxx::database > databaseExists(mongocxx::client &client, const std::string &databaseName)
Definition mongodb.cpp:84
mongocxx::collection ensureCollectionExists(mongocxx::database &db, const std::string &collectionName, bool createIfNotExistent)
Definition mongodb.cpp:122
std::optional< nlohmann::json > documentExists(mongocxx::collection &collection, const nlohmann::json &json)
Definition mongodb.cpp:176
std::vector< nlohmann::json > getAllDocuments(mongocxx::collection &collection)
Definition mongodb.cpp:240
void writeDataToDocument(mongocxx::collection &collection, const nlohmann::json &query, const nlohmann::json &update)
Definition mongodb.cpp:222
nlohmann::json ensureDocumentExists(mongocxx::collection &collection, const nlohmann::json &json, bool createIfNotExistent)
Definition mongodb.cpp:182
mongocxx::database ensureDatabaseExists(mongocxx::client &client, const std::string &databaseName, bool createIfNotExistent)
Definition mongodb.cpp:95
std::optional< mongocxx::collection > collectionExists(mongocxx::database &db, const std::string &collectionName)
Definition mongodb.cpp:112
nlohmann::json readDataFromDocument(mongocxx::collection &collection, const nlohmann::json &json)
Definition mongodb.cpp:211
std::string toCollectionName(const armem::MemoryID &id)
Definition mongodb.cpp:151
std::string toDocumentID(const armem::MemoryID &id)
Definition mongodb.cpp:139