forked from grantjenks/python-diskcache
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathissue_85.py
More file actions
142 lines (116 loc) · 3.68 KB
/
issue_85.py
File metadata and controls
142 lines (116 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""Test Script for Issue #85
$ export PYTHONPATH=`pwd`
$ python tests/issue_85.py
"""
import collections
import os
import random
import shutil
import sqlite3
import threading
import time
import django
def remove_cache_dir():
print('REMOVING CACHE DIRECTORY')
shutil.rmtree('.cache', ignore_errors=True)
def init_django():
global shard
print('INITIALIZING DJANGO')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings')
django.setup()
from django.core.cache import cache
shard = cache._cache._shards[0]
def multi_threading_init_test():
print('RUNNING MULTI-THREADING INIT TEST')
from django.core.cache import cache
def run():
cache.get('key')
threads = [threading.Thread(target=run) for _ in range(50)]
_ = [thread.start() for thread in threads]
_ = [thread.join() for thread in threads]
def show_sqlite_compile_options():
print('SQLITE COMPILE OPTIONS')
options = shard._sql('pragma compile_options').fetchall()
print('\n'.join(val for val, in options))
def create_data_table():
print('CREATING DATA TABLE')
shard._con.execute('create table data (x)')
nums = [(num,) for num in range(1000)]
shard._con.executemany('insert into data values (?)', nums)
commands = {
'begin/read/write': [
'BEGIN',
'SELECT MAX(x) FROM data',
'UPDATE data SET x = x + 1',
'COMMIT',
],
'begin/write/read': [
'BEGIN',
'UPDATE data SET x = x + 1',
'SELECT MAX(x) FROM data',
'COMMIT',
],
'begin immediate/read/write': [
'BEGIN IMMEDIATE',
'SELECT MAX(x) FROM data',
'UPDATE data SET x = x + 1',
'COMMIT',
],
'begin immediate/write/read': [
'BEGIN IMMEDIATE',
'UPDATE data SET x = x + 1',
'SELECT MAX(x) FROM data',
'COMMIT',
],
'begin exclusive/read/write': [
'BEGIN EXCLUSIVE',
'SELECT MAX(x) FROM data',
'UPDATE data SET x = x + 1',
'COMMIT',
],
'begin exclusive/write/read': [
'BEGIN EXCLUSIVE',
'UPDATE data SET x = x + 1',
'SELECT MAX(x) FROM data',
'COMMIT',
],
}
values = collections.deque()
def run(statements):
ident = threading.get_ident()
try:
for index, statement in enumerate(statements):
if index == (len(statements) - 1):
values.append(('COMMIT', ident))
time.sleep(random.random() / 10.0)
shard._sql(statement)
if index == 0:
values.append(('BEGIN', ident))
except sqlite3.OperationalError:
values.append(('ERROR', ident))
def test_transaction_errors():
for key, statements in commands.items():
print(f'RUNNING {key}')
values.clear()
threads = []
for _ in range(100):
thread = threading.Thread(target=run, args=(statements,))
threads.append(thread)
_ = [thread.start() for thread in threads]
_ = [thread.join() for thread in threads]
errors = [pair for pair in values if pair[0] == 'ERROR']
begins = [pair for pair in values if pair[0] == 'BEGIN']
commits = [pair for pair in values if pair[0] == 'COMMIT']
print('Error count:', len(errors))
print('Begin count:', len(begins))
print('Commit count:', len(commits))
begin_idents = [ident for _, ident in begins]
commit_idents = [ident for _, ident in commits]
print('Serialized:', begin_idents == commit_idents)
if __name__ == '__main__':
remove_cache_dir()
init_django()
multi_threading_init_test()
show_sqlite_compile_options()
create_data_table()
test_transaction_errors()