0
# Bytecode Caching
1
2
Performance optimization system that caches compiled template bytecode to filesystem or external storage systems like Memcached. Significantly improves template loading performance in production environments.
3
4
## Capabilities
5
6
### Bytecode Cache Base Class
7
8
Abstract base class for implementing bytecode caching strategies with pluggable storage backends.
9
10
```python { .api }
11
class BytecodeCache:
12
def load_bytecode(self, bucket):
13
"""
14
Load bytecode from cache into bucket.
15
16
Parameters:
17
bucket: Bucket instance to load bytecode into
18
"""
19
20
def dump_bytecode(self, bucket):
21
"""
22
Save bytecode from bucket to cache.
23
24
Parameters:
25
bucket: Bucket instance containing bytecode to save
26
"""
27
28
def clear(self):
29
"""
30
Clear entire cache.
31
"""
32
33
def get_cache_key(self, name, filename=None):
34
"""
35
Generate cache key for template.
36
37
Parameters:
38
name: Template name
39
filename: Template filename (optional)
40
41
Returns:
42
str: Cache key string
43
"""
44
45
def get_source_checksum(self, source):
46
"""
47
Generate checksum for template source.
48
49
Parameters:
50
source: Template source code
51
52
Returns:
53
str: Source checksum
54
"""
55
56
def get_bucket(self, environment, name, filename, source):
57
"""
58
Get cache bucket for template.
59
60
Parameters:
61
environment: Jinja2 environment instance
62
name: Template name
63
filename: Template filename
64
source: Template source code
65
66
Returns:
67
Bucket: Cache bucket instance
68
"""
69
70
def set_bucket(self, bucket):
71
"""
72
Store cache bucket.
73
74
Parameters:
75
bucket: Bucket instance to store
76
"""
77
```
78
79
### Filesystem Bytecode Cache
80
81
Filesystem-based bytecode caching for persistent local storage of compiled templates.
82
83
```python { .api }
84
class FileSystemBytecodeCache(BytecodeCache):
85
def __init__(self, directory=None, pattern='__jinja2_%s.cache'):
86
"""
87
Initialize filesystem bytecode cache.
88
89
Parameters:
90
directory: Cache directory path (default: system temp directory)
91
pattern: Filename pattern with %s placeholder for cache key
92
"""
93
```
94
95
Usage example:
96
97
```python
98
from jinja2 import Environment, FileSystemLoader, FileSystemBytecodeCache
99
import tempfile
100
import os
101
102
# Create cache directory
103
cache_dir = os.path.join(tempfile.gettempdir(), 'jinja2_cache')
104
os.makedirs(cache_dir, exist_ok=True)
105
106
# Setup environment with bytecode cache
107
env = Environment(
108
loader=FileSystemLoader('templates'),
109
bytecode_cache=FileSystemBytecodeCache(cache_dir)
110
)
111
112
# First load compiles and caches
113
template1 = env.get_template('page.html') # Slow: compile + cache
114
template2 = env.get_template('page.html') # Fast: load from cache
115
```
116
117
### Memcached Bytecode Cache
118
119
Memcached-based bytecode caching for distributed caching across multiple application instances.
120
121
```python { .api }
122
class MemcachedBytecodeCache(BytecodeCache):
123
def __init__(self, client, prefix='jinja2/bytecode/', timeout=None, ignore_memcache_errors=True):
124
"""
125
Initialize Memcached bytecode cache.
126
127
Parameters:
128
client: Memcached client instance
129
prefix: Key prefix for cache entries (default: 'jinja2/bytecode/')
130
timeout: Cache timeout in seconds (default: None for no expiration)
131
ignore_memcache_errors: Ignore Memcached errors (default: True)
132
"""
133
```
134
135
Usage example:
136
137
```python
138
from jinja2 import Environment, FileSystemLoader, MemcachedBytecodeCache
139
import memcache
140
141
# Setup Memcached client
142
mc = memcache.Client(['127.0.0.1:11211'])
143
144
# Setup environment with Memcached cache
145
env = Environment(
146
loader=FileSystemLoader('templates'),
147
bytecode_cache=MemcachedBytecodeCache(mc, timeout=3600) # 1 hour timeout
148
)
149
150
template = env.get_template('page.html')
151
```
152
153
### Cache Bucket
154
155
Cache storage unit that manages bytecode serialization and metadata.
156
157
```python { .api }
158
class Bucket:
159
def __init__(self, environment, key, checksum):
160
"""
161
Initialize cache bucket.
162
163
Parameters:
164
environment: Jinja2 environment instance
165
key: Cache key
166
checksum: Source checksum
167
"""
168
169
def load_bytecode(self, f):
170
"""
171
Load bytecode from file-like object.
172
173
Parameters:
174
f: File-like object to read from
175
"""
176
177
def write_bytecode(self, f):
178
"""
179
Write bytecode to file-like object.
180
181
Parameters:
182
f: File-like object to write to
183
"""
184
185
def bytecode_from_string(self, string):
186
"""
187
Load bytecode from byte string.
188
189
Parameters:
190
string: Bytecode as bytes
191
"""
192
193
def bytecode_to_string(self):
194
"""
195
Convert bytecode to byte string.
196
197
Returns:
198
bytes: Bytecode as bytes
199
"""
200
201
def reset(self):
202
"""
203
Clear bytecode from bucket.
204
"""
205
```
206
207
## Custom Cache Implementation
208
209
### Redis Bytecode Cache Example
210
211
Example implementation of a custom Redis-based bytecode cache:
212
213
```python
214
import pickle
215
from jinja2.bccache import BytecodeCache, Bucket
216
217
class RedisBytecodeCache(BytecodeCache):
218
def __init__(self, redis_client, prefix='jinja2:', timeout=3600):
219
self.redis = redis_client
220
self.prefix = prefix
221
self.timeout = timeout
222
223
def load_bytecode(self, bucket):
224
key = self.prefix + bucket.key
225
data = self.redis.get(key)
226
if data is not None:
227
bucket.bytecode_from_string(data)
228
229
def dump_bytecode(self, bucket):
230
key = self.prefix + bucket.key
231
data = bucket.bytecode_to_string()
232
if data is not None:
233
self.redis.setex(key, self.timeout, data)
234
235
def clear(self):
236
keys = self.redis.keys(self.prefix + '*')
237
if keys:
238
self.redis.delete(*keys)
239
240
# Usage
241
import redis
242
r = redis.Redis()
243
env = Environment(
244
loader=FileSystemLoader('templates'),
245
bytecode_cache=RedisBytecodeCache(r)
246
)
247
```
248
249
### Database Bytecode Cache Example
250
251
Example implementation using a database for bytecode storage:
252
253
```python
254
import sqlite3
255
from jinja2.bccache import BytecodeCache
256
257
class SQLiteBytecodeCache(BytecodeCache):
258
def __init__(self, database_path):
259
self.db_path = database_path
260
self._init_database()
261
262
def _init_database(self):
263
conn = sqlite3.connect(self.db_path)
264
conn.execute('''
265
CREATE TABLE IF NOT EXISTS bytecode_cache (
266
key TEXT PRIMARY KEY,
267
bytecode BLOB,
268
checksum TEXT,
269
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
270
)
271
''')
272
conn.commit()
273
conn.close()
274
275
def load_bytecode(self, bucket):
276
conn = sqlite3.connect(self.db_path)
277
cursor = conn.execute(
278
'SELECT bytecode FROM bytecode_cache WHERE key = ? AND checksum = ?',
279
(bucket.key, bucket.checksum)
280
)
281
row = cursor.fetchone()
282
conn.close()
283
284
if row:
285
bucket.bytecode_from_string(row[0])
286
287
def dump_bytecode(self, bucket):
288
data = bucket.bytecode_to_string()
289
if data is not None:
290
conn = sqlite3.connect(self.db_path)
291
conn.execute(
292
'INSERT OR REPLACE INTO bytecode_cache (key, bytecode, checksum) VALUES (?, ?, ?)',
293
(bucket.key, data, bucket.checksum)
294
)
295
conn.commit()
296
conn.close()
297
298
def clear(self):
299
conn = sqlite3.connect(self.db_path)
300
conn.execute('DELETE FROM bytecode_cache')
301
conn.commit()
302
conn.close()
303
```
304
305
## Performance Considerations
306
307
### Cache Effectiveness
308
309
Bytecode caching provides the most benefit when:
310
311
- Templates are reused frequently
312
- Template compilation is a bottleneck
313
- Templates contain complex logic or many includes/extends
314
- Running in production with stable templates
315
316
### Cache Invalidation
317
318
Caches automatically invalidate when:
319
320
- Template source files change (filesystem modification time)
321
- Template source content changes (checksum comparison)
322
- Environment configuration changes
323
- Jinja2 version changes
324
325
### Memory vs. Disk Trade-offs
326
327
```python
328
# In-memory cache for development
329
env = Environment(
330
loader=FileSystemLoader('templates'),
331
cache_size=100, # Keep 100 compiled templates in memory
332
auto_reload=True # Auto-reload on changes
333
)
334
335
# Disk cache for production
336
env = Environment(
337
loader=FileSystemLoader('templates'),
338
bytecode_cache=FileSystemBytecodeCache('/var/cache/jinja2'),
339
cache_size=0, # Disable memory cache
340
auto_reload=False # Disable auto-reload
341
)
342
```
343
344
## Types
345
346
```python { .api }
347
class CacheStatistics:
348
"""
349
Cache performance statistics for monitoring and optimization.
350
351
Attributes:
352
hits: Number of cache hits
353
misses: Number of cache misses
354
hit_ratio: Cache hit ratio (hits / (hits + misses))
355
size: Current cache size
356
max_size: Maximum cache size
357
"""
358
359
class CacheEntry:
360
"""
361
Individual cache entry with metadata.
362
363
Attributes:
364
key: Cache key
365
checksum: Source checksum
366
bytecode: Compiled bytecode
367
created_at: Creation timestamp
368
accessed_at: Last access timestamp
369
"""
370
```