| Line |
Branch |
Exec |
Source |
| 1 |
|
|
// <AppManager.hpp> -*- C++ -*- |
| 2 |
|
|
|
| 3 |
|
|
#pragma once |
| 4 |
|
|
|
| 5 |
|
|
#include "simdb/Assert.hpp" |
| 6 |
|
|
#include "simdb/apps/App.hpp" |
| 7 |
|
|
#include "simdb/pipeline/PipelineManager.hpp" |
| 8 |
|
|
#include "simdb/sqlite/DatabaseManager.hpp" |
| 9 |
|
|
#include "simdb/utils/StreamFormatters.hpp" |
| 10 |
|
|
#include "simdb/utils/ThreadSafeLogger.hpp" |
| 11 |
|
|
|
| 12 |
|
|
#include <filesystem> |
| 13 |
|
|
#include <iostream> |
| 14 |
|
|
#include <map> |
| 15 |
|
|
#include <set> |
| 16 |
|
|
#include <string> |
| 17 |
|
|
#include <string_view> |
| 18 |
|
|
#include <vector> |
| 19 |
|
|
|
| 20 |
|
|
#define PROFILE_APP_PHASE [[maybe_unused]] ScopedTimer timer(getDatabaseManager(), __FUNCTION__); |
| 21 |
|
|
|
| 22 |
|
|
namespace simdb { |
| 23 |
|
|
|
| 24 |
|
|
namespace utils { |
| 25 |
|
|
template <typename, typename = void> struct has_nested_factory : std::false_type |
| 26 |
|
|
{ |
| 27 |
|
|
}; |
| 28 |
|
|
|
| 29 |
|
|
template <typename T> struct has_nested_factory<T, std::void_t<typename T::AppFactory>> : std::true_type |
| 30 |
|
|
{ |
| 31 |
|
|
}; |
| 32 |
|
|
} // namespace utils |
| 33 |
|
|
|
| 34 |
|
|
class AppManager; |
| 35 |
|
|
class AppManagers; |
| 36 |
|
|
|
| 37 |
|
|
/*! |
| 38 |
|
|
* \class AppRegistrationBase |
| 39 |
|
|
* |
| 40 |
|
|
* \brief Abstract registration that adds an app type to an AppManager when |
| 41 |
|
|
* registerApp() is called. Used by AppManagers to register app types |
| 42 |
|
|
* before createAppManager(). |
| 43 |
|
|
*/ |
| 44 |
|
|
class AppRegistrationBase |
| 45 |
|
|
{ |
| 46 |
|
|
public: |
| 47 |
|
11 |
virtual ~AppRegistrationBase() = default; |
| 48 |
|
|
/// \brief Register this app type with the given AppManager (e.g. enable it for later creation). |
| 49 |
|
|
virtual void registerApp(AppManager* app_manager) const = 0; |
| 50 |
|
|
}; |
| 51 |
|
|
|
| 52 |
|
|
/// \brief Type-specific registration for AppT; created by AppManagers::registerApp<AppT>(). |
| 53 |
|
|
template <typename AppT> class AppRegistration : public AppRegistrationBase |
| 54 |
|
|
{ |
| 55 |
|
|
private: |
| 56 |
|
11 |
AppRegistration() = default; |
| 57 |
|
|
void registerApp(AppManager* app_manager) const override; |
| 58 |
|
|
friend class AppManagers; |
| 59 |
|
|
}; |
| 60 |
|
|
|
| 61 |
|
|
/*! |
| 62 |
|
|
* \class AppManager |
| 63 |
|
|
* |
| 64 |
|
|
* \brief Registers, enables, instantiates, and manages the lifecycle of SimDB |
| 65 |
|
|
* apps for one database. Obtainfrom AppManagers::createAppManager() or |
| 66 |
|
|
* AppManagers::getAppManager(). |
| 67 |
|
|
*/ |
| 68 |
|
|
class AppManager |
| 69 |
|
|
{ |
| 70 |
|
|
public: |
| 71 |
|
|
/// \brief Return the associated DatabaseManager. |
| 72 |
|
46 |
DatabaseManager* getDatabaseManager() const { return db_mgr_; } |
| 73 |
|
|
|
| 74 |
|
|
/// \brief Parameterize an app factory. Must be called before createEnabledApps(). |
| 75 |
|
|
/// Your app subclass must have a public nested class called "AppFactory", |
| 76 |
|
|
/// inheriting publicly from simdb::AppFactoryBase. Your nested AppFactory |
| 77 |
|
|
/// can have any signature it needs to accept all required app constructor |
| 78 |
|
|
/// arguments. |
| 79 |
|
|
/// |
| 80 |
|
|
/// void parameterize(int x, float y) |
| 81 |
|
|
/// { |
| 82 |
|
|
/// ... |
| 83 |
|
|
/// } |
| 84 |
|
|
/// |
| 85 |
|
|
/// For example: |
| 86 |
|
|
/// |
| 87 |
|
|
/// class MyApp : public simdb::App |
| 88 |
|
|
/// { |
| 89 |
|
|
/// public: |
| 90 |
|
|
/// MyApp(simdb::DatabaseManager* db_mgr, int x, float y); |
| 91 |
|
|
/// |
| 92 |
|
|
/// class AppFactory : public simdb::AppFactoryBase |
| 93 |
|
|
/// { |
| 94 |
|
|
/// public: |
| 95 |
|
|
/// void parameterize(int x, float y) |
| 96 |
|
|
/// { |
| 97 |
|
|
/// ctor_args_ = std::make_pair(x, y); |
| 98 |
|
|
/// } |
| 99 |
|
|
/// |
| 100 |
|
|
/// simdb::App* createApp(simdb::DatabaseManager* db_mgr) override |
| 101 |
|
|
/// { |
| 102 |
|
|
/// const auto & [x, y] = ctor_args_; |
| 103 |
|
|
/// return new MyApp(db_mgr, x, y); |
| 104 |
|
|
/// } |
| 105 |
|
|
/// |
| 106 |
|
|
/// void defineSchema(simdb::Schema& schema) const override |
| 107 |
|
|
/// { |
| 108 |
|
|
/// ... |
| 109 |
|
|
/// } |
| 110 |
|
|
/// |
| 111 |
|
|
/// private: |
| 112 |
|
|
/// std::pair<int,float> ctor_args_; |
| 113 |
|
|
/// }; |
| 114 |
|
|
/// }; |
| 115 |
|
|
/// |
| 116 |
|
|
/// Then do this: |
| 117 |
|
|
/// |
| 118 |
|
|
/// // Parameterize before createEnabledApps() |
| 119 |
|
|
/// |
| 120 |
|
|
/// // How to parameterize all instances of your app: |
| 121 |
|
|
/// app_mgr.parameterizeAppFactory<MyApp>(1 /*x*/, 2.2 /*y*/); |
| 122 |
|
|
/// |
| 123 |
|
|
/// // How to parameterize one instance of your app: |
| 124 |
|
|
/// app_mgr.parameterizeAppFactoryInstance<MyApp>(1 /*inst num*/, 1 |
| 125 |
|
|
/// /*x*/, 2.2 /*y*/); app_mgr.parameterizeAppFactoryInstance<MyApp>(2 |
| 126 |
|
|
/// /*inst num*/, 3 /*x*/, 4.4 /*y*/); |
| 127 |
|
|
/// |
| 128 |
|
|
/// // Assume have the AppManager by now: |
| 129 |
|
|
/// app_mgr.enableApp(MyApp::NAME); |
| 130 |
|
|
/// app_mgr.enableApp(MyApp::NAME, 2 /*inst count*/); |
| 131 |
|
|
/// |
| 132 |
|
|
/// // Then continue and create the apps: |
| 133 |
|
|
/// app_mgr.createEnabledApps(); |
| 134 |
|
|
/// |
| 135 |
|
|
/// IMPORTANT: If you already configured specific app instance factories |
| 136 |
|
|
/// with parameterizeAppFactoryInstance(), this method will throw away |
| 137 |
|
|
/// all your factory configurations, and all instances will end up using |
| 138 |
|
|
/// the same factory that is being "globally" configured right now (unless |
| 139 |
|
|
/// you call parameterizeAppFactoryInstance() again). Only a warning will |
| 140 |
|
|
/// be issued. |
| 141 |
|
3 |
template <typename AppT, typename... Args> void parameterizeAppFactory([[maybe_unused]] Args&&... args) |
| 142 |
|
|
{ |
| 143 |
|
|
if constexpr (utils::has_nested_factory<AppT>::value) |
| 144 |
|
|
{ |
| 145 |
26/28
void simdb::AppManager::parameterizeAppFactory<UnregisteredAppWithFactory>():
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 27 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 25 → 26 taken 1 time.
void simdb::AppManager::parameterizeAppFactory<MyApp, int, double>(int&&, double&&):
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 27 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 25 → 26 taken 1 time.
|
8 |
simdb_assert(enabled(AppT::NAME), "You need to call enableApp() before parameterizing factories."); |
| 146 |
|
|
|
| 147 |
|
✗ |
auto& app_factories = getDefaultAppFactories_(); |
| 148 |
|
|
|
| 149 |
0/4
void simdb::AppManager::parameterizeAppFactory<UnregisteredAppWithFactory>():
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
void simdb::AppManager::parameterizeAppFactory<MyApp, int, double>(int&&, double&&):
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
|
✗ |
auto num_overwritten = app_factories[AppT::NAME].size(); |
| 150 |
0/4
void simdb::AppManager::parameterizeAppFactory<UnregisteredAppWithFactory>():
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 46 not taken.
void simdb::AppManager::parameterizeAppFactory<MyApp, int, double>(int&&, double&&):
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 46 not taken.
|
✗ |
if (num_overwritten > 0) |
| 151 |
|
|
{ |
| 152 |
|
✗ |
std::cout << "WARNING: Throwing away " << num_overwritten << " app factor" |
| 153 |
|
|
<< (num_overwritten > 1 ? "ies " : "y") << " and creating a new one for all apps of type " |
| 154 |
0/4
void simdb::AppManager::parameterizeAppFactory<UnregisteredAppWithFactory>():
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
void simdb::AppManager::parameterizeAppFactory<MyApp, int, double>(int&&, double&&):
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
|
✗ |
<< AppT::NAME << ". Was this intentional?\n"; |
| 155 |
|
|
} |
| 156 |
|
|
|
| 157 |
0/4
void simdb::AppManager::parameterizeAppFactory<UnregisteredAppWithFactory>():
✗ Branch 48 → 49 not taken.
✗ Branch 49 → 50 not taken.
void simdb::AppManager::parameterizeAppFactory<MyApp, int, double>(int&&, double&&):
✗ Branch 48 → 49 not taken.
✗ Branch 49 → 50 not taken.
|
✗ |
app_factories[AppT::NAME].clear(); |
| 158 |
|
|
|
| 159 |
|
✗ |
constexpr size_t global_instance_num = 0; |
| 160 |
|
✗ |
auto factory = getNestedAppFactory_<AppT>(global_instance_num); |
| 161 |
|
✗ |
factory->parameterize(std::forward<Args>(args)...); |
| 162 |
|
|
} else |
| 163 |
|
|
{ |
| 164 |
4/4
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
|
1 |
throw DBException("No nested class 'AppFactory' exists for app '") << AppT::NAME << "'."; |
| 165 |
|
|
} |
| 166 |
|
✗ |
} |
| 167 |
|
|
|
| 168 |
|
|
/// Parameterize an app factory. Call this after enableApp() but before |
| 169 |
|
|
/// createEnabledApps(). Your app subclass must have a public nested class |
| 170 |
|
|
/// called "AppFactory", inheriting publicly from simdb::AppFactoryBase. |
| 171 |
|
|
template <typename AppT, typename... Args> |
| 172 |
|
8 |
void parameterizeAppFactoryInstance(size_t instance_num, [[maybe_unused]] Args&&... args) |
| 173 |
|
|
{ |
| 174 |
|
|
if constexpr (utils::has_nested_factory<AppT>::value) |
| 175 |
|
|
{ |
| 176 |
29/42
void simdb::AppManager::parameterizeAppFactoryInstance<UnregisteredAppWithFactory>(unsigned long):
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 27 not taken.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 25 → 26 taken 1 time.
void simdb::AppManager::parameterizeAppFactoryInstance<MyApp, int const&, float const&>(unsigned long, int const&, float const&):
✓ Branch 4 → 5 taken 4 times.
✓ Branch 5 → 6 taken 4 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 27 taken 4 times.
✗ Branch 11 → 12 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 25 → 26 not taken.
void simdb::AppManager::parameterizeAppFactoryInstance<MyApp, int, double>(unsigned long, int&&, double&&):
✓ Branch 4 → 5 taken 2 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 27 not taken.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 14 → 15 taken 2 times.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 21 → 22 taken 2 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 23 → 24 taken 2 times.
✓ Branch 25 → 26 taken 2 times.
|
20 |
simdb_assert(enabled(AppT::NAME), "You need to call enableApp() before parameterizing factories."); |
| 177 |
|
|
|
| 178 |
|
4 |
std::cout << "Parameterizing '" << AppT::NAME << "' app, instance " << instance_num << "\n"; |
| 179 |
|
4 |
auto factory = getNestedAppFactory_<AppT>(instance_num); |
| 180 |
|
4 |
factory->parameterize(std::forward<Args>(args)...); |
| 181 |
|
|
} else |
| 182 |
|
|
{ |
| 183 |
4/4
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
|
1 |
throw DBException("No nested class 'AppFactory' exists for app '") << AppT::NAME << "'."; |
| 184 |
|
|
} |
| 185 |
|
4 |
} |
| 186 |
|
|
|
| 187 |
|
|
/// Enable verbose mode for all apps in this AppManager. |
| 188 |
|
12 |
void setVerbose(bool verbose = true) |
| 189 |
|
|
{ |
| 190 |
|
12 |
verbose_ = verbose; |
| 191 |
2/3
✓ Branch 2 → 3 taken 12 times.
✗ Branch 8 → 5 not taken.
✓ Branch 8 → 9 taken 12 times.
|
12 |
for (auto app : getApps_()) |
| 192 |
|
|
{ |
| 193 |
|
✗ |
app->verbose_ = verbose_; |
| 194 |
|
12 |
} |
| 195 |
|
12 |
} |
| 196 |
|
|
|
| 197 |
|
|
/// After parsing command line arguments or configuration files, |
| 198 |
|
|
/// enable an app by its name. This will allow the app to be instantiated |
| 199 |
|
|
/// and run during the simulation lifecycle. |
| 200 |
|
|
/// |
| 201 |
|
|
/// class MyApp : public simdb::App |
| 202 |
|
|
/// { |
| 203 |
|
|
/// public: |
| 204 |
|
|
/// static constexpr const char* NAME = "MyApp"; |
| 205 |
|
|
/// // ... |
| 206 |
|
|
/// }; |
| 207 |
|
|
/// |
| 208 |
|
|
/// // Somewhere in your main function or config parsing code (meaning, |
| 209 |
|
|
/// // after command line args are parsed and very early in the |
| 210 |
|
|
/// simulation): simdb::AppManager::getInstance().enableApp(MyApp::NAME); |
| 211 |
|
13 |
void enableApp(const std::string& app_name, size_t num_instances = 1) |
| 212 |
|
|
{ |
| 213 |
|
13 |
getEnabledApps_()[app_name] = num_instances; |
| 214 |
|
13 |
} |
| 215 |
|
|
|
| 216 |
|
|
template <typename AppT> void enableApp(size_t num_instances = 1) |
| 217 |
|
|
{ |
| 218 |
|
|
static_assert(std::is_base_of<App, AppT>::value, "AppT must derive from App"); |
| 219 |
|
|
enableApp(AppT::NAME, num_instances); |
| 220 |
|
|
} |
| 221 |
|
|
|
| 222 |
|
|
/// Check if your app is enabled (might not be instantiated yet). |
| 223 |
|
28 |
bool enabled(const std::string& app_name) const |
| 224 |
|
|
{ |
| 225 |
|
28 |
const auto& enabled_apps = getEnabledApps_(); |
| 226 |
1/1
✓ Branch 4 → 5 taken 28 times.
|
28 |
return enabled_apps.find(app_name) != enabled_apps.end(); |
| 227 |
|
|
} |
| 228 |
|
|
|
| 229 |
|
|
/// Check if your app is enabled (might not be instantiated yet). |
| 230 |
|
18 |
template <typename AppT> bool enabled() const |
| 231 |
|
|
{ |
| 232 |
|
|
static_assert(std::is_base_of<App, AppT>::value, "AppT must derive from App"); |
| 233 |
12/12
bool simdb::AppManager::enabled<SimplePipeline>() const:
✓ Branch 4 → 5 taken 6 times.
✓ Branch 5 → 6 taken 6 times.
bool simdb::AppManager::enabled<PipelineSnooper>() const:
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
bool simdb::AppManager::enabled<WatchedPipeline>() const:
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
bool simdb::AppManager::enabled<DatabaseWatchdog>() const:
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
bool simdb::AppManager::enabled<MyApp>() const:
✓ Branch 4 → 5 taken 4 times.
✓ Branch 5 → 6 taken 4 times.
bool simdb::AppManager::enabled<simdb::argos::ArgosCollector>() const:
✓ Branch 4 → 5 taken 5 times.
✓ Branch 5 → 6 taken 5 times.
|
36 |
return enabled(AppT::NAME); |
| 234 |
|
|
} |
| 235 |
|
|
|
| 236 |
|
|
/// See how many instances of a particular app are enabled. |
| 237 |
|
1 |
size_t getEnabledAppInstances(const std::string& app_name) const |
| 238 |
|
|
{ |
| 239 |
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 7 not taken.
|
1 |
return enabled(app_name) ? getEnabledApps_().at(app_name) : 0; |
| 240 |
|
|
} |
| 241 |
|
|
|
| 242 |
|
|
/// See how many instances of a particular app are enabled. |
| 243 |
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
|
3 |
template <typename AppT> size_t getEnabledAppInstances() const { return getEnabledAppInstances(AppT::NAME); } |
| 244 |
|
|
|
| 245 |
|
|
/// Get an instantiated app. You may only call this method if AppT had |
| 246 |
|
|
/// exactly one instance configured: |
| 247 |
|
|
/// AppManager::enableApp(AppT::NAME); |
| 248 |
|
|
/// AppManager::enableApp(AppT::NAME, 1); |
| 249 |
|
|
/// |
| 250 |
|
|
/// For multi-instance apps, call getAppInstance<AppT>(instance_num) |
| 251 |
|
|
/// (zero-based). Note that for single-instance apps, you can still call |
| 252 |
|
|
/// getAppInstance<AppT>(0). |
| 253 |
|
10 |
template <typename AppT> AppT* getApp() |
| 254 |
|
|
{ |
| 255 |
|
|
static_assert(std::is_base_of<App, AppT>::value, "AppT must derive from App"); |
| 256 |
|
|
|
| 257 |
10/15
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 2 → 3 taken 2 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 2 → 3 taken 5 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
|
10 |
if (!enabled<AppT>()) |
| 258 |
|
|
{ |
| 259 |
|
✗ |
return nullptr; |
| 260 |
|
|
} |
| 261 |
|
|
|
| 262 |
|
10 |
auto& enabled_apps = getEnabledApps_(); |
| 263 |
33/105
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 8 → 9 taken 2 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 42 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 25 → 26 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 40 → 41 taken 1 time.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 42 taken 1 time.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 40 → 41 not taken.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 42 taken 1 time.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 40 → 41 not taken.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 42 taken 1 time.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 40 → 41 not taken.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 8 → 9 taken 5 times.
✓ Branch 9 → 10 taken 5 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 42 taken 5 times.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 40 → 41 not taken.
|
24 |
simdb_assert(enabled_apps.at(AppT::NAME) <= 1, "Need to call getAppInstance<AppT>(instance_num) since " |
| 264 |
|
|
<< "the '" << AppT::NAME << "' app was configured to have " |
| 265 |
|
|
<< enabled_apps.at(AppT::NAME) << " instances."); |
| 266 |
|
|
|
| 267 |
|
|
// Look for instance name |
| 268 |
10/10
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 44 → 45 taken 5 times.
✓ Branch 45 → 46 taken 5 times.
|
9 |
std::string instance_name = AppT::NAME + std::string("-0"); |
| 269 |
5/5
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 48 → 49 taken 1 time.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 48 → 49 taken 1 time.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 48 → 49 taken 1 time.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 48 → 49 taken 1 time.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 48 → 49 taken 5 times.
|
9 |
auto it = apps_.find(instance_name); |
| 270 |
5/10
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 81 not taken.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 81 not taken.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 81 not taken.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 51 → 52 taken 1 time.
✗ Branch 51 → 81 not taken.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 51 → 52 taken 5 times.
✗ Branch 51 → 81 not taken.
|
9 |
if (it != apps_.end()) |
| 271 |
|
|
{ |
| 272 |
5/10
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 56 not taken.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 56 not taken.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 56 not taken.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 56 not taken.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✓ Branch 54 → 55 taken 5 times.
✗ Branch 54 → 56 not taken.
|
9 |
auto app = dynamic_cast<AppT*>(it->second.get()); |
| 273 |
5/75
SimplePipeline* simdb::AppManager::getApp<SimplePipeline>():
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 80 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 78 → 79 not taken.
PipelineSnooper* simdb::AppManager::getApp<PipelineSnooper>():
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 80 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 78 → 79 not taken.
WatchedPipeline* simdb::AppManager::getApp<WatchedPipeline>():
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 80 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 78 → 79 not taken.
DatabaseWatchdog* simdb::AppManager::getApp<DatabaseWatchdog>():
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 80 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 78 → 79 not taken.
simdb::argos::ArgosCollector* simdb::AppManager::getApp<simdb::argos::ArgosCollector>():
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 80 taken 5 times.
✗ Branch 60 → 61 not taken.
✗ Branch 61 → 62 not taken.
✗ Branch 63 → 64 not taken.
✗ Branch 67 → 68 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 74 → 75 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 78 → 79 not taken.
|
9 |
simdb_assert(app, "App of type " << AppT::NAME << " is not of type " << typeid(AppT).name()); |
| 274 |
|
9 |
return app; |
| 275 |
|
|
} |
| 276 |
|
|
|
| 277 |
|
✗ |
return nullptr; |
| 278 |
|
9 |
} |
| 279 |
|
|
|
| 280 |
|
|
/// Get an instantiated app. Call this method for multi-instance apps. |
| 281 |
|
8 |
template <typename AppT> AppT* getAppInstance(size_t instance_num) |
| 282 |
|
|
{ |
| 283 |
|
|
static_assert(std::is_base_of<App, AppT>::value, "AppT must derive from App"); |
| 284 |
|
|
|
| 285 |
4/6
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✓ Branch 2 → 3 taken 4 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✓ Branch 2 → 3 taken 4 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
|
8 |
if (!enabled<AppT>()) |
| 286 |
|
|
{ |
| 287 |
|
✗ |
return nullptr; |
| 288 |
|
|
} |
| 289 |
|
|
|
| 290 |
|
|
// Look for instance name |
| 291 |
8/8
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✓ Branch 5 → 6 taken 4 times.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 9 → 10 taken 4 times.
✓ Branch 10 → 11 taken 4 times.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✓ Branch 5 → 6 taken 4 times.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 9 → 10 taken 4 times.
✓ Branch 10 → 11 taken 4 times.
|
24 |
std::string instance_name = AppT::NAME + std::string("-") + std::to_string(instance_num); |
| 292 |
2/2
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✓ Branch 15 → 16 taken 4 times.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✓ Branch 15 → 16 taken 4 times.
|
8 |
auto it = apps_.find(instance_name); |
| 293 |
2/4
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 48 not taken.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 48 not taken.
|
8 |
if (it != apps_.end()) |
| 294 |
|
|
{ |
| 295 |
2/4
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✓ Branch 21 → 22 taken 4 times.
✗ Branch 21 → 23 not taken.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✓ Branch 21 → 22 taken 4 times.
✗ Branch 21 → 23 not taken.
|
8 |
auto app = dynamic_cast<AppT*>(it->second.get()); |
| 296 |
2/30
SimplePipeline* simdb::AppManager::getAppInstance<SimplePipeline>(unsigned long):
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 47 taken 4 times.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 45 → 46 not taken.
MyApp* simdb::AppManager::getAppInstance<MyApp>(unsigned long):
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 47 taken 4 times.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 45 → 46 not taken.
|
8 |
simdb_assert(app, "App of type " << AppT::NAME << " is not of type " << typeid(AppT).name()); |
| 297 |
|
8 |
return app; |
| 298 |
|
|
} |
| 299 |
|
|
|
| 300 |
|
✗ |
return nullptr; |
| 301 |
|
8 |
} |
| 302 |
|
|
|
| 303 |
|
|
/// Optionally call this method after initializePipelines(), but before |
| 304 |
|
|
/// openPipelines(). This will reduce the number of non-database threads |
| 305 |
|
|
/// to the minimum across all app pipelines. |
| 306 |
|
|
/// |
| 307 |
|
|
/// Note that you can either call minimizeThreads() OR minimizeThreads(app1, |
| 308 |
|
|
/// app2, ...) but you cannot call both. |
| 309 |
|
|
void minimizeThreads() |
| 310 |
|
|
{ |
| 311 |
|
|
simdb_assert(pipeline_mgr_, "Pipeline manager not set - did you call initializePipelines()?"); |
| 312 |
|
|
pipeline_mgr_->minimizeThreads(); |
| 313 |
|
|
} |
| 314 |
|
|
|
| 315 |
|
|
/// Optionally call this method after initializePipelines(), but before |
| 316 |
|
|
/// openPipelines(). This will share the minimum number of non-database |
| 317 |
|
|
/// threads across the given apps' pipelines. |
| 318 |
|
|
template <typename... Apps> void minimizeThreads(const App* app, Apps&&... rest) |
| 319 |
|
|
{ |
| 320 |
|
|
simdb_assert(pipeline_mgr_, "Pipeline manager not set - did you call initializePipelines()?"); |
| 321 |
|
|
pipeline_mgr_->minimizeThreads(app, std::forward<Apps>(rest)...); |
| 322 |
|
|
} |
| 323 |
|
|
|
| 324 |
|
|
/// \brief Set the order in which app lifecycle hooks are invoked. |
| 325 |
|
|
/// |
| 326 |
|
|
/// postInit(), preTeardown(), and postTeardown() are called in this order |
| 327 |
|
|
/// across apps. \p ordered_app_names lists base app names (e.g. \c "App2", |
| 328 |
|
|
/// \c "App1"); hooks run first for all instances of the first name, then |
| 329 |
|
|
/// the second, etc. Apps not listed are invoked after the listed apps, in |
| 330 |
|
|
/// map order. Call before createEnabledApps() (or at least before the |
| 331 |
|
|
/// hooks run). Pass an empty vector to clear ordering and use default |
| 332 |
|
|
/// (map) order. |
| 333 |
|
|
void setAppOrderingForHooks(const std::vector<std::string>& ordered_app_names) |
| 334 |
|
|
{ |
| 335 |
|
|
hook_ordering_ = ordered_app_names; |
| 336 |
|
|
} |
| 337 |
|
|
|
| 338 |
|
|
/// \brief Set the order in which app lifecycle hooks are invoked (variadic). |
| 339 |
|
|
/// |
| 340 |
|
|
/// Same as setAppOrderingForHooks(vector) but takes a list of app names, |
| 341 |
|
|
/// e.g. setAppOrderingForHooks("App2", "App1") so App2's hooks run before |
| 342 |
|
|
/// App1's. |
| 343 |
|
|
template <typename... AppNames> |
| 344 |
|
|
void setAppOrderingForHooks(const std::string_view app_name, AppNames&&... app_names) |
| 345 |
|
|
{ |
| 346 |
|
|
hook_ordering_.clear(); |
| 347 |
|
|
hook_ordering_.reserve(1 + sizeof...(AppNames)); |
| 348 |
|
|
hook_ordering_.emplace_back(app_name); |
| 349 |
|
|
if constexpr (sizeof...(AppNames) > 0) |
| 350 |
|
|
{ |
| 351 |
|
|
(hook_ordering_.emplace_back(std::forward<AppNames>(app_names)), ...); |
| 352 |
|
|
} |
| 353 |
|
|
} |
| 354 |
|
|
|
| 355 |
|
|
private: |
| 356 |
|
|
/// AppManagers are associated 1-to-1 with a DatabaseManager. |
| 357 |
|
12 |
AppManager(DatabaseManager* db_mgr, ThreadSafeLogger* app_logger = nullptr) : |
| 358 |
|
12 |
db_mgr_(db_mgr), |
| 359 |
|
12 |
app_logger_(app_logger) |
| 360 |
|
|
{ |
| 361 |
|
12 |
} |
| 362 |
|
|
|
| 363 |
|
|
/// AppManager only to be instantiated by simdb::AppManagers |
| 364 |
|
|
friend class AppManagers; |
| 365 |
|
|
|
| 366 |
|
|
/// App registration only to be done by simdb::AppRegistration<AppT> |
| 367 |
|
|
template <typename AppT> friend class AppRegistration; |
| 368 |
|
|
|
| 369 |
|
|
/// Register an app as early as possible (doesn't create it yet). |
| 370 |
|
13 |
template <typename AppT> void registerApp_() |
| 371 |
|
|
{ |
| 372 |
|
|
if constexpr (utils::has_nested_factory<AppT>::value) |
| 373 |
|
|
{ |
| 374 |
|
|
// We don't need to create the nested factory object now. |
| 375 |
|
|
// When apps provide a nested factory, they are supposed |
| 376 |
|
|
// to call parameterizeApp<T>() / parameterizeAppInstance<T>() |
| 377 |
|
|
// before calling createEnabledApps(). |
| 378 |
|
|
// |
| 379 |
|
|
// If they forget to parameterize their own custom-factory app, |
| 380 |
|
|
// we will know it since we won't have the factory. These factories |
| 381 |
|
|
// are created in the parameterize*() calls. |
| 382 |
|
3 |
return; |
| 383 |
|
|
} else |
| 384 |
|
|
{ |
| 385 |
|
10 |
auto& app_factories = getDefaultAppFactories_(); |
| 386 |
15/75
void simdb::AppManager::registerApp_<SimplePipeline>():
✓ Branch 6 → 7 taken 2 times.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 31 taken 2 times.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 29 → 30 not taken.
void simdb::AppManager::registerApp_<PipelineSnooper>():
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 31 taken 1 time.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 29 → 30 not taken.
void simdb::AppManager::registerApp_<WatchedPipeline>():
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 31 taken 1 time.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 29 → 30 not taken.
void simdb::AppManager::registerApp_<DatabaseWatchdog>():
✓ Branch 6 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 31 taken 1 time.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 29 → 30 not taken.
void simdb::AppManager::registerApp_<simdb::argos::ArgosCollector>():
✓ Branch 6 → 7 taken 5 times.
✓ Branch 7 → 8 taken 5 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 31 taken 5 times.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 29 → 30 not taken.
|
30 |
simdb_assert(app_factories.find(AppT::NAME) == app_factories.end(), |
| 387 |
|
|
"App already registered: " << AppT::NAME); |
| 388 |
|
|
|
| 389 |
|
10 |
constexpr size_t global_instance_num = 0; |
| 390 |
15/15
void simdb::AppManager::registerApp_<SimplePipeline>():
✓ Branch 33 → 34 taken 2 times.
✓ Branch 34 → 35 taken 2 times.
✓ Branch 35 → 36 taken 2 times.
void simdb::AppManager::registerApp_<PipelineSnooper>():
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
void simdb::AppManager::registerApp_<WatchedPipeline>():
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
void simdb::AppManager::registerApp_<DatabaseWatchdog>():
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
void simdb::AppManager::registerApp_<simdb::argos::ArgosCollector>():
✓ Branch 33 → 34 taken 5 times.
✓ Branch 34 → 35 taken 5 times.
✓ Branch 35 → 36 taken 5 times.
|
10 |
auto& factory = app_factories[AppT::NAME][global_instance_num]; |
| 391 |
5/5
void simdb::AppManager::registerApp_<SimplePipeline>():
✓ Branch 38 → 39 taken 2 times.
void simdb::AppManager::registerApp_<PipelineSnooper>():
✓ Branch 38 → 39 taken 1 time.
void simdb::AppManager::registerApp_<WatchedPipeline>():
✓ Branch 38 → 39 taken 1 time.
void simdb::AppManager::registerApp_<DatabaseWatchdog>():
✓ Branch 38 → 39 taken 1 time.
void simdb::AppManager::registerApp_<simdb::argos::ArgosCollector>():
✓ Branch 38 → 39 taken 5 times.
|
10 |
factory = std::make_shared<AppFactory<AppT>>(); |
| 392 |
|
|
} |
| 393 |
|
10 |
} |
| 394 |
|
|
|
| 395 |
|
|
/// Get all Apps that belong to the given database. |
| 396 |
|
36 |
std::vector<App*> getApps_() |
| 397 |
|
|
{ |
| 398 |
|
36 |
std::vector<App*> apps; |
| 399 |
2/2
✓ Branch 12 → 5 taken 32 times.
✓ Branch 12 → 13 taken 36 times.
|
68 |
for (const auto& [key, app] : apps_) |
| 400 |
|
|
{ |
| 401 |
1/1
✓ Branch 9 → 10 taken 32 times.
|
32 |
apps.push_back(app.get()); |
| 402 |
|
|
} |
| 403 |
|
36 |
return apps; |
| 404 |
|
✗ |
} |
| 405 |
|
|
|
| 406 |
|
|
/// Get apps in the order to use for lifecycle hooks (postInit, preTeardown, postTeardown). |
| 407 |
|
24 |
std::vector<App*> getAppsInHookOrder_() |
| 408 |
|
|
{ |
| 409 |
1/2
✓ Branch 3 → 4 taken 24 times.
✗ Branch 3 → 6 not taken.
|
24 |
if (hook_ordering_.empty()) |
| 410 |
|
|
{ |
| 411 |
1/1
✓ Branch 4 → 5 taken 24 times.
|
24 |
return getApps_(); |
| 412 |
|
|
} |
| 413 |
|
|
// Group by base app name (instance name is "BaseName-0", "BaseName-1", ...). |
| 414 |
|
✗ |
std::map<std::string, std::vector<App*>> by_base; |
| 415 |
0/2
✗ Branch 22 → 9 not taken.
✗ Branch 22 → 23 not taken.
|
✗ |
for (const auto& [instance_name, app] : apps_) |
| 416 |
|
|
{ |
| 417 |
|
✗ |
auto dash = instance_name.find_last_of('-'); |
| 418 |
0/4
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
✗ Branch 14 → 16 not taken.
✗ Branch 15 → 16 not taken.
|
✗ |
std::string base = (dash != std::string::npos) ? instance_name.substr(0, dash) : instance_name; |
| 419 |
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
|
✗ |
by_base[base].push_back(app.get()); |
| 420 |
|
✗ |
} |
| 421 |
|
✗ |
std::vector<App*> out; |
| 422 |
0/1
✗ Branch 25 → 26 not taken.
|
✗ |
out.reserve(apps_.size()); |
| 423 |
0/2
✗ Branch 44 → 28 not taken.
✗ Branch 44 → 45 not taken.
|
✗ |
for (const std::string& base : hook_ordering_) |
| 424 |
|
|
{ |
| 425 |
0/1
✗ Branch 29 → 30 not taken.
|
✗ |
auto it = by_base.find(base); |
| 426 |
0/2
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 42 not taken.
|
✗ |
if (it != by_base.end()) |
| 427 |
|
|
{ |
| 428 |
0/2
✗ Branch 40 → 36 not taken.
✗ Branch 40 → 41 not taken.
|
✗ |
for (App* app : it->second) |
| 429 |
|
|
{ |
| 430 |
0/1
✗ Branch 37 → 38 not taken.
|
✗ |
out.push_back(app); |
| 431 |
|
|
} |
| 432 |
|
|
} |
| 433 |
|
|
} |
| 434 |
|
|
|
| 435 |
|
|
// Now append any apps that were not given explicit hook ordering |
| 436 |
0/2
✗ Branch 62 → 47 not taken.
✗ Branch 62 → 63 not taken.
|
✗ |
for (auto& [_, app] : apps_) |
| 437 |
|
|
{ |
| 438 |
0/3
✗ Branch 54 → 55 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 60 not taken.
|
✗ |
if (std::find(out.begin(), out.end(), app.get()) == out.end()) |
| 439 |
|
|
{ |
| 440 |
0/1
✗ Branch 58 → 59 not taken.
|
✗ |
out.push_back(app.get()); |
| 441 |
|
|
} |
| 442 |
|
|
} |
| 443 |
|
|
|
| 444 |
0/1
✗ Branch 63 → 64 not taken.
|
✗ |
auto apps = getApps_(); |
| 445 |
0/12
✗ Branch 66 → 67 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 70 → 71 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 84 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 77 → 78 not taken.
✗ Branch 78 → 79 not taken.
✗ Branch 79 → 80 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 82 → 83 not taken.
|
✗ |
simdb_assert(std::set<App*>(out.begin(), out.end()) == std::set<App*>(apps.begin(), apps.end())); |
| 446 |
|
✗ |
return out; |
| 447 |
|
✗ |
} |
| 448 |
|
|
|
| 449 |
|
|
/// Call after command line args and config files are parsed. |
| 450 |
|
12 |
void createEnabledApps_() |
| 451 |
|
|
{ |
| 452 |
2/2
✓ Branch 33 → 5 taken 13 times.
✓ Branch 33 → 34 taken 12 times.
|
25 |
for (const auto& [app_name, num_instances] : getEnabledApps_()) |
| 453 |
|
|
{ |
| 454 |
2/2
✓ Branch 30 → 9 taken 17 times.
✓ Branch 30 → 31 taken 13 times.
|
30 |
for (size_t instance_num = 0; instance_num < num_instances; ++instance_num) |
| 455 |
|
|
{ |
| 456 |
1/1
✓ Branch 9 → 10 taken 17 times.
|
17 |
auto factory = getAppFactory_(app_name, instance_num, false /*do not create*/); |
| 457 |
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 17 times.
|
17 |
if (!factory) |
| 458 |
|
|
{ |
| 459 |
|
✗ |
continue; |
| 460 |
|
|
} |
| 461 |
|
|
|
| 462 |
1/1
✓ Branch 12 → 13 taken 17 times.
|
17 |
App* app = factory->createApp(db_mgr_); |
| 463 |
|
17 |
app->app_logger_ = app_logger_; |
| 464 |
|
17 |
app->instance_ = instance_num; |
| 465 |
|
17 |
app->verbose_ = verbose_; |
| 466 |
4/4
✓ Branch 13 → 14 taken 17 times.
✓ Branch 16 → 17 taken 17 times.
✓ Branch 17 → 18 taken 17 times.
✓ Branch 18 → 19 taken 17 times.
|
51 |
std::string instance_name = app_name + std::string("-") + std::to_string(instance_num); |
| 467 |
1/1
✓ Branch 24 → 25 taken 17 times.
|
17 |
apps_[instance_name] = std::unique_ptr<App>(app); |
| 468 |
|
17 |
} |
| 469 |
|
|
} |
| 470 |
|
12 |
} |
| 471 |
|
|
|
| 472 |
|
|
/// Create app-specific schemas for the instantiated apps. |
| 473 |
|
9 |
void createSchemas_() |
| 474 |
|
|
{ |
| 475 |
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 6 → 7 taken 9 times.
|
9 |
PROFILE_APP_PHASE |
| 476 |
|
|
|
| 477 |
|
|
// TODO cnyce: We are currently creating the apps first, then creating the schemas. |
| 478 |
|
|
// There is no reason to do this in that order, and we should create the schemas |
| 479 |
|
|
// first. The doc (book) was written assuming schemas come first; leave the doc |
| 480 |
|
|
// that way and change the C++ code to match. Call out that you can freely write |
| 481 |
|
|
// to your tables in defineSchema right in your App's constructor. Then ensure |
| 482 |
|
|
// that the createEnabledApps call is inside a safeTransaction. |
| 483 |
1/1
✓ Branch 11 → 12 taken 9 times.
|
9 |
db_mgr_->safeTransaction([&]() { |
| 484 |
2/2
✓ Branch 34 → 4 taken 13 times.
✓ Branch 34 → 35 taken 9 times.
|
22 |
for (const auto& [app_name, app] : apps_) |
| 485 |
|
|
{ |
| 486 |
1/1
✓ Branch 7 → 8 taken 13 times.
|
13 |
auto user_app_name = app_name; |
| 487 |
|
13 |
auto idx = user_app_name.find_last_of("-"); |
| 488 |
1/9
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 20 taken 13 times.
✗ Branch 11 → 12 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
|
13 |
simdb_assert(idx != std::string::npos); |
| 489 |
1/1
✓ Branch 20 → 21 taken 13 times.
|
13 |
user_app_name = user_app_name.substr(0, idx); |
| 490 |
|
|
|
| 491 |
1/1
✓ Branch 23 → 24 taken 13 times.
|
13 |
auto tmp_substr = app_name.substr(idx); |
| 492 |
1/1
✓ Branch 24 → 25 taken 13 times.
|
13 |
auto instance_num = static_cast<size_t>(std::stoull(tmp_substr)); |
| 493 |
1/1
✓ Branch 25 → 26 taken 13 times.
|
13 |
AppFactoryBase* factory = getAppFactory_(user_app_name, instance_num); |
| 494 |
|
|
|
| 495 |
|
|
// TODO cnyce: We should consider automatically prepending "<app name>$" |
| 496 |
|
|
// before every table in the app schema. With a growing number of apps, |
| 497 |
|
|
// and SimDB living in open source, this will eventually trip someone |
| 498 |
|
|
// up from e.g. using a generic table like "SimMetadata" which collides. |
| 499 |
|
|
// You will have to document that the app name might have restrictions |
| 500 |
|
|
// that will match whatever restrictions SQLite puts on table names. |
| 501 |
1/1
✓ Branch 26 → 27 taken 13 times.
|
13 |
Schema app_schema; |
| 502 |
1/1
✓ Branch 27 → 28 taken 13 times.
|
13 |
factory->defineSchema(app_schema); |
| 503 |
1/1
✓ Branch 28 → 29 taken 13 times.
|
13 |
db_mgr_->appendSchema(app_schema); |
| 504 |
|
13 |
} |
| 505 |
|
9 |
}); |
| 506 |
|
9 |
} |
| 507 |
|
|
|
| 508 |
|
|
/// Call this after command line args and config files are parsed. |
| 509 |
|
6 |
void postInit_(int argc, char** argv) |
| 510 |
|
|
{ |
| 511 |
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 6 → 7 taken 6 times.
|
6 |
PROFILE_APP_PHASE |
| 512 |
|
|
|
| 513 |
2/2
✓ Branch 10 → 11 taken 6 times.
✓ Branch 11 → 12 taken 6 times.
|
6 |
db_mgr_->safeTransaction([&]() { |
| 514 |
3/3
✓ Branch 2 → 3 taken 6 times.
✓ Branch 9 → 5 taken 6 times.
✓ Branch 9 → 10 taken 6 times.
|
12 |
for (auto app : getAppsInHookOrder_()) |
| 515 |
|
|
{ |
| 516 |
1/1
✓ Branch 6 → 7 taken 6 times.
|
6 |
app->postInit(argc, argv); |
| 517 |
|
6 |
} |
| 518 |
|
6 |
}); |
| 519 |
|
6 |
} |
| 520 |
|
|
|
| 521 |
|
|
/// Call this once after postInit(). This will create all pipelines |
| 522 |
|
|
/// for all enabled apps, but it will not open the threads yet. |
| 523 |
|
9 |
void initializePipelines_() |
| 524 |
|
|
{ |
| 525 |
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 6 → 7 taken 9 times.
|
9 |
PROFILE_APP_PHASE |
| 526 |
|
|
|
| 527 |
1/12
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 29 taken 9 times.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 27 → 28 not taken.
|
9 |
simdb_assert(!pipeline_mgr_, "Pipelines already open"); |
| 528 |
|
|
|
| 529 |
1/1
✓ Branch 29 → 30 taken 9 times.
|
9 |
pipeline_mgr_ = std::make_unique<pipeline::PipelineManager>(db_mgr_); |
| 530 |
2/2
✓ Branch 42 → 34 taken 13 times.
✓ Branch 42 → 43 taken 9 times.
|
22 |
for (const auto& [app_name, app] : apps_) |
| 531 |
|
|
{ |
| 532 |
1/1
✓ Branch 39 → 40 taken 13 times.
|
13 |
app->createPipeline(pipeline_mgr_.get()); |
| 533 |
|
|
} |
| 534 |
|
|
|
| 535 |
|
|
// Print final pipeline configurations. |
| 536 |
3/3
✓ Branch 43 → 44 taken 9 times.
✓ Branch 45 → 46 taken 9 times.
✓ Branch 46 → 47 taken 9 times.
|
9 |
std::cout << "\nSimDB app pipeline configuration for database '" << db_mgr_->getDatabaseFilePath() << "':\n"; |
| 537 |
3/3
✓ Branch 48 → 49 taken 9 times.
✓ Branch 72 → 51 taken 13 times.
✓ Branch 72 → 73 taken 9 times.
|
22 |
for (auto pipeline : pipeline_mgr_->getPipelines()) |
| 538 |
|
|
{ |
| 539 |
4/4
✓ Branch 52 → 53 taken 13 times.
✓ Branch 53 → 54 taken 13 times.
✓ Branch 54 → 55 taken 13 times.
✓ Branch 55 → 56 taken 13 times.
|
13 |
std::cout << "---- Pipeline: " << pipeline->getName() << "\n"; |
| 540 |
3/3
✓ Branch 57 → 58 taken 13 times.
✓ Branch 68 → 60 taken 32 times.
✓ Branch 68 → 69 taken 13 times.
|
45 |
for (auto& [stage_name, stage] : pipeline->getOrderedStages()) |
| 541 |
|
|
{ |
| 542 |
3/3
✓ Branch 63 → 64 taken 32 times.
✓ Branch 64 → 65 taken 32 times.
✓ Branch 65 → 66 taken 32 times.
|
32 |
std::cout << "------ Stage: " << stage_name << "\n"; |
| 543 |
|
13 |
} |
| 544 |
|
9 |
} |
| 545 |
|
|
|
| 546 |
1/1
✓ Branch 74 → 75 taken 9 times.
|
9 |
std::cout << std::endl; |
| 547 |
|
9 |
} |
| 548 |
|
|
|
| 549 |
|
|
/// Call this once after initializePipelines() (and after minimizeThreads() |
| 550 |
|
|
/// if you called that too). |
| 551 |
|
9 |
void openPipelines_() |
| 552 |
|
|
{ |
| 553 |
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 6 → 7 taken 9 times.
|
9 |
PROFILE_APP_PHASE |
| 554 |
|
|
|
| 555 |
1/12
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 29 taken 9 times.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 27 → 28 not taken.
|
9 |
simdb_assert(pipeline_mgr_, "Pipeline manager not set - did you call initializePipelines()?"); |
| 556 |
1/1
✓ Branch 30 → 31 taken 9 times.
|
9 |
pipeline_mgr_->openPipelines(); |
| 557 |
|
9 |
} |
| 558 |
|
|
|
| 559 |
|
|
/// This method is to be called after the main simulation loop ends. |
| 560 |
|
|
/// All running apps' pipelines will be flushed, and all threads |
| 561 |
|
|
/// will be torn down. |
| 562 |
|
9 |
void postSimLoopTeardown_() |
| 563 |
|
|
{ |
| 564 |
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 6 → 7 taken 9 times.
|
9 |
PROFILE_APP_PHASE |
| 565 |
|
|
|
| 566 |
3/3
✓ Branch 9 → 10 taken 9 times.
✓ Branch 16 → 12 taken 13 times.
✓ Branch 16 → 17 taken 9 times.
|
22 |
for (auto app : getAppsInHookOrder_()) |
| 567 |
|
|
{ |
| 568 |
1/1
✓ Branch 13 → 14 taken 13 times.
|
13 |
app->preTeardown(); |
| 569 |
|
9 |
} |
| 570 |
|
|
|
| 571 |
1/2
✓ Branch 19 → 20 taken 9 times.
✗ Branch 19 → 22 not taken.
|
9 |
if (pipeline_mgr_) |
| 572 |
|
|
{ |
| 573 |
1/1
✓ Branch 21 → 22 taken 9 times.
|
9 |
pipeline_mgr_->postSimLoopTeardown(); |
| 574 |
|
|
} |
| 575 |
|
|
|
| 576 |
1/1
✓ Branch 24 → 25 taken 9 times.
|
9 |
db_mgr_->safeTransaction([&]() { |
| 577 |
3/3
✓ Branch 2 → 3 taken 9 times.
✓ Branch 9 → 5 taken 13 times.
✓ Branch 9 → 10 taken 9 times.
|
22 |
for (auto app : getAppsInHookOrder_()) |
| 578 |
|
|
{ |
| 579 |
1/1
✓ Branch 6 → 7 taken 13 times.
|
13 |
app->postTeardown(); |
| 580 |
|
9 |
} |
| 581 |
|
|
|
| 582 |
|
|
// TODO cnyce: We should associate the DatabaseManager and |
| 583 |
|
|
// the TinyStrings so that it gets flushed automatically. |
| 584 |
|
|
// This will let us document that postSimLoopTeardown() |
| 585 |
|
|
// is the only thing you have to call in the event of |
| 586 |
|
|
// an exception/abort/terminate during simulation. |
| 587 |
|
9 |
}); |
| 588 |
|
9 |
} |
| 589 |
|
|
|
| 590 |
|
|
/// Delete all instantiated apps. This may be needed since AppManager |
| 591 |
|
|
/// is a singleton and your simulator might want to call app destructors |
| 592 |
|
|
/// before the AppManager itself is destroyed on program exit. |
| 593 |
|
10 |
void destroyAllApps_() |
| 594 |
|
|
{ |
| 595 |
|
10 |
pipeline_mgr_.reset(); |
| 596 |
|
10 |
apps_.clear(); |
| 597 |
|
10 |
} |
| 598 |
|
|
|
| 599 |
|
|
using app_factories_t = std::map<std::string, // App name |
| 600 |
|
|
std::map<size_t, // App instance |
| 601 |
|
|
std::shared_ptr<AppFactoryBase>>>; // Factory |
| 602 |
|
|
|
| 603 |
|
|
/// Get a map for all registered app factories. |
| 604 |
|
10 |
app_factories_t& getDefaultAppFactories_() { return default_app_factories_; } |
| 605 |
|
|
|
| 606 |
|
|
/// Get a map for all registered app factories. |
| 607 |
|
36 |
const app_factories_t& getDefaultAppFactories_() const { return default_app_factories_; } |
| 608 |
|
|
|
| 609 |
|
|
/// Factories for apps with default constructors. |
| 610 |
|
|
app_factories_t default_app_factories_; |
| 611 |
|
|
|
| 612 |
|
|
/// Factories for apps that have a nested AppFactory class. |
| 613 |
|
|
app_factories_t nested_app_factories_; |
| 614 |
|
|
|
| 615 |
|
|
/// Access an app factory. |
| 616 |
|
|
template <typename AppT> |
| 617 |
|
4 |
typename AppT::AppFactory* getNestedAppFactory_(size_t instance_num, bool create_if_needed = true) |
| 618 |
|
|
{ |
| 619 |
1/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 48 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 48 taken 4 times.
|
4 |
if (!create_if_needed) |
| 620 |
|
|
{ |
| 621 |
0/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
|
✗ |
auto it = nested_app_factories_.find(AppT::NAME); |
| 622 |
0/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
|
✗ |
if (it == nested_app_factories_.end()) |
| 623 |
|
|
{ |
| 624 |
|
✗ |
return nullptr; |
| 625 |
|
|
} |
| 626 |
|
|
|
| 627 |
0/2
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 14 → 15 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 14 → 15 not taken.
|
✗ |
auto it2 = it->second.find(instance_num); |
| 628 |
0/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 20 not taken.
|
✗ |
if (it2 == it->second.end()) |
| 629 |
|
|
{ |
| 630 |
|
✗ |
return nullptr; |
| 631 |
|
|
} |
| 632 |
|
|
|
| 633 |
0/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
|
✗ |
auto factory = dynamic_cast<typename AppT::AppFactory*>(it2->second.get()); |
| 634 |
0/28
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 46 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 44 → 45 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 46 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 44 → 45 not taken.
|
✗ |
simdb_assert(factory, "Failed to downcast app factory for '" << AppT::NAME << "'."); |
| 635 |
|
|
|
| 636 |
|
✗ |
return factory; |
| 637 |
|
|
} |
| 638 |
|
|
|
| 639 |
3/6
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 50 → 51 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 52 → 53 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✓ Branch 50 → 51 taken 4 times.
✓ Branch 51 → 52 taken 4 times.
✓ Branch 52 → 53 taken 4 times.
|
8 |
auto& factory = nested_app_factories_[AppT::NAME][instance_num]; |
| 640 |
1/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 61 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✓ Branch 56 → 57 taken 4 times.
✗ Branch 56 → 61 not taken.
|
4 |
if (!factory) |
| 641 |
|
|
{ |
| 642 |
1/2
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 57 → 58 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✓ Branch 57 → 58 taken 4 times.
|
4 |
factory = std::make_shared<typename AppT::AppFactory>(); |
| 643 |
|
|
} |
| 644 |
|
|
|
| 645 |
1/4
UnregisteredAppWithFactory::AppFactory* simdb::AppManager::getNestedAppFactory_<UnregisteredAppWithFactory>(unsigned long, bool):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 64 not taken.
MyApp::AppFactory* simdb::AppManager::getNestedAppFactory_<MyApp>(unsigned long, bool):
✓ Branch 62 → 63 taken 4 times.
✗ Branch 62 → 64 not taken.
|
4 |
return dynamic_cast<typename AppT::AppFactory*>(factory.get()); |
| 646 |
|
|
} |
| 647 |
|
|
|
| 648 |
|
36 |
AppFactoryBase* getAppFactory_(const std::string& app_name, size_t instance_num, bool must_exist = true) const |
| 649 |
|
|
{ |
| 650 |
1/1
✓ Branch 2 → 3 taken 36 times.
|
36 |
auto app_factories = getAllAppFactories_(); |
| 651 |
|
|
|
| 652 |
1/1
✓ Branch 3 → 4 taken 36 times.
|
36 |
auto it = app_factories.find(app_name); |
| 653 |
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 28 taken 36 times.
|
36 |
if (it == app_factories.end()) |
| 654 |
|
|
{ |
| 655 |
0/13
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 27 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 25 → 26 not taken.
|
✗ |
simdb_assert(!must_exist, "No factory exists for app: " << app_name); |
| 656 |
|
✗ |
return nullptr; |
| 657 |
|
|
} |
| 658 |
|
|
|
| 659 |
1/1
✓ Branch 29 → 30 taken 36 times.
|
36 |
auto it2 = it->second.find(instance_num); |
| 660 |
2/2
✓ Branch 33 → 34 taken 6 times.
✓ Branch 33 → 60 taken 30 times.
|
36 |
if (it2 == it->second.end()) |
| 661 |
|
|
{ |
| 662 |
|
|
// If we looked for a specific app instance factory (non-zero) |
| 663 |
|
|
// and could not find it, look for a "global" factory with |
| 664 |
|
|
// instance_num 0 for this app. |
| 665 |
1/2
✓ Branch 34 → 35 taken 6 times.
✗ Branch 34 → 37 not taken.
|
6 |
if (instance_num > 0) |
| 666 |
|
|
{ |
| 667 |
|
6 |
constexpr size_t global_instance_num = 0; |
| 668 |
1/1
✓ Branch 35 → 36 taken 6 times.
|
6 |
return getAppFactory_(app_name, global_instance_num, must_exist); |
| 669 |
|
|
} |
| 670 |
|
|
|
| 671 |
0/15
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 59 not taken.
✗ Branch 40 → 41 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 49 → 50 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 55 → 56 not taken.
✗ Branch 57 → 58 not taken.
|
✗ |
simdb_assert(!must_exist, "No factory exists for instance " << instance_num << " for app: " << app_name); |
| 672 |
|
✗ |
return nullptr; |
| 673 |
|
|
} |
| 674 |
|
|
|
| 675 |
|
30 |
return it2->second.get(); |
| 676 |
|
36 |
} |
| 677 |
|
|
|
| 678 |
|
|
/// Return a union of the global and local app factories. |
| 679 |
|
36 |
app_factories_t getAllAppFactories_() const |
| 680 |
|
|
{ |
| 681 |
1/1
✓ Branch 3 → 4 taken 36 times.
|
36 |
auto default_app_factories = getDefaultAppFactories_(); |
| 682 |
1/1
✓ Branch 4 → 5 taken 36 times.
|
72 |
return combineFactories_(default_app_factories, nested_app_factories_); |
| 683 |
|
36 |
} |
| 684 |
|
|
|
| 685 |
|
|
/// Merge two app_factories_t together, verifying that they |
| 686 |
|
|
/// have no overlap. |
| 687 |
|
36 |
app_factories_t combineFactories_(const app_factories_t& global, const app_factories_t& local) const |
| 688 |
|
|
{ |
| 689 |
|
36 |
app_factories_t result = global; |
| 690 |
|
|
|
| 691 |
2/2
✓ Branch 34 → 5 taken 4 times.
✓ Branch 34 → 35 taken 36 times.
|
40 |
for (const auto& [app_name, local_instances] : local) |
| 692 |
|
|
{ |
| 693 |
1/1
✓ Branch 8 → 9 taken 4 times.
|
4 |
auto& result_instances = result[app_name]; |
| 694 |
|
|
|
| 695 |
2/2
✓ Branch 31 → 11 taken 6 times.
✓ Branch 31 → 32 taken 4 times.
|
10 |
for (const auto& [instance_id, factory] : local_instances) |
| 696 |
|
|
{ |
| 697 |
1/1
✓ Branch 14 → 15 taken 6 times.
|
6 |
const auto [it, inserted] = result_instances.emplace(instance_id, factory); |
| 698 |
|
|
|
| 699 |
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 29 taken 6 times.
|
6 |
if (!inserted) |
| 700 |
|
|
{ |
| 701 |
0/2
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
|
✗ |
throw std::logic_error("Duplicate AppFactory entry for app '" + app_name + "', instance " + |
| 702 |
0/3
✗ Branch 19 → 20 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
|
✗ |
std::to_string(instance_id)); |
| 703 |
|
|
} |
| 704 |
|
|
} |
| 705 |
|
|
} |
| 706 |
|
|
|
| 707 |
|
36 |
return result; |
| 708 |
|
✗ |
} |
| 709 |
|
|
|
| 710 |
|
|
/// Instantiated apps (implicitly enabled). |
| 711 |
|
|
/// Key is the App's NAME static member, or NAME-<instance> |
| 712 |
|
|
/// for apps with multiple instances (one-based). |
| 713 |
|
|
std::map<std::string, std::unique_ptr<App>> apps_; |
| 714 |
|
|
|
| 715 |
|
|
/// Optional order for lifecycle hooks (postInit, preTeardown, postTeardown). |
| 716 |
|
|
/// Empty means use default (map) order. |
| 717 |
|
|
std::vector<std::string> hook_ordering_; |
| 718 |
|
|
|
| 719 |
|
|
/// Enabled apps (may or may not be instantiated). |
| 720 |
|
|
/// Key is the App's NAME static member. |
| 721 |
|
|
/// Value is the number of instances to create. |
| 722 |
|
35 |
std::map<std::string, size_t>& getEnabledApps_() { return enabled_apps_; } |
| 723 |
|
|
|
| 724 |
|
|
/// Enabled apps (may or may not be instantiated). |
| 725 |
|
|
/// Key is the App's NAME static member. |
| 726 |
|
|
/// Value is the number of instances to create. |
| 727 |
|
29 |
const std::map<std::string, size_t>& getEnabledApps_() const { return enabled_apps_; } |
| 728 |
|
|
|
| 729 |
|
|
/// Enabled apps and their app instance count. |
| 730 |
|
|
std::map<std::string, size_t> enabled_apps_; |
| 731 |
|
|
|
| 732 |
|
|
/// Associated database. |
| 733 |
|
|
DatabaseManager* db_mgr_ = nullptr; |
| 734 |
|
|
|
| 735 |
|
|
/// All pipelines and threads are managed by PipelineManager. |
| 736 |
|
|
std::unique_ptr<pipeline::PipelineManager> pipeline_mgr_; |
| 737 |
|
|
|
| 738 |
|
|
/// App logger (thread-safe). Owned by AppManagers. |
| 739 |
|
|
ThreadSafeLogger* app_logger_ = nullptr; |
| 740 |
|
|
|
| 741 |
|
|
/// Verbose flag. |
| 742 |
|
|
bool verbose_ = false; |
| 743 |
|
|
|
| 744 |
|
|
/// RAII timer to measure the performance of various app setup/teardown |
| 745 |
|
|
/// phases. |
| 746 |
|
|
class ScopedTimer |
| 747 |
|
|
{ |
| 748 |
|
|
public: |
| 749 |
|
42 |
ScopedTimer(const DatabaseManager* db_mgr, const std::string& block_name) : |
| 750 |
|
42 |
start_(std::chrono::high_resolution_clock::now()), |
| 751 |
|
42 |
block_name_(block_name) |
| 752 |
|
|
{ |
| 753 |
1/1
✓ Branch 5 → 6 taken 42 times.
|
42 |
auto db_filepath = db_mgr->getDatabaseFilePath(); |
| 754 |
5/5
✓ Branch 6 → 7 taken 42 times.
✓ Branch 7 → 8 taken 42 times.
✓ Branch 8 → 9 taken 42 times.
✓ Branch 9 → 10 taken 42 times.
✓ Branch 10 → 11 taken 42 times.
|
42 |
std::cout << "SimDB: Entering " << block_name << " for database: " << db_filepath << "\n"; |
| 755 |
|
42 |
} |
| 756 |
|
|
|
| 757 |
|
42 |
~ScopedTimer() |
| 758 |
|
|
{ |
| 759 |
|
42 |
[[maybe_unused]] ios_format_saver fmt_saver(std::cout); |
| 760 |
|
|
|
| 761 |
|
42 |
auto end = std::chrono::high_resolution_clock::now(); |
| 762 |
|
42 |
std::chrono::duration<double> dur = end - start_; |
| 763 |
|
42 |
auto us = std::chrono::duration_cast<std::chrono::microseconds>(dur).count(); |
| 764 |
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 17 taken 42 times.
|
42 |
if (us >= 1000000) |
| 765 |
|
|
{ |
| 766 |
|
✗ |
auto sec = (double)us / 1000000; |
| 767 |
|
✗ |
std::cout << "SimDB: Completed " << block_name_ << " in "; |
| 768 |
|
✗ |
std::cout << std::fixed << std::setprecision(2) << sec << " seconds.\n"; |
| 769 |
2/2
✓ Branch 17 → 18 taken 21 times.
✓ Branch 17 → 26 taken 21 times.
|
42 |
} else if (us >= 1000) |
| 770 |
|
|
{ |
| 771 |
|
21 |
auto milli = (double)us / 1000; |
| 772 |
|
21 |
std::cout << "SimDB: Completed " << block_name_ << " in "; |
| 773 |
|
21 |
std::cout << std::fixed << std::setprecision(0) << milli << " milliseconds.\n"; |
| 774 |
|
|
} else |
| 775 |
|
|
{ |
| 776 |
|
21 |
auto micro = (double)us; |
| 777 |
|
21 |
std::cout << "SimDB: Completed " << block_name_ << " in "; |
| 778 |
|
21 |
std::cout << std::fixed << std::setprecision(0) << micro << " microseconds.\n"; |
| 779 |
|
|
} |
| 780 |
|
42 |
} |
| 781 |
|
|
|
| 782 |
|
|
private: |
| 783 |
|
|
std::chrono::high_resolution_clock::time_point start_; |
| 784 |
|
|
std::string block_name_; |
| 785 |
|
|
}; |
| 786 |
|
|
}; |
| 787 |
|
|
|
| 788 |
|
13 |
template <typename AppT> void AppRegistration<AppT>::registerApp(AppManager* app_manager) const |
| 789 |
|
|
{ |
| 790 |
|
13 |
app_manager->registerApp_<AppT>(); |
| 791 |
|
13 |
} |
| 792 |
|
|
|
| 793 |
|
|
/*! |
| 794 |
|
|
* \class AppManagers |
| 795 |
|
|
* |
| 796 |
|
|
* \brief Singleton-like holder for all DatabaseManagers and AppManagers. Call |
| 797 |
|
|
* registerApp<AppT>() for each app type before createAppManager(); then |
| 798 |
|
|
* createAppManager(db_file), createEnabledApps(), createSchemas(), |
| 799 |
|
|
* postInit(), initializePipelines(), openPipelines(). Use getAppManager() |
| 800 |
|
|
* or getDatabaseManager() to access managers. Obtain from |
| 801 |
|
|
* AppManagers::getInstance() or AppRegistrations::getInstance(). |
| 802 |
|
|
*/ |
| 803 |
|
|
class AppManagers |
| 804 |
|
|
{ |
| 805 |
|
|
public: |
| 806 |
|
|
/// \brief Register an app type; must be called before createAppManager() |
| 807 |
|
|
/// \note You need to call this method for all apps you might end up |
| 808 |
|
|
/// creating **before** calling createAppManager(). As soon as |
| 809 |
|
|
/// createAppManager() is called the first time, you can no |
| 810 |
|
|
/// longer call registerApp(). |
| 811 |
|
11 |
template <typename AppT> void registerApp() |
| 812 |
|
|
{ |
| 813 |
6/78
void simdb::AppManagers::registerApp<SimplePipeline>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 2 times.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
void simdb::AppManagers::registerApp<PipelineSnooper>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 1 time.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
void simdb::AppManagers::registerApp<WatchedPipeline>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 1 time.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
void simdb::AppManagers::registerApp<DatabaseWatchdog>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 1 time.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
void simdb::AppManagers::registerApp<MyApp>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 1 time.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
void simdb::AppManagers::registerApp<simdb::argos::ArgosCollector>():
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 22 taken 5 times.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
|
11 |
simdb_assert(!app_registration_locked_, |
| 814 |
|
|
"No more apps can be registered since createAppManager() " << "has already been called."); |
| 815 |
12/24
void simdb::AppManagers::registerApp<SimplePipeline>():
✓ Branch 22 → 23 taken 2 times.
✓ Branch 24 → 25 taken 2 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void simdb::AppManagers::registerApp<PipelineSnooper>():
✓ Branch 22 → 23 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void simdb::AppManagers::registerApp<WatchedPipeline>():
✓ Branch 22 → 23 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void simdb::AppManagers::registerApp<DatabaseWatchdog>():
✓ Branch 22 → 23 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void simdb::AppManagers::registerApp<MyApp>():
✓ Branch 22 → 23 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void simdb::AppManagers::registerApp<simdb::argos::ArgosCollector>():
✓ Branch 22 → 23 taken 5 times.
✓ Branch 24 → 25 taken 5 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
11 |
app_registrations_.emplace_back(new AppRegistration<AppT>()); |
| 816 |
|
11 |
} |
| 817 |
|
|
|
| 818 |
|
|
/// If you want all apps to share a global thread-safe logger, call this |
| 819 |
|
|
/// method before createAppManager(). |
| 820 |
|
|
/// |
| 821 |
|
|
/// Every line written to the logger will start with the given prefix. |
| 822 |
|
|
void useThreadSafeLogger(const std::string& prefix = "[simdb-log]") |
| 823 |
|
|
{ |
| 824 |
|
|
simdb_assert(accepting_logger_requests_, "No longer accepting thread-safe logger requests"); |
| 825 |
|
|
app_logger_ = std::make_unique<ThreadSafeLogger>(prefix); |
| 826 |
|
|
} |
| 827 |
|
|
|
| 828 |
|
|
/// If you want all apps to share a global thread-safe file logger, |
| 829 |
|
|
/// call this method before createAppManager(). |
| 830 |
|
|
/// |
| 831 |
|
|
/// Every line written to the logger will start with the given prefix. |
| 832 |
|
|
void useThreadSafeFileLogger(const std::string& filename) |
| 833 |
|
|
{ |
| 834 |
|
|
simdb_assert(accepting_logger_requests_, "No longer accepting thread-safe logger requests"); |
| 835 |
|
|
app_logger_ = std::make_unique<ThreadSafeFileLogger>(filename); |
| 836 |
|
|
} |
| 837 |
|
|
|
| 838 |
|
|
/// Enable verbose mode for all apps in all AppManager's. |
| 839 |
|
1 |
void setVerbose(bool verbose = true) |
| 840 |
|
|
{ |
| 841 |
|
1 |
verbose_ = verbose; |
| 842 |
1/2
✗ Branch 10 → 4 not taken.
✓ Branch 10 → 11 taken 1 time.
|
1 |
for (auto& [app_mgr, _] : db_mgrs_by_app_mgr_) |
| 843 |
|
|
{ |
| 844 |
0/1
✗ Branch 7 → 8 not taken.
|
✗ |
app_mgr->setVerbose(verbose_); |
| 845 |
|
|
} |
| 846 |
|
1 |
} |
| 847 |
|
|
|
| 848 |
|
|
/// Create a new AppManager with a new database. |
| 849 |
|
|
/// |
| 850 |
|
|
/// Pass in new_db=true to overwrite existing database, or new_db=false to use |
| 851 |
|
|
/// the existing database on disk. If new_db=false and the db_file does not |
| 852 |
|
|
/// exist, throws an exception. |
| 853 |
|
|
/// |
| 854 |
|
|
/// Throws if an AppManager for this database already exists. |
| 855 |
|
12 |
AppManager& createAppManager(const std::string& db_file, bool new_db = true) |
| 856 |
|
|
{ |
| 857 |
|
12 |
accepting_logger_requests_ = false; |
| 858 |
|
|
|
| 859 |
2/14
✓ Branch 3 → 4 taken 12 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 25 taken 12 times.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 23 → 24 not taken.
|
12 |
simdb_assert(app_mgrs_by_db_file_.find(db_file) == app_mgrs_by_db_file_.end(), |
| 860 |
|
|
"AppManager already exists for database: " << db_file); |
| 861 |
|
|
|
| 862 |
3/23
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 30 taken 12 times.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 12 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 53 taken 12 times.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 49 → 50 not taken.
✗ Branch 51 → 52 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
|
12 |
simdb_assert(new_db || std::filesystem::exists(db_file), |
| 863 |
|
|
"Cannot reuse database since it doesn't exist: " << db_file); |
| 864 |
|
|
|
| 865 |
3/5
✓ Branch 53 → 54 taken 12 times.
✓ Branch 55 → 56 taken 12 times.
✓ Branch 56 → 57 taken 12 times.
✗ Branch 129 → 130 not taken.
✗ Branch 129 → 131 not taken.
|
12 |
std::shared_ptr<DatabaseManager> db_mgr(new DatabaseManager(db_file, new_db)); |
| 866 |
2/4
✓ Branch 58 → 59 taken 12 times.
✓ Branch 62 → 63 taken 12 times.
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 134 not taken.
|
12 |
std::shared_ptr<AppManager> app_mgr(new AppManager(db_mgr.get(), app_logger_.get())); |
| 867 |
|
|
|
| 868 |
1/1
✓ Branch 64 → 65 taken 12 times.
|
12 |
app_mgr->setVerbose(verbose_); |
| 869 |
|
|
|
| 870 |
1/1
✓ Branch 65 → 66 taken 12 times.
|
12 |
db_mgrs_by_db_file_[db_file] = db_mgr; |
| 871 |
1/1
✓ Branch 67 → 68 taken 12 times.
|
12 |
app_mgrs_by_db_file_[db_file] = app_mgr; |
| 872 |
|
|
|
| 873 |
1/1
✓ Branch 70 → 71 taken 12 times.
|
12 |
app_mgrs_by_db_mgr_[db_mgr.get()] = app_mgr; |
| 874 |
1/1
✓ Branch 73 → 74 taken 12 times.
|
12 |
db_mgrs_by_app_mgr_[app_mgr.get()] = db_mgr; |
| 875 |
|
|
|
| 876 |
2/2
✓ Branch 83 → 77 taken 13 times.
✓ Branch 83 → 84 taken 12 times.
|
25 |
for (const auto& app_reg : app_registrations_) |
| 877 |
|
|
{ |
| 878 |
1/1
✓ Branch 80 → 81 taken 13 times.
|
13 |
app_reg->registerApp(app_mgr.get()); |
| 879 |
|
|
} |
| 880 |
|
12 |
app_registration_locked_ = true; |
| 881 |
1/1
✓ Branch 84 → 85 taken 12 times.
|
24 |
return *app_mgrs_by_db_file_[db_file]; |
| 882 |
|
12 |
} |
| 883 |
|
|
|
| 884 |
|
|
/// Get an existing AppManager with a database filename / filepath. |
| 885 |
|
|
/// Throws if createAppManager() was never called with this database. |
| 886 |
|
1 |
AppManager& getAppManager(const std::string& db_file) |
| 887 |
|
|
{ |
| 888 |
13/14
✓ Branch 3 → 4 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 25 not taken.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
|
3 |
simdb_assert(app_mgrs_by_db_file_.find(db_file) != app_mgrs_by_db_file_.end(), |
| 889 |
|
|
"AppManager does not exist for this database: " << db_file); |
| 890 |
|
✗ |
return *app_mgrs_by_db_file_[db_file]; |
| 891 |
|
|
} |
| 892 |
|
|
|
| 893 |
|
|
/// If there is only one AppManager, return it. Otherwise throw. |
| 894 |
|
2 |
AppManager& getAppManager() |
| 895 |
|
|
{ |
| 896 |
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 1 time.
|
2 |
if (app_mgrs_by_db_file_.size() == 1) |
| 897 |
|
|
{ |
| 898 |
|
1 |
return *app_mgrs_by_db_file_.begin()->second; |
| 899 |
|
|
} |
| 900 |
|
|
|
| 901 |
1/1
✓ Branch 10 → 11 taken 1 time.
|
1 |
throw DBException("Cannot call getAppManager() since there are ") |
| 902 |
3/3
✓ Branch 12 → 13 taken 1 time.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
|
2 |
<< app_mgrs_by_db_file_.size() << " AppManager's. Must be only one."; |
| 903 |
|
|
} |
| 904 |
|
|
|
| 905 |
|
|
/// If there is only one AppManager, return its DatabaseManager. Otherwise |
| 906 |
|
|
/// throw. |
| 907 |
|
5 |
DatabaseManager& getDatabaseManager() |
| 908 |
|
|
{ |
| 909 |
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 8 taken 1 time.
|
5 |
if (db_mgrs_by_db_file_.size() == 1) |
| 910 |
|
|
{ |
| 911 |
|
4 |
return *db_mgrs_by_db_file_.begin()->second; |
| 912 |
|
|
} |
| 913 |
|
|
|
| 914 |
1/1
✓ Branch 10 → 11 taken 1 time.
|
1 |
throw DBException("Cannot call getDatabaseManager() since there are ") |
| 915 |
3/3
✓ Branch 12 → 13 taken 1 time.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
|
2 |
<< db_mgrs_by_db_file_.size() << " AppManager's. Must be only one."; |
| 916 |
|
|
} |
| 917 |
|
|
|
| 918 |
|
|
/// Get a DatabaseManager for the given DB file. Throws if not found. |
| 919 |
|
1 |
DatabaseManager& getDatabaseManager(const std::string& db_file) |
| 920 |
|
|
{ |
| 921 |
1/1
✓ Branch 2 → 3 taken 1 time.
|
1 |
auto it = db_mgrs_by_db_file_.find(db_file); |
| 922 |
1/14
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 26 taken 1 time.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 24 → 25 not taken.
|
1 |
simdb_assert(it != db_mgrs_by_db_file_.end(), "DatabaseManager does not exist for file '" << db_file << "'."); |
| 923 |
|
2 |
return *it->second; |
| 924 |
|
|
} |
| 925 |
|
|
|
| 926 |
|
|
/// Get a mapping from all active AppManager's and their associated |
| 927 |
|
|
/// DatabaseManager's. |
| 928 |
|
46 |
std::vector<std::pair<AppManager*, DatabaseManager*>> getAllManagers() |
| 929 |
|
|
{ |
| 930 |
|
46 |
std::vector<std::pair<AppManager*, DatabaseManager*>> mgrs; |
| 931 |
2/2
✓ Branch 21 → 5 taken 47 times.
✓ Branch 21 → 22 taken 46 times.
|
93 |
for (auto& [db_file, db_mgr] : db_mgrs_by_db_file_) |
| 932 |
|
|
{ |
| 933 |
1/1
✓ Branch 8 → 9 taken 47 times.
|
47 |
auto it = app_mgrs_by_db_file_.find(db_file); |
| 934 |
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 13 taken 46 times.
|
47 |
if (it == app_mgrs_by_db_file_.end()) |
| 935 |
|
|
{ |
| 936 |
|
1 |
continue; |
| 937 |
|
|
} |
| 938 |
|
|
|
| 939 |
|
46 |
auto& app_mgr = it->second; |
| 940 |
2/2
✓ Branch 16 → 17 taken 46 times.
✓ Branch 17 → 18 taken 46 times.
|
46 |
mgrs.push_back(std::make_pair(app_mgr.get(), db_mgr.get())); |
| 941 |
|
|
} |
| 942 |
|
46 |
return mgrs; |
| 943 |
|
✗ |
} |
| 944 |
|
|
|
| 945 |
|
|
/// Call after command line args and config files are parsed. |
| 946 |
|
11 |
void createEnabledApps() |
| 947 |
|
|
{ |
| 948 |
3/3
✓ Branch 2 → 3 taken 11 times.
✓ Branch 11 → 5 taken 12 times.
✓ Branch 11 → 12 taken 11 times.
|
23 |
for (auto& [app_mgr, _] : getAllManagers()) |
| 949 |
|
|
{ |
| 950 |
1/1
✓ Branch 8 → 9 taken 12 times.
|
12 |
app_mgr->createEnabledApps_(); |
| 951 |
|
11 |
} |
| 952 |
|
11 |
} |
| 953 |
|
|
|
| 954 |
|
|
/// Create app-specific schemas for the instantiated apps. |
| 955 |
|
9 |
void createSchemas() |
| 956 |
|
|
{ |
| 957 |
3/3
✓ Branch 2 → 3 taken 9 times.
✓ Branch 11 → 5 taken 9 times.
✓ Branch 11 → 12 taken 9 times.
|
18 |
for (auto& [app_mgr, _] : getAllManagers()) |
| 958 |
|
|
{ |
| 959 |
1/1
✓ Branch 8 → 9 taken 9 times.
|
9 |
app_mgr->createSchemas_(); |
| 960 |
|
9 |
} |
| 961 |
|
9 |
} |
| 962 |
|
|
|
| 963 |
|
|
/// Call this after command line args and config files are parsed. |
| 964 |
|
6 |
void postInit(int argc, char** argv) |
| 965 |
|
|
{ |
| 966 |
3/3
✓ Branch 2 → 3 taken 6 times.
✓ Branch 11 → 5 taken 6 times.
✓ Branch 11 → 12 taken 6 times.
|
12 |
for (auto& [app_mgr, _] : getAllManagers()) |
| 967 |
|
|
{ |
| 968 |
1/1
✓ Branch 8 → 9 taken 6 times.
|
6 |
app_mgr->postInit_(argc, argv); |
| 969 |
|
6 |
} |
| 970 |
|
6 |
} |
| 971 |
|
|
|
| 972 |
|
|
/// Call this once after postInit(). This will create all pipelines |
| 973 |
|
|
/// for all enabled apps, but it will not open the threads yet. |
| 974 |
|
9 |
void initializePipelines() |
| 975 |
|
|
{ |
| 976 |
3/3
✓ Branch 2 → 3 taken 9 times.
✓ Branch 11 → 5 taken 9 times.
✓ Branch 11 → 12 taken 9 times.
|
18 |
for (auto& [app_mgr, _] : getAllManagers()) |
| 977 |
|
|
{ |
| 978 |
1/1
✓ Branch 8 → 9 taken 9 times.
|
9 |
app_mgr->initializePipelines_(); |
| 979 |
|
9 |
} |
| 980 |
|
9 |
} |
| 981 |
|
|
|
| 982 |
|
|
/// Call this once after initializePipelines() (and after minimizeThreads() |
| 983 |
|
|
/// if you called that too). |
| 984 |
|
9 |
void openPipelines() |
| 985 |
|
|
{ |
| 986 |
3/3
✓ Branch 2 → 3 taken 9 times.
✓ Branch 11 → 5 taken 9 times.
✓ Branch 11 → 12 taken 9 times.
|
18 |
for (auto& [app_mgr, _] : getAllManagers()) |
| 987 |
|
|
{ |
| 988 |
1/1
✓ Branch 8 → 9 taken 9 times.
|
9 |
app_mgr->openPipelines_(); |
| 989 |
|
9 |
} |
| 990 |
|
9 |
} |
| 991 |
|
|
|
| 992 |
|
|
/// Call postSimLoopTeardown() on all AppManager's. This destroys all Apps |
| 993 |
|
|
/// and AppManager's. It does NOT destroy the DatabaseManager's. Once this |
| 994 |
|
|
/// method is called, you have to access the DatabaseManager's using the |
| 995 |
|
|
/// 'getDatabaseManager(db_file)' API. |
| 996 |
|
9 |
void postSimLoopTeardown() |
| 997 |
|
|
{ |
| 998 |
2/2
✓ Branch 11 → 4 taken 9 times.
✓ Branch 11 → 12 taken 9 times.
|
18 |
for (auto& [_, app_mgr] : app_mgrs_by_db_file_) |
| 999 |
|
|
{ |
| 1000 |
1/1
✓ Branch 8 → 9 taken 9 times.
|
9 |
app_mgr->postSimLoopTeardown_(); |
| 1001 |
|
|
} |
| 1002 |
|
|
|
| 1003 |
|
9 |
destroy_(false); |
| 1004 |
|
9 |
} |
| 1005 |
|
|
|
| 1006 |
|
|
/// Destroy every AppManager and DatabaseManager we have. |
| 1007 |
|
1 |
void destroyAll() { destroy_(true); } |
| 1008 |
|
|
|
| 1009 |
|
|
private: |
| 1010 |
|
10 |
void destroy_(bool destroy_all) |
| 1011 |
|
|
{ |
| 1012 |
|
|
/// Destroy all AppManagers, DatabaseManagers, and Apps |
| 1013 |
2/2
✓ Branch 11 → 4 taken 10 times.
✓ Branch 11 → 12 taken 10 times.
|
20 |
for (auto& [_, app_mgr] : app_mgrs_by_db_file_) |
| 1014 |
|
|
{ |
| 1015 |
|
10 |
app_mgr->destroyAllApps_(); |
| 1016 |
|
|
} |
| 1017 |
|
|
|
| 1018 |
|
|
// Destroy AppManager's first in case they need to touch |
| 1019 |
|
|
// the database in their destructors. |
| 1020 |
|
10 |
app_mgrs_by_db_mgr_.clear(); |
| 1021 |
|
10 |
app_mgrs_by_db_file_.clear(); |
| 1022 |
|
|
|
| 1023 |
|
|
// Clear DatabaseManager maps. Hang onto db_mgrs_by_db_file_ |
| 1024 |
|
|
// so 'getDatabaseManager(db_file)' is still available. |
| 1025 |
|
10 |
db_mgrs_by_app_mgr_.clear(); |
| 1026 |
|
|
|
| 1027 |
|
|
// Destroy DatabaseManagers |
| 1028 |
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 9 times.
|
10 |
if (destroy_all) |
| 1029 |
|
|
{ |
| 1030 |
|
1 |
db_mgrs_by_db_file_.clear(); |
| 1031 |
|
|
} |
| 1032 |
|
10 |
} |
| 1033 |
|
|
|
| 1034 |
|
|
std::vector<std::unique_ptr<AppRegistrationBase>> app_registrations_; |
| 1035 |
|
|
bool app_registration_locked_ = false; |
| 1036 |
|
|
|
| 1037 |
|
|
std::map<std::string, std::shared_ptr<DatabaseManager>> db_mgrs_by_db_file_; |
| 1038 |
|
|
std::map<std::string, std::shared_ptr<AppManager>> app_mgrs_by_db_file_; |
| 1039 |
|
|
std::map<DatabaseManager*, std::shared_ptr<AppManager>> app_mgrs_by_db_mgr_; |
| 1040 |
|
|
std::map<AppManager*, std::shared_ptr<DatabaseManager>> db_mgrs_by_app_mgr_; |
| 1041 |
|
|
|
| 1042 |
|
|
std::unique_ptr<ThreadSafeLogger> app_logger_; |
| 1043 |
|
|
bool accepting_logger_requests_ = true; |
| 1044 |
|
|
bool verbose_ = false; |
| 1045 |
|
|
}; |
| 1046 |
|
|
|
| 1047 |
|
|
/*! |
| 1048 |
|
|
* \class AppRegistrations |
| 1049 |
|
|
* |
| 1050 |
|
|
* \brief Thin wrapper that exposes only registerApp<AppT>() on an AppManagers |
| 1051 |
|
|
* instance. Use when you want to restrict API surface to registration only. |
| 1052 |
|
|
*/ |
| 1053 |
|
|
class AppRegistrations |
| 1054 |
|
|
{ |
| 1055 |
|
|
public: |
| 1056 |
|
|
/// \brief Construct with the AppManagers instance to wrap. |
| 1057 |
|
|
explicit AppRegistrations(AppManagers* app_managers) : |
| 1058 |
|
|
app_managers_(app_managers) |
| 1059 |
|
|
{ |
| 1060 |
|
|
} |
| 1061 |
|
|
|
| 1062 |
|
|
/// \brief Register an app type (forwards to AppManagers::registerApp<AppT>()). |
| 1063 |
|
|
template <typename AppT> void registerApp() { app_managers_->registerApp<AppT>(); } |
| 1064 |
|
|
|
| 1065 |
|
|
private: |
| 1066 |
|
|
AppManagers* app_managers_ = nullptr; |
| 1067 |
|
|
}; |
| 1068 |
|
|
|
| 1069 |
|
|
} // namespace simdb |
| 1070 |
|
|
|