/
txn.py
121 lines (103 loc) · 3.38 KB
/
txn.py
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
# -*- coding: utf-8 -*-
# Copyright (c) 2010-2016, MIT Probabilistic Computing Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import contextlib
from bayeslite.exception import BayesDBException
from bayeslite.sqlite3_util import sqlite3_savepoint
from bayeslite.sqlite3_util import sqlite3_savepoint_rollback
from bayeslite.sqlite3_util import sqlite3_transaction
# XXX Can't do this simultaneously in multiple threads. Need
# lightweight per-thread state.
@contextlib.contextmanager
def bayesdb_caching(bdb):
bayesdb_txn_push(bdb)
try:
yield
finally:
bayesdb_txn_pop(bdb)
@contextlib.contextmanager
def bayesdb_savepoint(bdb):
bayesdb_txn_push(bdb)
try:
with sqlite3_savepoint(bdb._sqlite3):
yield
finally:
bayesdb_txn_pop(bdb)
@contextlib.contextmanager
def bayesdb_savepoint_rollback(bdb):
bayesdb_txn_push(bdb)
try:
with sqlite3_savepoint_rollback(bdb._sqlite3):
yield
finally:
bayesdb_txn_pop(bdb)
@contextlib.contextmanager
def bayesdb_transaction(bdb):
if bdb.txn_depth != 0:
raise BayesDBTxnError(bdb, 'Already in a transaction!')
bayesdb_txn_init(bdb)
bdb.txn_depth = 1
try:
with sqlite3_transaction(bdb._sqlite3):
yield
finally:
assert bdb.txn_depth == 1
bdb.txn_depth = 0
bayesdb_txn_fini(bdb)
def bayesdb_begin_transaction(bdb):
if bdb.txn_depth != 0:
raise BayesDBTxnError(bdb, 'Already in a transaction!')
bayesdb_txn_init(bdb)
bdb.txn_depth = 1
bdb.sql_execute("BEGIN")
def bayesdb_rollback_transaction(bdb):
if bdb.txn_depth == 0:
raise BayesDBTxnError(bdb, 'Not in a transaction!')
bdb.sql_execute("ROLLBACK")
bdb.txn_depth = 0
bayesdb_txn_fini(bdb)
def bayesdb_commit_transaction(bdb):
if bdb.txn_depth == 0:
raise BayesDBTxnError(bdb, 'Not in a transaction!')
bdb.sql_execute("COMMIT")
bdb.txn_depth = 0
bayesdb_txn_fini(bdb)
# XXX Maintaining a stack of savepoints in BQL is a little more
# trouble than it is worth at the moment, since users can rollback to
# or release any savepoint in the stack, not just the most recent one.
# (For the bdb.savepoint() context manager that is not an issue.)
# We'll implement that later.
def bayesdb_txn_push(bdb):
if bdb.txn_depth == 0:
bayesdb_txn_init(bdb)
else:
assert bdb.cache is not None
bdb.txn_depth += 1
def bayesdb_txn_pop(bdb):
bdb.txn_depth -= 1
if bdb.txn_depth == 0:
bayesdb_txn_fini(bdb)
else:
assert bdb.cache is not None
def bayesdb_txn_init(bdb):
assert bdb.txn_depth == 0
assert bdb.cache is None
bdb.cache = {}
def bayesdb_txn_fini(bdb):
assert bdb.txn_depth == 0
assert bdb.cache is not None
bdb.cache = None
class BayesDBTxnError(BayesDBException):
"""Transaction errors in a BayesDB."""
pass