IBR-DTNSuite  0.8
daemon/src/storage/SQLiteDatabase.cpp
Go to the documentation of this file.
00001 /*
00002  * SQLiteDatabase.cpp
00003  *
00004  *  Created on: 26.03.2012
00005  *      Author: morgenro
00006  */
00007 
00008 #include "storage/SQLiteDatabase.h"
00009 #include "storage/SQLiteConfigure.h"
00010 #include <ibrdtn/data/ScopeControlHopLimitBlock.h>
00011 #include <ibrdtn/utils/Clock.h>
00012 #include <ibrcommon/Logger.h>
00013 
00014 namespace dtn
00015 {
00016         namespace storage
00017         {
00018                 void sql_tracer(void*, const char * pQuery)
00019                 {
00020                         IBRCOMMON_LOGGER_DEBUG(50) << "sqlite trace: " << pQuery << IBRCOMMON_LOGGER_ENDL;
00021                 }
00022 
00023                 const std::string SQLiteDatabase::_tables[SQL_TABLE_END] =
00024                                 { "bundles", "blocks", "routing", "routing_bundles", "routing_nodes", "properties" };
00025 
00026                 const int SQLiteDatabase::DBSCHEMA_VERSION = 1;
00027                 const std::string SQLiteDatabase::QUERY_SCHEMAVERSION = "SELECT `value` FROM " + SQLiteDatabase::_tables[SQLiteDatabase::SQL_TABLE_PROPERTIES] + " WHERE `key` = 'version' LIMIT 0,1;";
00028                 const std::string SQLiteDatabase::SET_SCHEMAVERSION = "INSERT INTO " + SQLiteDatabase::_tables[SQLiteDatabase::SQL_TABLE_PROPERTIES] + " (`key`, `value`) VALUES ('version', ?);";
00029 
00030                 const std::string SQLiteDatabase::_sql_queries[SQL_QUERIES_END] =
00031                 {
00032                         "SELECT source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, fragmentoffset, appdatalength, hopcount, payloadlength FROM " + _tables[SQL_TABLE_BUNDLE] + " ORDER BY priority DESC LIMIT ?,?;",
00033                         "SELECT source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, fragmentoffset, appdatalength, hopcount, payloadlength FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset IS NULL LIMIT 1;",
00034                         "SELECT source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, fragmentoffset, appdatalength, hopcount, payloadlength FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ? LIMIT 1;",
00035                         "SELECT * FROM " + _tables[SQL_TABLE_BUNDLE] + " WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset != NULL ORDER BY fragmentoffset ASC;",
00036 
00037                         "SELECT source, timestamp, sequencenumber, fragmentoffset, procflags FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE expiretime <= ?;",
00038                         "SELECT filename FROM "+ _tables[SQL_TABLE_BUNDLE] +" as a, "+ _tables[SQL_TABLE_BLOCK] +" as b WHERE a.source_id = b.source_id AND a.timestamp = b.timestamp AND a.sequencenumber = b.sequencenumber AND ((a.fragmentoffset = b.fragmentoffset) OR ((a.fragmentoffset IS NULL) AND (b.fragmentoffset IS NULL))) AND a.expiretime <= ?;",
00039                         "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE expiretime <= ?;",
00040                         "SELECT expiretime FROM "+ _tables[SQL_TABLE_BUNDLE] +" ORDER BY expiretime ASC LIMIT 1;",
00041 
00042                         "SELECT ROWID FROM "+ _tables[SQL_TABLE_BUNDLE] +" LIMIT 1;",
00043                         "SELECT COUNT(ROWID) FROM "+ _tables[SQL_TABLE_BUNDLE] +";",
00044 
00045                         "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset IS NULL;",
00046                         "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ?;",
00047                         "DELETE FROM "+ _tables[SQL_TABLE_BUNDLE] +";",
00048                         "INSERT INTO "+ _tables[SQL_TABLE_BUNDLE] +" (source_id, timestamp, sequencenumber, fragmentoffset, source, destination, reportto, custodian, procflags, lifetime, appdatalength, expiretime, priority, hopcount, payloadlength) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);",
00049                         "UPDATE "+ _tables[SQL_TABLE_BUNDLE] +" SET custodian = ? WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset IS NULL;",
00050                         "UPDATE "+ _tables[SQL_TABLE_BUNDLE] +" SET custodian = ? WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ?;",
00051 
00052                         "UPDATE "+ _tables[SQL_TABLE_BUNDLE] +" SET procflags = ? WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ?;",
00053 
00054                         "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset IS NULL ORDER BY ordernumber ASC;",
00055                         "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ? ORDER BY ordernumber ASC;",
00056                         "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset IS NULL AND ordernumber = ?;",
00057                         "SELECT filename, blocktype FROM "+ _tables[SQL_TABLE_BLOCK] +" WHERE source_id = ? AND timestamp = ? AND sequencenumber = ? AND fragmentoffset = ? AND ordernumber = ?;",
00058                         "DELETE FROM "+ _tables[SQL_TABLE_BLOCK] +";",
00059                         "INSERT INTO "+ _tables[SQL_TABLE_BLOCK] +" (source_id, timestamp, sequencenumber, fragmentoffset, blocktype, filename, ordernumber) VALUES (?,?,?,?,?,?,?);",
00060 
00061                         "VACUUM;",
00062                 };
00063 
00064                 const std::string SQLiteDatabase::_db_structure[11] =
00065                 {
00066                         "CREATE TABLE IF NOT EXISTS `" + _tables[SQL_TABLE_BLOCK] + "` ( `key` INTEGER PRIMARY KEY ASC, `source_id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `sequencenumber` INTEGER NOT NULL, `fragmentoffset` INTEGER DEFAULT NULL, `blocktype` INTEGER NOT NULL, `filename` TEXT NOT NULL, `ordernumber` INTEGER NOT NULL);",
00067                         "CREATE TABLE IF NOT EXISTS `" + _tables[SQL_TABLE_BUNDLE] + "` ( `key` INTEGER PRIMARY KEY ASC, `source_id` TEXT NOT NULL, `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 DEFAULT NULL, `appdatalength` INTEGER DEFAULT NULL, `expiretime` INTEGER NOT NULL, `priority` INTEGER NOT NULL, `hopcount` INTEGER DEFAULT NULL, `payloadlength` INTEGER NOT NULL);",
00068                         "create table if not exists "+ _tables[SQL_TABLE_ROUTING] +" (INTEGER PRIMARY KEY ASC, Key int, Routing text);",
00069                         "create table if not exists "+ _tables[SQL_TABLE_BUNDLE_ROUTING_INFO] +" (INTEGER PRIMARY KEY ASC, BundleID text, Key int, Routing text);",
00070                         "create table if not exists "+ _tables[SQL_TABLE_NODE_ROUTING_INFO] +" (INTEGER PRIMARY KEY ASC, EID text, Key int, Routing text);",
00071                         "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_id = OLD.source_id AND " + _tables[SQL_TABLE_BLOCK] + ".timestamp = OLD.timestamp AND " + _tables[SQL_TABLE_BLOCK] + ".sequencenumber = OLD.sequencenumber AND ((" + _tables[SQL_TABLE_BLOCK] + ".fragmentoffset IS NULL AND old.fragmentoffset IS NULL) OR (" + _tables[SQL_TABLE_BLOCK] + ".fragmentoffset = old.fragmentoffset)); END;",
00072                         "CREATE UNIQUE INDEX IF NOT EXISTS blocks_bid ON " + _tables[SQL_TABLE_BLOCK] + " (source_id, timestamp, sequencenumber, fragmentoffset);",
00073                         "CREATE INDEX IF NOT EXISTS bundles_destination ON " + _tables[SQL_TABLE_BUNDLE] + " (destination);",
00074                         "CREATE INDEX IF NOT EXISTS bundles_destination_priority ON " + _tables[SQL_TABLE_BUNDLE] + " (destination, priority);",
00075                         "CREATE UNIQUE INDEX IF NOT EXISTS bundles_id ON " + _tables[SQL_TABLE_BUNDLE] + " (source_id, timestamp, sequencenumber, fragmentoffset);"
00076                         "CREATE INDEX IF NOT EXISTS bundles_expire ON " + _tables[SQL_TABLE_BUNDLE] + " (source_id, timestamp, sequencenumber, fragmentoffset, expiretime);",
00077                         "CREATE TABLE IF NOT EXISTS '" + _tables[SQL_TABLE_PROPERTIES] + "' ( `key` TEXT PRIMARY KEY ASC ON CONFLICT REPLACE, `value` TEXT NOT NULL);"
00078                 };
00079 
00080                 SQLiteDatabase::SQLBundleQuery::SQLBundleQuery()
00081                 { }
00082 
00083                 SQLiteDatabase::SQLBundleQuery::~SQLBundleQuery()
00084                 {
00085                 }
00086 
00087                 SQLiteDatabase::Statement::Statement(sqlite3 *database, const std::string &query)
00088                  : _database(database), _st(NULL), _query(query)
00089                 {
00090                         prepare();
00091                 }
00092 
00093                 SQLiteDatabase::Statement::~Statement()
00094                 {
00095                         if (_st != NULL) {
00096                                 sqlite3_finalize(_st);
00097                         }
00098                 }
00099 
00100                 sqlite3_stmt* SQLiteDatabase::Statement::operator*()
00101                 {
00102                         return _st;
00103                 }
00104 
00105                 void SQLiteDatabase::Statement::reset()
00106                 {
00107                         if (_st != NULL) {
00108                                 sqlite3_reset(_st);
00109                                 sqlite3_clear_bindings(_st);
00110                         }
00111                 }
00112 
00113                 int SQLiteDatabase::Statement::step()
00114                 {
00115                         if (_st == NULL)
00116                                 throw SQLiteQueryException("statement not prepared");
00117 
00118                         return sqlite3_step(_st);
00119                 }
00120 
00121                 void SQLiteDatabase::Statement::prepare()
00122                 {
00123                         if (_st != NULL)
00124                                 throw SQLiteQueryException("already prepared");
00125 
00126                         int err = sqlite3_prepare_v2(_database, _query.c_str(), _query.length(), &_st, 0);
00127 
00128                         if ( err != SQLITE_OK )
00129                                 throw SQLiteQueryException("failed to prepare statement: " + _query);
00130                 }
00131 
00132                 SQLiteDatabase::SQLiteDatabase(const ibrcommon::File &file, const size_t &size)
00133                  : _file(file), _size(size), _next_expiration(0)
00134                 {
00135                 }
00136 
00137                 SQLiteDatabase::~SQLiteDatabase()
00138                 {
00139                 }
00140 
00141                 int SQLiteDatabase::getVersion()
00142                 {
00143                         // Check version of SQLiteDB
00144                         int version = 0;
00145 
00146                         // prepare the statement
00147                         Statement st(_database, QUERY_SCHEMAVERSION);
00148 
00149                         // execute statement for version query
00150                         int err = st.step();
00151 
00152                         // Query finished no table found
00153                         if (err == SQLITE_ROW)
00154                         {
00155                                 std::string dbversion = (const char*) sqlite3_column_text(*st, 0);
00156                                 std::stringstream ss(dbversion);
00157                                 ss >> version;
00158                         }
00159 
00160                         return version;
00161                 }
00162 
00163                 void SQLiteDatabase::setVersion(int version)
00164                 {
00165                         std::stringstream ss; ss << version;
00166                         Statement st(_database, SET_SCHEMAVERSION);
00167 
00168                         // bind version text to the statement
00169                         sqlite3_bind_text(*st, 1, ss.str().c_str(), ss.str().length(), SQLITE_TRANSIENT);
00170 
00171                         int err = st.step();
00172                         if(err != SQLITE_DONE)
00173                         {
00174                                 IBRCOMMON_LOGGER(error) << "SQLiteDatabase: failed to set version " << err << IBRCOMMON_LOGGER_ENDL;
00175                         }
00176                 }
00177 
00178                 void SQLiteDatabase::doUpgrade(int oldVersion, int newVersion)
00179                 {
00180                         if (oldVersion > newVersion)
00181                         {
00182                                 IBRCOMMON_LOGGER(error) << "SQLiteDatabase: Downgrade from version " << oldVersion << " to version " << newVersion << " is not possible." << IBRCOMMON_LOGGER_ENDL;
00183                                 throw ibrcommon::Exception("Downgrade not possible.");
00184                         }
00185 
00186                         IBRCOMMON_LOGGER(info) << "SQLiteDatabase: Upgrade from version " << oldVersion << " to version " << newVersion << IBRCOMMON_LOGGER_ENDL;
00187 
00188                         for (int i = oldVersion; i < newVersion; i++)
00189                         {
00190                                 switch (i)
00191                                 {
00192                                 // if there is no version field, drop all tables
00193                                 case 0:
00194                                         for (size_t i = 0; i < SQL_TABLE_END; i++)
00195                                         {
00196                                                 Statement st(_database, "DROP TABLE IF EXISTS " + _tables[i] + ";");
00197                                                 int err = st.step();
00198                                                 if(err != SQLITE_DONE)
00199                                                 {
00200                                                         IBRCOMMON_LOGGER(error) << "SQLiteDatabase: drop table " << _tables[i] << " failed " << err << IBRCOMMON_LOGGER_ENDL;
00201                                                 }
00202                                         }
00203 
00204                                         // create all tables
00205                                         for (size_t i = 0; i < 11; i++)
00206                                         {
00207                                                 Statement st(_database, _db_structure[i]);
00208                                                 int err = st.step();
00209                                                 if(err != SQLITE_DONE)
00210                                                 {
00211                                                         IBRCOMMON_LOGGER(error) << "SQLiteDatabase: failed to create table " << _tables[i] << "; err: " << err << IBRCOMMON_LOGGER_ENDL;
00212                                                 }
00213                                         }
00214 
00215                                         // set new database version
00216                                         setVersion(1);
00217 
00218                                         break;
00219                                 }
00220                         }
00221                 }
00222 
00223                 void SQLiteDatabase::open()
00224                 {
00225                         //Configure SQLite Library
00226                         SQLiteConfigure::configure();
00227 
00228                         // check if SQLite is thread-safe
00229                         if (sqlite3_threadsafe() == 0)
00230                         {
00231                                 IBRCOMMON_LOGGER(critical) << "sqlite library has not compiled with threading support." << IBRCOMMON_LOGGER_ENDL;
00232                                 throw ibrcommon::Exception("need threading support in sqlite!");
00233                         }
00234 
00235                         //open the database
00236                         if (sqlite3_open_v2(_file.getPath().c_str(), &_database,  SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL))
00237                         {
00238                                 IBRCOMMON_LOGGER(error) << "Can't open database: " << sqlite3_errmsg(_database) << IBRCOMMON_LOGGER_ENDL;
00239                                 sqlite3_close(_database);
00240                                 throw ibrcommon::Exception("Unable to open sqlite database");
00241                         }
00242 
00243                         try {
00244                                 // check database version and upgrade if necessary
00245                                 int version = getVersion();
00246 
00247                                 IBRCOMMON_LOGGER(info) << "SQLiteDatabase: Database version " << version << " found." << IBRCOMMON_LOGGER_ENDL;
00248 
00249                                 if (version != DBSCHEMA_VERSION)
00250                                 {
00251                                         doUpgrade(version, DBSCHEMA_VERSION);
00252                                 }
00253                         } catch (const SQLiteQueryException&) {
00254                                 doUpgrade(0, DBSCHEMA_VERSION);
00255                         }
00256 
00257                         // disable synchronous mode
00258                         sqlite3_exec(_database, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
00259 
00260                         // enable sqlite tracing if debug level is higher than 50
00261                         if (IBRCOMMON_LOGGER_LEVEL >= 50)
00262                         {
00263                                 sqlite3_trace(_database, &sql_tracer, NULL);
00264                         }
00265 
00266 //                      //Check if the database is consistent with the filesystem
00267 //                      check_consistency();
00268 
00269                         // calculate next Bundleexpiredtime
00270                         update_expire_time();
00271                 }
00272 
00273                 void SQLiteDatabase::close()
00274                 {
00275                         //close Databaseconnection
00276                         if (sqlite3_close(_database) != SQLITE_OK)
00277                         {
00278                                 IBRCOMMON_LOGGER(error) << "unable to close database" << IBRCOMMON_LOGGER_ENDL;
00279                         }
00280 
00281                         // shutdown sqlite library
00282                         SQLiteConfigure::shutdown();
00283                 }
00284 
00285 //              void SQLiteDatabase::check_consistency()
00286 //              {
00287 //                      /*
00288 //                       * check if the database is consistent with the files on the HDD. Therefore every file of the database is put in a list.
00289 //                       * When the files of the database are scanned it is checked if the actual file is in the list of files of the filesystem. if it is so the entry
00290 //                       * of the list of files of the filesystem is deleted. if not the file is put in a seperate list. After this procedure there are 2 lists containing file
00291 //                       * which are inconsistent and can be deleted.
00292 //                       */
00293 //                      set<string> blockFiles,payloadfiles;
00294 //                      string datei;
00295 //
00296 //                      list<ibrcommon::File> blist;
00297 //                      list<ibrcommon::File>::iterator file_it;
00298 //
00299 //                      //1. Durchsuche die Dateien
00300 //                      _blockPath.getFiles(blist);
00301 //                      for(file_it = blist.begin(); file_it != blist.end(); file_it++)
00302 //                      {
00303 //                              datei = (*file_it).getPath();
00304 //                              if(datei[datei.size()-1] != '.')
00305 //                              {
00306 //                                      if(((*file_it).getBasename())[0] == 'b')
00307 //                                      {
00308 //                                              blockFiles.insert(datei);
00309 //                                      }
00310 //                                      else
00311 //                                              payloadfiles.insert(datei);
00312 //                              }
00313 //                      }
00314 //
00315 //                      //3. Check consistency of the bundles
00316 //                      check_bundles(blockFiles);
00317 //
00318 //                      //4. Check consistency of the fragments
00319 //                      check_fragments(payloadfiles);
00320 //              }
00321 
00322 //              void SQLiteDatabase::check_fragments(std::set<std::string> &payloadFiles)
00323 //              {
00324 //                      int err;
00325 //                      size_t timestamp, sequencenumber, fragmentoffset;
00326 //                      string filename, source, dest, custody, repto;
00327 //                      set<string> consistenFiles, inconsistenSources;
00328 //                      set<size_t> inconsistentTimestamp, inconsistentSeq_number;
00329 //                      set<string>::iterator file_it, consisten_it;
00330 //
00331 //                      sqlite3_stmt *getPayloadfiles = prepare("SELECT source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, fragmentoffset, appdatalength, hopcount FROM "+_tables[SQL_TABLE_BUNDLE]+" WHERE fragmentoffset != NULL;");
00332 //
00333 //                      for(err = sqlite3_step(getPayloadfiles); err == SQLITE_ROW; err = sqlite3_step(getPayloadfiles))
00334 //                      {
00335 //                              filename = (const char*)sqlite3_column_text(getPayloadfiles,10);
00336 //                              file_it = payloadFiles.find(filename);
00337 //
00338 //
00339 //                              if (file_it == payloadFiles.end())
00340 //                              {
00341 //                                      consisten_it = consistenFiles.find(*file_it);
00342 //
00343 //                                      //inconsistent DB entry
00344 //                                      if(consisten_it == consistenFiles.end())
00345 //                                      {
00346 //                                              //Generate Report
00347 //                                              source  = (const char*) sqlite3_column_text(getPayloadfiles, 0);
00348 //                                              dest    = (const char*) sqlite3_column_text(getPayloadfiles, 1);
00349 //                                              repto   = (const char*) sqlite3_column_text(getPayloadfiles, 2);
00350 //                                              custody = (const char*) sqlite3_column_text(getPayloadfiles, 3);
00351 //
00352 //                                              timestamp = sqlite3_column_int64(getPayloadfiles, 5);
00353 //                                              sequencenumber = sqlite3_column_int64(getPayloadfiles, 6);
00354 //                                              fragmentoffset = sqlite3_column_int64(getPayloadfiles, 8);
00355 //
00356 //                                              dtn::data::BundleID id( dtn::data::EID(source), timestamp, sequencenumber, true, fragmentoffset );
00357 //                                              dtn::data::MetaBundle mb(id);
00358 //
00359 //                                              mb.procflags = sqlite3_column_int64(getPayloadfiles, 4);
00360 //                                              mb.lifetime = sqlite3_column_int64(getPayloadfiles, 7);
00361 //                                              mb.destination = dest;
00362 //                                              mb.reportto = repto;
00363 //                                              mb.custodian = custody;
00364 //                                              mb.appdatalength = sqlite3_column_int64(getPayloadfiles, 9);
00365 //                                              mb.expiretime = dtn::utils::Clock::getExpireTime(timestamp, mb.lifetime);
00366 //
00367 //                                              if (sqlite3_column_type(getPayloadfiles, 10) != SQLITE_NULL)
00368 //                                              {
00369 //                                                      mb.hopcount = sqlite3_column_int64(getPayloadfiles, 10);
00370 //                                              }
00371 //
00372 //                                              dtn::core::BundleEvent::raise(mb, dtn::core::BUNDLE_DELETED, dtn::data::StatusReportBlock::DEPLETED_STORAGE);
00373 //                                      }
00374 //                              }
00375 //                              //consistent DB entry
00376 //                              else
00377 //                                      consistenFiles.insert(*file_it);
00378 //                                      payloadFiles.erase(file_it);
00379 //                      }
00380 //
00381 //                      sqlite3_reset(getPayloadfiles);
00382 //                      sqlite3_finalize(getPayloadfiles);
00383 //              }
00384 //
00385 //              void SQLiteDatabase::check_bundles(std::set<std::string> &blockFiles)
00386 //              {
00387 //                      std::set<dtn::data::BundleID> corrupt_bundle_ids;
00388 //
00389 //                      sqlite3_stmt *blockConistencyCheck = prepare("SELECT source_id, timestamp, sequencenumber, fragmentoffset, filename, ordernumber FROM "+ _tables[SQL_TABLE_BLOCK] +";");
00390 //
00391 //                      while (sqlite3_step(blockConistencyCheck) == SQLITE_ROW)
00392 //                      {
00393 //                              dtn::data::BundleID id;
00394 //
00395 //                              // get the bundleid
00396 //                              get_bundleid(blockConistencyCheck, id);
00397 //
00398 //                              // get the filename
00399 //                              std::string filename = (const char*)sqlite3_column_text(blockConistencyCheck, 4);
00400 //
00401 //                              // if the filename is not in the list of block files
00402 //                              if (blockFiles.find(filename) == blockFiles.end())
00403 //                              {
00404 //                                      // add the bundle to the deletion list
00405 //                                      corrupt_bundle_ids.insert(id);
00406 //                              }
00407 //                              else
00408 //                              {
00409 //                                      // file is available, everything is fine
00410 //                                      blockFiles.erase(filename);
00411 //                              }
00412 //                      }
00413 //                      sqlite3_reset(blockConistencyCheck);
00414 //                      sqlite3_finalize(blockConistencyCheck);
00415 //
00416 //                      for(std::set<dtn::data::BundleID>::const_iterator iter = corrupt_bundle_ids.begin(); iter != corrupt_bundle_ids.end(); iter++)
00417 //                      {
00418 //                              try {
00419 //                                      const dtn::data::BundleID &id = (*iter);
00420 //
00421 //                                      // get meta data of this bundle
00422 //                                      const dtn::data::MetaBundle m = get_meta(id);
00423 //
00424 //                                      // remove the hole bundle
00425 //                                      remove(id);
00426 //                              } catch (const dtn::storage::SQLiteDatabase::SQLiteQueryException&) { };
00427 //                      }
00428 //
00429 //                      // delete block files still in the blockfile list
00430 //                      for (std::set<std::string>::const_iterator iter = blockFiles.begin(); iter != blockFiles.end(); iter++)
00431 //                      {
00432 //                              ibrcommon::File blockfile(*iter);
00433 //                              blockfile.remove();
00434 //                      }
00435 //              }
00436 
00437                 void SQLiteDatabase::get(const dtn::data::BundleID &id, dtn::data::MetaBundle &meta) const
00438                 {
00439                         // check if the bundle is already on the deletion list
00440                         if (contains_deletion(id)) throw dtn::storage::BundleStorage::NoBundleFoundException();
00441 
00442                         size_t stmt_key = BUNDLE_GET_ID;
00443                         if (id.fragment) stmt_key = FRAGMENT_GET_ID;
00444 
00445                         // lock the prepared statement
00446                         Statement st(_database, _sql_queries[stmt_key]);
00447 
00448                         // bind bundle id to the statement
00449                         set_bundleid(st, id);
00450 
00451                         // execute the query and check for error
00452                         if (st.step() != SQLITE_ROW)
00453                         {
00454                                 stringstream error;
00455                                 error << "SQLiteDatabase: No Bundle found with BundleID: " << id.toString();
00456                                 IBRCOMMON_LOGGER_DEBUG(15) << error.str() << IBRCOMMON_LOGGER_ENDL;
00457                                 throw SQLiteQueryException(error.str());
00458                         }
00459 
00460                         // query bundle data
00461                         get(st, meta);
00462                 }
00463 
00464                 void SQLiteDatabase::get(Statement &st, dtn::data::MetaBundle &bundle, size_t offset) const
00465                 {
00466                         bundle.source = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 0) );
00467                         bundle.destination = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 1) );
00468                         bundle.reportto = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 2) );
00469                         bundle.custodian = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 3) );
00470                         bundle.procflags = sqlite3_column_int(*st, offset + 4);
00471                         bundle.timestamp = sqlite3_column_int64(*st, offset + 5);
00472                         bundle.sequencenumber = sqlite3_column_int64(*st, offset + 6);
00473                         bundle.lifetime = sqlite3_column_int64(*st, offset + 7);
00474                         bundle.expiretime = dtn::utils::Clock::getExpireTime(bundle.timestamp, bundle.lifetime);
00475 
00476                         if (bundle.procflags & data::Bundle::FRAGMENT)
00477                         {
00478                                 bundle.offset = sqlite3_column_int64(*st, offset + 8);
00479                                 bundle.appdatalength = sqlite3_column_int64(*st, offset + 9);
00480                         }
00481 
00482                         if (sqlite3_column_type(*st, offset + 10) != SQLITE_NULL)
00483                         {
00484                                 bundle.hopcount = sqlite3_column_int64(*st, 10);
00485                         }
00486 
00487                         bundle.payloadlength = sqlite3_column_int64(*st, 11);
00488                 }
00489 
00490                 void SQLiteDatabase::get(Statement &st, dtn::data::Bundle &bundle, size_t offset) const
00491                 {
00492                         bundle._source = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 0) );
00493                         bundle._destination = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 1) );
00494                         bundle._reportto = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 2) );
00495                         bundle._custodian = dtn::data::EID( (const char*) sqlite3_column_text(*st, offset + 3) );
00496                         bundle._procflags = sqlite3_column_int(*st, offset + 4);
00497                         bundle._timestamp = sqlite3_column_int64(*st, offset + 5);
00498                         bundle._sequencenumber = sqlite3_column_int64(*st, offset + 6);
00499                         bundle._lifetime = sqlite3_column_int64(*st, offset + 7);
00500 
00501                         if (bundle._procflags & data::Bundle::FRAGMENT)
00502                         {
00503                                 bundle._fragmentoffset = sqlite3_column_int64(*st, offset + 8);
00504                                 bundle._appdatalength = sqlite3_column_int64(*st, offset + 9);
00505                         }
00506                 }
00507 
00508                 const std::list<dtn::data::MetaBundle> SQLiteDatabase::get(dtn::storage::BundleStorage::BundleFilterCallback &cb) const
00509                 {
00510                         std::list<dtn::data::MetaBundle> ret;
00511 
00512                         const std::string base_query =
00513                                         "SELECT source, destination, reportto, custodian, procflags, timestamp, sequencenumber, lifetime, fragmentoffset, appdatalength, hopcount, payloadlength FROM " + _tables[SQL_TABLE_BUNDLE];
00514 
00515                         size_t offset = 0;
00516                         bool unlimited = (cb.limit() <= 0);
00517                         size_t query_limit = (cb.limit() > 0) ? cb.limit() : 10;
00518 
00519                         try {
00520                                 try {
00521                                         SQLBundleQuery &query = dynamic_cast<SQLBundleQuery&>(cb);
00522 
00523                                         // custom query string
00524                                         std::string query_string = base_query + " WHERE " + query.getWhere() + " ORDER BY priority DESC LIMIT ?,?;";
00525 
00526                                         // create statement for custom query
00527                                         Statement st(_database, query_string);
00528 
00529                                         while (unlimited || (ret.size() < query_limit))
00530                                         {
00531                                                 // bind the statement parameter
00532                                                 size_t bind_offset = query.bind(*st, 1);
00533 
00534                                                 // query the database
00535                                                 __get(cb, st, ret, bind_offset, offset);
00536 
00537                                                 // increment the offset, because we might not have enough
00538                                                 offset += query_limit;
00539                                         }
00540                                 } catch (const std::bad_cast&) {
00541                                         Statement st(_database, _sql_queries[BUNDLE_GET_FILTER]);
00542 
00543                                         while (unlimited || (ret.size() < query_limit))
00544                                         {
00545                                                 // query the database
00546                                                 __get(cb, st, ret, 1, offset);
00547 
00548                                                 // increment the offset, because we might not have enough
00549                                                 offset += query_limit;
00550                                         }
00551                                 }
00552                         } catch (const dtn::storage::BundleStorage::NoBundleFoundException&) { }
00553 
00554                         return ret;
00555                 }
00556 
00557                 void SQLiteDatabase::__get(const dtn::storage::BundleStorage::BundleFilterCallback &cb, Statement &st, std::list<dtn::data::MetaBundle> &ret, size_t bind_offset, size_t offset) const
00558                 {
00559                         bool unlimited = (cb.limit() <= 0);
00560                         size_t query_limit = (cb.limit() > 0) ? cb.limit() : 10;
00561 
00562                         // limit result according to callback result
00563                         sqlite3_bind_int64(*st, bind_offset, offset);
00564                         sqlite3_bind_int64(*st, bind_offset + 1, query_limit);
00565 
00566                         // returned no result
00567                         if (st.step() == SQLITE_DONE)
00568                                 throw dtn::storage::BundleStorage::NoBundleFoundException();
00569 
00570                         // abort if enough bundles are found
00571                         while (unlimited || (ret.size() < query_limit))
00572                         {
00573                                 dtn::data::MetaBundle m;
00574 
00575                                 // extract the primary values and set them in the bundle object
00576                                 get(st, m, 0);
00577 
00578                                 // check if the bundle is already on the deletion list
00579                                 if (!contains_deletion(m))
00580                                 {
00581                                         // ask the filter if this bundle should be added to the return list
00582                                         if (cb.shouldAdd(m))
00583                                         {
00584                                                 IBRCOMMON_LOGGER_DEBUG(40) << "add bundle to query selection list: " << m.toString() << IBRCOMMON_LOGGER_ENDL;
00585 
00586                                                 // add the bundle to the list
00587                                                 ret.push_back(m);
00588                                         }
00589                                 }
00590 
00591                                 if (st.step() != SQLITE_ROW) break;
00592                         }
00593 
00594                         st.reset();
00595                 }
00596 
00597                 void SQLiteDatabase::get(const dtn::data::BundleID &id, dtn::data::Bundle &bundle, blocklist &blocks) const
00598                 {
00599                         int err = 0;
00600 
00601                         IBRCOMMON_LOGGER_DEBUG(25) << "get bundle from sqlite storage " << id.toString() << IBRCOMMON_LOGGER_ENDL;
00602 
00603                         // if bundle is deleted?
00604                         if (contains_deletion(id)) throw dtn::storage::BundleStorage::NoBundleFoundException();
00605 
00606                         size_t stmt_key = BUNDLE_GET_ID;
00607                         if (id.fragment) stmt_key = FRAGMENT_GET_ID;
00608 
00609                         // do this while db is locked
00610                         Statement st(_database, _sql_queries[stmt_key]);
00611 
00612                         // set the bundle key values
00613                         set_bundleid(st, id);
00614 
00615                         // execute the query and check for error
00616                         if ((err = st.step()) != SQLITE_ROW)
00617                         {
00618                                 IBRCOMMON_LOGGER_DEBUG(15) << "sql error: " << err << "; No bundle found with id: " << id.toString() << IBRCOMMON_LOGGER_ENDL;
00619                                 throw dtn::storage::BundleStorage::NoBundleFoundException();
00620                         }
00621 
00622                         // read bundle data
00623                         get(st, bundle);
00624 
00625                         try {
00626 
00627                                 int err = 0;
00628                                 string file;
00629 
00630                                 // select the right statement to use
00631                                 const size_t stmt_key = id.fragment ? BLOCK_GET_ID_FRAGMENT : BLOCK_GET_ID;
00632 
00633                                 Statement st(_database, _sql_queries[stmt_key]);
00634 
00635                                 // set the bundle key values
00636                                 set_bundleid(st, id);
00637 
00638                                 // query the database and step through all blocks
00639                                 while ((err = st.step()) == SQLITE_ROW)
00640                                 {
00641                                         const ibrcommon::File f( (const char*) sqlite3_column_text(*st, 0) );
00642                                         int blocktyp = sqlite3_column_int(*st, 1);
00643 
00644                                         blocks.push_back( blocklist_entry(blocktyp, f) );
00645                                 }
00646 
00647                                 if (err == SQLITE_DONE)
00648                                 {
00649                                         if (blocks.size() == 0)
00650                                         {
00651                                                 IBRCOMMON_LOGGER(error) << "get_blocks: no blocks found for: " << id.toString() << IBRCOMMON_LOGGER_ENDL;
00652                                                 throw SQLiteQueryException("no blocks found");
00653                                         }
00654                                 }
00655                                 else
00656                                 {
00657                                         IBRCOMMON_LOGGER(error) << "get_blocks() failure: "<< err << " " << sqlite3_errmsg(_database) << IBRCOMMON_LOGGER_ENDL;
00658                                         throw SQLiteQueryException("can not query for blocks");
00659                                 }
00660 
00661                         } catch (const ibrcommon::Exception &ex) {
00662                                 IBRCOMMON_LOGGER(error) << "could not get bundle blocks: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
00663                                 throw dtn::storage::BundleStorage::NoBundleFoundException();
00664                         }
00665                 }
00666 
00667                 void SQLiteDatabase::store(const dtn::data::Bundle &bundle)
00668                 {
00669                         int err;
00670 
00671                         const dtn::data::EID _sourceid = bundle._source;
00672                         size_t TTL = bundle._timestamp + bundle._lifetime;
00673 
00674                         Statement st(_database, _sql_queries[BUNDLE_STORE]);
00675 
00676                         set_bundleid(st, bundle);
00677 
00678                         sqlite3_bind_text(*st, 5, bundle._source.getString().c_str(), bundle._source.getString().length(), SQLITE_TRANSIENT);
00679                         sqlite3_bind_text(*st, 6, bundle._destination.getString().c_str(), bundle._destination.getString().length(), SQLITE_TRANSIENT);
00680                         sqlite3_bind_text(*st, 7, bundle._reportto.getString().c_str(), bundle._reportto.getString().length(), SQLITE_TRANSIENT);
00681                         sqlite3_bind_text(*st, 8, bundle._custodian.getString().c_str(), bundle._custodian.getString().length(), SQLITE_TRANSIENT);
00682                         sqlite3_bind_int(*st, 9, bundle._procflags);
00683                         sqlite3_bind_int64(*st, 10, bundle._lifetime);
00684 
00685                         if (bundle.get(dtn::data::Bundle::FRAGMENT))
00686                         {
00687                                 sqlite3_bind_int64(*st, 11, bundle._appdatalength);
00688                         }
00689                         else
00690                         {
00691                                 sqlite3_bind_null(*st, 4);
00692                                 sqlite3_bind_null(*st, 11);
00693                         }
00694 
00695                         sqlite3_bind_int64(*st, 12, TTL);
00696                         sqlite3_bind_int64(*st, 13, dtn::data::MetaBundle(bundle).getPriority());
00697 
00698                         try {
00699                                 const dtn::data::ScopeControlHopLimitBlock &schl = bundle.getBlock<const dtn::data::ScopeControlHopLimitBlock>();
00700                                 sqlite3_bind_int64(*st, 14, schl.getHopsToLive() );
00701                         } catch (const dtn::data::Bundle::NoSuchBlockFoundException&) {
00702                                 sqlite3_bind_null(*st, 14 );
00703                         };
00704 
00705                         try {
00706                                 const dtn::data::PayloadBlock &pblock = bundle.getBlock<const dtn::data::PayloadBlock>();
00707                                 sqlite3_bind_int64(*st, 15, pblock.getLength() );
00708                         } catch (const dtn::data::Bundle::NoSuchBlockFoundException&) {
00709                                 sqlite3_bind_int64(*st, 15, 0 );
00710                         };
00711 
00712                         err = st.step();
00713 
00714                         if (err == SQLITE_CONSTRAINT)
00715                         {
00716                                 IBRCOMMON_LOGGER(warning) << "Bundle is already in the storage" << IBRCOMMON_LOGGER_ENDL;
00717 
00718                                 stringstream error;
00719                                 error << "SQLiteDatabase: store() failure: " << err << " " <<  sqlite3_errmsg(_database);
00720                                 throw SQLiteQueryException(error.str());
00721                         }
00722                         else if (err != SQLITE_DONE)
00723                         {
00724                                 stringstream error;
00725                                 error << "SQLiteDatabase: store() failure: " << err << " " <<  sqlite3_errmsg(_database);
00726                                 IBRCOMMON_LOGGER(error) << error.str() << IBRCOMMON_LOGGER_ENDL;
00727 
00728                                 throw SQLiteQueryException(error.str());
00729                         }
00730 
00731                         // set new expire time
00732                         new_expire_time(TTL);
00733                 }
00734 
00735                 void SQLiteDatabase::store(const dtn::data::BundleID &id, int index, const dtn::data::Block &block, const ibrcommon::File &file)
00736                 {
00737                         int blocktyp = (int)block.getType();
00738 
00739                         // protect this query from concurrent access and enable the auto-reset feature
00740                         Statement st(_database, _sql_queries[BLOCK_STORE]);
00741 
00742                         // set bundle key data
00743                         set_bundleid(st, id);
00744 
00745                         // set the column four to null if this is not a fragment
00746                         if (!id.fragment) sqlite3_bind_null(*st, 4);
00747 
00748                         // set the block type
00749                         sqlite3_bind_int(*st, 5, blocktyp);
00750 
00751                         // the filename of the block data
00752                         sqlite3_bind_text(*st, 6, file.getPath().c_str(), file.getPath().size(), SQLITE_TRANSIENT);
00753 
00754                         // the ordering number
00755                         sqlite3_bind_int(*st, 7, index);
00756 
00757                         // execute the query and store the block in the database
00758                         if (st.step() != SQLITE_DONE)
00759                         {
00760                                 throw SQLiteQueryException("can not store block of bundle");
00761                         }
00762                 }
00763 
00764                 void SQLiteDatabase::transaction()
00765                 {
00766                         // start a transaction
00767                         sqlite3_exec(_database, "BEGIN TRANSACTION;", NULL, NULL, NULL);
00768                 }
00769 
00770                 void SQLiteDatabase::rollback()
00771                 {
00772                         // rollback the whole transaction
00773                         sqlite3_exec(_database, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
00774                 }
00775 
00776                 void SQLiteDatabase::commit()
00777                 {
00778                         // commit the transaction
00779                         sqlite3_exec(_database, "END TRANSACTION;", NULL, NULL, NULL);
00780                 }
00781 
00782                 void SQLiteDatabase::remove(const dtn::data::BundleID &id)
00783                 {
00784                         {
00785                                 // select the right statement to use
00786                                 const size_t stmt_key = id.fragment ? BLOCK_GET_ID_FRAGMENT : BLOCK_GET_ID;
00787 
00788                                 // lock the database
00789                                 Statement st(_database, _sql_queries[stmt_key]);
00790 
00791                                 // set the bundle key values
00792                                 set_bundleid(st, id);
00793 
00794                                 // step through all blocks
00795                                 while (st.step() == SQLITE_ROW)
00796                                 {
00797                                         // delete each referenced block file
00798                                         ibrcommon::File blockfile( (const char*)sqlite3_column_text(*st, 0) );
00799                                         blockfile.remove();
00800                                 }
00801                         }
00802 
00803                         {
00804                                 const size_t stmt_key = id.fragment ? FRAGMENT_DELETE : BUNDLE_DELETE;
00805 
00806                                 // lock the database
00807                                 Statement st(_database, _sql_queries[stmt_key]);
00808 
00809                                 // then remove the bundle data
00810                                 set_bundleid(st, id);
00811                                 st.step();
00812 
00813                                 IBRCOMMON_LOGGER_DEBUG(10) << "bundle " << id.toString() << " deleted" << IBRCOMMON_LOGGER_ENDL;
00814                         }
00815 
00816                         //update deprecated timer
00817                         update_expire_time();
00818 
00819                         // remove it from the deletion list
00820                         remove_deletion(id);
00821                 }
00822 
00823                 void SQLiteDatabase::clear()
00824                 {
00825                         Statement vacuum(_database, _sql_queries[VACUUM]);
00826                         Statement bundle_clear(_database, _sql_queries[BUNDLE_CLEAR]);
00827                         Statement block_clear(_database, _sql_queries[BLOCK_CLEAR]);
00828 
00829                         bundle_clear.step();
00830                         block_clear.step();
00831 
00832                         if (SQLITE_DONE != vacuum.step())
00833                         {
00834                                 throw SQLiteQueryException("SQLiteBundleStore: clear(): vacuum failed.");
00835                         }
00836 
00837                         reset_expire_time();
00838                 }
00839 
00840                 bool SQLiteDatabase::empty() const
00841                 {
00842                         Statement st(_database, _sql_queries[EMPTY_CHECK]);
00843 
00844                         if (SQLITE_DONE == st.step())
00845                         {
00846                                 return true;
00847                         }
00848                         else
00849                         {
00850                                 return false;
00851                         }
00852                 }
00853 
00854                 unsigned int SQLiteDatabase::count() const
00855                 {
00856                         int rows = 0;
00857                         int err = 0;
00858 
00859                         Statement st(_database, _sql_queries[COUNT_ENTRIES]);
00860 
00861                         if ((err = st.step()) == SQLITE_ROW)
00862                         {
00863                                 rows = sqlite3_column_int(*st, 0);
00864                         }
00865                         else
00866                         {
00867                                 stringstream error;
00868                                 error << "SQLiteDatabase: count: failure " << err << " " << sqlite3_errmsg(_database);
00869                                 IBRCOMMON_LOGGER(error) << error.str() << IBRCOMMON_LOGGER_ENDL;
00870                                 throw SQLiteQueryException(error.str());
00871                         }
00872 
00873                         return rows;
00874                 }
00875 
00876                 const std::set<dtn::data::EID> SQLiteDatabase::getDistinctDestinations()
00877                 {
00878                         std::set<dtn::data::EID> ret;
00879                         return ret;
00880                 }
00881 
00882                 void SQLiteDatabase::update_expire_time()
00883                 {
00884                         Statement st(_database, _sql_queries[EXPIRE_NEXT_TIMESTAMP]);
00885 
00886                         int err = st.step();
00887 
00888                         if (err == SQLITE_ROW)
00889                         {
00890                                 _next_expiration = sqlite3_column_int64(*st, 0);
00891                         }
00892                         else
00893                         {
00894                                 _next_expiration = 0;
00895                         }
00896                 }
00897 
00898                 void SQLiteDatabase::expire(size_t timestamp)
00899                 {
00900                         /*
00901                          * Only if the actual time is bigger or equal than the time when the next bundle expires, deleteexpired is called.
00902                          */
00903                         size_t exp_time = get_expire_time();
00904                         if ((timestamp < exp_time) || (exp_time == 0)) return;
00905 
00906                         /*
00907                          * Performanceverbesserung: Damit die Abfragen nicht jede Sekunde ausgeführt werden müssen, speichert man den Zeitpunkt an dem
00908                          * 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.
00909                          * Nach dem Löschen wird die DB durchsucht und der nächste Ablaufzeitpunkt wird in die Variable gesetzt.
00910                          */
00911 
00912                         {
00913                                 Statement st(_database, _sql_queries[EXPIRE_BUNDLE_FILENAMES]);
00914 
00915                                 // query for blocks of expired bundles
00916                                 sqlite3_bind_int64(*st, 1, timestamp);
00917                                 while (st.step() == SQLITE_ROW)
00918                                 {
00919                                         ibrcommon::File block((const char*)sqlite3_column_text(*st,0));
00920                                         block.remove();
00921                                 }
00922                         }
00923 
00924                         {
00925                                 Statement st(_database, _sql_queries[EXPIRE_BUNDLES]);
00926 
00927                                 // query expired bundles
00928                                 sqlite3_bind_int64(*st, 1, timestamp);
00929                                 while (st.step() == SQLITE_ROW)
00930                                 {
00931                                         dtn::data::BundleID id;
00932                                         get_bundleid(st, id);
00933                                         dtn::core::BundleExpiredEvent::raise(id);
00934                                 }
00935                         }
00936 
00937                         {
00938                                 Statement st(_database, _sql_queries[EXPIRE_BUNDLE_DELETE]);
00939 
00940                                 // delete all expired db entries (bundles and blocks)
00941                                 sqlite3_bind_int64(*st, 1, timestamp);
00942                                 st.step();
00943                         }
00944 
00945                         //update deprecated timer
00946                         update_expire_time();
00947                 }
00948 
00949                 void SQLiteDatabase::vacuum()
00950                 {
00951                         Statement st(_database, _sql_queries[VACUUM]);
00952                         st.step();
00953                 }
00954 
00955                 void SQLiteDatabase::update(UPDATE_VALUES mode, const dtn::data::BundleID &id, const dtn::data::EID &eid)
00956                 {
00957                         if (mode == UPDATE_CUSTODIAN)
00958                         {
00959                                 // select query with or without fragmentation extension
00960                                 STORAGE_STMT query = BUNDLE_UPDATE_CUSTODIAN;
00961                                 if (id.fragment)        query = FRAGMENT_UPDATE_CUSTODIAN;
00962 
00963                                 Statement st(_database, _sql_queries[query]);
00964 
00965                                 sqlite3_bind_text(*st, 1, eid.getString().c_str(), eid.getString().length(), SQLITE_TRANSIENT);
00966                                 set_bundleid(st, id, 1);
00967 
00968                                 // update the custodian in the database
00969                                 int err = st.step();
00970 
00971                                 if (err != SQLITE_DONE)
00972                                 {
00973                                         stringstream error;
00974                                         error << "SQLiteDatabase: update_custodian() failure: " << err << " " <<  sqlite3_errmsg(_database);
00975                                         IBRCOMMON_LOGGER(error) << error.str() << IBRCOMMON_LOGGER_ENDL;
00976                                 }
00977                         }
00978                 }
00979 
00980                 void SQLiteDatabase::new_expire_time(size_t ttl)
00981                 {
00982                         if (_next_expiration == 0 || ttl < _next_expiration)
00983                         {
00984                                 _next_expiration = ttl;
00985                         }
00986                 }
00987 
00988                 void SQLiteDatabase::reset_expire_time()
00989                 {
00990                         _next_expiration = 0;
00991                 }
00992 
00993                 size_t SQLiteDatabase::get_expire_time()
00994                 {
00995                         return _next_expiration;
00996                 }
00997 
00998                 void SQLiteDatabase::add_deletion(const dtn::data::BundleID &id)
00999                 {
01000                         _deletion_list.insert(id);
01001                 }
01002 
01003                 void SQLiteDatabase::remove_deletion(const dtn::data::BundleID &id)
01004                 {
01005                         _deletion_list.erase(id);
01006                 }
01007 
01008                 bool SQLiteDatabase::contains_deletion(const dtn::data::BundleID &id) const
01009                 {
01010                         return (_deletion_list.find(id) != _deletion_list.end());
01011                 }
01012 
01013                 void SQLiteDatabase::set_bundleid(Statement &st, const dtn::data::BundleID &id, size_t offset) const
01014                 {
01015                         const std::string source_id = id.source.getString();
01016                         sqlite3_bind_text(*st, offset + 1, source_id.c_str(), source_id.length(), SQLITE_TRANSIENT);
01017                         sqlite3_bind_int64(*st, offset + 2, id.timestamp);
01018                         sqlite3_bind_int64(*st, offset + 3, id.sequencenumber);
01019 
01020                         if (id.fragment)
01021                         {
01022                                 sqlite3_bind_int64(*st, offset + 4, id.offset);
01023                         }
01024                 }
01025 
01026                 void SQLiteDatabase::get_bundleid(Statement &st, dtn::data::BundleID &id, size_t offset) const
01027                 {
01028                         id.source = dtn::data::EID((const char*)sqlite3_column_text(*st, offset + 0));
01029                         id.timestamp = sqlite3_column_int64(*st, offset + 1);
01030                         id.sequencenumber = sqlite3_column_int64(*st, offset + 2);
01031 
01032                         id.fragment = (sqlite3_column_text(*st, offset + 3) != NULL);
01033                         id.offset = sqlite3_column_int64(*st, offset + 3);
01034                 }
01035         } /* namespace storage */
01036 } /* namespace dtn */