diff options
author | Daniel Burrows <dburrows@debian.org> | 2009-07-27 07:42:47 -0700 |
---|---|---|
committer | Daniel Burrows <dburrows@debian.org> | 2009-07-27 07:42:47 -0700 |
commit | b198ccf4f06eca419a3ecaea9147eef461518a89 (patch) | |
tree | 49fdcd6eee4620e9d75412a52be82429d99f18ff /src/generic/util/sqlite.cc | |
parent | 8cc867d48715e1e2a1064a644a51356b20bb50af (diff) | |
download | aptitude-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.cc | 59 |
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) |