catalog, query UI: fix race condition and stabilize UI
add autocomplete, sidebar, deselect, and paging to UI
stability improvements to catalog
Change-Id: I2e873a41eaa8c10d9f9a1d605f33fb5217112d64
refs: #2634, 2638
diff --git a/catalog/src/query/query-adapter.hpp b/catalog/src/query/query-adapter.hpp
index ca86d5e..bada073 100644
--- a/catalog/src/query/query-adapter.hpp
+++ b/catalog/src/query/query-adapter.hpp
@@ -37,11 +37,10 @@
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/util/time.hpp>
#include <ndn-cxx/encoding/encoding-buffer.hpp>
+#include <ndn-cxx/util/in-memory-storage-lru.hpp>
#include "mysql/mysql.h"
-#include <iostream>
-
#include <map>
#include <memory>
#include <mutex>
@@ -104,6 +103,7 @@
* @param face: Face that will be used for NDN communications
* @param keyChain: KeyChain to sign query responses and evaluate the incoming query
* and ChronoSync requests against
+ * @param interest: Interest that needs to be handled
* @param databaseHandler: <typename DatabaseHandler> to the database that stores our catalog
*/
void
@@ -143,11 +143,28 @@
const ndn::Name& segmentPrefix, const char* payload, size_t payloadLength,
uint64_t segmentNo, bool isFinalBlock);
+ /**
+ * Helper function that generates query results from a Json query
+ *
+ * @param face: Face that will be used for NDN communications
+ * @param jsonQuery: String containing the JSON query
+ * @param keyChain: KeyChain to sign query responses and evaluate the incoming query
+ * and ChronoSync requests against
+ * @param interest: Interest that needs to be handled
+ * @param databaseHandler: <typename DatabaseHandler> to the database that stores our catalog
+ */
+ void
+ runJsonQuery(std::shared_ptr<ndn::Face> face, std::shared_ptr<ndn::KeyChain> keyChain,
+ std::shared_ptr<const ndn::Interest> interest, const std::string& jsonQuery,
+ std::shared_ptr<DatabaseHandler> databaseHandler);
+
// mutex to control critical sections
std::mutex m_mutex;
// @{ needs m_mutex protection
// The Queries we are currently writing to
std::map<std::string, std::shared_ptr<ndn::Data>> m_activeQueryToFirstResponse;
+
+ ndn::util::InMemoryStorageLru m_cache;
// @}
};
@@ -158,22 +175,23 @@
std::shared_ptr<DatabaseHandler> databaseHandler,
const ndn::Name& prefix)
: atmos::util::CatalogAdapter<DatabaseHandler>(face, keyChain, databaseHandler, prefix)
+ , m_cache(100000000)
{
- face->setInterestFilter(ndn::InterestFilter(ndn::Name(prefix).append("query")),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onQueryInterest,
- this, _1, _2),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterSuccess,
- this, _1),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterFailure,
- this, _1, _2));
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_face->setInterestFilter(ndn::InterestFilter(ndn::Name(prefix).append("query")),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onQueryInterest,
+ this, _1, _2),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterSuccess,
+ this, _1),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterFailure,
+ this, _1, _2));
- face->setInterestFilter(ndn::InterestFilter(ndn::Name(prefix).append("query-results")),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onQueryResultsInterest,
- this, _1, _2),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterSuccess,
- this, _1),
- bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterFailure,
- this, _1, _2));
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_face->setInterestFilter(ndn::InterestFilter(ndn::Name(prefix).append("query-results")),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onQueryResultsInterest,
+ this, _1, _2),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterSuccess,
+ this, _1),
+ bind(&atmos::query::QueryAdapter<DatabaseHandler>::onRegisterFailure,
+ this, _1, _2));
}
template <typename DatabaseHandler>
@@ -209,7 +227,21 @@
// CS so we just ignore any retrieval Interests that hit us for
// now. In the future, this should check some form of
// InMemoryStorage.
- std::cout << "Got to query result" << std::endl;
+ auto data = m_cache.find(interest.getName());
+ if (data) {
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_face->put(*data);
+ } else {
+ // regenerate query
+ const std::string jsonQuery(reinterpret_cast<const char*>(interest.getName()[atmos::util::CatalogAdapter<DatabaseHandler>::m_prefix.size()+1].value()));
+
+ std::shared_ptr<const ndn::Interest> interestPtr = interest.shared_from_this();
+ std::thread queryRegenThread(&QueryAdapter<DatabaseHandler>::runJsonQuery, this,
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_face,
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_keyChain, interestPtr,
+ jsonQuery,
+ atmos::util::CatalogAdapter<DatabaseHandler>::m_databaseHandler);
+ queryRegenThread.join();
+ }
}
template <typename DatabaseHandler>
@@ -256,7 +288,11 @@
data->setFinalBlockId(segmentName[-1]);
}
keyChain->sign(*data);
- face->put(*data);
+ //face->put(*data);
+
+ m_mutex.lock();
+ m_cache.insert(*data);
+ m_mutex.unlock();
}
template <typename DatabaseHandler>
@@ -266,22 +302,34 @@
std::shared_ptr<const ndn::Interest> interest,
std::shared_ptr<DatabaseHandler> databaseHandler)
{
+ // 1) Strip the prefix off the ndn::Interest's ndn::Name
+ // +1 to grab JSON component after "query" component
+ const std::string jsonQuery(reinterpret_cast<const char*>(interest->getName()[atmos::util::CatalogAdapter<DatabaseHandler>::m_prefix.size()+1].value()));
+ if (jsonQuery.length() > 0) {
+ runJsonQuery(face, keyChain, interest, jsonQuery, databaseHandler);
+ } // else NACK?
+}
+
+template <typename DatabaseHandler>
+void
+QueryAdapter<DatabaseHandler>::runJsonQuery(std::shared_ptr<ndn::Face> face,
+ std::shared_ptr<ndn::KeyChain> keyChain,
+ std::shared_ptr<const ndn::Interest> interest,
+ const std::string& jsonQuery,
+ std::shared_ptr<DatabaseHandler> databaseHandler)
+{
// @todo: we should return a NACK as we have no database
}
template <>
void
-QueryAdapter<MYSQL>::query(std::shared_ptr<ndn::Face> face,
- std::shared_ptr<ndn::KeyChain> keyChain,
- std::shared_ptr<const ndn::Interest> interest,
- std::shared_ptr<MYSQL> databaseHandler)
+QueryAdapter<MYSQL>::runJsonQuery(std::shared_ptr<ndn::Face> face,
+ std::shared_ptr<ndn::KeyChain> keyChain,
+ std::shared_ptr<const ndn::Interest> interest,
+ const std::string& jsonQuery,
+ std::shared_ptr<MYSQL> databaseHandler)
{
- std::cout << "Running query" << std::endl;
- // 1) Strip the prefix off the ndn::Interest's ndn::Name
- // +1 to grab JSON component after "query" component
- const std::string jsonQuery(reinterpret_cast<const char*>(interest->getName()[m_prefix.size()+1].value()));
-
// For efficiency, do a double check. Once without the lock, then with it.
if (m_activeQueryToFirstResponse.find(jsonQuery) != m_activeQueryToFirstResponse.end()) {
m_mutex.lock();
@@ -366,7 +414,7 @@
std::shared_ptr<MYSQL_RES> results = atmos::util::PerformQuery(databaseHandler, mysqlQuery.str());
MYSQL_ROW row;
- ndn::Name segmentPrefix(m_prefix);
+ ndn::Name segmentPrefix(atmos::util::CatalogAdapter<MYSQL>::m_prefix);
segmentPrefix.append("query-results");
segmentPrefix.append(version);