IceStormDB.cpp
Go to the documentation of this file.
1// **********************************************************************
2//
3// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
4//
5// This copy of Ice is licensed to you under the terms described in the
6// ICE_LICENSE file included in this distribution.
7//
8// **********************************************************************
9
10#include <fstream>
11
12#include <Ice/ConsoleUtil.h>
13#include <Ice/Ice.h>
14#include <IceDB/IceDB.h>
15#include <IceStorm/DBTypes.h>
16#include <IceUtil/DisableWarnings.h>
17#include <IceUtil/FileUtil.h>
18#include <IceUtil/Options.h>
19
20using namespace std;
21using namespace Ice;
22using namespace IceInternal;
23using namespace IceStorm;
24using namespace IceStormElection;
25
26class Client : public Ice::Application
27{
28public:
29 void usage();
30 virtual int run(int, char*[]);
31};
32
33#ifdef _WIN32
34
35int
36wmain(int argc, wchar_t* argv[])
37
38#else
39
40int
41main(int argc, char* argv[])
42
43#endif
44{
45 Client app;
46 return app.main(argc, argv);
47}
48
49void
51{
52 consoleErr << "Usage: " << appName() << " <options>\n";
53 consoleErr << "Options:\n"
54 "-h, --help Show this message.\n"
55 "-v, --version Display version.\n"
56 "--import FILE Import database from FILE.\n"
57 "--export FILE Export database to FILE.\n"
58 "--dbhome DIR Source or target database environment.\n"
59 "--dbpath DIR Source or target database environment.\n"
60 "--mapsize VALUE Set LMDB map size in MB (optional, import only).\n"
61 "-d, --debug Print debug messages.\n";
62}
63
64int
65Client::run(int argc, char* argv[])
66{
67 IceUtilInternal::Options opts;
68 opts.addOpt("h", "help");
69 opts.addOpt("v", "version");
70 opts.addOpt("d", "debug");
71 opts.addOpt("", "import", IceUtilInternal::Options::NeedArg);
72 opts.addOpt("", "export", IceUtilInternal::Options::NeedArg);
73 opts.addOpt("", "dbhome", IceUtilInternal::Options::NeedArg);
74 opts.addOpt("", "dbpath", IceUtilInternal::Options::NeedArg);
75 opts.addOpt("", "mapsize", IceUtilInternal::Options::NeedArg);
76
77 vector<string> args;
78 try
79 {
80 args = opts.parse(argc, const_cast<const char**>(argv));
81 }
82 catch (const IceUtilInternal::BadOptException& e)
83 {
84 consoleErr << argv[0] << ": " << e.reason << endl;
85 usage();
86 return EXIT_FAILURE;
87 }
88 if (!args.empty())
89 {
90 consoleErr << argv[0] << ": too many arguments" << endl;
91 usage();
92 return EXIT_FAILURE;
93 }
94
95 if (opts.isSet("help"))
96 {
97 usage();
98 return EXIT_SUCCESS;
99 }
100
101 if (opts.isSet("version"))
102 {
103 consoleOut << ICE_STRING_VERSION << endl;
104 return EXIT_SUCCESS;
105 }
106
107 if (!(opts.isSet("import") ^ opts.isSet("export")))
108 {
109 consoleErr << argv[0] << ": either --import or --export must be set" << endl;
110 usage();
111 return EXIT_FAILURE;
112 }
113
114 if (!(opts.isSet("dbhome") ^ opts.isSet("dbpath")))
115 {
116 consoleErr << argv[0]
117 << ": set the database environment directory with either --dbhome or --dbpath"
118 << endl;
119 usage();
120 return EXIT_FAILURE;
121 }
122
123 bool debug = opts.isSet("debug");
124 bool import = opts.isSet("import");
125 string dbFile = opts.optArg(import ? "import" : "export");
126 string dbPath;
127 if (opts.isSet("dbhome"))
128 {
129 dbPath = opts.optArg("dbhome");
130 }
131 else
132 {
133 dbPath = opts.optArg("dbpath");
134 }
135
136 string mapSizeStr = opts.optArg("mapsize");
137 size_t mapSize = IceDB::getMapSize(atoi(mapSizeStr.c_str()));
138
139 try
140 {
141 IceStorm::AllData data;
142
143 IceDB::IceContext dbContext;
144 dbContext.communicator = communicator();
145 dbContext.encoding.major = 1;
146 dbContext.encoding.minor = 1;
147
148 if (import)
149 {
150 consoleOut << "Importing database to directory " << dbPath << " from file " << dbFile
151 << endl;
152
153 if (!IceUtilInternal::directoryExists(dbPath))
154 {
155 consoleErr << argv[0] << ": output directory does not exist: " << dbPath << endl;
156 return EXIT_FAILURE;
157 }
158
159 if (!IceUtilInternal::isEmptyDirectory(dbPath))
160 {
161 consoleErr << argv[0] << ": output directory is not empty: " << dbPath << endl;
162 return EXIT_FAILURE;
163 }
164
165 ifstream fs(IceUtilInternal::streamFilename(dbFile).c_str(), ios::binary);
166 if (fs.fail())
167 {
168 consoleErr << argv[0] << ": could not open input file: " << strerror(errno) << endl;
169 return EXIT_FAILURE;
170 }
171 fs.unsetf(ios::skipws);
172
173 fs.seekg(0, ios::end);
174 streampos fileSize = fs.tellg();
175
176 if (!fileSize)
177 {
178 fs.close();
179 consoleErr << argv[0] << ": empty input file" << endl;
180 return EXIT_FAILURE;
181 }
182
183 fs.seekg(0, ios::beg);
184
185 vector<Ice::Byte> buf;
186 buf.reserve(static_cast<size_t>(fileSize));
187 buf.insert(buf.begin(), istream_iterator<Ice::Byte>(fs), istream_iterator<Ice::Byte>());
188
189 fs.close();
190
191 string type;
192 int version;
193
194 Ice::InputStream stream(communicator(), dbContext.encoding, buf);
195 stream.read(type);
196 if (type != "IceStorm")
197 {
198 consoleErr << argv[0] << ": incorrect input file type: " << type << endl;
199 return EXIT_FAILURE;
200 }
201 stream.read(version);
202 stream.read(data);
203
204 {
205 IceDB::Env env(dbPath, 2, mapSize);
206 IceDB::ReadWriteTxn txn(env);
207
208 if (debug)
209 {
210 consoleOut << "Writing LLU Map:" << endl;
211 }
212
213 IceDB::Dbi<string, LogUpdate, IceDB::IceContext, Ice::OutputStream> lluMap(
214 txn, "llu", dbContext, MDB_CREATE);
215
216 for (StringLogUpdateDict::const_iterator p = data.llus.begin();
217 p != data.llus.end();
218 ++p)
219 {
220 if (debug)
221 {
222 consoleOut << " KEY = " << p->first << endl;
223 }
224 lluMap.put(txn, p->first, p->second);
225 }
226
227 if (debug)
228 {
229 consoleOut << "Writing Subscriber Map:" << endl;
230 }
231
232 IceDB::
233 Dbi<SubscriberRecordKey, SubscriberRecord, IceDB::IceContext, Ice::OutputStream>
234 subscriberMap(txn, "subscribers", dbContext, MDB_CREATE);
235
236 for (SubscriberRecordDict::const_iterator q = data.subscribers.begin();
237 q != data.subscribers.end();
238 ++q)
239 {
240 if (debug)
241 {
242 consoleOut << " KEY = TOPIC("
243 << communicator()->identityToString(q->first.topic) << ") ID("
244 << communicator()->identityToString(q->first.id) << ")" << endl;
245 }
246 subscriberMap.put(txn, q->first, q->second);
247 }
248
249 txn.commit();
250 env.close();
251 }
252 }
253 else
254 {
255 consoleOut << "Exporting database from directory " << dbPath << " to file " << dbFile
256 << endl;
257
258 {
259 IceDB::Env env(dbPath, 2);
260 IceDB::ReadOnlyTxn txn(env);
261
262 if (debug)
263 {
264 consoleOut << "Reading LLU Map:" << endl;
265 }
266
267 IceDB::Dbi<string, LogUpdate, IceDB::IceContext, Ice::OutputStream> lluMap(
268 txn, "llu", dbContext, 0);
269
270 string s;
271 LogUpdate llu;
272 IceDB::ReadOnlyCursor<string, LogUpdate, IceDB::IceContext, Ice::OutputStream>
273 lluCursor(lluMap, txn);
274 while (lluCursor.get(s, llu, MDB_NEXT))
275 {
276 if (debug)
277 {
278 consoleOut << " KEY = " << s << endl;
279 }
280 data.llus.insert(std::make_pair(s, llu));
281 }
282 lluCursor.close();
283
284 if (debug)
285 {
286 consoleOut << "Reading Subscriber Map:" << endl;
287 }
288
289 IceDB::
290 Dbi<SubscriberRecordKey, SubscriberRecord, IceDB::IceContext, Ice::OutputStream>
291 subscriberMap(txn, "subscribers", dbContext, 0);
292
293 SubscriberRecordKey key;
294 SubscriberRecord record;
295 IceDB::ReadOnlyCursor<SubscriberRecordKey,
296 SubscriberRecord,
297 IceDB::IceContext,
298 Ice::OutputStream>
299 subCursor(subscriberMap, txn);
300 while (subCursor.get(key, record, MDB_NEXT))
301 {
302 if (debug)
303 {
304 consoleOut << " KEY = TOPIC("
305 << communicator()->identityToString(key.topic) << ") ID("
306 << communicator()->identityToString(key.id) << ")" << endl;
307 }
308 data.subscribers.insert(std::make_pair(key, record));
309 }
310 subCursor.close();
311
312 txn.rollback();
313 env.close();
314 }
315
316 Ice::OutputStream stream(communicator(), dbContext.encoding);
317 stream.write("IceStorm");
318 stream.write(ICE_INT_VERSION);
319 stream.write(data);
320
321 ofstream fs(IceUtilInternal::streamFilename(dbFile).c_str(), ios::binary);
322 if (fs.fail())
323 {
324 consoleErr << argv[0] << ": could not open output file: " << strerror(errno)
325 << endl;
326 return EXIT_FAILURE;
327 }
328 fs.write(reinterpret_cast<const char*>(stream.b.begin()), stream.b.size());
329 fs.close();
330 }
331 }
332 catch (const IceUtil::Exception& ex)
333 {
334 consoleErr << argv[0] << ": " << (import ? "import" : "export") << " failed:\n"
335 << ex << endl;
336 return EXIT_FAILURE;
337 }
338
339 return EXIT_SUCCESS;
340}
uint8_t data[1]
void usage()
virtual int run(int, char *[])
Definition Admin.cpp:69
virtual int run(int, char *[])
#define q
ICE_DB_API size_t getMapSize(int)
This file is part of ArmarX.
IceDB::IceContext dbContext
Definition Util.cpp:19
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
Ice::CommunicatorPtr communicator
Definition IceDB.h:489
Ice::EncodingVersion encoding
Definition IceDB.h:490