summaryrefslogtreecommitdiff
path: root/src/generic/util/sqlite.cc
diff options
context:
space:
mode:
authorDaniel Burrows <dburrows@debian.org>2009-07-27 07:42:47 -0700
committerDaniel Burrows <dburrows@debian.org>2009-07-27 07:42:47 -0700
commitb198ccf4f06eca419a3ecaea9147eef461518a89 (patch)
tree49fdcd6eee4620e9d75412a52be82429d99f18ff /src/generic/util/sqlite.cc
parent8cc867d48715e1e2a1064a644a51356b20bb50af (diff)
downloadaptitude-b198ccf4f06eca419a3ecaea9147eef461518a89.tar.gz
Implement a system for caching prepared SQL statements.
Prepared statements created via this mechanism are placed into the cache for reuse once the user is done with them. Statements won't be reused as long as at least one proxy object still exists. This gives us a mechanism for safe reuse of statements without having to worry that two different pieces of code might use the same statement object and step on each other. Also, boost::multi_index is awesome.
Diffstat (limited to 'src/generic/util/sqlite.cc')
-rw-r--r--src/generic/util/sqlite.cc59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/generic/util/sqlite.cc b/src/generic/util/sqlite.cc
index 4aaa3c1e..84a09b25 100644
--- a/src/generic/util/sqlite.cc
+++ b/src/generic/util/sqlite.cc
@@ -24,6 +24,11 @@ namespace aptitude
{
namespace sqlite
{
+ /** \brief The default maximum size of a database's statement
+ * cache.
+ */
+ const unsigned int default_statement_cache_limit = 100;
+
db::lock::lock(db &parent)
: handle(parent.handle)
{
@@ -38,6 +43,7 @@ namespace aptitude
db::db(const std::string &filename,
int flags,
const char *vfs)
+ : statement_cache_limit(default_statement_cache_limit)
{
const int result =
sqlite3_open_v2(filename.c_str(), &handle,
@@ -96,6 +102,59 @@ namespace aptitude
return rval;
}
+ void db::cache_statement(const statement_cache_entry &entry)
+ {
+ statement_cache_mru &mru(get_cache_mru());
+ mru.push_back(entry);
+
+ // Drop old entries from the cache if it's too large.
+ while(mru.size() > statement_cache_limit)
+ mru.pop_front();
+ }
+
+ db::statement_proxy_impl::~statement_proxy_impl()
+ {
+ // Careful here: the database might have been deleted while the
+ // proxy is active. WE RELY ON THE FACT THAT DELETING THE
+ // DATABASE NULLS OUT THE STATEMENT HANDLE.
+ if(entry.stmt->handle == NULL)
+ return; // The database is dead; nothing to do.
+ else
+ entry.stmt->parent.cache_statement(entry);
+ }
+
+ db::statement_proxy db::get_cached_statement(const std::string &sql)
+ {
+ // Check whether the statement exists in the cache.
+ statement_cache_hash_index &index(get_cache_hash_index());
+
+ statement_cache_hash_index::const_iterator found =
+ index.find(sql);
+
+ if(found != index.end())
+ {
+ // Extract the element from the set and return it.
+ statement_cache_entry entry(*found);
+ entry.stmt->reset();
+
+ index.erase(sql);
+
+ boost::shared_ptr<statement_proxy_impl> rval(new statement_proxy_impl(entry));
+ return statement_proxy(rval);
+ }
+ else
+ {
+ // Prepare a new SQL statement and return a proxy to it. It
+ // won't be added to the cache until the caller is done with
+ // it.
+ boost::shared_ptr<statement> stmt(statement::prepare(*this, sql));
+
+ statement_cache_entry entry(sql, stmt);
+ boost::shared_ptr<statement_proxy_impl> rval(new statement_proxy_impl(entry));
+ return statement_proxy(rval);
+ }
+ }
+
statement::statement(db &_parent, sqlite3_stmt *_handle)