Remove dependency on Selectors and refactor codebase.
Change-Id: Ic3024b76ba0eea61f790c91c36090b4aa68702a3
Refs: #4522
diff --git a/src/storage/index.cpp b/src/storage/index.cpp
deleted file mode 100644
index 3eb2cce..0000000
--- a/src/storage/index.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2017, Regents of the University of California.
- *
- * This file is part of NDN repo-ng (Next generation of NDN repository).
- * See AUTHORS.md for complete list of repo-ng authors and contributors.
- *
- * repo-ng is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "index.hpp"
-
-#include <ndn-cxx/util/sha256.hpp>
-#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
-
-namespace repo {
-
-/** @brief determines if entry can satisfy interest
- * @param hash SHA256 hash of PublisherPublicKeyLocator if exists in interest, otherwise ignored
- */
-static bool
-matchesSimpleSelectors(const Interest& interest, ndn::ConstBufferPtr& hash,
- const Index::Entry& entry)
-{
- const Name& fullName = entry.getName();
-
- if (!interest.getName().isPrefixOf(fullName))
- return false;
-
- size_t nSuffixComponents = fullName.size() - interest.getName().size();
- if (interest.getMinSuffixComponents() >= 0 &&
- nSuffixComponents < static_cast<size_t>(interest.getMinSuffixComponents()))
- return false;
- if (interest.getMaxSuffixComponents() >= 0 &&
- nSuffixComponents > static_cast<size_t>(interest.getMaxSuffixComponents()))
- return false;
-
- if (!interest.getExclude().empty() &&
- entry.getName().size() > interest.getName().size() &&
- interest.getExclude().isExcluded(entry.getName()[interest.getName().size()]))
- return false;
- if (!interest.getPublisherPublicKeyLocator().empty())
- {
- if (*entry.getKeyLocatorHash() != *hash)
- return false;
- }
- return true;
-}
-
-Index::Index(size_t nMaxPackets)
- : m_maxPackets(nMaxPackets)
- , m_size(0)
-{
-}
-
-
-bool
-Index::insert(const Data& data, int64_t id)
-{
- if (isFull())
- BOOST_THROW_EXCEPTION(Error("The Index is Full. Cannot Insert Any Data!"));
- Entry entry(data, id);
- bool isInserted = m_indexContainer.insert(entry).second;
- if (isInserted)
- ++m_size;
- return isInserted;
-}
-
-bool
-Index::insert(const Name& fullName, int64_t id,
- const ndn::ConstBufferPtr& keyLocatorHash)
-{
- if (isFull())
- BOOST_THROW_EXCEPTION(Error("The Index is Full. Cannot Insert Any Data!"));
- Entry entry(fullName, keyLocatorHash, id);
- bool isInserted = m_indexContainer.insert(entry).second;
- if (isInserted)
- ++m_size;
- return isInserted;
-}
-
-std::pair<int64_t,Name>
-Index::find(const Interest& interest) const
-{
- Name name = interest.getName();
- IndexContainer::const_iterator result = m_indexContainer.lower_bound(name);
- if (result != m_indexContainer.end())
- {
- return selectChild(interest, result);
- }
- else
- {
- return std::make_pair(0, Name());
- }
-}
-
-std::pair<int64_t,Name>
-Index::find(const Name& name) const
-{
- IndexContainer::const_iterator result = m_indexContainer.lower_bound(name);
- if (result != m_indexContainer.end())
- {
- return findFirstEntry(name, result);
- }
- else
- {
- return std::make_pair(0, Name());
- }
-}
-
-bool
-Index::hasData(const Data& data) const
-{
- Index::Entry entry(data, -1); // the id number is useless
- IndexContainer::const_iterator result = m_indexContainer.find(entry);
- return result != m_indexContainer.end();
-
-}
-
-std::pair<int64_t,Name>
-Index::findFirstEntry(const Name& prefix,
- IndexContainer::const_iterator startingPoint) const
-{
- BOOST_ASSERT(startingPoint != m_indexContainer.end());
- if (prefix.isPrefixOf(startingPoint->getName()))
- {
- return std::make_pair(startingPoint->getId(), startingPoint->getName());
- }
- else
- {
- return std::make_pair(0, Name());
- }
-}
-
-bool
-Index::erase(const Name& fullName)
-{
- Entry entry(fullName);
- IndexContainer::const_iterator findIterator = m_indexContainer.find(entry);
- if (findIterator != m_indexContainer.end())
- {
- m_indexContainer.erase(findIterator);
- m_size--;
- return true;
- }
- else
- return false;
-}
-
-const ndn::ConstBufferPtr
-Index::computeKeyLocatorHash(const KeyLocator& keyLocator)
-{
- const Block& block = keyLocator.wireEncode();
- ndn::ConstBufferPtr keyLocatorHash = ndn::util::Sha256::computeDigest(block.wire(), block.size());
- return keyLocatorHash;
-}
-
-std::pair<int64_t,Name>
-Index::selectChild(const Interest& interest,
- IndexContainer::const_iterator startingPoint) const
-{
- BOOST_ASSERT(startingPoint != m_indexContainer.end());
- bool isLeftmost = (interest.getChildSelector() <= 0);
- ndn::ConstBufferPtr hash;
- if (!interest.getPublisherPublicKeyLocator().empty())
- {
- KeyLocator keyLocator = interest.getPublisherPublicKeyLocator();
- const Block& block = keyLocator.wireEncode();
- hash = ndn::util::Sha256::computeDigest(block.wire(), block.size());
- }
-
- if (isLeftmost)
- {
- for (IndexContainer::const_iterator it = startingPoint;
- it != m_indexContainer.end(); ++it)
- {
- if (!interest.getName().isPrefixOf(it->getName()))
- return std::make_pair(0, Name());
- if (matchesSimpleSelectors(interest, hash, (*it)))
- return std::make_pair(it->getId(), it->getName());
- }
- }
- else
- {
- IndexContainer::const_iterator boundary = m_indexContainer.lower_bound(interest.getName());
- if (boundary == m_indexContainer.end() || !interest.getName().isPrefixOf(boundary->getName()))
- return std::make_pair(0, Name());
- Name successor = interest.getName().getSuccessor();
- IndexContainer::const_iterator last = interest.getName().size() == 0 ?
- m_indexContainer.end() : m_indexContainer.lower_bound(interest.getName().getSuccessor());
- while (true)
- {
- IndexContainer::const_iterator prev = last;
- --prev;
- if (prev == boundary)
- {
- bool isMatch = matchesSimpleSelectors(interest, hash, (*prev));
- if (isMatch)
- {
- return std::make_pair(prev->getId(), prev->getName());
- }
- else
- return std::make_pair(0, Name());
- }
- IndexContainer::const_iterator first =
- m_indexContainer.lower_bound(prev->getName().getPrefix(interest.getName().size() + 1));
- IndexContainer::const_iterator match =
- std::find_if(first, last, bind(&matchesSimpleSelectors, interest, hash, _1));
- if (match != last)
- {
- return std::make_pair(match->getId(), match->getName());
- }
- last = first;
- }
- }
- return std::make_pair(0, Name());
-}
-
-Index::Entry::Entry(const Data& data, int64_t id)
- : m_name(data.getFullName())
- , m_id(id)
-{
- const ndn::Signature& signature = data.getSignature();
- if (signature.hasKeyLocator())
- m_keyLocatorHash = computeKeyLocatorHash(signature.getKeyLocator());
-}
-
-Index::Entry::Entry(const Name& fullName, const KeyLocator& keyLocator, int64_t id)
- : m_name(fullName)
- , m_keyLocatorHash(computeKeyLocatorHash(keyLocator))
- , m_id(id)
-{
-}
-
-Index::Entry::Entry(const Name& fullName,
- const ndn::ConstBufferPtr& keyLocatorHash, int64_t id)
- : m_name(fullName)
- , m_keyLocatorHash(keyLocatorHash)
- , m_id(id)
-{
-}
-
-Index::Entry::Entry(const Name& name)
- : m_name(name)
-{
-}
-
-} // namespace repo
diff --git a/src/storage/index.hpp b/src/storage/index.hpp
deleted file mode 100644
index d60bd37..0000000
--- a/src/storage/index.hpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2018, Regents of the University of California.
- *
- * This file is part of NDN repo-ng (Next generation of NDN repository).
- * See AUTHORS.md for complete list of repo-ng authors and contributors.
- *
- * repo-ng is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef REPO_STORAGE_INDEX_HPP
-#define REPO_STORAGE_INDEX_HPP
-
-#include "../common.hpp"
-
-#include <set>
-
-namespace repo {
-
-class Index : noncopyable
-{
-public:
- class Error : public std::runtime_error
- {
- public:
- explicit
- Error(const std::string& what)
- : std::runtime_error(what)
- {
- }
- };
-
- class Entry
- {
- public:
- class Error : public std::runtime_error
- {
- public:
- explicit
- Error(const std::string& what)
- : std::runtime_error(what)
- {
- }
- };
-
- public:
- /**
- * @brief used by set to construct node
- */
- Entry() = default;
-
- /**
- * @brief construct Entry by data and id number
- */
- Entry(const Data& data, int64_t id);
-
- /**
- * @brief construct Entry by fullName, keyLocator and id number
- */
- Entry(const Name& fullName, const KeyLocator& keyLocator, int64_t id);
-
- /**
- * @brief construct Entry by fullName, keyLocatorHash and id number
- * @param fullName full name with digest computed from data
- * @param keyLocatorHash keyLocator hashed by sha256
- * @param id record ID from database
- */
- Entry(const Name& fullName, const ndn::ConstBufferPtr& keyLocatorHash, int64_t id);
-
- /**
- * @brief implicit construct Entry by full name
- *
- * Allow implicit conversion from Name for set lookups by Name
- */
- Entry(const Name& name);
-
- /**
- * @brief get the name of entry
- */
- const Name&
- getName() const
- {
- return m_name;
- }
-
- /**
- * @brief get the keyLocator hash value of the entry
- */
- const ndn::ConstBufferPtr&
- getKeyLocatorHash() const
- {
- return m_keyLocatorHash;
- }
-
- /**
- * @brief get record ID from database
- */
- int64_t
- getId() const
- {
- return m_id;
- }
-
- bool
- operator>(const Entry& entry) const
- {
- return m_name > entry.getName();
- }
-
- bool
- operator<(const Entry& entry) const
- {
- return m_name < entry.getName();
- }
-
- bool
- operator==(const Entry& entry) const
- {
- return m_name == entry.getName();
- }
-
- bool
- operator!=(const Entry& entry) const
- {
- return m_name != entry.getName();
- }
-
- private:
- Name m_name;
- ndn::ConstBufferPtr m_keyLocatorHash;
- int64_t m_id;
- };
-
-private:
- typedef std::set<Entry> IndexContainer;
-
-public:
- explicit
- Index(size_t nMaxPackets);
-
- /**
- * @brief insert entries into index
- * @param data used to construct entries
- * @param id obtained from database
- */
- bool
- insert(const Data& data, int64_t id);
-
- /**
- * @brief insert entries into index
- * @param data used to construct entries
- * @param id obtained from database
- */
- bool
- insert(const Name& fullName, int64_t id,
- const ndn::ConstBufferPtr& keyLocatorHash);
-
- /**
- * @brief erase the entry in index by its fullname
- */
- bool
- erase(const Name& fullName);
-
- /** @brief find the Entry for best match of an Interest
- * @return ID and fullName of the Entry, or (0,ignored) if not found
- */
- std::pair<int64_t, Name>
- find(const Interest& interest) const;
-
- /** @brief find the first Entry under a Name prefix
- * @return ID and fullName of the Entry, or (0,ignored) if not found
- */
- std::pair<int64_t, Name>
- find(const Name& name) const;
-
- /**
- * @brief determine whether same Data is already in the index
- * @return true if identical Data exists, false otherwise
- */
- bool
- hasData(const Data& data) const;
-
- /**
- * @brief compute the hash value of keyLocator
- */
- static const ndn::ConstBufferPtr
- computeKeyLocatorHash(const KeyLocator& keyLocator);
-
- size_t
- size() const
- {
- return m_size;
- }
-
-private:
- /**
- * @brief select entries which satisfy the selectors in interest and return their name
- * @param interest used to select entries by comparing the name and checking selectors
- * @param idName save the id and name of found entries
- * @param startingPoint the entry whose name is equal or larger than the interest name
- */
- std::pair<int64_t, Name>
- selectChild(const Interest& interest,
- IndexContainer::const_iterator startingPoint) const;
-
- /**
- * @brief check whether the index is full
- */
- bool
- isFull() const
- {
- return m_size >= m_maxPackets;
- }
-
- /**
- * @brief find the first entry with the prefix
- * @param prefix used to request the entries
- * @param startingPoint the entry whose name is equal or larger than the interest name
- * @return int64_t the id number of found entry
- * @return Name the name of found entry
- */
- std::pair<int64_t, Name>
- findFirstEntry(const Name& prefix,
- IndexContainer::const_iterator startingPoint) const;
-
-private:
- IndexContainer m_indexContainer;
- size_t m_maxPackets;
- size_t m_size;
-};
-
-} // namespace repo
-
-#endif // REPO_STORAGE_INDEX_HPP
diff --git a/src/storage/repo-storage.cpp b/src/storage/repo-storage.cpp
index 148116b..334b4d3 100644
--- a/src/storage/repo-storage.cpp
+++ b/src/storage/repo-storage.cpp
@@ -28,62 +28,52 @@
NDN_LOG_INIT(repo.RepoStorage);
-RepoStorage::RepoStorage(const int64_t& nMaxPackets, Storage& store)
- : m_index(nMaxPackets)
- , m_storage(store)
+RepoStorage::RepoStorage(Storage& store)
+ : m_storage(store)
{
}
-void
-RepoStorage::initialize()
-{
- NDN_LOG_DEBUG("Initialize");
- m_storage.fullEnumerate(bind(&RepoStorage::insertItemToIndex, this, _1));
-}
-
-void
-RepoStorage::insertItemToIndex(const Storage::ItemMeta& item)
-{
- NDN_LOG_DEBUG("Insert data to index " << item.fullName);
- m_index.insert(item.fullName, item.id, item.keyLocatorHash);
- afterDataInsertion(item.fullName);
-}
-
bool
RepoStorage::insertData(const Data& data)
{
- bool isExist = m_index.hasData(data);
- if (isExist)
- BOOST_THROW_EXCEPTION(Error("The Entry Has Already In the Skiplist. Cannot be Inserted!"));
- int64_t id = m_storage.insert(data);
- if (id == -1)
- return false;
- bool didInsert = m_index.insert(data, id);
- if (didInsert)
- afterDataInsertion(data.getName());
- return didInsert;
+ bool isExist = m_storage.has(data.getFullName());
+
+ if (isExist) {
+ NDN_LOG_DEBUG("Data already in storage, regarded as successful data insertion");
+ return true;
+ }
+
+ int64_t id = m_storage.insert(data);
+ NDN_LOG_DEBUG("Insert ID: " << id << ", full name:" << data.getFullName());
+ if (id == NOTFOUND)
+ return false;
+
+ afterDataInsertion(data.getName());
+ return true;
}
ssize_t
RepoStorage::deleteData(const Name& name)
{
+ NDN_LOG_DEBUG("Delete: " << name);
bool hasError = false;
- std::pair<int64_t,ndn::Name> idName = m_index.find(name);
- if (idName.first == 0)
- return false;
+
int64_t count = 0;
- while (idName.first != 0) {
- bool resultDb = m_storage.erase(idName.first);
- bool resultIndex = m_index.erase(idName.second); //full name
- if (resultDb && resultIndex) {
- afterDataDeletion(idName.second);
+ std::shared_ptr<Data> foundData;
+ Name foundName;
+ while ((foundData = m_storage.find(name))) {
+ foundName = foundData->getFullName();
+ bool resultDb = m_storage.erase(foundName);
+ if (resultDb) {
+ afterDataDeletion(foundName);
count++;
}
else {
hasError = true;
}
- idName = m_index.find(name);
+ NDN_LOG_DEBUG("Delete: " << name << ", found " << foundName << ", count " << count << ", result " << resultDb);
}
+
if (hasError)
return -1;
else
@@ -93,40 +83,15 @@
ssize_t
RepoStorage::deleteData(const Interest& interest)
{
- Interest interestDelete = interest;
- interestDelete.setChildSelector(0); //to disable the child selector in delete handle
- int64_t count = 0;
- bool hasError = false;
- std::pair<int64_t,ndn::Name> idName = m_index.find(interestDelete);
- while (idName.first != 0) {
- bool resultDb = m_storage.erase(idName.first);
- bool resultIndex = m_index.erase(idName.second); //full name
- if (resultDb && resultIndex) {
- afterDataDeletion(idName.second);
- count++;
- }
- else {
- hasError = true;
- }
- idName = m_index.find(interestDelete);
- }
- if (hasError)
- return -1;
- else
- return count;
+ return deleteData(interest.getName());
}
-shared_ptr<Data>
+std::shared_ptr<Data>
RepoStorage::readData(const Interest& interest) const
{
- std::pair<int64_t,ndn::Name> idName = m_index.find(interest);
- if (idName.first != 0) {
- shared_ptr<Data> data = m_storage.read(idName.first);
- if (data) {
- return data;
- }
- }
- return shared_ptr<Data>();
+ NDN_LOG_DEBUG("Reading data for " << interest.getName());
+
+ return m_storage.read(interest.getName());
}
diff --git a/src/storage/repo-storage.hpp b/src/storage/repo-storage.hpp
index ec5faa7..39e576d 100644
--- a/src/storage/repo-storage.hpp
+++ b/src/storage/repo-storage.hpp
@@ -22,10 +22,8 @@
#include "../common.hpp"
#include "storage.hpp"
-#include "index.hpp"
#include "../repo-command-parameter.hpp"
-#include <ndn-cxx/exclude.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <queue>
@@ -50,13 +48,7 @@
};
public:
- RepoStorage(const int64_t& nMaxPackets, Storage& store);
-
- /**
- * @brief rebuild index from database
- */
- void
- initialize();
+ RepoStorage(Storage& store);
/**
* @brief insert data into repo
@@ -66,7 +58,7 @@
/**
* @brief delete data from repo
- * @param name used to find entry needed to be erased in repo
+ * @param name from interest, use it as a prefix to find entry needed to be erased in repo
* @return if deletion in either index or database fail, return -1,
* otherwise return the number of erased entries
*/
@@ -83,24 +75,20 @@
deleteData(const Interest& interest);
/**
- * @brief read data from repo
+ * @brief read data from repo
* @param interest used to request data
* @return std::shared_ptr<Data>
*/
std::shared_ptr<Data>
readData(const Interest& interest) const;
-private:
- void
- insertItemToIndex(const Storage::ItemMeta& item);
-
public:
ndn::util::Signal<RepoStorage, ndn::Name> afterDataInsertion;
ndn::util::Signal<RepoStorage, ndn::Name> afterDataDeletion;
private:
- Index m_index;
Storage& m_storage;
+ const int NOTFOUND = -1;
};
} // namespace repo
diff --git a/src/storage/sqlite-storage.cpp b/src/storage/sqlite-storage.cpp
index 42739c3..91016ea 100644
--- a/src/storage/sqlite-storage.cpp
+++ b/src/storage/sqlite-storage.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
*
* This file is part of NDN repo-ng (Next generation of NDN repository).
* See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -19,23 +19,25 @@
#include "sqlite-storage.hpp"
#include "config.hpp"
-#include "index.hpp"
#include <ndn-cxx/util/sha256.hpp>
+#include <ndn-cxx/util/sqlite3-statement.hpp>
+
#include <boost/filesystem.hpp>
#include <istream>
+#include <ndn-cxx/util/logger.hpp>
+
namespace repo {
-using std::string;
+NDN_LOG_INIT(repo.SqliteStorage);
-SqliteStorage::SqliteStorage(const string& dbPath)
- : m_size(0)
+SqliteStorage::SqliteStorage(const std::string& dbPath)
{
if (dbPath.empty()) {
- std::cerr << "Create db file in local location [" << dbPath << "]. " << std::endl
- << "You can assign the path using -d option" << std::endl;
- m_dbPath = string("ndn_repo.db");
+ m_dbPath = std::string("ndn_repo.db");
+ NDN_LOG_DEBUG("Create db file in local location [" << m_dbPath << "]. " );
+ NDN_LOG_DEBUG("You can assign the path using -d option" );
}
else {
boost::filesystem::path fsPath(dbPath);
@@ -55,32 +57,31 @@
void
SqliteStorage::initializeRepo()
{
- char* errMsg = 0;
-
+ char* errMsg = nullptr;
int rc = sqlite3_open_v2(m_dbPath.c_str(), &m_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
#ifdef DISABLE_SQLITE3_FS_LOCKING
"unix-dotfile"
#else
- 0
+ nullptr
#endif
- );
+ );
if (rc == SQLITE_OK) {
- sqlite3_exec(m_db, "CREATE TABLE NDN_REPO ("
- "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "
- "name BLOB, "
- "data BLOB, "
- "keylocatorHash BLOB);\n "
- , 0, 0, &errMsg);
+ // Create a new table named NDN_REPO_V2, distinguish from the old table name(NDN_REPO)
+ sqlite3_exec(m_db, "CREATE TABLE NDN_REPO_V2 (name BLOB, data BLOB);", nullptr, nullptr, &errMsg);
// Ignore errors (when database already exists, errors are expected)
+ sqlite3_exec(m_db, "CREATE UNIQUE INDEX index_name ON NDN_REPO_V2 (name);", nullptr, nullptr, &errMsg);
}
else {
- std::cerr << "Database file open failure rc:" << rc << std::endl;
+ NDN_LOG_DEBUG("Database file open failure rc:" << rc);
BOOST_THROW_EXCEPTION(Error("Database file open failure"));
}
- sqlite3_exec(m_db, "PRAGMA synchronous = OFF", 0, 0, &errMsg);
- sqlite3_exec(m_db, "PRAGMA journal_mode = WAL", 0, 0, &errMsg);
+
+ // SQLite continues without syncing as soon as it has handed data off to the operating system
+ sqlite3_exec(m_db, "PRAGMA synchronous = OFF;", nullptr, nullptr, &errMsg);
+ // Uses a write-ahead log instead of a rollback journal to implement transactions.
+ sqlite3_exec(m_db, "PRAGMA journal_mode = WAL;", nullptr, nullptr, &errMsg);
}
SqliteStorage::~SqliteStorage()
@@ -88,211 +89,158 @@
sqlite3_close(m_db);
}
-void
-SqliteStorage::fullEnumerate(const std::function<void(const Storage::ItemMeta)>& f)
-{
- sqlite3_stmt* m_stmt = 0;
- int rc = SQLITE_DONE;
- string sql = string("SELECT id, name, keylocatorHash FROM NDN_REPO;");
- rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &m_stmt, 0);
- if (rc != SQLITE_OK)
- BOOST_THROW_EXCEPTION(Error("Initiation Read Entries from Database Prepare error"));
- int entryNumber = 0;
- while (true) {
- rc = sqlite3_step(m_stmt);
- if (rc == SQLITE_ROW) {
-
- ItemMeta item;
- item.fullName.wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(m_stmt, 1)),
- sqlite3_column_bytes(m_stmt, 1)));
- item.id = sqlite3_column_int(m_stmt, 0);
- item.keyLocatorHash = make_shared<const ndn::Buffer>(sqlite3_column_blob(m_stmt, 3),
- sqlite3_column_bytes(m_stmt, 3));
-
- try {
- f(item);
- }
- catch (...) {
- sqlite3_finalize(m_stmt);
- throw;
- }
- entryNumber++;
- }
- else if (rc == SQLITE_DONE) {
- sqlite3_finalize(m_stmt);
- break;
- }
- else {
- std::cerr << "Initiation Read Entries rc:" << rc << std::endl;
- sqlite3_finalize(m_stmt);
- BOOST_THROW_EXCEPTION(Error("Initiation Read Entries error"));
- }
- }
- m_size = entryNumber;
-}
-
int64_t
SqliteStorage::insert(const Data& data)
{
- Name name = data.getName();
+ Name name = data.getFullName(); // store the full name
+ ndn::util::Sqlite3Statement stmt(m_db, "INSERT INTO NDN_REPO_V2 (name, data) VALUES (?, ?);");
- Index::Entry entry(data, 0); //the id is not used
- int64_t id = -1;
- if (name.empty()) {
- std::cerr << "name is empty" << std::endl;
- return -1;
- }
-
- int rc = 0;
-
- sqlite3_stmt* insertStmt = 0;
-
- string insertSql = string("INSERT INTO NDN_REPO (id, name, data, keylocatorHash) "
- "VALUES (?, ?, ?, ?)");
-
- if (sqlite3_prepare_v2(m_db, insertSql.c_str(), -1, &insertStmt, 0) != SQLITE_OK) {
- sqlite3_finalize(insertStmt);
- std::cerr << "insert sql not prepared" << std::endl;
- }
//Insert
- auto result = sqlite3_bind_null(insertStmt, 1);
+ // Bind NULL to name value in NDN_REPO_V2 when initialize result.
+ auto result = sqlite3_bind_null(stmt, 1);
if (result == SQLITE_OK) {
- result = sqlite3_bind_blob(insertStmt, 2,
- entry.getName().wireEncode().wire(),
- entry.getName().wireEncode().size(), SQLITE_STATIC);
+ result = stmt.bind(1, name.wireEncode().value(),
+ name.wireEncode().value_size(), SQLITE_STATIC);
}
if (result == SQLITE_OK) {
- result = sqlite3_bind_blob(insertStmt, 3,
- data.wireEncode().wire(),
- data.wireEncode().size(), SQLITE_STATIC);
- }
- if (result == SQLITE_OK) {
- BOOST_ASSERT(entry.getKeyLocatorHash()->size() == ndn::util::Sha256::DIGEST_SIZE);
- result = sqlite3_bind_blob(insertStmt, 4,
- entry.getKeyLocatorHash()->data(),
- entry.getKeyLocatorHash()->size(), SQLITE_STATIC);
+ result = stmt.bind(2, data.wireEncode(), SQLITE_STATIC);
}
+ int id = 0;
if (result == SQLITE_OK) {
- rc = sqlite3_step(insertStmt);
+ int rc = 0;
+ rc = stmt.step();
if (rc == SQLITE_CONSTRAINT) {
- std::cerr << "Insert failed" << std::endl;
- sqlite3_finalize(insertStmt);
+ NDN_LOG_DEBUG("Insert failed");
BOOST_THROW_EXCEPTION(Error("Insert failed"));
- }
- sqlite3_reset(insertStmt);
- m_size++;
- id = sqlite3_last_insert_rowid(m_db);
+ }
+ sqlite3_reset(stmt);
+ id = sqlite3_last_insert_rowid(m_db);
}
else {
BOOST_THROW_EXCEPTION(Error("Some error with insert"));
}
-
- sqlite3_finalize(insertStmt);
return id;
}
-
bool
-SqliteStorage::erase(const int64_t id)
+SqliteStorage::erase(const Name& name)
{
- sqlite3_stmt* deleteStmt = 0;
+ ndn::util::Sqlite3Statement stmt(m_db, "DELETE FROM NDN_REPO_V2 WHERE name = ?;");
- string deleteSql = string("DELETE from NDN_REPO where id = ?;");
+ auto result = stmt.bind(1,
+ name.wireEncode().value(),
+ name.wireEncode().value_size(), SQLITE_STATIC);
- if (sqlite3_prepare_v2(m_db, deleteSql.c_str(), -1, &deleteStmt, 0) != SQLITE_OK) {
- sqlite3_finalize(deleteStmt);
- std::cerr << "delete statement prepared failed" << std::endl;
- BOOST_THROW_EXCEPTION(Error("delete statement prepared failed"));
- }
-
- if (sqlite3_bind_int64(deleteStmt, 1, id) == SQLITE_OK) {
- int rc = sqlite3_step(deleteStmt);
+ if (result == SQLITE_OK) {
+ int rc = stmt.step();
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
- std::cerr << " node delete error rc:" << rc << std::endl;
- sqlite3_finalize(deleteStmt);
- BOOST_THROW_EXCEPTION(Error(" node delete error"));
+ NDN_LOG_DEBUG("Node delete error rc:" << rc);
+ BOOST_THROW_EXCEPTION(Error("Node delete error"));
}
- if (sqlite3_changes(m_db) != 1)
+ if (sqlite3_changes(m_db) != 1) {
return false;
- m_size--;
+ }
}
else {
- std::cerr << "delete bind error" << std::endl;
- sqlite3_finalize(deleteStmt);
+ NDN_LOG_DEBUG("delete bind error");
BOOST_THROW_EXCEPTION(Error("delete bind error"));
}
- sqlite3_finalize(deleteStmt);
return true;
}
-
-shared_ptr<Data>
-SqliteStorage::read(const int64_t id)
+std::shared_ptr<Data>
+SqliteStorage::read(const Name& name)
{
- sqlite3_stmt* queryStmt = 0;
- string sql = string("SELECT * FROM NDN_REPO WHERE id = ? ;");
- int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
- if (rc == SQLITE_OK) {
- if (sqlite3_bind_int64(queryStmt, 1, id) == SQLITE_OK) {
- rc = sqlite3_step(queryStmt);
- if (rc == SQLITE_ROW) {
- auto data = make_shared<Data>();
- data->wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(queryStmt, 2)),
- sqlite3_column_bytes(queryStmt, 2)));
- sqlite3_finalize(queryStmt);
- return data;
+ return find(name);
+}
+
+bool
+SqliteStorage::has(const Name& name)
+{
+ // find exact match
+ return find(name, true) != nullptr;
+}
+
+std::shared_ptr<Data>
+SqliteStorage::find(const Name& name, bool exactMatch)
+{
+ NDN_LOG_DEBUG("Trying to find: " << name);
+ Name nameSuccessor;
+ if (!exactMatch) {
+ nameSuccessor = name.getSuccessor();
+ }
+
+ std::string sql;
+ if (exactMatch)
+ sql = "SELECT * FROM NDN_REPO_V2 WHERE name = ?;";
+ else
+ sql = "SELECT * FROM NDN_REPO_V2 WHERE name >= ? and name < ?;";
+
+ ndn::util::Sqlite3Statement stmt(m_db, sql);
+
+ auto result = stmt.bind(1,
+ name.wireEncode().value(),
+ name.wireEncode().value_size(), SQLITE_STATIC);
+
+ // use getsuccessor to locate prefix match items
+ if (result == SQLITE_OK && !exactMatch) {
+ // use V in TLV for prefix match when there is no exact match
+ result = stmt.bind(2,
+ nameSuccessor.wireEncode().value(),
+ nameSuccessor.wireEncode().value_size(), SQLITE_STATIC);
+ }
+
+ if (result == SQLITE_OK) {
+ int rc = stmt.step();
+ if (rc == SQLITE_ROW) {
+ Name foundName;
+
+ auto data = std::make_shared<Data>();
+ try {
+ data->wireDecode(stmt.getBlock(1));
}
- else if (rc == SQLITE_DONE) {
+ catch (const ndn::Block::Error& error) {
+ NDN_LOG_DEBUG(error.what());
return nullptr;
}
- else {
- std::cerr << "Database query failure rc:" << rc << std::endl;
- sqlite3_finalize(queryStmt);
- BOOST_THROW_EXCEPTION(Error("Database query failure"));
+ NDN_LOG_DEBUG("Data from db: " << *data);
+
+ foundName = data->getFullName();
+
+ if ((exactMatch && name == foundName) || (!exactMatch && name.isPrefixOf(foundName))) {
+ NDN_LOG_DEBUG("Found: " << foundName << " " << stmt.getInt(0));
+ return data;
}
}
- else {
- std::cerr << "select bind error" << std::endl;
- sqlite3_finalize(queryStmt);
- BOOST_THROW_EXCEPTION(Error("select bind error"));
+ else if (rc == SQLITE_DONE) {
+ return nullptr;
}
- sqlite3_finalize(queryStmt);
+ else {
+ NDN_LOG_DEBUG("Database query failure rc:" << rc);
+ BOOST_THROW_EXCEPTION(Error("Database query failure"));
+ }
}
else {
- sqlite3_finalize(queryStmt);
- std::cerr << "select statement prepared failed" << std::endl;
- BOOST_THROW_EXCEPTION(Error("select statement prepared failed"));
+ NDN_LOG_DEBUG("select bind error");
+ BOOST_THROW_EXCEPTION(Error("select bind error"));
}
return nullptr;
}
-int64_t
+uint64_t
SqliteStorage::size()
{
- sqlite3_stmt* queryStmt = 0;
- string sql("SELECT count(*) FROM NDN_REPO ");
- int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &queryStmt, 0);
- if (rc != SQLITE_OK)
- {
- std::cerr << "Database query failure rc:" << rc << std::endl;
- sqlite3_finalize(queryStmt);
- BOOST_THROW_EXCEPTION(Error("Database query failure"));
- }
+ ndn::util::Sqlite3Statement stmt(m_db, "SELECT count(*) FROM NDN_REPO_V2;");
- rc = sqlite3_step(queryStmt);
- if (rc != SQLITE_ROW)
- {
- std::cerr << "Database query failure rc:" << rc << std::endl;
- sqlite3_finalize(queryStmt);
- BOOST_THROW_EXCEPTION(Error("Database query failure"));
- }
-
- int64_t nDatas = sqlite3_column_int64(queryStmt, 0);
- if (m_size != nDatas) {
- std::cerr << "The size of database is not correct! " << std::endl;
+ int rc = stmt.step();
+ if (rc != SQLITE_ROW) {
+ NDN_LOG_DEBUG("Database query failure rc:" << rc);
+ BOOST_THROW_EXCEPTION(Error("Database query failure"));
}
- return nDatas;
+
+ uint64_t nData = stmt.getInt(0);
+ return nData;
}
} // namespace repo
diff --git a/src/storage/sqlite-storage.hpp b/src/storage/sqlite-storage.hpp
old mode 100755
new mode 100644
index 168cc41..4d7142b
--- a/src/storage/sqlite-storage.hpp
+++ b/src/storage/sqlite-storage.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014, Regents of the University of California.
+ * Copyright (c) 2018, Regents of the University of California.
*
* This file is part of NDN repo-ng (Next generation of NDN repository).
* See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -21,19 +21,17 @@
#define REPO_STORAGE_SQLITE_STORAGE_HPP
#include "storage.hpp"
-#include "index.hpp"
-#include <string>
-#include <iostream>
-#include <sqlite3.h>
-#include <stdlib.h>
-#include <vector>
-#include <queue>
+
#include <algorithm>
+#include <iostream>
+#include <queue>
+#include <stdlib.h>
+#include <string>
+#include <sqlite3.h>
+#include <vector>
namespace repo {
-using std::queue;
-
class SqliteStorage : public Storage
{
public:
@@ -50,7 +48,6 @@
explicit
SqliteStorage(const std::string& dbPath);
- virtual
~SqliteStorage();
/**
@@ -58,35 +55,30 @@
* @param data the data should be inserted into databse
* @return int64_t the id number of each entry in the database
*/
- virtual int64_t
- insert(const Data& data);
+ int64_t
+ insert(const Data& data) override;
/**
- * @brief remove the entry in the database by using id
- * @param id id number of each entry in the database
+ * @brief remove the entry in the database by using name as index
+ * @param name name of the data
*/
- virtual bool
- erase(const int64_t id);
+ bool
+ erase(const Name& name) override;
- /**
- * @brief get the data from database
- * @para id id number of each entry in the database, used to find the data
- */
- virtual std::shared_ptr<Data>
- read(const int64_t id);
+ std::shared_ptr<Data>
+ read(const Name& name) override;
+
+ bool
+ has(const Name& name) override;
+
+ std::shared_ptr<Data>
+ find(const Name& name, bool exactMatch = false) override;
/**
* @brief return the size of database
*/
- virtual int64_t
- size();
-
- /**
- * @brief enumerate each entry in database and call the function
- * insertItemToIndex to reubuild index from database
- */
- void
- fullEnumerate(const std::function<void(const Storage::ItemMeta)>& f);
+ uint64_t
+ size() override;
private:
void
@@ -95,7 +87,6 @@
private:
sqlite3* m_db;
std::string m_dbPath;
- int64_t m_size;
};
diff --git a/src/storage/storage.hpp b/src/storage/storage.hpp
old mode 100755
new mode 100644
index 5286c8a..146368f
--- a/src/storage/storage.hpp
+++ b/src/storage/storage.hpp
@@ -43,14 +43,6 @@
}
};
- class ItemMeta
- {
- public:
- int64_t id;
- Name fullName;
- ndn::ConstBufferPtr keyLocatorHash;
- };
-
public:
virtual
~Storage() = default;
@@ -63,31 +55,38 @@
insert(const Data& data) = 0;
/**
- * @brief remove the entry in the database by using id
- * @param id id number of entry in the database
+ * @brief remove the entry in the database by full name
+ * @param full name full name of the data
*/
virtual bool
- erase(const int64_t id) = 0;
+ erase(const Name& name) = 0;
/**
* @brief get the data from database
- * @param id id number of each entry in the database, used to find the data
+ * @param full name full name of the data
*/
virtual std::shared_ptr<Data>
- read(const int64_t id) = 0;
+ read(const Name& name) = 0;
+
+ /**
+ * @brief check if database already has the data
+ * @param full name full name of the data
+ */
+ virtual bool
+ has(const Name& name) = 0;
+
+ /**
+ * @brief find the data in database by full name and return it
+ * @param full name full name of the data
+ */
+ virtual std::shared_ptr<Data>
+ find(const Name& name, bool exactMatch = false) = 0;
/**
* @brief return the size of database
*/
- virtual int64_t
+ virtual uint64_t
size() = 0;
-
- /**
- * @brief enumerate each entry in database and call the function
- * insertItemToIndex to reubuild index from database
- */
- virtual void
- fullEnumerate(const std::function<void(const Storage::ItemMeta)>& f) = 0;
};
} // namespace repo