IBR-DTN  1.0.0
SQLiteDatabase.cpp
Go to the documentation of this file.
1 /*
2  * SQLiteDatabase.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "storage/SQLiteDatabase.h"
26 #include <ibrdtn/utils/Clock.h>
27 #include <ibrcommon/Logger.h>
28 #include <stdint.h>
29 
30 namespace dtn
31 {
32  namespace storage
33  {
34  void sql_tracer(void*, const char * pQuery)
35  {
36  IBRCOMMON_LOGGER_DEBUG_TAG("SQLiteDatabase", 50) << "sqlite trace: " << pQuery << IBRCOMMON_LOGGER_ENDL;
37  }
38 
39  const std::string SQLiteDatabase::TAG = "SQLiteDatabase";
40 
41  const std::string SQLiteDatabase::_select_names[] = {
42  "source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, expiretime, fragmentoffset, appdatalength, hopcount, netpriority, payloadlength, bytes",
43  "source, timestamp, sequencenumber, fragmentoffset, payloadlength, bytes",
44  "`source`, `timestamp`, `sequencenumber`, `fragmentoffset`, `fragmentlength`, `expiretime`"
45  };
46 
47  const std::string SQLiteDatabase::_where_filter[] = {
48  "source = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ? AND fragmentlength = ?",
49  "a.source = b.source AND a.timestamp = b.timestamp AND a.sequencenumber = b.sequencenumber AND a.fragmentoffset = b.fragmentoffset AND a.fragmentlength = b.fragmentlength"
50  };
51 
52  const std::string SQLiteDatabase::_tables[] =
53  { "bundles", "blocks", "routing", "routing_bundles", "routing_nodes", "properties", "bundle_set", "bundle_set_names" };
54 
55  // this is the version of a fresh created db scheme
56  const int SQLiteDatabase::DBSCHEMA_FRESH_VERSION = 8;
57 
58  const int SQLiteDatabase::DBSCHEMA_VERSION = 8;
59 
60  const std::string SQLiteDatabase::QUERY_SCHEMAVERSION = "SELECT `value` FROM " + SQLiteDatabase::_tables[SQLiteDatabase::SQL_TABLE_PROPERTIES] + " WHERE `key` = 'version' LIMIT 0,1;";
61  const std::string SQLiteDatabase::SET_SCHEMAVERSION = "INSERT INTO " + SQLiteDatabase::_tables[SQLiteDatabase::SQL_TABLE_PROPERTIES] + " (`key`, `value`) VALUES ('version', ?);";
62 
63  const std::string SQLiteDatabase::_sql_queries[SQL_QUERIES_END] =
64  {
65  "SELECT " + _select_names[0] + " FROM " + _tables[SQL_TABLE_BUNDLE],
66  "SELECT " + _select_names[0] + " FROM " + _tables[SQL_TABLE_BUNDLE] + " ORDER BY priority DESC, timestamp, sequencenumber, fragmentoffset, fragmentlength LIMIT ?,?;",
67  "SELECT " + _select_names[0] + " FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE " + _where_filter[0] + " LIMIT 1;",
68  "SELECT bytes FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE " + _where_filter[0] + " LIMIT 1;",
69  "SELECT DISTINCT destination FROM " + _tables[SQL_TABLE_BUNDLE],
70 
71  //EXPIRE_*
72  "SELECT " + _select_names[1] + " FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE expiretime <= ?;",
73  "SELECT filename FROM "+ _tables[SQL_TABLE_BUNDLE] +" as a, "+ _tables[SQL_TABLE_BLOCK] +" as b WHERE " + _where_filter[1] + " AND a.expiretime <= ?;",
74  "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE expiretime <= ?;",
75  "SELECT expiretime FROM "+ _tables[SQL_TABLE_BUNDLE] +" ORDER BY expiretime ASC LIMIT 1;",
76 
77  "SELECT ROWID FROM "+ _tables[SQL_TABLE_BUNDLE] +" LIMIT 1;",
78  "SELECT COUNT(ROWID) FROM "+ _tables[SQL_TABLE_BUNDLE] +";",
79 
80  "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE " + _where_filter[0] + ";",
81  "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +";",
82  "INSERT INTO "+ _tables[SQL_TABLE_BUNDLE] +" (source, timestamp, sequencenumber, fragmentoffset, fragmentlength, destination, reportto, custodian, procflags, lifetime, appdatalength, expiretime, priority, hopcount, netpriority, payloadlength, bytes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
83  "UPDATE "+ _tables[SQL_TABLE_BUNDLE] +" SET custodian = ? WHERE " + _where_filter[0] + ";",
84 
85  "UPDATE "+ _tables[SQL_TABLE_BUNDLE] +" SET procflags = ? WHERE " + _where_filter[0] + ";",
86 
87  //BLOCK_*
88  "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE " + _where_filter[0] + " ORDER BY ordernumber ASC;",
89  "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE " + _where_filter[0] + " AND ordernumber = ?;",
90  "DELETE FROM "+ _tables[SQL_TABLE_BLOCK] +";",
91  "INSERT INTO "+ _tables[SQL_TABLE_BLOCK] +" (source, timestamp, sequencenumber, fragmentoffset, fragmentlength, blocktype, filename, ordernumber) VALUES (?,?,?,?,?,?,?,?);",
92 
93  //BUNDLE_SET_*
94  "INSERT INTO " + _tables[SQL_TABLE_BUNDLE_SET] + " (set_id, source, timestamp, sequencenumber, fragmentoffset, fragmentlength, expiretime) VALUES (?,?,?,?,?,?,?);",
95  "DELETE FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ?;",
96  "SELECT " + _select_names[2] + " FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ? AND " + _where_filter[0] + " LIMIT 1;",
97  "SELECT " + _select_names[2] + " FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ? AND expiretime <= ?;",
98  "DELETE FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ? AND expiretime <= ?;",
99  "SELECT " + _select_names[2] + " FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ?;",
100  "SELECT COUNT(*) FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ?;",
101  "SELECT expiretime FROM "+ _tables[SQL_TABLE_BUNDLE_SET] +" WHERE set_id = ? ORDER BY expiretime ASC LIMIT 1;",
102  "INSERT INTO " + _tables[SQL_TABLE_BUNDLE_SET] + " SELECT " + _select_names[2] + ", ? FROM " + _tables[SQL_TABLE_BUNDLE_SET] + " WHERE set_id = ?;",
103 
104  //BUNDLE_SET_NAME_*
105  "INSERT INTO " + _tables[SQL_TABLE_BUNDLE_SET_NAME] + " (name, persistent) VALUES (?, ?);",
106  "SELECT id FROM " + _tables[SQL_TABLE_BUNDLE_SET_NAME] + " WHERE name = ? AND persistent = ? LIMIT 0, 1;",
107  "DELETE FROM " + _tables[SQL_TABLE_BUNDLE_SET_NAME] + " WHERE id = ? LIMIT 0, 1;",
108 
109  "VACUUM;"
110  };
111 
112  const std::string SQLiteDatabase::_db_structure[SQLiteDatabase::DB_STRUCTURE_END] =
113  {
114  "CREATE TABLE IF NOT EXISTS `" + _tables[SQL_TABLE_BLOCK] + "` ( `key` INTEGER PRIMARY KEY ASC, `source` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `sequencenumber` INTEGER NOT NULL, `fragmentoffset` INTEGER NOT NULL DEFAULT 0, `fragmentlength` INTEGER NOT NULL DEFAULT 0, `blocktype` INTEGER NOT NULL, `filename` TEXT NOT NULL, `ordernumber` INTEGER NOT NULL);",
115  "CREATE TABLE IF NOT EXISTS `" + _tables[SQL_TABLE_BUNDLE] + "` ( `key` INTEGER PRIMARY KEY ASC, `source` TEXT NOT NULL, `destination` TEXT NOT NULL, `reportto` TEXT NOT NULL, `custodian` TEXT NOT NULL, `procflags` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `sequencenumber` INTEGER NOT NULL, `lifetime` INTEGER NOT NULL, `fragmentoffset` INTEGER NOT NULL DEFAULT 0, `appdatalength` INTEGER NOT NULL DEFAULT 0, `fragmentlength` INTEGER NOT NULL DEFAULT 0, `expiretime` INTEGER NOT NULL, `priority` INTEGER NOT NULL, `hopcount` INTEGER DEFAULT NULL, `netpriority` INTEGER NOT NULL DEFAULT 0, `payloadlength` INTEGER NOT NULL DEFAULT 0, `bytes` INTEGER NOT NULL DEFAULT 0);",
116  "CREATE TABLE IF NOT EXISTS "+ _tables[SQL_TABLE_ROUTING] +" (INTEGER PRIMARY KEY ASC, KEY INT, Routing TEXT);",
117  "CREATE TABLE IF NOT EXISTS "+ _tables[SQL_TABLE_BUNDLE_ROUTING_INFO] +" (INTEGER PRIMARY KEY ASC, BundleID TEXT, KEY INT, Routing TEXT);",
118  "CREATE TABLE IF NOT EXISTS "+ _tables[SQL_TABLE_NODE_ROUTING_INFO] +" (INTEGER PRIMARY KEY ASC, EID text, KEY INT, Routing TEXT);",
119  "CREATE TRIGGER IF NOT EXISTS blocks_autodelete AFTER DELETE ON " + _tables[SQL_TABLE_BUNDLE] + " FOR EACH ROW BEGIN DELETE FROM " + _tables[SQL_TABLE_BLOCK] + " WHERE " + _tables[SQL_TABLE_BLOCK] + ".source = OLD.source AND " + _tables[SQL_TABLE_BLOCK] + ".timestamp = OLD.timestamp AND " + _tables[SQL_TABLE_BLOCK] + ".sequencenumber = OLD.sequencenumber AND " + _tables[SQL_TABLE_BLOCK] + ".fragmentoffset = OLD.fragmentoffset AND " + _tables[SQL_TABLE_BLOCK] + ".fragmentlength = OLD.fragmentlength; END;",
120  "CREATE INDEX IF NOT EXISTS blocks_bid ON " + _tables[SQL_TABLE_BLOCK] + " (source, timestamp, sequencenumber, fragmentoffset, fragmentlength);",
121  "CREATE INDEX IF NOT EXISTS bundles_destination ON " + _tables[SQL_TABLE_BUNDLE] + " (destination);",
122  "CREATE INDEX IF NOT EXISTS bundles_destination_priority ON " + _tables[SQL_TABLE_BUNDLE] + " (destination, priority);",
123  "CREATE UNIQUE INDEX IF NOT EXISTS bundles_id ON " + _tables[SQL_TABLE_BUNDLE] + " (source, timestamp, sequencenumber, fragmentoffset, fragmentlength);"
124  "CREATE INDEX IF NOT EXISTS bundles_expire ON " + _tables[SQL_TABLE_BUNDLE] + " (source, timestamp, sequencenumber, fragmentoffset, fragmentlength, expiretime);",
125  "CREATE TABLE IF NOT EXISTS '" + _tables[SQL_TABLE_PROPERTIES] + "' ( `key` TEXT PRIMARY KEY ASC ON CONFLICT REPLACE, `value` TEXT NOT NULL);",
126  "CREATE TABLE IF NOT EXISTS " + _tables[SQL_TABLE_BUNDLE_SET] + " (`source` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `sequencenumber` INTEGER NOT NULL, `fragmentoffset` INTEGER NOT NULL, `fragmentlength` INTEGER NOT NULL, `expiretime` INTEGER, `set_id` INTEGER, PRIMARY KEY(`set_id`, `source`, `timestamp`, `sequencenumber`, `fragmentoffset`, `fragmentlength`));",
127  "CREATE TABLE IF NOT EXISTS " + _tables[SQL_TABLE_BUNDLE_SET_NAME] + " (`id` INTEGER PRIMARY KEY, `name` TEXT NOT NULL, `persistent` INTEGER NOT NULL);",
128  "CREATE UNIQUE INDEX IF NOT EXISTS bundle_set_names_index ON " + _tables[SQL_TABLE_BUNDLE_SET_NAME] + " (`name`, `persistent`);"
129  };
130 
132  { }
133 
135  {
136  }
137 
138  SQLiteDatabase::Statement::Statement(sqlite3 *database, const std::string &query)
139  : _database(database), _st(NULL), _query(query)
140  {
141  prepare();
142  }
143 
145  {
146  if (_st != NULL) {
147  sqlite3_finalize(_st);
148  }
149  }
150 
152  {
153  return _st;
154  }
155 
157  {
158  if (_st != NULL) {
159  sqlite3_reset(_st);
160  sqlite3_clear_bindings(_st);
161  }
162  }
163 
165  {
166  if (_st == NULL)
167  throw SQLiteQueryException("statement not prepared");
168 
169  int ret = sqlite3_step(_st);
170 
171  // check if the return value signals an error
172  switch (ret)
173  {
174  case SQLITE_CORRUPT:
175  throw SQLiteQueryException("Database is corrupt: " + std::string(sqlite3_errmsg(_database)));
176 
177  case SQLITE_INTERRUPT:
178  throw SQLiteQueryException("Database interrupt: " + std::string(sqlite3_errmsg(_database)));
179 
180  case SQLITE_SCHEMA:
181  throw SQLiteQueryException("Database schema error: " + std::string(sqlite3_errmsg(_database)));
182 
183  case SQLITE_ERROR:
184  throw SQLiteQueryException("Database error: " + std::string(sqlite3_errmsg(_database)));
185 
186  default:
187  return ret;
188  }
189  }
190 
192  {
193  if (_st != NULL)
194  throw SQLiteQueryException("already prepared");
195 
196  int err = sqlite3_prepare_v2(_database, _query.c_str(), static_cast<int>(_query.length()), &_st, 0);
197 
198  if ( err != SQLITE_OK )
199  throw SQLiteQueryException("failed to prepare statement: " + _query);
200  }
201 
203 
204  SQLiteDatabase::SQLiteDatabase(const ibrcommon::File &file, DatabaseListener &listener)
205  : _file(file), _database(NULL), _next_expiration(0), _listener(listener), _faulty(false)
206  {
207  }
208 
210  {
211  }
212 
213  int SQLiteDatabase::getVersion() throw (SQLiteDatabase::SQLiteQueryException)
214  {
215  // Check version of SQLiteDB
216  int version = 0;
217 
218  // prepare the statement
219  Statement st(_database, QUERY_SCHEMAVERSION);
220 
221  // execute statement for version query
222  int err = st.step();
223 
224  // Query finished no table found
225  if (err == SQLITE_ROW)
226  {
227  std::string dbversion = (const char*) sqlite3_column_text(*st, 0);
228  std::stringstream ss(dbversion);
229  ss >> version;
230  }
231 
232  return version;
233  }
234 
235  void SQLiteDatabase::setVersion(int version) throw (SQLiteDatabase::SQLiteQueryException)
236  {
237  std::stringstream ss; ss << version;
238  Statement st(_database, SET_SCHEMAVERSION);
239 
240  // bind version text to the statement
241  sqlite3_bind_text(*st, 1, ss.str().c_str(), static_cast<int>(ss.str().length()), SQLITE_TRANSIENT);
242 
243  int err = st.step();
244  if(err != SQLITE_DONE)
245  {
246  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << "failed to set version " << err << IBRCOMMON_LOGGER_ENDL;
247  }
248  }
249 
250  void SQLiteDatabase::doUpgrade(int oldVersion, int newVersion) throw (ibrcommon::Exception)
251  {
252  if (oldVersion > newVersion)
253  {
254  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << "Downgrade from version " << oldVersion << " to version " << newVersion << " is not possible." << IBRCOMMON_LOGGER_ENDL;
255  throw ibrcommon::Exception("Downgrade not possible.");
256  }
257 
258  if ((oldVersion != 0) && (oldVersion < DBSCHEMA_FRESH_VERSION))
259  {
260  throw ibrcommon::Exception("Re-creation required.");
261  }
262 
263  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, info) << "Upgrade from version " << oldVersion << " to version " << newVersion << IBRCOMMON_LOGGER_ENDL;
264 
265  for (int j = oldVersion; j < newVersion; ++j)
266  {
267  switch (j)
268  {
269  // if there is no version field, drop all tables
270  case 0:
271  for (size_t i = 0; i < SQL_TABLE_END; ++i)
272  {
273  Statement st(_database, "DROP TABLE IF EXISTS " + _tables[i] + ";");
274  int err = st.step();
275  if(err != SQLITE_DONE)
276  {
277  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << "drop table " << _tables[i] << " failed " << err << IBRCOMMON_LOGGER_ENDL;
278  }
279  }
280 
281  // create all tables
282  for (size_t i = 0; i < (DB_STRUCTURE_END - 1); ++i)
283  {
284  Statement st(_database, _db_structure[i]);
285  int err = st.step();
286  if(err != SQLITE_DONE)
287  {
288  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << "failed to create table " << _tables[i] << "; err: " << err << IBRCOMMON_LOGGER_ENDL;
289  }
290  }
291 
292  // set new database version
293  setVersion(DBSCHEMA_FRESH_VERSION);
294  j = DBSCHEMA_FRESH_VERSION;
295  break;
296 
297  default:
298  // NO UPGRADE PATH HERE
299  if (DBSCHEMA_FRESH_VERSION > j)
300  throw ibrcommon::Exception("Re-creation required.");
301  }
302  }
303  }
304 
305  void SQLiteDatabase::open() throw (SQLiteDatabase::SQLiteQueryException)
306  {
307  //Configure SQLite Library
309 
310  // check if SQLite is thread-safe
311  if (sqlite3_threadsafe() == 0)
312  {
313  IBRCOMMON_LOGGER_TAG("SQLiteDatabase", critical) << "sqlite library has not compiled with threading support." << IBRCOMMON_LOGGER_ENDL;
314  throw ibrcommon::Exception("need threading support in sqlite!");
315  }
316 
317  //open the database
318  if (sqlite3_open_v2(_file.getPath().c_str(), &_database, SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL))
319  {
320  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << "Can't open database: " << sqlite3_errmsg(_database) << IBRCOMMON_LOGGER_ENDL;
321  sqlite3_close(_database);
322  throw ibrcommon::Exception("Unable to open sqlite database");
323  }
324  try {
325  // check database version and upgrade if necessary
326  int version = getVersion();
327 
328  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, info) << "Database version " << version << " found." << IBRCOMMON_LOGGER_ENDL;
329 
330  if (version != DBSCHEMA_VERSION)
331  {
332  doUpgrade(version, DBSCHEMA_VERSION);
333  }
334  } catch (const ibrcommon::Exception &ex) {
335  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, warning) << "upgrade failed, start-over with a fresh database" << IBRCOMMON_LOGGER_ENDL;
336  doUpgrade(0, DBSCHEMA_VERSION);
337  }
338 
339  // disable synchronous mode
340  sqlite3_exec(_database, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
341 
342  // enable sqlite tracing if debug level is higher than 50
343  if (IBRCOMMON_LOGGER_LEVEL >= 50)
344  {
345  sqlite3_trace(_database, &sql_tracer, NULL);
346  }
347 
348  // calculate next Bundleexpiredtime
349  update_expire_time();
350  }
351 
353  {
354  //close Databaseconnection
355  if (sqlite3_close(_database) != SQLITE_OK)
356  {
357  IBRCOMMON_LOGGER_TAG("SQLiteDatabase", error) << "unable to close database" << IBRCOMMON_LOGGER_ENDL;
358  }
359 
360  // shutdown sqlite library
362  }
363 
365  {
366  // lock the prepared statement
367  Statement st(_database, _sql_queries[BUNDLE_GET_ID]);
368 
369  // bind bundle id to the statement
370  set_bundleid(st, id);
371 
372  // execute the query and check for error
373  if ((st.step() != SQLITE_ROW) || _faulty)
374  {
375  stringstream error;
376  error << "No Bundle found with BundleID: " << id.toString();
377  IBRCOMMON_LOGGER_DEBUG_TAG(SQLiteDatabase::TAG, 15) << error.str() << IBRCOMMON_LOGGER_ENDL;
378  throw SQLiteQueryException(error.str());
379  }
380 
381  // query bundle data
382  get(st, meta);
383  }
384 
385  void SQLiteDatabase::get(Statement &st, dtn::data::MetaBundle &bundle, int offset) const throw (SQLiteDatabase::SQLiteQueryException)
386  {
387  try {
388  bundle.source = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset) );
389  bundle.destination = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 1) );
390  bundle.reportto = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 2) );
391  bundle.custodian = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 3) );
392  } catch (const dtn::InvalidDataException&) {
393  IBRCOMMON_LOGGER_TAG(TAG, warning) << "unable to read EIDs from database" << IBRCOMMON_LOGGER_ENDL;
394  throw SQLiteDatabase::SQLiteQueryException("unable to read EIDs from database");
395  }
396 
397  bundle.procflags = sqlite3_column_int(*st, offset + 4);
398  bundle.timestamp = sqlite3_column_int64(*st, offset + 5);
399  bundle.sequencenumber = sqlite3_column_int64(*st, offset + 6);
400  bundle.lifetime = sqlite3_column_int64(*st, offset + 7);
401  bundle.expiretime = sqlite3_column_int64(*st, offset + 8);
402 
403  if (bundle.procflags & data::Bundle::FRAGMENT)
404  {
405  bundle.setFragment(true);
406  bundle.fragmentoffset = sqlite3_column_int64(*st, offset + 9);
407  bundle.appdatalength = sqlite3_column_int64(*st, offset + 10);
408  }
409  else
410  {
411  bundle.setFragment(false);
412  bundle.fragmentoffset = 0;
413  bundle.appdatalength = 0;
414  }
415 
416  if (sqlite3_column_type(*st, offset + 11) != SQLITE_NULL)
417  {
418  bundle.hopcount = sqlite3_column_int64(*st, 11);
419  }
420  else
421  {
422  bundle.hopcount = dtn::data::Number::max();
423  }
424 
425  // restore net priority
426  bundle.net_priority = sqlite3_column_int(*st, 12);
427 
428  // set payload length
429  bundle.setPayloadLength(sqlite3_column_int64(*st, offset + 13));
430  }
431 
432  void SQLiteDatabase::get(Statement &st, dtn::data::Bundle &bundle, const int offset) const throw (SQLiteDatabase::SQLiteQueryException)
433  {
434  try {
435  bundle.source = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 0) );
436  bundle.destination = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 1) );
437  bundle.reportto = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 2) );
438  bundle.custodian = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 3) );
439  } catch (const dtn::InvalidDataException&) {
440  IBRCOMMON_LOGGER_TAG(TAG, warning) << "unable to read EIDs from database" << IBRCOMMON_LOGGER_ENDL;
441  throw SQLiteDatabase::SQLiteQueryException("unable to read EIDs from database");
442  }
443 
444  bundle.procflags = sqlite3_column_int(*st, offset + 4);
445  bundle.timestamp = sqlite3_column_int64(*st, offset + 5);
446  bundle.sequencenumber = sqlite3_column_int64(*st, offset + 6);
447  bundle.lifetime = sqlite3_column_int64(*st, offset + 7);
448  // offset = 8 -> expiretime
449 
450  if (bundle.procflags & data::Bundle::FRAGMENT)
451  {
452  bundle.fragmentoffset = sqlite3_column_int64(*st, offset + 9);
453  bundle.appdatalength = sqlite3_column_int64(*st, offset + 10);
454  }
455  }
456 
457  void SQLiteDatabase::iterateAll() throw (SQLiteDatabase::SQLiteQueryException)
458  {
459  Statement st(_database, _sql_queries[BUNDLE_GET_ITERATOR]);
460  // abort if enough bundles are found
461  while (st.step() == SQLITE_ROW)
462  {
464 
465  // extract the primary values and set them in the bundle object
466  get(st, m, 0);
467 
468  // call iteration callback
469  _listener.iterateDatabase(m, sqlite3_column_int(*st, 14));
470  }
471 
472  st.reset();
473  }
474 
476  {
477  size_t items_added = 0;
478 
479  const std::string base_query =
480  "SELECT " + _select_names[0] + " FROM " + _tables[SQL_TABLE_BUNDLE];
481 
482  size_t offset = 0;
483  const bool unlimited = (cb.limit() <= 0);
484  const size_t query_limit = 50;
485 
486  try {
487  try {
488  const SQLBundleQuery &query = dynamic_cast<const SQLBundleQuery&>(cb);
489 
490  // custom query string
491  const std::string query_string = base_query + " WHERE " + query.getWhere() + " ORDER BY priority DESC, timestamp, sequencenumber, fragmentoffset, fragmentlength LIMIT ?,?;";
492 
493  // create statement for custom query
494  Statement st(_database, query_string);
495 
496  while (unlimited || (items_added < query_limit))
497  {
498  // bind the statement parameter
499  int bind_offset = query.bind(*st, 1);
500 
501  // query the database
502  __get(cb, st, ret, items_added, bind_offset, offset, query_limit);
503 
504  // increment the offset, because we might not have enough
505  offset += query_limit;
506  }
507  } catch (const std::bad_cast&) {
508  Statement st(_database, _sql_queries[BUNDLE_GET_FILTER]);
509 
510  while (unlimited || (items_added < query_limit))
511  {
512  // query the database
513  __get(cb, st, ret, items_added, 1, offset, query_limit);
514 
515  // increment the offset, because we might not have enough
516  offset += query_limit;
517  }
518  }
519  } catch (const SQLiteDatabase::SQLiteQueryException &ex) {
520  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, critical) << ex.what() << IBRCOMMON_LOGGER_ENDL;
521  } catch (const dtn::storage::NoBundleFoundException&) { }
522 
523  if (items_added == 0) throw dtn::storage::NoBundleFoundException();
524  }
525 
526  void SQLiteDatabase::__get(const BundleSelector &cb, Statement &st, BundleResult &ret, size_t &items_added, const int bind_offset, const size_t offset, const size_t query_limit) const throw (SQLiteDatabase::SQLiteQueryException, NoBundleFoundException, BundleSelectorException)
527  {
528  const bool unlimited = (cb.limit() <= 0);
529 
530  // limit result according to callback result
531  sqlite3_bind_int64(*st, bind_offset, offset);
532  sqlite3_bind_int64(*st, bind_offset + 1, query_limit);
533 
534  // returned no result
535  if ((st.step() == SQLITE_DONE) || _faulty)
537 
538  // abort if enough bundles are found
539  while (unlimited || (items_added < query_limit))
540  {
542 
543  // extract the primary values and set them in the bundle object
544  get(st, m, 0);
545 
546  // check if the bundle is already expired
547  if ( !dtn::utils::Clock::isExpired( m ) )
548  {
549  // ask the filter if this bundle should be added to the return list
550  if (cb.addIfSelected(ret, m))
551  {
552  IBRCOMMON_LOGGER_DEBUG_TAG("SQLiteDatabase", 40) << "add bundle to query selection list: " << m.toString() << IBRCOMMON_LOGGER_ENDL;
553 
554  // bundle has been added - increment counter
555  items_added++;
556  }
557  }
558 
559  if (st.step() != SQLITE_ROW) break;
560  }
561 
562  st.reset();
563  }
564 
566  {
567  int err = 0;
568 
569  IBRCOMMON_LOGGER_DEBUG_TAG("SQLiteDatabase", 25) << "get bundle from sqlite storage " << id.toString() << IBRCOMMON_LOGGER_ENDL;
570 
571  // do this while db is locked
572  Statement st(_database, _sql_queries[BUNDLE_GET_ID]);
573 
574  // set the bundle key values
575  set_bundleid(st, id);
576 
577  // execute the query and check for error
578  if (((err = st.step()) != SQLITE_ROW) || _faulty)
579  {
580  IBRCOMMON_LOGGER_DEBUG_TAG(SQLiteDatabase::TAG, 15) << "sql error: " << err << "; No bundle found with id: " << id.toString() << IBRCOMMON_LOGGER_ENDL;
582  }
583 
584  // read bundle data
585  get(st, bundle);
586 
587  try {
588 
589  int err = 0;
590  string file;
591 
592  Statement st(_database, _sql_queries[BLOCK_GET_ID]);
593 
594  // set the bundle key values
595  set_bundleid(st, id);
596 
597  // query the database and step through all blocks
598  while ((err = st.step()) == SQLITE_ROW)
599  {
600  const ibrcommon::File f( (const char*) sqlite3_column_text(*st, 0) );
601  int blocktyp = sqlite3_column_int(*st, 1);
602 
603  blocks.push_back( blocklist_entry(blocktyp, f) );
604  }
605 
606  if (err == SQLITE_DONE)
607  {
608  if (blocks.size() == 0)
609  {
610  IBRCOMMON_LOGGER_TAG("SQLiteDatabase", error) << "get_blocks: no blocks found for: " << id.toString() << IBRCOMMON_LOGGER_ENDL;
611  throw SQLiteQueryException("no blocks found");
612  }
613  }
614  else
615  {
616  IBRCOMMON_LOGGER_TAG("SQLiteDatabase", error) << "get_blocks() failure: "<< err << " " << sqlite3_errmsg(_database) << IBRCOMMON_LOGGER_ENDL;
617  throw SQLiteQueryException("can not query for blocks");
618  }
619 
620  } catch (const ibrcommon::Exception &ex) {
621  IBRCOMMON_LOGGER_TAG("SQLiteDatabase", error) << "could not get bundle blocks: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
623  }
624  }
625 
627  {
628  int err;
629 
630  Statement st(_database, _sql_queries[BUNDLE_STORE]);
631 
632  set_bundleid(st, bundle);
633 
634  sqlite3_bind_text(*st, 6, bundle.destination.getString().c_str(), static_cast<int>(bundle.destination.getString().length()), SQLITE_TRANSIENT);
635  sqlite3_bind_text(*st, 7, bundle.reportto.getString().c_str(), static_cast<int>(bundle.reportto.getString().length()), SQLITE_TRANSIENT);
636  sqlite3_bind_text(*st, 8, bundle.custodian.getString().c_str(), static_cast<int>(bundle.custodian.getString().length()), SQLITE_TRANSIENT);
637  sqlite3_bind_int(*st, 9, bundle.procflags.get<uint32_t>());
638  sqlite3_bind_int64(*st, 10, bundle.lifetime.get<uint64_t>());
639 
640  if (bundle.get(dtn::data::Bundle::FRAGMENT))
641  {
642  sqlite3_bind_int64(*st, 11, bundle.appdatalength.get<uint64_t>());
643  }
644  else
645  {
646  sqlite3_bind_int64(*st, 11, -1);
647  }
648 
650  sqlite3_bind_int64(*st, 12, expire_time.get<uint64_t>());
651 
652  sqlite3_bind_int64(*st, 13, bundle.getPriority());
653 
654  try {
656  sqlite3_bind_int64(*st, 14, schl.getHopsToLive().get<uint64_t>() );
658  sqlite3_bind_null(*st, 14 );
659  }
660 
661  try {
662  const dtn::data::SchedulingBlock &sched = bundle.find<dtn::data::SchedulingBlock>();
663  sqlite3_bind_int(*st, 15, sched.getPriority().get<int>() );
665  sqlite3_bind_int64(*st, 15, 0 );
666  }
667 
668  // set payload length
669  sqlite3_bind_int64(*st, 16, bundle.getPayloadLength());
670 
671  // set bundle size
672  sqlite3_bind_int64(*st, 17, size);
673 
674  err = st.step();
675 
676  if (err == SQLITE_CONSTRAINT)
677  {
678  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, warning) << "Bundle is already in the storage" << IBRCOMMON_LOGGER_ENDL;
679 
680  stringstream error;
681  error << "store() failure: " << err << " " << sqlite3_errmsg(_database);
682  throw SQLiteQueryException(error.str());
683  }
684  else if ((err != SQLITE_DONE) || _faulty)
685  {
686  stringstream error;
687  error << "store() failure: " << err << " " << sqlite3_errmsg(_database);
688  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << error.str() << IBRCOMMON_LOGGER_ENDL;
689 
690  throw SQLiteQueryException(error.str());
691  }
692 
693  // set new expire time
694  new_expire_time(expire_time);
695  }
696 
697  void SQLiteDatabase::store(const dtn::data::BundleID &id, int index, const dtn::data::Block &block, const ibrcommon::File &file) throw (SQLiteDatabase::SQLiteQueryException)
698  {
699  int blocktyp = (int)block.getType();
700 
701  // protect this query from concurrent access and enable the auto-reset feature
702  Statement st(_database, _sql_queries[BLOCK_STORE]);
703 
704  // set bundle key data
705  set_bundleid(st, id);
706 
707  // set the block type
708  sqlite3_bind_int(*st, 6, blocktyp);
709 
710  // the filename of the block data
711  sqlite3_bind_text(*st, 7, file.getPath().c_str(), static_cast<int>(file.getPath().size()), SQLITE_TRANSIENT);
712 
713  // the ordering number
714  sqlite3_bind_int(*st, 8, index);
715 
716  // execute the query and store the block in the database
717  if (st.step() != SQLITE_DONE)
718  {
719  throw SQLiteQueryException("can not store block of bundle");
720  }
721  }
722 
723  void SQLiteDatabase::transaction() throw (SQLiteDatabase::SQLiteQueryException)
724  {
725  char *zErrMsg = 0;
726 
727  // start a transaction
728  int ret = sqlite3_exec(_database, "BEGIN TRANSACTION;", NULL, NULL, &zErrMsg);
729 
730  // check if the return value signals an error
731  if ( ret != SQLITE_OK )
732  {
733  sqlite3_free( zErrMsg );
734  throw SQLiteQueryException( zErrMsg );
735  }
736  }
737 
738  void SQLiteDatabase::rollback() throw (SQLiteDatabase::SQLiteQueryException)
739  {
740  char *zErrMsg = 0;
741 
742  // rollback the whole transaction
743  int ret = sqlite3_exec(_database, "ROLLBACK TRANSACTION;", NULL, NULL, &zErrMsg);
744 
745  // check if the return value signals an error
746  if ( ret != SQLITE_OK )
747  {
748  sqlite3_free( zErrMsg );
749  throw SQLiteQueryException( zErrMsg );
750  }
751  }
752 
753  void SQLiteDatabase::commit() throw (SQLiteDatabase::SQLiteQueryException)
754  {
755  char *zErrMsg = 0;
756 
757  // commit the transaction
758  int ret = sqlite3_exec(_database, "END TRANSACTION;", NULL, NULL, &zErrMsg);
759 
760  // check if the return value signals an error
761  if ( ret != SQLITE_OK )
762  {
763  sqlite3_free( zErrMsg );
764  throw SQLiteQueryException( zErrMsg );
765  }
766  }
767 
769  {
770  // return value (size of the bundle in bytes)
771  dtn::data::Length ret = 0;
772 
773  {
774  // lock the database
775  Statement st(_database, _sql_queries[BUNDLE_GET_LENGTH_ID]);
776 
777  // bind bundle id to the statement
778  set_bundleid(st, id);
779 
780  // execute the query and check for error
781  if (st.step() != SQLITE_ROW)
782  {
783  // no bundle found - stop here
784  return ret;
785  }
786  else
787  {
788  ret = sqlite3_column_int(*st, 0);
789  }
790  }
791 
792  {
793  // lock the database
794  Statement st(_database, _sql_queries[BLOCK_GET_ID]);
795 
796  // set the bundle key values
797  set_bundleid(st, id);
798 
799  // step through all blocks
800  while (st.step() == SQLITE_ROW)
801  {
802  // delete each referenced block file
803  ibrcommon::File blockfile( (const char*)sqlite3_column_text(*st, 0) );
804  blockfile.remove();
805  }
806  }
807 
808  {
809  // lock the database
810  Statement st(_database, _sql_queries[BUNDLE_DELETE]);
811 
812  // then remove the bundle data
813  set_bundleid(st, id);
814  st.step();
815 
816  IBRCOMMON_LOGGER_DEBUG_TAG("SQLiteDatabase", 10) << "bundle " << id.toString() << " deleted" << IBRCOMMON_LOGGER_ENDL;
817  }
818 
819  //update deprecated timer
820  update_expire_time();
821 
822  // return the size of the removed bundle
823  return ret;
824  }
825 
826  void SQLiteDatabase::clear() throw (SQLiteDatabase::SQLiteQueryException)
827  {
828  Statement vacuum(_database, _sql_queries[VACUUM]);
829  Statement bundle_clear(_database, _sql_queries[BUNDLE_CLEAR]);
830  Statement block_clear(_database, _sql_queries[BLOCK_CLEAR]);
831 
832  bundle_clear.step();
833  block_clear.step();
834 
835  if (SQLITE_DONE != vacuum.step())
836  {
837  throw SQLiteQueryException("SQLiteBundleStore: clear(): vacuum failed.");
838  }
839 
840  reset_expire_time();
841  }
842 
844  {
845  // lock the prepared statement
846  Statement st(_database, _sql_queries[BUNDLE_GET_ID]);
847 
848  // bind bundle id to the statement
849  set_bundleid(st, id);
850 
851  // execute the query and check for error
852  return !((st.step() != SQLITE_ROW) || _faulty);
853  }
854 
855  bool SQLiteDatabase::empty() const throw (SQLiteDatabase::SQLiteQueryException)
856  {
857  Statement st(_database, _sql_queries[EMPTY_CHECK]);
858 
859  if (SQLITE_DONE == st.step())
860  {
861  return true;
862  }
863  else
864  {
865  return false;
866  }
867  }
868 
869  size_t SQLiteDatabase::count() const throw (SQLiteDatabase::SQLiteQueryException)
870  {
871  size_t rows = 0;
872  int err = 0;
873 
874  Statement st(_database, _sql_queries[COUNT_ENTRIES]);
875 
876  if ((err = st.step()) == SQLITE_ROW)
877  {
878  rows = sqlite3_column_int(*st, 0);
879  }
880  else
881  {
882  stringstream error;
883  error << "count: failure " << err << " " << sqlite3_errmsg(_database);
884  throw SQLiteQueryException(error.str());
885  }
886 
887  return rows;
888  }
889 
890  const std::set<dtn::data::EID> SQLiteDatabase::getDistinctDestinations() throw (SQLiteDatabase::SQLiteQueryException)
891  {
892  std::set<dtn::data::EID> ret;
893 
894  Statement st(_database, _sql_queries[GET_DISTINCT_DESTINATIONS]);
895 
896  // step through all blocks
897  while (st.step() == SQLITE_ROW)
898  {
899  // delete each referenced block file
900  const std::string destination( (const char*)sqlite3_column_text(*st, 0) );
901  ret.insert(destination);
902  }
903 
904  return ret;
905  }
906 
907  void SQLiteDatabase::update_expire_time() throw (SQLiteDatabase::SQLiteQueryException)
908  {
909  Statement st(_database, _sql_queries[EXPIRE_NEXT_TIMESTAMP]);
910 
911  int err = st.step();
912 
913  if (err == SQLITE_ROW)
914  {
915  _next_expiration = sqlite3_column_int64(*st, 0);
916  }
917  else
918  {
919  _next_expiration = 0;
920  }
921  }
922 
923  void SQLiteDatabase::expire(const dtn::data::Timestamp &timestamp) throw ()
924  {
925  /*
926  * Only if the actual time is bigger or equal than the time when the next bundle expires, deleteexpired is called.
927  */
928  dtn::data::Timestamp exp_time = get_expire_time();
929  if ((timestamp < exp_time) || (exp_time == 0)) return;
930 
931  /*
932  * Performanceverbesserung: Damit die Abfragen nicht jede Sekunde ausgeführt werden müssen, speichert man den Zeitpunkt an dem
933  * das nächste Bündel gelöscht werden soll in eine Variable und führt deleteexpired erst dann aus wenn ein Bündel abgelaufen ist.
934  * Nach dem Löschen wird die DB durchsucht und der nächste Ablaufzeitpunkt wird in die Variable gesetzt.
935  */
936 
937  try {
938  Statement st(_database, _sql_queries[EXPIRE_BUNDLE_FILENAMES]);
939 
940  // query for blocks of expired bundles
941  sqlite3_bind_int64(*st, 1, timestamp.get<uint64_t>());
942  while (st.step() == SQLITE_ROW)
943  {
944  ibrcommon::File block((const char*)sqlite3_column_text(*st,0));
945  block.remove();
946  }
947  } catch (const SQLiteDatabase::SQLiteQueryException &ex) {
948  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
949  }
950 
951  try {
952  Statement st(_database, _sql_queries[EXPIRE_BUNDLES]);
953 
955 
956  // query expired bundles
957  sqlite3_bind_int64(*st, 1, timestamp.get<uint64_t>());
958  while (st.step() == SQLITE_ROW)
959  {
960  id.source = dtn::data::EID((const char*)sqlite3_column_text(*st, 0));
961  id.timestamp = sqlite3_column_int64(*st, 1);
962  id.sequencenumber = sqlite3_column_int64(*st, 2);
963 
964  id.setFragment(sqlite3_column_int64(*st, 3) >= 0);
965 
966  if (id.isFragment()) {
967  id.fragmentoffset = sqlite3_column_int64(*st, 3);
968  } else {
969  id.fragmentoffset = 0;
970  }
971 
972  id.setPayloadLength(sqlite3_column_int64(*st, 4));
973 
975 
976  // raise bundle removed event
977  _listener.eventBundleExpired(id, sqlite3_column_int(*st, 5));
978  }
979  } catch (const SQLiteDatabase::SQLiteQueryException &ex) {
980  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
981  }
982 
983  try {
984  Statement st(_database, _sql_queries[EXPIRE_BUNDLE_DELETE]);
985 
986  // delete all expired db entries (bundles and blocks)
987  sqlite3_bind_int64(*st, 1, timestamp.get<uint64_t>());
988  st.step();
989  } catch (const SQLiteDatabase::SQLiteQueryException &ex) {
990  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
991  }
992 
993  try {
994  //update deprecated timer
995  update_expire_time();
996  } catch (const SQLiteDatabase::SQLiteQueryException &ex) {
997  IBRCOMMON_LOGGER_TAG(SQLiteDatabase::TAG, error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
998  }
999  }
1000 
1001  void SQLiteDatabase::vacuum() throw (SQLiteDatabase::SQLiteQueryException)
1002  {
1003  Statement st(_database, _sql_queries[VACUUM]);
1004  st.step();
1005  }
1006 
1008  {
1009  if (mode == UPDATE_CUSTODIAN)
1010  {
1011  // select query with or without fragmentation extension
1012  Statement st(_database, _sql_queries[BUNDLE_UPDATE_CUSTODIAN]);
1013 
1014  sqlite3_bind_text(*st, 1, eid.getString().c_str(), static_cast<int>(eid.getString().length()), SQLITE_TRANSIENT);
1015  set_bundleid(st, id, 1);
1016 
1017  // update the custodian in the database
1018  int err = st.step();
1019 
1020  if (err != SQLITE_DONE)
1021  {
1022  stringstream error;
1023  error << "update_custodian() failure: " << err << " " << sqlite3_errmsg(_database);
1024  throw SQLiteDatabase::SQLiteQueryException(error.str());
1025  }
1026  }
1027  }
1028 
1029  void SQLiteDatabase::new_expire_time(const dtn::data::Timestamp &ttl) throw ()
1030  {
1031  if (_next_expiration == 0 || ttl < _next_expiration)
1032  {
1033  _next_expiration = ttl;
1034  }
1035  }
1036 
1037  void SQLiteDatabase::reset_expire_time() throw ()
1038  {
1039  _next_expiration = 0;
1040  }
1041 
1042  const dtn::data::Timestamp& SQLiteDatabase::get_expire_time() const throw ()
1043  {
1044  return _next_expiration;
1045  }
1046 
1047  void SQLiteDatabase::set_bundleid(Statement &st, const dtn::data::BundleID &id, int offset) const throw (SQLiteDatabase::SQLiteQueryException)
1048  {
1049  sqlite3_bind_text(*st, offset + 1, id.source.getString().c_str(), static_cast<int>(id.source.getString().length()), SQLITE_TRANSIENT);
1050  sqlite3_bind_int64(*st, offset + 2, id.timestamp.get<uint64_t>());
1051  sqlite3_bind_int64(*st, offset + 3, id.sequencenumber.get<uint64_t>());
1052 
1053  if (id.isFragment())
1054  {
1055  sqlite3_bind_int64(*st, offset + 4, id.fragmentoffset.get<uint64_t>());
1056  sqlite3_bind_int64(*st, offset + 5, id.getPayloadLength());
1057  }
1058  else
1059  {
1060  sqlite3_bind_int64(*st, offset + 4, -1);
1061  sqlite3_bind_int64(*st, offset + 5, -1);
1062  }
1063  }
1064 
1066  {
1067  _faulty = mode;
1068  }
1069  } /* namespace storage */
1070 } /* namespace dtn */
std::string toString() const
Definition: BundleID.cpp:190
bool contains(const dtn::data::BundleID &id)
size_t Length
Definition: Number.h:33
virtual const eid_set getDistinctDestinations()
static dtn::data::Timestamp getExpireTime(const dtn::data::Bundle &b)
Definition: Clock.cpp:91
void sql_tracer(void *, const char *pQuery)
Statement(sqlite3 *database, const std::string &)
virtual int bind(sqlite3_stmt *, int offset) const
static void raise(const dtn::data::Bundle &bundle)
void update(UPDATE_VALUES, const dtn::data::BundleID &id, const dtn::data::EID &)
const std::string TAG
Definition: dtnoutbox.cpp:62
static SDNV< Size > max()
Definition: SDNV.h:394
void store(const dtn::data::Bundle &bundle, const dtn::data::Length &size)
T get() const
Definition: SDNV.h:113
virtual void iterateDatabase(const dtn::data::MetaBundle &, const dtn::data::Length)=0
dtn::data::Size count() const
dtn::data::Length remove(const dtn::data::BundleID &id)
std::pair< int, const ibrcommon::File > blocklist_entry
void expire(const dtn::data::Timestamp &timestamp)
SQLiteDatabase(const ibrcommon::File &file, DatabaseListener &listener)
virtual void get(const BundleSelector &cb, BundleResult &result)
virtual const std::string getWhere() const =0
static bool isExpired(const dtn::data::Timestamp &timestamp, const dtn::data::Number &lifetime)
Definition: Clock.cpp:155
std::list< std::pair< int, const ibrcommon::File > > blocklist