commit 70fe1215a01020a87c9cdee139f4188b1424d006 Author: Damian Johnson atagar@torproject.org Date: Thu Aug 31 10:41:22 2017 -0700
Move cache to its own module
Not yet even close to what I'm planning, but moving this out of the base module is a good first step. --- nyx/__init__.py | 53 +------------------------------------- nyx/cache.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/cache.py | 26 +++++++++---------- 3 files changed, 93 insertions(+), 65 deletions(-)
diff --git a/nyx/__init__.py b/nyx/__init__.py index 8c3d396..c2032bc 100644 --- a/nyx/__init__.py +++ b/nyx/__init__.py @@ -31,10 +31,8 @@ Tor curses monitoring application. +- halt - stops daemon panels """
-import contextlib import distutils.spawn import os -import sqlite3 import sys import threading import time @@ -55,6 +53,7 @@ __license__ = 'GPLv3'
__all__ = [ 'arguments', + 'cache', 'controller', 'curses', 'log', @@ -86,17 +85,6 @@ CONFIG = stem.util.conf.config_dict('nyx', { NYX_INTERFACE = None TOR_CONTROLLER = None BASE_DIR = os.path.sep.join(__file__.split(os.path.sep)[:-1]) -CACHE = None -CACHE_LOCK = threading.RLock() - -SCHEMA_VERSION = 1 # version of our scheme, bump this if you change the following -SCHEMA = ( - 'CREATE TABLE schema(version NUMBER)', - 'INSERT INTO schema(version) VALUES (%i)' % SCHEMA_VERSION, - - 'CREATE TABLE relays(fingerprint TEXT PRIMARY KEY, address TEXT, or_port NUMBER, nickname TEXT)', -) -
# technically can change but we use this query a *lot* so needs to be cached
@@ -263,45 +251,6 @@ def data_directory(filename, config): return os.path.join(data_dir, filename)
-@contextlib.contextmanager -def cache(): - """ - Provides the sqlite cache for application data. - - :returns: **sqlite3.Connection** for our applicaion cache - """ - - global CACHE - - with CACHE_LOCK: - if CACHE is None: - cache_path = data_directory('cache.sqlite') - - if cache_path: - try: - CACHE = sqlite3.connect(cache_path) - schema = CACHE.execute('SELECT version FROM schema').fetchone()[0] - except: - schema = 'no schema' - - if schema != SCHEMA_VERSION: - stem.util.log.info('Cache schema of %s is out of date (has %s but current version is %s). Clearing the cache.' % (cache_path, schema, SCHEMA_VERSION)) - - CACHE.close() - os.remove(cache_path) - CACHE = sqlite3.connect(cache_path) - - for cmd in SCHEMA: - CACHE.execute(cmd) - else: - CACHE = sqlite3.connect(':memory:') - - for cmd in SCHEMA: - CACHE.execute(cmd) - - yield CACHE - - @uses_settings def expand_path(path, config): """ diff --git a/nyx/cache.py b/nyx/cache.py new file mode 100644 index 0000000..b989f20 --- /dev/null +++ b/nyx/cache.py @@ -0,0 +1,79 @@ +""" +Cache for frequently needed information. This persists to disk if we can, and +otherwise is an in-memory cache. +""" + +import contextlib +import os +import sqlite3 +import threading + +import stem.util.log + +import nyx + +CACHE = None +CACHE_LOCK = threading.RLock() + +SCHEMA_VERSION = 1 # version of our scheme, bump this if you change the following +SCHEMA = ( + 'CREATE TABLE schema(version NUMBER)', + 'INSERT INTO schema(version) VALUES (%i)' % SCHEMA_VERSION, + + 'CREATE TABLE relays(fingerprint TEXT PRIMARY KEY, address TEXT, or_port NUMBER, nickname TEXT)', +) + + +@contextlib.contextmanager +def cache(): + """ + Provides the sqlite cache for application data. + + :returns: :class:`~nyx.cache.Cache` for our applicaion + """ + + global CACHE + + with CACHE_LOCK: + if CACHE is None: + CACHE = Cache() + + yield CACHE + + +class Cache(object): + """ + Cache for frequently used information. + """ + + def __init__(self): + cache_path = nyx.data_directory('cache.sqlite') + + if cache_path: + try: + self._conn = sqlite3.connect(cache_path) + schema = self._conn.execute('SELECT version FROM schema').fetchone()[0] + except: + schema = 'no schema' + + if schema != SCHEMA_VERSION: + stem.util.log.info('Cache schema of %s is out of date (has %s but current version is %s). Clearing the cache.' % (cache_path, schema, SCHEMA_VERSION)) + + self._conn.close() + os.remove(cache_path) + self._conn = sqlite3.connect(cache_path) + + for cmd in SCHEMA: + self._conn.execute(cmd) + else: + self._conn = sqlite3.connect(':memory:') + + for cmd in SCHEMA: + self._conn.execute(cmd) + + def query(self, query, *param): + """ + Performs a query on our cache. + """ + + return self._conn.execute(query, param) diff --git a/test/cache.py b/test/cache.py index 01f99af..733fbca 100644 --- a/test/cache.py +++ b/test/cache.py @@ -5,7 +5,7 @@ Unit tests for nyx.cache. import tempfile import unittest
-import nyx +import nyx.cache
from mock import Mock, patch
@@ -17,7 +17,7 @@ NICKNAME = 'caersidi'
class TestCache(unittest.TestCase): def setUp(self): - nyx.CACHE = None # drop cached database reference + nyx.cache.CACHE = None # drop cached database reference
@patch('nyx.data_directory', Mock(return_value = None)) def test_memory_cache(self): @@ -25,10 +25,10 @@ class TestCache(unittest.TestCase): Create a cache in memory. """
- with nyx.cache() as cache: - self.assertEqual((0, 'main', ''), cache.execute("PRAGMA database_list").fetchone()) - cache.execute('INSERT INTO relays(fingerprint, address, or_port, nickname) VALUES (?,?,?,?)', (FINGERPRINT, ADDRESS, PORT, NICKNAME)) - self.assertEqual(NICKNAME, cache.execute('SELECT nickname FROM relays WHERE fingerprint=?', (FINGERPRINT,)).fetchone()[0]) + with nyx.cache.cache() as cache: + self.assertEqual((0, 'main', ''), cache.query('PRAGMA database_list').fetchone()) + cache.query('INSERT INTO relays(fingerprint, address, or_port, nickname) VALUES (?,?,?,?)', FINGERPRINT, ADDRESS, PORT, NICKNAME) + self.assertEqual(NICKNAME, cache.query('SELECT nickname FROM relays WHERE fingerprint=?', FINGERPRINT).fetchone()[0])
def test_file_cache(self): """ @@ -37,12 +37,12 @@ class TestCache(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix = '.sqlite') as tmp: with patch('nyx.data_directory', Mock(return_value = tmp.name)): - with nyx.cache() as cache: - self.assertEqual((0, 'main', tmp.name), cache.execute("PRAGMA database_list").fetchone()) - cache.execute('INSERT INTO relays(fingerprint, address, or_port, nickname) VALUES (?,?,?,?)', (FINGERPRINT, ADDRESS, PORT, NICKNAME)) - cache.commit() + with nyx.cache.cache() as cache: + self.assertEqual((0, 'main', tmp.name), cache.query('PRAGMA database_list').fetchone()) + cache.query('INSERT INTO relays(fingerprint, address, or_port, nickname) VALUES (?,?,?,?)', FINGERPRINT, ADDRESS, PORT, NICKNAME) + cache._conn.commit()
- nyx.CACHE = None + nyx.cache.CACHE = None
- with nyx.cache() as cache: - self.assertEqual(NICKNAME, cache.execute('SELECT nickname FROM relays WHERE fingerprint=?', (FINGERPRINT,)).fetchone()[0]) + with nyx.cache.cache() as cache: + self.assertEqual(NICKNAME, cache.query('SELECT nickname FROM relays WHERE fingerprint=?', FINGERPRINT).fetchone()[0])