summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-02-12 11:54:05 +0100
committerRoland Reichwein <mail@reichwein.it>2023-02-12 11:54:05 +0100
commitb0f8b28977e59b7fbfc1ce57ee5c102b8e4e0690 (patch)
tree926eb8dbd140d84ab0238ce7d671673056f12f56
parent7d5ca5cebfe3453aaa3c649bbc3e771e6d636ac9 (diff)
Touch documents on read (i.e. reset timeout on read)
-rw-r--r--connectionregistry.cpp10
-rw-r--r--connectionregistry.h5
-rw-r--r--debian/changelog1
-rw-r--r--storage.cpp19
-rw-r--r--storage.h3
-rw-r--r--tests/test-connectionregistry.cpp3
-rw-r--r--tests/test-storage.cpp29
-rw-r--r--whiteboard.cpp11
-rw-r--r--whiteboard.h1
9 files changed, 78 insertions, 4 deletions
diff --git a/connectionregistry.cpp b/connectionregistry.cpp
index 412472d..e3c0c11 100644
--- a/connectionregistry.cpp
+++ b/connectionregistry.cpp
@@ -61,6 +61,16 @@ std::unordered_set<ConnectionRegistry::connection>::iterator ConnectionRegistry:
return m_ids.at(id).end();
}
+std::unordered_map<ConnectionRegistry::connection, std::string>::iterator ConnectionRegistry::begin()
+{
+ return m_connections.begin();
+}
+
+std::unordered_map<ConnectionRegistry::connection, std::string>::iterator ConnectionRegistry::end()
+{
+ return m_connections.end();
+}
+
void ConnectionRegistry::dump() const
{
std::cout << "Connection Registry:" << std::endl;
diff --git a/connectionregistry.h b/connectionregistry.h
index 25bd3b6..c3c6884 100644
--- a/connectionregistry.h
+++ b/connectionregistry.h
@@ -22,9 +22,14 @@ public:
void addConnection(connection c);
void delConnection(connection c);
+ // iterate over all connections associated with a certain id
std::unordered_set<connection>::iterator begin(const std::string& id);
std::unordered_set<connection>::iterator end(const std::string& id);
+ // iterate over all connections
+ std::unordered_map<connection, std::string>::iterator begin();
+ std::unordered_map<connection, std::string>::iterator end();
+
void dump() const;
size_t number_of_connections() const;
diff --git a/debian/changelog b/debian/changelog
index 082b17f..41b4ce4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,7 @@ whiteboard (1.8) UNRELEASED; urgency=medium
* Added config.maxconnections, defaults to 1000
* Fixed package dependencies for PDF generation
+ * Touch documents on read (i.e. reset timeout on read)
-- Roland Reichwein <mail@reichwein.it> Fri, 10 Feb 2023 19:18:16 +0100
diff --git a/storage.cpp b/storage.cpp
index c5caa79..6060caf 100644
--- a/storage.cpp
+++ b/storage.cpp
@@ -30,7 +30,8 @@ Storage::Storage(const Config& config):
m_stmt_setCursorPos(m_db, "UPDATE documents SET cursorpos = ? WHERE id = ?"),
m_stmt_setRow(m_db, "INSERT OR REPLACE INTO documents (id, value, rev, cursorpos, timestamp) values (?, ?, ?, ?, ?)"),
m_stmt_getDbSizeGross(m_db, "SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()"),
- m_stmt_getDbSizeNet(m_db, "SELECT (page_count - freelist_count) * page_size as size FROM pragma_page_count(), pragma_freelist_count(), pragma_page_size()")
+ m_stmt_getDbSizeNet(m_db, "SELECT (page_count - freelist_count) * page_size as size FROM pragma_page_count(), pragma_freelist_count(), pragma_page_size()"),
+ m_stmt_touchDocument(m_db, "UPDATE documents SET timestamp = ? WHERE id = ?")
{
CompiledSQL::Guard g{m_stmt_create};
m_stmt_create.execute();
@@ -154,7 +155,8 @@ void Storage::setDocument(const std::string& id, const std::string& document)
m_stmt_setDocument_new.bind(3, 0);
m_stmt_setDocument_new.bind(4, 0);
m_stmt_setDocument_new.bind(5, static_cast<int64_t>(unixepoch()));
- m_stmt_setDocument_new.execute();
+ if (!m_stmt_setDocument_new.execute())
+ throw std::runtime_error("Unable to create document with id "s + id);
}
}
@@ -165,7 +167,7 @@ void Storage::setRevision(const std::string& id, int rev)
m_stmt_setRevision.bind(2, id);
if (!m_stmt_setRevision.execute())
- throw std::runtime_error("Unable to insert row with id "s + id);
+ throw std::runtime_error("Unable to set revision for id "s + id);
}
void Storage::setCursorPos(const std::string& id, int cursorPos)
@@ -175,7 +177,7 @@ void Storage::setCursorPos(const std::string& id, int cursorPos)
m_stmt_setCursorPos.bind(2, id);
if (!m_stmt_setCursorPos.execute())
- throw std::runtime_error("Unable to insert row with id "s + id);
+ throw std::runtime_error("Unable to set cursor position for id "s + id);
}
void Storage::setRow(const std::string& id, const std::string& document, int rev, int cursorPos)
@@ -222,3 +224,12 @@ std::string Storage::generate_id()
return "endofcodes";
}
+void Storage::touchDocument(const std::string& id)
+{
+ CompiledSQL::Guard g{m_stmt_touchDocument};
+ m_stmt_touchDocument.bind(1, static_cast<int64_t>(unixepoch()));
+ m_stmt_touchDocument.bind(2, id);
+ if (!m_stmt_touchDocument.execute())
+ throw std::runtime_error("Unable to touch document with id "s + id);
+}
+
diff --git a/storage.h b/storage.h
index f997657..131b786 100644
--- a/storage.h
+++ b/storage.h
@@ -30,6 +30,8 @@ public:
void setCursorPos(const std::string& id, int cursorPos);
void setRow(const std::string& id, const std::string& document, int rev, int cursorPos);
+ void touchDocument(const std::string& id);
+
void cleanup();
std::string generate_id();
@@ -55,6 +57,7 @@ private:
CompiledSQL m_stmt_setRow;
CompiledSQL m_stmt_getDbSizeGross;
CompiledSQL m_stmt_getDbSizeNet;
+ CompiledSQL m_stmt_touchDocument;
};
uint32_t checksum32(const std::string& s);
diff --git a/tests/test-connectionregistry.cpp b/tests/test-connectionregistry.cpp
index 282f397..dbc2b7e 100644
--- a/tests/test-connectionregistry.cpp
+++ b/tests/test-connectionregistry.cpp
@@ -114,14 +114,17 @@ TEST_F(ConnectionRegistryTest, test_iterators)
EXPECT_THROW(cr.begin(""), std::exception);
EXPECT_THROW(cr.end(""), std::exception);
+ EXPECT_EQ(std::distance(cr.begin(), cr.end()), 0);
cr.addConnection(c);
EXPECT_THROW(cr.begin(""), std::exception);
EXPECT_THROW(cr.end(""), std::exception);
+ EXPECT_EQ(std::distance(cr.begin(), cr.end()), 1);
cr.setId(c, "id1");
EXPECT_EQ(std::distance(cr.begin("id1"), cr.end("id1")), 1);
+ EXPECT_EQ(std::distance(cr.begin(), cr.end()), 1);
}
TEST_F(ConnectionRegistryTest, test_guard)
diff --git a/tests/test-storage.cpp b/tests/test-storage.cpp
index 51a6058..6239f8f 100644
--- a/tests/test-storage.cpp
+++ b/tests/test-storage.cpp
@@ -12,6 +12,7 @@
namespace fs = std::filesystem;
using namespace Reichwein;
+using namespace std::string_literals;
namespace {
const std::string testConfigFilename{"./test.conf"};
@@ -118,6 +119,16 @@ TEST_F(StorageTest, setDocument)
EXPECT_EQ(storage.getDocument("0"), "abc");
}
+TEST_F(StorageTest, touchDocument)
+{
+ Storage storage(*m_config);
+ EXPECT_THROW(storage.touchDocument("0"), std::exception);
+ storage.setDocument("0", "abc");
+ storage.touchDocument("0");
+ EXPECT_EQ(storage.getNumberOfDocuments(), 1UL);
+ EXPECT_EQ(storage.getDocument("0"), "abc");
+}
+
TEST_F(StorageTest, setRevision)
{
Storage storage(*m_config);
@@ -126,6 +137,15 @@ TEST_F(StorageTest, setRevision)
EXPECT_EQ(storage.getNumberOfDocuments(), 1UL);
EXPECT_EQ(storage.getRevision("0"), 123);
+
+ try {
+ storage.setRevision("1", 123);
+ FAIL();
+ } catch(const std::exception& ex) {
+ EXPECT_EQ("Unable to set revision for id 1"s, ex.what());
+ } catch(...) {
+ FAIL();
+ }
}
TEST_F(StorageTest, setCursorPos)
@@ -136,6 +156,15 @@ TEST_F(StorageTest, setCursorPos)
EXPECT_EQ(storage.getNumberOfDocuments(), 1UL);
EXPECT_EQ(storage.getCursorPos("0"), 1234);
+
+ try {
+ storage.setCursorPos("1", 12345);
+ FAIL();
+ } catch(const std::exception& ex) {
+ EXPECT_EQ("Unable to set cursor position for id 1"s, ex.what());
+ } catch(...) {
+ FAIL();
+ }
}
TEST_F(StorageTest, setRow)
diff --git a/whiteboard.cpp b/whiteboard.cpp
index 044321b..5424a79 100644
--- a/whiteboard.cpp
+++ b/whiteboard.cpp
@@ -448,6 +448,16 @@ void Whiteboard::on_accept(boost::system::error_code ec, boost::asio::ip::tcp::s
do_accept();
}
+// for long running connections, don't timeout them but touch associated ids
+// regularly, at cleanup time
+void Whiteboard::touch_all_connections()
+{
+ std::for_each(m_registry.begin(), m_registry.end(), [&](const std::pair<ConnectionRegistry::connection, std::string>& i)
+ {
+ m_storage->touchDocument(i.second);
+ });
+}
+
// the actual main() for testability
int Whiteboard::run(int argc, char* argv[])
{
@@ -502,6 +512,7 @@ int Whiteboard::run(int argc, char* argv[])
std::lock_guard<std::mutex> lock(m_storage_mutex);
if (!m_storage)
throw std::runtime_error("Storage not initialized");
+ touch_all_connections();
m_storage->cleanup();
storage_cleanup_timer.expires_at(storage_cleanup_timer.expires_at() + boost::asio::chrono::hours(24));
storage_cleanup_timer.async_wait(storage_cleanup_callback);
diff --git a/whiteboard.h b/whiteboard.h
index 7648bd4..53036ac 100644
--- a/whiteboard.h
+++ b/whiteboard.h
@@ -30,5 +30,6 @@ private:
void do_accept();
void on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket socket);
+ void touch_all_connections();
};