1
|
|
|
# coding: utf-8 |
2
|
|
|
|
3
|
|
|
from __future__ import unicode_literals |
4
|
|
|
from collections import defaultdict |
5
|
|
|
from threading import local |
6
|
|
|
|
7
|
|
|
from django.core.cache import caches |
8
|
|
|
from django.db import DEFAULT_DB_ALIAS |
9
|
|
|
|
10
|
|
|
from .settings import cachalot_settings |
11
|
|
|
from .signals import post_invalidation |
12
|
|
|
from .transaction import AtomicCache |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
class CacheHandler(local): |
16
|
|
|
@property |
17
|
|
|
def atomic_caches(self): |
18
|
|
|
if not hasattr(self, '_atomic_caches'): |
19
|
|
|
self._atomic_caches = defaultdict(list) |
20
|
|
|
return self._atomic_caches |
21
|
|
|
|
22
|
|
|
def get_atomic_cache(self, cache_alias, db_alias, level): |
23
|
|
|
if cache_alias not in self.atomic_caches[db_alias][level]: |
24
|
|
|
self.atomic_caches[db_alias][level][cache_alias] = AtomicCache( |
25
|
|
|
self.get_cache(cache_alias, db_alias, level-1), db_alias) |
26
|
|
|
return self.atomic_caches[db_alias][level][cache_alias] |
27
|
|
|
|
28
|
|
|
def get_cache(self, cache_alias=None, db_alias=None, atomic_level=-1): |
29
|
|
|
if db_alias is None: |
30
|
|
|
db_alias = DEFAULT_DB_ALIAS |
31
|
|
|
if cache_alias is None: |
32
|
|
|
cache_alias = cachalot_settings.CACHALOT_CACHE |
33
|
|
|
|
34
|
|
|
min_level = -len(self.atomic_caches[db_alias]) |
35
|
|
|
if atomic_level < min_level: |
36
|
|
|
return caches[cache_alias] |
37
|
|
|
return self.get_atomic_cache(cache_alias, db_alias, atomic_level) |
38
|
|
|
|
39
|
|
|
def enter_atomic(self, db_alias): |
40
|
|
|
if db_alias is None: |
41
|
|
|
db_alias = DEFAULT_DB_ALIAS |
42
|
|
|
self.atomic_caches[db_alias].append({}) |
43
|
|
|
|
44
|
|
|
def exit_atomic(self, db_alias, commit): |
45
|
|
|
if db_alias is None: |
46
|
|
|
db_alias = DEFAULT_DB_ALIAS |
47
|
|
|
atomic_caches = self.atomic_caches[db_alias].pop().values() |
48
|
|
|
if commit: |
49
|
|
|
to_be_invalidated = set() |
50
|
|
|
for atomic_cache in atomic_caches: |
51
|
|
|
atomic_cache.commit() |
52
|
|
|
to_be_invalidated.update(atomic_cache.to_be_invalidated) |
53
|
|
|
# This happens when committing the outermost atomic block. |
54
|
|
|
if not self.atomic_caches[db_alias]: |
55
|
|
|
for table in to_be_invalidated: |
56
|
|
|
post_invalidation.send(table, db_alias=db_alias) |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
cachalot_caches = CacheHandler() |
60
|
|
|
|