Mercurial > piecrust2
annotate piecrust/cache.py @ 1188:a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Writing the cache files fails in Python 3.8 because it looks like flushing
behaviour has changed. We need to explicitly flush. And even then, in very
rare occurrences, it looks like it can still run into racing conditions,
so we do a very hacky and ugly "retry" loop when fetching cached data :(
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 15 Jun 2021 22:36:23 -0700 |
parents | cd0345e4001e |
children |
rev | line source |
---|---|
0 | 1 import os |
2 import os.path | |
371
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
3 import shutil |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
4 import pickle |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
5 import hashlib |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
6 import logging |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
7 import repoze.lru |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
8 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
9 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
10 logger = logging.getLogger(__name__) |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
11 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
12 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
13 class ExtensibleCache(object): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
14 def __init__(self, base_dir): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
15 self.base_dir = base_dir |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
16 self.caches = {} |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
17 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
18 @property |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
19 def enabled(self): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
20 return True |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
21 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
22 def getCache(self, name): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
23 c = self.caches.get(name) |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
24 if c is None: |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
25 c_dir = os.path.join(self.base_dir, name) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
26 if not os.path.isdir(c_dir): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
27 os.makedirs(c_dir, 0o755) |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
28 |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
29 c = SimpleCache(c_dir) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
30 self.caches[name] = c |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
31 return c |
0 | 32 |
45
efd0d3bacc9e
Don't recursively clean the cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
5
diff
changeset
|
33 def getCacheDir(self, name): |
efd0d3bacc9e
Don't recursively clean the cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
5
diff
changeset
|
34 return os.path.join(self.base_dir, name) |
efd0d3bacc9e
Don't recursively clean the cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
5
diff
changeset
|
35 |
105
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
36 def getCacheNames(self, except_names=None): |
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
37 _, dirnames, __ = next(os.walk(self.base_dir)) |
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
38 if except_names is None: |
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
39 return dirnames |
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
40 return [dn for dn in dirnames if dn not in except_names] |
7d2fdf43d7ca
Property clean all caches when force baking, except the `app` cache.
Ludovic Chabant <ludovic@chabant.com>
parents:
45
diff
changeset
|
41 |
371
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
42 def clearCache(self, name): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
43 cache_dir = self.getCacheDir(name) |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
44 if os.path.isdir(cache_dir): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
45 logger.debug("Cleaning cache: %s" % cache_dir) |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
46 shutil.rmtree(cache_dir) |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
47 |
424
5feb71d31a4f
internal: Fix caches being orphaned from their directory.
Ludovic Chabant <ludovic@chabant.com>
parents:
416
diff
changeset
|
48 # Re-create the cache-dir because now our Cache instance points |
5feb71d31a4f
internal: Fix caches being orphaned from their directory.
Ludovic Chabant <ludovic@chabant.com>
parents:
416
diff
changeset
|
49 # to a directory that doesn't exist anymore. |
5feb71d31a4f
internal: Fix caches being orphaned from their directory.
Ludovic Chabant <ludovic@chabant.com>
parents:
416
diff
changeset
|
50 os.makedirs(cache_dir, 0o755) |
5feb71d31a4f
internal: Fix caches being orphaned from their directory.
Ludovic Chabant <ludovic@chabant.com>
parents:
416
diff
changeset
|
51 |
371
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
52 def clearCaches(self, except_names=None): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
53 for name in self.getCacheNames(except_names=except_names): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
54 self.clearCache(name) |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
55 |
0 | 56 |
57 class SimpleCache(object): | |
58 def __init__(self, base_dir): | |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
59 self.base_dir = base_dir |
0 | 60 if not os.path.isdir(base_dir): |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
61 raise Exception("Cache directory doesn't exist: %s" % base_dir) |
0 | 62 |
63 def isValid(self, path, time): | |
64 cache_time = self.getCacheTime(path) | |
65 if cache_time is None: | |
66 return False | |
67 if isinstance(time, list): | |
68 for t in time: | |
69 if cache_time < t: | |
70 return False | |
71 return True | |
72 return cache_time >= time | |
73 | |
74 def getCacheTime(self, path): | |
75 cache_path = self.getCachePath(path) | |
76 try: | |
77 return os.path.getmtime(cache_path) | |
78 except os.error: | |
79 return None | |
80 | |
81 def has(self, path): | |
82 cache_path = self.getCachePath(path) | |
83 return os.path.isfile(cache_path) | |
84 | |
85 def read(self, path): | |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
86 with self.openRead(path, mode='r', encoding='utf8') as fp: |
0 | 87 return fp.read() |
88 | |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
89 def openRead(self, path, mode='r', encoding=None): |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
90 cache_path = self.getCachePath(path) |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
91 return open(cache_path, mode=mode, encoding=encoding) |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
92 |
0 | 93 def write(self, path, content): |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
94 with self.openWrite(path, mode='w', encoding='utf8') as fp: |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
95 fp.write(content) |
1188
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
96 fp.flush() |
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
97 os.fsync(fp) |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
98 |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
99 def openWrite(self, path, mode='w', encoding=None): |
0 | 100 cache_path = self.getCachePath(path) |
101 cache_dir = os.path.dirname(cache_path) | |
102 if not os.path.isdir(cache_dir): | |
5 | 103 os.makedirs(cache_dir, 0o755) |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
104 return open(cache_path, mode=mode, encoding=encoding) |
0 | 105 |
3
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
106 def getCachePath(self, path): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
107 if path.startswith('.'): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
108 path = '__index__' + path |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
109 return os.path.join(self.base_dir, path) |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
110 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
111 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
112 class NullCache(object): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
113 def isValid(self, path, time): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
114 return False |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
115 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
116 def getCacheTime(self, path): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
117 return None |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
118 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
119 def has(self, path): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
120 return False |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
121 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
122 def read(self, path): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
123 raise Exception("Null cache has no data.") |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
124 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
125 def write(self, path, content): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
126 pass |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
127 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
128 def getCachePath(self, path): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
129 raise Exception("Null cache can't make paths.") |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
130 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
131 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
132 class NullExtensibleCache(object): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
133 def __init__(self): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
134 self.null_cache = NullCache() |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
135 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
136 @property |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
137 def enabled(self): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
138 return False |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
139 |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
140 def getCache(self, name): |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
141 return self.null_cache |
f485ba500df3
Gigantic change to basically make PieCrust 2 vaguely functional.
Ludovic Chabant <ludovic@chabant.com>
parents:
0
diff
changeset
|
142 |
371
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
143 def getCacheDir(self, name): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
144 raise NotImplementedError() |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
145 |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
146 def getCacheNames(self, except_names=None): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
147 return [] |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
148 |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
149 def clearCache(self, name): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
150 pass |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
151 |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
152 def clearCaches(self, except_names=None): |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
153 pass |
c2ca72fb7f0b
caching: Use separate caches for config variants and other contexts.
Ludovic Chabant <ludovic@chabant.com>
parents:
105
diff
changeset
|
154 |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
155 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
156 def _make_fs_cache_key(key): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
157 return hashlib.md5(key.encode('utf8')).hexdigest() |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
158 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
159 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
160 class MemCache(object): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
161 """ Simple memory cache. It can be backed by a simple file-system |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
162 cache, but items need to be pickle-able to do this. |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
163 """ |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
164 def __init__(self, size=2048): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
165 self.cache = repoze.lru.LRUCache(size) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
166 self.fs_cache = None |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
167 self._last_access_hit = None |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
168 self._invalidated_fs_items = set() |
687
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
169 self._missed_keys = [] |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
170 self._misses = 0 |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
171 self._hits = 0 |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
172 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
173 @property |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
174 def last_access_hit(self): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
175 return self._last_access_hit |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
176 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
177 def invalidate(self, key): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
178 logger.debug("Invalidating cache item '%s'." % key) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
179 self.cache.invalidate(key) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
180 if self.fs_cache: |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
181 logger.debug("Invalidating FS cache item '%s'." % key) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
182 fs_key = _make_fs_cache_key(key) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
183 self._invalidated_fs_items.add(fs_key) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
184 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
185 def put(self, key, item, save_to_fs=True): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
186 self.cache.put(key, item) |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
187 if self.fs_cache and save_to_fs: |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
188 fs_key = _make_fs_cache_key(key) |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
189 with self.fs_cache.openWrite(fs_key, mode='wb') as fp: |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
190 pickle.dump(item, fp, pickle.HIGHEST_PROTOCOL) |
1188
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
191 fp.flush() |
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
192 os.fsync(fp) |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
193 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
194 def get(self, key, item_maker, fs_cache_time=None, save_to_fs=True): |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
195 self._last_access_hit = True |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
196 item = self.cache.get(key) |
687
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
197 if item is not None: |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
198 self._hits += 1 |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
199 return item |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
200 |
876
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
201 if self.fs_cache is not None: |
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
202 if fs_cache_time is None: |
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
203 raise ValueError( |
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
204 "No file-system cache time was given for '%s'. " |
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
205 "This would result in degraded performance." % key) |
d1095774bfcf
refactor: Fix some issues with record/cache entry collisions, add counters.
Ludovic Chabant <ludovic@chabant.com>
parents:
852
diff
changeset
|
206 |
687
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
207 # Try first from the file-system cache. |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
208 fs_key = _make_fs_cache_key(key) |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
209 if (fs_key not in self._invalidated_fs_items and |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
210 self.fs_cache.isValid(fs_key, fs_cache_time)): |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
211 with self.fs_cache.openRead(fs_key, mode='rb') as fp: |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
212 item = pickle.load(fp) |
687
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
213 self.cache.put(key, item) |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
214 self._hits += 1 |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
215 return item |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
216 |
687
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
217 # Look into the mem-cache. |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
218 item = item_maker() |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
219 self.cache.put(key, item) |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
220 self._last_access_hit = False |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
221 self._misses += 1 |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
222 self._missed_keys.append(key) |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
223 |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
224 # Save to the file-system if needed. |
61d606fbc313
bake: Change `show-timers` to `show-stats`, add stats.
Ludovic Chabant <ludovic@chabant.com>
parents:
424
diff
changeset
|
225 if self.fs_cache is not None and save_to_fs: |
911
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
226 with self.fs_cache.openWrite(fs_key, mode='wb') as fp: |
f2b75e4be981
internal: Use pickle for caching things on disk.
Ludovic Chabant <ludovic@chabant.com>
parents:
876
diff
changeset
|
227 pickle.dump(item, fp, pickle.HIGHEST_PROTOCOL) |
1188
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
228 fp.flush() |
a7c43131d871
bake: Fix file write flushing problem with Python 3.8+
Ludovic Chabant <ludovic@chabant.com>
parents:
1009
diff
changeset
|
229 os.fsync(fp) |
416
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
230 |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
231 return item |
ff6cc43fb40c
internal: Move `MemCache` to the `cache` module, remove threading locks.
Ludovic Chabant <ludovic@chabant.com>
parents:
371
diff
changeset
|
232 |