diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index 72cb877..5299ab4 100644
a
|
b
|
|
1 | 1 | "File-based cache backend" |
2 | 2 | |
| 3 | import md5 |
3 | 4 | import os, time |
4 | 5 | try: |
5 | 6 | import cPickle as pickle |
6 | 7 | except ImportError: |
7 | 8 | import pickle |
8 | 9 | from django.core.cache.backends.base import BaseCache |
9 | | from django.utils.http import urlquote_plus |
10 | 10 | |
11 | 11 | class CacheClass(BaseCache): |
12 | 12 | def __init__(self, dir, params): |
… |
… |
class CacheClass(BaseCache):
|
29 | 29 | self._createdir() |
30 | 30 | |
31 | 31 | def add(self, key, value, timeout=None): |
32 | | fname = self._key_to_file(key) |
33 | | if timeout is None: |
34 | | timeout = self.default_timeout |
35 | | try: |
36 | | filelist = os.listdir(self._dir) |
37 | | except (IOError, OSError): |
38 | | self._createdir() |
39 | | filelist = [] |
40 | | if len(filelist) > self._max_entries: |
41 | | self._cull(filelist) |
42 | | if os.path.basename(fname) not in filelist: |
43 | | try: |
44 | | f = open(fname, 'wb') |
45 | | now = time.time() |
46 | | pickle.dump(now + timeout, f, 2) |
47 | | pickle.dump(value, f, 2) |
48 | | except (IOError, OSError): |
49 | | pass |
| 32 | if self.has_key(key): |
| 33 | return None |
| 34 | |
| 35 | self.set(key, value, timeout) |
50 | 36 | |
51 | 37 | def get(self, key, default=None): |
52 | 38 | fname = self._key_to_file(key) |
… |
… |
class CacheClass(BaseCache):
|
56 | 42 | now = time.time() |
57 | 43 | if exp < now: |
58 | 44 | f.close() |
59 | | os.remove(fname) |
| 45 | self._delete(fname) |
60 | 46 | else: |
61 | 47 | return pickle.load(f) |
62 | 48 | except (IOError, OSError, EOFError, pickle.PickleError): |
… |
… |
class CacheClass(BaseCache):
|
65 | 51 | |
66 | 52 | def set(self, key, value, timeout=None): |
67 | 53 | fname = self._key_to_file(key) |
| 54 | dir = os.path.dirname(fname) |
| 55 | |
68 | 56 | if timeout is None: |
69 | 57 | timeout = self.default_timeout |
| 58 | |
| 59 | self._cull() |
| 60 | |
70 | 61 | try: |
71 | | filelist = os.listdir(self._dir) |
72 | | except (IOError, OSError): |
73 | | self._createdir() |
74 | | filelist = [] |
75 | | if len(filelist) > self._max_entries: |
76 | | self._cull(filelist) |
77 | | try: |
| 62 | if not os.path.exists(dir): |
| 63 | os.makedirs(dir) |
| 64 | |
78 | 65 | f = open(fname, 'wb') |
79 | 66 | now = time.time() |
80 | 67 | pickle.dump(now + timeout, f, 2) |
… |
… |
class CacheClass(BaseCache):
|
84 | 71 | |
85 | 72 | def delete(self, key): |
86 | 73 | try: |
87 | | os.remove(self._key_to_file(key)) |
| 74 | self._delete(self._key_to_file(key)) |
88 | 75 | except (IOError, OSError): |
89 | 76 | pass |
90 | 77 | |
| 78 | def _delete(self, file): |
| 79 | os.remove(file) |
| 80 | try: |
| 81 | #remove the 2 subdirs if they're empty |
| 82 | dir = os.path.dirname(file) |
| 83 | os.rmdir(dir) |
| 84 | os.rmdir(os.path.dirname(dir)) |
| 85 | except: |
| 86 | pass |
| 87 | |
91 | 88 | def has_key(self, key): |
92 | | return os.path.exists(self._key_to_file(key)) |
| 89 | fname = self._key_to_file(key) |
| 90 | try: |
| 91 | f = open(fname, 'rb') |
| 92 | exp = pickle.load(f) |
| 93 | now = time.time() |
| 94 | if exp < now: |
| 95 | f.close() |
| 96 | self._delete(fname) |
| 97 | return False |
| 98 | else: |
| 99 | return True |
| 100 | except (IOError, OSError, EOFError, pickle.PickleError): |
| 101 | return False |
93 | 102 | |
94 | | def _cull(self, filelist): |
| 103 | def _cull(self): |
| 104 | if int(self._num_entries) < self._max_entries: |
| 105 | return |
| 106 | |
| 107 | try: |
| 108 | filelist = os.listdir(self._dir) |
| 109 | except (IOError, OSError): |
| 110 | return |
| 111 | |
95 | 112 | if self._cull_frequency == 0: |
96 | 113 | doomed = filelist |
97 | 114 | else: |
98 | | doomed = [k for (i, k) in enumerate(filelist) if i % self._cull_frequency == 0] |
99 | | for fname in doomed: |
| 115 | doomed = [os.path.join(self._dir, k) for (i, k) in enumerate(filelist) if i % self._cull_frequency == 0] |
| 116 | |
| 117 | for topdir in doomed: |
100 | 118 | try: |
101 | | os.remove(os.path.join(self._dir, fname)) |
| 119 | for root, _, files in os.walk(topdir): |
| 120 | for file in files: |
| 121 | self._delete(os.path.join(root,file)) |
102 | 122 | except (IOError, OSError): |
103 | 123 | pass |
104 | 124 | |
… |
… |
class CacheClass(BaseCache):
|
109 | 129 | raise EnvironmentError, "Cache directory '%s' does not exist and could not be created'" % self._dir |
110 | 130 | |
111 | 131 | def _key_to_file(self, key): |
112 | | return os.path.join(self._dir, urlquote_plus(key)) |
| 132 | path = md5.new(key.encode('utf-8')).hexdigest() |
| 133 | path = os.path.join(path[:2], path[2:4], path[4:]) |
| 134 | return os.path.join(self._dir, path) |
| 135 | |
| 136 | def _get_num_entries(self): |
| 137 | count = 0 |
| 138 | for _,_,files in os.walk(self._dir): |
| 139 | count += len(files) |
| 140 | return count |
| 141 | _num_entries = property(_get_num_entries) |
| 142 | |
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index 9ac2722..c6b8742 100644
a
|
b
|
class Cache(unittest.TestCase):
|
24 | 24 | |
25 | 25 | def test_add(self): |
26 | 26 | # test add (only add if key isn't already in cache) |
27 | | cache.add("addkey1", "value") |
| 27 | cache.set("addkey1", "value") |
28 | 28 | cache.add("addkey1", "newvalue") |
29 | 29 | self.assertEqual(cache.get("addkey1"), "value") |
30 | | |
| 30 | |
31 | 31 | def test_non_existent(self): |
32 | 32 | # get with non-existent keys |
33 | 33 | self.assertEqual(cache.get("does_not_exist"), None) |
… |
… |
class Cache(unittest.TestCase):
|
77 | 77 | |
78 | 78 | def test_expiration(self): |
79 | 79 | # expiration |
80 | | cache.set('expire', 'very quickly', 1) |
| 80 | cache.set('expire1', 'very quickly', 1) |
| 81 | cache.set('expire2', 'very quickly', 1) |
| 82 | cache.set('expire3', 'very quickly', 1) |
81 | 83 | time.sleep(2) |
82 | | self.assertEqual(cache.get("expire"), None) |
| 84 | |
| 85 | self.assertEqual(cache.get("expire1"), None) |
| 86 | |
| 87 | cache.add("expire2", "newvalue") |
| 88 | self.assertEqual(cache.get("expire2"), "newvalue") |
| 89 | |
| 90 | self.assertEqual(cache.has_key("expire3"), False) |
83 | 91 | |
84 | 92 | def test_unicode(self): |
85 | 93 | stuff = { |