A Discrete-Event Network Simulator
API
sqlite-output.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2018 Natale Patriciello <natale.patriciello@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  */
19 #include "sqlite-output.h"
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include "ns3/abort.h"
23 #include "ns3/unused.h"
24 #include "ns3/log.h"
25 #include "ns3/nstime.h"
26 
27 namespace ns3 {
28 
29 NS_LOG_COMPONENT_DEFINE ("SQLiteOutput");
30 
31 SQLiteOutput::SQLiteOutput (const std::string &name, const std::string &semName)
32  : m_semName (semName)
33 {
34  int rc = sqlite3_open (name.c_str (), &m_db);
35  NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to open DB");
36 }
37 
39 {
40  int rc = SQLITE_FAIL;
41 
42  rc = sqlite3_close_v2 (m_db);
43  NS_ABORT_MSG_UNLESS (rc == SQLITE_OK, "Failed to close DB");
44 }
45 
46 void
48 {
49  NS_LOG_FUNCTION (this);
50  SpinExec ("PRAGMA journal_mode = MEMORY");
51 }
52 
53 bool
54 SQLiteOutput::SpinExec (const std::string &cmd) const
55 {
56  return (SpinExec (m_db, cmd) == SQLITE_OK);
57 }
58 
59 bool
60 SQLiteOutput::SpinExec (sqlite3_stmt *stmt) const
61 {
62  int rc = SpinExec (m_db, stmt);
63  return !CheckError (m_db, rc, "", nullptr, false);
64 }
65 
66 bool
67 SQLiteOutput::WaitExec (const std::string &cmd) const
68 {
69  int rc = WaitExec (m_db, cmd);
70  return !CheckError (m_db, rc, cmd, nullptr, false);
71 }
72 
73 bool
74 SQLiteOutput::WaitExec (sqlite3_stmt *stmt) const
75 {
76  return (WaitExec (m_db, stmt) == SQLITE_OK);
77 }
78 
79 bool
80 SQLiteOutput::WaitPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
81 {
82  return (WaitPrepare (m_db, stmt, cmd) == SQLITE_OK);
83 }
84 
85 bool
86 SQLiteOutput::SpinPrepare (sqlite3_stmt **stmt, const std::string &cmd) const
87 {
88  return (SpinPrepare (m_db, stmt, cmd) == SQLITE_OK);
89 }
90 
91 template<typename T>
92 T
93 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
94 {
95  NS_UNUSED (stmt);
96  NS_UNUSED (pos);
97  NS_FATAL_ERROR ("Can't call generic fn");
98 }
99 
100 template<>
101 int
102 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
103 {
104  return sqlite3_column_int (stmt, pos);
105 }
106 
107 template<>
108 uint32_t
109 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
110 {
111  return static_cast<uint32_t> (sqlite3_column_int (stmt, pos));
112 }
113 
114 template<>
115 double
116 SQLiteOutput::RetrieveColumn (sqlite3_stmt *stmt, int pos) const
117 {
118  return sqlite3_column_double (stmt, pos);
119 }
120 
121 template<typename T>
122 bool
123 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const T &value) const
124 {
125  NS_UNUSED (stmt);
126  NS_UNUSED (pos);
127  NS_UNUSED (value);
128  NS_FATAL_ERROR ("Can't call generic fn");
129  return false;
130 }
131 
132 template<>
133 bool
134 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const Time &value) const
135 {
136  if (sqlite3_bind_double (stmt, pos, value.GetSeconds ()) == SQLITE_OK)
137  {
138  return true;
139  }
140  return false;
141 }
142 
143 template<>
144 bool
145 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const double &value) const
146 {
147  if (sqlite3_bind_double (stmt, pos, value) == SQLITE_OK)
148  {
149  return true;
150  }
151  return false;
152 }
153 
154 template<>
155 bool
156 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint32_t &value) const
157 {
158  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
159  {
160  return true;
161  }
162  return false;
163 }
164 
165 template<>
166 bool
167 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long &value) const
168 {
169  if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
170  {
171  return true;
172  }
173  return false;
174 }
175 
176 template<>
177 bool
178 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const long long &value) const
179 {
180  if (sqlite3_bind_int64 (stmt, pos, value) == SQLITE_OK)
181  {
182  return true;
183  }
184  return false;
185 }
186 
187 template<>
188 bool
189 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint16_t &value) const
190 {
191  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
192  {
193  return true;
194  }
195  return false;
196 }
197 
198 template<>
199 bool
200 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const uint8_t &value) const
201 {
202  if (sqlite3_bind_int (stmt, pos, static_cast<int> (value)) == SQLITE_OK)
203  {
204  return true;
205  }
206  return false;
207 }
208 
209 template<>
210 bool
211 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const int &value) const
212 {
213  if (sqlite3_bind_int (stmt, pos, value) == SQLITE_OK)
214  {
215  return true;
216  }
217  return false;
218 }
219 
220 template<>
221 bool
222 SQLiteOutput::Bind (sqlite3_stmt *stmt, int pos, const std::string &value) const
223 {
224  if (sqlite3_bind_text (stmt, pos, value.c_str (), -1, SQLITE_STATIC) == SQLITE_OK)
225  {
226  return true;
227  }
228  return false;
229 }
230 
231 int
232 SQLiteOutput::WaitPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd) const
233 {
234  int rc;
235  bool ret;
236  sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
237 
238  NS_ABORT_MSG_IF (sem == SEM_FAILED,
239  "FAILED to open system semaphore, errno: " << errno);
240 
241  if (sem_wait (sem) == 0)
242  {
243  rc = sqlite3_prepare_v2 (db, cmd.c_str (),
244  static_cast<int> (cmd.size ()),
245  stmt, nullptr);
246 
247  ret = CheckError (db, rc, cmd, sem, false);
248  if (ret)
249  {
250  return rc;
251  }
252 
253  sem_post (sem);
254  }
255  else
256  {
257  NS_FATAL_ERROR ("Can't lock semaphore");
258  }
259 
260  sem_close (sem);
261  sem = nullptr;
262 
263  return rc;
264 }
265 
266 int
267 SQLiteOutput::SpinPrepare (sqlite3 *db, sqlite3_stmt **stmt, const std::string &cmd)
268 {
269  int rc;
270 
271  do
272  {
273  rc = sqlite3_prepare_v2 (db, cmd.c_str (),
274  static_cast<int> (cmd.size ()),
275  stmt, nullptr);
276  }
277  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
278  return rc;
279 }
280 
281 int
282 SQLiteOutput::SpinStep (sqlite3_stmt *stmt)
283 {
284  int rc;
285  do
286  {
287  rc = sqlite3_step (stmt);
288  }
289  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
290 
291  return rc;
292 }
293 
294 int
295 SQLiteOutput::SpinFinalize (sqlite3_stmt *stmt)
296 {
297  int rc;
298  do
299  {
300  rc = sqlite3_finalize (stmt);
301  }
302  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
303 
304  return rc;
305 }
306 
307 int SQLiteOutput::SpinReset (sqlite3_stmt *stmt)
308 {
309  int rc;
310 
311  do
312  {
313  rc = sqlite3_reset (stmt);
314  }
315  while (rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
316 
317  return rc;
318 }
319 
320 void
321 SQLiteOutput::Error (sqlite3 *db, const std::string &cmd)
322 {
323  NS_ABORT_MSG (cmd << " error " << sqlite3_errmsg (db));
324 }
325 
326 bool
327 SQLiteOutput::CheckError (sqlite3 *db, int rc, const std::string &cmd,
328  sem_t *sem, bool hardExit)
329 {
330  if (rc != SQLITE_OK && rc != SQLITE_DONE)
331  {
332  if (sem != nullptr)
333  {
334  sem_post (sem);
335  sem_close (sem);
336  }
337  if (hardExit)
338  {
339  Error (db, cmd);
340  }
341  else
342  {
343  std::cerr << sqlite3_errmsg (db) << std::endl;
344  }
345  return true;
346  }
347  return false;
348 }
349 
350 int
351 SQLiteOutput::SpinExec (sqlite3 *db, const std::string &cmd)
352 {
353  sqlite3_stmt *stmt;
354  bool ret;
355 
356  int rc = SpinPrepare (db, &stmt, cmd);
357  ret = CheckError (db, rc, cmd, nullptr, false);
358  if (ret)
359  {
360  return rc;
361  }
362 
363  rc = SpinStep (stmt);
364  ret = CheckError (db, rc, cmd, nullptr, false);
365  if (ret)
366  {
367  return rc;
368  }
369 
370  rc = SpinFinalize (stmt);
371  CheckError (db, rc, cmd, nullptr, false);
372 
373  return rc;
374 }
375 
376 int
377 SQLiteOutput::SpinExec (sqlite3 *db, sqlite3_stmt *stmt)
378 {
379  bool ret;
380  int rc = SpinStep (stmt);
381  ret = CheckError (db, rc, "", nullptr, false);
382  if (ret)
383  {
384  return rc;
385  }
386 
387  rc = SpinFinalize (stmt);
388  return rc;
389 }
390 
391 int
392 SQLiteOutput::WaitExec (sqlite3 *db, sqlite3_stmt *stmt) const
393 {
394  bool ret;
395  int rc = SQLITE_ERROR;
396 
397  sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
398 
399  NS_ABORT_MSG_IF (sem == SEM_FAILED,
400  "FAILED to open system semaphore, errno: " << errno);
401 
402  if (sem_wait (sem) == 0)
403  {
404  rc = SpinStep (stmt);
405 
406  ret = CheckError (db, rc, "", sem, false);
407  if (ret)
408  {
409  return rc;
410  }
411 
412  rc = SpinFinalize (stmt);
413 
414  sem_post (sem);
415  }
416  else
417  {
418  NS_FATAL_ERROR ("Can't lock system semaphore");
419  }
420 
421  sem_close (sem);
422 
423  return rc;
424 }
425 
426 int
427 SQLiteOutput::WaitExec (sqlite3 *db, const std::string &cmd) const
428 {
429  sqlite3_stmt *stmt;
430  bool ret;
431  int rc = SQLITE_ERROR;
432 
433  sem_t *sem = sem_open (m_semName.c_str (), O_CREAT, S_IRUSR | S_IWUSR, 1);
434 
435  NS_ABORT_MSG_IF (sem == SEM_FAILED,
436  "FAILED to open system semaphore, errno: " << errno);
437 
438  if (sem_wait (sem) == 0)
439  {
440  rc = SpinPrepare (db, &stmt, cmd);
441  ret = CheckError (db, rc, cmd, sem, false);
442  if (ret)
443  {
444  return rc;
445  }
446 
447  rc = SpinStep (stmt);
448 
449  ret = CheckError (db, rc, cmd, sem, false);
450  if (ret)
451  {
452  return rc;
453  }
454 
455  rc = SpinFinalize (stmt);
456 
457  sem_post (sem);
458  }
459 
460  sem_close (sem);
461 
462  return rc;
463 }
464 
465 } // namespace ns3;
static bool CheckError(sqlite3 *db, int rc, const std::string &cmd, sem_t *sem, bool hardExit)
Check any error in the db.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:50
static void Error(sqlite3 *db, const std::string &cmd)
Fail, printing an error message from sqlite.
SQLiteOutput(const std::string &name, const std::string &semName)
SQLiteOutput constructor.
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:379
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
bool SpinExec(const std::string &cmd) const
Execute a command until the return value is OK or an ERROR.
#define NS_UNUSED(x)
Mark a local variable as unused.
Definition: unused.h:36
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
cmd
Definition: second.py:35
void SetJournalInMemory()
Instruct SQLite to store the journal in memory.
static int SpinStep(sqlite3_stmt *stmt)
Execute a step operation on a statement until the result is ok or an error.
std::string m_semName
System semaphore name.
static int SpinFinalize(sqlite3_stmt *stmt)
Finalize a statement until the result is ok or an error.
bool WaitPrepare(sqlite3_stmt **stmt, const std::string &cmd) const
Prepare a statement, waiting on a system semaphore.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool SpinPrepare(sqlite3_stmt **stmt, const std::string &cmd) const
Prepare a statement.
T RetrieveColumn(sqlite3_stmt *stmt, int pos) const
Retrieve a value from an executed statement.
~SQLiteOutput()
Destructor.
bool Bind(sqlite3_stmt *stmt, int pos, const T &value) const
Bind a value to a sqlite statement.
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
static int SpinReset(sqlite3_stmt *stmt)
Reset a statement until the result is ok or an error.
sqlite3 * m_db
Database pointer.
bool WaitExec(const std::string &cmd) const
Execute a command, waiting on a system semaphore.