Skip to content

Commit

Permalink
Merges invalidate_all, invalidate_tables and invalidate_models, while…
Browse files Browse the repository at this point in the history
… optimising it.
  • Loading branch information
BertrandBordage committed Oct 5, 2015
1 parent d93e4c3 commit abc00b1
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 70 deletions.
4 changes: 2 additions & 2 deletions benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import psycopg2

import cachalot
from cachalot.api import invalidate_all
from cachalot.api import invalidate
from cachalot.tests.models import Test


Expand Down Expand Up @@ -126,7 +126,7 @@ def __init__(self):
def bench_once(self, context, num_queries, invalidate_before=False):
for _ in range(self.n):
if invalidate_before:
invalidate_all(db_alias=self.db_alias)
invalidate(db_alias=self.db_alias)
with AssertNumQueries(num_queries, using=self.db_alias):
start = time()
self.query_function(self.db_alias)
Expand Down
83 changes: 28 additions & 55 deletions cachalot/api.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,64 @@
# coding: utf-8

from __future__ import unicode_literals
from collections import defaultdict

from django.conf import settings
from django.db import connections
from django.utils.six import string_types

from .cache import cachalot_caches
from .utils import _get_table_cache_key, _invalidate_table_cache_keys


__all__ = ('invalidate_tables', 'invalidate_models', 'invalidate_all')
__all__ = ('invalidate',)


def _aliases_iterator(cache_alias, db_alias):
def _get_table_cache_keys_per_cache(tables, cache_alias, db_alias):
no_tables = not tables
cache_aliases = settings.CACHES if cache_alias is None else (cache_alias,)
db_aliases = settings.DATABASES if db_alias is None else (db_alias,)
for cache_alias in cache_aliases:
for db_alias in db_aliases:
yield cache_alias, db_alias
table_cache_keys_per_cache = defaultdict(list)
for db_alias in db_aliases:
if no_tables:
tables = connections[db_alias].introspection.table_names()
for cache_alias in cache_aliases:
table_cache_keys = [
_get_table_cache_key(db_alias, t) for t in tables]
if table_cache_keys:
table_cache_keys_per_cache[cache_alias].extend(table_cache_keys)
return table_cache_keys_per_cache


def invalidate_tables(tables, cache_alias=None, db_alias=None):
"""
Clears what was cached by django-cachalot implying one or more SQL tables
from ``tables``.
If ``cache_alias`` is specified, it only clears the SQL queries stored
on this cache, otherwise queries from all caches are cleared.
If ``db_alias`` is specified, it only clears the SQL queries executed
on this database, otherwise queries from all databases are cleared.
:arg tables: SQL tables names
:type tables: iterable of strings
:arg cache_alias: Alias from the Django ``CACHES`` setting
:type cache_alias: string or NoneType
:arg db_alias: Alias from the Django ``DATABASES`` setting
:type db_alias: string or NoneType
:returns: Nothing
:rtype: NoneType
"""
def _get_tables(tables_or_models):
return [o if isinstance(o, string_types) else o._meta.db_table
for o in tables_or_models]

for cache_alias, db_alias in _aliases_iterator(cache_alias, db_alias):
table_cache_keys = [_get_table_cache_key(db_alias, t) for t in tables]
cache = cachalot_caches.get_cache(cache_alias)
_invalidate_table_cache_keys(cache, table_cache_keys)


def invalidate_models(models, cache_alias=None, db_alias=None):
"""
Shortcut for ``invalidate_tables`` where you can specify Django models
instead of SQL table names.
:arg models: Django models
:type models: iterable of ``django.db.models.Model`` subclasses
:arg cache_alias: Alias from the Django ``CACHES`` setting
:type cache_alias: string or NoneType
:arg db_alias: Alias from the Django ``DATABASES`` setting
:type db_alias: string or NoneType
:returns: Nothing
:rtype: NoneType
"""

invalidate_tables([model._meta.db_table for model in models],
cache_alias, db_alias)


def invalidate_all(cache_alias=None, db_alias=None):
def invalidate(tables_or_models=(), cache_alias=None, db_alias=None):
"""
Clears everything that was cached by django-cachalot.
Clears what was cached by django-cachalot implying one or more SQL tables
or models from ``tables_or_models``. If ``tables_or_models``
is not specified, all tables found in the database are invalidated.
If ``cache_alias`` is specified, it only clears the SQL queries stored
on this cache, otherwise queries from all caches are cleared.
If ``db_alias`` is specified, it only clears the SQL queries executed
on this database, otherwise queries from all databases are cleared.
:arg tables_or_models: SQL tables names
:type tables_or_models: iterable of strings or models, or NoneType
:arg cache_alias: Alias from the Django ``CACHES`` setting
:type cache_alias: string or NoneType
:arg db_alias: Alias from the Django ``DATABASES`` setting
:type cache_alias: string or NoneType
:type db_alias: string or NoneType
:returns: Nothing
:rtype: NoneType
"""

for cache_alias, db_alias in _aliases_iterator(cache_alias, db_alias):
tables = connections[db_alias].introspection.table_names()
table_cache_keys = [_get_table_cache_key(db_alias, t) for t in tables]
table_cache_keys_per_cache = _get_table_cache_keys_per_cache(
_get_tables(tables_or_models), cache_alias, db_alias)
for cache_alias, table_cache_keys in table_cache_keys_per_cache.items():
_invalidate_table_cache_keys(cachalot_caches.get_cache(cache_alias),
table_cache_keys)
8 changes: 2 additions & 6 deletions cachalot/management/commands/invalidate_cachalot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.conf import settings
from django.core.management.base import BaseCommand
from django.apps import apps
from ...api import invalidate_all, invalidate_models
from ...api import invalidate


class Command(BaseCommand):
Expand Down Expand Up @@ -40,10 +40,6 @@ def handle(self, *args, **options):
cache_str, db_str]))
+ '...')

if args:
invalidate_models(models,
cache_alias=cache_alias, db_alias=db_alias)
else:
invalidate_all(cache_alias=cache_alias, db_alias=db_alias)
invalidate(models, cache_alias=cache_alias, db_alias=db_alias)
if verbosity > 0:
self.stdout.write('Cache keys successfully invalidated.')
6 changes: 3 additions & 3 deletions cachalot/monkey_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
SQLCompiler, SQLInsertCompiler, SQLUpdateCompiler, SQLDeleteCompiler)
from django.db.transaction import Atomic, get_connection

from .api import invalidate_all, invalidate_tables, invalidate_models
from .api import invalidate
from .cache import cachalot_caches
from .settings import cachalot_settings
from .utils import (
Expand Down Expand Up @@ -110,7 +110,7 @@ def inner(cursor, sql, *args, **kwargs):
sql = sql.lower()
if 'update' in sql or 'insert' in sql or 'delete' in sql:
tables = _get_tables_from_sql(cursor.db, sql)
invalidate_tables(tables, db_alias=cursor.db.alias)
invalidate(tables, db_alias=cursor.db.alias)
return out

return inner
Expand Down Expand Up @@ -143,7 +143,7 @@ def inner(self, exc_type, exc_value, traceback):


def _invalidate_on_migration(sender, **kwargs):
invalidate_models(sender.get_models(), db_alias=kwargs['using'])
invalidate(sender.get_models(), db_alias=kwargs['using'])


def patch():
Expand Down
8 changes: 4 additions & 4 deletions cachalot/tests/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_invalidate_tables(self):
data2 = list(Test.objects.values_list('name', flat=True))
self.assertListEqual(data2, ['test1'])

invalidate_tables(['cachalot_test'])
invalidate(['cachalot_test'])

with self.assertNumQueries(1):
data3 = list(Test.objects.values_list('name', flat=True))
Expand All @@ -55,7 +55,7 @@ def test_invalidate_models(self):
data2 = list(Test.objects.values_list('name', flat=True))
self.assertListEqual(data2, ['test1'])

invalidate_models([Test])
invalidate([Test])

with self.assertNumQueries(1):
data3 = list(Test.objects.values_list('name', flat=True))
Expand All @@ -68,7 +68,7 @@ def test_invalidate_all(self):
with self.assertNumQueries(0):
Test.objects.get()

invalidate_all()
invalidate()

with self.assertNumQueries(1):
Test.objects.get()
Expand All @@ -81,7 +81,7 @@ def test_invalidate_all_in_atomic(self):
with self.assertNumQueries(0):
Test.objects.get()

invalidate_all()
invalidate()

with self.assertNumQueries(1):
Test.objects.get()
Expand Down

0 comments on commit abc00b1

Please sign in to comment.