1 #include "storage/serialization.hpp"
2 #include "storage/shared_memory.hpp"
3 #include "storage/shared_monitor.hpp"
4 #include "storage/storage.hpp"
5
6 #include "osrm/exception.hpp"
7 #include "util/log.hpp"
8 #include "util/meminfo.hpp"
9 #include "util/typedefs.hpp"
10 #include "util/version.hpp"
11
12 #include <boost/filesystem.hpp>
13 #include <boost/program_options.hpp>
14
15 #include <csignal>
16 #include <cstdlib>
17
18 using namespace osrm;
19
removeLocks()20 void removeLocks() { storage::SharedMonitor<storage::SharedRegionRegister>::remove(); }
21
deleteRegion(const storage::SharedRegionRegister::ShmKey key)22 void deleteRegion(const storage::SharedRegionRegister::ShmKey key)
23 {
24 if (storage::SharedMemory::RegionExists(key) && !storage::SharedMemory::Remove(key))
25 {
26 util::Log(logWARNING) << "could not delete shared memory region " << static_cast<int>(key);
27 }
28 }
29
listRegions(bool show_blocks)30 void listRegions(bool show_blocks)
31 {
32 osrm::util::Log() << "name\tshm key\ttimestamp\tsize";
33 if (!storage::SharedMonitor<storage::SharedRegionRegister>::exists())
34 {
35 return;
36 }
37 storage::SharedMonitor<storage::SharedRegionRegister> monitor;
38 std::vector<std::string> names;
39 const auto &shared_register = monitor.data();
40 shared_register.List(std::back_inserter(names));
41 for (const auto &name : names)
42 {
43 auto id = shared_register.Find(name);
44 auto region = shared_register.GetRegion(id);
45 auto shm = osrm::storage::makeSharedMemory(region.shm_key);
46 osrm::util::Log() << name << "\t" << static_cast<int>(region.shm_key) << "\t"
47 << region.timestamp << "\t" << shm->Size();
48
49 if (show_blocks)
50 {
51 using namespace storage;
52 auto memory = makeSharedMemory(region.shm_key);
53 io::BufferReader reader(reinterpret_cast<char *>(memory->Ptr()), memory->Size());
54
55 std::unique_ptr<BaseDataLayout> layout = std::make_unique<ContiguousDataLayout>();
56 serialization::read(reader, *layout);
57
58 std::vector<std::string> block_names;
59 layout->List("", std::back_inserter(block_names));
60 for (auto &name : block_names)
61 {
62 osrm::util::Log() << " " << name << " " << layout->GetBlockSize(name);
63 }
64 }
65 }
66 }
67
springClean()68 void springClean()
69 {
70 osrm::util::Log() << "Releasing all locks";
71 osrm::util::Log() << "ATTENTION! BE CAREFUL!";
72 osrm::util::Log() << "----------------------";
73 osrm::util::Log() << "This tool may put osrm-routed into an undefined state!";
74 osrm::util::Log() << "Type 'Y' to acknowledge that you know what your are doing.";
75 osrm::util::Log() << "\n\nDo you want to purge all shared memory allocated "
76 << "by osrm-datastore? [type 'Y' to confirm]";
77
78 const auto letter = getchar();
79 if (letter != 'Y')
80 {
81 osrm::util::Log() << "aborted.";
82 }
83 else
84 {
85 for (auto key : util::irange<storage::SharedRegionRegister::RegionID>(
86 0, storage::SharedRegionRegister::MAX_SHM_KEYS))
87 {
88 deleteRegion(key);
89 }
90 removeLocks();
91 }
92 }
93
94 // generate boost::program_options object for the routing part
generateDataStoreOptions(const int argc,const char * argv[],std::string & verbosity,boost::filesystem::path & base_path,int & max_wait,std::string & dataset_name,bool & list_datasets,bool & list_blocks,bool & only_metric)95 bool generateDataStoreOptions(const int argc,
96 const char *argv[],
97 std::string &verbosity,
98 boost::filesystem::path &base_path,
99 int &max_wait,
100 std::string &dataset_name,
101 bool &list_datasets,
102 bool &list_blocks,
103 bool &only_metric)
104 {
105 // declare a group of options that will be allowed only on command line
106 boost::program_options::options_description generic_options("Options");
107 generic_options.add_options() //
108 ("version,v", "Show version") //
109 ("help,h", "Show this help message") //
110 ("verbosity,l",
111 boost::program_options::value<std::string>(&verbosity)->default_value("INFO"),
112 std::string("Log verbosity level: " + util::LogPolicy::GetLevels()).c_str()) //
113 ("remove-locks,r", "Remove locks") //
114 ("spring-clean,s", "Spring-cleaning all shared memory regions");
115
116 // declare a group of options that will be allowed both on command line
117 // as well as in a config file
118 boost::program_options::options_description config_options("Configuration");
119 config_options.add_options() //
120 ("max-wait",
121 boost::program_options::value<int>(&max_wait)->default_value(-1),
122 "Maximum number of seconds to wait on a running data update "
123 "before aquiring the lock by force.") //
124 ("dataset-name",
125 boost::program_options::value<std::string>(&dataset_name)->default_value(""),
126 "Name of the dataset to load into memory. This allows having multiple datasets in memory "
127 "at the same time.") //
128 ("list",
129 boost::program_options::value<bool>(&list_datasets)
130 ->default_value(false)
131 ->implicit_value(true),
132 "List all OSRM datasets currently in memory") //
133 ("list-blocks",
134 boost::program_options::value<bool>(&list_blocks)
135 ->default_value(false)
136 ->implicit_value(true),
137 "List all OSRM datasets currently in memory")(
138 "only-metric",
139 boost::program_options::value<bool>(&only_metric)
140 ->default_value(false)
141 ->implicit_value(true),
142 "Only reload the metric data without updating the full dataset. This is an "
143 "optimization "
144 "for traffic updates.");
145
146 // hidden options, will be allowed on command line but will not be shown to the user
147 boost::program_options::options_description hidden_options("Hidden options");
148 hidden_options.add_options()("base,b",
149 boost::program_options::value<boost::filesystem::path>(&base_path),
150 "base path to .osrm file");
151
152 // positional option
153 boost::program_options::positional_options_description positional_options;
154 positional_options.add("base", 1);
155
156 // combine above options for parsing
157 boost::program_options::options_description cmdline_options;
158 cmdline_options.add(generic_options).add(config_options).add(hidden_options);
159
160 const auto *executable = argv[0];
161 boost::program_options::options_description visible_options(
162 boost::filesystem::path(executable).filename().string() + " [<options>] <configuration>");
163 visible_options.add(generic_options).add(config_options);
164
165 // print help options if no infile is specified
166 if (argc < 2)
167 {
168 util::Log() << visible_options;
169 return false;
170 }
171
172 // parse command line options
173 boost::program_options::variables_map option_variables;
174
175 try
176 {
177 boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
178 .options(cmdline_options)
179 .positional(positional_options)
180 .run(),
181 option_variables);
182 }
183 catch (const boost::program_options::error &e)
184 {
185 util::Log(logERROR) << e.what();
186 return false;
187 }
188
189 if (option_variables.count("version"))
190 {
191 util::Log() << OSRM_VERSION;
192 return false;
193 }
194
195 if (option_variables.count("help"))
196 {
197 util::Log() << visible_options;
198 return false;
199 }
200
201 if (option_variables.count("remove-locks"))
202 {
203 removeLocks();
204 return false;
205 }
206
207 if (option_variables.count("spring-clean"))
208 {
209 springClean();
210 return false;
211 }
212
213 boost::program_options::notify(option_variables);
214
215 return true;
216 }
217
CleanupSharedBarriers(int signum)218 [[noreturn]] void CleanupSharedBarriers(int signum)
219 { // Here the lock state of named mutexes is unknown, make a hard cleanup
220 removeLocks();
221 std::_Exit(128 + signum);
222 }
223
main(const int argc,const char * argv[])224 int main(const int argc, const char *argv[])
225 try
226 {
227 int signals[] = {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE};
228 for (auto sig : signals)
229 {
230 std::signal(sig, CleanupSharedBarriers);
231 }
232
233 util::LogPolicy::GetInstance().Unmute();
234
235 std::string verbosity;
236 boost::filesystem::path base_path;
237 int max_wait = -1;
238 std::string dataset_name;
239 bool list_datasets = false;
240 bool list_blocks = false;
241 bool only_metric = false;
242 if (!generateDataStoreOptions(argc,
243 argv,
244 verbosity,
245 base_path,
246 max_wait,
247 dataset_name,
248 list_datasets,
249 list_blocks,
250 only_metric))
251 {
252 return EXIT_SUCCESS;
253 }
254
255 util::LogPolicy::GetInstance().SetLevel(verbosity);
256
257 if (list_datasets || list_blocks)
258 {
259 listRegions(list_blocks);
260 return EXIT_SUCCESS;
261 }
262
263 storage::StorageConfig config(base_path);
264 if (!config.IsValid())
265 {
266 util::Log(logERROR) << "Config contains invalid file paths. Exiting!";
267 return EXIT_FAILURE;
268 }
269 storage::Storage storage(std::move(config));
270
271 return storage.Run(max_wait, dataset_name, only_metric);
272 }
273 catch (const osrm::RuntimeError &e)
274 {
275 util::Log(logERROR) << e.what();
276 return e.GetCode();
277 }
278 catch (const std::bad_alloc &e)
279 {
280 util::DumpMemoryStats();
281 util::Log(logERROR) << "[exception] " << e.what();
282 util::Log(logERROR) << "Please provide more memory or disable locking the virtual "
283 "address space (note: this makes OSRM swap, i.e. slow)";
284 return EXIT_FAILURE;
285 }
286