def test_get_with_default(self):
     """
     Tests the capability of QueryCache for retrieving items with a default value
     """
     c = QueryCache(ceiling=20)
     # set 10 values
     for x in range(10):
         c[x] = x
     # arrange for the first 5 to be permanent
     for x in range(5):
         for r in range(QueryCache._maxlevel + 2):
             v = c[x]
             self.assertEqual(v, x)
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 10,
         'permanentcount': 5
     })
     # Test defaults for existing (including in permanents)
     for x in range(10):
         v = c.get(x, -1)
         self.assertEqual(v, x)
     # Test defaults for others
     for x in range(10, 15):
         v = c.get(x, -1)
         self.assertEqual(v, -1)
 def test_clear_on_overflow(self):
     """Tests that only non-permanent items in the cache are wiped-out on ceiling overflow
     """
     c = QueryCache(ceiling=10)
     # set 10 values
     for x in range(10):
         c[x] = x
     # arrange for the first 5 to be permanent
     for x in range(5):
         for r in range(QueryCache._maxlevel + 2):
             v = c[x]
             self.assertEqual(v, x)
     # Add the 11-th
     c[10] = 10
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 6,
         'permanentcount': 5
     })
 def test_iterkeys(self):
     """
     Tests the iterating on keys in the cache
     """
     c = QueryCache(ceiling=20)
     # set 10 values
     for x in range(10):
         c[x] = x
     # arrange for the first 5 to be permanent
     for x in range(5):
         for r in range(QueryCache._maxlevel + 2):
             v = c[x]
             self.assertEqual(v, x)
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 10,
         'permanentcount': 5
     })
     keys = sorted(c)
     for x in range(10):
         self.assertEqual(x, keys[x])
Exemple #4
0
    def __init__(self, repo, schema):
        # rql st and solution cache.
        self._cache = QueryCache(repo.config['rql-cache-size'])
        # rql cache key cache. Don't bother using a Cache instance: we should
        # have a limited number of queries in there, since there are no entries
        # in this cache for user queries (which have no args)
        self._ck_cache = {}
        # some cache usage stats
        self.cache_hit, self.cache_miss = 0, 0
        # rql parsing / analysing helper
        self.solutions = repo.vreg.solutions
        rqlhelper = repo.vreg.rqlhelper
        # set backend on the rql helper, will be used for function checking
        rqlhelper.backend = repo.config.system_source_config['db-driver']

        def parse(rql, annotate=False, parse=rqlhelper.parse):
            """Return a freshly parsed syntax tree for the given RQL."""
            try:
                return parse(rql, annotate=annotate)
            except UnicodeError:
                raise RQLSyntaxError(rql)

        self._parse = parse
Exemple #5
0
class RQLCache(object):
    def __init__(self, repo, schema):
        # rql st and solution cache.
        self._cache = QueryCache(repo.config['rql-cache-size'])
        # rql cache key cache. Don't bother using a Cache instance: we should
        # have a limited number of queries in there, since there are no entries
        # in this cache for user queries (which have no args)
        self._ck_cache = {}
        # some cache usage stats
        self.cache_hit, self.cache_miss = 0, 0
        # rql parsing / analysing helper
        self.solutions = repo.vreg.solutions
        rqlhelper = repo.vreg.rqlhelper
        # set backend on the rql helper, will be used for function checking
        rqlhelper.backend = repo.config.system_source_config['db-driver']

        def parse(rql, annotate=False, parse=rqlhelper.parse):
            """Return a freshly parsed syntax tree for the given RQL."""
            try:
                return parse(rql, annotate=annotate)
            except UnicodeError:
                raise RQLSyntaxError(rql)

        self._parse = parse

    def __len__(self):
        return len(self._cache)

    def get(self, cnx, rql, args):
        """Return syntax tree and cache key for the given RQL.

        Returned syntax tree is cached and must not be modified
        """
        # parse the query and binds variables
        cachekey = (rql, )
        try:
            if args:
                # search for named args in query which are eids (hence
                # influencing query's solutions)
                eidkeys = self._ck_cache[rql]
                if eidkeys:
                    # if there are some, we need a better cache key, eg (rql +
                    # entity type of each eid)
                    cachekey = _rql_cache_key(cnx, rql, args, eidkeys)
            rqlst = self._cache[cachekey]
            self.cache_hit += 1
            statsd_c('cache_hit')
        except KeyError:
            self.cache_miss += 1
            statsd_c('cache_miss')
            rqlst = self._parse(rql)
            # compute solutions for rqlst and return named args in query
            # which are eids. Notice that if you may not need `eidkeys`, we
            # have to compute solutions anyway (kept as annotation on the
            # tree)
            eidkeys = self.solutions(cnx, rqlst, args)
            if args and rql not in self._ck_cache:
                self._ck_cache[rql] = eidkeys
                if eidkeys:
                    cachekey = _rql_cache_key(cnx, rql, args, eidkeys)
            self._cache[cachekey] = rqlst
        return rqlst, cachekey

    def pop(self, key, *args):
        """Pop a key from the cache."""
        self._cache.pop(key, *args)
 def test_querycache(self):
     c = QueryCache(ceiling=20)
     # write only
     for x in range(10):
         c[x] = x
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 10,
         'permanentcount': 0
     })
     c = QueryCache(ceiling=10)
     # we should also get a warning
     for x in range(20):
         c[x] = x
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 10,
         'permanentcount': 0
     })
     # write + reads
     c = QueryCache(ceiling=20)
     for n in range(4):
         for x in range(10):
             c[x] = x
             c[x]
     self.assertEqual(c._usage_report(), {
         'transientcount': 10,
         'itemcount': 10,
         'permanentcount': 0
     })
     c = QueryCache(ceiling=20)
     for n in range(17):
         for x in range(10):
             c[x] = x
             c[x]
     self.assertEqual(c._usage_report(), {
         'transientcount': 0,
         'itemcount': 10,
         'permanentcount': 10
     })
     c = QueryCache(ceiling=20)
     for n in range(17):
         for x in range(10):
             c[x] = x
             if n % 2:
                 c[x]
             if x % 2:
                 c[x]
     self.assertEqual(c._usage_report(), {
         'transientcount': 5,
         'itemcount': 10,
         'permanentcount': 5
     })